How would I protect _G variables from exploiters?

_G is a table that works through all scripts.

e.g:
Script 1:

_G.Test = "Hello"

Script 2:

print(_G.Test) -- Prints Hello

Is there any way to stop an exploiter from going…

_G.Score = 9999999

Are _G values replicated? (Meaning does a change from a local script apply globally?)

Thanks,
Winky.

1 Like

Some exploits have a separate _G table, although you should not be using _G anyways as there is no reason to. You should instead restructure your code to be more modular in nature.

1 Like

As for your question:
Are _G values replicated? (Meaning does a change from a local script apply globally?)

They are global (I am fairly certain. correct me if I am wrong)

I don’t think there is any way to stop exploiters from accessing the table but I don’t think it a good idea to have scores/cash or anything important in it.

Again, correct me if I’m wrong.

1 Like

This is correct. At least not anything important on the client. OP should fix their implementation.

Do _G variables replicate? If a local script contained _G.Test = "Hello" would a global script containing print(_G.Test) print “Hello”?

No, that would be terrible lol

There is a separate everything on every machine.

So it is not replicated?

See:

1 Like

It is shared between Local Scripts but not Global Scripts. (I think lol)

1 Like

_G is not replicated, on client _G shares between all local scripts and on the server it’s shared between server scripts, it works similar to module scripts except that you don’t have to require it.

It is generally not recommended to use _G, not due safety issues (it’s perfectly fine to use, it’s secure) but because you can easily make mistakes in it.

It’s fine to have things like cash, level, player stats, etc in _G but the issue is that you can easily overwrite tables by accident unlike in modules.

When using modules you have all your variables sorted, you can see which variables are inside that module and it’s more easy to refer to one because you know it’s there/exists and if you want to use the same name for a variable for example, you can re-use that same name in a secondary module.

When using _G, all of your variables and tables are all clumped together and unsorted pretty much, this is not a big issue but it can lead to confusion and accidental overwriting/messing up.

_G is not bad and it works almost the same as module scripts minus having to require() it.
It’s not slow, it does not have any security issues for as far as I know or whatsoever.

A lot of scripters don’t like _G and will likely discourage you to use it, but really the only problem with it is that variables are just clumped and put together unsorted so you may find yourself accidentally overwriting something you did not mean to, etc but this can be a little avoided if you can find yourself a way to keep track of which variables are used for what, etc, although this will be challenging, you’d have to find a way so you can see all variables in _G, _G does not (unlike modules) show what variables are inside so you sometimes end up guessing what variable you have to refer to or memorize the names, you’ll may find yourself looking through each script to see which script uses/made what variable, etc.

Tl;dr: Using _G is almost the same as using module scripts, it’s not bad, not slow, does not have security issues and it’s not replicated across server-client boundaries, most scripters just do not recommend using it because it’s clumped together and unsorted and you end up looking through each script to see which one made what variable, otherwise you may accidentally overwrite a already existing variable.

8 Likes

This is super helpful. Thank you so much!

Couldn’t you organize variables in _G by doing _G.[plr.UserId].Data = {1,1,1}?

Correct me if I am wrong, but doesn’t that defeat the issue of having organization withing _G?

1 Like

Immutable state with _G would still not be good but is only slightly better than mutable global state. I doubt someone’s cash and level is immutable so this is incorrect.

No they aren’t the same at all. Not sure where you got this from.

2 Likes

I don’t think I said that _G and module scripts are exactly the same, they just work very similar, they both hold tables that can be globally accessed and do not replicate over client/server boundary.

About storing player stats, you can use it for player stats just fine, it’s just not recommended if you use huge player stats with inventories and such for example.

It’s fine to use _G, but not recommended for complex or large tables and such.

1 Like

If modules are “very similar” to _G you might as well use modules. Write more modular code instead.

It is not fine to use _G, I can’t think of a use case where you would want to pollute the global environment.

1 Like

How would you go about using a module similar to the usage of _G?

As in… module.Thing = 1 would not transfer between scripts.

I also stated that it’s recommended to use modules, modular systems are more readable and sorted.

But if people really want to use _G for something, we should not entirely stop them from doing so.

Sure using _G can be a hassle when trying to keep things organized and such, but I’ve also seen a lot of scripters make up random reasons as to why not to use _G that barely made sense…

So again, modules are recommended, but if you want to use _G for small and simple global variables and such, it’s fine to do so, if you stumble upon a problem, scripting support exists for reasons.

1 Like

It will transfer between scripts if multiple scripts require() the same module.

You would just require the module when you need it. That is a good thing. By using _G it is basically everywhere. When using modules your “global variables” are only there when you need them.

we should because it introduces bad habits when code should be modular by nature

1 Like

So this will work?

Module:

return{"Test"}

Script 1:

module.Table[1] = "Hello"

Script 2:

print(module.Table[1]) -- Prints "Hello"

require calls are memoized and it always returns the same reference.

If your module returns a table and script 1 and script 2 requires it as well they both have reference to the same table.

Might I also add:

By using _G you have to do some awful hack like

repeat
    wait()
until _G.your_variable ~= nil

to guarantee that the variable exists just in case the scripts that use it load before the scripts that actually declare it do.

Which is one hell of a disadvantage. Modules don’t ever have this issue.

1 Like