How to replicate a ModuleScript?

In this specific situation I have a ModuleScript storing a bunch of information, however as ModuleScripts don’t replicate across all scripts requiring them it becomes kind of impractical when I for instance want to set a value in the ModuleScript outside it and have it replicate everywhere.

--modulescript

local module = {}
module.test = "Hello"
return module
--script

local module = require(script.Parent)
module.test2 = "Hi"
print(module.test2) -- "Hi"
--script 2 (which I want the change to replicate to)

local module = require(script.Parent)
print(module.test2) -- nil (not replicating the change)

How would I go about doing this?

Hmm, first ideal that comes to mind looking to avoid a datastore for this would be:
A folder with the values setup to be changed and read by the ModuleScript.
The kind you place in manually. # StringValue, BoolValue, # NumberValue.
Then you could read the .Value data or change it from the ModuleScript.

This is how others seem to do it. See this all the time.

Are you using a server script or a local script?

ModuleScript values do not replicate to client/server. Each client/server gets their own copy, so if you change the value “test” on the server, it will not change on the client, you must use a remote event to detect the change.

That is not at all what the issue is. I want the changes to replicate on all server scripts, my issue doesn’t involve crossing the client-server boundary.

I don’t know why it isn’t working for you then. I just tested the same format and it worked perfectly fine for me.

1 Like

This isn’t something I’d like to do unless absolutely necessary as:

  1. I’m trying to pursue an object-oriented approach,
  2. having to read instance values is, from what I’m aware, slow for the Luau VM,
  3. the use-case is heavily focused on optimization.

They work fine … Take a look at some of the more complicated free models. You will see folders like this in many of them under many names used for many things. They are like mini datastores with none of the cost. Roblox themselves do this all the time in their models.

Reading and writing values using instances is generally bad practice, unreliable, and slower. All of those I’d ideally like to avoid seeing as my use-case is a cryptographic module.

There is realistically no reason to use a value if you’re going to use a modulescript for the same level boundary (ex: same server side scripts)

values replicate to the clients, which is not what u want.

1 Like

Sometimes works by using the __newindex metamethod like so. It doesn’t work all the time and is a bit wonky, hence I’m not marking it as a solution in case someone has a reliable way to fix the issue:

metatable.__newindex = function(table, key, value)
    rawset(table,key,value)
end

I’m pretty sure that changes made in a module do replicate across all scripts requiring them on the same side of the client-server boundary. It looks like your method at the top was setting it from the script requiring the module. It should replicate, as long as the value is changed from within the module.

local module = {}
module.__index = module
module.someValue = nil

function module:ChangeValue(newValue)
    self.someValue = newValue
end

return module

This has worked for me in the past. Hope it helps.

ModuleScripts should only run once per Luau VM and its return value should be cached. The only reason why your code example shouldn’t work properly (as in script 2 being able to read module.test2) is when the two scripts are in different Actors.
(Or if script 2 runs before script 1 and so prints nil because script 1 hasn’t run yet, but I assume that’s only an issue with this tiny repro you’ve provided)

The script in the OP working as intended:
x

1 Like

What’s an Actor? I repro’d the example using the same set-up (Modulescript > Script, Script) except in ServerScriptService. It gave me the same output as in the screenshots, so didn’t work in Studio or the client.
I also ideally want the changes to sync no matter the loading time, so if I change/set a variable (in one Script’s environment) in the ModuleScript, I want it to sync to all other Scripts that have require’d the module, as well as any scripts that require the module in the future

Okay, I figured out the culprit.

My module is structured in this way:

--!strict
local Towers = {}
Towers.__index = Towers
function Towers.new()
-- loader function
    local self = setmetatable({}, Towers)

    self:init()
    return self
function Towers:init()
-- init function
end

return Towers

, where I was requiring it with the .new() function. I re-tried just requiring it by itself without calling that function, where it worked, but the issue is I want to modify some variables which are first pre-loaded with .new(), which the synced modifying doesn’t work with (as it returns self). How would I go about doing that?

Here’s an example of what I want to do:

--!strict
local Towers = {}
Towers.__index = Towers
function Towers.new()
-- loader function
    local self = setmetatable({}, Towers)

    self:init()
    return self
function Towers:init()
Towers.test = "Hello"
end

return Towers
--script
local Towers = require(script.Parent)
print(Towers) -- {}, as the __index returns the unmodified self table
print(Towers.test) -- "Hello", works, but only if I query it directly

I want the above snippet to somehow get the table environment containing the variable, but obviously calling it directly by .new() and getting it from there won’t sync the changes, nor will it show me the variable if I print the table due to the __index metamethod.