Are module scripts safer than _G?

Hello!

So, I was wondering if Module scripts are safer than _G global table. Can clients change _G values? Is it bad to use _G?

What are you attempting to achieve?
I’m trying to learn about this.

What is the issue?
There aren’t issues

What solutions have you tried so far?
I tried to find info. about this but I didn’t find anything.

Any help is appreciated! :smile:

From what I could find,

Thanks for your reply!

I want to know if exploiters can change _G variables. That post didn’t explain that. I think they can’t, right? Because exploiters can only change client-side stuff and _G variables are server-side stuff.

You are right, though, taking into consideration that you can still change them on the client side, I’d say module scripts are safer, since you can’t change them, even when you’re on the client side.

_G is a variable global to the machine it’s on, whether client or server (with some caveats around script permissions which are not relevant). Neither is safer, both can be changed on whichever machine they’re on. Using module scripts is better for organization as data dependencies are made obvious alongside the order in which things run.

1 Like

Thank you :smiley: Just one more question, so that’s the only module scripts’ advantage? Aren’t there more advantages? Sorry, I’m trying to learn :smile:

If you have a modulescript named mymodule in workspace:

local tab = {}
tab.number = 3
return tab

If you require() this modulescript from two scripts, each one will receive the same return object, or in this case, the table named “tab”. This means any values stored within the table, such as “number” will be shared. So if in Script 1 I do:

Script 1:

tab = require(game.workspace.mymodule)
tab.number = 100

Now if in script 2 I do:

tab = require(game.workspace.mymodule)
print(tab.number) -- prints 100

This is because once the module has been required the first time, it runs the code in the module which creates tab, and the value 3 inside tab. When you require the same module a second time, the engine detects that this module has already been run before, so it doesn’t run the code again (or else tab.number would get reset to 3), but instead gives Script 2 the same return object (tab), which also happens to be the one affected by Script 1 changing tab.number to 100.

If you have script 3, script 4, etc all requiring this same module, they all get access to the same tab, so changing tab.number using any of these scripts would change the number for all these scripts.

Why do people say its “unsafe” to use _G? _G is similar to tab, except that all scripts automatically have access to this same table, even without requiring it. Let’s say I have a game with a “gold” coins, and also “gold” ore. If I have 2 scripts, one increasing the amount of “gold” coins on the server, and another stating how much “gold” is mined on the server

--Gold Coin Script
_G.gold = 0
while true do
   wait(1)
   _G.gold = _G.gold + 1000
end

--Gold ore script
_G.gold = 5

Oh no! Both my gold ore and gold coins are stored in the same place: _G.gold
If I have some other script that prints the number of gold ores mined, after 10 seconds it will print 10,000, not 5!
It’s pretty obvious here what went wrong, but for larger projects with 100s of scripts you could easily forget whether or not some spot in the _G table is already being used by another script.

With module scripts, if I really wanted to use this “gold” key, I could however many times I want, as long as each stored in a different table.

So if I have 3 scripts that do something with the number of gold ores, I would make a module like:

local GoldOreModule = {}
GoldOreModule.gold = 5
return GoldOreModule

Then all three of the scripts that require() this module can access the same table and same gold ore value.

Then in some different 3 scripts that mess with gold coins, you’d require this module:

local GoldCoinsModule = {}
GoldCoinsModule.gold = 100000
return GoldCoinsModule

These two gold values shouldn’t interfere, since they exist in two different tables, returned by two different modules. However I can still freely share some gold value across multiple scripts, as long as they require() the same module.

A note about client/server, for both the _G table and any tables returned by a modulescript, these objects do not cross the client server boundary. That means that in my original example with mymodule in workspace, if I required it with a localscript and changed tab.number to 1000, then required it with a server script, and did print(tab.number) on the server script, it would print 3. Tables can only be shared between different localscripts, or between different scripts, but not between scripts and localscripts and vice versa. There is a different _G table on every client from the _G table on the server.

Exploiters would only be able to change entries in the _G table for their own client, not other clients, and also not the server because all of these have individual _G tables.

1 Like

Wow, I didn’t expect such a explanation! Thank you so much now I understand! I thought that _G was unsafe and a bad practice. Again, thanks for the explanation you answered all of my questions! :smiley: