Roblox Datastore

Hey, recently I released a new game and one big problem we ran into was data store issues this is how we scripted it!

local module = {}

local DataStoreService = game:GetService("DataStoreService")
local PlayerDataSave = DataStoreService:GetDataStore("PlayerData_18")

local function AddStat(plr,status)
	for names,stat in pairs(status)do
		for q,w in pairs(stat) do
			if q == plr.UserId then
				print(q.." == ".. plr.UserId)
				for name,v in pairs(w) do
					for num,sta in pairs(v)do
						if sta.amt then
							if plr:WaitForChild(name):FindFirstChild(sta.Name) then
								plr:WaitForChild(name)[sta.Name].Value = sta.Value --or false
								plr:WaitForChild(name)[sta.Name].amt.Value = sta.amt --or 0
							else
								warn(sta.Name.." is not a member of ".. plr.Name.."/".. name)
							end	
						else
							if sta.Names then
								if sta.Names == "RankEquip" or sta.Names == "MiniGame" then
									local call = pcall(function()
										plr:WaitForChild(sta.Names).Value = sta.Value
									end)
								else
									local call = pcall(function()
										plr:WaitForChild(name):WaitForChild(sta.Names).Value = sta.Value
									end)
								end
							elseif sta.Questies then
								plr:WaitForChild(sta.Questies).Value = sta.Value
							else
								for o,p in pairs(sta) do
									local call = pcall(function()
	
										plr:WaitForChild(name)[o].Value = p
									end)	
								end
							end
						end	
					end	
				end	
			end
		end
	end
end

module.PlayerAdded = function(player)
	local Table = {}
	local loaded
	local data = PlayerDataSave:GetAsync(player.UserId)
	loaded = pcall(function()
	table.insert(Table,{[player.UserId] = data })
	wait(2)
	if data then
		AddStat(player,Table)
	else
		print("No Data")
	end		
	end)

	if not loaded then
		warn(player.Name.." Data not loaded")
		for i,v in pairs(Table) do
			if player:FindFirstChild(i) then
				player[i]:Destroy()
			end
		end
		player:Kick("Data Loaded Incorrectly")
	else
		warn(player.Name.." Data loaded")
	end
end

module.PlayerRemoving = function(player)
	local PlayerData = {
		leaderstats = {};
		Upgrades = {};
		Codes = {};
		Ranks = {};
		Island = {};
		GemShopFolder = {};
		Chests = {};
		PlayerUpgradeFolder = {};
		Rebirth = {};
		RankEquip = {};
		MiniGame = {};
		Quest = {};
		QuestAries = {};
	}

	local saved
	saved = pcall(function()
		for num,stat in pairs(player.leaderstats:GetChildren())do
			table.insert(PlayerData.leaderstats,{[stat.Name] = stat.Value})
		end
		for num,stat in pairs(player.Upgrades:GetChildren())do
			table.insert(PlayerData.Upgrades,{Name = stat.Name,Value = stat.Value,amt = stat.amt.Value})
		end
		for num,stat in pairs(player.Codes:GetChildren())do
			table.insert(PlayerData.Codes,{[stat.Name] = stat.Value})
		end
		for num,stat in pairs(player.Ranks:GetChildren())do
			table.insert(PlayerData.Ranks,{[stat.Name] = stat.Value})
		end
		for num,stat in pairs(player.Island:GetChildren())do
			table.insert(PlayerData.Island,{[stat.Name] = stat.Value})
		end
		for num,stat in pairs(player.GemShopFolder:GetChildren())do
			table.insert(PlayerData.GemShopFolder,{[stat.Name] = stat.Value})
		end
		for num,stat in pairs(player.Chests:GetChildren())do
			table.insert(PlayerData.Chests,{[stat.Name] = stat.Value})
		end
		for num,stat in pairs(player.PlayerUpgradeFolder:GetChildren())do
			table.insert(PlayerData.PlayerUpgradeFolder,{[stat.Name] = stat.Value})
		end
		for num,stat in pairs(player.Quest:GetChildren())do
			table.insert(PlayerData.Quest,{[stat.Name] = stat.Value})
		end
		table.insert(PlayerData.Rebirth,{Names = player.Rebirth.Upgrade.Name ,Value = player.Rebirth.Upgrade.Value})
		table.insert(PlayerData.RankEquip,{Names = player.RankEquip.Name ,Value = player.RankEquip.Value})
		table.insert(PlayerData.MiniGame,{Names = player.MiniGame.Name ,Value = player.MiniGame.Value})
		table.insert(PlayerData.QuestAries,{Questies = player.BossDead.Name, Value  = player.BossDead.Value})
		table.insert(PlayerData.QuestAries,{Questies = player.Tokens.Name, Value  = player.Tokens.Value})

		PlayerDataSave:SetAsync(player.UserId,PlayerData)
	end)
	if not saved then
		warn(player.Name.." Data Lost")
	else
		warn(player.Name.." Data Saved")
	end
end

return module

Even after doing all this work we still got complaints about data loss, does anyone know a good way to save data or fix this? Thanks :slight_smile:

There is data loss probably because there is WAY too much stuff that is being stored. There is a data store size limit.

I recommend separating these into separate data stores instead of 1 datastore for everything

	local PlayerData = {
		leaderstats = {};
		Upgrades = {};
		Codes = {};
		Ranks = {};
		Island = {};
		GemShopFolder = {};
		Chests = {};
		PlayerUpgradeFolder = {};
		Rebirth = {};
		RankEquip = {};
		MiniGame = {};
		Quest = {};
		QuestAries = {};
	}

Yea but whats a good way to fix this? :smiley:

You could make different datastores for the joining player. I’m not good with data stores though. I mainly use data store 2

local LeaderstatData = DataStoreService:GetDataStore("Leaderstat")
local UpgradesData = DataStoreService:GetDataStore("Upgrades")
local CodesData = DataStoreService:GetDataStore("Codes")
local RankData = DataStoreService:GetDataStore("Ranks")

The data loss can be also a cause of using SetAsync() instead of UpdateAsync(). Didn’t even know that too after reading this post. Maybe that’s the cause of you problem.

Yea we tried this but it didn’t help

maybe try to rewrite it using these functions I made?

function SafeSave(Datastore, Key, Value)
	local Attempts = 0
	local Success = false
	local Error = nil
	repeat
		Attempts += 1
		Success, Error = pcall(function()
			Datastore:SetAsync(Key, Value)
		end)
		if not Success then wait(10) end
	until
	Success or Attempts >= 3
	if Error ~= nil or not Success then print("<Error while saving data>\n    - "..(Error or "No Error")) return nil end
	return Success
end


function SafeGet(Datastore, Key)
	local Attempts = 0
	local Data = nil
	local Success = false
	local Error = nil
	repeat
		Attempts += 1
		Success, Error = pcall(function()
			Data = Datastore:GetAsync(Key)
		end)
		if not Success then wait(10) end
	until
	Success or Attempts >= 3
	if Error ~= nil or not Success then print("<Error while retrieving data>\n    - "..(Error or "No Error")) return nil end
	return Data
end


function SafeUpdate(Datastore, Key, Logic)
	local Attempts = 0
	local Data = nil
	local Success = false
	local Error = nil
	repeat
		Attempts += 1
		Success, Error = pcall(function()
			Data = Datastore:UpdateAsnyc(Key, Logic)
		end)
		if not Success then wait(10) end
	until
	Success or Attempts >= 3
	if Error ~= nil or not Success then print("<Error while updating data>\n    - "..(Error or "No Error")) return nil end
	return Data
end

Yeah Ill give it a go, Thanks!