Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
4

Best way to store modules?

Asked by
LuaQuest 450 Moderation Voter
8 years ago

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!

0
Well, to speed things up, you could use things like global variables/functions, so you don't have to define the modules for every script :P TheDeadlyPanther 2460 — 8y
0
This is great because I literally have a module just built so that I can require and call it and all modules can be accessed directly. LegitimatlyMe 519 — 8y

1 answer

Log in to vote
4
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
8 years ago

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.

1
Doesn't the environment editing in the latter example affect only the ModuleScript's environment, not the calling Script's? adark 5487 — 8y
1
He's doing getfenv(0), which gets the environment of the thread. Normally, if ScriptA loads M and does M(), it'll edit the script's environment. Also, mistake in the last codeblock: M has to be called before being to do utility.blah() einsteinK 145 — 7y
Ad

Answer this question