Intro to ModuleScripts

This tutorial is directed to people who have little-to-no knowledge on how modules work. If you’re already experienced in this field this tutorial probably won’t be much use.


ModuleScripts are an incredibly useful object. You’ve probably seen them being used in things like free models - they’re a backbone of many larger games like Phantom Forces or Jailbreak.

In short, ModuleScripts hold information that can be used and accessed by other scripts - mainly to prevent code repetition. You might know what a function is:

local function doBruh(parameter)
    print(parameter)
end)

But this function can only be used on that script. Or, let’s say you have some information about the player:

local playerStats = {
    Money = 5;
}

and you want to, say, check if you player has 5 money in five different scripts.

To do this you’d use a module script. You would run a function in a module script, pass the table as a parameter and do something to it. Then you’d return the table back to the client.

See how easy that is? Instead of having five different functions in five different scripts, you only need one.


How do module scripts work?

local module = {} -- This is the module table. 
-- You can use it if you have **more than one item inside your module**.
-- If you only have one then you can just ```return``` that item.
-- You can rename it to whatever you'd like, just make sure to return 
-- it at the end.

-- You can store data in a module. 
module.Number = 5;

module.MyTable = {
    Bruh = 5;
    NotBruh = -5;
};

-- Here's an example of a function embedded in a module.
function module.Bruh(param)
    if param = module.Number then
        return module.Number -- Returning a variable is how a module 
        -- sends info back to the client. You can return pretty much
        -- anything.
    end
end)

return module -- If you leave this bit out the whole script won't work.

Single item module: (requested by @colbert2677)

local bruh = 5

return function(param) -- You still need to return something back (this applies to all modulescripts), 
-- only we're returning one object instead of a table (tables hold many
-- objects).
    print(bruh)
end)

--This thing still works the same as any other module. 
-- Just remember that instead of requiring the module and using 
-- module.Function(), simply just require the module and do 
-- module().

Single item modules can return anything. You don’t need to use it for just functions:

local myTable = {
    points = 5
}

-- To access this, again, you'd require it, but instead of using 
-- module.myTable, you'd simply just use module.

For example, if I were to use this specific module in a LocalScript:

local module = game.ReplicatedStorage.ModuleScript

print(module) -- This would just print the table
-- You can now use module just like any other table

module["points"] = 6

That might seem a bit advanced but honestly it’s pretty easy. Think of storing stuff in a module just like storing things in a regular script but everything can access it (if it’s in the right place, like ReplicatedStorage.)


How do I access it?

Now that you have your module, you need to access it. You can do this by using the require() function.

This bit is important. If you use require from the client, you can’t access modules in ServerStorage and such. Those can only be used by the server. Same goes for if you’re requiring on the server, you won’t be able to access modules in things like PlayerGui.

If it’s in things like ReplicatedStorage, then yeah, you can access it.

If you’re requiring from the client you can also use game.Players.LocalPlayer in your module and mess with the client’s things.

Getting a module is as simple as using require(TheModulesDirectory). Replace TheModulesDirectory with your module’s directory. You can also require using an asset ID, although I don’t recommend this.


Use cases of a module

In my game Operation: Strife this module is used to shake the camera. It is only used by the client, so I can use things like game.Players.LocalPlayer.

local module = {}

runService = game:GetService("RunService");

return function initCameraShake(intensity,shakeType) -- the main 
-- function that shakes the camera. not used by the client
	local plr = game.Players.LocalPlayer
	local char = plr.Character or plr.CharacterAdded:Wait()
	local hum = char:WaitForChild("Humanoid")
	
	if shakeType == "walk" then
		local now = tick()

		local bobbleX = math.cos(now * 6) / 7
		local bobbleY = math.cos(math.sin(now * 3)) / 4

		local bobble = Vector3.new(bobbleX, bobbleY , 0) * intensity

		hum.CameraOffset = hum.CameraOffset:Lerp(bobble, .25)
	end
end

Because I have loads of scripts which need to shake the camera I can just plop this script in ReplicatedStorage and require+use it whenever I need it. See how this saves time?


That’s pretty much all I got. If you have any questions just post it in the comments and I’ll read and respond to it.

12 Likes

For the last example, do you have other table members? I feel like in that case you could just return the function and name the module after the function. In this vein you could avoid using a table and reading from an index when the table has no use other than to hold that single function at any time.

local RunService = game:GetService("RunService")

return function(intensity, shakeType)
    -- code
end

No, I don’t and I just used the table cause it’s the default modulescript layout. I don’t feel like making it more complex since it does what it needs to do.

That’s not more complex though? :stuck_out_tongue:

ModuleScripts are able to return any valid datatype, including nil. If your table isn’t actually doing anything then it’d be more prudent to not return a table to begin with and return the function directly instead. For a tutorial titled “Intro to ModuleScripts”, this should be something you mention.

Using the boilerplate is fine but my advice is that if you’re making a primer on ModuleScripts then you need to also introduce different ways to use them. Modules that only hold a single function should likewise just return that function directly. If you have a table then you’re carrying all that unneeded baggage to create it. It’s negligible but still unnecessary (double memory allocations, blank table construction and reallocation from size 0 → 1, future uses of it need to access the hash part of the table for a singular function, so on).

You can still make improvements even if something “does what it needs to do”. Complacency is not a good thing to be comfortable with. Look for ways to improve your code. :slight_smile:

Here’s a brief rundown I gave of ModuleScripts in a post some time back:

1 Like

Alright, I changed it so it now encompasses single-item modules. I haven’t really used them that often (I usually just return tables because most of the time my modules are jampacked with stuff) so I hope the code is correct. It should be, but a read over from you would be nice, thank you