Bug fixing a sandbox tycoon save system

So i recently made a sandbox tycoon. I made a saving system too. However the saving system only seems to work 50% of the time. Half the time the players plot just wont load. I put it under code review since it only works half the time… Also PLEASE dont just tell me to use datastore2 unless it is literally the ONLY solution.

The code might be inneficent garbage i know…

local AutoSaveWait = 30
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Save = ReplicatedStorage:WaitForChild("Save")
local PlayersLoaded = {}
game.Players.PlayerAdded:Connect(function(Player)
		
		local DataStoreService = game:GetService("DataStoreService")
		local PlayerData = DataStoreService:GetDataStore("GameTestingStore0.0.0.0.16")
	
	local leaderstats = Instance.new("Folder")
	leaderstats.Parent = Player
	leaderstats.Name = "leaderstats"
	
	local Cash = Instance.new("IntValue")
	Cash.Parent = leaderstats
	Cash.Name = "Cash"
	Cash.Value = 1000
	
	local Items = Instance.new("Folder")
	Items.Parent = Player
	Items.Name = "PlayerItems"
	
	local Loaded = Instance.new("BoolValue")
	Loaded.Parent = Player
	Loaded.Value = false
	Loaded.Name = "DataLoaded"
	
		local Data = PlayerData:GetAsync(Player.UserId)
		
		if Data ~= nil then
			print("Player has data")
		
		Cash.Value = Data["Cash"]
		local Items = Data["Items"]
		local BlockPositions = Data["BlockPositions"]
	--[[
		local Plot
		
		for i, v in pairs(game.Workspace.Plots:GetChildren()) do
			if v.Part.Owner.Value == Player.Name then
				Plot = v
			end
		end
		
		for i, v in pairs(BlockPositions) do
			local Obj = game.ReplicatedStorage.Objects:FindFirstChild(v.Name)
			local Clone = Obj:Clone()
			Clone:SetPrimaryPartCFrame(Plot.Part.CFrame * CFrame.new(v.CFS.X, v.CFS.Y, v.CFS.Z) * CFrame.Angles(0, math.rad(v.CFS.R), 0))
			Clone.PrimaryPart.Transparency = 1
			Clone.PrimaryPart.CanCollide = false
			Clone.Parent = Plot.SaveFolder
		end
]]		
		for i, v in pairs(Items) do
			local ItemValue = Instance.new("IntValue")
			ItemValue.Name = v.Name
			ItemValue.Parent = Player.PlayerItems
			ItemValue.Value = v.Value
		end
		
		else
			print("New player set up data")
			local NewData = {
				
			["Cash"] = Cash.Value,
			Items = {},
			
			}
			
			PlayerData:SetAsync(Player.UserId, NewData)
		end
		
		local function autoSave(Player, Data)
			local success, err = pcall(function()
				
				PlayerData:SetAsync(Player.UserId, Data)
				
			end)
			
			
			
			if success then
				return "Data was saved"
			else
				return "Error -- Data was not saved"
			end
		end
		
	while wait(AutoSaveWait) do
		local SaveTable = {}
		local Plot
		
		local ItemsTemp = {}
	
		for i, v in pairs(Player.PlayerItems:GetChildren()) do
			table.insert(ItemsTemp, 1, {
				["Name"] = v.Name,
				["Value"] = v.Value,
				
				
				
			}
			)
		end
		
		for i, v in pairs(game.Workspace.Plots:GetChildren()) do
			if v.Part.Owner.Value == Player.Name then
				Plot = v
			end
		end
		
		
		for i, v in pairs(Plot.SaveFolder:GetChildren()) do
			table.insert(SaveTable,{
				["Name"] = v.Name,
				
				["CFS"] = {
					--[[["X"] = v.PrimaryPart.CFrame.X;
					["Y"] = v.PrimaryPart.CFrame.Y;
					["Z"] = v.PrimaryPart.CFrame.Z;]]
					
					["X"] = Plot.Part.CFrame:ToObjectSpace(CFrame.new(v.PrimaryPart.CFrame.p)).X;
					["Y"] = Plot.Part.CFrame:ToObjectSpace(CFrame.new(v.PrimaryPart.CFrame.p)).Y;	
					["Z"] = Plot.Part.CFrame:ToObjectSpace(CFrame.new(v.PrimaryPart.CFrame.p)).Z;
					["R"] = v.PrimaryPart.Orientation.Y;
				}
				
				
				
			}	
		)
		end
		
		
		local NewData = {
			Items = ItemsTemp,
				["Cash"] = Cash.Value,
				BlockPositions = SaveTable,
			
		}
		
			
		
				local msg = autoSave(Player, NewData)
		
		Save.OnServerEvent:Connect(function(MsgPlayer)
			autoSave(MsgPlayer, NewData)
			
		
		end)
		
		
				print(msg)
			end
	
end)

