Saving Obby Checkpoints (DataStore)

I have been researching DataStores for a bit and I have to say the process is confusing to say the least. All the videos and forum posts I have watched/read through have helped steer me in the right direction but I am still unsure how to set it up without ruining my script that I already have put together. For reference this is my script that I have below:

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local TweenTime = TweenInfo.new(1)
local Checkpoints = workspace:WaitForChild("Checkpoints"):GetChildren()
local SoundService = game:GetService("SoundService")
local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("ObbyDataStore")

local SoundTemplate = Instance.new("Sound")
SoundTemplate.SoundId = "rbxassetid://6979299092"
SoundTemplate.Volume = .2
SoundTemplate.Pitch = 1
SoundTemplate.RollOffMaxDistance = 20
SoundTemplate.RollOffMinDistance = 10

local function FindCheckpoint(character, stage)
    for i, checkpoint in pairs(Checkpoints) do
        local checkpoint_number = tonumber(checkpoint.Name)
        if stage.value == checkpoint_number then
            return checkpoint
        end
    end
end

Players.PlayerAdded:Connect(function(player)
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = player
    
    local stage = Instance.new("IntValue")
    stage.Name = "Stage"
    stage.Value = 0
    stage.Parent = leaderstats
    
    player.CharacterAdded:Connect(function(character)
        local root_part = character:WaitForChild("HumanoidRootPart")
        local checkpoint = FindCheckpoint(character, stage)
        
        RunService.Heartbeat:Wait()
        root_part.CFrame = checkpoint.CFrame * CFrame.new(0,1,0)
    end)
end)

for i, checkpoint in pairs(Checkpoints) do
    local sound = SoundTemplate:Clone() -- Clone a sound object for each checkpoint
    sound.Parent = checkpoint -- Attach the sound to the checkpoint
    
    checkpoint.Touched:Connect(function(touch)
        local humanoid = touch.Parent:FindFirstChild("Humanoid")
        if humanoid and humanoid.Health > 0 then
            local player = Players:GetPlayerFromCharacter(touch.Parent)
            if player then
                local leaderstats = player:WaitForChild("leaderstats")
                local stage = leaderstats.Stage
                
                local checkpoint_number = tonumber(checkpoint.Name)
                if checkpoint_number - stage.Value == 1 then
                    stage.Value = checkpoint_number
                    
                    -- Play the sound effect when the checkpoint is touched
                    sound:Play()
                    
                    local goal = {
                        Size = checkpoint.Size + Vector3.new(2, 0.5, 2),
                        Transparency = 1
                    }
                    
                    local checkpointclone = checkpoint:Clone()
                    checkpointclone.Parent = workspace
                    
                    local tween = TweenService:Create(checkpointclone, TweenTime, goal)
                    tween:Play()
                    
                    tween.Completed:Connect(function()
                        checkpointclone:Destroy()
					end)
					
					local soundClone = sound:Clone()
					soundClone.Parent = checkpointclone
					
					local soundConnection = soundClone.Playing:Connect(function()
						if soundClone.Playing then
							soundClone:Stop()
							soundClone:Disconnect()
						end
					end)
					
					soundClone:Play()
                end
            end
        end
    end)
end

This script holds the checkpoints as well as the checkpoint sounds/effects. But, I want to have it where, if you leave the game and you’re at a certain checkpoint, it’ll save the data so when you come back, you’ll be back to where you left off at. Any help is much appreciated!

1 Like

To save the data, you’d have to create a new PlayerRemoving event, and use

local success, errorMessage = pcall(function()
	DataStore:SetAsync("", 0) -- first argument should be the players userid, 
-- second argument is the value that youre saving
end)
-- in a pcall in case the save fails

You’d load that data in basically the same way. Insert this near where you create the value of the checkpoints

local success, checkpoints = pcall(function()
	DataStore:GetAsync("") -- whatever you used to save it
end)

stage.Value = checkpoints
4 Likes

So I would do:

Players.PlayersRemoving:Connect(function(player)
   local sucess, errorMessage = pcall(function()
   DataStore:SetAsync(player.UserId, checkpoints[player.UserId])
end)

And then insert this somewhere else:

local success, checkpoints = pcall(function()
    DataStore:GetAsync("checkpoints")
end)

stage.Value = checkpoints

Would it be something like this? I’m still a beginner scripter so I am unsure about how to set up things.

1 Like

Can be simplified to:

local success, checkpoints = pcall(DataStore.SetAsync, DataStore, "", 0)
local success, checkpoints = pcall(DataStore.GetAsync, DataStore, "")

plus, the “second argument” part isnt really true.

3 Likes

Assign player checkpoint to a stringvalue (Name it the checkpoint name) then use this.

player.CharacterAdded:Connect(function(character)
    local CheckPoint = Player.CheckPoint.Value
    local SpawnPoint = workspace:FindFirstChild(CheckPoint, true)
    character:MoveTo(SpawnPoint.Position + Vector3.new(0,2,0))
end)
3 Likes

Small Thing:

Vector3.yAxis*2

2 Likes

There was a youtube video that had a script like that which I had tried but it unfortunately didn’t work :confused:

What didn’t work?

The script that was provided.
Here’s the video I am referring to: https://www.youtube.com/watch?v=idcsSqPbTPs&t=73s&ab_channel=Septureal
Although, looking over the video, the script is slightly different so I’ll attempt to try that as well! What does it mean to assign player checkpoint to a stringvalue?

1 Like

I assume you’re using team changes? When you change the player team, change the stringvalue on the player too.

1 Like

Would I still enter in the same information that I provided but in the shorter terms you provided?

Players.PlayersRemoving:Connect(function(player)
   local sucess, errorMessage = pcall(function()
   DataStore:SetAsync(player.UserId, checkpoints[player.UserId])
end)
local success, checkpoints = pcall(function()
    DataStore:GetAsync("checkpoints")
end)

stage.Value = checkpoints
1 Like

I’m using Checkpoints that I have made in the workspace that are acting as the stage placeholders seen here:
Capture

The script itself is in ServerScriptService that references the checkpoints in the workspace. I think I know what you’re referring to in terms of team changes but I don’t believe that is something I am using. It’s just a custom leaderboard that I reference in the script itself.

A little update: Yesterday I found a tutorial that was simple enough to follow that ended up helping immensely!
Here is the link to the video if anyone else is struggling with DataStores as well:
https://www.youtube.com/watch?v=_UsLW-Sm7Ww&t=55s

I thank everyone for their comments and helpful directions as well! It really does help me understand the topic more :smiley:

2 Likes