Why Module Scripts?

This is less of a problem then a persevere for efficiency and learning further knowledge. I have been a coder for about a year now and I always was perplexed about Module Scripts I know how they worked but I never could understand why they are so common for developers to use.

First, I use Remote Events to fire universal code. And if I didn’t I’d use _G. So why is it so necessary to have for a good game?!

Mabye it’s my definition of a Module Script. Isn’t a Module Script a script that can be referenced from any other script that’s in the same version of the game(Server/Client)

Just give me a example of where a Module Script is useful.

And tell me if this post was spam so I don’t post more like it.

4 Likes

You can’t be sure if a function is present in _G.
As for an example for a good use of a ModuleScript, I use it in my weapons framework. I have a module for every effect of the weapon, from the bullet trail, to the muzzle gas, to explosive ammo. Depending on the purpose of the module, it will be run server or clientside. Sometimes both. Here’s an example of one:

ExplosiveAmmo

  • Client: Show visual explosion with no blast pressure.
  • Server: Apply explosion with no visuals and just blast pressure.

This code is all require()d and read from a single module in ReplicatedStorage.

tl;dr: They’re great for sharing code between server and client.

3 Likes

RemoteEvents and ModuleScripts do COMPLETELY different jobs. They’re not interchangable.

As for _G, _G quickly becomes unorganized, along with never being sure if the functions you want to call are in it when you want them.

ModuleScripts have neither of these problems. They’re as organized as you are and will always have what you need.

ModuleScripts encourage the Unix way (one thing for every task, in Roblox’s case, one script for every task). For example, say you have a bunch of guns that, aside from numbers, function the exact same. Without ModuleScripts, you’d have one huge table in _G. With ModuleScripts, you can include a ModuleScript for every weapon you have. Example: In the same folder you store a shotgun, including its models and sounds, you can include a ModuleScript with a table of all the information. You COULD use value objects for this, but ModuleScripts are cleaner and more extendable.

Outside of the data storage use case, developers often use them to house libraries. For example, if you have a library of code to handle experience (max experience for one level, get level from experience, etc) you can house all that code in one ModuleScript.

ModuleScripts are easier to do OOP with than _G because, again, you can always be sure that everything the class needs (itself, its superclass, and everything after) exist.

7 Likes

But you still need Scripts in those guns to fire the Module rather I would just do a for i,gun in ipairs loop. Plus I still see no reason why remote Events/Functions can’t do the same thing?

Remote events/functions are methods for sending data accross the client server boundry. If you mean events and callbacks from said remote events and functions, that is an entirely viable use. The purpose of ModuleScripts is to have your code in a separate object for whatever reason. If you prefer keeping all your functions in one server and one client script, that’s you.

2 Likes

Ideally you wouldn’t have scripts in any of the guns, just one catch-all “gun handler” (still assuming all guns function exactly the same apart from numbers).

1 Like

I put a folder in Workspace named RemoteEventFolder and I have a code that received those remote events in serverscriptstorage. I fire those events with my clients code. I guess it would be kinda useful to be able to fire code in the same game vierson(Server/Client) as where you fire it from but there has to be more to it then that.

ModuleScripts play the role of modules/headers in just about every other language. The C++ .hpp, C .h, Python .whateveritscalledmodules, etc.
It’s for keeping code organized and keeping each source purposeful.

You can make a game without them, but it won’t be “generally” organized.

2 Likes

Creating functions to be used similarly to modules by using _G will require you to have two different versions of the code, one to be used on the client and one to be used on the server. If you’re using Remote Events/Functions to achieve a mock-module effect, you’ll just be causing latency issues by having so much unneeded client-server communication.

Example:

I have a script on the server, inside of ServerScriptService that has the following code;

_G["Hello"] = function()
	print("Hello world!");
end;

If I try to call _G.Hello() from a normal server script, it will print “Hello world!” just fine (assuming that the function actually exists in the moment that I attempt to call it.)

However, if I try to call _G.Hello() from a client script, it won’t work because I’ve only created the function inside the global server, not the client. That means that you’ll have to be updating two different versions of the same script!

As previously mentioned, sure, you could use a remote to communicate with the server and use some of these functions (if they’re intended to be shared), but that’s just asking for latency issues. And, if you’re executing the code on the server rather than straight up returning the functions to the client, then the server will be unable to to use these functions to change client-sided objects.

