Issue with my data store script

So I’ve got a folder of the values, all the values are the same as what is shown in the folderChildren table below. I have it print out the values when the script detects a new player, and when the player leaves.

When the save runs, it prints out the new values. In this case lets say Stars is 130,000. When loading it appears to load an old value of 115,000. Everytime I leave, the script prints out the new value, yet when I load the game again, it loads the old value of 115,000. Any idea what’s wrong here? I’m testing repeatedly in studio.

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

local folderChildren = {
	"Stars",
	"Item1",
	"Item2",
	"Item3",
	"Item4",
	"Item5",
	"Item6",
	"Item7",
	"Item8",
	"Item9",
	"Pet1",
	"Pet2",
	"Powerup1",
	"Powerup2", 
	"Powerup3", 
	"Powerup4",
	"Powerup5", 
	"Powerup6", 
	"Powerup7",
	"Powerup8"
}

game.Players.PlayerAdded:Connect(function(player)
	local newFolder = script:WaitForChild("PlayerData"):Clone()
	newFolder.Parent = player
	
	local folder = player:WaitForChild("PlayerData")
	local savedValues = DataStore:GetAsync("FolderValues") or "New"
	if savedValues == "New"  then
		print(player.Name.." has started the aventure!")
	else
		for _, child in ipairs(folder:GetChildren()) do
			for i, childName in ipairs(folderChildren) do
				if child.Name == childName then
					child.Value = savedValues[i]
					print(child.Value)
					break
				end
			end
		end
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local folder = player.PlayerData
	local values = {}
	for _, child in ipairs(folder:GetChildren()) do
		for i, childName in ipairs(folderChildren) do
			if child.Name == childName then
				values[i] = child.Value
				print(child.Value)
				break
			end
		end
	end
	DataStore:SetAsync("FolderValues", values)
end)

The issue appears to be in saving.

– save2 (is never printed when this fails) any idea why this is happening?

game.Players.PlayerRemoving:Connect(function(player)
	local folder = player.PlayerData
	local values = {}
	for _, child in ipairs(folder:GetChildren()) do
		for i, childName in ipairs(folderChildren) do
			if child.Name == childName then
				values[i] = child.Value
				print(child.Value)
				break
			end
		end
	end
	print("save1")
	DataStore:SetAsync("FolderValues", values)
	print("save2")
end)

You have many issues in that script. By not using pcall to handle the loading, you are possibly overwritting the starter values. (this will happen in real server, not in studio (not by normal means))

You are double looping when its not needed too.

I disabled some lines in your script and added some stuff, test it. Still the first issue I mentioned I did not fixed it.

This is assuming that the folder PlayerData you are cloning and placing in Player already contains the values you want with names etc.

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

game.Players.PlayerAdded:Connect(function(player)
	local newFolder = script:WaitForChild("PlayerData"):Clone()
	newFolder.Parent = player

	--local folder = player:WaitForChild("PlayerData")
	local savedValues = DataStore:GetAsync("FolderValues") or "New"
	if savedValues == "New"  then
		print(player.Name.." has started the aventure!")
	else
		--[[
		for _, child in ipairs(folder:GetChildren()) do
			for i, childName in ipairs(folderChildren) do
				if child.Name == childName then
					child.Value = savedValues[i]
					print(child.Value)
					break
				end
			end
		end
		]]
		print(savedValues)
		for ValName, Val in pairs(savedValues) do
			if newFolder:FindFirstChild(ValName) then
				newFolder:FindFirstChild(ValName).Value = Val
			end
		end
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local folder = player.PlayerData
	local values = {}
	--[[
	for _, child in ipairs(folder:GetChildren()) do
		for i, childName in ipairs(folderChildren) do
			if child.Name == childName then
				values[i] = child.Value 
				print(child.Value)
				break
			end
		end
	end
	]]
	for _, Val in pairs(player:FindFirstChild("PlayerData")) do -- set it to the folder of values in player
		print(Val.Name, Val.Value)
		values[Val.Name] = Val.Value 
	end
	warn(values)
	DataStore:SetAsync("FolderValues", values)
end)

The reason I had the table of names, and the loops was because the values might not be in the same order, loading and saving. At least that’s my theory, the values might not load in the correct order.

Edit: it doesn’t work btw

The values doesnt need an order to be loaded.

When player joins, you get the datastore. Iterate that datastore, and find the values in player that match with the key of the table(ds), update them, thats all.

If theres 30 keys in table, then it will repeat 30 times, each time you use the name of the key, which could be “Stars”, in player folder you find a value with a name “Stars”, and update its value.

Same on saving, you iterate the player folder, find 30 values, once per value you create a new key in table using the name of value as key, and insert the value into that key, after 30 iterations you have a table with 30 keys, with name and its values, thats what you wanna save in datastore.

When player joins, they have that table in datastore, iterate it etc

And why it doesnt work? Im gonna give it a try, why not

for _, Val in pairs(player:FindFirstChild("PlayerData")) do

Needs to be:

for _, Val in pairs(player:FindFirstChild("PlayerData"):GetChildren()) do

That fixes the error, but it doesn’t seem to load the values.

This is what I mean, they’re not in the same order.

