Roblox data store broken. Random players losing their stats every server shutdown

Wrap this in a coroutine so it saves all the players’ data at once.

Also, I don’t see any autosaving?

Edit: How to use corountines:

if RunService:IsStudio() then
		return
	end
	for _,plr in pairs(game.Players:GetPlayers()) do
        corountine.wrap(function()
		local PlayerUserId = "Player_"..plr.UserId

		local data = {
			Strength = plr.leaderstats.Strength.Value;
		}

		local success, errormessage = pcall(function()
			DataStore:UpdateAsync(PlayerUserId, function(OldData)
				return data
			end)
		end)

		if success then
			print('Data Successfully Saved!')
		end
		if errormessage then
			print('Data UnSuccessfully Saved!')
			warn(errormessage)
		end
        end)()
	end

The auto data save script is in a different script.

I have an auto save script and im using game:closetobind() and players are still losing their stats! I don’t get why its still happening

Sorry for bumping this topic a lot of times but i REALLY need help right now.

1 Like

It has been 18 hours and still no answer.

But then i would need to reset everyone’s data

You should switch while you have less players.

1 Like

My game once reached 30 playings while that bug existed and one of my players spent 100 hours playing my game so no.

Can you show the autosaving script?

I already showed the auto saving script.

This should work perfectly. As some people have already mentioned, you need to make sure it is saving data when the player leaves, and when the server is being shutdown.

To detect when the server is shutting down you can use the BindToClose event. You should make it that when the server is shutting down, before closing the server, it goes through every player in game and saves their data. This may back up your datastore, so make sure to add a small delay between each player in the loop. But, since the server is shutting down anyways, it shouldn’t be an issue.

1 Like

Also, one minor issue with your above script is that exploiters can spam the Autosave event, which would backup your datastore. You should add a server-sided cooldown for the autosave event.

1 Like

So like this?

--insert save function here
function onShutdown()
	for _,plr in ipairs(game.Players:GetPlayers()) do
		coroutine.wrap(save)(plr)
	end
end
game:BindToClose(function()
	onShutdown()
	wait(1)
end)

I wouldn’t use the coroutines, so it doesn’t go too fast. Also, after running the save function, make sure to add a small wait, maybe just wait().

This is what I would revise

local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("DataStore3")
local DataStore1 = DataStoreService:GetDataStore("Pets4")
local DataStore2 = DataStoreService:GetDataStore("PetsEquips1")

local function save(plr)
    local PlayerUserId = "Player_"..plr.UserId

	local data = {
		Strength = plr.leaderstats.Strength.Value;
		Prestige = plr.SecretFolder.Prestige.Value;
		Cash = plr.leaderstats.Cash.Value;
		StrengthMulti = plr.SecretFolder.StrengthMulti.Value;
		Rank = plr.SecretFolder.Rank.Value;
		TimePlayed = plr.SecretFolder.TimePlayed.Value;
		Rebirths = plr.SecretFolder.Rebirths.Value;
		RobuxDonated = plr.SecretFolder.RobuxDonated.Value;
		StrengthMultiplier = plr.SecretFolder.StrengthMultiplier.Value;
		CashMultiplier = plr.SecretFolder.CashMultiplier.Value;
		EggsHatched = plr.leaderstats.EggsHatched.Value;
	}

	DataStore:UpdateAsync(PlayerUserId, function(OldData)
			return data
	end)
	local key = "pets-"..plr.UserId
	local activated = {}

	for i,v in pairs(plr.Pets:GetChildren()) do
		if v:IsA("BoolValue") then
			table.insert(activated, v.Name)
		end
	end
	DataStore1:SetAsync(key,activated)
	local key = "petsequip-"..plr.UserId
	local activated = {}

	for i,v in pairs(plr.Equipped:GetChildren()) do
		if v:IsA("BoolValue") then
			table.insert(activated, v.Name)
		end
	end
	DataStore2:SetAsync(key,activated)
end

local function onShutdown()
	for _,plr in pairs(game.Players:GetPlayers()) do
		save(plr)
        wait()
	end
end

game:BindToClose(function()
	onShutdown()
	wait(1)
end)

local cooldown = {}

game.ReplicatedStorage.AutoSave.OnServerEvent:Connect(function(plr)
    local t = tick()
    if cooldown[plr.Name]==nil or t-cooldown[plr.Name]>=250 then
        -- It has been at least 250 seconds since the last time the event was fired by the player
        cooldown[plr.Name]=t
        save(plr)
    end
end)

game.Players.PlayerRemoving:Connect(save)

Thats a bit too complex. I would rather use the debounce method instead

This should actually just be your full script. I filled out the save function as well

I made some edits. I know you’re not supposed to give people an entire script, but that script should be fully functional.

But that doesn’t account for time. The tick function returns a number of seconds, and always increases. This could be used to check how much time has passed since the last time the event was fired by the player.