-- Compiled with roblox-ts v3.0.0 local stack = {} -- This is used to store alternative data for hooks such as useDeltaTime local secondaryStack = {} local function cleanupUnused() -- ▼ Array.pop ▼ local _length = #stack local _result = stack[_length] stack[_length] = nil -- ▲ Array.pop ▲ local context = _result assert(context, "No context to cleanup.") for _, storage in pairs(context.node) do for key, state in storage.states do if not (context.activeKeys[key] ~= nil) and (not storage.cleanup or storage.cleanup(state)) then storage.states[key] = nil end end end end --[[ * * Starts a new stack frame for a function, ensuring cleanup after execution. * Intended to be used in systems. * * @param node - The node to store the state for the current function. * @param callback - The function to execute within the new stack frame. ]] local function start(node, callback) local _arg0 = { activeKeys = {}, node = node, } table.insert(stack, _arg0) callback() cleanupUnused() stack[#stack] = nil end --[[ * * Creates or retrieves a state object for a hook, keyed by a unique identifier. * * @template T The type of the hook state. * @param key - A unique string identifier for the hook state. * @param discriminator - An optional value to further distinguish different * states within the same key. Defaults to the key itself. * @param cleanup - An optional function that determines whether the state * should be cleaned up. It should return true if the state should be removed. * If not provided, the state will be cleaned up when the hook was not * accessed in the current context. * @returns The state object of type T. ]] local function useHookState(key, discriminator, cleanup) if discriminator == nil then discriminator = key end local context = stack[#stack] assert(context, "Hooks can only be used within a `start` function.") local storage = context.node[key] if not storage then storage = { cleanup = cleanup, states = {}, } context.node[key] = storage end local stringDiscriminator = tostring(discriminator) local compositeKey = `{key}-{stringDiscriminator}` context.activeKeys[compositeKey] = true local state = storage.states[compositeKey] if state == nil then state = {} local _states = storage.states local _state = state _states[compositeKey] = _state end return state end return { start = start, useHookState = useHookState, secondaryStack = secondaryStack, }