Need help with an obby checkpoint script!

Yo, I’m a beginner dev and if y’all don’t mind I need a little assistance with a script here. Very rarely, when a player loads into the game on stage 1, they go to touch stage 2 and remain on stage 1 until resetting. I believe it started happening when I added my “checkpoint sounds” local script and I’ll see what happens if I remove/tamper with that. I haven’t touched the checkpoint script since around May. But I just need to know what’s going on with it down below:


local checkpoints = workspace:WaitForChild("Checkpoints")

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local DatastoreService = game:GetService("DataStoreService")
local Data = DatastoreService:GetDataStore("1")
local sessionData = {}

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

	local stage = Instance.new("NumberValue")
	stage.Name = "Stage"
	stage.Parent = leaderstats

	local success = nil
	local playerData = nil
	local attempt = 1

	repeat 
		success, playerData = pcall(function() -- here pcall or protected call is just repeat waiting until the data loads for the player
			return Data:GetAsync(player.UserId)
		end)

		attempt += 1
		if not success then 
			warn(playerData)
			task.wait(2)
		end

	until success or attempt == 5 -- it repeats it until it loads

	if success then --if it loads then make the table with their data inside
		print("Data loaded: "..player.Name)
		if not playerData then -- if they have no table then they're a new player so we create the table 
			print("new player, giving default data")

			playerData = {
				["Stage"] = 1, --add all your values and stuff inside of the data

			}
		end

		sessionData[player.UserId] = playerData --set the data to a table with the players id and make to make a variable
	else
		warn("couldnt load data: "..player.Name)
		player:Kick("couldnt load your data, rejoin") --if the data couldnt load we kick them so their not just sitting there forever waiting
	end

	stage.Value = sessionData[player.UserId].Stage --here we get the numbervalue created above and get the value of it and set it to the value inside of the table

	stage:GetPropertyChangedSignal("Value"):Connect(function()
		sessionData[player.UserId].Stage = stage.Value --update the table value whenever the leaderstat value changes
	end)


	leaderstats.Parent = player

end

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

	player.CharacterAdded:Connect(function(char)
		local leaderstats = player:WaitForChild("leaderstats")
		local stage = leaderstats.Stage

		local hum = char:WaitForChild("Humanoid")
		task.wait()
		char:MoveTo(checkpoints[stage.Value].Position)

		hum.Touched:Connect(function(hit)
			if hit.Parent == checkpoints then
				if tonumber(hit.Name) == stage.Value + 1 then
					stage.Value += 1
				end
			end
		end)
	end)
end)



function PlayerLeaving(player)

	if sessionData[player.UserId] then
		local success = nil
		local errorMsg = nil
		local attempt = 1


		repeat
			success, errorMsg = pcall(function()
				Data:SetAsync(player.UserId, sessionData[player.UserId]) --here is the same as loading data just repeat waits until the data saves
			end)

			attempt += 1
			if not success then 
				warn(errorMsg)
				task.wait(2)
			end

		until success or attempt == 5

		if success then 
			print("Data saved: "..player.Name)
		else
			warn("Cant save: "..player.Name)
		end

	end

end

Players.PlayerRemoving:Connect(PlayerLeaving)

function ServerShutdown()
	if RunService:IsStudio() then
		return
	end

	for i, player in ipairs(Players:GetPlayers()) do
		task.spawn(function()
			PlayerLeaving(player)
		end)
	end
end
game:BindToClose(ServerShutdown)
3 Likes

Try this in your Players.PlayerAdded function:

Players.PlayerAdded:Connect(function(player)
	PlayerAdded(player)
	local char = player.Character or player.CharacterAdded:Wait()
	--Rest of the script

I believe that your other PlayerAdded function is yielding the script, which causes the CharacterAdded event to not be fired when the player joins.

1 Like

– Define the checkpoint object
local Checkpoint = {}
Checkpoint.__index = Checkpoint

– Constructor function for creating a new checkpoint
function Checkpoint.new(position)
local self = setmetatable({}, Checkpoint)
self.position = position
self.activated = false
return self
end

– Function to check if a player has reached the checkpoint
function Checkpoint:playerReached(playerPosition)
local distance = (playerPosition - self.position).Magnitude
return distance < 5 – Adjust the distance threshold as needed
end

– Function to activate the checkpoint for a player
function Checkpoint:activate()
self.activated = true
print(“Checkpoint activated!”)
end

– Sample usage:

– Create a checkpoint at a specific position
local checkpoint1 = Checkpoint.new(Vector3.new(10, 0, 0))

– Simulate a player reaching the checkpoint
local playerPosition = Vector3.new(9, 0, 0)
if checkpoint1:playerReached(playerPosition) then
checkpoint1:activate()
end

Here you go;)

1 Like

I think you are overriding your variables.

Change this to:

repeat 
		success, result = pcall(function() -- here pcall or protected call is just repeat waiting until the data loads for the player
            local data = Data:GetAsync(player.UserId)
            playerData = data
			return data
		end)

		attempt += 1
		if not success then 
			warn(result)
			task.wait(2)
		end

	until success or attempt == 5
1 Like

Gotcha I’ll test it out right now! :sunglasses:

1 Like

Huh? Mane I’m a beginner so I’m confused on what to do here! :joy::sob:

1 Like

It now shows 2 blue lines under the words result and playerData, so I’ll try putting local in front of the lines

Alright this works perfectly, i rejoined a few times and tested it out! Only problem is it doesn’t save the progress anymore when the person leaves. Like if they leave on stage 50 they’ll be there when they join back! Any idea how to fix that, actually is that even needed? What I’m worried about is if somebody leaves on stage 100 and they wanna finish my game, if it kicks them all the way back to stage 1 will they get upset about it? :thinking:

I’m not sure, ill look at the code and try to find the issue.

1 Like

Preciate you, take your time :sunglasses:

1 Like

Could it be because you set the stage in playerData to 1 every time? Maybe try setting it to the

result

variable instead?

1 Like

What do I change in that section? How do i do that?

Change this to


playerData = {
		      ["Stage"] = result, --add all your values and stuff inside of the data
}

This should set the stage to the result of your GetAsync() call.

1 Like

Done, now the only thing it says is “unknown global ‘result’ “

Oh, I’m sorry to hear that, I’m also not that good at it, but I’m okay

1 Like

try using

playerData = {
		      ["Stage"] = playerData.Stage, --add all your values and stuff inside of the data
}
1 Like

All good mane, nothing wrong with us being new. I’m happy y’all are all being helpful because other people just tell me “remoteevent this, boolean that” :rofl:

2 Likes

Still doesn’t save BUT that’s fine mane! Hell, I’m just happy that the checkpoints aren’t bugging anymore. It isn’t a really long thousand stage obby anyways so I’m sure most players won’t mind when I start advertising. Thank y’all for your help though! Also, Merry late Christmas and wish y’all a wonderful 2024 :sunglasses: :love_you_gesture: :100:

2 Likes

Yo Mort, I ran into the same problem again after leaving and rejoining the game like 20 times but it’s still very rarely. Any idea on how to fix it completely or should i just redo the whole checkpoint script? I brought 10 friends in the game and it worked fine.

Sometimes datastoreservice doesnt save things due to some sort of error or rate issues. You will just have to retry it if it doesn’t save, or accept how it is since it is really rare.

1 Like