DataStore not working when last player leaves the game (in private servers)

First of all before i get any quick replies;

  1. This works if there are 2 players and then one leaves. my problem is that the event just doesn’t activate when the last player leaves
  2. My DataStoreSystem module is working correctly and i know for a fact that it is not the cause of error. I know that the error lies somewhere in this code, or close proximity

I have a datastoresystem which saves data by private servers and not by players. What i expect this code to do is save everything Everytime a player leaves the game. regardless if there is another one in the game or not. the problem is that it only seems to work when a player stays in the game. When i test with 1 player, play a bit and then leave the game. nothing shows up in my games error report (you can see warnings there aswell) which further indicates this code is not being ran at all. If i test with 2 players i can see the warnings both in the ingame logs and on my games error report. does playerremoving only activate if theres a player left in the game?

game.Players.PlayerRemoving:Connect(function(Player)
	warn("Starting Save") --Warns only warn when playing with 2+ players
	if ServerType == "VIPServer" then --I have confirmed this to be TRUE
		warn("Trying to save")
		local Data = UpgradeHandler.ReturnDataForSaving() --This works. Data equals the data i want
		warn("Returned data,", Data)
		DataStore.UploadData(PrivateServerId, Data) --This works with no errormessage from SetAsync
		warn("UploadedData") --this shows the data was uploaded succesfully. Never prints in logs
	else
		warn("Isnt VIP server") --This isnt triggered and it shouldnt be triggered
	end
end)
28 Likes

Add a game:BindToClose() call. This ensures that any functions work before the server shuts down.

16 Likes

I know about BindToClose, But im wondering if PlayerRemoving just never triggers when last player leaves. I would prefer doing it without BindToClose

13 Likes

It might just be that you’re using Studio.
Studio has weird bugs with PlayerRemoving.

12 Likes

I am not using studio. im in a private server on the game. Is it even possible to emulate private servers on studio?

15 Likes

I just tried using BindToClose but that also doesnt trigger when the last player leaves and i still have the problem of only being able to save if a player is still in the game

13 Likes

I know this isn’t related to private servers, but what happens when you try this in a public server?

12 Likes


Okay so this is weird. when leaving on a public server (one player) it does say “Starting Save” but then also says “Isnt VIP server” since well its not a private server. Now im really confused as shouldnt the “Starting Save” print on a private server too?

13 Likes

Why do you want to not use BindToClose? It’s necessary for data requests to go through.

Let me break it down.

  • Server closes: Players.PlayerRemoving will fire for the last player.
  • Request gets sent to the data store queue.
  • No BindToClose function to be run - game server closes.
  • When the game server closes, all unprocessed data store requests are cleared no matter what.
  • Therefore, data does not save.

You see how the data store methods end in Async? In this context, they are asynchronous network requests. For these requests, your code will only yield so far as to authenticate the requests. It won’t wait for them to be processed.

You need to wait on BindToClose to give these requests time to process. There’s no point saving on BindToClose either, it will just put more stress on the data stores. Either Players:GetPlayers() returns a blank table, or you’re adding more save data for players that will already have their data saved when they are kicked.

Try adding this:

game:BindToClose(function()
    task.wait(if game:GetService("RunService"):IsStudio() then 5 else 30) --30 seconds is the limit
end)
15 Likes
12 Likes

Looks like a python thing.

task.wait(game:GetService("RunService"):IsStudio() and 5 or 30)
11 Likes

That didn’t help as the “PlayerRemoving” event does still not fire when the last player leaves on a privateserver but it does fire when the last player leaves on a public server

11 Likes

Please get out, I already said i have a fully working datastore module which i have written myself and do not plan on changing it. if you had read my 2nd note in my post (close to the top) you wouldnt have written this message. People like you are honestly really annoying

10 Likes

I see. If PlayerRemoving does not fire, can you see if Players:GetPlayers() returns a blank table or not in BindToClose?


my code snippet and your code snippet will do the same thing. What I gave is valid Luau syntax; in Python it’s slightly different.

val1 if condition else val2
9 Likes

I added a warn(game.Players:GetPlayers()) (before the task.wait) but the warn does not show up in my error logs. this leads me to believe that either the error logs are broken or the bindtoclose function is never ran at all

10 Likes

Error logs do take some time to come through. Have you checked to see if data saves by modifying it when you’re the last player left and seeing if it has saved next time you join?

There’s no private-server-only conditionals in your code that could cause this, are there?

10 Likes

When the last player leaves the game, you do not have much time to do many things. Even those warn() calls may take up too much time. I’m not really a fan of game:BindToClose(). However, if you’re doing more than a few things with returns (like those warn() calls), this may be the way to go.
If I do use a game:BindToClose(), I will make sure the PlayerRemoving doesn’t save with the last player… letting that be picked up with the game:BindToClose().

10 Likes

