DataStore not saving

Hello. My datastore is not saving the data after I leave the game. Can anyone tell me what’s wrong? This is my code:

local dss = game:GetService("DataStoreService")
local ds = dss:GetOrderedDataStore("1")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

game.Players.PlayerAdded:Connect(function(player)
	
	local playerKey = "Player_"..player.UserId
	
	local leaderstats = Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"
	
	local money = Instance.new("IntValue", leaderstats)
	money.Name = "Money"
	money.Value = ds:GetAsync(playerKey.."money") or 0
	ds:SetAsync(playerKey.."money", money.Value)	
	
	local level = Instance.new("IntValue", leaderstats)
	level.Name = "Level"
	level.Value = ds:GetAsync(playerKey.."level") or 1
	ds:SetAsync(playerKey.."level", level.Value)	
	
	local exp = Instance.new("IntValue", leaderstats)
	exp.Name = "Exp"
	exp.Value = ds:GetAsync(playerKey.."exp") or 100
	ds:SetAsync(playerKey.."exp", exp.Value)	
	
	local income = Instance.new("IntValue", leaderstats)
	income.Name = "Income"
	income.Value = ds:GetAsync(playerKey.."income") or 0
	ds:SetAsync(playerKey.."income", income.Value)	
	
	local mg1 = Instance.new("IntValue", leaderstats)
	mg1.Name = "mg1"
	mg1.Value = ds:GetAsync(playerKey.."mg1") or 0
	ds:SetAsync(playerKey.."mg1", mg1.Value)
	
	local mg10 = Instance.new("IntValue", leaderstats)
	mg10.Name = "mg10"
	mg10.Value = ds:GetAsync(playerKey.."mg10") or 0
	ds:SetAsync(playerKey.."mg10", mg10.Value)
	
	local mg100 = Instance.new("IntValue", leaderstats)
	mg100.Name = "mg100"
	mg100.Value = ds:GetAsync(playerKey.."mg100") or 0
	ds:SetAsync(playerKey.."mg100", mg100.Value)
	
	local mg1k = Instance.new("IntValue", leaderstats)
	mg1k.Name = "mg1k"
	mg1k.Value = ds:GetAsync(playerKey.."mg1k") or 0
	ds:SetAsync(playerKey.."mg1k", mg1k.Value)
	
	local mg10k = Instance.new("IntValue", leaderstats)
	mg10k.Name = "mg10k"
	mg10k.Value = ds:GetAsync(playerKey.."mg10k") or 0
	ds:SetAsync(playerKey.."mg10k", mg10k.Value)
	
	local mg100k = Instance.new("IntValue", leaderstats)
	mg100k.Name = "mg100k"
	mg100k.Value = ds:GetAsync(playerKey.."mg100k") or 0
	ds:SetAsync(playerKey.."mg100k", mg100k.Value)
	
	local function updateStats()
		ds:SetAsync(playerKey.."money", money.Value)
		ds:SetAsync(playerKey.."level", level.Value)
		ds:SetAsync(playerKey.."exp", exp.Value)
		ds:SetAsync(playerKey.."income", income.Value)
		ds:SetAsync(playerKey.."mg1", mg1.Value)
		ds:SetAsync(playerKey.."mg10", mg10.Value)
		ds:SetAsync(playerKey.."mg100", mg100.Value)
		ds:SetAsync(playerKey.."mg1k", mg1k.Value)
		ds:SetAsync(playerKey.."mg10k", mg10k.Value)
		ds:SetAsync(playerKey.."mg100k", mg100k.Value)
		print("Updated")
	end
	
	while true do
		wait(1)
		money.Value = money.Value + income.Value
	end
	
	money.Changed:Connect(function()
		if money.Value > exp.Value then
			level.Value = level.Value + 1
			exp.Value = exp.Value*1.2
			print("money is greater than exp")
		end
	end)



	game:BindToClose(function()
	    -- if the current session is studio, do nothing
	    if RunService:IsStudio() then
	        return
	    end
	 
	    print("saving player data")
	 
	    -- go through all players, saving their data
	    local players = Players:GetPlayers()
	    for _, player in pairs(players) do
	        local userId = player.UserId
	        if 1==1 then
	            -- wrap in pcall to handle any errors
	            local success, result = pcall(function()
					-- SetAsync yields so will stall shutdown
					ds:SetAsync(playerKey.."money", money.Value)
					ds:SetAsync(playerKey.."level", level.Value)
					ds:SetAsync(playerKey.."exp", exp.Value)
					ds:SetAsync(playerKey.."income", income.Value)
					ds:SetAsync(playerKey.."mg1", mg1.Value)
					ds:SetAsync(playerKey.."mg10", mg10.Value)
					ds:SetAsync(playerKey.."mg100", mg100.Value)
					ds:SetAsync(playerKey.."mg1k", mg1k.Value)
					ds:SetAsync(playerKey.."mg10k", mg10k.Value)
					ds:SetAsync(playerKey.."mg100k", mg100k.Value)
					print("Updated")
	            end)
	            if not success then
	                warn(result)
	            end    
	        end
	    end
	 
	    print("completed saving player data")
	 
	end)
	game.Players.PlayerRemoving:Connect(updateStats)
end)
1 Like

Any errors, Is everything not saving or only some? Also try adding prints to further narrow down your issue.

There are no errors. I only have a button in my game that gives money, and I know it’s working because the money increases in the leaderboard. But when I rejoin the game it goes back to 0.

It’s also not printing “Updated” when I click stop on roblox studio testing mode.

Are you testing it in studio or in game?
Try publishing and testing it in game.

-- if the current session is studio, do nothing
if RunService:IsStudio() then
    return
end

Removing these lines of code should make it work in Studio.

ds:SetAsync(playerKey.."money", money.Value)
ds:SetAsync(playerKey.."level", level.Value)
ds:SetAsync(playerKey.."exp", exp.Value)
ds:SetAsync(playerKey.."income", income.Value)
ds:SetAsync(playerKey.."mg1", mg1.Value)
ds:SetAsync(playerKey.."mg10", mg10.Value)
ds:SetAsync(playerKey.."mg100", mg100.Value)
ds:SetAsync(playerKey.."mg1k", mg1k.Value)
ds:SetAsync(playerKey.."mg10k", mg10k.Value)
ds:SetAsync(playerKey.."mg100k", mg100k.Value)

This is going to create ENORMOUS DataStore queues, and is the most likely culprit of why your data doesn’t save.

Why not switch to a generic DataStore, put all of the information in a table and save it all under one key? All it takes is a bit of elbow grease and you’re right on track!

ds = game:GetService("DataStoreService"):GetDataStore("1")
local data = {
	money = money.Value;
	level = level.Value;
	exp = exp.Value;
	income = income.Value;
	mg1 = mg1.Value;
	mg10 = mg10.Value;
	mg100 = mg100.Value;
	mg1k = mg1k.Value;
	mg10k = mg10k.Value;
	mg100k = mg100k.Value
}

ds:SetAsync(playerKey.."data", data)

You are able to save the data like this, using playerKey.."data" and writing all of the players data to that one key.

Another issue is that you are trying to call SetAsync after each value is fetched, which is only going to add to a queue that prevents data from loading properly. I’ve gone ahead and removed the pointless SetAsync calls, as well as transferred your GetAsync spam to using the one key system.

local leaderstats = Instance.new("Folder", player)
leaderstats.Name = "leaderstats"

local data = ds:GetAsync(playerKey.."data")

local money = Instance.new("IntValue", leaderstats)
money.Name = "Money"
money.Value = data.money or 0
	

local level = Instance.new("IntValue", leaderstats)
level.Name = "Level"
level.Value = data.level or 1	

local exp = Instance.new("IntValue", leaderstats)
exp.Name = "Exp"
exp.Value = data.exp or 100	

local income = Instance.new("IntValue", leaderstats)
income.Name = "Income"
income.Value = data.income or 0

local mg1 = Instance.new("IntValue", leaderstats)
mg1.Name = "mg1"
mg1.Value = data.mg1 or 0

local mg10 = Instance.new("IntValue", leaderstats)
mg10.Name = "mg10"
mg10.Value = data.mg10 or 0

local mg100 = Instance.new("IntValue", leaderstats)
mg100.Name = "mg100"
mg100.Value = data.mg100 or 0

local mg1k = Instance.new("IntValue", leaderstats)
mg1k.Name = "mg1k"
mg1k.Value = data.mg1k or 0

local mg10k = Instance.new("IntValue", leaderstats)
mg10k.Name = "mg10k"
mg10k.Value = data.mg10k or 0

local mg100k = Instance.new("IntValue", leaderstats)
mg100k.Name = "mg100k"
mg100k.Value = data.mg100k or 0

Some things I won’t fix for you but are certainly issues:

  • You are writing your BindToClose and PlayerRemoving function inside of your PlayerAdded function, which is very inefficient, you shouldn’t have them written inside each other, you should have them written separately in the scope of the script.
  • You are including 10 values in leaderstats and only a small percentage of those can actually be shown on the leaderboard, I recommend keeping important stats such as “money” and “level” on the leaderboard, but keeping everything else in a separate folder.
  • You are using the second value of Instance.new to set it’s parent which isn’t recommended and sacrafices performance, it’s much better to define the Instance and it’s values, then setting the parent using [Instance].Parent = parent
  • As I mentioned, you are using an OrderedDataStore in this example, which by no means should be used to store as much data as you are attempting to - and it CERTAINLY should not be an alternative to a generic DataStore for holding player data.

If this still doesn’t work (and you are testing in studio), make sure to enable Studio API Access in Game Settings -> Security.

3 Likes

You have an update function written that you chose not to use and opted to instead just copy and paste its contents, you have a useless if 1==1 then condition, and you have game:BindToClose() inside an individual player’s onPlayerAdded function, which normally wouldnt be an issue but here you loop through everyone for some reason, saving that single player’s data many times on a uselessly large number of data stores. Without having even tried to read the whole script, I can tell that the DataStore budget is being exceeded and with it, most of the data doesn’t get saved.

I’m sorry if this isn’t helpful, but something tells me you just copied and pasted a lot of code, like a Frankenstein creating his monster. You need to learn more of the basics before you try something like this. I tried using DataStores back in 2017 when I first started programming, and even now I’m still learning how to use it.

Thanks a lot! I was having a lot of trouble in organizing myself with this many values and this is what I needed.

Actually all of the code was made by myself, except for the BindToClose() function, which was taken from the Api reference. I’m just having trouble because I’m a beginner and it’s the first time I make a game with this many values.

Don’t worry, everybody makes these kind of mistakes! Don’t take it too harsh, its a learning experience.

(Datastores aren’t the simplest thing.)

1 Like