Код
#include "extdll.h"
#include "meta_api.h"
#undef C_DLLEXPORT
#ifdef __linux__
#include <sys/mman.h>
#define C_DLLEXPORT extern "C" __attribute__((visibility("default")))
#else
#define C_DLLEXPORT extern "C" __declspec(dllexport)
#endif
#define HUD_PRINTRADIO 5
enum {
PF_messageBegin,
PF_messageByte,
PF_messageString,
PF_messageEnd,
PF_Last
};
typedef struct message_s {
BOOL doneSay;
BOOL doneText;
char *str[5];
int argNum;
int sayTextId;
int textMsgId;
} message_t;
typedef struct hooks_s {
void *address;
void *handler;
unsigned char patchBytes[5];
unsigned char originalBytes[5];
} hooks_t;
hooks_t hookMessage[PF_Last];
message_t eventMessage;
plugin_info_t Plugin_info = {
META_INTERFACE_VERSION,
"ChatFix",
"1.4",
"10/08/14",
"s1lent",
"http://www.aghl.ru/",
"ChatFix",
PT_STARTUP,
PT_NEVER,
};
DLL_FUNCTIONS gpFunctionTable;
enginefuncs_t g_engfuncs;
enginefuncs_t g_engfuncs_post;
meta_globals_t *gpMetaGlobals;
gamedll_funcs_t *gpGamedllFuncs;
mutil_funcs_t *gpMetaUtilFuncs;
globalvars_t *gpGlobals;
META_FUNCTIONS gMetaFunctionTable;
C_DLLEXPORT int Meta_Query(char *,plugin_info_t **pPlugInfo,mutil_funcs_t *pMetaUtilFuncs) {
*pPlugInfo = &Plugin_info;
gpMetaUtilFuncs = pMetaUtilFuncs;
return TRUE;
}
BOOL allowMemoryPatch(void *ptr) {
#ifdef __linux__
void *addr = (void *)((long)ptr & ~(4096 - 1));
return !mprotect(addr,sysconf(_SC_PAGESIZE),(PROT_READ|PROT_WRITE|PROT_EXEC));
#else
static DWORD oldProtection;
return VirtualProtect(ptr,5,PAGE_EXECUTE_READWRITE,&oldProtection);
#endif
}
BOOL doPatch(hooks_t *a) {
if(allowMemoryPatch(a->address)) {
memcpy(a->address,a->patchBytes,5);
}
return TRUE;
}
BOOL undoPatch(hooks_t *a) {
if(allowMemoryPatch(a->address)) {
memcpy(a->address,a->originalBytes,5);
}
return TRUE;
}
inline void T_MESSAGE_BEGIN(int msg_dest,int msg_type,const float *pOrigin = NULL,edict_t *ed = NULL) {
hooks_t *a = &hookMessage[PF_messageBegin];
if(undoPatch(a)) {
reinterpret_cast<void (*)(int,int,const float *,edict_t *)>(a->address)(msg_dest,msg_type,pOrigin,ed);
doPatch(a);
}
}
inline void T_WRITE_BYTE(int iValue) {
hooks_t *a = &hookMessage[PF_messageByte];
if(undoPatch(a)) {
reinterpret_cast<void (*)(int)>(a->address)(iValue);
doPatch(a);
}
}
inline void T_WRITE_STRING(const char *szString) {
hooks_t *a = &hookMessage[PF_messageString];
if(undoPatch(a)) {
reinterpret_cast<void (*)(const char *)>(a->address)(szString);
doPatch(a);
}
}
inline void T_MESSAGE_END() {
hooks_t *a = &hookMessage[PF_messageEnd];
if(undoPatch(a)) {
reinterpret_cast<void (*)()>(a->address)();
doPatch(a);
}
}
void MessageBegin(int msg_dest,int msg_type,const float *pOrigin,edict_t *ed) {
message_t *p = &eventMessage;
if(p->sayTextId == msg_type) {
for(unsigned int i = 0; i < (sizeof(p->str) / sizeof(p->str[0]) - 1); i++) {
*(p->str[i]) = '\0';
}
p->argNum = 0;
p->doneSay = TRUE;
}
else if(p->textMsgId == msg_type) {
for(unsigned int i = 0; i < (sizeof(p->str) / sizeof(p->str[0]) - 1); i++) {
*(p->str[i]) = '\0';
}
p->argNum = 0;
p->doneText = TRUE;
}
T_MESSAGE_BEGIN(msg_dest,msg_type,pOrigin,ed);
};
void WriteByte(int iValue) {
message_t *p = &eventMessage;
if(p->doneText) {
if(iValue != HUD_PRINTTALK && iValue != HUD_PRINTRADIO) {
p->doneText = FALSE;
}
}
T_WRITE_BYTE(iValue);
};
void WriteString(const char *szString) {
message_t *p = &eventMessage;
if(p->doneSay || p->doneText) {
if(!p->argNum && *(szString) == '#') {
if(p->doneSay) {
p->doneSay = FALSE;
}
if(p->doneText) {
p->doneText = FALSE;
}
T_WRITE_STRING(szString);
return;
}
strcpy(p->str[p->argNum],szString);
*(p->str[p->argNum++] + 186) = '\0';
return;
}
T_WRITE_STRING(szString);
};
void MessageEnd() {
message_t *p = &eventMessage;
if(p->argNum) {
if(p->doneSay) {
switch(p->argNum) {
case 1: {
T_WRITE_STRING("%s");
T_WRITE_STRING((const char *)p->str[0]);
break;
}
case 2: {
T_WRITE_STRING((const char *)p->str[0]);
T_WRITE_STRING((const char *)p->str[1]);
break;
}
case 3: {
T_WRITE_STRING((const char *)p->str[0]);
T_WRITE_STRING((const char *)p->str[1]);
T_WRITE_STRING((const char *)p->str[2]);
break;
}
default: {
break;
}
}
p->doneSay = FALSE;
}
else if(p->doneText) {
switch(p->argNum) {
case 1: {
char *str = const_cast<char *>(p->str[0]);
if(!str) {
break;
}
int i = 0;
BOOL bHashLocaliz = FALSE;
BOOL bBottomLine = FALSE;
char *phaystack = new char[187];
for(;*str; *(str++), i++) {
if(!bHashLocaliz && (*str == '#')) {
bHashLocaliz = TRUE;
}
else if(bHashLocaliz) {
if(bBottomLine && (*str == 0x20)) {
bHashLocaliz = FALSE;
bBottomLine = FALSE;
*(phaystack + (i++)) = 0xA0;
}
else if(!bBottomLine && (*str == 0x5F)) {
bBottomLine = TRUE;
}
}
*(phaystack + i) = *str;
}
*(phaystack + i) = *(phaystack + 186) = '\0';
T_WRITE_STRING((const char *)phaystack);
delete[] phaystack;
break;
}
case 2: {
T_WRITE_STRING((const char *)p->str[0]);
T_WRITE_STRING((const char *)p->str[1]);
break;
}
case 3: {
T_WRITE_STRING((const char *)p->str[0]);
T_WRITE_STRING((const char *)p->str[1]);
T_WRITE_STRING((const char *)p->str[2]);
break;
}
case 4: {
T_WRITE_STRING((const char *)p->str[0]);
T_WRITE_STRING((const char *)p->str[1]);
T_WRITE_STRING((const char *)p->str[2]);
T_WRITE_STRING((const char *)p->str[3]);
break;
}
case 5: {
T_WRITE_STRING((const char *)p->str[0]);
T_WRITE_STRING((const char *)p->str[1]);
T_WRITE_STRING((const char *)p->str[2]);
T_WRITE_STRING((const char *)p->str[3]);
T_WRITE_STRING((const char *)p->str[4]);
break;
}
default: {
break;
}
}
p->doneText = FALSE;
}
}
T_MESSAGE_END();
}
int RegUserMsg_Post(const char *szName,int)
{
message_t *p = &eventMessage;
if(!strcmp(szName,"SayText")) {
p->sayTextId = META_RESULT_ORIG_RET(int);
}
else if(!strcmp(szName,"TextMsg")) {
p->textMsgId = META_RESULT_ORIG_RET(int);
}
RETURN_META_VALUE(MRES_IGNORED,0);
}
C_DLLEXPORT int GetEngineFunctions_Post(enginefuncs_t *pengfuncsFromEngine,int *interfaceVersion) {
memset(&g_engfuncs_post,0,sizeof(enginefuncs_t));
g_engfuncs_post.pfnRegUserMsg = RegUserMsg_Post;
memcpy(pengfuncsFromEngine,&g_engfuncs_post,sizeof(enginefuncs_t));
return TRUE;
}
C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now,META_FUNCTIONS *pFunctionTable,meta_globals_t *pMGlobals,gamedll_funcs_t *pGamedllFuncs) {
if(!pMGlobals) {
return FALSE;
}
gpMetaGlobals = pMGlobals;
if(!pFunctionTable) {
return FALSE;
}
gpGamedllFuncs = pGamedllFuncs;
void *r[] = {
(void *)(*g_engfuncs.pfnMessageBegin), (void *)MessageBegin,
(void *)(*g_engfuncs.pfnWriteByte), (void *)WriteByte,
(void *)(*g_engfuncs.pfnWriteString), (void *)WriteString,
(void *)(*g_engfuncs.pfnMessageEnd), (void *)MessageEnd
};
message_t *p = &eventMessage;
for(unsigned int i = 0; i < (sizeof(p->str) / sizeof(p->str[0]) - 1); i++) {
p->str[i] = new char[187];
}
hooks_t *a = NULL;
for(int j = 0; j < PF_Last * 2; j += 2) {
a = &hookMessage[j / 2];
a->address = r[j];
a->handler = r[j + 1];
a->patchBytes[0] = 0xE9;
// hooks of jump
*((unsigned long *)(&a->patchBytes[1])) = (unsigned long)a->handler - (unsigned long)a->address - 5;
memcpy(a->originalBytes,(void *)a->address,5);
if(allowMemoryPatch(a->address)) {
memcpy(a->address,a->patchBytes,5);
}
}
gMetaFunctionTable.pfnGetEngineFunctions_Post = GetEngineFunctions_Post;
memcpy(pFunctionTable,&gMetaFunctionTable,sizeof(META_FUNCTIONS));
return TRUE;
}
C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now,PL_UNLOAD_REASON reason) {
return FALSE;
}
#ifdef __linux__
C_DLLEXPORT void GiveFnptrsToDll(enginefuncs_t *pengfuncsFromEngine,globalvars_t *pGlobals) {
#else
#ifdef _MSC_VER
C_DLLEXPORT __declspec(naked) void GiveFnptrsToDll(enginefuncs_t *pengfuncsFromEngine,globalvars_t *pGlobals) {
__asm {
push ebp
mov ebp,esp
sub esp,__LOCAL_SIZE
push ebx
push esi
push edi
}
#else // _MSC_VER
#ifdef __GNUC__
C_DLLEXPORT void __stdcall GiveFnptrsToDll(enginefuncs_t *pengfuncsFromEngine,globalvars_t *pGlobals) {
#else
#error There is no support (yet) for your compiler. Please use MSVC or GCC compilers.
#endif
#endif // _MSC_VER
#endif // __linux__
memcpy(&g_engfuncs,pengfuncsFromEngine,sizeof(enginefuncs_t));
gpGlobals = pGlobals;
#ifdef _MSC_VER
if(sizeof(int *) == 8) {
__asm {
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret 16
}
}
else {
__asm {
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret 8
}
}
#endif // #ifdef _MSC_VER
}