Datastores not working correctly

In each of the different parts(places) of my game (part 1, part 2, part 3) i need only the respective values to be in leaderstats:

  • Part 1: Deaths1 & Escapes1
  • Part 2: Deaths2 & Escapes2
  • Part 3: Deaths3 & Escapes3

How can i go about editing the script so that i can easily make those changes for each Part of my game without ruining the data saves?

You’re going to have to load all the data anyways to keep it persistent, so you can keep it as is.

If you want to hide the leaderstats though, you can do this:

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")

local defaultData = {
	leaderstats = {
		["Deaths I"] = 0,
		["Escapes I"] = 0
	},

	storedData = {
		["Deaths II"] = 0,
		["Escapes II"] = 0,
		["Deaths III"] = 0,
		["Escapes III"] = 0
	}
}

local leaderstatsName = game.PlaceId == firstPlace and "leaderstats" or "folder"

local function SaveData(player, data)
	local success, errorMessage = pcall(function()
		playerDataStore:SetAsync(player.UserId, data)
	end)

	if not success then
		warn(errorMessage)
	end
end

local function OnPlayerRemoving(player)
	local data = defaultData

	for folderName, folderValues in defaultData do
		local folder = player[folderName == "leaderstats" and leaderstatsName or folderName]

		for valueName, _ in folderValues do
			data[folderName][valueName] = folder[valueName].Value
		end
	end

	SaveData(player, data)
end

Players.PlayerAdded:Connect(function(player)
	local playerData = playerDataStore:GetAsync(player.UserId) or defaultData

	for folderName, folderValues in defaultData do
		local folder = Instance.new("Folder")
		folder.Name = folderName == "leaderstats" and leaderstatsName or folderName

		for valueName, _ in folderValues do
			local intValue = Instance.new("IntValue")
			intValue.Name = valueName
			intValue.Value = playerData[folderName][valueName]
			intValue.Parent = folder
		end
		
		folder.Parent = player
	end
end)

Players.PlayerRemoving:Connect(OnPlayerRemoving)

game:BindToClose(function()
	for i, player in Players:GetPlayers() do
		task.spawn(OnPlayerRemoving, player)
	end
end)

When i go to my second place, for example, though it doesn’t load my saved Part 1 values.
Here’s the code for the second place:

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")

local defaultData = {
	leaderstats = {
		["Deaths II"] = 0,
		["Escapes II"] = 0,
	},

	storedData = {
		["Deaths I"] = 0,
		["Escapes I"] = 0,
		["Deaths III"] = 0,
		["Escapes III"] = 0
	}
}

local leaderstatsName = game.PlaceId == myreal2ndplaceidishere and "leaderstats" or "folder"

local function SaveData(player, data)
	local success, errorMessage = pcall(function()
		playerDataStore:SetAsync(player.UserId, data)
	end)

	if not success then
		warn(errorMessage)
	end
end

local function OnPlayerRemoving(player)
	local data = defaultData

	for folderName, folderValues in defaultData do
		local folder = player[folderName == "leaderstats" and leaderstatsName or folderName]

		for valueName, _ in folderValues do
			data[folderName][valueName] = folder[valueName].Value
		end
	end

	SaveData(player, data)
end

Players.PlayerAdded:Connect(function(player)
	local playerData = playerDataStore:GetAsync(player.UserId) or defaultData

	for folderName, folderValues in defaultData do
		local folder = Instance.new("Folder")
		folder.Name = folderName == "leaderstats" and leaderstatsName or folderName

		for valueName, _ in folderValues do
			local intValue = Instance.new("IntValue")
			intValue.Name = valueName
			intValue.Value = playerData[folderName][valueName]
			intValue.Parent = folder
		end

		folder.Parent = player
	end
end)

Players.PlayerRemoving:Connect(OnPlayerRemoving)

game:BindToClose(function()
	for i, player in Players:GetPlayers() do
		task.spawn(OnPlayerRemoving, player)
	end
end)

Yeah, is that not what you wanted the script to do?

If you want everything to load, use the original script here:

That is what i want, but when i check the storedData folder inside of the Player, where Deaths1, Escapes1, Deaths3, & Escapes3 should all be, they’re in the folder but their values are all at zero, so they didn’t save from place 1 or place 3. I’m trying to get all of the data to transfer to the other places because in my Lobby place i have leaderboards for each of the different values.

Oh, I just realized you did it wrong. If you want the leaderstats to only show the current world’s count, then we have to do something different.

Code:

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")

local defaultData = {
	["Deaths I"] = 0,
	["Escapes I"] = 0,
	["Deaths II"] = 0,
	["Escapes II"] = 0,
	["Deaths III"] = 0,
	["Escapes III"] = 0
}

local leaderstatValues = {"Death I", "Escapes I"} -- Change this depending on level

local function SaveData(player, data)
	local success, errorMessage = pcall(function()
		playerDataStore:SetAsync(player.UserId, data)
	end)

	if not success then
		warn(errorMessage)
	end
end

local function OnPlayerRemoving(player)
	local leaderstats = player.leaderstats
	local storedData = player.storedData
	
	local data = {}

	for valueName, _ in defaultData do
		data[valueName] = table.find(leaderstatValues, valueName) and leaderstats[valueName].Value or storedData[valueName].Value
	end

	SaveData(player, data)
end

Players.PlayerAdded:Connect(function(player)
	local playerData = playerDataStore:GetAsync(player.UserId) or defaultData
	
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	
	local storedData = Instance.new("Folder")
	storedData.Name = "storedData"
	
	for valueName, _ in defaultData do
		local intValue = Instance.new("IntValue")
		intValue.Name = valueName
		intValue.Value = playerData[valueName]
		intValue.Parent = table.find(leaderstatValues, valueName) and leaderstats or storedData
	end
	
	leaderstats.Parent = player
	storedData.Parent = player
end)

Players.PlayerRemoving:Connect(OnPlayerRemoving)

game:BindToClose(function()
	for i, player in Players:GetPlayers() do
		task.spawn(OnPlayerRemoving, player)
	end
end)

You will have to reset your data again.

Do i need to reset everybody’s data as well? because there are a couple of other people that have tested my game out and they have data. Is there a way to reset all data? if that’s what i need to do?

You can use this in your command bar:

local DSS = game:GetService("DataStoreService")
local DataStore = DSS:GetDataStore("playerData")
local KeysPages = DataStore:ListKeysAsync()
		
while true do
	local CurrentKeysPage = KeysPages:GetCurrentPage()
			
	for j, Key in pairs(CurrentKeysPage) do
		DataStore:RemoveAsync(Key.KeyName)
	end
			
	if KeysPages.IsFinished then break end
			
	KeysPages:AdvanceToNextPageAsync()
end

If you want me to implement a way that preserves their data, tell me. There will be a performance cost though.

The data still isn’t saving or transferring.
Code:

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")

local defaultData = {
	["Deaths I"] = 0,
	["Escapes I"] = 0,
	["Deaths II"] = 0,
	["Escapes II"] = 0,
	["Deaths III"] = 0,
	["Escapes III"] = 0
}

local leaderstatValues = {"Deaths I", "Escapes I"} -- Change this depending on level

local function SaveData(player, data)
	local success, errorMessage = pcall(function()
		playerDataStore:SetAsync(player.UserId, data)
	end)

	if not success then
		warn(errorMessage)
	end
end

local function OnPlayerRemoving(player)
	local leaderstats = player.leaderstats
	local storedData = player.storedData

	local data = {}

	for valueName, _ in defaultData do
		data[valueName] = table.find(leaderstatValues, valueName) and leaderstats[valueName] or storedData[valueName]
	end

	SaveData(player, data)
end

Players.PlayerAdded:Connect(function(player)
	local playerData = playerDataStore:GetAsync(player.UserId) or defaultData

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

	local storedData = Instance.new("Folder")
	storedData.Name = "storedData"

	for valueName, _ in defaultData do
		local intValue = Instance.new("IntValue")
		intValue.Name = valueName
		intValue.Value = playerData[valueName]
		intValue.Parent = table.find(leaderstatValues, valueName) and leaderstats or storedData
	end

	leaderstats.Parent = player
	storedData.Parent = player
end)

Players.PlayerRemoving:Connect(OnPlayerRemoving)

game:BindToClose(function()
	for i, player in Players:GetPlayers() do
		task.spawn(OnPlayerRemoving, player)
	end
end)

You’re testing this ingame right? If so, does it save when you leave and rejoin for place one?

Yes, i tested it ingame. It doesn’t save when i leave and rejoin place one.

Are there any errors or warnings?

You only ran the command once right?

I ran the command for myself a couple of times on accident lol. And i ran the one that resets all datastores once.
Here’s what’s in the Output:

  • DataStoreService: CantStoreValue: Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters. API: SetAsync, Data Store: playerData - Studio
  • Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters. - Server - Leaderstats/Datastore:22

Oops, I made a typo. Check my edited code.

which code did you edit? i can’t tell lol

1 Like

i replace the code with that and its still not working. Wait… im testing in roblox studio right now and when i open up the player in the explorer there are two leaderstats folders in there, one of them has the saved values and the other has zero values.
Edit: i accidentally had another script that was creating a leaderstats folder and i forgot to delete it, so im gonna test in Roblox again quick.

IT WORKS FINALLY THANK YOU SO MUCH! especially for your quick responses!!!
Here’s the working code:

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")

local defaultData = {
	["Deaths I"] = 0,
	["Escapes I"] = 0,
	["Deaths II"] = 0,
	["Escapes II"] = 0,
	["Deaths III"] = 0,
	["Escapes III"] = 0
}

local leaderstatValues = {"Deaths I", "Escapes I"}

local function SaveData(player, data)
	local success, errorMessage = pcall(function()
		playerDataStore:SetAsync(player.UserId, data)
	end)

	if not success then
		warn(errorMessage)
	end
end

local function OnPlayerRemoving(player)
	local leaderstats = player.leaderstats
	local storedData = player.storedData

	local data = {}

	for valueName, _ in defaultData do
		data[valueName] = table.find(leaderstatValues, valueName) and leaderstats[valueName].Value or storedData[valueName].Value
	end

	SaveData(player, data)
end

Players.PlayerAdded:Connect(function(player)
	local playerData = playerDataStore:GetAsync(player.UserId) or defaultData

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

	local storedData = Instance.new("Folder")
	storedData.Name = "storedData"

	for valueName, _ in defaultData do
		local intValue = Instance.new("IntValue")
		intValue.Name = valueName
		intValue.Value = playerData[valueName]
		intValue.Parent = table.find(leaderstatValues, valueName) and leaderstats or storedData
	end

	leaderstats.Parent = player
	storedData.Parent = player
end)

Players.PlayerRemoving:Connect(OnPlayerRemoving)

game:BindToClose(function()
	for i, player in Players:GetPlayers() do
		task.spawn(OnPlayerRemoving, player)
	end
end)
1 Like

No problem, I would appreciate the solution though.

If you have any questions, feel free to ask. Have a good day/night!

1 Like

Of course!! Thank you so much!

1 Like