diff --git a/Kit/Managers/ClientObjectManager/init.luau b/Kit/Managers/ClientObjectManager/init.luau index 3a1ac65..61207b0 100644 --- a/Kit/Managers/ClientObjectManager/init.luau +++ b/Kit/Managers/ClientObjectManager/init.luau @@ -41,7 +41,7 @@ local LightingManager = require(Kit.Managers.LightingManager) local ClientObjectManager = { __initialized = false, - VERSION_NUMBER = "6.1.3", --@kit-version + VERSION_NUMBER = "6.1.3", --@kit-version } :: _TDefs.ClientObjectsController type Repo = { [string]: any } @@ -106,42 +106,34 @@ local function getRepository(overrideRepository: Instance?) return repository end -local function loadScript(targetScope: ScopeTypes.Scope, scriptPath: string, instance: Instance?) - local thisScript = targetScope.repository[scriptPath] - if not thisScript then - return +-- This function must run using scope::spawn or scope::defer +local function runScript(targetScope: ScopeTypes.Scope, scriptPath: string, thisScript: ScopeTypes.RepositoryModule | ScopeTypes.LegacyRepositoryModule, instance: Instance?) + debug.setmemorycategory(scriptPath) + local innerScope = targetScope:inherit({ + instance = instance, + scriptPath = scriptPath, + }) + if instance then + targetScope.activeScripts[scriptPath][instance] = true + innerScope:attach(instance) end - local thread: thread - thread = targetScope:defer(function() - debug.setmemorycategory(scriptPath) - local innerScope = targetScope:inherit({ - instance = instance, - scriptPath = scriptPath, - }) - if instance then - targetScope.activeScripts[scriptPath][instance] = true - innerScope:attach(instance) - end - - if typeof(thisScript) == "function" then - thisScript(innerScope, Utility) - elseif typeof(thisScript) == "table" and typeof(thisScript.Run) == "function" then - thisScript.Run(innerScope, Utility) - else - Log({ - `Repository Script "{scriptPath}" does not have a runner function.`, - type = "info", - printType = "warn", - }) - end + if typeof(thisScript) == "function" then + thisScript(innerScope, Utility) + elseif typeof(thisScript) == "table" and typeof(thisScript.Run) == "function" then + thisScript.Run(innerScope, Utility) + else + Log({ + `Repository Script "{scriptPath}" does not have a runner function.`, + type = "info", + printType = "warn", + }) + end - innerScope:add(thread, function() - targetScope:remove(thread) - if instance and targetScope.rootScope:isAlive() then - targetScope.activeScripts[scriptPath][instance] = nil - end - end) + innerScope:add(function() + if instance and targetScope.rootScope:isAlive() then + targetScope.activeScripts[scriptPath][instance] = nil + end end) end @@ -153,8 +145,8 @@ end ]=] function ClientObjectManager:ScanFolder(targetScope: ScopeTypes.Scope, path: Instance, targetPath: Instance?) local repository = targetScope.repository - local activeScripts = targetScope.activeScripts - + local activeScripts = targetScope.activeScripts + --> Get objects that shouldnt be loaded in (yet?) local objectBlacklist = {} for _, instance in CollectionService:GetTagged("SkipObjectLoad") do @@ -164,51 +156,42 @@ function ClientObjectManager:ScanFolder(targetScope: ScopeTypes.Scope, path: Ins end --> Get scripts - local scriptQueue = {} for scriptPath, thisScript in repository do - for _, instance in CollectionService:GetTagged("CO_" .. scriptPath) do - if not instance:IsDescendantOf(path) then - continue - end + if typeof(thisScript) == "table" and thisScript.CanQueue == false then + continue + end + + if not activeScripts[scriptPath] then + activeScripts[scriptPath] = {} + end + + for _, instance in CollectionService:GetTagged("CO_" .. scriptPath) do + if not instance:IsDescendantOf(path) then + continue + end if activeScripts[scriptPath] and activeScripts[scriptPath][instance] then continue end local shouldQueue = true - if typeof(thisScript) == "table" and thisScript.CanQueue == false then - shouldQueue = false - end - if shouldQueue then - -- As bad as this loop looks, it's actually not since each - -- CO removes the tag when it's loaded so this check will - -- almost never run more than once or twice - for blacklistedInstance in objectBlacklist do - if blacklistedInstance == instance or instance:IsDescendantOf(blacklistedInstance) then - shouldQueue = false - break - end + for blacklistedInstance in objectBlacklist do + if blacklistedInstance == instance or instance:IsDescendantOf(blacklistedInstance) then + shouldQueue = false + break end end if shouldQueue then - scriptQueue[instance] = scriptPath - if not activeScripts[scriptPath] then - activeScripts[scriptPath] = {} - end + targetScope:defer(runScript, targetScope, scriptPath, thisScript, instance) end end end - - for _, instance in path:GetChildren() do - if targetPath then + + if targetPath then + for _, instance in path:GetChildren() do instance.Parent = targetPath end end - - --> Run Scripts - for instance, scriptPath in scriptQueue do - loadScript(targetScope, scriptPath, instance) - end end --[=[ @@ -239,22 +222,22 @@ function ClientObjectManager:LoadClientObjects( repository = thisRepository, }) - local container = rootScope:add(Instance.new("Folder")) - container.Name = `{tower}TempContainer` - container.Parent = ReplicatedStorage - rootScope.shared.TempContainer = container - - --> Scan folder for repo scripts - ClientObjectManager:ScanFolder(rootScope, from, target) - from:Destroy() - + local container = rootScope:add(Instance.new("Folder")) + container.Name = `{tower}TempContainer` + container.Parent = ReplicatedStorage + rootScope.shared.TempContainer = container + --> Load RunOnStart repo scripts for scriptPath, thisScript in thisRepository do if typeof(thisScript) == "table" and thisScript.RunOnStart then - loadScript(rootScope, scriptPath) + rootScope:spawn(runScript, rootScope, scriptPath, thisScript) end end + --> Scan folder for repo scripts + ClientObjectManager:ScanFolder(rootScope, from, target) + from:Destroy() + --> Deregister any lighting presets & cleanup variables on scope cleanup local tower = rootScope.tower rootScope:add(function() diff --git a/Kit/Managers/ScopeConstructor/TypeDefs.luau b/Kit/Managers/ScopeConstructor/TypeDefs.luau index e870a49..180f44f 100644 --- a/Kit/Managers/ScopeConstructor/TypeDefs.luau +++ b/Kit/Managers/ScopeConstructor/TypeDefs.luau @@ -73,7 +73,7 @@ export type __Scope_params = { [any]: unknown, }, debug: boolean, - repository: { [string]: (LegacyRepositoryModule | RepositoryModule)? }, + repository: { [string]: (LegacyRepositoryModule | RepositoryModule) }, active: boolean, activeScripts: { [string]: { [Instance]: boolean } }, diff --git a/Kit/Repository/Interactables/BoostPad.luau b/Kit/Repository/Interactables/BoostPad.luau deleted file mode 100644 index 73bbaa0..0000000 --- a/Kit/Repository/Interactables/BoostPad.luau +++ /dev/null @@ -1,270 +0,0 @@ ---!strict ---!optimize 2 ---@version boostpad-6.1.0 ---@creator Camille ---[[ --------------------------------------------------------------------------------- --=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -⚠️ WARNING - PLEASE READ! ⚠️ -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -If you are submitting to EToH: - -PLEASE, **DO NOT** make any script edits to this script. -To make a script edit, please read the following: -https://etohgame.github.io/kit/docs/misc#writingediting-repository-scripts - -If you have any suggestions, please let us know. -Thank you --------------------------------------------------------------------------------- -]] - --- !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! --- !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! --- !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! - --- boost pads have been deprecated in 6.1.0 in favor of merging it's --- functionality into the main booster object. this script will remain as there --- are still towers that use it, however please be aware that it will no longer --- be maintained. any bugs with legacy boost pads will NOT be fixed and you --- should convert them to regular boosters if you want to use them - --- !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! --- !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! --- !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! IMPORTANT WARNING !!! - -local HttpService = game:GetService("HttpService") -local Players = game:GetService("Players") -local ReplicatedStorage = game:GetService("ReplicatedStorage") -local RunService = game:GetService("RunService") -local Workspace = game:GetService("Workspace") - -local _T = require(ReplicatedStorage.Framework.ClientTypes) -local CharacterManager_Types = require(ReplicatedStorage.Framework.Kit.Managers.CharacterManager.TypeDefs) - -local BoostPad = { - CanQueue = true, - RunOnStart = false, -} - -local FPS_CAP = 1 / 60 - -local PAD_CONFIG_TEMPLATE -function BoostPad.Init(utility: _T.Utility) - local Config = utility.Config - PAD_CONFIG_TEMPLATE = { - Type = "Unknown", - Distance = 10, - Power = 50, - HideGUI = false, - } -end - -type BoostPad = { - pad: BasePart, - hitbox: BasePart, - configuration: { [string]: any }, - id: string, - touching: boolean, -} - -type BoostPadCache = { - boostPads: { BoostPad }, - activePads: { [string]: BoostPad? }, -} - -function BoostPad.Run(scope: _T.Scope, utility: _T.Utility) - --> Setup - local boostPadConfig = scope.instance - if not boostPadConfig then - return - end - - local boostPad = boostPadConfig.Parent - if not boostPad or not boostPad:IsA("BasePart") then - return - end - - scope:log({ - "BoostPads have been deprecated in favor of the new Pad mode on regular Boosters.", - "Please convert your old BoostPads into regular Boosters.", - `Path: {boostPad:GetFullName()}`, - type = "warn", - }) - - local CharacterUtil = utility.Character - local Config = utility.Config - local configuration = Config.GetConfig(scope, boostPadConfig, PAD_CONFIG_TEMPLATE):ObserveChanges() - - --> Cache system and main loop - local function handleCache(rootScope: _T.Scope, utility: _T.Utility) - local cache: BoostPadCache = { - boostPads = {}, - activePads = {}, - } - - local function getBoostData(boostPad: BoostPad): CharacterManager_Types.BoostData - local boostModule = - CharacterUtil.getBoostModule(boostPad.configuration.Type) :: CharacterManager_Types.Boost - - return { - type = boostPad.configuration.Type, - power = boostPad.configuration.Power, - hideGUI = boostPad.configuration.HideGUI, - - module = boostModule, - - -- everything below is not used in boost pads but they have to - -- be here as placeholders to avoid type errors - startTime = 0, - mode = "Pad", - duration = 0, - timerDecimals = 0, - startTweenInfo = TweenInfo.new(), - endTweenInfo = TweenInfo.new(), - infinite = false, - multiplier = 0, - timeLeft = 0, - } - end - - --> Get Hitbox - local overlapParams = OverlapParams.new() - overlapParams.FilterType = Enum.RaycastFilterType.Include - overlapParams.CollisionGroup = "" - utility.Character.getHitbox("StaticCenter", overlapParams) - rootScope:add(Players.LocalPlayer.CharacterAdded:Connect(function(character) - task.wait() - overlapParams.FilterDescendantsInstances = {} - utility.Character.getHitbox("StaticCenter", overlapParams) - end)) - - --> Loop - local lastTick = os.clock() - local CharacterUtil = utility.Character - local isTableEmpty = utility.Table.IsEmpty - rootScope:add(RunService.Heartbeat:Connect(function(deltaTime: number) - debug.profilebegin("BoostPads -> Update") - - if isTableEmpty(cache.boostPads) then - return - end - - --> Cap loop to 60fps - local currentTick = os.clock() - if currentTick - lastTick < FPS_CAP then - return - end - lastTick = currentTick - - --> Get touching parts and determine if a boost pad is being touched - local touchingPads: { BoostPad } = {} - for _, boostPad in cache.boostPads do - if - boostPad.touching - and boostPad.pad:GetAttribute("Activated") ~= false - and #Workspace:GetPartsInPart(boostPad.hitbox, overlapParams) > 0 - then - table.insert(touchingPads, boostPad) - elseif boostPad.touching then - -- checks above failed and the touching variable is still true - boostPad.touching = false - end - end - - --> Activate boost if touching - local boostTypesFound = {} - for _, pad in touchingPads do - boostTypesFound[pad.configuration.Type] = true - - local activePad = cache.activePads[pad.configuration.Type] - if activePad and activePad.id ~= pad.id or not activePad then - local existingBoost = CharacterUtil.getActiveBoost(pad.configuration.Type, "Pad") - if existingBoost then - CharacterUtil.removeBoost(existingBoost) - end - - cache.activePads[pad.configuration.Type] = pad - local boostData = getBoostData(pad) - CharacterUtil.startBoost(boostData) - end - end - - --> If not touching, deactivate boost - for boostType, pad in cache.activePads do - if pad and not boostTypesFound[boostType] then - cache.activePads[boostType] = nil - - local activeBoost = CharacterUtil.getActiveBoost(boostType, "Pad") - if activeBoost then - CharacterUtil.removeBoost(activeBoost) - end - end - end - - debug.profileend() - end)) - - return cache - end - - local cache = utility.Scope.getCached(scope, scope.scriptPath, handleCache) - - --> setting up this boost pad now - scope:attach(boostPad) - - -- check for problems - local testBoostData = CharacterUtil.getBoostModule(configuration.Type) - if not configuration.Type or not testBoostData then - scope:log({ - "BoostPad has an unknown Type and cannot function.", - `Path: {boostPad:GetFullName()}`, - type = "warn", - }) - return - end - - -- create a hitbox based on the configured distance - local boostPadHitbox = Instance.fromExisting(boostPad) - boostPadHitbox.Name = "Hitbox" - boostPadHitbox.Transparency = 1 - boostPadHitbox.CanCollide = false - boostPadHitbox.CanTouch = true - boostPadHitbox.CanQuery = true - boostPadHitbox.Massless = true - boostPadHitbox.Size = Vector3.new(boostPad.Size.X, math.abs(configuration.Distance), boostPad.Size.Z) - boostPadHitbox.CFrame = boostPad.CFrame * CFrame.new(0, (configuration.Distance * 0.5) + (boostPad.Size.Y * 0.5), 0) - - local boostPadWeld = Instance.new("WeldConstraint") - boostPadWeld.Part0 = boostPad - boostPadWeld.Part1 = boostPadHitbox - boostPadWeld.Parent = boostPadHitbox - boostPadHitbox.Parent = boostPad - boostPadHitbox.Anchored = false - - -- add to the boost pad list - local boostPadData: BoostPad = { - pad = boostPad, - hitbox = boostPadHitbox, - configuration = configuration, - id = HttpService:GenerateGUID(), - touching = false, - } - - table.insert(cache.boostPads, boostPadData) - scope:add(boostPadHitbox.Touched:Connect(function(touchingPart) - if not utility.ClientObjects.validatePlayerToucher(touchingPart, "StaticCenter") then - return - end - boostPadData.touching = true - end)) - - scope:add(function() - local index = table.find(cache.boostPads, boostPadData) - if index then - table.remove(cache.boostPads, index) - end - end) -end - -return BoostPad diff --git a/Kit/Repository/Interactables/Booster/init.luau b/Kit/Repository/Interactables/Booster/init.luau index 1850461..a58eb73 100644 --- a/Kit/Repository/Interactables/Booster/init.luau +++ b/Kit/Repository/Interactables/Booster/init.luau @@ -45,7 +45,7 @@ type BoosterCache = { local Booster = { CanQueue = true, - RunOnStart = false, + RunOnStart = true, } local BOOSTER_CONFIG_TEMPLATE @@ -66,6 +66,10 @@ function Booster.Run(scope: _T.Scope, utility: _T.Utility) --> Setup local boosterConfig = scope.instance if not boosterConfig then + local repo = scope.rootScope.repository + if not repo["Interactables/BoostPad"] then + repo["Interactables/BoostPad"] = Booster + end return end @@ -73,6 +77,36 @@ function Booster.Run(scope: _T.Scope, utility: _T.Utility) if not booster or not booster:IsA("BasePart") then return end + + --> BoostPad backwards compatibility + if scope.scriptPath == "Interactables/BoostPad" then + scope:log({ + "BoostPads have been deprecated in favor of the new Pad mode on regular Boosters.", + "Please convert your old BoostPads into regular Boosters.", + `Path: {booster:GetFullName()}`, + type = "warn", + }) + + local startTweenConfig = scope:add(Instance.new("Configuration")) + startTweenConfig.Parent = boosterConfig + startTweenConfig.Name = "StartTweenConfiguration" + startTweenConfig:SetAttribute("Time", 0) + startTweenConfig:SetAttribute("Direction", Enum.EasingDirection.In) + startTweenConfig:SetAttribute("Style", Enum.EasingStyle.Linear) + + local endTweenConfig = scope:add(Instance.new("Configuration")) + endTweenConfig.Parent = boosterConfig + endTweenConfig.Name = "EndTweenConfiguration" + endTweenConfig:SetAttribute("Time", 0) + endTweenConfig:SetAttribute("Direction", Enum.EasingDirection.In) + endTweenConfig:SetAttribute("Style", Enum.EasingStyle.Linear) + + boosterConfig:SetAttribute("Mode", "Pad") + boosterConfig:SetAttribute("PadDistance", boosterConfig:GetAttribute("Distance")) + scope:add(boosterConfig:GetAttributeChangedSignal("Distance"):Connect(function() + boosterConfig:SetAttribute("PadDistance", boosterConfig:GetAttribute("Distance")) + end)) + end local CharacterUtil = utility.Character local Config = utility.Config