Made Several Data Store Scripts, None Successful

Hey, so I’ve made many data store scripts following many YouTube videos. I have API Services on, I have the place published to Roblox, and I am 99% sure that I didn’t mis spell or incorrectly capitalize anything. The problem is that when I leave the game, it doesn’t save and I have tried many different script styles. I would very much appreciate any help, thanks :slight_smile:

Here is my script:

local DSS = game:GetService("DataStoreService")
local myDS = DSS:GetDataStore("myDataStore")

game.Players.PlayerAdded:Connect(function(player)
	
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	print("Made leaderstats!")
	
	local Coins = Instance.new("IntValue")
	Coins.Name = "Coins"
	Coins.Parent = leaderstats
	print("Made Coins!")
	
	local playerUserId = "Player_"..player.UserId
	print(playerUserId)
	
	-- Load data
	
	local data -- Makes it work in the WHOLE script
	local success, errormessage = pcall(function()
		data = myDS:GetAsync(playerUserId)
	end)
	
	if success then
		Coins.Value = data
		-- Set Coins = to the data
		print("Loaded data!")
	end


end)


game.Players.PlayerRemoving:Connect(function(player)
	local playerUserId = "Player_"..player.UserId
	
	local data = player.leaderstats.Coins.Value
	
	local success, errormessage = pcall(function()
		myDS:SetAsync(playerUserId, data)
	end)
	
	if success then
		print("Data save was successfull!")
	else
		print("Data save failed :(")
		warn(errormessage)
	end
	
end)
2 Likes

Try using update async instead of set async.

1 Like

in studio sometimes it wont save the data, try using game:bindtoclose but don’t remove the player removing part. make sure you have api services on

1 Like

I believe you’ll want to do a return statement here instead of data =

Try it like this…

local data -- Makes it work in the WHOLE script
	local success, results = pcall(function()
	   return myDS:GetAsync(playerUserId)
	end)
if success then
    if results then
    	Coins.Value = results
    	-- Set Coins = to the data
    	print("Loaded data!")
end

This could resolve your issue as long as the data is being set into the datastore. One thing to note is that using UpdateAsync is safer than just strictly using SetAsync as you can check the old data before you modify the values.

Inside PlayerAdded…

    local initialCoins = 50

      local data -- Makes it work in the WHOLE script
        	local success, results = pcall(function()
      		   return myDS:GetAsync(playerUserId)
        	end)
        if success then
            if results then
    	    	Coins.Value = results
    	    	-- Set Coins = to the data
    	    	print("Loaded data!")
            else
  --If interested in setting the initial value into the datastore immediately if the player doesn't have the value yet set (hasn't joined before)
            local s, r = pcall(function()
                myDS:SetAsync(playerUserId, initialValue) 
            end)
    	end

Inside PlayerRemoving

local success, errormessage = pcall(function()
	myDS:UpdateAsync(playerUserId, function(oldValue)
        --Inside here you could compare the old data before setting the new data. Good if you don't want players to go backwards in some instances. What if there was a quest they shouldn't be able to do again? We can do this by checking our old values vs the new ones. For our purposes though...
        local newValue = player.leaderstats.Coins.Value
        return newValue

    end)
end)

And as @RareFeeling stated, Game:BindToClose() should be used. Since you’re on studio, it’s closing the game before it can write to the Datastore, which also could happen when published if the last player leaves your server.

1 Like

Alot of ppl have trouble with trying to save on player removing instead of just that you should do autosave but not just autosave every minute or so only save players data that has changed so it doesn’t overload the datastores as much to do this I edited your code some by moveing your save into a function and calling it on remove and in while loop
also i fixed your Coins.Value = data to Coins.Value = data or 0 because if the player has never had data it can come back nil so set it to 0 as default if you want them to start with 100 coins put the value there

local DSS = game:GetService("DataStoreService")
local myDS = DSS:GetDataStore("myDataStore")
local PlayersToSave = {}   -- setup a table to hold players that the data has changed on 
local TimeBetweenAutoSave = 60 -- the time between each autosave check if they are in table above to save

