Save Leaderstats not working correctly

This script incorrectly creates a leaderstat and saves it with the DataStoreService.
Parent of this script is ServerScriptService.

local stat = "Cash" 
local startamount = 2500 


local DataStore = game:GetService("DataStoreService")
local ds = DataStore:GetDataStore("LeaderStatSave")

game.Players.PlayerAdded:connect(function(player)
local leader = Instance.new("Folder",player)
leader.Name = "leaderstats"
local Cash = Instance.new("IntValue",leader)
Cash.Name = stat
Cash.Value = ds:GetAsync(player.UserId) or startamount
ds:SetAsync(player.UserId, Cash.Value)
Cash.Changed:connect(function()
ds:SetAsync(player.UserId, Cash.Value)
end)
end)

game.Players.PlayerRemoving:connect(function(player)
ds:SetAsync(player.UserId, player.leaderstats.Cash.Value) 
end)

image
Yes I have access allowed.

It works when I join the game and use console and type
game.Players.voideriaa.leaderstats.Cash.Value = 100

then I leave and rejoin and the Data Save worked but it doesn’t work when you get the output change from the ball function which is the gamble part of my gamble
(you get the money to your leaderstat but it doesn’t save on rejoin)

function SpawnBall()



	if bet == 0 then
	else
alreadyBet = true
		if game.Players.LocalPlayer.leaderstats.Cash.Value >= bet then
			game.Players.LocalPlayer.leaderstats.Cash.Value = game.Players.LocalPlayer.leaderstats.Cash.Value - bet



			local RS = game:GetService("ReplicatedStorage")

			local BallList = RS:WaitForChild("PlinkoBalls")

			local Balls = BallList:GetChildren()
			local items = BallList:GetChildren()
			local randomBall = items[math.random(1, #items)]
			alreadyBet = true

			print("Low Risk Ball Purchased")
			local ballCopy = randomBall:Clone()
			for i = 1, #Balls do
				ballCopy.Parent = game.Workspace.Plinko.Balls
				ballCopy.Name = "PlinkoBall"
				ballCopy.Value.Value = bet

			end

			if alreadyBet == true then
				print(ballCopy)
				return
			end
			end
		end
end

	local riskType = script.Parent.Parent.risk.Text
	
	if riskType == "LOW RISK" then

for I,Risks in pairs(game.ReplicatedStorage.LowRisk:GetChildren()) do
	--will clone all parts inside this folder.... so it will print something in the Output, and points may be allocated ( currently will not work because you must create your own system of points )
	local T = Risks:Clone()
	T.Parent = game.Workspace.LowRisk
	--T.Parent = game.Workspace.LowRisk
	T.Touched:Connect(function(Hit)
		if T.Name == "0.5x" then
			print("0.5x Outcome")
			local outcome = bet * 0.5
			game.Players.LocalPlayer.leaderstats.Cash.Value = game.Players.LocalPlayer.leaderstats.Cash.Value + outcome
		end
		if T.Name == "1.0x" then
			print("1.0x Outcome")
			local outcome = bet * 1.0
			game.Players.LocalPlayer.leaderstats.Cash.Value = game.Players.LocalPlayer.leaderstats.Cash.Value + outcome
		end
		if T.Name == "1.3x" then
			print("1.3x Outcome")
			local outcome = bet * 1.3
			game.Players.LocalPlayer.leaderstats.Cash.Value = game.Players.LocalPlayer.leaderstats.Cash.Value + outcome
		end
		if T.Name == "1.5x" then
			print("1.5x Outcome")
			local outcome = bet * 1.5
			game.Players.LocalPlayer.leaderstats.Cash.Value = game.Players.LocalPlayer.leaderstats.Cash.Value + outcome
		end
		if T.Name == "2.0x" then
			print("2.0x Outcome")
			local outcome = bet * 2.0
			game.Players.LocalPlayer.leaderstats.Cash.Value = game.Players.LocalPlayer.leaderstats.Cash.Value + outcome
		end	
		if T.Name == "3.5x" then
			print("3.5x Outcome")
			local outcome = bet * 3.5
			game.Players.LocalPlayer.leaderstats.Cash.Value = game.Players.LocalPlayer.leaderstats.Cash.Value + outcome
		end	
		Hit:Destroy() -- Destroy the cloned ball
		if T.Name == "0.8x" then
			print("0.8x Outcome")
			local outcome = bet * 0.8
			game.Players.LocalPlayer.leaderstats.Cash.Value = game.Players.LocalPlayer.leaderstats.Cash.Value + outcome
		end	

	end)
	end
	end


script.Parent.MouseButton1Click:Connect(SpawnBall)

There are three things wrong with this.

  1. In the leader stats creation script, NEVER, and I mean NEVER save every change or right after changing it to the saved value. You can save on an interval, when the player leaves, or when the game closes, but not on every change.
  2. You are trying to change the value from a local script, which will not affect the server and cause it not to save.
  3. In the leader stats script, you immediately set the parent of the Cash, which isn’t too bad of a problem but can affect performance. So, set the parent of the value AFTER all of the changes are made to the value.

So, in short, the leader stats script should look more like this:

local stat = "Cash" 
local startamount = 2500 


local DataStore = game:GetService("DataStoreService")
local ds = DataStore:GetDataStore("LeaderStatSave")

game.Players.PlayerAdded:connect(function(player)
	local leader = Instance.new("Folder",player)
	leader.Name = "leaderstats"
	
	local Cash = Instance.new("IntValue")
	Cash.Name = stat
	Cash.Value = ds:GetAsync(player.UserId) or startamount
	Cash.Parent = leader
end)

game.Players.PlayerRemoving:connect(function(player)
	ds:SetAsync(player.UserId, player.leaderstats.Cash.Value) 
end)

game:BindToClose(function()
	for i,player in pairs(game.Players:GetPlayers()) do
		ds:SetAsync(player.UserId, player.leaderstats.Cash.Value) 
	end
end)

Also, as for the plinko, you should handle that completely on the server and change the Cash from there.

1 Like

Its because your “bet” script is a local script, and saving is done with a server script, so basically when your money changes from the local script it is NOT viewed by the server since it is client-sided / affects the player ONLY and others wont see it, try remote Events or change your “bet” script to a “normal” script, you will need to modify some stuff tho…

1 Like

I need it to be local so I can get the path for localplayer

1 Like

You don’t need the code the be in a local script in order to get the path for the player. It’ll still work either way.

Try this script in a new server script:

local Players = game:GetService("Players")
local TestService = game:GetService("TestService")
local RunService = game:GetService("RunService")
local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("DataStore1") --Name the DataStore whatever you want

Players.PlayerAdded:Connect(function(player)

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


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

	local value1Data = Cash


	local s, e = pcall(function()
		value1Data = myDataStore:GetAsync(player.UserId..'-Value1') or 0 --check if they have data, if not it'll be "0"
	end)

	if s then
		Cash.Value = value1Data --setting data if its success
	else
		TestService:Error(e)  --if not success then we error it to the console
	end
end)

Players.PlayerRemoving:Connect(function(player)
    local s, e = pcall(function()
	   myDataStore:SetAsync(player.UserId..'-Value1', player.leaderstats.Cash.Value) --setting data
    end)
	if not s then TestService:Error(e) 
	end
end)

game:BindToClose(function()
  local s, e = pcall(function()
	for _, player in ipairs(Players:GetPlayers()) do
		myDataStore:SetAsync(player.UserId..'-data', player.leaderstats.Cash.Value)
	end
  end)
      if not s then 
          TestService:Error(e)
       end
end)

That code is already a server script.

What @voideriaa needs to be able to get the player and set the cash is to use RemoteEvents.

2 Likes