#include #include #include #include #ifdef __linux__ #include #include #endif #if _MSC_VER #if _MSC_VER >= 1400 #define stricmp _stricmp #endif #endif #ifdef __linux__ #define stricmp strcasecmp #endif #ifdef _WIN32 #define VirtFuncSpawn 0 #define VirtFuncTakeDamage 12 #elif __linux__ #define VirtFuncSpawn 2 #define VirtFuncTakeDamage 14 #endif #ifdef _WIN32 #define PrivateToEdict(pPrivate) (*(entvars_t **)((char*)pPrivate + 4))->pContainingEntity #elif __linux__ #define PrivateToEdict(pPrivate) (*(entvars_t **)pPrivate)->pContainingEntity #endif plugin_info_t Plugin_info = { META_INTERFACE_VERSION, // ifvers "WPMG", // name "Alpha", // version "2011/11/7", // date "WPMG Team", // author "http://www.wpmg.ru", // url "WPMG", // logtag, all caps please PT_ANYTIME, // (when) loadable PT_ANYPAUSE // (when) unloadable }; meta_globals_t *gpMetaGlobals; mutil_funcs_t *gpMetaUtilFuncs; enginefuncs_t g_engfuncs; globalvars_t *gpGlobals; bool g_bActivated = false; bool g_bInitialized = false; void *pOrigFuncSpawn = NULL; void *pOrigFuncTakeDamage = NULL; void print_srvconsole(char *fmt, ...) { va_list argptr; static char string[384]; va_start(argptr, fmt); vsnprintf(string, sizeof(string) - 1, fmt, argptr); string[sizeof(string) - 1] = '\0'; va_end(argptr); SERVER_PRINT(string); } #ifdef _WIN32 void __fastcall HookSpawn(void *pthis) #elif __linux__ void HookSpawn(void *pthis) #endif { print_srvconsole("::Spawn(void) %d prehook!\n", ENTINDEX(PrivateToEdict(pthis))); #ifdef _WIN32 reinterpret_cast(pOrigFuncSpawn)(pthis, 0); #elif __linux__ reinterpret_cast(pOrigFuncSpawn)(pthis); #endif SERVER_PRINT("::Spawn(void) posthook!\n"); } #ifdef _WIN32 int __fastcall HookTakeDamage(void *pthis, int i, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamage) #elif __linux__ int HookTakeDamage(void *pthis, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamage) #endif { SERVER_PRINT("::TakeDamage(int) prehook!\n"); #ifdef _WIN32 int iOrigRet = reinterpret_cast(pOrigFuncTakeDamage)(pthis, 0, pevInflictor, pevAttacker, flDamage, bitsDamage); #elif __linux__ int iOrigRet = reinterpret_cast(pOrigFuncTakeDamage)(pthis, pevInflictor, pevAttacker, flDamage, bitsDamage); #endif SERVER_PRINT("::TakeDamage(int) posthook!\n"); return iOrigRet; } void MakeHookSpawn() { edict_t *pEdict = CREATE_ENTITY(); CALL_GAME_ENTITY(PLID, "player", &pEdict->v); if (pEdict->pvPrivateData == NULL) { REMOVE_ENTITY(pEdict); return; } #ifdef _WIN32 void **vtable = *((void***)((char*)pEdict->pvPrivateData)); #elif __linux__ void **vtable = *((void***)(((char*)pEdict->pvPrivateData) + 0x94)); #endif REMOVE_ENTITY(pEdict); if(vtable == NULL) return; int **ivtable = (int **)vtable; pOrigFuncSpawn = (void *)ivtable[VirtFuncSpawn]; #ifdef _WIN32 DWORD OldFlags; VirtualProtect(&ivtable[VirtFuncSpawn], sizeof(int *), PAGE_READWRITE, &OldFlags); #elif __linux__ mprotect(&ivtable[VirtFuncSpawn], sizeof(int*), PROT_READ | PROT_WRITE); #endif ivtable[VirtFuncSpawn] = (int *)HookSpawn; } void MakeHookTakeDamage() { edict_t *pEdict = CREATE_ENTITY(); CALL_GAME_ENTITY(PLID, "player", &pEdict->v); if (pEdict->pvPrivateData == NULL) { REMOVE_ENTITY(pEdict); return; } #ifdef _WIN32 void **vtable = *((void***)((char*)pEdict->pvPrivateData)); #elif __linux__ void **vtable = *((void***)(((char*)pEdict->pvPrivateData) + 0x94)); #endif REMOVE_ENTITY(pEdict); if(vtable == NULL) return; int **ivtable = (int **)vtable; pOrigFuncTakeDamage = (void *)ivtable[VirtFuncTakeDamage]; #ifdef _WIN32 DWORD OldFlags; VirtualProtect(&ivtable[VirtFuncTakeDamage], sizeof(int *), PAGE_READWRITE, &OldFlags); #elif __linux__ mprotect(&ivtable[VirtFuncTakeDamage], sizeof(int*), PROT_READ | PROT_WRITE); #endif ivtable[VirtFuncTakeDamage] = (int *)HookTakeDamage; } void ServerActivatePost(edict_t *pEdictList, int edictCount, int clientMax) { if (g_bActivated) RETURN_META(MRES_IGNORED); MakeHookSpawn(); MakeHookTakeDamage(); g_bActivated = true; RETURN_META(MRES_IGNORED); } void ServerDeactivatePost() { if (!g_bInitialized) RETURN_META(MRES_IGNORED); g_bInitialized = false; RETURN_META(MRES_IGNORED); } void ClientCommandPost(edict_t *pEntity) { const char *szArg; szArg = CMD_ARGV(0); if (stricmp(szArg, "say")) RETURN_META(MRES_IGNORED); szArg = CMD_ARGV(1); if (stricmp(szArg, "/damage")) RETURN_META(MRES_IGNORED); #ifdef _WIN32 reinterpret_cast((*((void***)((char*)pEntity->pvPrivateData)))[VirtFuncTakeDamage])(pEntity->pvPrivateData, 0, &(pEntity->v), &(pEntity->v), 50.0, DMG_SLASH); #elif defined __linux__ reinterpret_cast((*((void***)(((char*)pEntity->pvPrivateData) + 0x94)))[VirtFuncTakeDamage])(pEntity->pvPrivateData, &(pEntity->v), &(pEntity->v), 50.0, DMG_SLASH); #endif RETURN_META(MRES_IGNORED); } int SpawnPre(edict_t *pEnt) { if (g_bInitialized) RETURN_META_VALUE(MRES_IGNORED, 0); g_bActivated = false; g_bInitialized = true; RETURN_META_VALUE(MRES_IGNORED, 0); } C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) { gpMetaUtilFuncs = pMetaUtilFuncs; *pPlugInfo = &Plugin_info; return(TRUE); } static META_FUNCTIONS gMetaFunctionTable; C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) { gpMetaGlobals = pMGlobals; gMetaFunctionTable.pfnGetEntityAPI2 = GetEntityAPI2; gMetaFunctionTable.pfnGetEntityAPI2_Post = GetEntityAPI2_Post; memcpy(pFunctionTable, &gMetaFunctionTable, sizeof(META_FUNCTIONS)); return(TRUE); } #ifdef __linux__ // linux prototype C_DLLEXPORT void GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals) { #else #ifdef _MSC_VER // MSVC: Simulate __stdcall calling convention C_DLLEXPORT __declspec(naked) void GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals) { __asm // Prolog { // Save ebp push ebp // Set stack frame pointer mov ebp, esp // Allocate space for local variables // The MSVC compiler gives us the needed size in __LOCAL_SIZE. sub esp, __LOCAL_SIZE // Push registers push ebx push esi push edi } #else // _MSC_VER #ifdef __GNUC__ // GCC can also work with this C_DLLEXPORT void __stdcall GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals) { #else // __GNUC__ // compiler not known #error There is no support (yet) for your compiler. Please use MSVC or GCC compilers or contact the AMX Mod X dev team. #endif // __GNUC__ #endif // _MSC_VER #endif // __linux__ // ** Function core <-- memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); gpGlobals = pGlobals; // --> ** Function core #ifdef _MSC_VER // Epilog if (sizeof(int*) == 8) { // 64 bit __asm { // Pop registers pop edi pop esi pop ebx // Restore stack frame pointer mov esp, ebp // Restore ebp pop ebp // 2 * sizeof(int*) = 16 on 64 bit ret 16 } } else { // 32 bit __asm { // Pop registers pop edi pop esi pop ebx // Restore stack frame pointer mov esp, ebp // Restore ebp pop ebp // 2 * sizeof(int*) = 8 on 32 bit ret 8 } } #endif // #ifdef _MSC_VER } DLL_FUNCTIONS gFunctionTable; C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion) { memset(&gFunctionTable, 0, sizeof(DLL_FUNCTIONS)); gFunctionTable.pfnSpawn = SpawnPre; memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS)); return 1; } DLL_FUNCTIONS gFunctionTable_Post; C_DLLEXPORT int GetEntityAPI2_Post(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion) { memset(&gFunctionTable_Post, 0, sizeof(DLL_FUNCTIONS)); gFunctionTable_Post.pfnServerActivate = ServerActivatePost; gFunctionTable_Post.pfnServerDeactivate = ServerDeactivatePost; gFunctionTable_Post.pfnClientCommand = ClientCommandPost; memcpy(pFunctionTable, &gFunctionTable_Post, sizeof(DLL_FUNCTIONS)); return 1; }