Data not saving

Also, all the variable names are changeable, and don’t forget to add a

game.Players.PlayerAdded:Connect(load)
game.Players.PlayerRemoving:Connect(save)
game:BindToClose(function()
    for i, plr in pairs(game.Players: GetChildren()) do
        save(plr)
    end
end)

Also, watch out for copying and pasting, I used spaces instead of indenting, and capitalization is wrong is some places

1 Like

i made some code for you, this time in studio, so feel free to copy it! if you have any questions about how it works, ill happily help!

local DataStoreService = game:GetService("DataStoreService")
local CoinsStore = DataStoreService:GetDataStore("CoinsStore")

local tries = 3
local dataloaded = nil

local function save(player)
	if dataloaded then
		local key = player.UserId
		local count = 0

		local data = {}
		
		for i, Value in pairs(player.playerstats) do
			local Thing = {
				["Name"] = Value.Name,
				["Value"] = Value.Value
			}
			table.insert(data, Thing)
		end
		
		local success, err

		repeat
			success, err = pcall(function()
				CoinsStore:SetAsync(key, data)
			end)

			count = count + 1
		until count >= tries or success

		if not success then
			warn("Data could not be set." .. tostring(err))

			return
		end
	else
		warn("Data has not been loaded. Do not attempt to set data when it has not been loaded.")

		return
	end
end

local function load(player)
	
	local playerstats = Instance.new("Folder")
	playerstats.Name = "playerstats"
	playerstats.Parent = player
	

	local key = player.UserId
	local count = 0

	local data

	local success, err

	-- Loading Magic

	repeat
		success, err = pcall(function()
			data = CoinsStore:GetAsync(key)
		end)

		count = count + 1
	until count >= tries or success

	-- Did we load?

	if not success then
		warn("Failed to read data." .. tostring(err))

		player:Kick("Failed to read data. Please rejoin the game.")

		return
	end

	-- We Loaded. Hooray

	if data then
		for i, table in pairs(data) do
			local Value = Instance.new("IntValue") -- can be changed to bool value, string value, etc.
			Value.Name = table.Name
			Value.Value = table.Value
			Value.Parent = playerstats
		end
		dataloaded = true
	else
		local coins = Instance.new("IntValue")
		coins.Name = "Coins"
		coins.Parent = playerstats
		
		local dataId = Instance.new("IntValue")
		dataId.Name = "DataId"
		dataId.Value = --set value here

		dataloaded = true
	end

end

game.Players.PlayerAdded:Connect(load)
game.Players.PlayerRemoving:Connect(save)
game:BindToClose(function()
	for i, plr in ipairs(game.Players:GetPlayers()) do
		save(plr)
	end
end)
1 Like

Thank you for writing this code for me. I really appreciate it, but it does not seem to work for me. No errors in the output or anything.

If the code doesn’t work, first of all, try changing some of the variables I put in

Secondly, make sure you have studio access to API services enabled. Without it enabled, datastores won’t work (might be the cause of your problem)

If that doesn’t work, try putting that script into a different place, and see if it works (make sure studio access to API services is enabled, can be found in game settings → security)

1 Like

You arent allowed to write entire scripts for people, just letting you know.

1 Like
  1. The Rules:
    About the Scripting Support category

  2. Doesnt mean you give out entire code.

1 Like

There is a reason nobody does this, saying “oh, because it doesnt say this” just simplt isnt true, even if they say or dont say they want code for stuff, you still dont provide the entire thing.

If you are recommending a Source, Provide the Source.

talk to me over Messages btw, not replies to a topic, we would be flooding the topic with off topic stuff.

1 Like

Alright, I enabled API Access to studio but now its saying:
Warn Statement

whenever I leave. Should I test this system in-game or in studio as I am currently doing right now?

In this section, make sure that both statements have dataloaded = true. I edited the code a bit after, perhaps you copied the code before I edited it

It print can’t save, because data loaded hasn’t been set to true, and it only does so in the above statements. Try it, and let me know if it works!

1 Like

I did it, and there is an error in the for loop:

if dataloaded then
		local key = player.UserId
		local count = 0

		local data = {}

		for i, Value in pairs(player.playerstats) do --error here
			local Thing = {
				["Name"] = Value.Name,
				["Value"] = Value.Value
			}
			table.insert(data, Thing)
		end

It says, invalid argument #1 to 'pairs' (table expected, got Instance)

Also, I have a question, in

does the else statement mean that there is no data and it is a new player? And for this:

