Data store saving problem

sup sup

for some reason in my game, data store is so broken for some reasons idk why… it only saves some things but then doesnt save other things. also my game is a cross game type where u can get tp to other places within the game.

pls can someone tell me how to get a full 100% saving data system?? my current data system is broken. pls send and ty

here is the script i made (pls help me fix it i literally know nothing about data store ALSO i would prefer profile service but i have no idea how to use it so please can u guys help me pleease my game is literally close to being done)

local Players = game:GetService("Players")
local Debris = game:GetService("Debris")

local playerDataStore = DataStoreService:GetDataStore("PlayerData")

local function deepCopy(tbl)
	local copy = {}
	for k, v in pairs(tbl) do
		if typeof(v) == "table" then
			copy[k] = deepCopy(v)
		else
			copy[k] = v
		end
	end
	return copy
end

-- Function to get default data
local function getDefaultData()
	return {
		Level = 1,
		Exp = 0,
		RequiredExp = 300,
		Wins = 0,
		Money = 0,
		MaxHealth = 100,
		Damage = 0,
		WalkSpeed = 16,
		Tokens = 0,
		HealthCost = 1,
		DamageCost = 1,
		SpeedCost = 1,
		ExpMultiplier = 1,
		CelestialPotion = false,
		PowerPotion = false,
		ShiningStaff = false,
		Detector = false,
		ConjureStaff = false,
		FusionCoil = false,
		BeginnerTitle = true,
		ExperiencedTitle = false,
		ColdTitle = false,
		CrateOpenerTitle = false,
		ConquerorTitle = false
	}
end

-- Save data safely
local function saveData(player)
	if not player then return end

	local key = "Player_" .. player.UserId
	local data = {
		Level = player:FindFirstChild("Lvl") and player.Lvl.Value or 1,
		Exp = player:FindFirstChild("Exp") and player.Exp.Value or 0,
		RequiredExp = player:FindFirstChild("RequiredExpPlr") and player.RequiredExpPlr.Value or 300,
		Wins = player:FindFirstChild("leaderstats") and player.leaderstats:FindFirstChild("Victories") and player.leaderstats.Victories.Value or 0,
		Money = player:FindFirstChild("Money") and player.Money.Value or 0,
		MaxHealth = player:FindFirstChild("MaxHealth") and player.MaxHealth.Value or 100,
		Damage = player:FindFirstChild("Damage") and player.Damage.Value or 0,
		WalkSpeed = player:FindFirstChild("WalkSpeed") and player.WalkSpeed.Value or 16,
		Tokens = player:FindFirstChild("Tokens") and player.Tokens.Value or 0,
		HealthCost = player:FindFirstChild("HealthCost") and player.HealthCost.Value or 1,
		DamageCost = player:FindFirstChild("DamageCost") and player.DamageCost.Value or 1,
		SpeedCost = player:FindFirstChild("SpeedCost") and player.SpeedCost.Value or 1,
		ExpMultiplier = player:FindFirstChild("ExpMultiplier") and player.ExpMultiplier.Value or 1,
		CelestialPotion = player:FindFirstChild("CelestialPotion") and player.CelestialPotion.Value or false,
		PowerPotion = player:FindFirstChild("PowerPotion") and player.PowerPotion.Value or false,
		ShiningStaff = player:FindFirstChild("ShiningStaff") and player.ShiningStaff.Value or false,
		Detector = player:FindFirstChild("Detector") and player.Detector.Value or false,
		ConjureStaff = player:FindFirstChild("ConjureStaff") and player.ConjureStaff.Value or false,
		FusionCoil = player:FindFirstChild("FusionCoil") and player.FusionCoil.Value or false,
		BeginnerTitle = player:FindFirstChild("BeginnerTitle") and player.BeginnerTitle.Value or true,
		ExperiencedTitle = player:FindFirstChild("ExperiencedTitle") and player.ExperiencedTitle.Value or false,
		ColdTitle = player:FindFirstChild("ColdTitle") and player.ColdTitle.Value or false,
		CrateOpenerTitle = player:FindFirstChild("CrateOpenerTitle") and player.CrateOpenerTitle.Value or false,
		ConquerorTitle = player:FindFirstChild("ConquerorTitle") and player.ConquerorTitle.Value or false
	}

	local success = false
	local errorMessage

	for attempt = 1, 5 do
		success, errorMessage = pcall(function()
			playerDataStore:UpdateAsync(key, function(oldData)
				return deepCopy(data)
			end)
		end)
		if success then
			break
		else
			warn("Attempt " .. attempt .. " to save data for " .. player.Name .. " failed: " .. tostring(errorMessage))
			task.wait(1)
		end
	end

	if not success then
		warn("[CRITICAL] Failed to save data for " .. player.Name .. " after multiple attempts.")
	end
