Efficiently detecting a held-down key

Background Information (skippable):

What I have is a Tool that welds an invisible shield to the character’s arm via a Script. The shield has two BoolValues: Equipped and Blocking. Equipped will be toggled (as well as changing the shield’s visibility) when the tool is activated.

What I want to do is make it so that if the player holds down E, Blocking is set to true and they play a blocking animation.

My original idea for this was to have a LocalScript check when the player is pressing/releasing E (using UserInputService) to set the value of Blocking accordingly as I have not found a way to detect user key input with a Script.

The Script has a Blocking.Changed event for a function that plays the animation of raising the shield if Equipped and pausing the animation until no longer Blocking.

The problem is that the LocalScript only changes Blocking for the client when the player presses E, so Blocking.Changed never registers for the Script which reads Blocking on the server.

TLDR: Do I have to use a RemoteEvent from a LocalScript to tell a Script that the player is holding E, or is there a better approach out there? I’m pretty new to scripting on Roblox, apologies.

EDIT: improved wording for people searching this up

9 Likes

Hello there,

To answer your question of:

Yes, yes you need to… But Why?

Well, Roblox has this feature (Filtering Enabled) that prevents hackers from trying to manipulate / change anything that shouldn’t be changed so that scripted games can run only based on the scripts that the developers themselves make and not some random player. The solution was to have a clear split between what scripts and services the client (player’s device) can access and run. To allow for client input (eg. pressing a key) to be detected in any way, local scripts (scripts that can actually work on the client) are used. However, these local scripts are only restricted to run in certain client-accessible services. As such, this shows that you just shouldn’t trust the client to do any of the important stuff. (Yes, hackers are that bad.)

The reason why we use Remote Events is because, only these magical items of wisdom allow for communication between the player and the server. For the server to ever detect input from the player, you can fire a remote event to tell the server to do a specific action that the player wants to do.

Woah, that’s amazing!
To that, I say, I agree.

Anyway, to start off about these remote stuff, just remember this:

The client (local scripts) do all the input. (Key Press, Mouse Click). Then, use a remote event to pass it to a server script, and finally, let the server script, do the rest.

To detect input in the client, do:

-- In a local script
game:GetService("UserInputService").InputBegan:connect(function(input) -- Input Began checks if the player presses anything and fires whenever the player does so.
    if input.KeyCode = Enum.KeyCode.E then -- This detects for a "e" press.
    -- Fire a remote event
    yourRemoteEvent:FireServer()
    end
end)

 game:GetService("UserInputService").InputEnded:connect(function(input) -- Fires when input ended
    -- Send another remote event to stop Bool Value when enabled.
end)

To receive from a server script, do:

-- In normal (server) script

    --Remote event received, save it as a value.
    yourRemoteEvent.OnServerEvent:Connect(function()
    --Set Equipped BoolValue to true.
    end)

Note:

This is mostly correct except that after you detect e press on a local script, send a remote event to the server script, then set blocking to true. This way, the server’s Blocking will then actually change.

As, Roblox has enabled filtering enabled / Experimental Mode for all games, this is (possibly) the best and safest method to send your data to the server. Anything you change on a local script itself will only run on the player’s device, so while the player looking at the device may see it, the server doesn’t replicate which means that no one else will see it.

Some useful sources:

Remote Events and Functions

An answer about key pressed which I find really helpful.

InputBegan for UserInputService

InputEnded for UserInputService

21 Likes

“Elegantly”? Just do it on the client. Any and all input must always be handled client-side. Any change that needs to be visible to other clients can be propagated via a RemoteEvent. The animation should be done on the client-side. UserInputService and ContextActionService have a number of functions for detecting input if you’re interested in a quick skim through those pages.

The only server-side thing I see you needing here is setting the “Blocking” value so that other tools will be able to utilise the value. You do not have to use a RemoteEvent except for the client requesting the server to toggle blocking mode. Make sure that the server validates the client’s request. You’d most likely have to pass something when the key is pressed and unpressed.


@AbandonedRick

No, this is not how FilteringEnabled works and it pertains to exploiters, not hackers. The purpose of FilteringEnabled is to prevent the client from replicating changes to other clients. In a FilteringEnabled environment, only items that the client has active ownership over (or replication control) are propagated. With or without FilteringEnabled, clients can still change anything that they have access to.

Not factual. There has always been a clear divide between server-only and client-only methods, services and the like. This is unrelated to FilteringEnabled.

This too is not factual. LocalScripts can access a very large number of services and are only restricted from indexing a few (e.g. ServerStorage and ServerScriptService). They will only run in a very limited number of containers. The Wiki specifies those as the following:

  • A player’s backpack, or a Tool that they are in possession of
  • A player’s character
  • A player’s PlayerGui
  • A player’s PlayerScripts
  • ReplicatedFirst

