Every player being given the same data table

I’ve just come back to a game from about 2-3 months ago, and it was working perfectly fine when I left it, just joined now with a friend and the data system is completely broken.

-- Data module
local data = {
    Level = 1
}

return data

-- Main script
local dataStoreService = game:GetService('DataStoreService')
local playerDataStore = dataStoreService:GetDataStore('PlayerDataStore')

local playersData = {}

function updateData(backbone, update)
	local new = update
	
	if update == nil then return backbone end
	
	function recurse(tab, ...)
		local args = {...}
		local target = new
		
		for i = select('#', ...), 1, -1 do
			target = target[args[i]]
		end
		
		for i, v in next, tab do
			if type(v) ~= 'table' or (type(v) == 'table' and target[i] == nil) then
				target[i] = v
			else
				recurse(tab[i], i, ...)
			end
		end
	end

	recurse(backbone)
	
	return new
end

function dataManager:GetData(player) -- Fired when player joins
	local loadData = playerDataStore:GetAsync(player.UserId) or data
	
	playersData[player.UserId] = updateData(loadData, data)
end

Now I have this updateData table. What this table did was check the ‘new’ data module (located at the top of the script) for any changes to the players saved data. If the player had a new data model missing, it would be added to their data without affecting any of their previous data. Not sure if now something has changed within roblox that screws up this function? But this function has to stay put.

And when I do
print(player, playersData[player.UserId])
after the data is ready, it returns the same table. Well, table, followed by a bunch of numbers and letters, but it’s the same for both players

[Player1 table: 00000255CE9DB340]
[Player2 table: 00000255CE9DB340]

You’re returning the same table as you pass in. When you pass in a table to a function, it passes a reference to the table, so it will be the same table.

1 Like

Wdym???

You pass in two parameters to your function, update and backbone.
You should be modifying backbone, and returning that, however you are modifying the update variable which holds a reference to the data table so it will be the same table anywhere it is used.

You should be doing recurse(new) and settings the target variable to backbone, if I am not mistaken.

2 Likes

When I did this tho

local dataStoreService = game:GetService('DataStoreService')
local playerDataStore = dataStoreService:GetDataStore('PlayerDataStore')

local playersData = {}

function dataManager:GetData(player) -- Fired when player joins
	local loadData = playerDataStore:GetAsync(player.UserId) or data
	
	playersData[player.UserId] = loadData 

    print(player, playersData[player.UserId])
end

And completely got rid of the updateData function, it still occured. So it can’t be anything to do with that function.

It is because of or data
Try using or updateData({}, data)

Could it be because PlayerData is outside PlayerAdded? Since it’s outside wouldnt that mean it gets overidden with the newest players data? But at the same time it makes no sense cause I’ve had it like that forever

No. It’s because you return the data table if no data exists for the user and if several people have no data, they will all use the same data table.

1 Like

If no data exists then they are given the default data. This can’t be the problem

You’re saving a reference to the table. Tables don’t get copied whenever you put them in other variables.

2 Likes

If I did or updateData({}, data) then that means only new players will get the updateData. The point of UpdateData is for players who have a data store already

Then you’ll have to transfer the contents of data into a new table, then assign that.

1 Like

[Player1 table: 00000204E282B3C0]
[Player2 table: 00000204E282B3C0]

local loadData = PlayerDataStore:GetAsync(Player.UserId) or updateData({}, Data)
		
	PlayersData[Player.UserId] = loadData
	
	print(Player, PlayersData[Player.UserId])

Still got the same result

local newData = {};
for i,v in pairs(Data) do
newData[i] = v;
end

Use this code, then assign newData if they do not have any data saved.
This will transfer everything from the default data into a new table.

1 Like
local loadData = playerDataStore:GetAsync(player.UserId) or {ActualDataTableHere}

What do you mean ActualDataTableHere?? the or data is

{
    Level = 1
}

I literally mean move that piece of code onto the place of “or data

But the piece of code is

return {
	CurrentBackpack = 'Starter',
	CurrentBread = 'Brown',
	CurrentDucks = {
		{Tier = 1, Rarity = 'Common'},
	},
		
	Cash = 0,
	Gems = 0,
	Happiness = 0,
	MaxHappiness = 25,
	Rebirths = 0,
	
	Inventory = {
		Backpacks = {
			'Starter'
		},
		Breads = {
			'Brown'
		},
		Ducks = {
			{Tier = 1, Rarity = 'Common'},
		},
	},
	
	Codes = {
		
	},
	
	Levels = {
		['Frantic Farm'] = false,
		['Walters Waterpark'] = false
	},
}

Would take up too much space in one line

local loadData = playerDataStore:GetAsync(player.UserId) or {
	CurrentBackpack = 'Starter',
	CurrentBread = 'Brown',
	CurrentDucks = {
		{Tier = 1, Rarity = 'Common'},
	},
		
	Cash = 0,
	Gems = 0,
	Happiness = 0,
	MaxHappiness = 25,
	Rebirths = 0,
	
	Inventory = {
		Backpacks = {
			'Starter'
		},
		Breads = {
			'Brown'
		},
		Ducks = {
			{Tier = 1, Rarity = 'Common'},
		},
	},
	
	Codes = {
		
	},
	
	Levels = {
		['Frantic Farm'] = false,
		['Walters Waterpark'] = false
	},
}
1 Like

Wow :confused: That actually worked! Can you explain why using a variable name does not work?? Cause I’ve had it that way for several months and never ran into this problem ever before