Data store not working in game and studio

I have made this data saving script with tutorials on Youtube (I understand the code and I didnt just copy paste it). When I left the game on studio, it doesnt “Print” anything when the player left. Making the data of the user not getting saved. I have tried playing the game itself outside the studio but still it doesnt work. I have turned on API service on roblox studio and there is no error printing. What could be the issue?

v Whole Script v

local Players = game:GetService("Players")
local SS = game:GetService("ServerStorage")
local DS = game:GetService("DataStoreService")
local playerDataStore = DS:GetDataStore("MainData")

local playerTable = {}

--[Functions]--

-->Add Speed
function addSpeed()
	while wait(1)  do
		for i, plr in pairs(playerTable) do
			local chr = plr.Character or plr.CharacterAdded:Wait()
			local speed = plr.leaderstats.Speed
			local Humanoid = chr:WaitForChild("Humanoid")
			speed.Value += 1
			Humanoid.WalkSpeed = speed.Value * 0.05
		end
	end
end

function saveData(plr)
	print("Saving")
	local leaderstats = plr.leaderstats
	local playerData = {leaderstats.Speed.Value, leaderstats.Wins.Value}
	
	local succ, err = pcall(function()
		playerDataStore:SetAsync(plr.UserId, playerData)
	end)
	if not succ then warn(err) end
	
end

--[Main]--

--> Player Joining
Players.PlayerAdded:Connect(function(plr)
	--Add speed and leaderboard
	local leaderboard = Instance.new("Folder")
	leaderboard.Parent = plr
	leaderboard.Name = "leaderstats"
	
	local Speed = Instance.new("NumberValue")
	Speed.Name = "Speed"
	Speed.Parent = leaderboard
	Speed.Value = 1
	
	local Wins = Instance.new("NumberValue")
	Wins.Name = "Wins"
	Wins.Parent = leaderboard
	Wins.Value = 0
	
	local Zone = Instance.new("StringValue")
	Zone.Name = "Zone"
	Zone.Parent = plr
	Zone.Value = "Zone 1"
	
	local trailFolder = Instance.new("Folder")
	trailFolder.Parent = plr
	trailFolder.Name = "Trail"
	
	local playerData 
	
	local succ, err = pcall(function()
		local playerID = plr.UserId
		playerData = playerDataStore:GetAsync(playerID)
	end)
	print(playerData ,succ, err)
	if succ then
		if playerData then
			Speed.Value = playerData.Speed
			Wins.Value = playerData.Wins
			print("Has")
		else
			print("Has not")
			Speed.Value = 1
			Wins.Value = 0
		end
	else
		warn(err)
		Speed.Value = 1
		Wins.Value = 0
	end
	
	
	plr.CharacterAdded:Connect(function(chr)
		local BBGui = SS.Misc.playerBillboard:Clone()
		BBGui.Parent = chr.Head
		BBGui.Main.userName.Text = plr.Name
		BBGui.Main.userSpeed.Text = "👟: "..Speed.Value
		BBGui.Main.userWins.Text = "🏆:"..Wins.Value
		
		local trailAttachment = SS.Misc.TrailAttachment:Clone()
		trailAttachment.Parent = chr
		trailAttachment.Weld.Part1 = chr.HumanoidRootPart
		
		for _, trail in pairs(plr.Trail:GetChildren()) do
			if trail:GetAttribute("Equip") == true then
				local trail = trail:Clone()
				trail.Parent = trailAttachment
				trail.Attachment0 = trailAttachment.Attachment1
				trail.Attachment1 = trailAttachment.Attachment2
				break
			end
		end
		
		chr.Humanoid.WalkSpeed = Speed.Value * 0.05
	end)
	
	table.insert(playerTable, plr)
	
end)

addSpeed()

Players.PlayerRemoving:Connect(function(plr)
	print("Leaving")
	saveData(plr)
end)

game:BindToClose(function()
	for _, plr in pairs(game.Players:GetPlayers()) do
		saveData(plr)
	end
end)

Ok I see the problem.

This is how you load the values:

			Speed.Value = playerData.Speed
			Wins.Value = playerData.Wins

Which in theory it would work, the problem is that PlayerData doesnt have a Speed Value.
How to fix this?
In your save function do this instead:

-- Currrent
local playerData = {leaderstats.Speed.Value, leaderstats.Wins.Value}
-- What should work
local playerData = {
    Speed = leaderstats.Speed.Value, 
    Wins = leaderstats.Wins.Value
}

See by just putting the values into a table it sets the key for the item stored as a number, with this we can set it to what we want!

Hope this works!

1 Like

You cannot save arrays in a datastore, instead, you’ll have to encode them using JSON, and decode them after. You can achieve this by using HttpService. Also, you saved it as an array, but tried to load it as a dictionary. The code below should work:

local HttpService = game:GetService("HttpService")
local Players = game:GetService("Players")
local SS = game:GetService("ServerStorage")
local DS = game:GetService("DataStoreService")
local playerDataStore = DS:GetDataStore("MainData")

local playerTable = {}

--[Functions]--

-->Add Speed
function addSpeed()
	while wait(1)  do
		for i, plr in pairs(playerTable) do
			local chr = plr.Character or plr.CharacterAdded:Wait()
			local speed = plr.leaderstats.Speed
			local Humanoid = chr:WaitForChild("Humanoid")
			speed.Value += 1
			Humanoid.WalkSpeed = speed.Value * 0.05
		end
	end
end

function saveData(plr)
	print("Saving")
	local leaderstats = plr.leaderstats
	local playerData = {["Speed"] = leaderstats.Speed.Value; ["Wins"] = leaderstats.Wins.Value;}
	
	local succ, err = pcall(function()
		playerDataStore:SetAsync(plr.UserId, HttpService:JSONEncode(playerData))
	end)
	if not succ then warn(err) end
	
end

--[Main]--

--> Player Joining
Players.PlayerAdded:Connect(function(plr)
	--Add speed and leaderboard
	local leaderboard = Instance.new("Folder")
	leaderboard.Parent = plr
	leaderboard.Name = "leaderstats"
	
	local Speed = Instance.new("NumberValue")
	Speed.Name = "Speed"
	Speed.Parent = leaderboard
	Speed.Value = 1
	
	local Wins = Instance.new("NumberValue")
	Wins.Name = "Wins"
	Wins.Parent = leaderboard
	Wins.Value = 0
	
	local Zone = Instance.new("StringValue")
	Zone.Name = "Zone"
	Zone.Parent = plr
	Zone.Value = "Zone 1"
	
	local trailFolder = Instance.new("Folder")
	trailFolder.Parent = plr
	trailFolder.Name = "Trail"
	
	local playerData 
	
	local succ, err = pcall(function()
		local playerID = plr.UserId
		playerData = HttpService:JSONDecode(playerDataStore:GetAsync(playerID))
	end)
	print(playerData ,succ, err)
	if succ then
		if playerData then
			Speed.Value = playerData["Speed"]
			Wins.Value = playerData["Wins"}
			print("Has")
		else
			print("Has not")
			Speed.Value = 1
			Wins.Value = 0
		end
	else
		warn(err)
		Speed.Value = 1
		Wins.Value = 0
	end
	
	
	plr.CharacterAdded:Connect(function(chr)
		local BBGui = SS.Misc.playerBillboard:Clone()
		BBGui.Parent = chr.Head
		BBGui.Main.userName.Text = plr.Name
		BBGui.Main.userSpeed.Text = "👟: "..Speed.Value
		BBGui.Main.userWins.Text = "🏆:"..Wins.Value
		
		local trailAttachment = SS.Misc.TrailAttachment:Clone()
		trailAttachment.Parent = chr
		trailAttachment.Weld.Part1 = chr.HumanoidRootPart
		
		for _, trail in pairs(plr.Trail:GetChildren()) do
			if trail:GetAttribute("Equip") == true then
				local trail = trail:Clone()
				trail.Parent = trailAttachment
				trail.Attachment0 = trailAttachment.Attachment1
				trail.Attachment1 = trailAttachment.Attachment2
				break
			end
		end
		
		chr.Humanoid.WalkSpeed = Speed.Value * 0.05
	end)
	
	table.insert(playerTable, plr)
	
end)

addSpeed()

Players.PlayerRemoving:Connect(function(plr)
	print("Leaving")
	saveData(plr)
end)

game:BindToClose(function()
	for _, plr in pairs(game.Players:GetPlayers()) do
		saveData(plr)
	end
end)
1 Like

Datastore service automatically uses JSONEncode and JSONDecode by default so there isnt a reason to do this.

That and again they reference something that doesnt exist like I said in my reply :]

I tried your code and it prints the “err”. It says “Argument missing 1 or nil”. What should I do?

I tried this but still, no luck and it doesnt work… thank you though

1 Like

When the player leaves, it doesnt print anything or like the function when the player leaves doesnt run. Is there a way to fix this?

Can I see your code with my changes? There could be another problem, but the thing I mentioned is still a part of the problem, at least from the look of it

I only changed the line that you mentioned

local Players = game:GetService("Players")
local SS = game:GetService("ServerStorage")
local DS = game:GetService("DataStoreService")
local playerDataStore = DS:GetDataStore("MainData")

local playerTable = {}

--[Functions]--

-->Add Speed
function addSpeed()
	while wait(1)  do
		for i, plr in pairs(playerTable) do
			local chr = plr.Character or plr.CharacterAdded:Wait()
			local speed = plr.leaderstats.Speed
			local Humanoid = chr:WaitForChild("Humanoid")
			speed.Value += 1
			Humanoid.WalkSpeed = speed.Value * 0.05
		end
	end
end

--> Save player data
function saveData(plr)
	print("Saving")
	local leaderstats = plr.leaderstats
	local playerData = {
		Speed = leaderstats.Speed.Value, 
		Wins = leaderstats.Wins.Value}
	
	local succ, err = pcall(function()
		playerDataStore:SetAsync(plr.UserId, playerData)
	end)
	if not succ then warn(err) end
	
end

--[Main]--

--> Player Joining
Players.PlayerAdded:Connect(function(plr)
	--Add speed and leaderboard
	local leaderboard = Instance.new("Folder")
	leaderboard.Parent = plr
	leaderboard.Name = "leaderstats"
	
	local Speed = Instance.new("NumberValue")
	Speed.Name = "Speed"
	Speed.Parent = leaderboard
	Speed.Value = 1
	
	local Wins = Instance.new("NumberValue")
	Wins.Name = "Wins"
	Wins.Parent = leaderboard
	Wins.Value = 0
	
	local Zone = Instance.new("StringValue")
	Zone.Name = "Zone"
	Zone.Parent = plr
	Zone.Value = "Zone 1"
	
	local trailFolder = Instance.new("Folder")
	trailFolder.Parent = plr
	trailFolder.Name = "Trail"
	
	local playerData 
	
	local succ, err = pcall(function()
		local playerID = plr.UserId
		playerData = playerDataStore:GetAsync(playerID)
	end)
	print(playerData ,succ, err)
	if succ then
		if playerData then
			Speed.Value = playerData.Speed
			Wins.Value = playerData.Wins
			print("Has")
		else
			print("Has not")
			Speed.Value = 1
			Wins.Value = 0
		end
	else
		warn(err)
		Speed.Value = 1
		Wins.Value = 0
	end
	
	
	plr.CharacterAdded:Connect(function(chr)
		local BBGui = SS.Misc.playerBillboard:Clone()
		BBGui.Parent = chr.Head
		BBGui.Main.userName.Text = plr.Name
		BBGui.Main.userSpeed.Text = "👟: "..Speed.Value
		BBGui.Main.userWins.Text = "🏆:"..Wins.Value
		
		local trailAttachment = SS.Misc.TrailAttachment:Clone()
		trailAttachment.Parent = chr
		trailAttachment.Weld.Part1 = chr.HumanoidRootPart
		
		for _, trail in pairs(plr.Trail:GetChildren()) do
			if trail:GetAttribute("Equip") == true then
				local trail = trail:Clone()
				trail.Parent = trailAttachment
				trail.Attachment0 = trailAttachment.Attachment1
				trail.Attachment1 = trailAttachment.Attachment2
				break
			end
		end
		
		chr.Humanoid.WalkSpeed = Speed.Value * 0.05
	end)
	
	table.insert(playerTable, plr)
	
end)

addSpeed()

game.Players.PlayerRemoving:Connect(function(plr)
	print("Leaving")
	table.remove(playerTable, table.find(playerTable, plr))
	saveData(plr)
end)

game:BindToClose(function()
	for _, plr in pairs(game.Players:GetPlayers()) do
		saveData(plr)
	end
end)

Ohh wait I see now.

So you call the addSpeed function, of which never stops running, thus the game never connects the RbxEvent .PlayerRemoving!
Simple fix!