Not a good model. There are very few cases, if any at all, in which your client should make a demand of the server. Clients should always be asking permission to do something, while the server runs a few checks before accepting the request. In a model like this, an exploiter would be able to fire the remote once and permanently set the blocking state to true. I personally don’t know a proper solution, but at the very least I know that this looks client-authoritative which is not going to end well. You could pass the InputObject that UserInputService gets from InputBegan/Ended to a remote and check its typeof on the server. I highly doubt this is a viable solution though.

8 Likes

Hi @colbert2677,

Judging by the way that OP wrote his post, and through the quote:

Correct me if I’m wrong, but I highly doubt that he understands how do remote events and functions work. Thus, I am using easy to understand examples to bring across the message. To start in learning such kinds of things, it is easier to have simpler terms laid out to you before you get to know the actual word for it: Because what’s the point of learning a word but not understanding anything about the concept?


To answer the part on:

Whoops, I didn’t know that exploiters and hackers are two different things. Well, you learn something everyday, thanks!

Other than that, I would like to apologize, maybe I should have included it more times, however, I would like to say that I did actually mention about such replication further down the post. I did think about using the word “replicate”, but would someone new to such topics understand what does “replicating” means and how to replicate? I for one definitely didn’t, but we’re all different, so maybe OP will understand?


Again, I want to emphasise that someone who is new to the topic really just needs to understand the concept. Maybe it’s just me again, but if I was new to this and someone described Filtering Enabled and remote functions as the “prevention of exploitation through the use of server-client replication and verification”, I wouldn’t understand. I mean, what is exploitation? What is replication and how to I replicate? What is a client?

If I can use simple terms such as “clear divide” which holds a physical meaning of separation to depict filtering enabled, anyone in this world would understand that you are trying to stop some sort of transmission between server and client.


Could you elaborate further? What is the difference between:

and

Based on my quote, it says that local scripts only work in some places which the client can access? Which would what you described as:

Maybe I’m wrong somewhere. Do correct me because learning is always key.


I’m a little confused with this too. Shouldn’t a local script with the code:

Isn’t the above script just checking if the player presses a key then fires a remote event to the server script to set blocking to true? Then when player input ended and if the input end is a “E” then send another remote event to the server to change Blocking? Also, what is the point of passing an input object to the server for checking. So what if the exploiter changes the key from “E” to “F”? I mean that’s completely aesthetic and doesn’t need change core functionality, unless I have not considered a certain scenario where such would be disastrous.

Note: The above is only if the local script is checking for key press. If it is anything else that changes an important function, then server checking should be done. For example, you obviously shouldn’t set the player’s walk speed on the client itself.

I’m also not sure about this part. Would input end send a remote event to the server which changes Blocking? Also, if the hacker really wants to switch around the remote events for input started and input ended then it is only his client that will be doing the opposite, setting blocking to true on “e” not press. It doesn’t affect anyone else and doesn’t change up much.

1 Like

Learning good practice earlier and gaining the understanding of something you don’t know is better than opening up with bad practice and having problems later down the line comprehending or switching over when it comes to a concept. It’s better to give the answer straight. If you want to enlighten someone on a topic, then you should explain how to do it in a way that’s proper.


There is no thinking behind it. Replication is a literal statement. To replicate means to copy, therefore referring to replication means to copy the changes of something to be used for another. You answered for it halfway but there’s still an incomplete definition you sport. LocalScripts are capable of replicating changes without the server’s help but on a very limited number of things.


But you don’t need to. It’s not relevant. Server, client and shared access services and methods have always existed. They have nothing to do with FilteringEnabled.

Again, this is another literal statement. If they don’t understand then you explain or direct them to a resource in which they can understand. The words used in several of these statements are almost all literal meanings.


In you address to what I said about where LocalScripts can run, the difference is that you mentioned that LocalScripts can run in any service that a client can access. This is not true. There are very specific containers that need to be selected for a client to run code.

Your statement:

What I posted gives the very specific containers that a LocalScript need to be placed in for client-side code to be run. I misread your post so I made a mistake on what I said, though yes, what I said was further defining what you said (and it was also factual).

EDIT: Fixed above, I missed where you said “certain”.


My statement on code model is not related to the code you posted, it’s related to the statement you made (which is why I quoted it in the first place).

There’s very few cases, if any, where the client should be telling the server what to do. The client should be making requests of the server to do something, and the server should check if those requests are legitimate or allowed before processing them.

The client-side code you posted is fine. The issue lies in the server code you posted, which holds a comment “set blocking to true”. The way you’re directing OP is that the client should fire a remote when a key is pressed or released, while the server sets blocking to true. THIS, is not agreeable. The server should be performing checks to see if certain conditions are met first before just setting blocking to true (e.g. if they aren’t stunned or the player doesn’t have a shield, for example).