end

-- Load data safely
local function loadData(player)
	local key = "Player_" .. player.UserId
	local data
	local success, errorMessage

	for attempt = 1, 5 do
		success, errorMessage = pcall(function()
			data = playerDataStore:GetAsync(key)
		end)
		if success then
			break
		else
			warn("Attempt " .. attempt .. " to load data for " .. player.Name .. " failed: " .. tostring(errorMessage))
			task.wait(1)
		end
	end

	if not success or not data then
		data = getDefaultData()
	end

	return data
end

-- Player joins
Players.PlayerAdded:Connect(function(player)
	-- Leaderstats setup
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local data = loadData(player)

	local Level = Instance.new("NumberValue")
	Level.Name = "Lvl"
	Level.Parent = player
	Level.Value = data.Level or 1

	local ExpMultiplier = Instance.new("NumberValue")
	ExpMultiplier.Name = "ExpMultiplier"
	ExpMultiplier.Parent = player
	ExpMultiplier.Value = 1

	local Exp = Instance.new("NumberValue")
	Exp.Name = "Exp"
	Exp.Parent = player
	Exp.Value = data.Exp or 0

	local Wins = Instance.new("NumberValue")
	Wins.Name = "Victories"
	Wins.Parent = leaderstats
	Wins.Value = data.Wins or 0

	local RequiredExp = Instance.new("NumberValue")
	RequiredExp.Name = "RequiredExpPlr"
	RequiredExp.Parent = player
	RequiredExp.Value = data.RequiredExp or (Level.Value * 300)

	local Money = Instance.new("NumberValue")
	Money.Name = "Money"
	Money.Parent = player
	Money.Value = data.Money or 0

	local Tokens = Instance.new("NumberValue")
	Tokens.Name = "Tokens"
	Tokens.Parent = player
	Tokens.Value = data.Tokens or 0

	local MaxHealth = Instance.new("NumberValue")
	MaxHealth.Name = "MaxHealth"
	MaxHealth.Parent = player
	MaxHealth.Value = data.MaxHealth or 100

	local Damage = Instance.new("NumberValue")
	Damage.Name = "Damage"
	Damage.Parent = player
	Damage.Value = data.Damage or 0

	local WalkSpeed = Instance.new("NumberValue")
	WalkSpeed.Name = "WalkSpeed"
	WalkSpeed.Parent = player
	WalkSpeed.Value = data.WalkSpeed or 16

	local HealthCost = Instance.new("NumberValue")
	HealthCost.Name = "HealthCost"
	HealthCost.Parent = player
	HealthCost.Value = data.HealthCost or 1

	local DamageCost = Instance.new("NumberValue")
	DamageCost.Name = "DamageCost"
	DamageCost.Parent = player
	DamageCost.Value = data.DamageCost or 1

	local SpeedCost = Instance.new("NumberValue")
	SpeedCost.Name = "SpeedCost"
	SpeedCost.Parent = player
	SpeedCost.Value = data.SpeedCost or 1
	
	local CelestialPotion = Instance.new("BoolValue")
	CelestialPotion.Name = "CelestialPotion"
	CelestialPotion.Parent = player
	CelestialPotion.Value = data.CelestialPotion or false

	local PowerPotion = Instance.new("BoolValue")
	PowerPotion.Name = "PowerPotion"
	PowerPotion.Parent = player
	PowerPotion.Value = data.PowerPotion or false

	local ShiningStaff = Instance.new("BoolValue")
	ShiningStaff.Name = "ShiningStaff"
	ShiningStaff.Parent = player
	ShiningStaff.Value = data.ShiningStaff or false

	local Detector = Instance.new("BoolValue")
	Detector.Name = "Detector"
	Detector.Parent = player
	Detector.Value = data.Detector or false

	local ConjureStaff = Instance.new("BoolValue")
	ConjureStaff.Name = "ConjureStaff"
	ConjureStaff.Parent = player
	ConjureStaff.Value = data.ConjureStaff or false

	local FusionCoil = Instance.new("BoolValue")
	FusionCoil.Name = "FusionCoil"
	FusionCoil.Parent = player
	FusionCoil.Value = data.FusionCoil or false
	
	local BeginnerTitle = Instance.new("BoolValue")
	BeginnerTitle.Name = "BeginnerTitle"
	BeginnerTitle.Parent = player
	BeginnerTitle.Value = data.BeginnerTitle or true

	local ExperiencedTitle = Instance.new("BoolValue")
	ExperiencedTitle.Name = "ExperiencedTitle"
	ExperiencedTitle.Parent = player
	ExperiencedTitle.Value = data.ExperiencedTitle or false

	local ColdTitle = Instance.new("BoolValue")
	ColdTitle.Name = "ColdTitle"
	ColdTitle.Parent = player
	ColdTitle.Value = data.ColdTitle or false

	local CrateOpenerTitle = Instance.new("BoolValue")
	CrateOpenerTitle.Name = "CrateOpenerTitle"
	CrateOpenerTitle.Parent = player
	CrateOpenerTitle.Value = data.CrateOpenerTitle or false

	local ConquerorTitle = Instance.new("BoolValue")
	ConquerorTitle.Name = "ConquerorTitle"
	ConquerorTitle.Parent = player
	ConquerorTitle.Value = data.ConquerorTitle or false

	-- Level up system
	Exp.Changed:Connect(function()
		while Exp.Value >= RequiredExp.Value do
			Exp.Value -= RequiredExp.Value
			Level.Value += 1
			Tokens.Value += 1

			if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
				local sound = game.Workspace.Sounds.LevelUpSound:Clone()
				sound.Parent = player.Character.HumanoidRootPart
				sound:Play()
				Debris:AddItem(sound, 4)
			end

			RequiredExp.Value = Level.Value * 300
		end
	end)
end)

