View Single Post
Author Message
XAD
Senior Member
Join Date: Mar 2004
Location: Sweden
Old 01-21-2005 , 11:37   YACCH: Simple ConCommand hooking...
Reply With Quote #1

Well, as people will need to hook ConCommand (due to autobuy) I thought I would share my version of hooking ConCommand, which make the coding a hook almost the same as a regular ConCommand...

Example to hook 'say'...
Code:
extern ICvar *g_pCVar;

PLUGIN_CON_COMMAND_F( say, "Display player message", FCVAR_GAMEDLL )
{
	... your code ...
	if( ... do not call original function ... )
		return PLUGIN_STOP;

	return PLUGIN_CONTINUE;
}
NOTE! If you create multiple hooks they will be called in the order declared. Between different server plugins I don't know as I haven't tested it.
NOTE2! I have only tested this on linux... please let me know if it works on windows...

/X

PS! The name of the class should probably be something else than plugin but that's what I started with...

The header file...
Code:
//-----------------------------------------------------------------------------
// Purpose: Support command hook, requires g_pCVar to be allocated.
// NOTE! Default ICvar allocation is 'g_pCVar'. 
//       To use a different pointer name define "ENGINEVAR" before
//       including this header file.
//-----------------------------------------------------------------------------
#ifndef ENGINECVAR
#define ENGINECVAR (g_pCVar)
#endif

extern ICvar *ENGINECVAR;

#define PLUGIN_CON_COMMAND( name, description ) \
   static PLUGIN_RESULT name(); \
   static PluginConCommand name##_command( #name, name, description ); \
   static PLUGIN_RESULT name()

#define PLUGIN_CON_COMMAND_F( name, description, flags ) \
   static PLUGIN_RESULT name(); \
   static PluginConCommand name##_command( #name, name, description, flags ); \
   static PLUGIN_RESULT name()

// Called when a ConCommand needs to execute 
// (return with PLUGIN_CONTINUE to call original function)
typedef PLUGIN_RESULT (*FnPluginCommandCallback)( void );

// Special ConCommand to hook commands
class PluginConCommand : public ConCommand
{ 
friend class ConCommandBaseMgr;
friend class CCvar;

public: 
	PluginConCommand( void ) : ConCommand() { Create(); }
	PluginConCommand( char const *pName, FnPluginCommandCallback fnCallback, 
	                  char const *pHelpString = 0, int flags = 0, 
	                  FnCommandCompletionCallback completionFunc = 0 )
	                : ConCommand( pName, NULL, pHelpString, flags, completionFunc )
	                { Create( pName, fnCallback ); }

	// Invoke the original function
	virtual void Dispatch( void )
	{
		if( m_fnPluginCommandCallback && (*m_fnPluginCommandCallback)() != PLUGIN_CONTINUE )
			return;
		if ( m_pConCommandOriginal && m_pConCommandOriginal->IsCommand() )
			m_pConCommandOriginal->Dispatch();
	}

protected:

	virtual void Create( const char *pName = NULL, FnPluginCommandCallback fnCallback = NULL )
	{
		m_fnPluginCommandCallback = fnCallback;
		m_pConCommandOriginal     = NULL;
	}

	// Override Init
	virtual void Init( void )
	{
		if( ! m_pConCommandOriginal )
		{
			const char *name = GetName();
			if( name && name[0] )
			{
				// Search the engine command list
				ConCommandBase const *cmd = NULL;
				if( ENGINECVAR )
					cmd = ENGINECVAR->GetCommands();
				for ( ; cmd && stricmp( name, cmd->GetName() ); cmd = cmd->GetNext() )
					{}
				if( cmd && cmd != this && cmd->IsCommand() )
				{
					m_pConCommandOriginal = (ConCommand*) cmd;
					Msg( "[%s] Plugin created hook on command \"%s\"\n",
					     VNAME, cmd->GetName() );
				}
			}
		}
		ConCommand::Init();
	}

protected:

	// This will hold the new callback pointer
	FnPluginCommandCallback     m_fnPluginCommandCallback;

	// This will hold a pointer to the original command
	ConCommand                 *m_pConCommandOriginal;
};
XAD is offline