Obby Saving button

Hi, I am making an obby and I need to make a button that will save your progress on what stage you are in. I’m not trying to make an auto save because I want people to replay the game from the beginning if they are interested to. Should I make a gui and then enter the correct script into it? Or is there something else I should do?

This is the auto saving code that I have, but would like to change it a little (if possible) so it could complete my wantings.

local DataStoreService = game:GetService("DataStoreService")
local StageDataStore = DataStoreService:GetDataStore("StageData")

local function TouchedPart(part, touchedPart)
	local ply = game.Players:GetPlayerFromCharacter(touchedPart.Parent)
	if ply then
		if ply.leaderstats.Stage.Value < tonumber(part.Name) then
			ply.leaderstats.Stage.Value = tonumber(part.Name)
		end
	end
end

local function AddTouchStageGiver()
	local stageNum = 1
	while true do
		local part = game.Workspace:FindFirstChild(tostring(stageNum))
		if part then
			part.Touched:connect(function (touchedPart)
				TouchedPart(part, touchedPart)
			end)
		else
			break
		end
		stageNum = stageNum + 1
		wait()
	end
end

local function GetSavedStage(ply)
	return StageDataStore:GetAsync(tostring(ply.UserId)) or 1
end

local function SaveCurrentStage(ply)
	StageDataStore:SetAsync(tostring(ply.UserId), ply.leaderstats.Stage.Value)
end

local SPAWN_OFFSET = Vector3.new(0, 5, 0)

local function GetStageSpawnCFrames(stage)
	local stageSpawnPart = game.Workspace:FindFirstChild(tostring(stage))
	
	if not stageSpawnPart then
		return game.Workspace:FindFirstChild("1").CFrame + SPAWN_OFFSET
	end
	
	return stageSpawnPart.CFrame + SPAWN_OFFSET
end

local stageValues = {}

local function CharacterAdded(ply, char)
	repeat wait() until stageValues[ply]
	char:SetPrimaryPartCFrame(GetStageSpawnCFrames(stageValues[ply].Value))
end

game.Players.PlayerAdded:connect(function (ply)
	local leaderstats = Instance.new("ObjectValue", ply)
	leaderstats.Name = "leaderstats"
	
	ply.CharacterAdded:connect(function (char)
		CharacterAdded(ply, char)
	end)
	
	local stage = Instance.new("IntValue", leaderstats)
	stage.Name = "Stage"
	stage.Value = GetSavedStage(ply)
	
	stageValues[ply] = stage	
	
	--[[
	if ply.Character then
		CharacterAdded(ply, ply.Character)
	end
	--]]
end)

game.Players.PlayerRemoving:connect(function (ply)
	SaveCurrentStage(ply)
end)

wait(1)
AddTouchStageGiver()

I appreciate your help, thank you!

You could make it so that there is a GUI button, and when the player clicks the button, a RemoteEvent is fired to alert the server. Once the server detects the event firing, it can update the datastore (i.e. save where they are).

1 Like

Anyways, to help you I will go over the process of doing this BRIEFLY, there are many better ways of doing this but this is probably the simplest to understand.

local Button = --YourButtonVariable 

--Saving on click I HIGHLY RECOMMEND THAT YOU ADD A DEBOUNCE 
Button.MouseButton1Click:Connect(function()
   DataStoreVariable:SetAsync(plr.UserId, {plr.Stage.Value, plr.Points.Value, plr.Cash.Value}) 
--I added the extra values to show you that you can add more, feel free to replace them. We're saving multiple values inside an array. 
--I highly recommend that you check if the values are different or not by checking them with GetAsync and adding a debounce so you prevent a high amount of requests!
end)

To load the saved stats:

--Loading saved stats
game.Players.PlayerAdded:Connect(function(plr)
     --Create the Stage,Money,Points etcetc Values Instances inside the player here
     local Data = DataStoreVariable:GetAsync(plr.UserId) 
     if Data then --if Data is found i.e player is not new.
          plr.Money.Value = Data[1]
          plr.Points.Value = Data[2] 
          ---continue 
     end
end)

I also recommend that you make use of pcalls whenever saving i.e whenever using SetAsync or UpdateAsync.

Do not forget to add a debounce/cooldown when clicking the button and make sure to check whether the stats have changed since last save by checking the data with GetAsync so you do not throttle the datastore as this can cause a mess

4 Likes

Thank you! I will definitely try this out as soon as possible

That’s a good idea. I’ll try this out as well as the other solution. Thank you!