Thanks for reading this in advance.
I’m fiddling with a data-persistence module that interfaces with the DataStoreService, and I’m running into a befuddling issue: when I run the game in a two-player test server, any changes made to one player’s data are replicated in the other; If Player1 gets a KO, Player2 gets a KO, etc. After banging my head against the wall for a couple hours, I’m convinced I’ve managed to track down the source, a single function in my module:
local function setupPlayerData(player)
local pID = "Player_" .. player.UserId
local success, data, oldData
success, data = dataRetry(function()
return pData:GetAsync(pID)
end)
success, oldData = dataRetry(function()
return pData:GetAsync(player.UserId)
end)
if success then
if data then sessionData[pID] = data
elseif oldData then sessionData[pID] = convertOld(data)
else sessionData[pID] = {Game = game_Stats, Class = setmetatable(class_Stats, mt)}
end
else warn("Cannot access data store for player!")
end
end
If the datastore is functioning, but the player doesn’t have any data, it creates an entry for the player in sessionData and sets it to a table containing two other tables, one being the default game data and the other being a list of data relevant to every playable class in the game. The two tables - game_stats and class_Stats - are global variables listed at the top of the script, which I’ll show you here:
i_n = Instance.new
c3 = Color3.new
uit = Enum.UserInputType
kc = Enum.KeyCode
--
function wfc(p, o, t)
return p:WaitForChild(o, t)
end
function newC3(r, g, b)
return c3(r/255, g/255, b/255)
end
--
local ss = game:GetService("ServerStorage")
local cBin = wfc(ss, "Classes")
local dss = game:GetService("DataStoreService")
local pData = dss:GetDataStore("PSATest")
local manager = {}
local sessionData = {}
local class_Stats = {}
local gData = {}
local autosave_int = 300
--
for _,p in pairs(cBin:GetChildren()) do
--
local t = {
Wins = 0,
Rounds = 0,
KOs = 0,
WOs = 0,
KDR = 0,
WR = 0,
Damage = 0,
Healing = 0,
Time = 0,
Skin = "",
PrimaryColor = newC3(91, 93, 105),
SecondaryColor = newC3(159, 161, 172),
TertiaryColor = newC3(248, 248, 248),
}
local g = {
KOs = 0,
WOs = 0,
Rounds = 0
}
--
class_Stats[p.Name] = t
gData[p.Name] = g
end
local game_Stats = {
--
Stats = {
Points = 0,
Rounds = 0,
Wins = 0,
Streak = 0,
KOs = 0,
WOs = 0,
KDR = 0,
WR = 0,
Damage = 0,
Healing = 0,
Time = 0,
LastPlayed = os.date("*t"),
Joined = os.date("*t"),
},
--
Settings = {
Class = "Warrior",
Playing = true, ToolMode = false,
OverheadHP = false, SmallUI = false,
ShowHits = false, Volume = 50
},
--
KeyBinds = {
ATK = {uit.MouseButton1, kc.Unknown},
AB1 = {uit.Keyboard, kc.Q},
AB2 = {uit.Keyboard, kc.E},
CRT = {uit.Keyboard, kc.F}
},
PadBinds = {
ATK = {uit.Gamepad1, kc.ButtonR2},
AB1 = {uit.Gamepad1, kc.ButtonX},
AB2 = {uit.Gamepad1, kc.ButtonY},
CRT = {uit.Gamepad1, kc.ButtonB}
},
--
Inventory = {}
}
local mt = {
__call = function(stats, class)
stats = stats[class]
if stats then gData.KOs = gData.KOs + stats.KOs
gData.WOs = gData.WOs + stats.WOs
gData.Rounds = gData.Rounds + stats.Rounds
end
end
}
Thus, I’m assuming changes to individual players’ data are replicated to the others because they technically don’t have their own data tables, just a pointer to the global tables I defined at the top of the data script. I’ve tried localizing them to the function instead, to no avail. If this is in fact the issue, how can I give new players a copy of the default data tables without simply making a pointer to them?