Created
August 6, 2020 17:10
-
-
Save howmanysmall/483ce7aec5436058b226077fedf31ee2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local RunService = game:GetService("RunService") | |
local Heartbeat = RunService.Heartbeat | |
local LinkToInstanceIndex = newproxy(false) | |
local Janitors = setmetatable({}, {__mode = "k"}) | |
local Janitor = {__index = {CurrentlyCleaning = true}} | |
local TypeDefaults = { | |
["function"] = true; | |
["RBXScriptConnection"] = "Disconnect"; | |
} | |
local function Wait(Seconds) | |
Seconds = math.max(Seconds or 0.03, 0) | |
local TimeRemaining = Seconds | |
while TimeRemaining > 0 do | |
TimeRemaining -= Heartbeat:Wait() | |
end | |
return Seconds - TimeRemaining | |
end | |
local function Finish(Thread, Success, ...) | |
if not Success then | |
warn(debug.traceback(Thread, tostring((...)))) | |
end | |
return Success, ... | |
end | |
local function FastSpawn(Function, ...) | |
local Thread = coroutine.create(Function) | |
return Finish(Thread, coroutine.resume(Thread, ...)) | |
end | |
function Janitor.new() | |
return setmetatable({CurrentlyCleaning = false}, Janitor) | |
end | |
function Janitor.__index:Add(Object, MethodName, Index) | |
if Index then | |
self:Remove(Index) | |
local This = Janitors[self] | |
if not This then | |
This = {} | |
Janitors[self] = This | |
end | |
This[Index] = Object | |
end | |
self[Object] = MethodName or TypeDefaults[typeof(Object)] or "Destroy" | |
return Object | |
end | |
function Janitor.__index:Remove(Index) | |
local This = Janitors[self] | |
if This then | |
local Object = This[Index] | |
if Object then | |
local MethodName = self[Object] | |
if MethodName then | |
if MethodName == true then | |
Object() | |
else | |
Object[MethodName](Object) | |
end | |
self[Object] = nil | |
end | |
This[Index] = nil | |
end | |
end | |
end | |
function Janitor.__index:Get(Index) | |
local This = Janitors[self] | |
if This then | |
return This[Index] | |
end | |
end | |
function Janitor.__index:Cleanup() | |
if not self.CurrentlyCleaning then | |
self.CurrentlyCleaning = nil | |
for Object, MethodName in next, self do | |
if MethodName == true then | |
Object() | |
else | |
Object[MethodName](Object) | |
end | |
self[Object] = nil | |
end | |
local This = Janitors[self] | |
if This then | |
for Index in next, This do | |
This[Index] = nil | |
end | |
Janitors[self] = nil | |
end | |
self.CurrentlyCleaning = false | |
end | |
end | |
local NULL = nil | |
function Janitor.__index:Destroy() | |
self:Cleanup() | |
setmetatable(self, NULL) | |
end | |
Janitor.__call = Janitor.__index.Cleanup | |
--- Makes the Janitor clean up when the instance is destroyed | |
-- @param Instance Instance The Instance the Janitor will wait for to be Destroyed | |
-- @returns Disconnectable table to stop Janitor from being cleaned up upon Instance Destroy (automatically cleaned up by Janitor, btw) | |
-- @author Corecii | |
local Disconnect = {Connected = true} | |
Disconnect.__index = Disconnect | |
function Disconnect:Disconnect() | |
self.Connected = false | |
self.Connection:Disconnect() | |
end | |
function Janitor.__index:LinkToInstance(Object, AllowMultiple) | |
local Reference = Instance.new("ObjectValue") | |
Reference.Value = Object | |
local ManualDisconnect = setmetatable({}, Disconnect) | |
local Connection | |
local function ChangedFunction(Obj, Par) | |
if not Reference.Value then | |
ManualDisconnect.Connected = false | |
return self:Cleanup() | |
elseif Obj == Reference.Value and not Par then | |
Obj = nil | |
Wait(0.03) | |
if (not Reference.Value or not Reference.Value.Parent) and ManualDisconnect.Connected then | |
if not Connection.Connected then | |
ManualDisconnect.Connected = false | |
return self:Cleanup() | |
else | |
while true do | |
Wait(0.2) | |
if not ManualDisconnect.Connected then | |
return | |
elseif not Connection.Connected then | |
ManualDisconnect.Connected = false | |
return self:Cleanup() | |
elseif Reference.Value.Parent then | |
return | |
end | |
end | |
end | |
end | |
end | |
end | |
Connection = Object.AncestryChanged:Connect(ChangedFunction) | |
ManualDisconnect.Connection = Connection | |
Object = nil | |
FastSpawn(ChangedFunction, Reference.Value, Reference.Value.Parent) | |
if AllowMultiple then | |
self:Add(ManualDisconnect, "Disconnect") | |
else | |
self:Add(ManualDisconnect, "Disconnect", LinkToInstanceIndex) | |
end | |
return ManualDisconnect | |
end | |
return Janitor |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment