-- Compiled with roblox-ts v1.3.3 local TS = _G[script] local FN_MARKER = "__trove_fn_marker__" local THREAD_MARKER = "__trove_thread_marker__" local function getObjCleanupFn(obj, cleanupMethod) local t = typeof(obj) if t == "function" then return FN_MARKER elseif t == "thread" then return THREAD_MARKER end if cleanupMethod ~= nil then return cleanupMethod end if t == "Instance" then return "Destroy" elseif t == "RBXScriptConnection" then return "Disconnect" elseif t == "table" then if obj.Destroy ~= nil then return "Destroy" elseif obj.Disconnect ~= nil then return "Disconnect" elseif obj.destroy ~= nil then return "destroy" elseif obj.disconnect ~= nil then return "disconnect" end end error("failed to get cleanup function for object " .. (typeof(obj) .. (": " .. tostring(obj))), 3) end --[[ * * A Trove helps track and clean up objects. ]] local Trove do Trove = setmetatable({}, { __tostring = function() return "Trove" end, }) Trove.__index = Trove function Trove.new(...) local self = setmetatable({}, Trove) return self:constructor(...) or self end function Trove:constructor() self.objects = {} self.cleaning = false end function Trove:add(obj, cleanupMethod) if self.cleaning then error("Cannot call trove.add() while cleaning", 2) end local cleanup = getObjCleanupFn(obj, cleanupMethod) local _objects = self.objects local _arg0 = { obj = obj, cleanup = cleanup, } table.insert(_objects, _arg0) return obj end function Trove:addPromise(promise) if self.cleaning then error("Cannot call trove.addPromise() while cleaning", 2) end if promise:getStatus() == TS.Promise.Status.Started then promise:finally(function() if self.cleaning then return nil end self:findAndRemoveFromObjs(promise, false) end) self:add(promise, "cancel") end return promise end function Trove:connect(signal, handler) if self.cleaning then error("Cannot call trove.connect() while cleaning", 2) end return self:add(signal:Connect(handler)) end function Trove:bindToRenderStep(name, priority, renderFn) if self.cleaning then error("Cannot call trove.bindToRenderStep() while cleaning", 2) end game:GetService("RunService"):BindToRenderStep(name, priority, renderFn) self:add(function() game:GetService("RunService"):UnbindFromRenderStep(name) end) end function Trove:remove(obj) if self.cleaning then error("Cannot call trove.remove() while cleaning", 2) end return self:findAndRemoveFromObjs(obj, true) end function Trove:clone(instance) if self.cleaning then error("Cannot call trove.clone() while cleaning", 2) end return self:add(instance:Clone()) end function Trove:extend() if self.cleaning then error("Cannot call trove.extend() while cleaning", 2) end return self:add(Trove.new()) end function Trove:attachToInstance(instance) if self.cleaning then error("Cannot call trove.attachToInstance() while cleaning", 2) end if not instance:IsDescendantOf(game) then error("Instance is not a descendant of the game hierarchy", 2) end return self:add(instance.Destroying:Connect(function() return self:destroy() end)) end function Trove:clean() if self.cleaning then return nil end self.cleaning = true local _objects = self.objects local _arg0 = function(obj) return self:cleanupObj(obj) end for _k, _v in ipairs(_objects) do _arg0(_v, _k - 1, _objects) end table.clear(self.objects) self.cleaning = false end function Trove:destroy() self:clean() end function Trove:findAndRemoveFromObjs(obj, cleanup) local _objects = self.objects local _arg0 = function(track) return track.obj == obj end -- ▼ ReadonlyArray.findIndex ▼ local _result = -1 for _i, _v in ipairs(_objects) do if _arg0(_v, _i - 1, _objects) == true then _result = _i - 1 break end end -- ▲ ReadonlyArray.findIndex ▲ local index = _result if index ~= -1 then local track = self.objects[index + 1] -- ▼ Array.unorderedRemove ▼ local _index = index + 1 local _exp = self.objects local _length = #_exp local _value = _exp[_index] if _value then _exp[_index] = _exp[_length] _exp[_length] = nil end -- ▲ Array.unorderedRemove ▲ if cleanup then self:cleanupObj(track) end end return false end function Trove:cleanupObj(track) if track.cleanup == FN_MARKER then track.obj() elseif track.cleanup == THREAD_MARKER then task.cancel(track.obj) else (track.obj)[track.cleanup](track.obj) end end end return { Trove = Trove, }