I'm having data loss

Hello, I have a leaderstats script which has Coins, Gems etc…
Saving and loading data works fine but I’m having few data loss everyday.

I tried using UpdateAsync(), but it’s way too complicated, and I couldn’t figure out, how am I going to optimize the UpdateAsync() to my all datas.

My script:

-- // Service \\ --

local DataStoreService = game:GetService("DataStoreService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")






-- // Pre-Created Variables \\ --

local CoinsData = DataStoreService:GetDataStore("COINS-V9.0.0")
local GemData = DataStoreService:GetDataStore("GEMS-V8.0.0")
local PlanetData = DataStoreService:GetDataStore("PLANET-V7.0.0")
local RebirthData = DataStoreService:GetDataStore("REBIRTH-V7.0.0")


-- // Functions \\ --


local function CheckRebirths(Player,Rebirth)
	
	local Price = 0

	if Rebirth == 0 then
		Price = 1000
	
	
	else

		Price = Rebirth * 5000
	end
	Player.RebirthPrice.Value = Price
	
	ReplicatedStorage.RemoteEvents.SendRebirthInfo:FireClient(Player, Price)
	
end




game.Players.PlayerAdded:Connect(function(Player)
	
	
	local RebirthPrice = Instance.new("IntValue")
	RebirthPrice.Name = "RebirthPrice"
	RebirthPrice.Parent = Player
	
	
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = Player
	
	local Coins = Instance.new("IntValue")
	Coins.Name = "Coins"
	Coins.Parent = leaderstats
	Coins.Value = CoinsData:GetAsync(Player.UserId,Coins.Value) or 0
	
	local Gems = Instance.new("IntValue")
	Gems.Name = "Gems"
	Gems.Parent = leaderstats
	Gems.Value = GemData:GetAsync(Player.UserId, Gems.Value) or 0
	
	
	local Planet = Instance.new("IntValue")
	Planet.Name = "Planet"
	Planet.Parent = leaderstats
	Planet.Value = PlanetData:GetAsync(Player.UserId, Planet.Value) or 0
	
	local Rebirths = Instance.new("IntValue")
	Rebirths.Name = "Rebirths"
	Rebirths.Parent = leaderstats
	Rebirths.Value = RebirthData:GetAsync(Player.UserId, Rebirths.Value) or 0
	
	
	CheckRebirths(Player, Rebirths.Value)
	
	
	
	
	game.Players.PlayerRemoving:Connect(function(plr)
		print("Data saved.")

	
			print("Updating.")
			GemData:SetAsync(plr.UserId, Gems.Value)
			CoinsData:SetAsync(plr.UserId,Coins.Value)
			PlanetData:SetAsync(plr.UserId, Planet.Value)
			RebirthData:SetAsync(plr.UserId, Rebirths.Value)
	
	
	end)

	
end)


ReplicatedStorage.RemoteEvents.GetPlanet.OnServerEvent:Connect(function(plr, amount)
	plr.leaderstats.Planet.Value += amount
	
end)


ReplicatedStorage.RemoteEvents.Rebirth.OnServerEvent:Connect(function(user)
	local newPrice = 0
	

	
	
	user.leaderstats.Coins.Value -= user.RebirthPrice.Value
	
	user.leaderstats.Rebirths.Value += 1
user.leaderstats.Gems.Value += 1
	
newPrice = user.leaderstats.Rebirths.Value * 5000
	
	
	
	
	
	user.leaderstats.Coins.Value = 0
	user.leaderstats.Planet.Value = 0

		

	
	CheckRebirths(user, user.leaderstats.Rebirths.Value)
end)

Thank you!

2 Likes

Hello!

There is many issues I can see within this script and I will try my best to explain them all.

  1. Your PlayerRemoving function should not be inside the PlayerJoined Function and should be seperate.
  2. You should be using pcall()'s to catch any issues if your are not able to receive the players data.
  3. I highly recommend combining all your datastores into one by saving a table to one datastore instead.

Here is an example of a datastore I have created:

local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("PlayerData")

local CreateLeaderstats = function(Player, Data)
	-- Do leaderstats stuff.
	print(Data.Coins) -- Example of new table system.
end

game.Players.PlayerAdded:Connect(function(Player)
	local Attempts = 0
	RequestData = function()
		local Success, Data = pcall(function()
			return DataStore:GetAsync(Player.UserId)
		end)
		
		if Success then
			if Data then
				-- They have previous saved data.
				CreateLeaderstats(Player, Data)
			else
				--New player
				local Data = {
					["Coins"] = 100,
					["Gems"] = 10,
					--Etc
				}
				CreateLeaderstats(Player, Data)
			end
		else
			if Attempts < 3 then -- If not able to get data try again.
				Attempts = Attempts + 1
				wait(5) -- To prevent datastore request dropping.
				RequestData()
			else
				Player:Kick("Error loading data.")
			end
		end
	end
	RequestData()
end)

game.Players.PlayerRemoving:Connect(function(Player)
	local Data = {
		["Coins"] = Player.leaderstats.Coins.Value,
		["Gems"] = Player.leaderstats.Gems.Value,
	}
	DataStore:SetAsync(Player.UserId, Data)
end)
3 Likes

Thanks for you answer, I’ll try that.

I’ve updated my answer with an example.

1 Like

Data loss is not too common, however not impossible.
I would recommend using ProfileService as it has excellent features, including session-locking (useful if you have a trading system as it prevents duplication and so on).

ProfileService
ProfileService — API

Regardless, I do suggest that you add a game:BindToClose() and save on an interval, ex. every 2-3 minutes.
You should also wrap your calls in a pcall (protected call) and handle errors when they occur.

The last thing I suggest is having everything inside a table, like this:

local SaveTable = {
	GEMS		= 0,
	COINS 		= 0,
	REBIRTHS	= 0,
	PLANET		= 'DEFAULT VALUE',
}

That way, you only need to write to the datastore once, and don’t risk some of the calls failing.
Usage: DataStoreKey:SetAsync(Key, SaveTable)

2 Likes

The load will be like this right?

local coins = data:GetAsync(plr.UserId, Table[1])

You should access it as Table.NAME_HERE or Table[‘NAME_HERE’] as the order it is saved in is not like the way you set it up.

No it would be

local coins = data:GetAsync(plr.UserId).Coins

But you should be doing

local data = data:GetAsync(plr.UserId)
local coins = data.Coins

That is possible but that could cause some severe glitches

Okay thanks, let me try it.
30

Not sure what you mean there. In what sense? This is the way you access the values of keys in a dictionary. Dictionaries are best practice for working with DataStores.

Yeah I just understood your sentence now. Sorry for the confusion.

Thank you very much it works!
I edited fellow parts and it works*