Saving Spawnpoint System

I’m trying to make a save system for checkpoints. the problem is the following: does anyone know how to make one spawn in a specific location as if it were a checkpoint but it is a part, I am also trying to make it so that only people can spawn with the value of the stage.
This is the script for saving and creating the value:

local DataStore = game:GetService("DataStoreService")
local Data1 = DataStore:GetDataStore("Data1")
local Data2 = DataStore:GetDataStore("Data2")

game.Players.PlayerAdded:Connect(function(player)
	
	local folder = Instance.new("Folder", player)
	folder.Name = "Stats"
	
	local coins = Instance.new("IntValue", folder)
	coins.Name = "coins"
	
	local stage = Instance.new("IntValue", folder)
	stage.Name = "stage"
	
	local DataA1
	local DataA2
	
	local ok, errorf = pcall(function()
		DataA1 = Data1:GetAsync(player.UserId)
		DataA2 = Data2:GetAsync(player.UserId)
	end)
	if ok then
		print("Data")
		coins.Value = DataA1 or 100
		stage.Value = DataA2 or 1
	else
		print("Error")
		error(errorf)
	end
	
	
end)
game.Players.PlayerRemoving:Connect(function(player)
	
	local ok, errorf = pcall(function()
		Data1:SetAsync(player.UserId, player.Stats.coins.Value)
		Data2:SetAsync(player.UserId, player.Stats.stage.Value)
	end)
	if ok then
		print("DataB")
	else
		print("ErrorB")
		error(errorf)
	end
end)

This is the other script that I am trying to do so that they spawn there but I don’t know how to do it when they die and it has some bugs

local savespawn1 = game.Workspace:WaitForChild("SpawnPoint1")

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(char)
		local hum = char:WaitForChild("Humanoid")
		local Torso = player.Character:WaitForChild("UpperTorso")
			if player.Stats.stage.Value == 1 then
			Torso.CFrame = savespawn1.CFrame
				
			end
		end)
	end)
2 Likes

Maybe add a task.wait() before Torso.CFrame = savespawn1.CFrame. Put in the parameters a good number that works for you.

rather than writing a new if statement for each checkpoint i recommend putting all the checkpoints in a folder in workspace and doing this:

local folder = game.Workspace.SpawnsFolder

--the script to determine which spawn
HumanoidRootPart:PivotTo(folder["savespawn"..tostring(player.Stats.stage.Value)])

Are you referring to saving the blocks in which I want the checkpoint to be saved to have easy access to that data and be able to change the Cframe data?

1 Like

I just realized something about your datastore system. It’s impossible make two requests through one pcall

1 Like

well my obby uses these to teleport player and update checkpoint

  • teleport using SetPrimaryPartCFrame
  • name checkpoints 1,2,3… or add attribute called “checkpointValue” and compare to leaderstats when touched. this way you know where to teleport to
heres my tp code unedited
player.CharacterAdded:Connect(function(character)
		-- Special case (player just started game or had prestiged (resets stage))
		if stage.Value == 0 then 
			local spawnpoint = game.Workspace.BaseParts.Other:WaitForChild("spawn") -- we could just check for object type too without checking name
			if not spawnpoint then return end 

			repeat task.wait() until character.PrimaryPart ~= nil
			character:SetPrimaryPartCFrame(spawnpoint.CFrame:ToWorldSpace(CFrame.new(0,5,0)))
			return
		end
		
		-- General case
		for _, checkpoint in ipairs(checkpoints:GetChildren()) do
			if tostring(stage.Value) == checkpoint.Name and checkpoint:FindFirstChild("Hitbox") then
				local hitbox = checkpoint:FindFirstChild("Hitbox")
				if not hitbox then return end 
			
				repeat task.wait() until character.PrimaryPart ~= nil
				character:SetPrimaryPartCFrame(hitbox.CFrame:ToWorldSpace(CFrame.new(0,1,-4) * CFrame.Angles(0,math.rad(-90),0)))
				break
			end
		end
	end)
if tp code is hard to understand see this

image

We can use HumanoidRoorPart it’s another way.

yes you can and it works perfectly

the hitbox would be what the person has to touch to change the value of the stage?

yeah! touch hitbox → compare checkpointName and playerStage sizes → update stage if larger
but i would use attributes instead of model names if i was starting now. its easier to edit

simplified version of the code i use (server)
for _,checkpointDescendant in ipairs(checkpoints:GetDescendants()) do
	
	-- Hitbox stuff
	if checkpointDescendant.Name == "Hitbox" then
		local hitbox = checkpointDescendant

		hitbox.Touched:Connect(function(toucher)
		if game:GetService("Players"):GetPlayerFromCharacter(toucher.Parent) then
			local player = game:GetService("Players"):GetPlayerFromCharacter(toucher.Parent)
			local leaderstats = player:WaitForChild("leaderstats")
			local stage = leaderstats:WaitForChild("Stage")
			local stageDataStore = DataStore2("stage 2", player) -- if youre not using DataStore2 update when player leaves instead
			local coinsDataStore = DataStore2("coins", player)
						
			if tonumber(checkpoint.Name) > stage.Value and tonumber(checkpoint.Name) - stage.Value <= 4 then -- if delta<=4 (some stages can be skipped with skill)
				coinsDataStore:Increment((tonumber(checkpoint.Name) - stage.Value),0) -- 1 coin/stage
				stageDataStore:Set(tonumber(checkpoint.Name))
			elseif ... then -- add any cheat prevention here, like "if checkpoint is 4 higher than stage" or "if players stage is changing > 10 stages/s"
				respawnModule.respawnPlayer(player)
			end
		end
	end
end

additionally if you want you can only connect Touched if its higher than players stage in first place, and disconnect when player surpasses it so you wont be storing useless connections