1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-03-22 13:19:40 +01:00

more filling in of the provider for episode1

--HG--
branch : sourcemm-1.6.0
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/branches/sourcemm-1.6.0%40433
This commit is contained in:
David Anderson 2007-09-27 20:43:03 +00:00
parent 194b42b0f2
commit cc18058a51
2 changed files with 243 additions and 2 deletions

View File

@ -1,23 +1,41 @@
#include "convar_smm.h"
#include <eiface.h>
#include <tier0/icommandline.h>
#include <tier1/utldict.h>
#include <sourcehook/sourcehook.h>
#include <sh_vector.h>
#include <sh_string.h>
#include "provider_util.h"
#include "provider_ep1.h"
#include "console.h"
/* Types */
typedef void (*CONPRINTF_FUNC)(const char *, ...);
struct UsrMsgInfo
{
int size;
String name;
};
/* Imports */
#undef CommandLine
DLL_IMPORT ICommandLine *CommandLine();
/* Functions */
CONPRINTF_FUNC ExtractRemotePrinter();
bool CacheUserMessages();
void ClientCommand(edict_t *pEdict);
/* Variables */
bool usermsgs_extracted = false;
CVector<UsrMsgInfo> usermsgs_list;
CONPRINTF_FUNC echo_msg_func = NULL;
METAMOD_COMMAND client_cmd_handler = NULL;
ICvar *icvar = NULL;
ISourceHook *g_SHPtr = NULL;
IVEngineServer *engine = NULL;
IServerGameDLL *server = NULL;
ICvar *icvar = NULL;
IServerGameClients *gameclients = NULL;
unsigned int g_PLID;
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
void BaseProvider::ConsolePrint(const char *str)
{
@ -34,6 +52,9 @@ void BaseProvider::ConsolePrint(const char *str)
void BaseProvider::Notify_DLLInit_Pre()
{
echo_msg_func = ExtractRemotePrinter();
usermsgs_extracted = CacheUserMessages();
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false);
}
bool BaseProvider::IsRemotePrintingAvailable()
@ -177,6 +198,91 @@ void BaseProvider::UnregisterConCommandBase(ConCommandBase *pCommand)
return g_SMConVarAccessor.Unregister(pCommand);
}
int BaseProvider::GetUserMessageCount()
{
if (!usermsgs_extracted)
{
return -1;
}
return (int)usermsgs_list.size();
}
int BaseProvider::FindUserMessage(const char *name, int *size)
{
for (size_t i = 0; i < usermsgs_list.size(); i++)
{
if (usermsgs_list[i].name.compare(name) == 0)
{
if (size)
{
*size = usermsgs_list[i].size;
}
return (int)i;
}
}
return -1;
}
const char *BaseProvider::GetUserMessage(int index, int *size)
{
if (!usermsgs_extracted || index < 0 || index >= (int)usermsgs_list.size())
{
return NULL;
}
if (size)
{
*size = usermsgs_list[index].size;
}
return usermsgs_list[index].name.c_str();
}
const char *BaseProvider::GetGameDescription()
{
return server->GetGameDescription();
}
void BaseProvider::SetClientCommandHandler(METAMOD_COMMAND callback)
{
client_cmd_handler = callback;
}
class GlobCommand : public IMetamodSourceCommandInfo
{
public:
unsigned int GetArgCount()
{
return engine->Cmd_Argc() - 1;
}
const char *GetArg(unsigned int num)
{
return engine->Cmd_Argv(num);
}
const char *GetArgString()
{
return engine->Cmd_Args();
}
};
void ClientCommand(edict_t *pEdict)
{
if (client_cmd_handler)
{
GlobCommand cmd;
bool result;
if ((result = client_cmd_handler(pEdict, &cmd)) == true)
{
RETURN_META(MRES_SUPERCEDE);
}
}
}
//////////////////////////////////////////////////////////////////////////
//THERE BE HAX HERE!!!! DON'T TELL ALFRED, BUT GABE WANTED IT THAT WAY. //
// (note: you can find the offset by looking for the text //
@ -203,9 +309,13 @@ bool vcmp(const void *_addr1, const void *_addr2, size_t len)
for (size_t i=0; i<len; i++)
{
if (addr2[i] == '*')
{
continue;
}
if (addr1[i] != addr2[i])
{
return false;
}
}
return true;
@ -222,7 +332,7 @@ CONPRINTF_FUNC ExtractRemotePrinter()
while (pBase)
{
if ( strcmp(pBase->GetName(), "echo") == 0 )
if (strcmp(pBase->GetName(), "echo") == 0)
{
callback = ((ConCommand *)pBase)->GetCallback();
ptr = (unsigned char *)callback;
@ -261,4 +371,132 @@ CONPRINTF_FUNC ExtractRemotePrinter()
return NULL;
}
//////////////////////////////////////////////////////////////////////
// EVEN MORE HACKS HERE! YOU HAVE BEEN WARNED! //
// Signatures necessary in finding the pointer to the CUtlDict that //
// stores user message information. //
// IServerGameDLL::GetUserMessageInfo() normally crashes with bad //
// message indices. This is our answer to it. Yuck! <:-( //
//////////////////////////////////////////////////////////////////////
#ifdef OS_WIN32
/* General Windows sig */
#define MSGCLASS_SIGLEN 7
#define MSGCLASS_SIG "\x8B\x0D\x2A\x2A\x2A\x2A\x56"
#define MSGCLASS_OFFS 2
/* Dystopia Wimdows hack */
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x56\x8B\x74\x24\x2A\x85\xF6\x7C\x2A\x3B\x35\x2A\x2A\x2A\x2A\x7D"
#define MSGCLASS2_OFFS 11
/* Windows frame pointer sig */
#define MSGCLASS3_SIGLEN 18
#define MSGCLASS3_SIG "\x55\x8B\xEC\x51\x89\x2A\x2A\x8B\x2A\x2A\x50\x8B\x0D\x2A\x2A\x2A\x2A\xE8"
#define MSGCLASS3_OFFS 13
#elif defined OS_LINUX
/* No frame pointer sig */
#define MSGCLASS_SIGLEN 14
#define MSGCLASS_SIG "\x53\x83\xEC\x2A\x8B\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x89"
#define MSGCLASS_OFFS 9
/* Frame pointer sig */
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x55\x89\xE5\x53\x83\xEC\x2A\x8B\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x89"
#define MSGCLASS2_OFFS 11
#endif
struct UserMessage
{
int size;
const char *name;
};
typedef CUtlDict<UserMessage *, int> UserMsgDict;
/* This is the ugliest function in all of SourceMM */
bool CacheUserMessages()
{
/* Get address of original GetUserMessageInfo() */
char *vfunc = NULL;
/* :TODO: fix this for v5 (char *)SH_GET_ORIG_VFNPTR_ENTRY(server, &IServerGameDLL::GetUserMessageInfo); */
/* Oh dear, we have a relative jump on our hands
* PVK II on Windows made me do this, but I suppose it doesn't hurt to check this on Linux too...
*/
if (*vfunc == '\xE9')
{
/* Get address from displacement...
*
* Add 5 because it's relative to next instruction:
* Opcode <1 byte> + 32-bit displacement <4 bytes>
*/
vfunc += *reinterpret_cast<int *>(vfunc + 1) + 5;
}
CUtlDict<UserMessage *, int> *dict = NULL;
if (vcmp(vfunc, MSGCLASS_SIG, MSGCLASS_SIGLEN))
{
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
}
else if (vcmp(vfunc, MSGCLASS2_SIG, MSGCLASS2_SIGLEN))
{
#ifdef OS_WIN32
/* If we get here, the code is possibly inlined like in Dystopia */
/* Get the address of the CUtlRBTree */
char *rbtree = *reinterpret_cast<char **>(vfunc + MSGCLASS2_OFFS);
/* CUtlDict should be 8 bytes before the CUtlRBTree (hacktacular!) */
dict = reinterpret_cast<UserMsgDict *>(rbtree - 8);
#elif defined OS_LINUX
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS2_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
#ifdef OS_WIN32
}
else if (vcmp(vfunc, MSGCLASS3_SIG, MSGCLASS3_SIGLEN))
{
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS3_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
}
if (dict)
{
int msg_count = dict->Count();
/* Ensure that count is within bounds of an unsigned byte, because that's what engine supports */
if (msg_count < 0 || msg_count > 255)
{
return false;
}
UserMessage *msg;
UsrMsgInfo u_msg;
/* Cache messages in our CUtlDict */
for (int i = 0; i < msg_count; i++)
{
msg = dict->Element(i);
u_msg.name = msg->name;
u_msg.size = msg->size;
usermsgs_list.push_back(u_msg);
}
return true;
}
return false;
}

View File

@ -3,8 +3,10 @@
#include <metamod_provider.h>
#include <ISmmAPI.h>
#include "oslink.h"
using namespace SourceMM;
using namespace SourceHook;
class BaseProvider : public IMetamodSourceProvider
{
@ -43,6 +45,7 @@ public:
extern IVEngineServer *engine;
extern IServerGameDLL *server;
extern IServerGameClients *gameclients;
extern ICvar *icvar;
#endif //_INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_