game.Players.PlayerRemoving:Connect(function(Player)
	
	for i, v in pairs(game.Workspace.Plots:GetChildren()) do
		if v.Part.Owner.Value == Player.Name then
			for i, Model in pairs(v.SaveFolder:GetChildren()) do
				Model:Destroy()
			end
		end
	end
end)


while wait(1) do
	function Load()
	local success, response = pcall(function()
	for i, Player in pairs(game.Players:GetChildren()) do
		if Player.DataLoaded.Value ~= true then
		local DataStoreService = game:GetService("DataStoreService")
		local PlayerData = DataStoreService:GetDataStore("GameTestingStore0.0.0.0.16")
		
		
	local Data = PlayerData:GetAsync(Player.UserId)
	
	if Data ~= nil then
		print("Player has data")
		

		local BlockPositions = Data["BlockPositions"]
		
		local Plot
		
		for i, v in pairs(game.Workspace.Plots:GetChildren()) do
			if v.Part.Owner.Value == Player.Name then
				Plot = v
			end
		end
		if BlockPositions ~= nil then
		for i, v in pairs(BlockPositions) do
			local Obj = game.ReplicatedStorage.Objects:FindFirstChild(v.Name)
			local Clone = Obj:Clone()
			Clone:SetPrimaryPartCFrame(Plot.Part.CFrame * CFrame.new(v.CFS.X, v.CFS.Y, v.CFS.Z) * CFrame.Angles(0, math.rad(v.CFS.R), 0))
			Clone.PrimaryPart.Transparency = 1
			Clone.PrimaryPart.CanCollide = false
			Clone.Parent = Plot.SaveFolder
				end
				end
				Player.DataLoaded.Value = true
		end
		end
			end
	
		end)
		end
	Load()
	
end
1 Like

Is the time it fails always come with the “Error – Data was not saved” and how does this return msg get processed?

tbh i dont do anything with it. Do you think some sort of loop checking it if it worked. But if it doesnt try again???

Use
while true do
success, response =pcall(function()
– Save data
Wait(3)
end)

If success then
break
end
end

– ive made a part saved that gets parts propertys so its 100% possible. Yours will be even easier as its just getting model names and their position and rotation

Quick question. Should i replace my while loop with this or should i replace my player added function?

Since I didn’t see you use :BindToClose() event, I suggest you implement that in your code. It’ll work when the server itself shutdowns, but will immediately ensure that the data is saved for everyone beforehand. PlayerRemoving may be inconsistent and the server could shutdown before actually saving data.

The player removing code removes all the objects on the players plot.

1 Like

When you save or load data.
This will reduce the chance of the datastore not setting data or not retrieving the store.

If your store fails to save data the data or gets corrupt it will be nil
If it fails to get the stored info it will return nil. If there’s no data saved it will be nil.

1 Like

Yeah i ended up following your advice and also found a bug where the data would only save for the last player that joined

1 Like