Leaderstats datastore not working

I’ve tried looking around for a way to fix this error, but havent found anything. Im making leaderstats for a simulator, and for some reason the stats wont save with my datastore script.

The script:

local dataStore = game:GetService("DataStoreService"):GetDataStore("SaveData")

game.Players.PlayerAdded:Connect(function(plr)
	wait()
	local plrid = "id_"..plr.UserId
	
	local save1 = plr.leaderstats.Weight
	local save2 = plr.leaderstats.Protein
	local save3 = plr.leaderstats.Strength
	local save4 = plr.leaderstats.Wins
	
	local GetSaved = dataStore:GetAsync(plrid)
	if GetSaved then
		save1.Value = GetSaved[1]
		save2.Value = GetSaved[2]
		save3.Value = GetSaved[3]
		save4.Value = GetSaved[4]
		
	else
		local NumberForSaving = {save1.Value, save2.Value, save3.Value, save4.Value}
		dataStore:GetAsync(plrid, NumberForSaving)
	end
	
end)

game.Players.PlayerRemoving:Connect(function(plr)
	dataStore:SetAsync("id"..plr.UserId, {plr.leaderstats.Weight.Value, plr.leaderstats.Protein.Value, plr.leaderstats.Strength.Value, plr.leaderstats.Wins.Value})
end)

I can’t figure out whats causing this to happen exactly, but I am getting two errors that might be the source of this problem.

" 19:32:18.622 Players:GetNameFromUserIdAsync() failed: HTTP 429 (Too Many Requests) - Server"
and
" 19:32:15.327 Unable to cast value to Object - Server - Datastore:24"
I don’t know why i’m getting an error for line 24, since thats where the PlayerAdded function ends. So, I’m thinking it might be the http error.

1 Like

I believe you wanted this to be a :SetAsync() call rather than :GetAsync()

1 Like

Why use SetAsync(), that is outdated and flawed in various ways use UpdateAsync().

It’s prolly due to the fact that the server is calling the function plenty of times

2 Likes

I just changed it, but even after I test I got that error

1 Like

So is there anything I could do to remove that error, I don’t know how I would change it.
Previously before I’ve tried to delay it, but that didnt work.

2 Likes

You might want to wrap the getasync and setasync in a pcall function

1 Like

Where are you seen that SetAsync was outdated? According to the documentation SetAsync is not deprecated and is very viable and contains differences with UpdateAsync.

I agree that when updating a player’s data, using UpdateAsync is a better solution. However, if no player-related data is found, using SetAsync to initialize the player’s data for the first time is a good practice in my opinion. It is crucial to distinguish between an API error and non-existent data, such as using the success value obtained from a pcall to determine whether you have successfully accessed what should be the user’s data.

If success is true, you can assume it’s a new user and save this data with SetAsync. Later, you can use UpdateAsync to compare certain data and avoid data loss. In summary, UpdateAsync is not the new SetAsync, but rather a method that works differently and is complementary to SetAsync in creating a module that manages player data.

2 Likes

Thank you for saying the difference between the two, before I was just using two UpdateAsync

1 Like

This is my first time using a pcall function, but this is what I have rn.

local dataStore = game:GetService("DataStoreService"):GetDataStore("SaveData")

game.Players.PlayerAdded:Connect(function(plr)
	wait()
	local plrid = "id_"..plr.UserId

	local save1 = plr.leaderstats.Weight
	local save2 = plr.leaderstats.Protein
	local save3 = plr.leaderstats.Strength
	local save4 = plr.leaderstats.Wins


	local GetSaved = dataStore:GetAsync(plrid)
	if GetSaved then
		save1.Value = GetSaved[1]
		save2.Value = GetSaved[2]
		save3.Value = GetSaved[3]
		save4.Value = GetSaved[4]

	else
		local NumberForSaving = {save1.Value, save2.Value, save3.Value, save4.Value}
		local succes, err = pcall(function()

			dataStore:SetAsync(plrid, NumberForSaving)
			
		end
		)
	end
end)

game.Players.PlayerRemoving:Connect(function(plr)
	local success, err = pcall(function()
		
		dataStore:UpdateAsync("id"..plr.UserId, {plr.leaderstats.Weight.Value, plr.leaderstats.Protein.Value, plr.leaderstats.Strength.Value, plr.leaderstats.Wins.Value})
		
	end)
end)

Currently adding a pcall function doesn’t do anything for me, but I think I just might be doing it wrong.

1 Like

That looks fine, but try adding

if not success then
print(err)
end

after each pcall function to see what could be going wrong

Im getting “unknown global” for success and err for some reason.

1 Like

You write "id_"..plrid in the PlayerAdded function but "id"..plr.UserId in the PlayerRemoving function. So you use two different key because you missed the underscore on the PlayerRemoving function.