I understand that the logs may take some time but i have waited a few minutes which sould be more than enough. I am modifying the data before i leave but since PlayerRemoving doesnt run it doesnt save, unless i use 2 players. If i use 2 players everything saves and loads perfectly fine. There are no “private-server-only conditionals” in my code other than what was seen in my original post

10 Likes

Theres also as seen here no SetAsync calls being made further showing that the function doesnt run
I am also able to post my full code if needed

10 Likes

I still cant get any of the 2 events (PlayerRemoving and BindToClose) to run when on a private server. They do run on a public server as usual. See normally this would be caused by the code never actually reaching the line where the connection is made but i have a print statement right before and right after and they both print so it must mean its connected. Im just so confused by this and Im not sure what to do anymore

Here is my (Probably unoptimized) Main script All other code exists in module scripts)

--This is the main script for the system.
--You shouldn't have to edit any of this in order for the game to work.
--Thanks to @KdudeDev for the InfiniteMath module

--DebugMode (Enable If the script is not working for some reason. This will help diagnose the issue)
local DebugMode = true

--Services
local RunService = game:GetService("RunService")

--Modules
local GetServerType = require(script.Modules.GetServerType)
local DataStore = require(script.Modules.DataStoreHandler)
local InfiniteMath = require(script.Modules.InfiniteMath)
local HideUpgrades = require(script.Modules.HideUpgrades)
local UpgradeHandler = require(script.Modules.UpgradeHandler)

--ExtraModules
local CurrenciesModule = require(script.Currencies)
local GameSettings = require(script.GameSettings)


for Iteration, UpgradeModel in pairs(game.Workspace.Upgrades:GetChildren()) do
	HideUpgrades["Hide"](UpgradeModel)
end

local Currencies = {}
local Currencygain = {}
for Iteration, Currency in pairs(CurrenciesModule) do
	Currencies[Currency] = InfiniteMath.new(0)
	Currencygain[Currency] = {}
	Currencygain[Currency]["Total"] = InfiniteMath.new(0)
	Currencygain[Currency]["Additive"] = InfiniteMath.new(0)
	Currencygain[Currency]["Multiplicative"] = InfiniteMath.new(1)
end
Currencies["Points"] = InfiniteMath.new(0) --temproary
Currencies["PrestigePoints"] = InfiniteMath.new(0) --temproary
if DebugMode then print("Currency amounts before loading", Currencies, Currencygain) end

local ServerType : string = "Fail"
local PrivateServerId : any = nil
repeat 
	ServerType, PrivateServerId = GetServerType.Get()
until ServerType ~= "Fail"
local LoadedDataFromCloud, Succes = {}, nil
if ServerType == "VIPServer" then
	if DebugMode then print("Attempting to load private server data") end
	Succes, LoadedDataFromCloud = DataStore.LoadData(PrivateServerId)
	if not Succes then
		for Iteration, Player in pairs(game.Players:GetPlayers()) do
			Player:Kick("Failed to load server data")
		end
	end
	if LoadedDataFromCloud ~= nil then
		LoadedDataFromCloud["IsLoaded"] = true
		Currencies = LoadedDataFromCloud["Currencies"]
		Currencygain = LoadedDataFromCloud["CurrencyGain"]
		LoadedDataFromCloud["DebugMode"] = DebugMode
	else
		LoadedDataFromCloud = {}
		LoadedDataFromCloud["IsLoaded"] = false
		LoadedDataFromCloud["Currencies"] = Currencies
		LoadedDataFromCloud["CurrencyGain"] = Currencygain
		LoadedDataFromCloud["DebugMode"] = DebugMode
	end
else
	LoadedDataFromCloud = {}
	LoadedDataFromCloud["IsLoaded"] = false
	LoadedDataFromCloud["Currencies"] = Currencies
	LoadedDataFromCloud["CurrencyGain"] = Currencygain
	LoadedDataFromCloud["DebugMode"] = DebugMode
end
print("e")
game.Players.PlayerRemoving:Connect(function()
	warn("Starting Save")
	if ServerType == "VIPServer" then
		warn("Trying to save")
		local Data = UpgradeHandler.ReturnDataForSaving()
		warn("Returned data,", Data)
		DataStore.UploadData(PrivateServerId, Data)
		warn("UploadedData")
	else
		warn("Isnt VIP server")
	end
end)
game:BindToClose(function()
	warn(#game.Players:GetPlayers())
	if RunService:IsStudio() then task.wait(3) else task.wait(10) end
end)
print("e2")

if DebugMode then print(LoadedDataFromCloud) end
if DebugMode then print("Currency amounts after loading", Currencies, Currencygain) end
HideUpgrades["Show"](game.Workspace.Upgrades.Upgrade1)
if DebugMode then print("Initializing UpgradeHandler") end
UpgradeHandler["Initialize"](LoadedDataFromCloud)
Currencies, Currencygain = nil, nil
if DebugMode then print("Finished Initializing UpgradeHandler") end


9 Likes