Loading:
https://gyazo.com/8f925e2045c971520aeb0b82f3f394b7

Saving:
https://gyazo.com/67616fb6d429415d5c67efb85e3e48a4

They’re not in the same order.

Yeah oops, a little mistake :face_with_hand_over_mouth:

Another reason?

from where this print comes?
image

The ‘print(savedValues)’ in the load function

And the one on save, is the warn function you used to print the table.

When it saves, and uses the warn()

It shows the correct order as seen here: https://gyazo.com/b9e4acd989e2b27f564c522a5d7dba3d

But loading almost seems reversed. With the star count being on the top of the table instead of the bottom.

Change the datastore to a new name to start with a fresh one, that seems that old values you already saved before

Look, I tested the script, and after creating a folder with random values using the names you provided, I tested the script, and my prints are correct:

Loading:
image

Saving:
image

Okay, and on a second note.

I’ve been doing new runs over and over. And sometimes it will show the table (on loading like this)

https://gyazo.com/8f925e2045c971520aeb0b82f3f394b7 (Shows as straight indexes)

And then shows the actual name of the value instead of just the index number: https://gyazo.com/a7be4f5db8586c955245ba5232ecc8e3

[I’ll go and create a new datastore]

1 Like

I created a new data store and same issue happens. Like if I keep doing this over and over. It will eventually not work and load properly. Or maybe it’s not saving I’m not sure. I’ll create a video demonstrating. Give me a couple mins.

As shown here. I start with 50,000 which is loaded. I then increase that to 75,000. And I leave game. The table shows 75,000. When I load, it show’s and loads 50,000

This is the script:
– I renamed the data store → “FolderDataTest2”

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

game.Players.PlayerAdded:Connect(function(player)
	local newFolder = script:WaitForChild("PlayerData"):Clone()
	newFolder.Parent = player

	--local folder = player:WaitForChild("PlayerData")
	local savedValues = DataStore:GetAsync("FolderValues") or "New"
	if savedValues == "New"  then
		print(player.Name.." has started the aventure!")
	else
		--[[
		for _, child in ipairs(folder:GetChildren()) do
			for i, childName in ipairs(folderChildren) do
				if child.Name == childName then
					child.Value = savedValues[i]
					print(child.Value)
					break
				end
			end
		end
		]]
		print(savedValues)
		for ValName, Val in pairs(savedValues) do
			if newFolder:FindFirstChild(ValName) then
				newFolder:FindFirstChild(ValName).Value = Val
			end
		end
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local folder = player.PlayerData
	local values = {}
	--[[
	for _, child in ipairs(folder:GetChildren()) do
		for i, childName in ipairs(folderChildren) do
			if child.Name == childName then
				values[i] = child.Value 
				print(child.Value)
				break
			end
		end
	end
	]]
	for _, Val in pairs(player:FindFirstChild("PlayerData"):GetChildren()) do -- set it to the folder of values in player
		print(Val.Name, Val.Value)
		values[Val.Name] = Val.Value 
	end
	warn(values)
	DataStore:SetAsync("FolderValues", values)
end)

Edit: Like keep trying over and over, it only sometimes works. Is this some sort of studio bug.

You are using BindToClose() ?

If not, theres a chance that when studio closes, it has not enough time to save the datastore, thats why pcall prints are useful, try this and watch prints:

game.Players.PlayerAdded:Connect(function(player)
	local newFolder = script:WaitForChild("PlayerData"):Clone()
	newFolder.Parent = player

	local savedValues = DataStore:GetAsync("FolderValues") or "New"
	if savedValues == "New"  then
		print(player.Name.." has started the aventure!")
	else
		print(savedValues)
		for ValName, Val in pairs(savedValues) do
			if newFolder:FindFirstChild(ValName) then
				newFolder:FindFirstChild(ValName).Value = Val
			end
		end
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local folder = player.PlayerData
	local values = {}
	for _, Val in pairs(player:FindFirstChild("PlayerData"):GetChildren()) do
		--print(Val.Name, Val.Value)
		values[Val.Name] = Val.Value 
	end
	warn(values)
	
	local succ, err = pcall(function()
		return DataStore:SetAsync("FolderValues", values)
	end)
	
	if succ then
		warn("Data saved!")
	else
		warn("failed to save", err)
	end
	
	warn("end of script") -- if this doesnt print means that game is closing before saving
	
end)

What is BindToClose() ?

And I tried pcall already, it wouldn’t print the error. It’s as if a threadcrash is happening.

I’ll try this though

[Edit: warn(“end of script”) – if this doesnt print means that game is closing before saving]

This isn’t printing.

game:BindToClose() fires when server is shutting down/closing. It gives you the chance to perform certain tasks as saving player’s datastores before it closes, to make sure the data is really saved and not lost.

Sometimes in studio due to many tasks your game is doing when closing etc, its not really having enough time to save the datastore. The prints/warns will be usefull to let you know if studio actually saved the datastore or not, check the prints at the end of the script I sent.

	if succ then
		warn("Data saved!")
	else
		warn("failed to save", err)
	end
	
	warn("end of script") -- if this doesnt print or any of previous warns means that game is closing before saving