Debris2 | Open Source

Debris2

an extension to Roblox Debris Service:

  • You can use this to:

    • Disconnect RBXScriptConnections
    • Destroy Instances
    • Remove tables with a .Destroy method
  • With Added functionality of:

    • Adding multiple items at once
    • Canceling Debris
    • Overriding lifeTime
    • Setting Debris.Destroyed callback
    • You can easily replace this with Debris without having to worry about your code breaking.
    • Uses Heatbeat for better precision
  • Methods:

    • AddItem (item: Instance or table or RBXScriptConnection, lifeTime: number?) → Debris
    • AddItems (arrayOfItems: {Instance, table, RBXScriptConnection}, lifeTime: number?) → void
    • GetAllDebris () → Debris2.Instances
    • GetDebris (item: Instance or table or RBXScriptConnection) → Debris2.Instances.Debris

Been though Code Review and Discussion to ensure quality

Debris2.lua

Pastebin

--[[ 
	@game/ReplicatedStorage/Debris2
		Debris2 = {
			Instances {
				[Debris: instance or table or RBXScriptConnection] = {
					lifeTime = lifeTime: number,
					removalTime = tick() + lifeTime: number,
					Destroyed = nil, -- Destroyed: callback Function | nil by default
					Cancel = function -- remove references and disconnect Hearbeat
					Instance = item: (Instance or table or RBXScriptConnection),
				},
			},
		}
		
		-- Methods
		AddItem (item: Instance or table or RBXScriptConnection, lifeTime: number?) -> Debris
		AddItems (arrayOfItems: {Instance, table, RBXScriptConnection}, lifeTime: number?) -> void
		GetAllDebris () -> Debris2.Instances
		GetDebris (item: Instance or table or RBXScriptConnection) -> Debris
--]]

local Debris2 = {
	Instances = {}
}

--| SERVICES:
local RunS = game:GetService("RunService")
	local Heatbeat = RunS.Heartbeat

--| MODULES:

--| VARIABLES:

local Instances = Debris2.Instances

--| TABLES:

local Connections = {}

local ValidTypes = {
	["Instance"] = "Destroy",
	["table"] = true,
	["RBXScriptConnection"] = "Disconnect",
}

local METHODS = { -- add any Custom Destroy/Remove/Clear/CleanUp methods here
	"Destroy",
	"Disconnect",
	
	"destroy",
	"disconnect",
}

--| META TABLES:

--| FUNCTIONS:

local function removeItem(typeOf, object)
	if typeOf == "Instance" then
		pcall(object.Destroy, object)
	elseif typeOf == "RBXScriptConnection" then
		pcall(object.Disconnect, object)
	else
		for _,v in ipairs(METHODS) do -- _, v: method name
			if object[v] then
				pcall(object[v], v)
				break
			end
		end
	end
end

local function addDebris(object, lifeTime)
	
	local typeOf = typeof(object)
	
	assert(ValidTypes[typeof(object)])
	assert(typeof(lifeTime) == "number")
	
	if (not Instances[object]) then
		table.insert(Instances, object)
	end
	
	Instances[object] = {
		["lifeTime"] = lifeTime,
		removalTime = tick() + lifeTime,
--		Destroyed = nil, -- Destroyed: callback Function
		Cancel = function() -- remove references and disconnect Hearbeat
			Connections[object]:Disconnect()
			table.remove(Instances,table.find(Instances, object))
			Instances[object] = nil
		end,
		["Instance"] = object,
	}
	
	local debris = Instances[object]
	
	Connections[object] = Heatbeat:Connect(function()
		if debris and tick() >= debris.removalTime then
			if debris.Destroyed then
				debris.Destroyed()
			end
			debris.Cancel()
			removeItem(typeOf,object)
		end
		debris = Instances[object]
	end)
	
	return Instances[object]
end

--| METHODS:

function Debris2:AddItem(item, lifeTime) -- item: (Instance, table, RBXScriptConnection), lifeTime: number
	return addDebris(item, lifeTime)
end

function Debris2:AddItems(arrayOfItems, lifeTime) -- arrayOfItems: (Instance, table, RBXScriptConnection), lifeTime: number
	for _,item in ipairs(arrayOfItems) do
		addDebris(item, lifeTime)
	end
end

function Debris2:GetAllDebris()
	return Instances
end
Debris2.getAllDebris = Debris2.GetAllDebris

function Debris2:GetDebris(item)
	return Instances[item]
end
Debris2.getDebris = Debris2.GetDebris

--| SCRIPTS:

-- return:
return Debris2

Example Code
local Debris2 = require(game.ReplicatedStorage.Debris2)

local parts = {}

for i = 1, 5 do
	local part = Instance.new("Part")
	part.Name = i
	part.Anchored = true
	part.Parent = workspace
	local debris = Debris2:AddItem(part,3)
	function debris.Destroyed()
		print("Destroyed",part)
	end
	if i == 1 then
		debris.Cancel()
	end
	table.insert(parts,part)
end

Debris2:AddItem({},3).Destroyed = function()
	print("DESTROYED")
end
Debris2:AddItem(parts[2].AncestryChanged:Connect(function(...) print(...) end),3).Cancel()

Debris2:AddItems(parts,4)

Debris2:getDebris(parts[1]).Cancel()

wait(5)

print(#Debris2:getAllDebris())

feel free to make pull requests, this is my first open source project on Github, I’m sure that the Documentation & Code can be improved immensely!

Motivation

As you already know Debris doesn’t have a lot of functionality, in-fact there’s only one method you can use :AddItem

And it could be quite limiting




45 Likes

This is really great, thank you for doing this. The service used deprecated methods, but we got a better alternative now. I tried it out and overall seems great :+1:

2 Likes

This module is insane, It can handle my raytracer with performance much greater than the built in debris service, (Roughly 50000 objects being added and removed every second)

The module does get a bit mad when it has to process that many but its still much better than the built in system (lots of failed assertions)

I’d make an argument here, but since it’s important, Is it better to use this or DebrisGobbler; Based on the user experiences, I’d like the a stable response about both of these modules.

I have a concern about this module, Why not handle all the things in a single heartbeat instead of creating a new heartbeat every object?

DebrisGobbler seems easier to use and was optimized for efficiency. Debris2, is “an extension to Debris", i.e., it provides a bigger API, willingly sacrificing performance.

1 Like

I actually don’t know what DebrisGobbler is, this module is very old and is probably outdated compared to newer ones


@PhoenixRessusection thank you!