How would I add BindToClose into my datastore?

I have a datastore that struggles to save, but I was told that there was an issue with BindToClose not being in the script. However, how would I do that as I want it to save consistently with no problems.

local STAT_NAME = "Stage"
local PREVENT_SKIPPING = true

local dataStore = game:GetService('DataStoreService'):GetDataStore('PlaceHolederName')

local checkpoints = {}

local i = 1
while true do

	local checkpoint = game.Workspace:FindFirstChild("Checkpoint " .. i, true)
	if not checkpoint then print("Last Checkpoint : " .. i-1) break end
	table.insert(checkpoints, checkpoint)
	i = i + 1
end


game.Players.PlayerAdded:connect(function(player)
	local leaderstats = player:FindFirstChild("leaderstats") or Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"
	
    local checkpointStat = Instance.new("IntValue", leaderstats)
	checkpointStat.Name = STAT_NAME
	checkpointStat.Value = 1
	
	local pointsKey = "player"..player.UserId
	
	local savedStuff = dataStore:GetAsync(pointsKey)

    if savedStuff then
        checkpointStat.Value = savedStuff
    else
	    wait(5)
	    if savedStuff then
			checkpointStat.Value = savedStuff
		end
    end

	player.CharacterAdded:connect(function(character)
		local goto = checkpoints[leaderstats.Stage.Value]
		if goto then
			repeat wait() until character.Parent
			character:MoveTo(goto.Position)
		else
			warn("Checkpoint " .. checkpointStat.Value .. " not found")
		end
	end)
	
	while true do
		wait(30)
		dataStore:SetAsync(pointsKey, leaderstats.Stage.Value)
	end
end)

for index, checkpoint in ipairs(checkpoints) do
	checkpoint.Touched:connect(function(hit)
		local player = game.Players:GetPlayerFromCharacter(hit.Parent)
		if not player then return end
		local humanoid = hit.Parent:FindFirstChild("Humanoid")
		if not humanoid or humanoid.Health <= 0 then return end
		local leaderstats = player:FindFirstChild("leaderstats")
		if not leaderstats then return end
		
		if (PREVENT_SKIPPING and leaderstats.Stage.Value + 1 == index) or (not PREVENT_SKIPPING and leaderstats.Stage.Value < index) then
			leaderstats.Stage.Value = index
		end
	end)
end

game.Players.PlayerRemoving:Connect(function(player)
    local pointsKey = "player"..player.UserId

    local valuesToSave = player.leaderstats.Stage.Value
    wait(5)
    if not valuesToSave then return end
    dataStore:SetAsync(pointsKey, valuesToSave)
end)
1 Like

I don’t know if it’s the best way and I’m almost sure it isn’t but I would do it, wait for more comments

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

(...)

game:BindToClose(function()
	--if not RunService:IsStudio() then
		for i,v in pairs(Players:GetPlayers()) do
			local pointsKey = "player"..v.UserId
			
			local valuesToSave = v.leaderstats.Stage.Value
			wait(5)
			if not valuesToSave then return end
			dataStore:SetAsync(pointsKey, valuesToSave)
		end
	--end
end)
1 Like

For the BindToClose function you could just iterate through all the players in the game and save their data just as if they were leaving the game.

EDIT: @seiyakido details how to do this above

I would look at this thread, it isn’t really as simple as just looping through all players and saving.
you have to put each request into its own coroutine, otherwise there is a chance that all player won’t save. (based on player count)

AS A SIDE NOTE: you can depend on Autosaving features to save within studio, BindToClose and PlayerRemoving wont work everytime in studio.

2 Likes