-- Save on leave
Players.PlayerRemoving:Connect(function(player)
	saveData(player)
end)

-- Save on shutdown
game:BindToClose(function()
	for _, player in ipairs(Players:GetPlayers()) do
		task.spawn(function()
			saveData(player)
		end)
	end
	-- Give enough time for saves
	task.wait(5)
end)

Hey bro. I am all down for writing your own datastore stuff but if you just want an easy solution to creating a datastore, managing client data and stuff safely and again pretty easy just use ProfileStore.

Example of saving data can be found here: Tutorial - ProfileStore


Now with your issue could you provide any logs if there is any in the console? If you don’t know how to open it just go to view and there should be a console icon you can click on otherwise just click F9 on your keyboard. You can see both client and server logs from there (if there is any) send any relevant logs please.

Secondly. I don’t recommend doing this, I feel this will cause a problem later on. What will happen if the instance is deleted or replaced somehow also why not just run this in a local script?



Exp.Changed:Connect(function()
		while Exp.Value >= RequiredExp.Value do
			Exp.Value -= RequiredExp.Value
			Level.Value += 1
			Tokens.Value += 1

			if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
				local sound = game.Workspace.Sounds.LevelUpSound:Clone()
				sound.Parent = player.Character.HumanoidRootPart
				sound:Play()
				Debris:AddItem(sound, 4)
			end

			RequiredExp.Value = Level.Value * 300
		end
	end)

One last question why aren’t you using the actual saving function instead? I personally have not really touched updated but surely you should be using the save function instead for saving no?



	local success = false
	local errorMessage

	for attempt = 1, 5 do
		success, errorMessage = pcall(function()
			playerDataStore:UpdateAsync(key, function(oldData)
				return deepCopy(data)
			end)
		end)
		if success then
			break
		else
			warn("Attempt " .. attempt .. " to save data for " .. player.Name .. " failed: " .. tostring(errorMessage))
			task.wait(1)
		end
	end

	if not success then
		warn("[CRITICAL] Failed to save data for " .. player.Name .. " after multiple attempts.")
	end

thxs for advice!! also i do know how to use console and stuff ive been on roblox studio for like a few year its just that i didnt rlly bother learning data store i was more focused in other things i wanted to do

also i wana use profile server bc it is more accurate at saving and data store will soon start to cost money

but ty for the feedback and advice!!

They’re fully free storage. I am not sure why you think they’d charge.

That’d be for Roblox Extended Services, most developers should never come close to reaching the regular storage limit.

1 Like

Ah right I understand the confusion. Makes sense.