Not at all. InputObjects cannot be created with Instance.new. The use case is having the client send an InputObject to the server. The server validates if what it receives was:

  • An InputObject
  • Has the KeyCode Enum.KeyCode.E
  • Meets all other conditions

It’s neither aesthetic or pointless, but I did mention that it wasn’t really a viable solution.

Not sure what relevance this holds. I’ll make a note on this though: clients can change their WalkSpeed and so can the server. The property will replicate server-to-client, but not client-to-server. On the other hand, if a client sets their WalkSpeed, positions still replicate since the client has network ownership of their characters.

Not my point. Your code is client-authoritative. The client fires a remote to tell the server that it pressed or released a key and the server sets blocking accordingly. An exploiter doesn’t need to even think about InputBegan or InputEnded. They just have to fire the remote once as “key pressed” and it’ll be locked to blocking permanently. In addition, an exploiter can have their code listen to the value being changed to false and fire the remote so blocking gets set back to true.

EDIT: Fixed my post a bit, misread something.

3 Likes

Hello again @colbert2677,

Well, that is quite an assumption that you have made there. After all, we are all developers from all walks of life. Some are very young and don’t understand various terms, some are much much older and have much more experience in such fields. Not everyone that you talk to will be qualified experts with a degree. We should always take into consideration their understanding of a certain topic before putting large words that they will have to google up themselves when this forum should be the site that explains everything to them and aid them in their work.

About the above… How is this related to the topic at hand? I’ve only mentioned all that he needs to know. The knowledge that a local script can replicate on its own does not aid with the situation. I mean all he is doing he trying to detect for “e” on a local script and fire to server. A local script that replicates without the server doesn’t change the fact that he needs to use a local script to send it to the server. The local script is still involved and will be regardless of whether your statement was true.


Again, you’re assuming that OP has been here since 2008 and knows about what the client, server and all this is about. It doesn’t matter when it has been out. As long as you are new to this field of study, you will not know what they are.

Learning a coding language is like a baby learning his first language. You can’t just tell him to explain the meaning of what is supercalifragilisticexpialidocious and expect him to straight up know about it. You will have to start from the basics, A, B, C. Yes, not even words. They have to start from the simplest of all, a single alphabet.


This is complimentary and should definitely be checked by the server. I thought I implied that in my first post but I guess it must have been made more prominent.

This one’s my fault. I was doing a project on walk speed and yet I still forgot that you can set walk speed on the client. An example that I should have used should have been the example you made: Equipping the shield and all.

Ahhh, I see what you mean. I actually never thought of it like this. I’ll change up my answer above. Thanks!

No, no. When input started and input object is E, fire a remote event to the server and set blocking to true. When input ended and input object is E, fire a remote event to the server and set blocking to false. Thus, blocking will be false when you remove E.

…? I gave an explanation for what I said AND provided a way to solve misconceptions, misunderstandings or lack of knowledge. I’m completely aware that each developer’s understanding of a topic is different, but in some cases there’s only one way to understand something at conceptual level.

Because it explains what I said? That a good portion of it can be done on the client? The purpose of this thread is to figure out how to detect when a key is being held and OP is asking about approaches to this. Part of understanding how a LocalScript works is part of “appetising” the solution. I never said a single thing about ignoring the presence of LocalScripts.


No? How? It’s not relevant to the topic, this is the point I’m trying to convey. This scrutinization of the point I made was wholly unnecessary.


The properties of an InputObject are read-only and it’s unnecessary to account for changes to an InputObject. The client fires the InputObject and the server checks its key code. You cannot remove a KeyCode from an InputObject. I specifically didn’t agree with the way you worded it, which suggests client authority in this situation.

1 Like

Add-on:
Honestly, after re-thinking the code out, I see what @colbert2677 mean when he says that he can’t figure out an efficient way of detecting “e” without exploit. To that, I agree. However, after that, I thought about how does Roblox itself detect input, for example from a keyboard to move, not to mention that you could speed hack by exploiting the walk speed. That was, when I realised that Roblox probably does what we do. they let a local script detect input and move accordingly. Well, then why don’t players exploit by making W continuously pressed without actually having to press W? That is because, there is little point to do that. I mean so what if you are able to walk infinitely in the direction that you want? You see, there is no incentive doing so, the player doesn’t gain anything from this. In the case of the OP, I feel that pressing “e” to enable shield is giving the player too much power. (All players, not just exploiters). I mean a normal player could as easily as a hacker, continuously press the “e” button on the keyboard or place a heavy object on the “e” button and have infinite shield. You see, there is an incentive to do this, you get infinite shield. My suggestion would be to add a cool down to the shield OR maybe when the player equips sword, the shield cannot be equipped. This way, there is No Incentive in holding the “e” button. After all, the shield will eventually have to go away. Thus, in conclusion, I would just like to say that it is not the local script that is “client-authoritative”. it is the feature! I mean you are giving so much power to the players whereby they can infinitely equip the shield. Now, that is the problem.

