DataStore script resetting occasionally when people leave or ALT+F4 their games

I’ve been having a lot of issues with this DataStore script. I want it to store practically every value inside of the player, whether they’re stored under the player or in different folders.

I’ve been using this script and it seemed to work perfectly fine, but recently, me and a couple of my friends have come across an issue where, occasionally, whenever one of us leaves and rejoins the game, our stats get fully reset back to what they originally are set to in leaderstats.

I don’t really see a reason why this script wouldn’t work, but then again, I’m not very experienced with DataStore, so I really just need a quick fix for this that would solve periodic or constant data resets. Thank you!

The code for the DataStore Script is listed below:

local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetDataStore("PlayerDataStore")

local function savePlayerData(player)
	local playerId = player.UserId
	local playerKey = "Player_" .. playerId

	local playerData = {}

	for _, child in pairs(player:GetChildren()) do
		if child:IsA("ValueBase") and child.Name ~= "BiomeLuck" then
			playerData[child.Name] = child.Value
		elseif child:IsA("Folder") then
			local subData = {}
			for _, subChild in pairs(child:GetChildren()) do
				if subChild:IsA("IntValue") or subChild:IsA("NumberValue") or subChild:IsA("BoolValue") then
					subData[subChild.Name] = subChild.Value
				end
			end
			playerData[child.Name] = subData
		end
	end

	local success, error = pcall(function()
		dataStore:SetAsync(playerKey, playerData)
	end)

	if not success then
		warn("Failed to save data for player " .. playerId .. ": " .. error)
	end
end

local function loadPlayerData(player)
	local playerId = player.UserId
	local playerKey = "Player_" .. playerId

	local success, playerData = pcall(function()
		return dataStore:GetAsync(playerKey)
	end)

	if success then
		if playerData then
			for key, value in pairs(playerData) do
				local target = player:FindFirstChild(key)
				if target then
					if typeof(value) == "table" then
						for subKey, subValue in pairs(value) do
							local subTarget = target:FindFirstChild(subKey)
							if subTarget then
								subTarget.Value = subValue
							end
						end
					else
						target.Value = value
					end
				end
			end
		end
	else
		warn("Failed to load data for player " .. playerId)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	loadPlayerData(player)
end)
game.Players.PlayerRemoving:Connect(function(player)
	savePlayerData(player)
end)
game:BindToClose(function()
    for _, player in pairs(game.Players:GetPlayers()) do
        savePlayerData(player)
    end
end)

you can modify the savePlayerData function to use a repeat loop with error handling. Here’s the updated version of the script

local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetDataStore("PlayerDataStore")

local function savePlayerData(player)
    local playerId = player.UserId
    local playerKey = "Player_" .. playerId

    local playerData = {}

    for _, child in pairs(player:GetChildren()) do
        if child:IsA("ValueBase") and child.Name ~= "BiomeLuck" then
            playerData[child.Name] = child.Value
        elseif child:IsA("Folder") then
            local subData = {}
            for _, subChild in pairs(child:GetChildren()) do
                if subChild:IsA("IntValue") or subChild:IsA("NumberValue") or subChild:IsA("BoolValue") then
                    subData[subChild.Name] = subChild.Value
                end
            end
            playerData[child.Name] = subData
        end
    end

    local success = false
    repeat
        success, error = pcall(function()
            dataStore:SetAsync(playerKey, playerData)
        end)
        if not success then
            warn("Failed to save data for player " .. playerId .. ": " .. error)
            wait(1) -- Wait for 1 second before retrying
        end
    until success
end

-- Rest of the script remains the same...

thanks for the reply, but it doesn’t seem to always save the players’ data, it still resets it sometimes. is there anything else that i can do to always save it while keeping the core functionality of the datastore script?

While still keeping core functionality

local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetDataStore("PlayerDataStore")

local function savePlayerData(player)
	local playerId = player.UserId
	local playerKey = "Player_" .. playerId

	local playerData = {}

	for _, child in pairs(player:GetChildren()) do
		if child:IsA("ValueBase") and child.Name ~= "BiomeLuck" then
			playerData[child.Name] = child.Value
		elseif child:IsA("Folder") then
			local subData = {}
			for _, subChild in pairs(child:GetChildren()) do
				if subChild:IsA("IntValue") or subChild:IsA("NumberValue") or subChild:IsA("BoolValue") then
					subData[subChild.Name] = subChild.Value
				end
			end
			playerData[child.Name] = subData
		end
	end

	local success, error
	for i = 1, 3 do  -- Retry up to 3 times
		success, error = pcall(function()
			dataStore:SetAsync(playerKey, playerData)
		end)
		if success then break end
		wait(1)  -- Wait a bit before retrying
	end

	if not success then
		warn("Failed to save data for player " .. playerId .. ": " .. error)
	end
end

local function loadPlayerData(player)
	local playerId = player.UserId
	local playerKey = "Player_" .. playerId

	local success, playerData
	for i = 1, 3 do  -- Retry up to 3 times
		success, playerData = pcall(function()
			return dataStore:GetAsync(playerKey)
		end)
		if success then break end
		wait(1)  -- Wait a bit before retrying
	end

	if success then
		if playerData then
			for key, value in pairs(playerData) do
				local target = player:FindFirstChild(key)
				if target then
					if typeof(value) == "table" then
						for subKey, subValue in pairs(value) do
							local subTarget = target:FindFirstChild(subKey)
							if subTarget then
								subTarget.Value = subValue
							end
						end
					else
						target.Value = value
					end
				end
			end
		end
	else
		warn("Failed to load data for player " .. playerId)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	loadPlayerData(player)
end)
game.Players.PlayerRemoving:Connect(function(player)
	savePlayerData(player)
end)
game:BindToClose(function()
    for _, player in pairs(game.Players:GetPlayers()) do
        savePlayerData(player)
    end
end)

thanks again but this still doesn’t always save the player’s data, can it be something that i did wrong with setting up player values in the first place?

It might be data store service eating all your requests for today saying IM HUNGRY GIVE COOKIES :cookie: