DataStore problem on tycoon game! New players dont load correctly

Hi everyone! I am running into a DataStore problem! I am creating a tycoon game (my first game!), Which has the big problem, that when a new player enters the game, the tycoon loads incorrectly, and has several errors such as, for example, the dropper does not work correctly, and the buttons they get bug! Attached video of the things that happen when starting the game with a different key to reset the data of a player!

The problem is only for new players (without data), since if the same player closes the game, and re-enters, loading the saved data. The tycoon works correctly!

I leave the two Scripts that I think are the problem!

DATASAVING (in ServerScriptService)

local ds_service = game:GetService("DataStoreService")
local tycoon_ds = ds_service:GetDataStore("TycoonData")
local stats_ds = ds_service:GetDataStore("PlayerData")

local server_storage = game:GetService("ServerStorage")
local players = game:GetService("Players")
local http_service = game:GetService("HttpService")

local give_item_event = script.GiveItem

local player_list = {}

function RemoveFromPlayerList(player)
	if player then
		for i, v in pairs(player_list) do
			if v == player then
				table.remove(player_list, i)
				break
			end
		end
	end
end

function GetKey(player)
	return "keygameA5-"..player.UserId
end

function OnPlayerAdded(player)
	table.insert(player_list, #player_list + 1, player)
	local key = GetKey(player)
	local player_stats = stats_ds:GetAsync(key)
	local money_list = server_storage:WaitForChild("PlayerMoney")
	print(player_stats)
	--START
	if player_stats then
		print("P with Stats!")
		local money = money_list:WaitForChild(player.Name)
		local leaderstats = player:WaitForChild("leaderstats")
		local lvl = leaderstats.Level
		local exp = leaderstats.Exp
		if leaderstats then
			money.Value = player_stats[1] or 0
			lvl.Value = player_stats[2] or 1
			exp.Value = player_stats[3] or 0
			stats_ds:GetAsync(key,{money.Value,lvl.Value,exp.Value})
			print("Loaded DATA 3")
		end
	else if player_stats == nil then
			print("P NULL STATS")
			local money = money_list:WaitForChild(player.Name)
			local leaderstats = player:WaitForChild("leaderstats")
			print(leaderstats)
			local lvl = leaderstats.Level
			local exp = leaderstats.Exp
			if leaderstats then
				player_stats = {}
				money.Value = player_stats[1] or 0
				lvl.Value = player_stats[2] or 1
				exp.Value = player_stats[3] or 0
				stats_ds:SetAsync(key,{money.Value,lvl.Value,exp.Value})
				print("Saved DATA 3")
				stats_ds:GetAsync(key,{money.Value,lvl.Value,exp.Value})
				print("Loaded DATA 4")
			end
			local tycoon = money:WaitForChild("OwnsTycoon")
			print(tycoon)
			if tycoon then
				if tycoon.Value ~= nil then
					local save_data = {}
					for i, item in pairs(tycoon.Value.PurchasedObjects:GetChildren()) do
						table.insert(save_data, #save_data + 1, item.Name)
					end
					tycoon_ds:SetAsync(key, http_service:JSONEncode(save_data))
					print(http_service:JSONEncode(save_data))
				end
			end
		end
		
	end
end

function OnPlayerRemoving(player)
	RemoveFromPlayerList(player)
	local key = GetKey(player)
	local money_list = server_storage:WaitForChild("PlayerMoney")
	if money_list then
		local money = money_list:WaitForChild(player.Name)
		local leaderstats = player:WaitForChild("leaderstats")
		local lvl = leaderstats.Level
		local exp = leaderstats.Exp
		if money then
			local tycoon = money:WaitForChild("OwnsTycoon")
			if tycoon then
				if tycoon.Value ~= nil then
					local save_data = {}
					for i, item in pairs(tycoon.Value.PurchasedObjects:GetChildren()) do
						table.insert(save_data, #save_data + 1, item.Name)
					end
					tycoon_ds:SetAsync(key, http_service:JSONEncode(save_data))
					print(http_service:JSONEncode(save_data))
				end
			end
			stats_ds:SetAsync(key, {money.Value,lvl.Value,exp.Value})
			print("Saved Cash : "..money.Value)
			print("Saved Level : "..lvl.Value)
			print("Saved Exp : "..exp.Value)
		end
	end
end

function LoadTycoon(player, tycoon)
	if tycoon.Parent.Name == "Tycoons" then
		local key = GetKey(player)
		local tycoon_data = tycoon_ds:GetAsync(key)
		if tycoon_data then
			tycoon_data = http_service:JSONDecode(tycoon_data)
		end
		if tycoon_data and #tycoon_data > 0 then
			for i, item in pairs(tycoon_data) do
				give_item_event:Fire(tycoon, item)
			end
			if tycoon.Buttons:WaitForChild("StartGAME") then
				tycoon.Buttons.StartGAME:Destroy()
			end
		end
	end
end

players.PlayerAdded:Connect(OnPlayerAdded)
players.PlayerRemoving:Connect(OnPlayerRemoving)

game:BindToClose(function()
	for i, v in pairs(players:GetPlayers()) do
		OnPlayerRemoving(v)
	end
	wait(3)
end)

while wait(0.25) do
	for i, v in pairs(player_list) do
		local stats_folder = server_storage:WaitForChild("PlayerMoney")
		if stats_folder then
			local tycoon = stats_folder:WaitForChild(v.Name):WaitForChild("OwnsTycoon")
			if tycoon then
				if tycoon.Value == nil then
					tycoon:GetPropertyChangedSignal("Value"):Connect(function()
						print("Tycoon owned")
						LoadTycoon(v, tycoon.Value)
					end)
				else
					table.remove(player_list, i)
				end
			end
		end
	end
end

PLAYERSPAWN (in ServerScriptService)

local players = game:GetService("Players")
local server_storage = game:GetService("ServerStorage")
local data_store = game:GetService("DataStoreService"):GetDataStore("TycoonData")
local tycoons = workspace.ShoppingTycoon2021.Tycoons

function GetEmptyTycoon()
	for i, v in pairs(tycoons:GetChildren()) do
		if v.Owner.Value == nil then
			return v
		end
	end
	return nil
end

function HasDataCheck(player)
	local key = "keygameA5-"..player.UserId
	local data = data_store:GetAsync(key)
	return data and data ~= "[]"
end

function ClaimTycoon(player, tycoon)
	print("claimtycoon")
	local player_stats = server_storage:WaitForChild("PlayerMoney"):WaitForChild(player.Name)
	local owns_tycoon = player_stats:WaitForChild("OwnsTycoon")
	 tycoon.Owner.Value = player
	local entrance = tycoon.Entrance:FindFirstChildWhichIsA("Model")
	entrance.Name = player.Name.."'s Mall"
	entrance.Head.Transparency = 0.9
	entrance.Head.CanCollide = false
	player.TeamColor = tycoon.TeamColor.Value
	wait(0.5)
	owns_tycoon.Value = tycoon
end

function OnCharAdded(char, spawn_location)
	if char then
		local hrp = char:WaitForChild("HumanoidRootPart")
		local humanoid = char:WaitForChild("Humanoid")
		local i = 0
		repeat wait(0.05) 
			char:SetPrimaryPartCFrame(spawn_location.CFrame + Vector3.new(0, 5, 0))
			i += 1
		until hrp.Position == spawn_location.Position + Vector3.new(0, 5, 0) or i == 10 or humanoid.Health <= 0
	end
end

function OnPlayerAdded(player)
	local tycoon = GetEmptyTycoon()
	if tycoon then
		if HasDataCheck(player) then
			OnCharAdded(workspace:WaitForChild(player.Name), tycoon.Essentials.Spawn)
			player.CharacterAdded:Connect(function(char)
				OnCharAdded(char, tycoon.Essentials.Spawn)
			end)
			local i = 0
			repeat wait() i += 1 until #tycoon.Purchases:GetChildren() == 0 or i == 100
			ClaimTycoon(player, tycoon)
		else
			local char = workspace:WaitForChild(player.Name)
			char:SetPrimaryPartCFrame(tycoon.Entrance.NewPlayerSpawn.CFrame + Vector3.new(0, 5, 0))
			
			local player_stats = server_storage:WaitForChild("PlayerMoney"):WaitForChild(player.Name)
			local owns_tycoon = player_stats:WaitForChild("OwnsTycoon")
			owns_tycoon:GetPropertyChangedSignal("Value"):Connect(function()
				if owns_tycoon.Value.Parent.Name == "Tycoons" then
					player.CharacterAdded:Connect(function(char)
						OnCharAdded(char, owns_tycoon.Value.Essentials.Spawn)
					end)
				end
			end)
		end
	end
end

players.PlayerAdded:Connect(OnPlayerAdded)

I am currently working on migrating the script to DataStore2 since I felt that it is simpler and more optimized, but I await your point of view to continue or solve it!

Please I ask for your help as I am very new to fully understand what may be the cause!
From now on I thank you for your help!

(I apologize for my bad English! )

Is game.ServerStorage.PlayerMoney.<PlayerName>
being initialized anywhere?

If you talk about the creation of it, yes, in a script called Core_Handler, inside the tycoon Model (client) .

CORE_HANDLER

local Tycoons = {}
local Teams = game:GetService('Teams')
local Settings = require(script.Parent.Settings)
local BC = BrickColor
local Storage = Instance.new('Folder', game.ServerStorage)
Storage.Name = "PlayerMoney"
Instance.new('Model',workspace).Name = "PartStorage" --  parts dropped go in here to be killed >:)

function returnColorTaken(color)
	for i,v in pairs(Teams:GetChildren()) do
		if v:IsA('Team') then
			if v.TeamColor == color then
				return true
			end
		end
	end
	return false
end
--run this first so if there is a 'white' team it is switched over
if not Settings['AutoAssignTeams'] then
	local teamHire = Instance.new('Team', Teams)
	teamHire.TeamColor = BC.new('White')
	teamHire.Name = "For Hire"
end

for i,v in pairs(script.Parent:WaitForChild('Tycoons'):GetChildren()) do
	Tycoons[v.Name] = v:Clone() -- Store the tycoons then make teams depending on the tycoon names
	if returnColorTaken(v.TeamColor) then
		--//Handle duplicate team colors
		local newColor;
		repeat
			wait()
			newColor = BC.Random()
		until returnColorTaken(newColor) == false
		v.TeamColor.Value = newColor
	end
	--Now that there are for sure no duplicates, make your teams
	local NewTeam = Instance.new('Team',Teams)
	NewTeam.Name = v.Name
	NewTeam.TeamColor = v.TeamColor.Value
	if not Settings['AutoAssignTeams'] then
		NewTeam.AutoAssignable = false
	end
	v.PurchaseHandler.Disabled = false
end

function getPlrTycoon(player)
	for i,v in pairs(script.Parent.Tycoons:GetChildren()) do
		if v:IsA("Model") then
			if v.Owner.Value == player then
				return v
			end
		end
	end
	return nil
end

game.Players.PlayerAdded:connect(function(player)
	local plrStats = Instance.new("NumberValue",game.ServerStorage.PlayerMoney)
	plrStats.Name = player.Name
	local isOwner = Instance.new("ObjectValue",plrStats)
	isOwner.Name = "OwnsTycoon"
end)

game.Players.PlayerRemoving:connect(function(player)
	local plrStats = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
	wait(1)
	if plrStats ~= nil then
		plrStats:Destroy()
	end
	local tycoon = getPlrTycoon(player)
	if tycoon then
		local backup = Tycoons[tycoon.Name]:Clone()
		tycoon:Destroy()
		wait()
		backup.Parent=script.Parent.Tycoons
	end
end)

.
But if you talk about where it is called in the DataSaving and PlayerSpawn scripts, they are too!

local money_list = server_storage:WaitForChild("PlayerMoney")

ServerStorage from the client???

That’s wrong? I have read out there, that it is better to use the ReplicatedStorage.
Have you noticed anything bad besides that?
Sorry I’m just starting out in the script world!

ServerStorage
" A container whose contents are only accessible on the server. Objects descending from ServerStorage will not replicate to the client and will not be accessible from LocalScript s."

I haven’t gone over your code carefully, but that did jump out at me. A good place to start.
Scripts run on the server. LocalScripts run on the client. ModuleScripts can be either.

Note: A Script (as opposed to a LocalScript) runs on the server regardless of how it is
grouped / placed in the object explorer hierarchy.

1 Like

Thank you very much for the help! I’ll take a look at it