When i change the properties of an object inside of a module script the results dont translate back into the local script, they change into the server if I run the same code in a server script, it just doesnt work on a local script. The object will be made and be given all the properties just not if I try to update it.
local script different script different man
you can require a module two times
1-localscript
2-script
they different
script cant touch localscript module,
localscript module cant touch script module
i require the module twice once in server and once in local, just local doesnt work the same as server for some reason
I have this inside the openegg method inside the module
self.petInventory["Check"] = "ho"
print(self)
This inside the local script
gameObject:OpenEgg(LocalPlayer,EggToOpen)
print(gameObject)
Below are the two prints one is from the module and one is from the local script
{
[“CurrentlySelling”] = false,
[“EnergyIntake”] = 10,
[“ItemsCarrying”] = 0,
[“WaitTime”] = 0.6,
[“petCapacity”] = 10,
[“petInventory”] = ▼ {
[“Check”] = “ho”,
[“Pet1”] = {…}
}
} - Client - GameMechanics:205
{
[“CurrentlySelling”] = false,
[“EnergyIntake”] = 10,
[“ItemsCarrying”] = 0,
[“WaitTime”] = 0.6,
[“petCapacity”] = 10,
[“petInventory”] = {}
} - Client - PlayerHandeller:110
That’s because server script’s and local script’s version of a module script’s return value don’t share the same memory, so don’t share the same data.
A server script requiring this module fetches a table that exists in memory on the server machine, the actual server host.
A local script requiring this module fetches a table that exists in memory on your client machine, the machine you are using to play.
ModuleScripts aren’t designed to replicate their return values across the network by default, so they don’t share the same values on both server and client. You need to manually do the replication yourself with RemoteFunctions or RemoteEvents with your own code, but I wouldn’t recommend taking this approach because it is very insecure and easily exploited.
You should be using those remote objects if you want to talk between server and client.
I’m not trying to replicate any data through the server/client boundary all I’m trying to do is use a module script with a local script I just used the server script as a comparison to say that when I use the same module script but use a server script instead of a local script the code works fine.
In the code/prints I supplied they are both from Client side, neither is sent from server.
Oh I see, it’s hard to tell what exactly you’re asking about by the posts alone.
What exactly is it that the code is trying to do then? There isn’t any information in these posts about what the structure is used for, how exactly the module manipulates it and when, or how the local scripts use it. You need to provide more code to provide a working context to make sense of the issue.
Right now it sounds like there are two different tables being used and passed around, which would explain why the changes don’t propagate.
All i’m trying to do is change a value of the object I create with the module script.
function GameMechanics.new(Player)
local NewTable = {}
NewTable = {
ItemsCarrying = 0,
petInventory = {},
petCapacity = 10,
CurrentlySelling = false,
WaitTime = 0.6,
EnergyIntake = 10
}
return setmetatable(NewTable,GameMechanics)
end
This is my initialising code for the module and if I try to change any of them values in a different method they don’t change inside the localscript when I call self again it will have changed but the values in the localscript remain the same.
Something small here to look at that’s most likely unrelated to the issue:
local NewTable = {} -- making a new empty table
NewTable = { -- replacing the old empty table with a brand new table with values inside of it
...
You’re creating an empty table only to replace it with one that is populated.
As for the metatable, does the metatable have a __newindex
metamethod?
Also, upon closer inspection the two tables appear to be completely different ones altogether, which would explain why the property addition isn’t propagating. The Client - GameMechanics:205
one has a Pet1
field which the PlayerHandeller:110
one doesn’t have, and the GameMechanics one also has a petInventory
table that is populated while the other is empty.
How are you keeping track of references to these? Are you making any new copies anywhere in other scripts that could be overwriting and replacing the one PlayerHandler
knows about?
There is a lot of code that is being missed out sorry for not including it.
First I use NewTable = {} because I use them both server and local side
function GameMechanics.new(Player)
local NewTable = {}
if (isServer) then
NewTable = {
ItemsCarrying = 0,
petInventory = {},
petCapacity = 10,
CurrentlySelling = false,
WaitTime = 0.6,
EnergyIntake = 10
}
else
NewTable = Remotes.CreateGameObject:InvokeServer()
end
print(NewTable)
return setmetatable(NewTable,GameMechanics)
end
the data of the NewTable is set through a copy of the servers data.
Pet1 is only inside the other Table as in the same function that sets the
self.petInventory["Check"] = "ho"
I also set Pet1
function GameMechanics:OpenEgg(Player,EggToOpenModel)
if (isServer) then
print(self.WaitTime .. "\n wait time :D")
--Checks that the players character exits and that there is an egg to open
if Player.Character and EggToOpenModel and Player.leaderstats:FindFirstChild("Energy") then
if EggListLib[EggToOpenModel.Name] and (Vector3.new(EggToOpenModel.PrimaryPart.Position.x,0,EggToOpenModel.PrimaryPart.Position.z) - Vector3.new(Player.Character.PrimaryPart.Position.x,0,Player.Character.PrimaryPart.Position.z)).magnitude < EggToOpenModel.PrimaryPart.Size.z then
--This rolls using math.random between 1 and 10k to get a Rarity, I might move this to a library if the amount of rarities change
local EggToOpen = EggListLib[EggToOpenModel.Name]
local NumOfCategories = Length(EggToOpen)
print(NumOfCategories)
if NumOfCategories == 5 then
--legendary should have .25% for total categories epic should have 1.75% rare should have 8% uncommon should have 30% and common should have 60%
local Rarity = ""
local RarityRandom = math.random(1,10000)
if RarityRandom >= 9975 then
print("with a ticket of " .. RarityRandom .. " we got a legendary")
Rarity = "Legendary"
elseif RarityRandom >= 9800 then
print("with a ticket of " .. RarityRandom .. " we got a Epic")
Rarity = "Epic"
elseif RarityRandom >= 9000 then
print("with a ticket of " .. RarityRandom .. " we got a rare")
Rarity = "Rare"
elseif RarityRandom >= 6000 then
print("with a ticket of " .. RarityRandom .. " we got a uncommon")
Rarity = "UnCommon"
else
print("with a ticket of " .. RarityRandom .. " we got a common")
Rarity = "Common"
end
--Once a Rarity has been found then we randomly choose one within the rarity
if EggToOpen[Rarity] then
local PetRandomindex = math.random(1,Length(EggToOpen[Rarity]))
if EggToOpen[Rarity][PetRandomindex] then
local PetRandom = EggToOpen[Rarity][PetRandomindex]
if Player:FindFirstChild("leaderstats") then
if PetSpecsLib[PetRandom] then
if PetSpecsLib[PetRandom]["Rarity"] == Rarity then
local PetSpecs = PetSpecsLib[PetRandom]
local lengthOfInventory = Length(self.petInventory)
local PetInvSpace = lengthOfInventory + 1
if PetInvSpace <= self.petCapacity then
print("bought a new pet which is #" .. PetInvSpace)
self.petInventory["Pet" .. tostring(PetInvSpace)] = {
Name = PetRandom,
Rarity = PetSpecs["DuckRarity"],
EnergyRate = PetSpecs["EnergyRate"],
lvl = 1,
exp = 0
}
end
end
end
end
end
end
end
end
end
else
self = Remotes.OpenEgg:InvokeServer(EggToOpenModel)
self.petInventory["Check"] = "ho"
print(self)
end
end
Check is only set on client side as I wanted to check if the fact that we ran
self = Remotes.OpenEgg:InvokeServer(EggToOpenModel)
broke the code, but even when i run
self.petInventory["Check"] = "ho"
client side it still breaks
This code right here would only hide the instance of the object that self
represents, it doesn’t write to the values or replace them with the new values from the Remotes.OpenEgg:InvokeServer
call.
Using hypothetical memory addresses, like if you were to print the tables to see something like table: 0x1101380
on a standard Lua VM, the code would look like this:
-- self = table: 0xAAAAAA
self = Remotes.OpenEgg:InvokeServer(EggToOpenModel) -- overwrite 'self' with table: 0xBBBBBB
-- self = table: 0xBBBBBB
self.petInventory["Check"] = "ho"
print(self) -- output: table: 0xBBBBBB
Then in your local script:
-- gameObject = table: 0xAAAAAA
gameObject:OpenEgg(LocalPlayer,EggToOpen)
-- gameObject = table:0xAAAAAA
print(gameObject) -- output: table: 0xAAAAAA
-- would not see changes from table 0xBBBBBB because those are in a different table
You would need to copy over the values after the call to Remotes.OpenEgg:InvokeServer
local newServerState = Remotes.OpenEgg:InvokeServer(EggToOpenModel)
-- copy values from newServerState to self
print(self) -- output: 0xAAAAAA
print(newServerState) -- output: 0xBBBBBB
Thanks i’ll just return the values that I change on the server side then write them individually to the self instead of changing self itself.
Why can’t I just set it to self though, why do I have to individually set each element inside of the self table.
What you’re describing is a “copy by value”, where copying a structure copies over all the individual values inside the structure too.
What Lua and Luau do is they copy by reference instead, where self
isn’t the raw value of the table and all the data inside of it, but rather self
is a reference to the table. It’s a memory address that points to the table. When you pass around a table, you aren’t passing around the value of the table. You’re passing around a reference to the table, and multiple references to the same table will all point back to it, and see the same values both before and after changes.
Pass by value
local tableA = { Name = "TableA" }
local tableB = tableA
local tableC = tableA
tableB.Name = "TableB"
tableC.Name = "TableC"
print(TableA) -- { Name = "TableA" }
print(TableB) -- { Name = "TableB" }
print(TableC) -- { Name = "TableC" }
tableA = tableC
tableC.Name = "TableD"
print(TableA) -- { Name = "TableC" }
print(TableB) -- { Name = "TableB" }
print(TableC) -- { Name = "TableD" }
TableB = { Name = "New TableB" }
print(TableA) -- { Name = "TableC" }
print(TableB) -- { Name = "New TableB" }
print(TableC) -- { Name = "TableD" }
Pass by reference:
local tableA = { Name = "TableA" }
local tableB = tableA
local tableC = tableA
tableB.Name = "TableB"
tableC.Name = "TableC"
print(TableA) -- { Name = "TableC" }
print(TableB) -- { Name = "TableC" }
print(TableC) -- { Name = "TableC" }
tableA = tableC
tableC.Name = "TableD"
print(TableA) -- { Name = "TableD" }
print(TableB) -- { Name = "TableD" }
print(TableC) -- { Name = "TableD" }
TableB = { Name = "New TableB" }
print(TableA) -- { Name = "TableD" }
print(TableB) -- { Name = "New TableB" }
print(TableC) -- { Name = "TableD" }
Edit: fixed some typos and added an additional case to highlight the differences more