How to make checkpoints save?

  1. What do you want to achieve? That my checkpoints save

  2. What is the issue? I have no idea how to do that

  3. What solutions have you tried so far? I’ve tried looking but I didn’t get what they were doing

DataStore Script

local DataStore = game:GetService("DataStoreService")
local DeathStore = DataStore:GetDataStore("Deaths")
local RCStore = DataStore:GetDataStore("RC")

game.Players.PlayerAdded:Connect(function(player)

	local leaderstats = Instance.new("Model", player)
	leaderstats.Name = "leaderstats"

	local Deaths = Instance.new("IntValue", leaderstats)
	Deaths.Name = "Deaths"
	
	local RC = Instance.new("IntValue", leaderstats)
	RC.Name = "RC"

	pcall(function()
		local DeathValue = DeathStore:GetAsync(player.UserId)
		local RCValue = RCStore:GetAsync(player.UserId)
		
		player.CharacterAdded:Connect(function(character)
			character:WaitForChild("Humanoid").Died:Connect(function()
				Deaths.Value = Deaths.Value + 1
			end)
		end)

		if DeathValue then
			Deaths.Value = DeathValue
		else
			Deaths.Value = 0
		end

		if RCValue then
			RC.Value = RCValue
		else
			RC.Value = 0
		end
		
	end)
end)

game.Players.PlayerRemoving:Connect(function(player)
	pcall(function()
		if player:FindFirstChild("leaderstats") then
			if player.leaderstats:FindFirstChild("Deaths") and player.leaderstats.Deaths.Value then
				DeathStore:SetAsync(player.UserId, player.leaderstats.Deaths.Value)
			end
		end
		
		if player:FindFirstChild("leaderstats") then
			if player.leaderstats:FindFirstChild("RC") and player.leaderstats.RC.Value then
				RCStore:SetAsync(player.UserId, player.leaderstats.RC.Value)
			end
		end
	end)
end)

game:BindToClose(function()
	wait()
end)

How would I implement that my checkpoints save in my datastore script? Feedback is appreciated!

You could number the checkpoint 1 - how many total checkpoints you have. Just save the number of the checkpoint the player was on in the data store. Another thing – When the player steps on a checkpoint, you can make a variable inside the player and change it according to the number of the checkpoint and use the number in the variable to save. When they come back to play, if they have a checkpoint saved, teleport them to that checkpoint using the number. If they don’t have checkpoint saved, it most likely means they have not played the game before, therefore you’ll spawn them at the 1st checkpoint.

So maybe like –

datastorename:SetAsync(player.UserId, player.Checkpoint.Value)

And when joining back –

local CheckpointData

local success, errorMessage = pcall(function()
  CheckpointData = datastorename:GetAsync(player.UserId)

end)

if success then
   if CheckpointData then
   -- teleport them
   else
     -- spawn them at first checkpoint
   end
  print("Success!")
else

    warn(errorMessage)
end

Obviously not the same variables you’ll use but you get the point.

4 Likes
local Players = game:GetService("Players")
local DataStores = game:GetService("DataStoreService")
local DataStore = DataStores:GetDataStore("DataStore")

local ProtectedCall = pcall

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

	local Deaths = Instance.new("IntValue")
	Deaths.Name = "Deaths"
	Deaths.Parent = Leaderstats

	local RC = Instance.new("IntValue")
	RC.Name = "RC"
	RC.Parent = Leaderstats
		
	local Success, Result = ProtectedCall(function()
		return DataStore:GetAsync("Data_"..Player.UserId)
	end)
	
	if Success then
		if Result then
			if type(Result) == "table" then
				Deaths.Value = Result[1] or 0
				RC.Value = Result[2] or 0
			end
		end
	else
		warn(Result)
	end
	
	Player.CharacterAdded:Connect(function(Character)
		local Humanoid = Character:WaitForChild("Humanoid")
		Humanoid.Died:Connect(function()
			Deaths.Value += 1
		end)
	end)
end)

Players.PlayerRemoving:Connect(function(Player)
	local Success, Result = ProtectedCall(function()
		return DataStore:SetAsync("Data_"..Player.UserId, {Player.leaderstats.Deaths.Value, Player.leaderstats.RC.Value})
	end)
	
	if Success then
		return
	else
		warn(Result)
	end
end)

game:BindToClose(function()
	for _, Player in ipairs(Players:GetPlayers()) do
		local Success, Result = ProtectedCall(function()
			return DataStore:SetAsync("Data_"..Player.UserId, {Player.leaderstats.Deaths.Value, Player.leaderstats.RC.Value})
		end)

		if Success then
			return
		else
			warn(Result)
		end
	end
end)

I’d recommend minimising DataStore requests by storing everything inside of a table so that you only need to make a single DataStore request when both saving and loading a player’s data. I’ve also added some other minor improvement/optimisations and made use of the BindToClose() function as well.

I’m assuming the “RC” stat tracks checkpoints, with this script the value of that stat will save (just remember to change that stat whenever the player reaches a new checkpoint).

2 Likes