y0mike
Active member
C++:
struct SCommandEntry
{
SCommandEntry( const std::string& cmd, int nargs, const std::function< void( const std::vector< std::string >& ) > & cb ) :
strCmd( cmd ), numArgs( nargs ), fnCallback( cb )
{
}
std::string strCmd;
int numArgs;
std::function< void( const std::vector< std::string >& ) > fnCallback;
};
static std::vector< SCommandEntry > s_cmdEntries;
void AddCommand( const char * szCmd, int numArgs, const std::function< void( const std::vector< std::string >& ) > &fnCallback )
{
s_cmdEntries.emplace_back( szCmd, numArgs, fnCallback );
}
bool iequals( const std::string& a, const std::string& b )
{
return std::equal( a.begin(), a.end(),
b.begin(), b.end(),
[ ]( char a, char b ) {
return tolower( a ) == tolower( b );
} );
}
bool __stdcall onCommandReceived( const char * strCommand )
{
// g_pCons->Write( "Command: %s\n", strCommand );
std::vector< std::string > vecArgs = SplitString( strCommand, " " );
for ( const auto & entry : s_cmdEntries ) {
if ( !vecArgs.empty() && !entry.strCmd.empty() &&
iequals( vecArgs[ 0 ].c_str(), entry.strCmd.c_str() ) )
{
// remove the first argument which is the command name (e.g /command)
vecArgs.erase( vecArgs.begin() );
// ensure that the num. of arguments matched the amount this command hsould have
int numArgs = vecArgs.size();
if ( entry.numArgs != numArgs )
return false; // todo: print return message but im lazy
// make sure the callback is valid
if ( entry.fnCallback )
{
// call it
entry.fnCallback( vecArgs );
return true;
}
}
}
return false;
}
uintptr_t _onCommandReceived_jmpBack;
uintptr_t _onCommandReceived_jmpRet;
__declspec( naked ) void __stdcall proxy_onCommandReceived() {
__asm
{
push edi
call onCommandReceived
cmp al, 1
je NoSir
mov eax, edi
mov dword ptr [ esp + 0x128 ], 0
jmp _onCommandReceived_jmpBack
NoSir:
pop edi
pop esi
jmp _onCommandReceived_jmpRet
}
}
void InitCmdCode()
{
/*
.text:00065C9A 8B C7 mov eax, edi
.text:00065C9C C7 84 24 28 01 00 00 00+ mov dword ptr [esp+128h], 0
*/
HookInstallJUMP( ( uintptr_t )GetModuleHandle( "samp.dll" ) + 0x65C9A, proxy_onCommandReceived, 11 );
_onCommandReceived_jmpBack = ( uintptr_t )GetModuleHandle( "samp.dll" ) + 0x65CA7;
_onCommandReceived_jmpRet = ( uintptr_t )GetModuleHandle( "samp.dll" ) + 0x65D15;
}
Example usage
C++:
AddCommand( "/loadcfg", 1, [ ]( const std::vector< std::string >& strArgs )
{
if ( !std::experimental::filesystem::exists( strArgs.front() ) )
return;
settings.load( strArgs.front() );
} );