task.spawn!

Just replace your code:

local Players = game:GetService("Players")
local SS = game:GetService("ServerStorage")
local DS = game:GetService("DataStoreService")
local playerDataStore = DS:GetDataStore("MainData")

local playerTable = {}

--[Functions]--

-->Add Speed
function addSpeed()
	while wait(1)  do
		for i, plr in pairs(playerTable) do
			local chr = plr.Character or plr.CharacterAdded:Wait()
			local speed = plr.leaderstats.Speed
			local Humanoid = chr:WaitForChild("Humanoid")
			speed.Value += 1
			Humanoid.WalkSpeed = speed.Value * 0.05
		end
	end
end

--> Save player data
function saveData(plr)
	print("Saving")
	local leaderstats = plr.leaderstats
	local playerData = {
		Speed = leaderstats.Speed.Value, 
		Wins = leaderstats.Wins.Value}
	
	local succ, err = pcall(function()
		playerDataStore:SetAsync(plr.UserId, playerData)
	end)
	if not succ then warn(err) end
	
end

--[Main]--

--> Player Joining
Players.PlayerAdded:Connect(function(plr)
	--Add speed and leaderboard
	local leaderboard = Instance.new("Folder")
	leaderboard.Parent = plr
	leaderboard.Name = "leaderstats"
	
	local Speed = Instance.new("NumberValue")
	Speed.Name = "Speed"
	Speed.Parent = leaderboard
	Speed.Value = 1
	
	local Wins = Instance.new("NumberValue")
	Wins.Name = "Wins"
	Wins.Parent = leaderboard
	Wins.Value = 0
	
	local Zone = Instance.new("StringValue")
	Zone.Name = "Zone"
	Zone.Parent = plr
	Zone.Value = "Zone 1"
	
	local trailFolder = Instance.new("Folder")
	trailFolder.Parent = plr
	trailFolder.Name = "Trail"
	
	local playerData 
	
	local succ, err = pcall(function()
		local playerID = plr.UserId
		playerData = playerDataStore:GetAsync(playerID)
	end)
	print(playerData ,succ, err)
	if succ then
		if playerData then
			Speed.Value = playerData.Speed
			Wins.Value = playerData.Wins
			print("Has")
		else
			print("Has not")
			Speed.Value = 1
			Wins.Value = 0
		end
	else
		warn(err)
		Speed.Value = 1
		Wins.Value = 0
	end
	
	
	plr.CharacterAdded:Connect(function(chr)
		local BBGui = SS.Misc.playerBillboard:Clone()
		BBGui.Parent = chr.Head
		BBGui.Main.userName.Text = plr.Name
		BBGui.Main.userSpeed.Text = "👟: "..Speed.Value
		BBGui.Main.userWins.Text = "🏆:"..Wins.Value
		
		local trailAttachment = SS.Misc.TrailAttachment:Clone()
		trailAttachment.Parent = chr
		trailAttachment.Weld.Part1 = chr.HumanoidRootPart
		
		for _, trail in pairs(plr.Trail:GetChildren()) do
			if trail:GetAttribute("Equip") == true then
				local trail = trail:Clone()
				trail.Parent = trailAttachment
				trail.Attachment0 = trailAttachment.Attachment1
				trail.Attachment1 = trailAttachment.Attachment2
				break
			end
		end
		
		chr.Humanoid.WalkSpeed = Speed.Value * 0.05
	end)
	
	table.insert(playerTable, plr)
	
end)

task.spawn(addSpeed) -- This is a fix hopefully

game.Players.PlayerRemoving:Connect(function(plr)
	print("Leaving")
	table.remove(playerTable, table.find(playerTable, plr))
	saveData(plr)
end)

game:BindToClose(function()
	for _, plr in pairs(game.Players:GetPlayers()) do
		saveData(plr)
	end
end)

(If you want to see what changed, just look for where you call the addSpeed function).

So the problem is that the addSpeed function is a while loop that will run forever, hence stopping any code after the point you triggered the function, but using task.spawn it ignores the yield of the function, hence allowing all of the other code to run!

1 Like

Thank you so much for the help and also @PagomenosOruxeiosss, thank you.
It is fixed now. The “task.spawn” fixed the problem. I didnt notice that the while loop is causing the problem

2 Likes