For my game I made an avatar editor… However, I have a local script when the player clicks a “Play” button that checks if the player has saved a character before. It uses a remote function to a script that returns the value from a module. It works with 1 player, but when i have multiple players it always returns “Yes” instead of “No”. How would I fix this? Or is there a better way to check this?
Here is local script:
script.Parent.PlayButton.MouseButton1Click:Connect(function()
script.Parent.PlayButton.Visible = false
local send = GetTableEvent:InvokeServer("Character")
if send == "No" then
game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = 0
game.Workspace.CurrentCamera.CameraType = "Scriptable"
game.Workspace.CurrentCamera.CFrame =
game.Workspace.CurrentStuff.AvatarEditor.Camera.CFrame
script.Parent.Parent.AvatarEditorFrame.Visible = true
elseif send == "Yes" then
print("HasCharacter")
end
end)
Here is the normal script:
local GetTableEvent = game.ReplicatedStorage.Stuff.GetFromTable
local DataModule = require(game.ReplicatedStorage.Modules.MainData)
function ReturnValue(plr,value)
local NewVal = DataModule:GetFromTable(plr, value)
return NewVal
end
GetTableEvent.OnServerInvoke = ReturnValue
And Finally Here is the Module:
function PlayerStatManager:GetFromTable(player, statName)
local playerUserId = 'Player_" .. player.UserId
local SendBack = sessionData[playerUserId][statName]
return SendBack
end
return PlayerStatManager
You aren’t going to get help effectively with that unindented code. We can’t read that thing. and only post the codes that are relevant. I also do not see anywhere where you return “Yes” or “No”.
The wildest guess I’m going to make here is that there is a massive discrepancy between the data that the module is able to reasonably get and your own code. What are you using to add data to the table? There is no way that the only code you have in your PlayerStatManager Module is a singular function.
local PlayerStatManager = {}
local sessionData = {}
local Main = {
["Name"] = nil,
["Tokens"] = 0,
["TutorialMayor"] = "No",
["Character"] = "No",
["AlienTrigger"] = "No",
}
local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerDataTest26)
local AUTOSAVE_INTERVAL = 70
function PlayerStatManager:ChangeValue(player, statName, value)
local playerUserId = "Player_" .. player.UserId
sessionData[playerUserId][statName] = value
print(sessionData[playerUserId][statName])
end
-- Function to add player to table
local function setupPlayerData(player)
local playerUserId = "Player_" .. player.UserId
local success, data = pcall(function()
return playerData:GetAsync(playerUserId)
end)
if success then
if data then
-- Data exists for this player
sessionData[playerUserId] = data
else
-- Data store is working, but no current data for this player
sessionData[playerUserId] = Main
end
else
warn("Cannot access data")
end
end
-- Function to save player's data
local function savePlayerData(playerUserId)
if sessionData[playerUserId] then
local success, err = pcall(function()
playerData:SetAsync(playerUserId, sessionData[playerUserId])
end)
if not success then
warn("Cannot save data")
end
end
end
-- Function to save player data on exit
local function saveOnExit(player)
local playerUserId = "Player_" .. player.UserId
savePlayerData(playerUserId)
end
local function autoSave()
while wait(AUTOSAVE_INTERVAL) do
for playerUserId, data in pairs(sessionData) do
savePlayerData(playerUserId)
end
end
end
spawn(autoSave) -- runs auto save
game.Players.PlayerAdded:Connect(setupPlayerData)
game.Players.PlayerRemoving:Connect(saveOnExit)
Instead of setting it at the top of script, put it in the function.
I would do something like this.
-- Data store is working, but no current data for this player
sessionData[playerUserId] = {} -- I habitually define the table first
sessionData[playerUserId] = {["Name"] = nil,["Tokens"] = 0,["TutorialMayor"] = "No",["Character"] = "No",["AlienTrigger"] = "No"}
Or you could probably do
local Main = {["Name"] = nil,["Tokens"] = 0,["TutorialMayor"] = "No",["Character"] = "No",["AlienTrigger"] = "No"}
sessionData[playerUserId] = Main
The issue OP is facing is that tables are passed by reference, not by value. Assigning an existing table to a new index is just going to reference that old table and the changes already made to it. (As elaboration why the above works)
You should note though, that your first snippet of code has a ‘habit’ that is entirely redundant; functionally nothing changes, but in practice you are reserving memory for a new table ( {} is the constructor for tables, you are constructing a new one two times ) and then drop all references to it to reserve more memory for another new table. Removing the line entirely changes nothing in the result but uses less memory. Normally habits are fine, but if they are wasting resources it’s worth to take note and stop doing it.
So the ideal solution then would be something simple, like this?
-- Data store is working, but no current data for this player
sessionData[playerUserId] = {["Name"] = nil,["Tokens"] = 0,["TutorialMayor"] = "No",["Character"] = "No",["AlienTrigger"] = "No"}
That would indeed be sufficient. To customize it further it’s a thought to instead assign the result of a function that generates the starter table with a few possible presets (from args given), but anything works as long as the table returned is a new one and not a reference to the default itself.