P.S Problem with BindToClose solved, but there is no problem with saving data
Briefly about the problem: I have my own script for saving data, I have a function that saves them when the player exits. It is already clear that the function does not work.
When a player logs out with him, the server shuts down, so I used BindToClose to stop the server from shutting down. Data is not saved, Studio freezes and gives an error (Not running script because past shutdown deadline).
I read a lot on the forum, there were a lot of articles with no solution or no suitable solution. But I found the answer…
This answer had a solution that works. As you understand, the answer does not suit me
Of course, I did not understand what kind of code was written, but I understood:
-
The code works
-
The code is complex
-
Code works with threads
-
The code doesn’t do what I want
By the way, this code:
aloe.FailSafeSave = function()
-- this is only called when the game is shutting down
local mainThread = coroutine.running() -- This just gets a reference to the current thread so we can yield it and resume it later
local numThreadsRunning = 0
for _, player in ipairs(game.Players:GetPlayers()) do
local startSavingThread = coroutine.wrap(function()
aloe.Save(player) -- Async function, yields until saving finishes (could implement a retry here if you pcall it and check for failure)
numThreadsRunning -= 1 -- This thread finished, decrement the counter
if numThreadsRunning == 0 then
-- Resume the main thread if this was the last thread to run
coroutine.resume(mainThread)
end
end)
numThreadsRunning += 1
-- No need to defer, coroutine.wrap() already yields when it starts,
-- so numThreadsRunning will have a chance to count all the way up before this actually runs
startSavingThread(player) -- Start the saving thread
end
if numThreadsRunning > 0 then
-- Gets resumed once all saveThreads have finished
coroutine.yield()
end
end
aloe.Save = function(player)
dataSet:SetAsync(player.UserId, sessionData[player])
RapSet:SetAsync(player.Name .. ";" .. player.UserId, aloe.RAPCalculate(player))
end
As I understand it, when the server is turned off, the code calls the save function and creates threads, but I need to wait until the already saving function saves everything, then you can turn off the server
I would be grateful if you could explain to me how I can change the save function or write the code for BindToClose, and perhaps adapt the code above. Or to understand what I do not understand in the logic of closing or saving?
Part of the code needed to save data (and needed to understand the problem, without unnecessary code)
local PlayerData = {}
local numDataForSave = 0
function PlayerAdded (plr)
local UserId = plr.UserId
local success, Key = pcall(function ()
return Playerid(UserId)
end)
if not success then WriteErrors(Key, nil, UserId) Key = UserId end
PlayerData[Key] = {}
numDataForSave += 1
while wait() do
if Players.PlayerRemoving:Wait().UserId == UserId then
for i, v in pairs(PlayerData[Key]) do -- [key] = {[DSS] = {["Data"] = nil, ["userIds"] = UserId, ["options"] = options, ["Edit"] = false}}
if v["Edit"] then
local key = i
local dssName = v
local data = v["Data"]
local userIds = v["userIds"]
local options = v["options"]
for x = 1, 5 do
local PcallError = nil
if data == nil then
local success, Error = pcall(function()
local GDS = dss:GetDataStore(dssName)
GDS:RemoveAsync(key)
end)
PcallError = Error
else
local success, Error = pcall(function()
local GDS = dss:GetDataStore(dssName)
GDS:SetAsync(key, data, userIds, options)
end)
PcallError = Error
end
if success == false then
WriteErrors("An error occurred while recording: " .. PcallError, dssName, key)
else
break
end
task.wait(0.1)
end
--PlayerData[key][dssName] = nil
end
end
PlayerData[Key] = nil
numDataForSave -= 1
break
end
end
end
if AutoSave then
Players.PlayerAdded:Connect(PlayerAdded)
game:BindToClose(function() -- I tried many solutions with for and others with while
while numDataForSave > 0 do
print(numDataForSave)
task.wait(1)
end
end)
end
New working code: