Is it a good idea to use global variables to update client inputs?

User input functions take up a lot of space and are slightly distracting, so would it be a good idea to have one LocalScript update the player’s inputs by using _G, then have another LocalScript (more relevant to the stuff I’m coding) access those inputs anytime they want?

I am aware that it is generally a bad idea to use global variables, but if they’re for something as ubiquitous as user input, then is it acceptable?

This is what the input updating LocalScript would look like:

local uis = game:GetService("UserInputService")
local rs = game:GetService("RunService")

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local char = workspace:WaitForChild(player.Name)
local hum = char:WaitForChild("Humanoid")

-- Global variables
_G.mouse1Down = false
_G.mouse2Down = false
_G.pressingF = false

uis.InputBegan:Connect(function(input, guiActive)
	if guiActive then return end
	local keycode = input.KeyCode
	if input.UserInputType == Enum.UserInputType.Keyboard then
		if keycode == Enum.KeyCode.F then
			_G.pressingF = true
		end
	elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
		_G.mouse1Down = true
	elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
		_G.mouse2Down = true
	end
end)

uis.InputEnded:Connect(function(input, guiActive)
	if guiActive then return end
	local keycode = input.KeyCode
	
	if input.UserInputType == Enum.UserInputType.Keyboard then
		if keycode == Enum.KeyCode.F then
			_G.pressingF = false
		end
	elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
		_G.mouse1Down = false
	elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
		_G.mouse2Down = false
	end
end)
2 Likes

On second thought, this is a bad idea. If I had a function in a different localscript fire whenever an input is being pressed by relying on a global variable being true, then it would repeatedly fire unless I created a debounce variable for each global input variable, which would be a hassle.

For future reference, if your global state is only ever written to once or from one place and then read from one or more different places later, it’s probably fine, but you could still look if there’s a better way of doing it.

2 Likes

_G has it’s downfalls and security problems.
I recommend to use ModuleScripts in the future.

1 Like

This is very vague, and the 2nd point is not true since _G is about as secure as modules.

3 Likes

This is simply not true, the only ‘downfall’ of _G I can think of is that it might get messier than an module script system but that depends on how you use it. And as far as security goes _G is as secure as modulescripts.

Back to the main problem, I see nothing wrong with this. Maybe instaid of setting it to true you can make it so it fires a function so you won’t need a loop to check if something is true or not.

--example of what I mean
_G.mouse1DownFuncs = {}

--input script
uis.InputBegan:Connect(function(input, guiActive)
	if guiActive then return end
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		for k,v in pairs(_G.mouse1DownFuncs) do --loop through the functions bound to this event
			v() --call them
		end
	end
end

--another random script
table.insert(_G.mouse1DownFuncs,function()
	print("Hello, World!")
end)
table.insert(_G.mouse1DownFuncs,function()
	print("Hey I also fire!")
end)

You now can bind them to the mouse1Down event without having a loop, this is what I would do, you don’t need to change it your current code is fine as it is but I would prefer this over having booleans.

What he means by this is that _G can be hijacked quite easily by exploits and might allow them to access environments they shouldn’t have access to via setmetatable __index and getfenv(2)

It is generally never recommend to use _G and rather close everything down to private variables. I would recommend using modulescripts then adding function hooks for which modulescripts are needing the events. This also increases code optimization since there’s no loop and it’s handled asynchronously.

2 Likes

This is exactly what I mean! Thanks for explaining.

Literally the same is possible with modules at no extra effort. This isn’t a valid “downfall”.

4 Likes

I do agree with it being possible to do it with modules doesn’t make it a downfall but it does make it a viable entry point for exploiters. With modulescripts you are able to lock down the environment given from the return and make it as hard as possible for them to access it. Modulescripts security is also being improved with Roblox as time goes on unlike _G. (also just kind of a weird thing if I remember right is that returning true or false somehow allows someone to get the environment)

But this isn’t true. Just because the return value of a module is cached doesn’t mean anything; any functions it returns can have their environment and upvalues accessed, and any table it returns can be edited. There’s also no exploit related “security” that is being improved on for modules. What are you referring to?

Ah sorry, I’m thinking this the wrong way, yes you are correct with it all. I wasn’t remembering that exploiters have access to all memory, environments and stuff like that. I was thinking of it from a pure lua trying to break into a game like a script builder.