Players' value gets overwritten by other players' value?

Player1 joins has no data, and gets data. The same with Player2. If Player1 starts earning Money and if Player2 starts to collect Money after let’s say Player1 has 50 Money, then Player2 will get 51 Money?

NoteStudio and bolere_bolere are new players, whilst mortenerjsefh already had data and both of the newer players get each other’s values after one of them earn “Money”:
image

Note: This doesn’t happen to players with data already.

local DataService = {} -- This is a module.
local PlayerSessionData = {} -- Storage for every players' data.

-- Data holder/structure in my system:
local DataStructure = {
	Currencies = {
		Money = 0,
		Stars = 0
	}
}

-- Money handler:
local MoneyCollect = {}

local function CollectMoney(player, world)
	local Money = PlayerSessionData[player].Currencies.Money
	local Equipped = PlayerSessionData[player].Upgrades.Equipped
	local Amount = UpgradeModule[world][Equipped].Increase
	if not PlayerSessionData[player].Currencies.Money then
		return warn("Player does not have Money, data!")
	end
	local function AwardMoney()
		PlayerSessionData[player].Currencies.Money = PlayerSessionData[player].Currencies.Money + Amount
		DataService:SyncLeaderstats(player) -- this only sync the player's SessionValues to Leaderstats.
	end
	if not MoneyCollect[tostring(player.UserId)] then
		MoneyCollect[tostring(player.UserId)] = true
		AwardMoney()
		MoneyCollect[tostring(player.UserId)] = false
	end
end

-- Connections:
MoneyEvent.OnServerEvent:Connect(CollectMoney)

return DataService

I might think that it might be the way that I change each players’ money?

It’s hard to say exactly without seeing more context, but this probably has to do with how you set up your default data. You’re just setting it to DataStructure, I’d assume, rather than deep copying it. This means each player who needs to use the default data table ends up using the same table, rather than a new table with the same values.

3 Likes

I do not understand how deep copying it would be helpful, and how could I use it?

Module:

--// 𝙎𝙀𝙍𝙑𝙀𝙍
local DataService = {}

-- Variables:
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local PlayerData = DataStoreService:GetDataStore("PlayerData")
local MoneyEvent = game.ReplicatedStorage.Assets.Events:WaitForChild("CollectMoney")
local PlayerSessionData = {} -- Storage for every players' data.

local DataStructure = {
	Currencies = {
		Money = 0
	}
}

-- Functions:
function DataService:SaveData(player) -- Saves players' data.
	if not player then
		return warn("Player does not exist anymore!")
	end
	local tries = 0
	local success
	repeat
		tries = tries + 1
		success = pcall(function()
			PlayerData:SetAsync("data:"..player.UserId, PlayerSessionData[player])
		end)
		if not success then
			wait(1)
		end
	until tries == 5 or success
	if not success then
		warn("Cannot save data for "..player.Name.."!")
	else
		warn("Data was saved for "..player.Name.."!")
	end
end

function DataService:LoadData(player) -- Loads players' data.
	local Data = PlayerData:GetAsync("data:"..player.UserId)
	PlayerSessionData[player] = Data
end

function DataService:SetupLeaderstats(player)
	local Folder = Instance.new("Folder", player)
	Folder.Name = "leaderstats"
	local Money = Instance.new("IntValue", Folder)
	Money.Name = "Money"
	Money.Value = PlayerSessionData[player].Currencies.Money
end

function DataService:SyncLeaderstats(player)
	local leaderstats = player:WaitForChild("leaderstats")
	leaderstats.Money.Value = PlayerSessionData[player].Currencies.Money
end

function DataService:SetupData(player) -- The setup for players' data.
	local Data = PlayerData:GetAsync("data:"..player.UserId)
	if not Data then -- Creates new data if the player doesn't have it.
		PlayerSessionData[player] = DataStructure
		self:SetupLeaderstats(player) -- Add physically visible leaderstats.
		return print(player.Name .. " has no data!")
	end
	if Data then
		print(player.Name .. " has data!")
		self:LoadData(player) -- Load data.
		wait(0.5) -- Wait extra to wait for data to prevent UpToDate error.
		self:SetupLeaderstats(player) -- Add physically visible leaderstats.
	end
end

local function CollectStar(player, amount)
	amount = 1
	PlayerSessionData[player].Currencies.Money = PlayerSessionData[player].Currencies.Money + amount
	DataService:SyncLeaderstats(player)
end

-- Connections:
MoneyEvent.OnServerEvent:Connect(CollectStar)

return DataService

Here, each player without data is getting assigned the same table. Whenever you edit their data in that server, the same table (that every player without data is using) would be edited. If you deep-copied DataStructure at this line, then each player would have their own table with the same values, as they should.

You would just swap that line to PlayerSessionData[player] = yourDeepCopyFunction(DataStructure). The page I linked has a few different functions on it, just make sure to use one of the actual deep copy ones.

4 Likes

You can do what @posatta suggested or initialize a new table for each player this way:

PlayerSessionData[player] = {
	Currencies = {
		Money = 0
	}
}
1 Like

:+1: You saved my game from this huge issue, thanks!

1 Like