Finally, I would just like to say that my method should work just fine and you shouldn’t need server checking since it is as easily exploitable as checking in client.

3 Likes

there is never one way to understand something. I mean, we all learnt scripting differently. Some learnt it from scripting tutorial videos, some from the Roblox Wiki, some just tried it out, and it worked! Not to mention the fact that different people learn differently.

Other than that, just look at the Roblox Wiki. One of the most basic concepts, the variable is explained in much simpler terms: “a name you can use to hold a value”. They don’t mention things like variables are used in functions and stuff like that because Roblox acknowledges that people who are reading it are likely to not know anything about functions.

Regarding this, even if it was mentioned or not, it wouldn’t have changed the fact that OP a local script runs from the client and has to be used for input.

Imagine a new robloxian enters into the world of scripting on Roblox in 2019. He wouldn’t know that clients and servers were a thing until when he learns about them. Even if these were a thing in the past, he won’t understand until he learns about their concepts. As such, it doesn’t matter if it existed in the past, he just has to learn about it. To add on, filtering enabled is also heavily relevant to the servers and clients and should be used as terms to describe the issue better to someone new to the topic.

At a conceptual level. No matter what way you learn, you still arrive at the same conclusion. What I intended by this phrase may not so much understanding, but properly understanding the concept.


So…? I don’t get what you’re trying to retort here. That’s literally what you and I both have been saying. I don’t understand where the misconception was drawn.


So what? This is branching away from my initial disagreement. I disagreed with your statement that FilteringEnabled is relevant to the division of services that servers and clients can access. It’s off-topic in the first place and this is getting out of hand. Unless it’s related to OP, please DM me to continue.

1 Like

Side note from the conversation above: is blocking a gameplay action or a visual action? What I mean is: will raising your shield prevent damage (or something along those lines) or is it just an animation (like a salute)

If it’s a visual element, you don’t need to worry about remote events. The client automatically has replication control over their character model (the player can move without sending remote events). You can run the animation on a local script and all other players will see the action.

If it’s a gameplay element, then you’ll need follow the previously stated course of action: use a remote event to inform the server that the client wants to “block”. Adding one thing though, it’s probably better not to play the animation on the server because there’s a small delay between when the client fires a remote event and when the server receives that event. I would recommend firing the remote event on the client, starting the animation on the client, and then letting the server handle any gameplay ramifications of “blocking”.

1 Like

It’s a gameplay element. I guess I was just confused because I saw that a bunch of gear like Noir Periastron have the ability to detect the Q key being pressed, etc. with no RemoteEvents, but it seems you need to have the tool equipped which I do not want.

I ended up making it fire an event with true/false (holding/releasing E) for a Script that sets the Blocking value and plays/ends the animation on the player accordingly. Not sure how I would make the animation play on the client, wouldn’t it not display the animation for other people? Do I play the animation on both the client and on the server?

Just play the animation on the client and it will replicate (although make sure the server gives the client NetworkOwnership of the shield). Since the client is given NetworkOwnership of it’s character model by default, all positional changes to the character model done by a local script will automatically replicate to the server and other players.
If you play solo, and navigate to the Player’s Character, you’ll notice that the Animate script (which controls animations) is a local script.

I just checked the gear and it contains both a RemoteEvent and RemoteFunction to receive inputs from the client.

For example, inside the helpfully named ‘Script’:

Tool:WaitForChild'Input'.OnServerEvent:Connect(function(client, button, down, ...)
	if client.Character == Tool.Parent then
		if button == 'Key' then
			if down then
				lightsOut(...)
			end
		end
	end
end)

It’s a slightly strange naming system to me, but it seems that when the Input LocalScript detects the player has pressed the key to turn the light off it fires the remote events with parameters ‘Key’, to distinguish between keys and mouse clicks, the key that’s pressed (‘q’), and whether it is held down. (‘client’ is the player who fired the remote which is always received as a parameter by the server, and here the server checks that the player who fired it is the one who owns the tool, and not an exploiter)

1 Like

Ok tbh I didn’t read into all of your issue here, it seems this thread has been going on for a while. But I haven’t seen anyone tell you about Keydown.

Simply calling this will return true or false if the key is currently being pressed:

game:GetService(‘UserInputService’):IsKeyDown(Enum.KeyCode.E)

10 Likes