So one thing I cannot really find lots of info about is how exactly events and signals work.
I cannot find any details about how they’re garbage collected and under what conditions.
And since the deferred events update events work slightly different if you have your game set to deferred so this also requires a slight change to how some scripts clean up things after object destruction.
One of the things I’m concerned about in Roblox is not knowing what the exact conditions are for events to be disconnected and worries about floating event connections.
I think we all know that…
-- Inside a BasePart.
script.Parent.Touched:Connect(function(object)
print("Touched: " .. object:GetFullName())
end)
If the BasePart
were to be :Destroy()
'd, all events get disconnected, so it’s safe to assume that this will be garbage collected properly and securely.
Now onto a slightly more complex case.
Let’s say that in workspace.Zombie.AIScript
we have the following:
local targets = {}
...
function addTarget(object)
if not object:FindFirstChild("Humanoid") then return end
table.insert(targets, object)
end
local event = workspace.ChildAdded:Connect(addTarget)
Here we have a script inside a zombie that tracks targets.
Zombie later gets killed in the game and is :Destroy()
'd.
What happens to this event?
The zombie is destroyed, but we’re listening to an event of game.Workspace
.
And we all know that workspace
never gets :Destroy()
'd (as that would basically delete/break the game if you could), so it’s connections will never be broken by game logic.
What happens to the event we connected in the script?
Module script.
Now let’s take the above example but now we apply it using module scripts for modular zombie AI.
game.ReplicatedStorage.Modules.ZombieAI
local zombie_class = {}
zombie_class.__index = zombie
function zombie_class:new(model)
local zombie = setmetatable({}, self)
zombie.model = model
zombie.targets = {}
...
model.Humanoid.Died:Connect(function() -- Gets GC'd when model is Destroy()'d.
zombie:die()
end)
workspace.ChildAdded:Connect(function(target) -- ???
if not target:FindFirstChild("Humanoid") then return end
table.insert(zombie.targets, target)
end)
...
return zombie
end
In workspace.Zombie.AIScript
:
local zombie_module = require(game.ReplicatedStorage.Modules.ZombieAI)
local zombie = zombie_module:new(script.Parent)
In this case I don’t know if the event gets properly disposed of because it’s created inside a module script.
The script that initiated it will be :Destroy()
'd when the zombie dies, however module scripts can technically still execute their code even if the script that initiated it got deleted???
And what would happen if I did this same thing, but inside an Actor instead?
As far as I know, every Actor
creates it’s own Luau Virtual Machine
for Parallel Luau and I assume that virtual machine is also deleted/cleansed whenever the Actor
is :Destroy()
'd.
But still have no idea what happens with events and signal connections that are made with an Actor
and I can find no documentation or other posts about it.