Do I have to put a number there because it is a new player? Or is it intentional like that?

Also I’m very sorry for the late response lol, busy with school and had to do other things.

Thanks so much.

In the for loop, I forgot to put a get children

This part:

for i, Value in pairs(player.playerstats) do

Should be replaced with:

for i, Value in pairs(player.playerstats:GetChildren()) do

Yes, the else that you showed is for when a player has joined game for the first time, and doesn’t have any saves

You have to set the value you want for the dataId, because I don’t know what that variable is. Set it as 0, 25, or whatever! or change “IntValue” in Instance.new() to anything you would like and set value accordingly

Let me know if you have any other issues!

1 Like

Thank you, it works much better now. However, I want the # of coins to be in an IntValue inside of playerstats. I can’t seem to make it change, and there are no errors in the script.

When I print the IntValue storing the coins when the game saves, it keeps saying it’s 0 even though I add the value at the beginning of the load function.

I am also viewing the change on the client side and the server side in case it changes on one of them.

Here is the script starting from the load function, idk what’s happening.

local function load(player)

	player:WaitForChild("leaderstats"):WaitForChild("Stage"):GetPropertyChangedSignal("Value"):Connect(function()
		print('player leaderstats changed')
		local leaderstats = player:WaitForChild("leaderstats"):WaitForChild("Stage").Value
		local coinValue = tonumber(script.playerstats.Coins.Value)
		if leaderstats < 20 and leaderstats > 1 then --in easy
			coinValue += 2
		elseif leaderstats < 40 and leaderstats > 20 then --if in casual
			coinValue += 4
		elseif leaderstats < 51 and leaderstats > 40 then --if in medium
			coinValue += 5
		end
	end)

	local playerstats = Instance.new("Folder")
	playerstats.Name = "playerstats"
	playerstats.Parent = player


	local key = player.UserId
	local count = 0

	local data

	local success, err

	-- Loading Magic

	repeat
		success, err = pcall(function()
			data = CoinsStore:GetAsync(key)
		end)

		count = count + 1
	until count >= tries or success

	-- Did we load?

	if not success then
		warn("Failed to read data." .. tostring(err))

		player:Kick("Failed to read data. Please rejoin the game.")

		return
	end

	-- We Loaded. Hooray

	if data then
		for i, table in pairs(data) do
			local Value = Instance.new("IntValue") -- can be changed to bool value, string value, etc.
			Value.Name = table.Name
			Value.Value = table.Value
			Value.Parent = playerstats
		end
		dataloaded = true
	else
		local coins = Instance.new("IntValue")
		coins.Name = "Coins"
		coins.Parent = playerstats

		local dataId = Instance.new("IntValue")
		dataId.Name = "DataId"
		dataId.Value = 0

		dataloaded = true
	end

end

game.Players.PlayerAdded:Connect(load)
game.Players.PlayerRemoving:Connect(save)
game:BindToClose(function()
	for i, plr in ipairs(game.Players:GetPlayers()) do
		save(plr)
		print('fired save function')
	end
end)

Unsure of how it works,as you add the coinvalue variable before the coin instance is loaded in?

Also, an IntValue has the default value always set to 0, so if you aren’t changing the value while in game (do it from server, client edits don’t save) then it will always be 0

Also, I assume you want to add coins based on difficulty?

Problem: let’s say that when you get to stage 21 you have 50 coins. When you reach stage 22, it asks to add 4 coins. Now the CoinsValue variable is set to 54. But the player coins is still 50. You changed the value of the variable, not the IntValue in the player.playerstats.

Instead, set CoinsValue as just the path to the IntValue
~

CoinsValue = player.playerstats.Coins

CoinsValue.Value += 4

This will add 4 to the player coins

Also, and I can’t stress this enough, I really recommend only having the saving / loading functions as part of the datastores script, and put everything else (like the stat hanged event) into a separate script.

Also, don’t forget to actually create stuff… I don’t see you creating a leader stats folder in this script, but it’s good, again, if it works, it works, just keep this script working the way it’s intended: saving + loading

Let me know if you have any other trouble!

1 Like

Hi, I changed some stuff in the script. So basically, this part:

Is in another script (see what I wrote below this) and that basically handles the coin value adding.


The coin instance is already loaded in:
Hierarchy
The script inside of the Coins IntValue is changing the coin value that it’s parented in.


There is also an error: attempt to index number with 'Name' in this part:
(I made it stand out)

