Setting one index in an array is setting all the other indices to the same value

Im trying to make a simple data management system

For some reason, whenever i want to set the data for one index in this array, all the rest of the indices are set to the same value. Like for example, if i were to set PlayerData[59876342] to “Hello”, all other entries (PlayerData[29347920], PlayerData[82957629], etc) will also be set to “Hello” with that single line of code. Does anyone know why this is happening? is there some property of tables that i dont understand here?

You mind showing the rest of the code? Specifically the parts where the Equip function is called, and other places where you modify stuff in the PlayerData table? (^▽^)

1 Like

The Equip function is an invoke from the client. The client invokes the function to equip an item, all it does is passes a few string values (Class is the class of the item to be equipped, name is the name of the item to be equipped, and other is a control variable for a particular type of item)

Here is the full script of this datastore:

local studio = game:GetService("RunService"):IsStudio()
local Storage = game:GetService("DataStoreService"):GetDataStore("PlayerData")
local meta = game:GetService("DataStoreService"):GetDataStore("Time")
local get = Storage.GetAsync
local set = Storage.SetAsync
local Functions = game.ReplicatedStorage.ServerRemotes
local Events = game.ReplicatedStorage.ServerRemotes
local filter = game:GetService("TextService")
local CasePrices = {0, 10, 50, 200}
local Item_Data = require(game.ReplicatedStorage.ItemData)
local repr = require(3148021300)


local Debounces = {}
local COMMON_SKINS = {}
local RARE_SKINS = {}
local EPIC_SKINS = {}
local LEGACY_SKINS = {}

local Tables = {
	[2] = {120,190,200},
	[3] = {100,150,195},
	[4] = {25, 180,185}
}