function SavePlayersData(player)  -- the save function itself call by remove and by autosave
	local playerUserId = "Player_"..player.UserId

	local data = player.leaderstats.Coins.Value

	local success, errormessage = pcall(function()
		myDS:SetAsync(playerUserId, data)
	end)

	if success then
		print("Data save was successfull!")
	else
		print("Data save failed :(")
		warn(errormessage)
	end
end


game.Players.PlayerAdded:Connect(function(player)

	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	print("Made leaderstats!")

	local Coins = Instance.new("IntValue")
	Coins.Name = "Coins"
	Coins.Parent = leaderstats
	print("Made Coins!")

	local playerUserId = "Player_"..player.UserId
	print(playerUserId)

	-- Load data

	local data -- Makes it work in the WHOLE script
	local success, errormessage = pcall(function()
		data = myDS:GetAsync(playerUserId)          -- !!!! if data has never been set this will return successful and data will be nil
	end)

	if success then
		Coins.Value = data or 0     -- !!!! this will set a default to the coins incase they don't have any data which would be nil
		-- Set Coins = to the data
		print("Loaded data!")
	end

	
	Coins.Changed:Connect(function()   -- this catches the change of the coins value either add or subtracted any change to it will then add them to the autosave table for next loop to save the data
		table.insert(PlayersToSave,player)  -- add the player to this table because their data has changed
	end)
	
end)


game.Players.PlayerRemoving:Connect(function(player)
	if table.find(PlayersToSave,player) then  -- if the players data changed they will be in this table so save their data on remove else don't   -- you can remove this and just do a save here if you want but may overload datastore
		SavePlayersData(player)  -- save when they leave if it can sometimes this doesn't save in studio
		table.remove(PlayersToSave,table.find(PlayersToSave,player))    -- after save then remove them from the table
	end
end)

while true do   -- this autosave loop only saves player data if it has changed
	wait(TimeBetweenAutoSave)
	spawn(function()  -- spawn incase of error
		for _, player in ipairs(PlayersToSave) do  -- go through all the players in the PlayersToSave because their data changed and save them
			SavePlayersData(player)  -- save when they leave if it can sometimes this doesn't save in studio
			table.remove(PlayersToSave,table.find(PlayersToSave,player))    -- after save then remove them from the table
		end
	end)
end
1 Like
1 Like

Just to make sure you are changing your coins value on the server correct? if not it will save the value that the server has which would be the default.

as @Nyonic said PlayerRemoving isn’t very reliable in my experience. I haven’t used it in a while so they may have fixed some of the issues but, when the player crashes be it from internet connection going out, pc crashing, or Roblox crashing it doesn’t always fire before the player object is removed. So, typically you would get cases of data loss, but it should still work in your case if you are just leaving. As mentioned several times its probably the server shutting down before the data gets saved so you should try bindtoclose to fix this issue. If you wish to change playerremoving you would have to use game.Players.ChildRemoved:Connect() and you would store your stats somewhere else like replicated storage. This will make it so if the player object is removed you are still able to reference it and the players data.

1 Like

Yea this is just me using his code and adding the auto save with auto save at 60 seconds they can only lose data up to 1 min ago if crash I have a lot of experience in dealing with datastore on game that was crashing. you can bind to close but either way the best option is to hold a table like the one for saving the player with each players data then access the data with the players name when the removing or bind function is called which allows data access even when player isn’t present in the game only reason it wont totally save is on a server crash out which then your autosave feature would cover this in most cases

This is how my systems are setup and no one has lost data yet on them that I know of

so in his code he could add PlayerData = {} – table then initial PlayerData[Player.Name] = Coins.Value
and when it changes in that function for coins set it there also with PlayerData[Player.Name] = Coins.Value

then in the save function instead of saving the coins value just save the PlayerData[Player.Name]
on playerremoving remove them from the table with PlayerData[Player.Name] = nil

I even have exp with datastore2 which imo isn’t a very good or reliable system in many ways its limited and more complicated than it needs to be (unless it has gotten some good updates over the last year)

1 Like

use game:bindtoclose(), if you test by yourself the server stops before playerremoving finishes and the data doesn’t save

1 Like

Thank you very much Nyonic! I am a beginner but I will try to fully understand this. Your game, Club Nyonic is one of the first games I ever played and I really like it :smiley:

Nyonic, thank you very much for the script! I used it in my game. I named it CoinsSave and put it in ServerScriptService. I published my place and went on to it via Roblox and increased my coins and it didn’t save :frowning: I almost think it is a problem with Roblox or something but probably not.

local DSS = game:GetService("DataStoreService")
local myDS = DSS:GetDataStore("myDataStore")
local PlayersToSave = {}   -- setup a table to hold players that the data has changed on 
local TimeBetweenAutoSave = 60 -- the time between each autosave check if they are in table above to save

function SavePlayersData(player)  -- the save function itself call by remove and by autosave
	local playerUserId = "Player_"..player.UserId

	local data = player.leaderstats.Coins.Value

	local success, errormessage = pcall(function()
		myDS:SetAsync(playerUserId, data)
	end)

	if success then
		print("Data save was successfull!")
	else
		print("Data save failed :(")
		warn(errormessage)
	end
end


game.Players.PlayerAdded:Connect(function(player)

	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	print("Made leaderstats!")

	local Coins = Instance.new("IntValue")
	Coins.Name = "Coins"
	Coins.Parent = leaderstats
	print("Made Coins!")

	local playerUserId = "Player_"..player.UserId
	print(playerUserId)

	-- Load data

	local data -- Makes it work in the WHOLE script
	local success, errormessage = pcall(function()
		data = myDS:GetAsync(playerUserId)          -- !!!! if data has never been set this will return successful and data will be nil
	end)

	if success then
		Coins.Value = data or 0     -- !!!! this will set a default to the coins incase they don't have any data which would be nil
		-- Set Coins = to the data
		print("Loaded data!")
	end


	Coins.Changed:Connect(function()   -- this catches the change of the coins value either add or subtracted any change to it will then add them to the autosave table for next loop to save the data
		table.insert(PlayersToSave,player)  -- add the player to this table because their data has changed
	end)

end)


game.Players.PlayerRemoving:Connect(function(player)
	if table.find(PlayersToSave,player) then  -- if the players data changed they will be in this table so save their data on remove else don't   -- you can remove this and just do a save here if you want but may overload datastore
		SavePlayersData(player)  -- save when they leave if it can sometimes this doesn't save in studio
		table.remove(PlayersToSave,table.find(PlayersToSave,player))    -- after save then remove them from the table
	end
end)

while true do   -- this autosave loop only saves player data if it has changed
	wait(TimeBetweenAutoSave)
	spawn(function()  -- spawn incase of error
		for _, player in ipairs(PlayersToSave) do  -- go through all the players in the PlayersToSave because their data changed and save them
			SavePlayersData(player)  -- save when they leave if it can sometimes this doesn't save in studio
			table.remove(PlayersToSave,table.find(PlayersToSave,player))    -- after save then remove them from the table
		end
	end)
end

how are you increasing you coinsvalue where is that script?

1 Like

Right now I just have a button for it, for testing purposes. I have it so when you click it, it increases by 1. Here is the script:

script.Parent.MouseButton1Click:Connect(function()
	game.Players.LocalPlayer.leaderstats.Coins.Value = game.Players.LocalPlayer.leaderstats.Coins.Value + 1
end)

coinssetup savesuccess

this works fine even in studio it saved for me (which sometimes if you don’t let autosave run studio doesnt save on stop)

i think what your doing wrong here is this is probably a client side or local script
so if you are changing the value with the client you will visually see it change but on the server it is still 0 because it wasn’t changed by the server

to fix this in that mouse click function you should fire a remove event that then changes the value on the server

In studio you can change stuff on the server by toggling the Current: Client button and to get back to client toggle Current: Server button (which it changes into)

1 Like