if data then
		for i, table in pairs(data) do
			local Value = Instance.new("IntValue") -- can be changed to bool value, string value, etc.

			Value.Name = table.Name --this line

			Value.Value = table.Value
			Value.Parent = playerstats
		end
		dataloaded = true

Here is the entire script if you need it:

local DataStoreService = game:GetService("DataStoreService")
local CoinsStore = DataStoreService:GetDataStore("CoinStore")
local repStorage = game:GetService("ReplicatedStorage")

local tries = 3
local dataloaded = nil

local function save(player)

	if dataloaded then
		local key = player.UserId
		local count = 0

		local data = {}

		for i, Value in pairs(player.playerstats:GetChildren()) do
			local Thing = {
				["Name"] = Value.Name,
				["Value"] = Value.Value
			}
			table.insert(data, Thing)
		end

		print(data)

		local success, err

		repeat
			success, err = pcall(function()
				CoinsStore:SetAsync(key, data)
				print(script.playerstats.Coins.Value)
				print('Saved!')
			end)

			count = count + 1
		until count >= tries or success

		if not success then
			warn("Data could not be set." .. tostring(err))
			return
		end
	else
		warn("Data has not been loaded. Do not attempt to set data when it has not been loaded.")

		return
	end
end

local function load(player)

	local playerstats = Instance.new("Folder")
	playerstats.Name = "playerstats"
	playerstats.Parent = player
	
	print('playerstats created')


	local key = player.UserId
	local count = 0

	local data

	local success, err

	-- Loading Magic

	repeat
		success, err = pcall(function()
			data = CoinsStore:GetAsync(key)
			print('got data')
			print(data)
		end)

		count = count + 1
	until count >= tries or success

	-- Did we load?

	if not success then
		warn("Failed to read data." .. tostring(err))

		player:Kick("Failed to read data. Please rejoin the game.")

		return
	end

	-- We Loaded. Hooray

	if data then
		for i, table in pairs(data) do
			local Value = Instance.new("IntValue") -- can be changed to bool value, string value, etc.
			Value.Name = table.Name
			Value.Value = table.Value
			Value.Parent = playerstats
		end
		dataloaded = true
	else
		warn('Player has no data! Creating new data for them.')
		local coins = Instance.new("IntValue")
		coins.Name = "Coins"
		coins.Parent = playerstats

		local dataId = Instance.new("IntValue")
		dataId.Name = "DataId"
		dataId.Value = 0

		dataloaded = true
	end

end

game.Players.PlayerAdded:Connect(load)
game.Players.PlayerRemoving:Connect(save)
game:BindToClose(function()
	for i, plr in ipairs(game.Players:GetPlayers()) do
		save(plr)
		print('fired save function')
	end
end)

repStorage.RequestData.OnServerInvoke = function(player)
	return script.playerstats.Coins.Value
end

one:

it will not update, as you are changing a number value, not coins. converting it using tonumber() secures the inability to change it, but im here just to help with saving.

two: try changing the name from table to savedInstance

for i, savedInstance in pairs(data) do

if that doesnt work try saving the name in a tostring()

for i, Value in pairs(player.playerstats:GetChildren()) do
	local Thing = {
		["Name"] = tostring(Value.Name),
		["Value"] = Value.Value
	}
	table.insert(data, Thing)
end

Ohhhhh, I think I may have found the problem.

Testing the game while in studio, I go to players > myName > playerstats but in playerstats, nothing is there! The folder is empty.

Why is this happening?


I did all your steps and I think it would work if there was stuff in the playerstats since the for loops use the playerstats.


update: I just created a DataId value and a Coin value inside of player.playerstats but it still gives me the error: attempt to index number with 'Name'

i do not understand why things are ging wrong

created a place in roblox, copied the script you provided before

local DataStoreService = game:GetService("DataStoreService")
local CoinsStore = DataStoreService:GetDataStore("CoinStore")
local repStorage = game:GetService("ReplicatedStorage")

local tries = 3
local dataloaded = nil

local function save(player)
	--make sure that data has actually loaded in (to not clear by accident)
	if dataloaded then
		local key = player.UserId
		local count = 0

		local data = {}
		
		--adds the name and value of every IntValue in playerstats to the "data" table
		for i, Value in pairs(player.playerstats:GetChildren()) do
			local Thing = {
				["Name"] = Value.Name,
				["Value"] = Value.Value
			}
			table.insert(data, Thing)
		end

		print(data)

		local success, err
		
		---keeps trying to set async until it either succeeds or goes over the allowed tries to save
		repeat
			success, err = pcall(function()
				CoinsStore:SetAsync(key, data)
				print(player.playerstats.Coins.Value)
				print('Saved!')
			end)

			count = count + 1
		until count >= tries or success
		
		-- warns if data could not be set
		if not success then
			warn("Data could not be set: " .. tostring(err))
			return
		end
	else
		-- warns that data has not loaded.
		warn("Data has not been loaded. Do not attempt to set data when it has not been loaded.")

		return
	end
