Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 46 additions & 4 deletions Client/mods/deathmatch/ClientCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*****************************************************************************/

#include "StdInc.h"
#include "logic/CRegisteredCommands.h"
#include <game/CWeapon.h>
#include <game/CTaskManager.h>
#include <game/Task.h>
Expand Down Expand Up @@ -57,10 +58,42 @@ bool COMMAND_Executed(const char* szCommand, const char* szArguments, bool bHand
strClumpedCommandUTF = strClumpedCommandUTF.substr(0, MAX_COMMAND_LENGTH);
strClumpedCommand = UTF16ToMbUTF8(strClumpedCommandUTF);

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

// Call the onClientConsole event
CClientPlayer* localPlayer = g_pClientGame->GetLocalPlayer();

// First try to process with registered Lua commands
CommandExecutionResult commandResult = g_pClientGame->GetRegisteredCommands()->ProcessCommand(szCommandBufferPointer, szArguments, false);

// If command was handled by Lua, don't send to server
if (commandResult.wasExecuted)
{
return true; // Command was handled locally, don't send to server
}

// If no Lua handler was found, trigger onClientCommand event to allow interception
CLuaArguments arguments;
arguments.PushString(szCommandBufferPointer);
arguments.PushBoolean(false); // executedByFunction

if (szArguments && *szArguments)
{
std::istringstream stream{szArguments};
for (std::string arg; stream >> arg;)
{
arguments.PushString(arg.c_str());
}
}

if (localPlayer)
{
localPlayer->CallEvent("onClientCommand", arguments, false);

// If command was handled by onClientCommand event, don't send to server
if (g_pClientGame->GetEvents()->WasEventCancelled())
{
return true; // Command was intercepted and handled
}
}


if (localPlayer != nullptr)
{
Expand Down Expand Up @@ -108,7 +141,16 @@ bool COMMAND_Executed(const char* szCommand, const char* szArguments, bool bHand

// Call our comand-handlers for core-executed commands too, if allowed
if (bAllowScriptedBind)
g_pClientGame->GetRegisteredCommands()->ProcessCommand(szCommand, szArguments);
{
CommandExecutionResult coreCommandResult = g_pClientGame->GetRegisteredCommands()->ProcessCommand(szCommand, szArguments, false);

// If core command failed, don't show unknown message (these are usually keybinds)
if (!coreCommandResult.wasExecuted)
{
// Silently ignore failed keybind commands to prevent spam
return true;
}
}
}
return false;
}
Expand Down
1 change: 1 addition & 0 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2733,6 +2733,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, executedByFunction, ...", NULL, false);

// Chat events
m_Events.AddEvent("onClientChatMessage", "text, r, g, b, messageType", NULL, false);
Expand Down
10 changes: 5 additions & 5 deletions Client/mods/deathmatch/logic/CRegisteredCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,14 @@ bool CRegisteredCommands::CommandExists(const char* szKey, CLuaMain* pLuaMain)
return GetCommand(szKey, pLuaMain) != nullptr;
}

bool CRegisteredCommands::ProcessCommand(const char* szKey, const char* szArguments)
CommandExecutionResult CRegisteredCommands::ProcessCommand(const char* szKey, const char* szArguments, bool executedByFunction)
{
assert(szKey);

CommandExecutionResult result;

// Call the handler for every virtual machine that matches the given key
int iCompareResult;
bool bHandled = false;
m_bIteratingList = true;
list<SCommand*>::const_iterator iter = m_Commands.begin();
for (; iter != m_Commands.end(); iter++)
Expand All @@ -171,14 +172,13 @@ bool CRegisteredCommands::ProcessCommand(const char* szKey, const char* szArgume
{
// Call it
CallCommandHandler((*iter)->pLuaMain, (*iter)->iLuaFunction, (*iter)->strKey, szArguments);
bHandled = true;
result.wasExecuted = true;
}
}
m_bIteratingList = false;
TakeOutTheTrash();

// Return whether some handler was called or not
return bHandled;
return result;
}

CRegisteredCommands::SCommand* CRegisteredCommands::GetCommand(const char* szKey, class CLuaMain* pLuaMain)
Expand Down
8 changes: 7 additions & 1 deletion Client/mods/deathmatch/logic/CRegisteredCommands.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ enum class MultiCommandHandlerPolicy : std::uint8_t
ALLOW = 2
};

struct CommandExecutionResult
{
bool wasCancelled = false;
bool wasExecuted = false;
};

class CRegisteredCommands
{
struct SCommand
Expand All @@ -48,7 +54,7 @@ class CRegisteredCommands
void GetCommands(lua_State* luaVM);
void GetCommands(lua_State* luaVM, CLuaMain* pTargetLuaMain);

bool ProcessCommand(const char* szKey, const char* szArguments);
CommandExecutionResult ProcessCommand(const char* szKey, const char* szArguments, bool executedByFunction = false);

private:
SCommand* GetCommand(const char* szKey, class CLuaMain* pLuaMain = NULL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*****************************************************************************/

#include "StdInc.h"
#include "CRegisteredCommands.h"

int CLuaFunctionDefs::AddCommandHandler(lua_State* luaVM)
{
Expand Down Expand Up @@ -90,7 +91,8 @@ int CLuaFunctionDefs::ExecuteCommandHandler(lua_State* luaVM)
if (pLuaMain)
{
// Call it
if (m_pRegisteredCommands->ProcessCommand(strKey, strArgs))
CommandExecutionResult result = m_pRegisteredCommands->ProcessCommand(strKey, strArgs, true);
if (result.wasExecuted && !result.wasCancelled)
{
lua_pushboolean(luaVM, true);
return 1;
Expand Down
21 changes: 19 additions & 2 deletions Server/mods/deathmatch/logic/CConsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,15 @@ bool CConsole::HandleInput(const char* szCommand, CClient* pClient, CClient* pEc

// Let the script handle it
int iClientType = pClient->GetClientType();
bool wasHandled = false;

switch (iClientType)
{
case CClient::CLIENT_PLAYER:
{
// See if any registered command can process it
CPlayer* pPlayer = static_cast<CPlayer*>(pClient);
m_pRegisteredCommands->ProcessCommand(szKey, szArguments, pClient);
wasHandled = m_pRegisteredCommands->ProcessCommand(szKey, szArguments, pClient);

// HACK: if the client gets destroyed before here, dont continue
if (m_pPlayerManager->Exists(pPlayer))
Expand All @@ -102,23 +103,39 @@ bool CConsole::HandleInput(const char* szCommand, CClient* pClient, CClient* pEc
Arguments.PushString(szCommand);
pPlayer->CallEvent("onConsole", Arguments);
}

// If command wasn't handled, send "unknown command" message to client
if (!wasHandled && m_pPlayerManager->Exists(pPlayer))
{
SString strError("Unknown command or cvar: %s", szKey);
pPlayer->SendEcho(strError);
return false;
}
break;
}
case CClient::CLIENT_CONSOLE:
{
// See if any registered command can process it
CConsoleClient* pConsole = static_cast<CConsoleClient*>(pClient);
m_pRegisteredCommands->ProcessCommand(szKey, szArguments, pClient);
wasHandled = m_pRegisteredCommands->ProcessCommand(szKey, szArguments, pClient);

// Call the console event
CLuaArguments Arguments;
Arguments.PushString(szCommand);
pConsole->CallEvent("onConsole", Arguments);

// If command wasn't handled, it's unknown
if (!wasHandled)
{
return false;
}
break;
}
default:
break;
}

return wasHandled;
}

// Doesn't exist
Expand Down