After testing your code by creating the leaderstats and the necessary values and changing the key of the PlayerRemoving, I had no problems. I noticed that you added a wait at the start of the function probably because you connected another one to create the leaderstats but I think this is very bad practice. Trying to have only one connection to the PlayerAdded event, it’s a better practice.

local dataStore = game:GetService("DataStoreService"):GetDataStore("SaveData")

game.Players.PlayerAdded:Connect(function(plr)
	local plrid = "id_"..plr.UserId
	print(plrid)

	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = plr

	local save1 = Instance.new("IntValue")
	save1.Name = "Weight"
	save1.Parent = leaderstats

	local save2 = Instance.new("IntValue")
	save2.Name = "Protein"
	save2.Parent = leaderstats

	local save3 = Instance.new("IntValue")
	save3.Name = "Strength"
	save3.Parent = leaderstats

	local save4 = Instance.new("IntValue")
	save4.Name = "Wins"
	save4.Parent = leaderstats

	local GetSaved = dataStore:GetAsync(plrid)
	print(GetSaved)
	if GetSaved then
		save1.Value = GetSaved[1]
		save2.Value = GetSaved[2]
		save3.Value = GetSaved[3]
		save4.Value = GetSaved[4]
	else
		local NumberForSaving = {save1.Value, save2.Value, save3.Value, save4.Value}
		dataStore:SetAsync(plrid, NumberForSaving)
	end
end)

game.Players.PlayerRemoving:Connect(function(plr)
	local leaderstats = plr:WaitForChild("leaderstats")
	print(leaderstats.Weight.Value, leaderstats.Protein.Value, leaderstats.Strength.Value, leaderstats.Wins.Value)
	dataStore:SetAsync("id_"..plr.UserId, {leaderstats.Weight.Value, leaderstats.Protein.Value, leaderstats.Strength.Value, leaderstats.Wins.Value})
end)

This is a completly fixed version of your code:

local DataStoreService = game:GetService("DataStoreService")
local PlayerService = game:GetService("Players")

local dataStore = DataStoreService:GetDataStore("SaveData")

local function RetryFunction(...)
	local tries, success, result = 0, false, nil
	repeat
		tries += 1
		success, result = pcall(...)
	until ((tries >= 4) or success)
	return success, result
end

PlayerService.PlayerAdded:Connect(function(plr)
	local plrid = "id_"..plr.UserId
	
	local success, obtainedData = RetryFunction(dataStore.GetAsync, dataStore, plrid)
	if success then
		-- Create the leaderstats after having found the data to prevent data loss by PlayerRemoving
		local leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = plr
		
		local save1 = Instance.new("IntValue")
		save1.Name = "Weight"
		save1.Parent = leaderstats
		
		local save2 = Instance.new("IntValue")
		save2.Name = "Protein"
		save2.Parent = leaderstats
		
		local save3 = Instance.new("IntValue")
		save3.Name = "Strength"
		save3.Parent = leaderstats
		
		local save4 = Instance.new("IntValue")
		save4.Name = "Wins"
		save4.Parent = leaderstats
		
		-- Assign the obtained data or create a new saving
		if obtainedData then
			save1.Value = obtainedData[1]
			save2.Value = obtainedData[2]
			save3.Value = obtainedData[3]
			save4.Value = obtainedData[4]
		else
			local NumberForSaving = {save1.Value, save2.Value, save3.Value, save4.Value}
			dataStore:SetAsync(plrid, NumberForSaving)
		end
	else
		-- Data loss prevention
		warn(obtainedData) -- Print error
		plr:Kick("Data loss prevention: Sorry, we are unable to obtain your data, please try to log in again later.")
	end
end)

PlayerService.PlayerRemoving:Connect(function(plr)
	local leaderstats = plr:FindFirstChild("leaderstats")
	if leaderstats then
		local value1 = leaderstats:FindFirstChild("Weight")
		local value2 = leaderstats:FindFirstChild("Protein")
		local value3 = leaderstats:FindFirstChild("Strength")
		local value4 = leaderstats:FindFirstChild("Wins")
		if value1 and value2 and value3 and value4 then
			dataStore:SetAsync("id_"..plr.UserId, {value1.Value, value2.Value, value3.Value, value4.Value})
		end
	end
end)

I created a function to try to obtain the data with 4 tries maximum. If you are unable to access the API then Roblox has a problem and I advise you to kick the player so as not to rewrite this data.

If you want to know more about pcall you can read the documentation by clicking on the blue text.

In PlayerRemoving I decided to try to find all the values before assigning them to the data store. I think this could cause problems but in any case using values as you do is in my opinion bad practice. Instead, try opting for a table-based structure and using a ModuleScript to create your database system.

If you have any questions, please don’t hesitate to ask me. I don’t know if I was very clear in my explanations but if you copy and paste my code it should work.

1 Like

This worked, thank you. I don’t know I just completely missed the “_” I forgot to add. Thank you for also telling me about having two scripts connected to PlayerAdded, i’ll try not to do it in the future.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.