Data Loss Over Time With DataStore

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve?
    I want my data to stop getting deleted randomly.
  2. What is the issue?
    Sometimes when players enter and leave the game, data loss occurs.
  3. What solutions have you tried so far?
    I tried a few different YouTube tutorials for DataStore, read a bit about ProfileService and Datastore 2, followed some tutorials on them but it was too much hassle to implement, and my game does not involve trading or even any purchases for that matter. Updated my DataStore to use UpdateAsync hoping that would work, I still lose data over time and I’m at my wits end, not sure what I’m doing wrong. I am trying to save a pretty long table (I shortened it for devforum, it’s over 200 values), that may be the cause but I don’t know of other solutions. Thanks.
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local RunService = game:GetService("RunService")
local DataStore = DataStoreService:GetDataStore("BadgesList")
local EmojiPrompt = game:GetService("ReplicatedStorage"):WaitForChild("EmojiPrompt")

local data = {
	["A001Backpack"] = 0,
	["A002FramedPicture"] = 0,
	["A003MansShoe"] = 0,
	["A004SlightlySmilingFace"] = 0,
	["A005PensiveFace"] = 0,
	["A006SmilingFace"] = 0,
	["A007FaceWithMask"] = 0,
	["A008NauseousFace"] = 0,
	["A009Carrot"] = 0,
	["A010Eye"] = 0,
}

local function setupPlayerData(player : Player)
	local key = "Player-" ..player.UserId
	
	local leaderstats = Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"
	
	local strength = Instance.new("IntValue", leaderstats)
	strength.Name = "Found"
	
	local badges = Instance.new("Folder", player)
	badges.Name = "Badges"
	
	for name, value in pairs(data) do
		local new = Instance.new("IntValue")
		new.Name = name
		new.Parent = badges
	end
	
	local success, returnValue
	
	success, returnValue = pcall(DataStore.GetAsync, DataStore, key)
	
	if success then
		if returnValue ~= nil then
			print("Loaded Player's Data!")
			print(returnValue)
			player.leaderstats.Found.Value = if returnValue.Strength then returnValue.Strength else 0
			for name, value in pairs(returnValue.DataStructure) do
				local BadgeValue = player.Badges[name].Value
				BadgeValue = value
				if BadgeValue == 1 then
					player:WaitForChild("Backpack").EmojiIcon.Value = game.Workspace.Emojis:FindFirstChild(name).Emoji.SurfaceGui.TextLabel.Text
					player:WaitForChild("Backpack").EmojiName.Value = name
					EmojiPrompt:FireClient(player)
				end
				task.wait()
			end
		end
	else
		print("Couldn't load"..player.Name.."'s Data!")
		player:Kick("Couldn't load your data, sorry. Roblox's datastore might be down! Please contact a developer if your problem persists.")
	end
end

local function saveData(player : Player)
	local key = "Player-" ..player.UserId
	
	local leaderstats = player:FindFirstChild("leaderstats")
	local badges = player:FindFirstChild("Badges")
	
	if not leaderstats or not badges then return end
	
	local strength = leaderstats:FindFirstChild("Found")
	local data = badges:GetChildren()
	
	if not strength or not data then warn ("No Stat Found!") return end
	
	local dataTable = {
		Strength = strength.Value,
		DataStructure = {}
	}
	for name, value in pairs(data) do
		dataTable.DataStructure[value.Name] = value.Value
	end
	
	local success, returnValue

	success, returnValue = pcall(DataStore.UpdateAsync, DataStore, key, function()
		return dataTable
	end)

	if success then
		print("Saved Player Data!")
		print(returnValue)
	else
		warn("Couldn't load"..player.Name.."'s Data! DATA LOSS")
	end
end

local function onShutDown()
	if RunService:IsStudio() then
		task.wait(2)
	else
		local finished = Instance.new("BindableEvent", script.Parent)
		finished.Name = "Finished"
		local allPlayers = Players:GetPlayers()
		local leftPlayers = #allPlayers
		
		for _, player in ipairs(allPlayers) do
			coroutine.wrap(function()
				saveData(player)
			end)
			leftPlayers -= 1
			
			if leftPlayers <= 0 then
				finished:Fire()
			end
		end
		
		finished.Event:Wait()
	end
end

Players.PlayerAdded:Connect(setupPlayerData)
Players.PlayerRemoving:Connect(saveData)

game:BindToClose(onShutDown)

Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.

2 Likes

This problem may occur due to DataStore failing to save the values. This is why we use pcall to handle errors that may not even be your fault at times. I recommend trying to implement a “retry” system, where if the DataStore update fails, it retries a couple more times before giving out.

For the retry, would I be using a while loop, or is there some built in function for retries for datastores?

While loop, yeah, unfortunately there is no built-in function for DataStore retries.