Datastore woes again - need more eyes

I need another set of eyes. I have a button that increases the Numbers in the leaderstats. It seems to be working and I don’t know why the games not saving or loading (nothing in the output). My thinking was to be able to add new leaderstats and playerstats IntValue’s in the future. So far I have a single button that increases the numbers in the leaderstats and it doesn’t seem to load or save any new information


-- Leaderstats and Datastore --
local DataStoreService = game:GetService("DataStoreService")
local PlayerDataStore = DataStoreService:GetDataStore("PlayerData_01")
local RunService = game:GetService("RunService")
local isStudio = RunService:IsStudio()

local function loadData(player)
	local success, data = pcall(function()
		return PlayerDataStore:GetAsync(player.UserId)
	end)

	if success and data then
		for _, stat in pairs(player.playerstats:GetChildren()) do
			if data[stat.Name] then
				stat.Value = data[stat.Name]
			end
		end
	end

	local leaderstatsData = player.leaderstats:GetChildren()
	if #leaderstatsData > 0 then
		local success, data = pcall(function()
			return PlayerDataStore:GetAsync("leaderstats_"..player.UserId)
		end)

		if success and data then
			for _, child in pairs(leaderstatsData) do
				if child:IsA("IntValue") and data[child.Name] then
					child.Value = data[child.Name]
				end
			end
		end
	end
end

local function saveData(player)
	local dataToSave = {}
	for _, stat in pairs(player.playerstats:GetChildren()) do
		if stat:IsA("IntValue") then
			dataToSave[stat.Name] = stat.Value
		end
	end

	local leaderstatsData = player.leaderstats:GetChildren()
	if #leaderstatsData > 0 then
		local leaderstatsDataToSave = {}
		for _, data in pairs(leaderstatsData) do
			if data:IsA("IntValue") then
				leaderstatsDataToSave[data.Name] = data.Value
			end
		end
		dataToSave["leaderstats"] = leaderstatsDataToSave
	end

	local success, errorMessage = pcall(function()
		PlayerDataStore:SetAsync(player.UserId, dataToSave)
	end)

	if not success then
		warn(errorMessage)
	else
		print("Player data saved successfully for: "..player.UserId)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

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

	local numbers = Instance.new("IntValue")
	numbers.Name = "Numbers"
	numbers.Value = 0
	numbers.Parent = leaderstats

	local fire = Instance.new("IntValue")
	fire.Name = "Fire"
	fire.Value = 0
	fire.Parent = playerstats

	local water = Instance.new("IntValue")
	water.Name = "Water"
	water.Value = 0
	water.Parent = playerstats

	local earth = Instance.new("IntValue")
	earth.Name = "Earth"
	earth.Value = 0
	earth.Parent = playerstats

	local air = Instance.new("IntValue")
	air.Name = "Air"
	air.Value = 0
	air.Parent = playerstats

	local timePlayed = Instance.new("IntValue")
	timePlayed.Name = "TimePlayed"
	timePlayed.Value = 0
	timePlayed.Parent = playerstats

	local buttonPresses = Instance.new("IntValue")
	buttonPresses.Name = "ButtonPresses"
	buttonPresses.Value = 0
	buttonPresses.Parent = playerstats

	loadData(player) -- load player data here
end)

game.Players.PlayerRemoving:Connect(function(player)
	saveData(player) -- save player data here
end)

game:BindToClose(function()
	if not isStudio then
		for _, player in pairs(game.Players:GetPlayers()) do
			task.spawn(function()
				saveData(player)
			end)
		end
	end
end)
1 Like

Nvm, ignore this post. DIdn’t know you can use the 2nd variable as the 2nd return value.

local success, data = pcall(function()
    return PlayerDataStore:GetAsync(player.UserId)
end)

if success and data then

PCall function returns two value:

  1. A boolean value whether it was a success or not
  2. The error message if it was an error

So you can’t just return PlayerDataStore:GetAsync(“leaderstats_”…player.UserId) as it will do nothing in your next line of code. Instead store your data variable outside of the pcall function and make changes inside.

It seems as though you’re setting a key using the player’s id but then trying to retrieve it using a concatenated string.


You set your key like this:

local success, errorMessage = pcall(function()
	PlayerDataStore:SetAsync(player.UserId, dataToSave)
end)

But you’re trying to read it like this:

local success, data = pcall(function()
	return PlayerDataStore:GetAsync("leaderstats_"..player.UserId)
end)

player.UserId does not equal “leaderstats_”…player.UserId

Instead, when you read it do this:

local success, data = pcall(function()
	return PlayerDataStore:GetAsync(player.UserId)
end)

Then since you stored a table inside your key you can do local savedLeaderstats = data["leaderstats"]

Also, it is of particular note that you ARE allowed to use data as the second return value when you’re reading a key using :GetAsync():

It is only in setting a key that you use error as the second return value.

Hope this helps! :smile:

Try this:
(The issue is that when creating the table to save, you nested the leaderstats into that datastore, but when loading you are trying to get a leaderstats key datastore, instead of getting the value from the other key you created for the player. I tested this script and works fine)

-- Leaderstats and Datastore --
local DataStoreService = game:GetService("DataStoreService")
local PlayerDataStore = DataStoreService:GetDataStore("PlayerData_01")
local RunService = game:GetService("RunService")
local isStudio = RunService:IsStudio()

local function loadData(player)
	local success, data = pcall(function()
		return PlayerDataStore:GetAsync(player.UserId)
	end)

	if success then
		if data then
			warn(data)
			for _, stat in pairs(player.playerstats:GetChildren()) do
				if data[stat.Name] then
					stat.Value = data[stat.Name]
				end
			end
			
			local leaderFolder = player:WaitForChild("leaderstats")
			for key, value in pairs(data["leaderstats"]) do
				if leaderFolder[key] then
					leaderFolder[key].Value = value
				end
			end
		else
			warn("no data, new player")
		end
	else
		warn("DSS reading failed")
	end
end

local function saveData(player)
	local dataToSave = {}
	
	for _, stat in pairs(player.playerstats:GetChildren()) do
		if stat:IsA("IntValue") then
			dataToSave[stat.Name] = stat.Value
		end
	end

	local leaderstatsData = player.leaderstats:GetChildren()
	if #leaderstatsData > 0 then
		local leaderstatsDataToSave = {}
		for _, data in pairs(leaderstatsData) do
			if data:IsA("IntValue") then
				leaderstatsDataToSave[data.Name] = data.Value
			end
		end
		dataToSave["leaderstats"] = leaderstatsDataToSave
	end
	
	warn(dataToSave)
	
	local success, errorMessage = pcall(function()
		PlayerDataStore:SetAsync(player.UserId, dataToSave)
	end)
	
	
	if not success then
		warn(errorMessage)
	else
		print("Player data saved successfully for: "..player.UserId)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

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

	local numbers = Instance.new("IntValue")
	numbers.Name = "Numbers"
	numbers.Value = 0
	numbers.Parent = leaderstats

	local fire = Instance.new("IntValue")
	fire.Name = "Fire"
	fire.Value = 0
	fire.Parent = playerstats

	local water = Instance.new("IntValue")
	water.Name = "Water"
	water.Value = 0
	water.Parent = playerstats

	local earth = Instance.new("IntValue")
	earth.Name = "Earth"
	earth.Value = 0
	earth.Parent = playerstats

	local air = Instance.new("IntValue")
	air.Name = "Air"
	air.Value = 0
	air.Parent = playerstats

	local timePlayed = Instance.new("IntValue")
	timePlayed.Name = "TimePlayed"
	timePlayed.Value = 0
	timePlayed.Parent = playerstats

	local buttonPresses = Instance.new("IntValue")
	buttonPresses.Name = "ButtonPresses"
	buttonPresses.Value = 0
	buttonPresses.Parent = playerstats

	loadData(player) -- load player data here
end)

game.Players.PlayerRemoving:Connect(function(player)
	saveData(player) -- save player data here
end)

game:BindToClose(function()
	if not isStudio then
		for _, player in pairs(game.Players:GetPlayers()) do
			task.spawn(function()
				saveData(player)
			end)
		end
	end
end)

Ohh, I didn’t know that. Ignore my previous post then.
Just a quick question, when it errors will the errorMessage return as the data or still the message?

Thanks for that. Both warn’s worked and the data was saved. Idk what i was thinking but when the scripts get longer I seem to struggle to comprehend it all.

1 Like

They were simply coded to have different returns by the Roblox developers.


:SetAsync() has these returns:

success & errorMessage

This helps us easily see why our write function failed. We simply don’t need to return the data because the data is what we’re passing into arguments.


:GetAsync() has these returns:

success & data

This helps us easily get the data from our read function.


You can read more about the returns and parameters here:

No promblem! :yum:
Oh, and click the 3 dots at the top right corner of the output window, and disable log mode so you can see the content of the tables printed

Captura

1 Like

So if I add something down the track into leaderstats like rank, level or another currency there shouldn’t be any major changes needed?

1 Like

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