I’m not really familiar with exploiters manipulating data, that information is what I gathered from the article itself, since many people mentioned it in the replies.
I might seem like an idiot but which article?
Oh okay
But I see people below saying that _G is not replicated across the server-client, if you assign a global variable in server and client can’t access
_G isn’t shared across the network so I don’t really see how that could be an issue. Although I kind of see what you are saying because any client can change the _G data on their device, so you just have to be careful using it on the client or only store data that affects maybe something like client settings.
Using it on the server is completely safe though; the only issue being different load times with scripts (also an issue on client).
Actually afaik, unless an exploiter can hook into the client VM (not saying this is completely impossible), _G is pretty secure.
Its 100% secure on the server.
However, you should not be using _G due to the issues of race conditions, Roblox loading order when it comes to scripts is undefined. Since _G exists on the VM stack the same way a module would, it would be much better to use a module as you can add extra functionality into the module to control when it loads
_G.Hello = "Hello World!"
print(_G.Hello) --> nil, oh no this script ran first
if you have implicit control over script loading order by encapsulating the scripts in ModuleScripts with a single loader script, since the loading order can be guaranteed, it’s safe to use _G in this case
local scripts = {
script._GVariableSetter,
script._GVariableReader
}
Another place where it’s safe to use _G is inside event handlers, since they’ll never run straight away.
Race conditions wouldn’t be an issue if you don’t plan on modifying the data after first assignment.
Dont understand what you mean here, the OP wants to use _G to hold functions and call them, which means you need to read the table.
_G.TimesSaidHello = 0
function _G:SayHello()
self.TimesSaidHello += 1
print("Hello World")
end
_G:SayHello() --> attempt to call nil value
This is only an issue if the declaration happens in the same resumption cycle as it’s called in.
This code is safe, since we guarantee that the value is set beforehand
task.wait() --makes the thread wait a resumption cycle
_G:SayHello() --> Hello World
So this means I have to task.wait if I don’t expect _G script to be loaded right?
_G.Scripts = {
Yes = function()
print("yes")
end
}
--another script
task.wait()
_G.Scripts.Yes()
If you’re setting the value of _G within a script with no yields (waits), you can safely task.wait
in any other scripts to ensure that the data is set.
If you want to add an extra level of safety, you can wrap access to _G in a while loop
local scripts = _G.Scripts
while not scripts then
task.wait()
scripts = _G.Scripts
end
From what I know, nothing is really wrong with using it, but its good practice to use ModuleScripts. People don’t use _G
for a reason, not sure what that is, but it just makes things look ugly.
Roblox has built in globals for convenience purposes… IT ISN’T UGLY
That last part was my opinion, in my opinion _G
looks ugly, probably should’ve clarified that first.
please read:
TLDR: you cant ensure what script is going to run first because Luau is single-threaded so the state of _G cant be guaranteed.
EDIT: this is a wrong reply, @e4r54yt64rtq26
From how it was explained to me, race conditions is when data is being changed from two or more different pieces of code at the same time. How is this related to reading it?
The reason im doing a while wait is because the value may already be there and it’d be pointless to wait in that case
repeat until
will always run once.
Nvm
Also @e4r54yt64rtq26 , I don’t think it’s ugly, I mean require is longer than _G so if your gonna say it’s ugly than modulescripts would also be ugly.
Please, for your own sanity, do not do this.
You’re only setting yourself up for organizational hell down the line. You’re going to have dozens upon dozens of functions all listed under _G with nothing to organize groups of similar functions, which can cause a truckload of problems with navigating your code and debugging.
And you’re doing this all for what? Avoiding spending 5-10 seconds typing out a single line of code? Having to require modulescripts in every script that you use them is entirely beneficial for you, because it lets you more clearly keep track of what modules you’re using and where.
You can read up on the Single Responsibility Principle of software design to get a better idea of why to avoid throwing all your functionality into one place.
I mean you could nest tables in it like:
_G.SomeFunctions = {...}
_G.OtherFunctions = {...}
What point is there for that still? If you’re going through the effort to do that then you may as well create separate modulescripts for that.
Your example already creates modules via the nested tables, only instead of storing those modules in their own scripts, you store them all in _G. Again, to what benefit?