With a ModuleScript, you can just plop it into ReplicatedStorage and it will be capable of being used inside of client AND server scripts without having to manage duplicate code.

This is just one (albeit important) reason. Read the posts above mine for various others.

2 Likes

SO if I had a bunch of NPC AIs I could use a Module Script to easily control all of them with one code?

For something like that, I’d use CollectionService and tag the AI’s, then you can manage them all from one script more easily without having to deal with global tables OR modules, although modules would still be nice to implement for certain things in this scenario.

After tagging the models, you can place a script inside of ServerScriptService with the code;

local CollectionService = game:GetService("CollectionService");

function hookup(ai)
	-- write code here to be applied to the ai
end;

CollectionService:GetInstanceRemovedSignal("AI"):Connect(function(obj)
	-- one of the AI was removed from the game, run code here if you need to handle that
end);

CollectionService:GetInstanceAddedSignal("AI"):Connect(function(obj)
	-- a new object was added to the game with the 'ai' tag, run code here to handle it
	hookup(obj);
end);


-- get currently existing objects with the AI tag and apply the hookup function to them
for i,v in ipairs(CollectionService:GetTagged("AI")) do 
	hookup(v);
end;

You could even use this method to tag all of your AI’s with a default AI code, and then add more tags to handle different situations, such as “Archer” or “Assassin”.

Edit: I know that I can just do “:Connect(hookup)” but I left it as an open function as an example to show where the code would be added.

6 Likes

This is similar to asking “Why Functions?”.

We use functions to save space, organize our code, etc. I’m going to assume we agree that functions are incredibly useful.

Now lets take those reasons and just expand on them. Instead of having one extremely large code, you could have several scripts.

But what if those several scripts needed the same function? Instead of having the same function in every single script, you can just make a single module script.

Sure, you have global functions instead, but modules are more organized, or at least I find them.

But for remotes, they definitely can’t replace your modules. You might want the module on the client side, would you call a remote event just for it to call the client back?

3 Likes

If you ever work with someone else on code, it’s best to organize your code into modules that serve a specialized function. While it takes more effort, it makes your code much less esoteric.

I’ve made a semi-popular building plugin that used no modules (it was developed before they were even a thing), and it had thousands of lines. It worked perfectly for my purposes, and it took a lot less time to build than it would have if I had used modules (I tried making a module-based plugin once, but quickly lost all motivation, though I’ve always been absorbed in other projects anyways). With long, single scripts, you can make your code a lot more esoteric and ad-hoc. However, whenever I try making edits to that plugin now, I forget everything about its organization, and have to jump around between functions to figure out what sections of code are responsible for what.

That’s fine if you’re working by yourself and don’t really plan on expanding the codebase any further than what it’s already been expanded to, but if you ever want to work with other people (especially since, on team create, only one person can edit a script at a time), modules let other people (such as your future self) figure out what the hell is going on with your code by the mere fact that everything is organized much more robustly.

When you have modules laid out in a folder, you can pinpoint exactly what part of your code you need to make changes to, rather than having to dig through thousands of lines in functions. It’s also a lot less performance taxing, since shared functions can be grouped together in one big thread (which is what you want in your code).

There are some other things. For example, it forces a server/client distinction (whereas if you have two things of the same name in the _G table, one will override the other in Play Solo, which fundamentally breaks solo testing). Also, one cool thing about modules, is that they’re only stored in memory once on a server or a client. Therefore, they can be used similarly to a localized _G table, that can be interfaced by all of the things that need them. You can read and write to a required module, and it will affect all other instances on the same server/client that accesses that module. Play Solo cuts the time it takes to launch a test in half, so using modules instead of _G for things like that helps a lot.

3 Likes

Somebody brought up _G.

silent reeeee

13 Likes

I think the reason I never use modules is because my game is not as complex as more experienced coder’s games. I just finished making my 3rd. I am a Noob here.

Holy Cheese why have I never heard of Tags?!

Wait! Is a Module Script like a instance with multiple functions Events and properties/variables. That is cool

No but you can put all that inside the actual script.

1 Like

That’s what I mean so it’s a custom instance. That’s so cool

The instance itself does not inherit the require()s returning data, or the instance would essentially upon being parented somewhere where LuaSourceContainers run.