Introduction
So I'm making a game that's heavily reliant on modules
. It has 5 core libraries
(table, string, math, utility, and data).
Problem:
Each one of these modules
is going to be required
by several scripts, each of which will vary from client-sided
ones to server-sided
. I typically store my modules in the script that will use them, but in this case I'm going to have multiple use them, and on different sides of the network.
The first thing that came to my mind was ReplicatedStorage
service, however the code I'd have to write at the beginning of each script to import the libraries
would become very tedious. Here's what it'd look like:
local RepStorage = game:GetService("ReplicatedStorage") local Modules = RepStorage:WaitForChild("ModuleFolder") local math = require(Modules:WaitForChild"MathLibrary") local table = require(Modules:WaitForChild"TableLibrary") local string = require(Modules:WaitForChild"StringLibrary") local utility = require(Modules:WaitForChild"UtilityLibrary") local data = require(Modules:WaitForChild"DataLibrary")
And it'd be even longer the more modules
I added. Is there a better way to store
and/or retrieve
these modules?
If anyone has any better ideas, I'd really appreciate it. Thanks!
Two ideas come to mind, but there are probably other options that might fit better.
It ultimately comes down to loading one module which has loaded the others:
-- A ModuleScript, the parent of all of the other modules: wait() local t = {} for _, child in pairs(script:GetChildren()) do t[child.Name] = require(child) end return t -- (if you wanted to change naming convention automatically -- you could do something like -- t[child.Name:gsub("[Ll]ibrary", ""):lower()] = require(child) -- etc. Otherwise, you could just name them how you want -- them to be used (`utility` instead of `UtilityLibrary`)
-- A Script needing access to the modules local M = require(game.ServerStorage:WaitForChild("Modules")) M.utility.blah()
This is nice and clear and clean, but it's not great because of the M.
. You could just use local utility = M.utility
, etc, but then you'll have a statement per module, which is what you're trying to avoid.
Lua does have a 'solution' to this problem. Using getfenv
and setfenv
, you can dynamically create/change global variables.
I personally do not like allowing this much "magic". The main practical argument against it is that Script Analysis (and any other static-analysis tools you happen to have) will complain everywhere about where you use the modules. But I digress:
-- Loading module: return function() wait() for _, child in pairs(script:GetChildren()) do local e = getfenv(0) e[child.Name] = require(child) end end
Then you can simply use this as
-- A Script needing access to the modules local M = require(game.ServerStorage:WaitForChild("Modules")) utility.blah()
However, you'll get a pesky blue underline under utility
since it isn't clear where it is defined.