for x, i in pairs(require(game.ReplicatedStorage.ItemData).Gunner) do
	
	if x == "DEFAULT" then
	
	elseif i.Rarity == 1 then
		COMMON_SKINS[#COMMON_SKINS + 1] = {x, "Gunner", 1}
	elseif i.Rarity == 2 then
		RARE_SKINS[#RARE_SKINS + 1] = {x, "Gunner", 2}
	elseif i.Rarity == 3 then
		EPIC_SKINS[#EPIC_SKINS + 1] = {x, "Gunner", 3}
	else
		LEGACY_SKINS[#LEGACY_SKINS + 1] = {x, "Gunner", 4}
	end
end

for x, i in pairs(require(game.ReplicatedStorage.ItemData).Marksman) do
	if x == "DEFAULT" then
		
	elseif i.Rarity == 1 then
		COMMON_SKINS[#COMMON_SKINS + 1] = {x, "Marksman", 1}
	elseif i.Rarity == 2 then
		RARE_SKINS[#RARE_SKINS + 1] = {x, "Marksman", 2}
	elseif i.Rarity == 3 then
		EPIC_SKINS[#EPIC_SKINS + 1] = {x, "Marksman", 3}
	else
		LEGACY_SKINS[#LEGACY_SKINS + 1] = {x, "Marksman", 4}
	end
end

for x, i in pairs(require(game.ReplicatedStorage.ItemData).Cannoneer) do
	if x == "DEFAULT" then
		
	elseif i.Rarity == 1 then
		COMMON_SKINS[#COMMON_SKINS + 1] = {x, "Cannoneer", 1}
	elseif i.Rarity == 2 then
		RARE_SKINS[#RARE_SKINS + 1] = {x, "Cannoneer", 2}
	elseif i.Rarity == 3 then
		EPIC_SKINS[#EPIC_SKINS + 1] = {x, "Cannoneer", 3}
	else
		LEGACY_SKINS[#LEGACY_SKINS + 1] = {x, "Cannoneer", 4}
	end
end

for x, i in pairs(require(game.ReplicatedStorage.ItemData).Tagger) do
	if x == "DEFAULT" then
		
	elseif i.Rarity == 1 then
		COMMON_SKINS[#COMMON_SKINS + 1] = {x, "Tagger", 1}
	elseif i.Rarity == 2 then
		RARE_SKINS[#RARE_SKINS + 1] = {x, "Tagger", 2}
	elseif i.Rarity == 3 then
		EPIC_SKINS[#EPIC_SKINS + 1] = {x, "Tagger", 3}
	else
		LEGACY_SKINS[#LEGACY_SKINS + 1] = {x, "Tagger", 4}
	end
end


local PlayerData = {}

game.Players.PlayerAdded:Connect(function(plr)	
	--Create a data package
	local DataModel = {}
	
	--retrieve latest player data
	local success, plrKeys = pcall(get, meta, plr.userId)
	
	while not success do wait(1)
		print(plrKeys)
		local success, plrKeys = pcall(get, meta, plr.userId)
	end
	
	
	local highest = 0
	if plrKeys then
		for _, i in pairs(plrKeys) do
			if i then
				if i > highest then
					highest = i
				end
			end
		end
	end
	
	
	
	local success, data = pcall(get, Storage, plr.userId .. highest)
	
	while not success do wait(1)
		print(data)
		success, data = pcall(get, Storage, plr.userId .. highest)
	end
	
	
	
	--Unpack player data
	data = nil
	if data ~= nil then
		DataModel = data
	else
		DataModel = require(game.ReplicatedStorage.InitPlayerData)
	end
	
	
	PlayerData[tostring(plr.UserId)] = DataModel
	
	
	
	
	
	local statss = game.ReplicatedStorage.InitPlayerLeaderStats:Clone()
	for _, i in pairs(statss:GetChildren()) do
		i.Parent = plr
	end
	statss:Destroy()
	
	plr.Level.Value = DataModel.Level
end)


game.Players.PlayerRemoving:Connect(function(plr)
	
	--Pack player data
	local Export = PlayerData[tostring(plr.UserId)]
	
	
	--Add to dataStore
	
	local id = plr.userId
	local currTime = os.time()
	
	meta:UpdateAsync(id, function(data)
		local updateData = data or {}
		updateData[#updateData + 1] = currTime
		return updateData
	end)
	Storage:SetAsync(id .. currTime, Export)
	
	table.remove(PlayerData, tostring(plr.UserId))
end)

local function PrintoutData()
	print("GLOBAL SERVER DATA")
	print(" ")
	for x, i in pairs(PlayerData) do
		print(game.Players:GetPlayerByUserId(x).Name .. "'s Data: ")
		print(" ")
		print(repr(i))
	end
	print(" ")
end



local function ReturnData(plr)
	local data = PlayerData[tostring(plr.UserId)]
	
	if data == nil then
		repeat wait(1) until PlayerData[tostring(plr.UserId)]
		data = PlayerData[tostring(plr.UserId)]
	end
	
	return data
end

local function Equip(plr, class, name, other)
	local data = PlayerData[tostring(plr.UserId)]
	
	if data == nil then
		repeat wait(1) until PlayerData[tostring(plr.UserId)]
		data = PlayerData[tostring(plr.UserId)]
	end
	
	local own = false
	
	for _, i in pairs(data[class.."Skins"]) do
		if i == name then
			own = true
		end
	end
	
	if own then
		if class ~= "Music" then
			PlayerData[tostring(plr.UserId)]["Equip"..class] = name
			--data["Equip"..class] = name
		else
			if other then
				data["EquipMusic"][2] = name
			else
				data["EquipMusic"][1] = name
			end
		end
	end
	
	PrintoutData()
	return
end

local function Sell(plr, class, name)
	for _, i in pairs(Debounces) do
		if i[1] == plr then
			return
		end
	end
	
	
	table.insert(Debounces, #Debounces + 1, {plr, tick()})
	
	if name == "DEFAULT" or name == "NONE" then return end
	
	local data = PlayerData[tostring(plr.UserId)]
	
	if data == nil then
		repeat wait(1) until PlayerData[tostring(plr.UserId)]
		data = PlayerData[tostring(plr.UserId)]
	end
	
	local own = false
	
	for x, i in pairs(data[class.."Skins"]) do
		if i == name then
			own = x
		end
	end
	
	
	if own then
		local price = Item_Data[class][name].Price
		
		table.remove(data[class.."Skins"], own)
		
		data.Coins = data.Coins + price
	end
	
	
	
	local Equip = data["Equip" .. class]
	
	
	if class~= "Music" then
		local Owned = false
		
		for _, i in pairs(data[class.."Skins"]) do
			if i == Equip then
				Owned = true
			end
		end
		
		if not Owned then
			data["Equip" .. class] = "DEFAULT"
		end
	else
		local Owned = false
		local Owned2 = false

		for _, i in pairs(data["MusicSkins"]) do
			if i == Equip[1] then
				Owned = true
			end
			
			if i == Equip[2] then
				Owned2 = true
			end
		end

		if not Owned then
			data["EquipMusic"][1] = "NONE"
		end
		
		if not Owned2 then
			data["EquipMusic"][2] = "NONE"
		end
	end
	
	
	return
end


local function BuyCase(plr, tier)
	local data = PlayerData[tostring(plr.UserId)]
	
	if data == nil then
		repeat wait(1) until PlayerData[tostring(plr.UserId)]
		data = PlayerData[tostring(plr.UserId)]
	end
	
	local Coins = data.Coins
	
	if Coins >= CasePrices[tier] then
		if tier == 2 then
			data.Coins = Coins - CasePrices[tier]
			data.RareCases = data.RareCases + 1
		elseif tier == 3 then
			data.Coins = Coins - CasePrices[tier]
			data.EpicCases = data.EpicCases + 1
		elseif tier == 4 then
			data.Coins = Coins - CasePrices[tier]
			data.LegacyCases = data.LegacyCases + 1
		end
	end
	
	
	return
end

local function OpenCase(plr, tier)
	local data = PlayerData[tostring(plr.UserId)]
	
	if data == nil then
		repeat wait(1) until PlayerData[tostring(plr.UserId)]
		data = PlayerData[tostring(plr.UserId)]
	end
	
	local Type
	
	if tier == 4 then
		Type = "Legacy"
	elseif tier == 3 then
		Type = "Epic"
	else
		Type = "Rare"
	end
	
	if data[Type.."Cases"] >= 1 then
		data[Type.."Cases"] = data[Type.."Cases"] - 1
		
		local Rarity1 = math.random(1,200)
		local Rarity2 = math.random(1,200)
		local Rarity3 = math.random(1,200)
		
		local sel = math.random(1,3)
		
		
		if sel == 1 then
			Rarity1 = Tables[tier][tier-1]+1
		elseif sel == 2 then
			Rarity2 = Tables[tier][tier-1]+1
		else
			Rarity3 = Tables[tier][tier-1]+1
		end
		
		local Skin1
		local Skin2
		local Skin3
		
		Skin1 = COMMON_SKINS[math.random(1, #COMMON_SKINS)]
		if Rarity1 >= Tables[tier][1] then
			Skin1 = RARE_SKINS[math.random(1, #RARE_SKINS)]
		end
		if Rarity1 >= Tables[tier][2] then
			Skin1 = EPIC_SKINS[math.random(1, #EPIC_SKINS)]
		end
		if Rarity1 >= Tables[tier][3] then
			Skin1 = LEGACY_SKINS[math.random(1, #LEGACY_SKINS)]
		end	
		
		
		Skin2 = COMMON_SKINS[math.random(1, #COMMON_SKINS)]
		if Rarity2 >= Tables[tier][1] then
			Skin2 = RARE_SKINS[math.random(1, #RARE_SKINS)]
		end
		if Rarity2 >= Tables[tier][2] then
			Skin2 = EPIC_SKINS[math.random(1, #EPIC_SKINS)]
		end
		if Rarity2 >= Tables[tier][3] then
			Skin2 = LEGACY_SKINS[math.random(1, #LEGACY_SKINS)]
		end	
		
		
		Skin3 = COMMON_SKINS[math.random(1, #COMMON_SKINS)]
		if Rarity3 >= Tables[tier][1] then
			Skin3 = RARE_SKINS[math.random(1, #RARE_SKINS)]
		end
		if Rarity3 >= Tables[tier][2] then
				Skin3 = EPIC_SKINS[math.random(1, #EPIC_SKINS)]
		end
		if Rarity3 >= Tables[tier][3] then
			Skin3 = LEGACY_SKINS[math.random(1, #LEGACY_SKINS)]
		end	
		
				
		data[Skin1[2].."Skins"][#data[Skin1[2].."Skins"] + 1] = Skin1[1]
		data[Skin2[2].."Skins"][#data[Skin2[2].."Skins"] + 1] = Skin2[1]
		data[Skin3[2].."Skins"][#data[Skin3[2].."Skins"] + 1] = Skin3[1]
		
		return {Skin1, Skin2, Skin3}
	end
	
	return false
end

local function AddXp(plr, amount)
	local data = PlayerData[tostring(plr.UserId)]

	if data == nil then
		repeat wait(1) until PlayerData[tostring(plr.UserId)]
		data = PlayerData[tostring(plr.UserId)]
	end
	
	
	local xp = data.LevelUpProgress
	local level = data.Level
	local xpCap = level * 15 + 15
	
	plr.Score.Value = plr.Score.Value + amount
	
	if xp + amount >= xpCap then
		data.Level = level + 1
		data.LevelUpProgress = (xp + amount) - xpCap
		data.Coins = data.Coins + 5
		
		
		if level + 1 % 5 == 0 then
			if level + 1 % 100 == 0 then
				data.LegacyCases = data.LegacyCases + 1
			elseif level + 1 % 25 == 0 then
				data.EpicCases = data.EpicCases + 1
			else
				data.RareCases = data.RareCases + 1
			end
		end
		
		plr.Level.Value = plr.Level.Value + 1
		
		return
	end
	
	data.LevelUpProgress = data.LevelUpProgress + amount
	
	return
end

game:GetService("RunService").Heartbeat:Connect(function()
	for x, i in pairs(Debounces) do
		if tick() > i[2] + 1 then
			table.remove(Debounces, x)
		end
	end
end)


game.ReplicatedStorage.ServerRemotes.SellSkin.OnServerInvoke = Sell
game.ReplicatedStorage.ServerRemotes.BuyCases.OnServerInvoke = BuyCase
game.ReplicatedStorage.ServerRemotes.OpenCases.OnServerInvoke = OpenCase
game.ReplicatedStorage.ServerRemotes.EquipWeapon.OnServerInvoke = Equip
game.ReplicatedStorage.ServerRemotes.RetrieveCurrentData.OnServerInvoke = ReturnData
game.ReplicatedStorage.ServerRemotes.GetCurrentData.OnInvoke = ReturnData
game.ReplicatedStorage.ServerRemotes.AddXp.OnInvoke = AddXp
1 Like

So I’ve read through the code, and I didn’t find anything that’d be doing that… Only thing that I can think of is to change the entries from string to number (instead of PlayerData[tostring(plr.UserId)], do PlayerData[plr.UserId]), which might fix it? But other than that, I can’t think of anything that might be causing it…

1 Like

the tostring() was an attempt to fix it by using a solid string index, but that didnt seem to be the problem.

Well then, you should ask someone smarter than me because there is actually nothing there that might be causing this. I did this exact method to cache player data before using frameworks, and I’ve never had this problem. (⌒_⌒;)

1 Like

I figured it out. In the player added function, The script gives the player a starter table of values if they do not already have a save. For lua tables, setting the value of a variable to an array does not clone the array, it simply sets a reference to the original array. Apparently when using require() on a module script containing an array, this has the same property of simply setting a reference. To solve this problem, all i had to do was iterate through the module script and rebuild the array for each player when they needed it instead of just giving them the module directly.

2 Likes