end

local function load(player)
	
	-- creates playerstats
	local playerstats = Instance.new("Folder")
	playerstats.Name = "playerstats"
	playerstats.Parent = player

	print('playerstats created')


	local key = player.UserId
	local count = 0

	local data

	local success, err
	
	-- tries to fetch data from datastore until either succeeds or takes too many attempts
	repeat
		success, err = pcall(function()
			data = CoinsStore:GetAsync(key)
			print('got data')
			print(data)
		end)

		count = count + 1
	until count >= tries or success
	
	-- if didnt fetch data
	if not success then
		warn("Failed to read data." .. tostring(err))
		
		--kicks to force player to try again
		player:Kick("Failed to read data. Please rejoin the game.")

		return
	end
	
	-- if data exists (player left the game, and then rejoined some time later)
	if data then
		-- for data creates values, puts them in playerstats
		
		--[[ saved table looks like this at the point of writing:
		data = {
			[1] = {
				["Name"] = "Coins",
				["Value "] = 3
			}
			[2] = {
				["Name"] = "DataId",
				["Value"] = 10
			}
		}
		keep in mind its random values, yours will be different, cuz you set them yourself, i picked 2 random ones
		]]
		for i, table in pairs(data) do
			local Value = Instance.new("IntValue") -- can be changed to bool value, string value, etc.
			Value.Name = table.Name
			Value.Value = table.Value
			Value.Parent = playerstats
		end
		dataloaded = true
	else
		-- does not exist (player joined first time) so we create instance, set value, and parent
		warn('Player has no data! Creating new data for them.')
		local coins = Instance.new("IntValue")
		coins.Name = "Coins"
		coins.Parent = playerstats

		local dataId = Instance.new("IntValue")
		dataId.Name = "DataId"
		dataId.Value = 0
		dataId.Parent = playerstats 

		dataloaded = true
	end

end

--load when player joins
game.Players.PlayerAdded:Connect(load)

--save when player leaves
game.Players.PlayerRemoving:Connect(save)

--save when game gets shut down
game:BindToClose(function()
	for i, plr in ipairs(game.Players:GetPlayers()) do
		save(plr)
		print('fired save function')
	end
end)

i basically edited the location of playerstats.coins (in the print function)
deleted and wrote in table.insert(data, Thing), and added a dataId.Parent = playerstats that i forgot before. thats it. the saving and loading functions work correctly, create a new topic if your having trouble with other stuff, this isnt so much about saving anymore

also added text hints about what code does

hope i helped!!!

1 Like

tested your script, turned on API services, and everything works fine! it appears that the only thing you were missing was

image

then

image
image

followed by

image

1 Like

i noticed that its been more than a week, and you have neither marked this topic as “solved”, or responded to me for more help.

because of this, ive noticed that you are having trouble with the for loops and the creation of values.

the reason i did

for i, Value in pairs(player.playerstats:GetChildren()) do
	local Thing = {
		["Name"] = Value.Name,
		["Value"] = Value.Value
	}
	table.insert(data, Thing)
end

instead of something like

local data = {
	player.playerstats.Coins.Value,
	player.playerstats.DataId.Value
}

was so it would be easier to create a third or fourth value, and so on…

if you wanted to add a value, lets say its called “StageCount”, all i would hae to do to add a value was add a

local Stage = Instance.new("IntValue")
Stage.Name = "StageCount"
Stage.Value = 0
Stage.Parent = playerstats

in the place where the new data is created for new players

this would add a value, then save name and value, then, upon rejoining, player would get a value created based on name and value.

if you save the data like this:

local data = {
	player.playerstats.Coins.Value,
	player.playerstats.DataId.Value
}

then you could load in the data like this:

local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = data[1]
coins.Parent = playerstats

local dataId = Instance.new("IntValue")
dataId.Name = "DataId"
dataId.Value = data[2]
dataId.Parent = playerstats 

instead of the method that i demonstrated

hope i helped! (if you did, would appreciate if you mark a post as the solution, would help a lot of people using this as reference)

1 Like

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