DataStore Problem/Data Loss

Thanks, I added BindToClose() to the code but data loss problem persists. People still reports completely deleted data.

It would probably be helpful if you knew what error the pcall is giving. You could either have the pcall displayed on the clients screen when the data is auto saved or you can send the error to a discord webhook with the player name and the data if you want. Just be sure not to spam the discord webhook.

Why are you using GetAysnc when the player is leaving? i think it would be better to call that once, when the player joins. if you needed a way to check if a player has new data you should use UpdateASync() as it returns the previously stored data and allows you to update it at the same, furthermore adding a BindtoClose (as kind of mentioned above) and placing a wait inside should make the server wait (given amount, max is 30secs ) before fulling closing, thus allowing time for all players data to save( in theory) , here’s what i mean:

game:BindToClose(function()---Fired when the server is about to close
  wait(10) -----wait
print("ServerClosing")
end)
1 Like

I added BindtoClose() to the code but data loss problem persists. And UpdateASync() is not working on this situation. So I have to use SetASync() for now. (PlayerRemoving function)

I’m using GetAysnc to check data, it’s like; if one of player data is less than saved data, don’t save.

What do you mean UpdateAsync() is not working in this situation? From past experience, that would suggest an issue with values, not the actual saving/loading.

Some data is saving and some is not right( so its not that its not saving any data at all)?

What if there is all of that values are strings, which is you can’t use UpdateAsync()? I want that solution actually. There must be a solution about that.

You can use UpdateAsync for anything that set Async can save as well, so you can save strings using it For example: (using your set-up)

(this is just some quick pseudo code, you probably should modify it)

  local success, message = pcall(function()
DataStore:UpdateAsync(PlayerKey, function(oldData)
if oldData == nil then
 return Saving ----returns saving, (table)
     else
         --Save other data using return
                end
         end)

      end

end

https://developer.roblox.com/en-us/api-reference/function/GlobalDataStore/UpdateAsync

Can you explain me more the else statement in that script? Because it’s not saving data if there are data.

If the game shuts down unexpectedly the data will not save. The reason is because the BindToClose function will not work if it is in the PlayerRemoving Function. PlayerRemoving does not fire if the server unexpectedly shuts down. If I were you I would create a save function(Be sure to put pcalls and if you could DataStore the pcall errors and check them that would probably give you the answer to Data Loss). Like so

function saveData(plr)
    --Code to save
end

Then you call this function to Save Data when player is leaving.

game.Players.PlayerRemoving:Connect(function(plr)
       saveData(plr)
end)

If the server shuts down BindToClose is going to save the data.

game:BindToClose(function()
	for _,v in pairs(game.Players:GetChildren()) do
		saveData(v.Name) -- v is the player name
	end
end)

There is a Example BindToClose script here. If this still doesn’t help could you take a picture of the PlayerSave folder.

2 Likes

game:BindToClose(function()
saveData(plr) --?
end)

How to detect plr (Player) on BindToClose()?

Thanks for pointing that out i fixed the post.

I left out the local for plr.

game:BindToClose(function()
local plr = game.Players.LocalPlayer.Name
saveData(plr)
end)

A better option would be too do

game:BindToClose(function()
	for _,v in pairs(game.Players:GetChildren()) do
		saveData(v.Name) -- v is the player name
	end
end)

In this example, v would not be the player name, v would be the player instance. You’d need to say v.Name to get the actual player name.

I made a tutorial on YouTube using this code. It seems to work for me (this version is untested).

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetDataStore("name_here")

local dataLoaded = false
local tries = 3

local function Set(plr)
	if dataLoaded then
		local key = "key#-" .. plr.UserId
		
		local data = {
			["currency1"] = plr.leaderstats.name.Value,
			["currency2"] = plr.leaderstats.name2.Value
		}
		
		local success, err
		local count = 0
		
		repeat
			success, err = pcall(function()
				dataStore:SetAsync(key, data)
			end)
			
			count = count + 1
			
			wait(0.5)
		until count >= tries or success
		
		if not success then
			warn("Failed to serialize data. Error code: " .. tostring(err))
			
			return
		end
	end
end

local function Get(plr)
	local key = "key#-" .. plr.UserId
	
	local serialized
	local success, err
	
	local count = 0
	
	repeat
		success, err = pcall(function()
			serialized = dataStore:GetAsync(key)
		end)
		
		count = count + 1
		
		wait(0.5)
	until count >= tries or success
	
	if not success then
		warn("Failed to read data. Error code: " .. tostring(err))
		
		return
	end
	
	if serialized then
		return serialized
	else
		local starterStats = {
			["currency1"] = 10,
			["currency2"] = 20
		}
		
		return starterStats
	end
end

local function CreateStats(plr)
	local stats = Instance.new("Folder")
	stats.Name = "leaderstats"
	stats.Parent = plr
	
	local data = Get(plr)
	
	local currency1 = Instance.new("IntValue")
	currency1.Name = "name"
	currency1.Parent = stats
	
	local currency2 = Instance.new("IntValue")
	currency2.Name = "name2"
	currency2.Parent = stats
	
	currency1.Value = data.currency1
	currency2.Value = data.currency2
	
	dataLoaded = true
	Set(plr)
end

game:BindToClose(function()
	for _, v in pairs(game.Players:GetChildren()) do
		Set(v.Name) -- v.Name is the player name
	end
end)

Players.PlayerAdded:Connect(CreateStats)
Players.PlayerRemoving:Connect(Set)

You forgot to add a BindToClose function. This needs to be added just incase of server shutdown data won’t be lost. It is better to use UpdateAsync than SetAsync.

game:BindToClose(function()
	for _,v in pairs(game.Players:GetChildren()) do
		Set(v.Name) -- v.Name is the player name
	end
end)
2 Likes

Really, the only solution is to change to a new system, unfortunately you will have to rewrite everything.

UpdateASync() caused more problems somehow. (More reports coming about data loss now)

There’s a lot of data here, and people bought items/upgrades with real money. So I can’t rewrite everything, data scheme must remain the same.

It would make it easier if you provide a screenshot of the PlayerSave tell us if its Bool,Number,String values. The Player that reports data loss is it just certain data(if so which value) or is the whole safe getting wiped?

All data getting wiped somehow.

(I know the screenshot has more data than script but, I just added part of the script here)