added client-based console commands
authorDavid Anderson <dvander@alliedmods.net>
Fri Feb 16 02:17:41 2007 +0000 (2007-02-16)
changeset 500868e9b19a872
parent 499 961a75a6d466
child 501 e209a7296936
added client-based console commands
extended console command functions to have an argument number
renamed Result to Action
core/CConCmdManager.cpp
core/CConCmdManager.h
core/CPlayerManager.cpp
core/smn_console.cpp
plugins/include/console.inc
plugins/include/sourcemod.inc
     1.1 --- a/core/CConCmdManager.cpp	Fri Feb 16 00:04:14 2007 +0000
     1.2 +++ b/core/CConCmdManager.cpp	Fri Feb 16 02:17:41 2007 +0000
     1.3 @@ -40,6 +40,7 @@
     1.4  
     1.5  void CConCmdManager::OnSourceModShutdown()
     1.6  {
     1.7 +	/* All commands should already be removed by the time we're done */
     1.8  	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &CConCmdManager::SetCommandClient, false);
     1.9  	g_RootMenu.RemoveRootConsoleCommand("cmds", this);
    1.10  	g_PluginSys.RemovePluginsListener(this);
    1.11 @@ -53,6 +54,7 @@
    1.12  void CConCmdManager::OnPluginDestroyed(IPlugin *plugin)
    1.13  {
    1.14  	CmdList *pList;
    1.15 +	List<ConCmdInfo *> removed;
    1.16  	if (plugin->GetProperty("CommandList", (void **)&pList, true))
    1.17  	{
    1.18  		CmdList::iterator iter;
    1.19 @@ -65,14 +67,25 @@
    1.20  				|| cmd.type == Cmd_Console)
    1.21  			{
    1.22  				ConCmdInfo *pInfo = cmd.pInfo;
    1.23 +				/* See if this is being removed */
    1.24 +				if (removed.find(pInfo) != removed.end())
    1.25 +				{
    1.26 +					continue;
    1.27 +				}
    1.28  				/* See if there are still hooks */
    1.29  				if (pInfo->srvhooks
    1.30  					&& pInfo->srvhooks->GetFunctionCount())
    1.31  				{
    1.32  					continue;
    1.33  				}
    1.34 +				if (pInfo->conhooks
    1.35 +					&& pInfo->conhooks->GetFunctionCount())
    1.36 +				{
    1.37 +					continue;
    1.38 +				}
    1.39  				/* Remove the command */
    1.40  				RemoveConCmd(pInfo);
    1.41 +				removed.push_back(pInfo);
    1.42  			}
    1.43  		}
    1.44  		delete pList;
    1.45 @@ -89,12 +102,39 @@
    1.46  	m_CmdClient = client + 1;
    1.47  }
    1.48  
    1.49 +ResultType CConCmdManager::DispatchClientCommand(int client, ResultType type)
    1.50 +{
    1.51 +	const char *cmd = engine->Cmd_Argv(0);
    1.52 +	int args = engine->Cmd_Argc() - 1;
    1.53 +
    1.54 +	ConCmdInfo *pInfo;
    1.55 +	if (sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
    1.56 +	{
    1.57 +		cell_t result = type;
    1.58 +		if (pInfo->conhooks && pInfo->conhooks->GetFunctionCount())
    1.59 +		{
    1.60 +			pInfo->conhooks->PushCell(client);
    1.61 +			pInfo->conhooks->PushCell(args);
    1.62 +			pInfo->conhooks->Execute(&result);
    1.63 +		}
    1.64 +		if (result >= Pl_Stop)
    1.65 +		{
    1.66 +			return Pl_Stop;
    1.67 +		}
    1.68 +		type = (ResultType)result;
    1.69 +	}
    1.70 +
    1.71 +	return type;
    1.72 +}
    1.73 +
    1.74  void CConCmdManager::InternalDispatch()
    1.75  {
    1.76 -	if (m_CmdClient)
    1.77 -	{
    1.78 -		return;
    1.79 -	}
    1.80 +	/**
    1.81 +	 * Note: Console commands will EITHER go through IServerGameDLL::ClientCommand,
    1.82 +	 * OR this dispatch.  They will NEVER go through both.
    1.83 +	 * -- 
    1.84 +	 * Whether or not it goes through the callback is determined by FCVAR_GAMEDLL
    1.85 +	 */
    1.86  
    1.87  	const char *cmd = engine->Cmd_Argv(0);
    1.88  	ConCmdInfo *pInfo;
    1.89 @@ -104,9 +144,33 @@
    1.90  	}
    1.91  
    1.92  	cell_t result = Pl_Continue;
    1.93 -	if (pInfo->srvhooks)
    1.94 +	int args = engine->Cmd_Argc() - 1;
    1.95 +
    1.96 +	if (m_CmdClient == 0)
    1.97  	{
    1.98 -		pInfo->srvhooks->Execute(&result);
    1.99 +		if (pInfo->srvhooks && pInfo->srvhooks->GetFunctionCount())
   1.100 +		{
   1.101 +			pInfo->srvhooks->PushCell(args);
   1.102 +			pInfo->srvhooks->Execute(&result);
   1.103 +		}
   1.104 +	
   1.105 +		/* Check if there's an early stop */
   1.106 +		if (result >= Pl_Stop)
   1.107 +		{
   1.108 +			if (!pInfo->sourceMod)
   1.109 +			{
   1.110 +				RETURN_META(MRES_SUPERCEDE);
   1.111 +			}
   1.112 +			return;
   1.113 +		}
   1.114 +	}
   1.115 +
   1.116 +	/* Execute console command hooks */
   1.117 +	if (pInfo->conhooks && pInfo->conhooks->GetFunctionCount())
   1.118 +	{
   1.119 +		pInfo->conhooks->PushCell(m_CmdClient);
   1.120 +		pInfo->conhooks->PushCell(args);
   1.121 +		pInfo->conhooks->Execute(&result);
   1.122  	}
   1.123  
   1.124  	if (result >= Pl_Handled)
   1.125 @@ -119,6 +183,34 @@
   1.126  	}
   1.127  }
   1.128  
   1.129 +void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction, 
   1.130 +									   const char *name, 
   1.131 +									   const char *description, 
   1.132 +									   int flags)
   1.133 +{
   1.134 +	ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
   1.135 +
   1.136 +	if (!pInfo->conhooks)
   1.137 +	{
   1.138 +		pInfo->conhooks = g_Forwards.CreateForwardEx(NULL, ET_Hook, 2, NULL, Param_Cell, Param_Cell);
   1.139 +	}
   1.140 +
   1.141 +	pInfo->conhooks->AddFunction(pFunction);
   1.142 +
   1.143 +	/* Add to the plugin */
   1.144 +	CmdList *pList;
   1.145 +	IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
   1.146 +	if (!pPlugin->GetProperty("CommandList", (void **)&pList))
   1.147 +	{
   1.148 +		pList = new CmdList();
   1.149 +		pPlugin->SetProperty("CommandList", pList);
   1.150 +	}
   1.151 +	PlCmdInfo info;
   1.152 +	info.pInfo = pInfo;
   1.153 +	info.type = Cmd_Console;
   1.154 +	pList->push_back(info);
   1.155 +}
   1.156 +
   1.157  void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, 
   1.158  									  const char *name, 
   1.159  									  const char *description, 
   1.160 @@ -144,7 +236,7 @@
   1.161  	}
   1.162  	PlCmdInfo info;
   1.163  	info.pInfo = pInfo;
   1.164 -	info.type = Cmd_Console;
   1.165 +	info.type = Cmd_Server;
   1.166  	pList->push_back(info);
   1.167  }
   1.168  
   1.169 @@ -310,8 +402,7 @@
   1.170  			}
   1.171  			name = cmd.pInfo->pCmd->GetName();
   1.172  			help = cmd.pInfo->pCmd->GetHelpText();
   1.173 -			g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
   1.174 -				
   1.175 +			g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);		
   1.176  		}
   1.177  
   1.178  		return;
     2.1 --- a/core/CConCmdManager.h	Fri Feb 16 00:04:14 2007 +0000
     2.2 +++ b/core/CConCmdManager.h	Fri Feb 16 02:17:41 2007 +0000
     2.3 @@ -38,10 +38,12 @@
     2.4  		sourceMod = false;
     2.5  		pCmd = NULL;
     2.6  		srvhooks = NULL;
     2.7 +		conhooks = NULL;
     2.8  	}
     2.9  	bool sourceMod;					/**< Determines whether or not concmd was created by a SourceMod plugin */
    2.10  	ConCommand *pCmd;				/**< Pointer to the command itself */
    2.11  	IChangeableForward *srvhooks;	/**< Hooks on this name as a server command */
    2.12 +	IChangeableForward *conhooks;	/**< Hooks on this name as a console command */
    2.13  };
    2.14  
    2.15  class CConCmdManager :
    2.16 @@ -63,6 +65,8 @@
    2.17  	void OnRootConsoleCommand(const char *command, unsigned int argcount);
    2.18  public:
    2.19  	void AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
    2.20 +	void AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
    2.21 +	ResultType DispatchClientCommand(int client, ResultType type);
    2.22  private:
    2.23  	void InternalDispatch();
    2.24  	ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags);
     3.1 --- a/core/CPlayerManager.cpp	Fri Feb 16 00:04:14 2007 +0000
     3.2 +++ b/core/CPlayerManager.cpp	Fri Feb 16 02:17:41 2007 +0000
     3.3 @@ -15,6 +15,7 @@
     3.4  #include "ForwardSys.h"
     3.5  #include "ShareSys.h"
     3.6  #include "AdminCache.h"
     3.7 +#include "CConCmdManager.h"
     3.8  
     3.9  CPlayerManager g_Players;
    3.10  
    3.11 @@ -51,15 +52,14 @@
    3.12  
    3.13  	ParamType p1[] = {Param_Cell, Param_String, Param_Cell};
    3.14  	ParamType p2[] = {Param_Cell};
    3.15 -	ParamType p3[] = {Param_Cell, Param_String};
    3.16  
    3.17  	m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1);
    3.18  	m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2);
    3.19  	m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2);
    3.20  	m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2);
    3.21 -	m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 1, p2);
    3.22 +	m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 2, NULL, Param_Cell, Param_Cell);
    3.23  	m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
    3.24 -	m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, p3);
    3.25 +	m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
    3.26  }
    3.27  
    3.28  void CPlayerManager::OnSourceModShutdown()
    3.29 @@ -197,6 +197,7 @@
    3.30  		g_SourceMod.SetAuthChecking(true);
    3.31  	}
    3.32  
    3.33 +	//:todo: this must meta return
    3.34  	return (res) ? true : false;
    3.35  }
    3.36  
    3.37 @@ -328,10 +329,26 @@
    3.38  
    3.39  void CPlayerManager::OnClientCommand(edict_t *pEntity)
    3.40  {
    3.41 -	cell_t res;
    3.42 +	cell_t res = Pl_Continue;
    3.43 +	int client = engine->IndexOfEdict(pEntity);
    3.44 +
    3.45 +	int args = engine->Cmd_Argc() - 1;
    3.46 +
    3.47 +	m_clcommand->PushCell(client);
    3.48 +	m_clcommand->PushCell(args);
    3.49 +	m_clcommand->Execute(&res, NULL);
    3.50  
    3.51 -	m_clcommand->PushCell(engine->IndexOfEdict(pEntity));
    3.52 -	m_clcommand->Execute(&res, NULL);
    3.53 +	if (res >= Pl_Stop)
    3.54 +	{
    3.55 +		RETURN_META(MRES_SUPERCEDE);
    3.56 +	}
    3.57 +
    3.58 +	res = g_ConCmds.DispatchClientCommand(client, (ResultType)res);
    3.59 +
    3.60 +	if (res >= Pl_Handled)
    3.61 +	{
    3.62 +		RETURN_META(MRES_SUPERCEDE);
    3.63 +	}
    3.64  }
    3.65  
    3.66  void CPlayerManager::OnClientSettingsChanged(edict_t *pEntity)
     4.1 --- a/core/smn_console.cpp	Fri Feb 16 00:04:14 2007 +0000
     4.2 +++ b/core/smn_console.cpp	Fri Feb 16 02:17:41 2007 +0000
     4.3 @@ -342,6 +342,25 @@
     4.4  	return 1;
     4.5  }
     4.6  
     4.7 +static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
     4.8 +{
     4.9 +	char *name,*help;
    4.10 +	IPluginFunction *pFunction;
    4.11 +
    4.12 +	pContext->LocalToString(params[1], &name);
    4.13 +	pContext->LocalToString(params[3], &help);
    4.14 +	pFunction = pContext->GetFunctionById(params[2]);
    4.15 +
    4.16 +	if (!pFunction)
    4.17 +	{
    4.18 +		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
    4.19 +	}
    4.20 +
    4.21 +	g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]);
    4.22 +
    4.23 +	return 1;
    4.24 +}
    4.25 +
    4.26  REGISTER_NATIVES(convarNatives)
    4.27  {
    4.28  	{"CreateConVar",		sm_CreateConVar},
    4.29 @@ -363,5 +382,6 @@
    4.30  	{"GetConVarMax",		sm_GetConVarMax},
    4.31  	{"ResetConVar",			sm_ResetConVar},
    4.32  	{"RegServerCmd",		sm_RegServerCmd},
    4.33 +	{"RegConsoleCmd",		sm_RegConsoleCmd},
    4.34  	{NULL,					NULL}
    4.35  };
     5.1 --- a/plugins/include/console.inc	Fri Feb 16 00:04:14 2007 +0000
     5.2 +++ b/plugins/include/console.inc	Fri Feb 16 02:17:41 2007 +0000
     5.3 @@ -79,7 +79,7 @@
     5.4   * @return				A Result value.  Not handling the command
     5.5   *						means that Source will report it as "not found."
     5.6   */
     5.7 -functag SrvCmd Action:public();
     5.8 +functag SrvCmd Action:public(argCount);
     5.9  
    5.10  /**
    5.11   * Creates a server-only console command, or hooks an already existing one.  
    5.12 @@ -92,7 +92,6 @@
    5.13   */
    5.14  native RegServerCmd(const String:cmd[], SrvCmd:callback, const String:description[]="", flags=0);
    5.15  
    5.16 -#if 0
    5.17  /**
    5.18   * Called when a generic console command is invoked.
    5.19   *
    5.20 @@ -100,7 +99,7 @@
    5.21   * @return				A Result value.  Not handling the command
    5.22   *						means that Source will report it as "not found."
    5.23   */
    5.24 -functag ConCmd Action:public(client);
    5.25 +functag ConCmd Action:public(client, argCount);
    5.26  
    5.27  /**
    5.28   * Creates a console command, or hooks an already existing one.
    5.29 @@ -113,6 +112,7 @@
    5.30   */
    5.31  native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:description[]="", flags=0);
    5.32  
    5.33 +#if 0
    5.34  /**
    5.35   * Hooks a specific client-only command.
    5.36   *
     6.1 --- a/plugins/include/sourcemod.inc	Fri Feb 16 00:04:14 2007 +0000
     6.2 +++ b/plugins/include/sourcemod.inc	Fri Feb 16 02:17:41 2007 +0000
     6.3 @@ -128,7 +128,7 @@
     6.4   * @param client		Player index.
     6.5   * @noreturn
     6.6   */
     6.7 -forward OnClientCommand(client);
     6.8 +forward OnClientCommand(client, argCount);
     6.9  
    6.10  /**
    6.11   * Called whenever the client's settings are changed.