Skip to content

Add onClientCommand event to cancel client-side commands #4303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

ColombuxMaximus
Copy link
Contributor

@ColombuxMaximus ColombuxMaximus commented Jul 16, 2025

Adds onClientCommand event to intercept and cancel client-side commands before execution.

#3160

Before you go ahead and create a pull request, please make sure:

If your work is incomplete, do not prefix your pull request with "WIP", instead
create a draft pull request: https://github.blog/2019-02-14-introducing-draft-pull-requests/

Thank you!

@ColombuxMaximus
Copy link
Contributor Author

Let me know if there's something else. Not sure why some of my comments/answers are not showing.
( @Dutchman101 )
image

@ColombuxMaximus
Copy link
Contributor Author

Hello @FileEX just in case you missed my comment to your review because Github says it's 'Pending'

@@ -2722,6 +2722,7 @@ void CClientGame::AddBuiltInEvents()
// Console events
m_Events.AddEvent("onClientConsole", "text", NULL, false);
m_Events.AddEvent("onClientCoreCommand", "command", NULL, false);
m_Events.AddEvent("onClientCommand", "command", NULL, false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nullptr

@ColombuxMaximus
Copy link
Contributor Author

Thank you @FileEX
Can you check here if everything is correct?

I'll test it tomorrow in game

Copy link

@MohabCodeX MohabCodeX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job , i have made some changes that will enhance command handling by adding argument support to the event , but i don't have changing permission to your branch , anyway the final usage would be like this :

function onClientCommand(command, arguments)
    outputChatBox("Command: " .. command, 255, 255, 0)
    outputChatBox("Arguments: " .. arguments, 0, 255, 255)

    if command == "blocked" then
        outputChatBox("Command blocked!", 255, 0, 0)
        return false
    end

    return true
end

addEventHandler("onClientCommand", root, onClientCommand)
image

@FileEX
Copy link
Contributor

FileEX commented Jul 27, 2025

Thank you @FileEX Can you check here if everything is correct?

I'll test it tomorrow in game

Okay, I didn’t realize that CCommands::Execute is part of the Core project. So let's keep everything within Deathmatch.

My suggestion is that COMMAND_Executed should return two booleans: something like wasCanceled and wasExecuted. Then, in CCommands::Execute, we display Unknown command or cvar: only if wasCanceled is false. The event can stay inside COMMAND_Executed.

Also, I noticed a bug. COMMAND_Executed should return false if:

g_pClientGame->GetRegisteredCommands()->ProcessCommand(szCommandBufferPointer, szArguments);

returns false – because that means the command doesn’t exist. Right now, it always returns true, even if the command doesn’t exist. As a result, when you type something like /foo, there’s no “unknown command” message – it just silently fails. You could fix this as well while you're at it.

Lastly, regarding executeCommandHandler – I think this function should also trigger onClientCommand, but with an additional parameter like executedByFunction to indicate whether the command was triggered manually (by typing) or programmatically (via function).

You could also consider having the CRegisteredCommands::ProcessCommand function trigger the event instead of COMMAND_Executed, and have it return two booleans – whether the command was canceled and whether it was executed (i.e., if it exists). That way, executeCommandHandler, which directly calls CRegisteredCommands::ProcessCommand, would benefit from the same logic. This way, we avoid triggering the event in two different places.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants