Just to clarify, When you now bind a function using BindToClose, The game server itself will pass the enum to your bound function as the first parameter. It’s not necessary for you to pass anything in your own code.
Previously creators didn’t have direct information as to why the server was closing.
We’re hoping creators find this useful for a variety of scenarios! Some experience developers who tested this feature have also found this helpful for tracking down memory leaks by collecting information for servers that shutdown due to the OutOfMemory reason.
Thanks a lot! This is such a good change! Our game had a problem in the early days where memory leaks caused server crashes. Everyone in the server would lose their hard-earned winstreaks if they were mid-game during a server crash.
Now, this seems to never happen, but if it ever does, I can be confident that they won’t be recognized as having “left the game during a match” and losing their winstreak, because BindToClose automatically removes the mid-game status in our game.
Just want to throw my hat in the ring to support this idea.
This is absolutely the main use case for us and, pending an official analytics integration, all I see us using this Enum for is passing it to our own analytics to get this data.
I would really appreciate if BindToClose function would return RBXScriptConnection, so I can disconnect the event. Right now it returns () (AKA nothing), and there seems to be no way of disconnecting it.
My library allows to start a service, and stop the service. If the service is stopped by the script, it can’t disconnect BindToClose and will most likely result in a memory leak.
I don’t know about BindToClose returning an event, however, for your issue, I’d make your service store the methods in a seperate table that can be accessed from DataModel:BindToClose and just add/remove methods from the list when necessary.
And, in the BindToClose method, you can just iterate over the list and call each method. If the list is empty, nothing happens
function service:BindToClose(identifier: string, method: (closeReason: Enum.CloseReason) -> ())
methodsList[identifier] = method -- assign the method to the list of methods
end
function service:UnbindFromClose(identifier: string)
methodsList[identifier] = nil -- remove the method from the list
end
-- ^^ This is a more simplified version of what I mean
-- (a seperate script)
-- Run each method from a BindToClose callback
game:BindToClose(function(closeReason)
for _, boundMethod in methodsList do
task.spawn(boundMethod, closeReason)
end
end)
Can we get a separate reason for when it’s closing because of Studio closing or play-test stopping? That way, we can skip saving, et cetera if we want.
Memory leak occurs because functions keep getting added via the BindToClose method. Not when the functions in the internal list are called. The continous growth of the internal list of functions that you cannot remove from is a problem.
-- Pretend that this is C++ code
local callbacks = {}
local function onBindClose(callback)
table.insert(callbacks, callback)
end
-- This is Luau code (with ability to call "onBindClose")
for i = 1, 100 do
onBindClose(function() end)
end
-- Pretend that this is C++ code
print(#callbacks) -- 100
I am aware of this workaround, but it doesn’t solve the problem that there is no way to remove function from the internal list. It’s a bad design in my opinion, because If I can add a function, I should always be able to remove it.
It should either return RBXScriptConnection or a function that you can call.
local connection = game:OnBindClose(function() end)
connection:Disconnect()
local disconnect = game:OnBindClose(function() end)
disconnect()
The OnBindClose method is a bit weird, because it doesn’t follow the current standard where if it was implemented today, it would’ve been something like this:
local connection = game.Closing:Connect(function(reason)
print("Game is about to close", reason)
end)
connection:Disconnect()
So, most likely the disconnect function would be more fitting. At end of the day, I don’t care how it is implemented, as long as there is a way to remove the function I passed into OnBindClose from the internal list.