Let’s say we have a LocalScript inside an Actor object and it requires a ModuleScript that is not inside the actor.
And let’s say we have another LocalScript that is not inside an Actor but is instead in ReplicatedFirst so it runs first and it requires the same module.
Now, let’s say the module looks something like this
local module = {
CoolScript = nil
}
return module
In the LocalScript located in ReplicatedFirst let’s have it require this module and then set CoolScript to a reference of itself.
local module = require(moduleObj)
module.CoolScript = script
What is supposed to happen when I require the same module from the script within the Actor? Should CoolScript be set?
local module = require(moduleObj)
print(module.CoolScript)
When I try this myself, I see nil printed in the output. The reason I’m confused is that I didn’t see this mentioned anywhere in the documentation and it kind of breaks all of my plans. In my testing and in this example I don’t have any code running in parallel yet. Nothing has been desynchronized. It’s just a LocalScript in an actor.
This has taken me a few very frustrating hours to figure out. Thanks in advance.
As far as I am aware, using require() on a module script will return the exact same thing to all scripts, generally being in the form of a table.
When you are changing the value of CoolScript, you aren’t changing the value in the module, rather you changed the value in the table that was copied to the localscript, which is why you don’t see the change replicated to the other script.
So in answer to your original question:
While scripts in actors get a copy of the contents of the required module script, they do NOT get their own instance, and instead access (and modify) a copy of the table which was in the module
It’s frustrating that this is how I have to find this out. It seems like something they really should mention somewhere on this page.
I found a mention of it here in a preview post. It’s the last place I would think to look.
ModuleScripts
Scripts that run in the same Actor are running in the same Luau VM, but scripts that run in different actors may run in different VMs. You can’t control the allocation of Actors to VMs or the total number of VMs - it depends on the number of cores the processor has and some other internal parameters.
When you require a ModuleScript from a Script inside the Actor, the script is going to get loaded (& cached) in every VM it’s needed in. This means that if your ModuleScript has mutable state, this state will not be global to your game anymore - it will be global to a VM, and there may be multiple VMs at play.
We encourage use of ModuleScripts that don’t contain global state. In the future we’re going to provide a shared storage that will be thread-safe so that games that use parallel execution can use it to store truly global state, as well as ways to communicate between scripts safely using messages, but for now you should be aware of this gotcha.
I guess it’s time to refactor my whole damn game, or at least look for performance improvements elsewhere.
I just have the same issue today. simply i was learning this actor thing and then i said hey lets do this after a while seemed like instead of copying the module who got changed globally what normal scripts do it copied the module like it was new and nothing have changed now suprisingly i hade modules issue laterly with the table keep changing all across the scripts i wish i knew this earlier that way i haven’t used too much table.clone(moduleitem) but anyways its pretty handy so i don’t know if im angry or happy about this.
Summery:
i guess modules have thier own states where if its cloned from a script without a actor it will be assigned as the global context(client/server) state but somehow actors make that possible to change the state of the modules and make a whole new state who is the default module so if the global state changes im assuming only global will take the hit the actors or anyother states that are out there will be default or in thier own bubble.