I have a data saving script but I don't whats wrong with it

  1. What do you want to achieve? I am trying to have three values (stage, deaths and time spent).

  2. What is the issue? My stages are not saving, the seconds are not going up and the deaths are not saving. These are my checkpoints : (they have teamchangeontouch off) Capture

  3. What solutions have you tried so far? I have tried the scripting helpers website but it was quite confusing.

This is my code:

local dss = game:GetService("DataStoreService")
local Datastore = dss:GetDataStore("ObbyData")
local checkpoints = workspace.Checkpoints
print("Checkpoints leaderstats working")
print("Deaths leaderstats working")
print("Time leaderstats working")
game.Players.PlayerAdded:Connect(function(plr)
	local obbyData = Datastore:GetAsync(plr.UserId .. "-obbyStageProgress")
	local stats = Instance.new("Folder")
	stats.Name = "leaderstats"
	stats.Parent = plr
	local stage = Instance.new("StringValue")
	stage.Name = "Stage"
	stage.Value = obbyData or 1
	stage.Parent = stats
	local wipeouts = Instance.new("IntValue")
	wipeouts.Name = "Deaths"
	wipeouts.Value = 0
	wipeouts.Parent = stats
	local Data = Datastore:GetAsync(plr.UserId)
	if Data then
		wipeouts.Value = Data
	end
	local second = Instance.new("IntValue")
	second.Name = "Seconds"
	second.Value = stats
	local Dat = Datastore:GetAsync(plr.UserId)
	if Dat then
		second.Value = Data
	end
	game.Players.PlayerRemoving:Connect(function(Player)
	Datastore:SetAsync(Player.UserId, Player.leaderstats.Seconds.Value,Player.leaderstats.Deaths.Value) -- Change "Money" with your currency.
end)

	local char = plr.Character or plr.CharacterAdded:Wait()
	char:WaitForChild("HumanoidRootPart").CFrame = checkpoints[stage.Value].CFrame
	char.Humanoid.Touched:Connect(function(touch)
		if touch.Parent == checkpoints then 
			if (tonumber(touch.Name)and tonumber(touch.Name)>tonumber(stage.Value))or touch.Name == "End" then
				stage.Value = touch.Name
				pcall(function()
					Datastore:SetAsync(plr.UserId.. "-obbyStageProgress", plr.leaderstats.Stage.Value,plr.leaderstats.Deaths.Value,plr.leaderstats.Seconds.Value)
					
				end)
			end
		end
	end)
	plr.CharacterAdded:Connect(function(char)
		local hrp = char:WaitForChild("HumanoidRootPart")
		local humanoid = char:WaitForChild("Humanoid")
		hrp:GetPropertyChangedSignal("CFrame"):Wait()
		hrp.CFrame = checkpoints[stage.Value].CFrame
			
					
		humanoid.Died:Connect(function(touch)
				wipeouts.Value = wipeouts.Value +1
		
			if touch.Parent == checkpoints then
				if (tonumber(touch.Name)and tonumber(touch.Name)>tonumber(stage.Value))or touch.Name == "End"then
					stage.Value = touch.Name
while true do
						wait(2)
						
						wipeout.Value = wipeout.Value + 1	
					end
					pcall(function()
													
						game.Players.PlayerRemoving:Connect(function(player)
							Datastore:SetAsync(plr.UserId.. "-obbyStageProgress", plr.leaderstats.Stage.Value,plr.leaderstats.Deaths.Value,plr.leaderstats.Seconds.Value
					
						end)
					end)
									
										
			end
		end
			

				end
			end
		end)
	end)
end)

This is in server script service

The way you’re saving data here is quite confusing, if you need to save multiple values to a single DataStore, then try using a dictionary instead of various keys.

You could instead do that separately or use a table ({Seconds.Value, Deaths.Value}), the way you’re currently handling a tuple of values is incorrect.

Why’s your PlayerRemoving connection within the PlayerAdded connection as well? Do that separately for neatness and functionality (for some reason you’ve got 2 PlayerRemoving connections?) .

One way you could do this: you’ll need to make sure the values are automatically set to their corresponding names, e,g the stage would be the stage the player’s on, could be achieved with a Touched and Changed event etc.

Do something like this

 -- pseudo code, not intended to fully function
 -- retrieve data, wrap in pcall
 -- add functionality, like teleporting the player to their respective stage etc.

 local function onAdded(player)

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

 if not success then --[[retry retrieval for a finite amount of time]] end
 data = data or { stage = 1, wipeouts = 0, seconds = 0 }
 
 local stats = Instance.new("Folder")      
 stats.Name = "leaderstats"

 local stage = Instance.new("IntValue")
 stage.Name = "stage"
 stage.Value = data.stage
 stage.Parent = stats
 
 local wipeouts = Instance.new("IntValue")
 wipeouts.Name = "wipeouts"
 wipeouts.Value = data.wipeouts
 wipeouts.Parent = stats

 local seconds = Instance.new("IntValue")
 seconds.Name = "seconds"
 seconds.Value = data.seconds
 seconds.Parent = stats

 stats.Parent = player

end)

players.PlayerAdded:Connect(onAdded)

 local function onRemoving(player)
      local stageValue = player.stage.Value
      local wipeoutsValue  = player.wipeouts.Value
      local secondsValue = player.seconds.Value

      DataStore:SetAsync(player.UserId, {stage = stageValue, wipeouts = wipeoutsValue, seconds = secondsValue})  
      -- pcall and stuff for catching errors
 end

 players.PlayerRemoving:Connect(onRemoving)