mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-02-20 13:54:14 +01:00
merged 1.6.0 -> trunk
--HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40456
This commit is contained in:
parent
afbd6cc123
commit
6fea65ae4b
@ -1,6 +1,6 @@
|
||||
[PRODUCT]
|
||||
major = 1
|
||||
minor = 5
|
||||
minor = 6
|
||||
revision = 0
|
||||
|
||||
[sourcemm]
|
||||
|
@ -1,662 +0,0 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#include "convar_smm.h"
|
||||
#include "CSmmAPI.h"
|
||||
#include "sourcemm.h"
|
||||
#include "concommands.h"
|
||||
#include "CPlugin.h"
|
||||
#include "vsp_listener.h"
|
||||
|
||||
/**
|
||||
* @brief Implementation of main API interface
|
||||
* @file CSmmAPI.cpp
|
||||
*/
|
||||
|
||||
using namespace SourceMM;
|
||||
|
||||
CSmmAPI g_SmmAPI;
|
||||
|
||||
CSmmAPI::CSmmAPI()
|
||||
{
|
||||
m_ConPrintf = NULL;
|
||||
m_CmdCache = false;
|
||||
m_MsgCount = -1;
|
||||
m_VSP = false;
|
||||
}
|
||||
|
||||
CSmmAPI::~CSmmAPI()
|
||||
{
|
||||
m_UserMessages.RemoveAll();
|
||||
}
|
||||
|
||||
void CSmmAPI::LogMsg(ISmmPlugin *pl, const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
static char buffer[2048];
|
||||
|
||||
va_start(ap, msg);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
LogMessage("[%s] %s", pl->GetLogTag(), buffer);
|
||||
}
|
||||
|
||||
CreateInterfaceFn CSmmAPI::engineFactory(bool syn)
|
||||
{
|
||||
if (syn)
|
||||
return EngineFactory;
|
||||
return g_Engine.engineFactory;
|
||||
}
|
||||
|
||||
CreateInterfaceFn CSmmAPI::physicsFactory(bool syn)
|
||||
{
|
||||
if (syn)
|
||||
return PhysicsFactory;
|
||||
return g_Engine.physicsFactory;
|
||||
}
|
||||
|
||||
CreateInterfaceFn CSmmAPI::fileSystemFactory(bool syn)
|
||||
{
|
||||
if (syn)
|
||||
return FileSystemFactory;
|
||||
return g_Engine.fileSystemFactory;
|
||||
}
|
||||
|
||||
CreateInterfaceFn CSmmAPI::serverFactory(bool syn)
|
||||
{
|
||||
if (syn)
|
||||
return CreateInterface;
|
||||
return g_GameDll.factory;
|
||||
}
|
||||
|
||||
CGlobalVars *CSmmAPI::pGlobals()
|
||||
{
|
||||
return g_Engine.pGlobals;
|
||||
}
|
||||
|
||||
void CSmmAPI::SetLastMetaReturn(META_RES res)
|
||||
{
|
||||
m_Res = res;
|
||||
}
|
||||
|
||||
META_RES CSmmAPI::GetLastMetaReturn()
|
||||
{
|
||||
return m_Res;
|
||||
}
|
||||
|
||||
IConCommandBaseAccessor *CSmmAPI::GetCvarBaseAccessor()
|
||||
{
|
||||
return static_cast<IConCommandBaseAccessor *>(&g_SMConVarAccessor);
|
||||
}
|
||||
|
||||
bool CSmmAPI::RegisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand)
|
||||
{
|
||||
if (pCommand->IsCommand())
|
||||
{
|
||||
g_PluginMngr.AddPluginCmd(plugin, pCommand);
|
||||
} else {
|
||||
g_PluginMngr.AddPluginCvar(plugin, pCommand);
|
||||
}
|
||||
|
||||
return g_SMConVarAccessor.Register(pCommand);
|
||||
}
|
||||
|
||||
void CSmmAPI::UnregisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand)
|
||||
{
|
||||
if (pCommand->IsCommand())
|
||||
{
|
||||
g_PluginMngr.RemovePluginCmd(plugin, pCommand);
|
||||
} else {
|
||||
g_PluginMngr.RemovePluginCvar(plugin, pCommand);
|
||||
}
|
||||
|
||||
g_SMConVarAccessor.Unregister(g_PluginMngr.FindByAPI(plugin)->m_Id, pCommand);
|
||||
}
|
||||
|
||||
void CSmmAPI::ConPrint(const char *fmt)
|
||||
{
|
||||
(m_ConPrintf)("%s", fmt);
|
||||
}
|
||||
|
||||
void CSmmAPI::ConPrintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
static char buffer[4096];
|
||||
|
||||
va_start(ap, fmt);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
(m_ConPrintf)("%s", buffer);
|
||||
}
|
||||
|
||||
void CSmmAPI::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener)
|
||||
{
|
||||
CPluginManager::CPlugin *pl = g_PluginMngr.FindByAPI(plugin);
|
||||
|
||||
pl->m_Events.push_back(pListener);
|
||||
}
|
||||
|
||||
void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
|
||||
{
|
||||
if (id)
|
||||
{
|
||||
*id = 0;
|
||||
}
|
||||
|
||||
if (!iface)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//first check ours... we get first chance!
|
||||
if (strcmp(iface, MMIFACE_SOURCEHOOK) == 0)
|
||||
{
|
||||
if (_ret)
|
||||
{
|
||||
*_ret = IFACE_OK;
|
||||
}
|
||||
return static_cast<void *>(static_cast<SourceHook::ISourceHook *>(&g_SourceHook));
|
||||
} else if (strcmp(iface, MMIFACE_PLMANAGER) == 0) {
|
||||
if (_ret)
|
||||
{
|
||||
*_ret = IFACE_OK;
|
||||
}
|
||||
return static_cast<void *>(static_cast<ISmmPluginManager *>(&g_PluginMngr));
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin *pl;
|
||||
SourceHook::List<IMetamodListener *>::iterator event;
|
||||
IMetamodListener *api;
|
||||
int ret = 0;
|
||||
void *val = NULL;
|
||||
|
||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++)
|
||||
{
|
||||
pl = (*iter);
|
||||
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++)
|
||||
{
|
||||
api = (*event);
|
||||
ret = IFACE_FAILED;
|
||||
if ( (val=api->OnMetamodQuery(iface, &ret)) != NULL )
|
||||
{
|
||||
if (_ret)
|
||||
*_ret = ret;
|
||||
if (id)
|
||||
*id = pl->m_Id;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_ret)
|
||||
*_ret = IFACE_FAILED;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//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 //
|
||||
// "Echo text to console", you'll find the callback cmd pushed on the //
|
||||
// stack.) //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define SIGLEN 8
|
||||
#define ENGINE486_SIG "\x55\x89\xE5\x53\x83\xEC\x14\xBB"
|
||||
#define ENGINE486_OFFS 40
|
||||
#define ENGINE686_SIG "\x53\x83\xEC\x08\xBB\x01\x00\x00"
|
||||
#define ENGINE686_OFFS 50
|
||||
#define ENGINEAMD_SIG "\x53\x51\xBB\x01\x00\x00\x00\x51"
|
||||
#define ENGINEAMD_OFFS 47
|
||||
#define ENGINEW32_SIG "\xA1\x2A\x2A\x2A\x2A\x56\xBE\x01"
|
||||
#define ENGINEW32_OFFS 38
|
||||
#define IA32_CALL 0xE8
|
||||
|
||||
bool vcmp(const void *_addr1, const void *_addr2, size_t len)
|
||||
{
|
||||
unsigned char *addr1 = (unsigned char *)_addr1;
|
||||
unsigned char *addr2 = (unsigned char *)_addr2;
|
||||
|
||||
for (size_t i=0; i<len; i++)
|
||||
{
|
||||
if (addr2[i] == '*')
|
||||
continue;
|
||||
if (addr1[i] != addr2[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Thanks to fysh for the idea of extracting info from "echo" and for
|
||||
// having the original offsets at hand!
|
||||
bool CSmmAPI::CacheCmds()
|
||||
{
|
||||
ICvar *pCvar = g_Engine.icvar;
|
||||
|
||||
ConCommandBase *pBase = pCvar->GetCommands();
|
||||
unsigned char *ptr = NULL;
|
||||
FnCommandCallback callback = NULL;
|
||||
int offs = 0;
|
||||
|
||||
while (pBase)
|
||||
{
|
||||
if ( strcmp(pBase->GetName(), "echo") == 0 )
|
||||
{
|
||||
//callback = //*((FnCommandCallback *)((char *)pBase + offsetof(ConCommand, m_fnCommandCallback)));
|
||||
callback = ((ConCommand *)pBase)->GetCallback();
|
||||
ptr = (unsigned char *)callback;
|
||||
#ifdef OS_LINUX
|
||||
if (vcmp(ptr, ENGINE486_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINE486_OFFS;
|
||||
}
|
||||
else if (vcmp(ptr, ENGINE686_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINE686_OFFS;
|
||||
}
|
||||
else if (vcmp(ptr, ENGINEAMD_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINEAMD_OFFS;
|
||||
}
|
||||
#elif defined OS_WIN32 // Only one Windows engine binary so far...
|
||||
if (vcmp(ptr, ENGINEW32_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINEW32_OFFS;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!offs || ptr[offs - 1] != IA32_CALL)
|
||||
{
|
||||
m_ConPrintf = (CONPRINTF_FUNC)Msg;
|
||||
return false;
|
||||
}
|
||||
//get the relative offset
|
||||
m_ConPrintf = *((CONPRINTF_FUNC *)(ptr + offs));
|
||||
//add the base offset, to the ip (which is the address+offset + 4 bytes for next instruction)
|
||||
m_ConPrintf = (CONPRINTF_FUNC)((unsigned long)m_ConPrintf + (unsigned long)(ptr + offs) + 4);
|
||||
|
||||
m_CmdCache = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
|
||||
}
|
||||
|
||||
m_ConPrintf = (CONPRINTF_FUNC)Msg;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSmmAPI::CmdCacheSuccessful()
|
||||
{
|
||||
return m_CmdCache;
|
||||
}
|
||||
|
||||
void CSmmAPI::GetApiVersions(int &major, int &minor, int &plvers, int &plmin)
|
||||
{
|
||||
major = SM_VERS_API_MAJOR;
|
||||
minor = SM_VERS_API_MINOR;
|
||||
plvers = PLAPI_VERSION;
|
||||
plmin = PLAPI_MIN_VERSION;
|
||||
}
|
||||
|
||||
void CSmmAPI::GetShVersions(int &shvers, int &shimpl)
|
||||
{
|
||||
shvers = SH_IFACE_VERSION;
|
||||
shimpl = SH_IMPL_VERSION;
|
||||
}
|
||||
|
||||
int CSmmAPI::FormatIface(char iface[], unsigned int maxlength)
|
||||
{
|
||||
int length = (int)strlen(iface);
|
||||
int i;
|
||||
int num = 0;
|
||||
|
||||
for (i = length - 1; i >= 0; i--)
|
||||
{
|
||||
if (!isdigit(iface[i]))
|
||||
{
|
||||
if (i != length - 1)
|
||||
{
|
||||
num = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (num && ((int)maxlength <= length)) || (!num && ((int)maxlength <= length + 3)) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i != length - 1)
|
||||
num = atoi(&(iface[++i]));
|
||||
|
||||
num++;
|
||||
|
||||
snprintf(&(iface[i]), 4, "%03d", num);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
void *CSmmAPI::InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, int *ret)
|
||||
{
|
||||
char _if[256]; /* assume no interface goes beyond this */
|
||||
size_t len = strlen(iface);
|
||||
int num = 0;
|
||||
void *pf = NULL;
|
||||
|
||||
if (max > 999)
|
||||
max = 999;
|
||||
|
||||
if (len + 4 > sizeof(_if))
|
||||
{
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_FAILED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(_if, iface);
|
||||
|
||||
do
|
||||
{
|
||||
if ( (pf = (fn)(_if, ret)) != NULL )
|
||||
break;
|
||||
if (num > max)
|
||||
break;
|
||||
} while (( num = FormatIface(_if, len+1) ));
|
||||
|
||||
return pf;
|
||||
}
|
||||
|
||||
void *CSmmAPI::VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min)
|
||||
{
|
||||
char buffer[256]; /* assume no interface will go beyond this */
|
||||
size_t len = strlen(iface);
|
||||
int ret; /* just in case something doesn't handle NULL properly */
|
||||
|
||||
if (len > sizeof(buffer) - 4)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(buffer, iface);
|
||||
|
||||
if (min != -1)
|
||||
{
|
||||
char *ptr = &buffer[len - 1];
|
||||
int digits = 0;
|
||||
while (isdigit(*ptr) && digits <=3)
|
||||
{
|
||||
*ptr = '\0';
|
||||
digits++;
|
||||
ptr--;
|
||||
}
|
||||
if (digits != 3)
|
||||
{
|
||||
/* for now, assume this is an error */
|
||||
strcpy(buffer, iface);
|
||||
} else {
|
||||
char num[4];
|
||||
min = (min == 0) ? 1 : min;
|
||||
snprintf(num, sizeof(num), "%03d", min);
|
||||
strcat(buffer, num);
|
||||
}
|
||||
}
|
||||
|
||||
return InterfaceSearch(fn, buffer, IFACE_MAXNUM, &ret);
|
||||
}
|
||||
|
||||
const char *CSmmAPI::GetBaseDir()
|
||||
{
|
||||
return g_ModPath.c_str();
|
||||
}
|
||||
|
||||
void CSmmAPI::PathFormat(char *buffer, size_t len, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
size_t mylen = UTIL_FormatArgs(buffer, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
for (size_t i = 0; i < mylen; i++)
|
||||
{
|
||||
if (buffer[i] == ALT_SEP_CHAR)
|
||||
{
|
||||
buffer[i] = PATH_SEP_CHAR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSmmAPI::ClientConPrintf(edict_t *client, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
static char buffer[4096];
|
||||
|
||||
va_start(ap, fmt);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
g_Engine.engine->ClientPrintf(client, buffer);
|
||||
}
|
||||
|
||||
void CSmmAPI::LoadAsVSP()
|
||||
{
|
||||
size_t len;
|
||||
char engine_file[PATH_SIZE];
|
||||
char engine_path[PATH_SIZE];
|
||||
char rel_path[PATH_SIZE * 2];
|
||||
|
||||
GetFileOfAddress(g_Engine.engine, engine_file, sizeof(engine_file));
|
||||
|
||||
/* Chop off the "engine" file part */
|
||||
len = strlen(engine_file);
|
||||
for (size_t i = len - 1; i >= 0 && i < len; i--)
|
||||
{
|
||||
if (engine_file[i] == '/'
|
||||
|| engine_file[i] == '\\')
|
||||
{
|
||||
engine_file[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
abspath(engine_path, engine_file);
|
||||
|
||||
const char *usepath = g_SmmPath.c_str();
|
||||
if (UTIL_Relatize(rel_path, sizeof(rel_path), engine_path, g_SmmPath.c_str()))
|
||||
{
|
||||
usepath = rel_path;
|
||||
}
|
||||
|
||||
char command[PATH_SIZE * 2];
|
||||
g_VspListener.SetLoadable(true);
|
||||
UTIL_Format(command, sizeof(command), "plugin_load \"%s\"\n", usepath);
|
||||
g_Engine.engine->ServerCommand(command);
|
||||
}
|
||||
|
||||
void CSmmAPI::EnableVSPListener()
|
||||
{
|
||||
/* If GameInit already passed and we're not already enabled or loaded, go ahead and LoadAsVSP load */
|
||||
if (bGameInit && !m_VSP && !g_VspListener.IsLoaded())
|
||||
{
|
||||
LoadAsVSP();
|
||||
}
|
||||
m_VSP = true;
|
||||
}
|
||||
|
||||
int CSmmAPI::GetGameDLLVersion()
|
||||
{
|
||||
return g_GameDllVersion;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
|
||||
/* This is the ugliest function in all of SourceMM */
|
||||
/* :TODO: Make this prettier */
|
||||
bool CSmmAPI::CacheUserMessages()
|
||||
{
|
||||
/* Get address of original GetUserMessageInfo() */
|
||||
char *vfunc = (char *)SH_GET_ORIG_VFNPTR_ENTRY(g_GameDll.pGameDLL, &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;
|
||||
}
|
||||
|
||||
UserMsgDict *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)
|
||||
{
|
||||
m_MsgCount = dict->Count();
|
||||
|
||||
/* Ensure that count is within bounds of an unsigned byte, because that's what engine supports */
|
||||
if (m_MsgCount < 0 || m_MsgCount > 255)
|
||||
{
|
||||
m_MsgCount = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
UserMessage *msg;
|
||||
|
||||
/* Cache messages in our CUtlDict */
|
||||
for (int i = 0; i < m_MsgCount; i++)
|
||||
{
|
||||
msg = dict->Element(i);
|
||||
m_UserMessages.Insert(msg->name, msg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSmmAPI::MsgCacheSuccessful()
|
||||
{
|
||||
return m_MsgCount > -1;
|
||||
}
|
||||
|
||||
int CSmmAPI::GetUserMessageCount()
|
||||
{
|
||||
return m_MsgCount;
|
||||
}
|
||||
|
||||
int CSmmAPI::FindUserMessage(const char *name, int *size)
|
||||
{
|
||||
int index = m_UserMessages.Find(name);
|
||||
|
||||
if (size && index > -1)
|
||||
{
|
||||
UserMessage *msg = m_UserMessages.Element(index);
|
||||
*size = msg->size;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
const char *CSmmAPI::GetUserMessage(int index, int *size)
|
||||
{
|
||||
if (m_MsgCount <= 0 || index < 0 || index >= m_MsgCount)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UserMessage *msg = m_UserMessages.Element(index);
|
||||
|
||||
if (size)
|
||||
{
|
||||
*size = msg->size;
|
||||
}
|
||||
|
||||
return msg->name;
|
||||
}
|
||||
|
||||
int CSmmAPI::GetVSPVersion()
|
||||
{
|
||||
return g_VspVersion;
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_CSMM_API_H
|
||||
#define _INCLUDE_CSMM_API_H
|
||||
|
||||
/**
|
||||
* @brief Header for CSmmAPI implementation
|
||||
* @file CSmmAPI.h
|
||||
*/
|
||||
|
||||
#include "ISmmAPI.h"
|
||||
#include <tier1/utldict.h>
|
||||
|
||||
struct UserMessage
|
||||
{
|
||||
int size;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
typedef CUtlDict<UserMessage *, int> UserMsgDict;
|
||||
|
||||
typedef void (*CONPRINTF_FUNC)(const char *, ...);
|
||||
|
||||
namespace SourceMM
|
||||
{
|
||||
class CSmmAPI : public ISmmAPI
|
||||
{
|
||||
public:
|
||||
CSmmAPI();
|
||||
~CSmmAPI();
|
||||
public:
|
||||
void LogMsg(ISmmPlugin *pl, const char *msg, ...);
|
||||
public:
|
||||
CreateInterfaceFn engineFactory(bool syn=true);
|
||||
CreateInterfaceFn physicsFactory(bool syn=true);
|
||||
CreateInterfaceFn fileSystemFactory(bool syn=true);
|
||||
CreateInterfaceFn serverFactory(bool syn=true);
|
||||
CGlobalVars *pGlobals();
|
||||
void SetLastMetaReturn(META_RES res);
|
||||
META_RES GetLastMetaReturn();
|
||||
IConCommandBaseAccessor *GetCvarBaseAccessor();
|
||||
bool RegisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand);
|
||||
void UnregisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand);
|
||||
void ConPrint(const char *fmt);
|
||||
void ConPrintf(const char *fmt, ...);
|
||||
bool RemotePrintingAvailable()
|
||||
{
|
||||
return CmdCacheSuccessful();
|
||||
}
|
||||
virtual void GetApiVersions(int &major, int &minor, int &plvers, int &plmin);
|
||||
virtual void GetShVersions(int &shvers, int &shimpl);
|
||||
virtual void AddListener(ISmmPlugin *plugin, IMetamodListener *pListener);
|
||||
virtual void *MetaFactory(const char *iface, int *ret, PluginId *id);
|
||||
virtual int FormatIface(char buffer[], unsigned int maxlength);
|
||||
virtual void *InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, int *ret);
|
||||
virtual const char *GetBaseDir();
|
||||
virtual void PathFormat(char *buffer, size_t len, const char *fmt, ...);
|
||||
void ClientConPrintf(edict_t *client, const char *fmt, ...);
|
||||
void *VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min=-1);
|
||||
void EnableVSPListener();
|
||||
int GetGameDLLVersion();
|
||||
int GetUserMessageCount();
|
||||
int FindUserMessage(const char *name, int *size=NULL);
|
||||
const char *GetUserMessage(int index, int *size=NULL);
|
||||
int GetVSPVersion();
|
||||
public:
|
||||
bool CacheCmds();
|
||||
bool CmdCacheSuccessful();
|
||||
void LoadAsVSP();
|
||||
bool VSPEnabled()
|
||||
{
|
||||
return m_VSP;
|
||||
}
|
||||
bool CacheUserMessages();
|
||||
bool MsgCacheSuccessful();
|
||||
private:
|
||||
META_RES m_Res;
|
||||
CONPRINTF_FUNC m_ConPrintf;
|
||||
bool m_CmdCache;
|
||||
bool m_VSP;
|
||||
int m_MsgCount;
|
||||
UserMsgDict m_UserMessages;
|
||||
};
|
||||
};
|
||||
|
||||
extern SourceMM::CSmmAPI g_SmmAPI;
|
||||
|
||||
#define CONMSG g_SmmAPI.ConPrintf
|
||||
#define CLIENT_CONMSG g_SmmAPI.ClientConPrintf
|
||||
|
||||
#endif //_INCLUDE_CSMM_API_H
|
@ -1,12 +1,29 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_PLUGINMANAGER_H
|
||||
#define _INCLUDE_PLUGINMANAGER_H
|
||||
|
@ -1,12 +1,29 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_ISMM_API_H
|
||||
#define _INCLUDE_ISMM_API_H
|
||||
@ -18,7 +35,7 @@
|
||||
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include <sourcehook/sourcehook.h>
|
||||
#include <sourcehook.h>
|
||||
#include "IPluginManager.h"
|
||||
|
||||
#if defined __GNUC__
|
||||
@ -33,7 +50,12 @@ class ISmmPlugin;
|
||||
|
||||
#define MMIFACE_SOURCEHOOK "ISourceHook" /**< ISourceHook Pointer */
|
||||
#define MMIFACE_PLMANAGER "IPluginManager" /**< SourceMM Plugin Functions */
|
||||
#define IFACE_MAXNUM 999
|
||||
#define IFACE_MAXNUM 999 /**< Maximum interface version */
|
||||
|
||||
#define SOURCE_ENGINE_UNKNOWN 0 /**< Could not determine the engine version */
|
||||
#define SOURCE_ENGINE_ORIGINAL 1 /**< Original Source Engine (used by The Ship) */
|
||||
#define SOURCE_ENGINE_EPISODEONE 2 /**< Episode 1 Source Engine (second major SDK) */
|
||||
#define SOURCE_ENGINE_ORANGEBOX 3 /**< Orange Box Source Engine (third major SDK) */
|
||||
|
||||
class ISmmAPI
|
||||
{
|
||||
@ -119,7 +141,7 @@ public: // Added in 1.00-RC2 (0:0)
|
||||
*
|
||||
* @param plugin Parent plugin API pointer.
|
||||
* @param pCommand ConCommandBase to register.
|
||||
* @return True if successful, false otherwise. Does not return false yet.
|
||||
* @return True if successful, false otherwise.
|
||||
*/
|
||||
virtual bool RegisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand) =0;
|
||||
|
||||
@ -133,6 +155,7 @@ public: // Added in 1.00-RC2 (0:0)
|
||||
|
||||
/**
|
||||
* @brief Prints an unformatted string to the remote server console.
|
||||
*
|
||||
* Note: Newlines are not added automatically.
|
||||
*
|
||||
* @param str Message string.
|
||||
@ -141,6 +164,7 @@ public: // Added in 1.00-RC2 (0:0)
|
||||
|
||||
/**
|
||||
* @brief Prints a formatted message to the remote server console.
|
||||
*
|
||||
* Note: Newlines are not added automatically.
|
||||
*
|
||||
* @param fmt Formatted message.
|
||||
@ -205,9 +229,9 @@ public: // Added in 1.1.2 (1:1)
|
||||
*/
|
||||
virtual int FormatIface(char iface[], unsigned int maxlength) =0;
|
||||
|
||||
public: // Added in 1.2.0 (1:2)
|
||||
public: // Added in 1.2 (1:2)
|
||||
/**
|
||||
* @brief Searches for an interface for you.
|
||||
* @brief Searches for an interface, eliminating the need to loop through FormatIface().
|
||||
*
|
||||
* @param fn InterfaceFactory function.
|
||||
* @param iface Interface string name.
|
||||
@ -219,15 +243,17 @@ public: // Added in 1.2.0 (1:2)
|
||||
|
||||
/**
|
||||
* @brief Returns the base directory of the game/server, equivalent to
|
||||
* IVEngineServer::GetGameDir(), except the path is absolute.
|
||||
* IVEngineServer::GetGameDir(), except the path is absolute.
|
||||
*
|
||||
* @return Static pointer to game's absolute basedir.
|
||||
*/
|
||||
virtual const char *GetBaseDir() =0;
|
||||
|
||||
/**
|
||||
* @brief Formats a file path to the local OS. Does not include any base directories.
|
||||
* Note that all slashes and black slashes are reverted to the local OS's expectancy.
|
||||
* @brief Formats a file path to the local OS.
|
||||
*
|
||||
* Does not include any base directories. Note that all slashes and black
|
||||
* slashes are reverted to the local OS's expectancy.
|
||||
*
|
||||
* @param buffer Destination buffer to store path.
|
||||
* @param len Maximum length of buffer, including null terminator.
|
||||
@ -237,15 +263,15 @@ public: // Added in 1.2.0 (1:2)
|
||||
|
||||
public: // Added in 1.2.2 (1:3)
|
||||
/**
|
||||
* @brief Prints text in the specified client's console. Same as IVEngineServer::ClientPrintf
|
||||
* except that it allows for string formatting.
|
||||
* @brief Prints text in the specified client's console. Same as
|
||||
* IVEngineServer::ClientPrintf except that it allows for string formatting.
|
||||
*
|
||||
* @param client Client edict pointer.
|
||||
* @param fmt Formatted string to print to the client.
|
||||
*/
|
||||
virtual void ClientConPrintf(edict_t *client, const char *fmt, ...) =0;
|
||||
|
||||
public: // Added in 1.3.0 (1:4)
|
||||
public: // Added in 1.3 (1:4)
|
||||
/**
|
||||
* @brief Wrapper around InterfaceSearch(). Assumes no maximum.
|
||||
* This is designed to replace the fact that searches only went upwards.
|
||||
@ -253,27 +279,34 @@ public: // Added in 1.3.0 (1:4)
|
||||
*
|
||||
* @param fn Interface factory function.
|
||||
* @param iface Interface string.
|
||||
* @param min Minimum value to search from. If zero, searching begins from the
|
||||
* first available version regardless of the interface.
|
||||
* Note that this can return interfaces EARLIER than the version specified.
|
||||
* A value of -1 (default) specifies the string version as the minimum.
|
||||
* Any other value specifices the minimum value to search from.
|
||||
* @param min Minimum value to search from. If zero, searching
|
||||
* begins from the first available version regardless
|
||||
* of the interface. Note that this can return
|
||||
* interfaces EARLIER than the version specified. A
|
||||
* value of -1 (default) specifies the string version
|
||||
* as the minimum. Any other value specifices the
|
||||
* minimum value to search from.
|
||||
* @return Interface pointer, or NULL if not found.
|
||||
*/
|
||||
virtual void *VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min=-1) =0;
|
||||
|
||||
public: // Added in 1.4.0 (1:5)
|
||||
public: // Added in 1.4 (1:5)
|
||||
/**
|
||||
* @brief Tells SourceMM to add VSP hooking capability to plugins.
|
||||
*
|
||||
* Since this potentially uses more resources than it would otherwise, plugins have to
|
||||
* explicitly enable the feature. Whether requested or not, if it is enabled, all plugins
|
||||
* will get a pointer to the VSP listener through IMetamodListener.
|
||||
* Since this potentially uses more resources than it would otherwise,
|
||||
* plugins have to explicitly enable the feature. Whether requested or
|
||||
* not, if it is enabled, all plugins will get a pointer to the VSP
|
||||
* listener through IMetamodListener. This will not be called more than
|
||||
* once for a given plugin; if it is requested more than once, each
|
||||
* successive call will only give the pointer to plugins which have not
|
||||
* yet received it.
|
||||
*/
|
||||
virtual void EnableVSPListener() =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the interface version of the GameDLL's IServerGameDLL implementation.
|
||||
* @brief Returns the interface version of the GameDLL's IServerGameDLL
|
||||
* implementation.
|
||||
*
|
||||
* @return Interface version of the loaded IServerGameDLL.
|
||||
*/
|
||||
@ -282,7 +315,8 @@ public: // Added in 1.4.0 (1:5)
|
||||
/**
|
||||
* @brief Returns the number of user messages in the GameDLL.
|
||||
*
|
||||
* @return Number of user messages, or -1 if SourceMM has failed to get user message list.
|
||||
* @return Number of user messages, or -1 if SourceMM has
|
||||
* failed to get user message list.
|
||||
*/
|
||||
virtual int GetUserMessageCount() =0;
|
||||
|
||||
@ -303,15 +337,42 @@ public: // Added in 1.4.0 (1:5)
|
||||
* @return Message name, or NULL on failure.
|
||||
*/
|
||||
virtual const char *GetUserMessage(int index, int *size=NULL) =0;
|
||||
|
||||
public: // Added in 1.5.0 (1:6)
|
||||
/**
|
||||
* @brief Returns the highest interface version of IServerPluginCallbacks that the engine supports.
|
||||
* This is useful for games that run on older versions of the Source engine, such as The Ship.
|
||||
* @brief Returns the highest interface version of IServerPluginCallbacks
|
||||
* that the engine supports. This is useful for games that run on older
|
||||
* versions of the Source engine, such as The Ship.
|
||||
*
|
||||
* @return Highest interface version of IServerPluginCallbacks.
|
||||
* Returns 0 if SourceMM's VSP listener isn't currently enabled.
|
||||
* Returns 0 if SourceMM's VSP listener isn't currently
|
||||
* enabled.
|
||||
*/
|
||||
virtual int GetVSPVersion() =0;
|
||||
|
||||
public: // Added in 1.6.0 (1:7)
|
||||
/**
|
||||
* @brief Returns the engine interface that MM:S is using as a backend.
|
||||
*
|
||||
* The values will be one of the SOURCE_ENGINE_* constants from the top
|
||||
* of this file.
|
||||
*
|
||||
* @return A SOURCE_ENGINE_* constant value.
|
||||
*/
|
||||
virtual int GetSourceEngineBuild() =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the VSP listener loaded.
|
||||
*
|
||||
* This is useful for late-loading plugins which need to decide whether
|
||||
* to add a listener or not (or need to get the pointer at all).
|
||||
*
|
||||
* @param Optional pointer to store the VSP version.
|
||||
* @return IServerPluginCallbacks pointer, or NULL if an
|
||||
* IMetamodListener event has yet to occur for
|
||||
* EnableVSPListener().
|
||||
*/
|
||||
virtual IServerPluginCallbacks *GetVSPInfo(int *pVersion) =0;
|
||||
};
|
||||
|
||||
|
||||
@ -320,11 +381,13 @@ public: // Added in 1.5.0 (1:6)
|
||||
*
|
||||
* 1.1.0 Bumped API to 1:0. The breaking changes occurred in SourceHook and the plugin API.
|
||||
* 1.1.2 Added API call for generating iface names.
|
||||
* 1.2.0 Added API more helper functions and new SourceHook version.
|
||||
* 1.2 Added API more helper functions and new SourceHook version.
|
||||
* 1.2.2 Added API for printing to client console (with string formatting).
|
||||
* 1.3.0 Added new interface search API.
|
||||
* 1.4.0 Added VSP listener and user message API.
|
||||
* 1.3 Added new interface search API.
|
||||
* 1.4 Added VSP listener and user message API.
|
||||
* 1.5.0 Added API for getting highest supported version of IServerPluginCallbacks.
|
||||
* 1.6.0 Added API for Orange Box.
|
||||
*/
|
||||
|
||||
#endif //_INCLUDE_ISMM_API_H
|
||||
|
||||
|
@ -1,12 +1,29 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_ISMM_PLUGIN_H
|
||||
#define _INCLUDE_ISMM_PLUGIN_H
|
||||
@ -17,7 +34,7 @@
|
||||
*/
|
||||
|
||||
#include <interface.h>
|
||||
#include <sourcehook/sourcehook.h>
|
||||
#include <sourcehook.h>
|
||||
#include "ISmmAPI.h"
|
||||
|
||||
#define PLAPI_VERSION 12
|
||||
@ -33,6 +50,7 @@ public:
|
||||
public:
|
||||
/**
|
||||
* @brief Called on plugin load.
|
||||
*
|
||||
* NOTE - As of API 7, this is called as DLLInit() executes - after the parameters are known, but before
|
||||
* the original GameDLL function is called. Therefore, you cannot hook it, but you don't need to -
|
||||
* Load() is basically your hook.
|
||||
@ -40,22 +58,24 @@ public:
|
||||
* However, take care to note that if your plugin is unloaded, and the gamedll/engine have cached
|
||||
* an interface you've passed, something will definitely crash. Be careful.
|
||||
*
|
||||
* @param id Internal id of plugin. Saved globally by PLUGIN_SAVEVARS()
|
||||
* @param ismm External API for SourceMM. Saved globally by PLUGIN_SAVEVARS()
|
||||
* @param list Contains a list of factories. Hook a factory call by setting one equal to your own function.
|
||||
* @param late Set to true if your plugin was loaded late (not at server load).
|
||||
* @param error Error message buffer
|
||||
* @param maxlen Size of error message buffer
|
||||
* @return True if successful, return false to reject the load.
|
||||
* @param id Internal id of plugin. Saved globally by PLUGIN_SAVEVARS()
|
||||
* @param ismm External API for SourceMM. Saved globally by PLUGIN_SAVEVARS()
|
||||
* @param list Contains a list of factories. Hook a factory call by setting one equal to your own function.
|
||||
* @param late Set to true if your plugin was loaded late (not at server load).
|
||||
* @param error Error message buffer
|
||||
* @param maxlen Size of error message buffer
|
||||
* @return True if successful, return false to reject the load.
|
||||
*/
|
||||
virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late) =0;
|
||||
|
||||
/**
|
||||
* @brief Called when your plugin is "queried". This is useful for rejecting a loaded
|
||||
* state. For example, if your plugin wants to stop operating, it can simply return
|
||||
* false and copy an error message. This will notify other plugins or MM:S of something
|
||||
* bad that happened. NOTE - MM:S will not cache the return state, so if you return false,
|
||||
* your plugin will not actually be paused or unloaded. This callback will be called when:
|
||||
* @brief Called when your plugin is "queried".
|
||||
*
|
||||
* This is useful for rejecting a loaded state. For example, if your plugin wants
|
||||
* to stop operating, it can simply return false and copy an error message. This
|
||||
* will notify other plugins or MM:S of something bad that happened. NOTE - MM:S
|
||||
* will not cache the return state, so if you return false, your plugin will not
|
||||
* actually be paused or unloaded. This callback will be called when:
|
||||
* - Another plugin requests it
|
||||
* - Someone types "meta list", it will show up as "REFUSED"
|
||||
* - When Metamod need to re-check the plugin's status
|
||||
@ -132,10 +152,11 @@ public:
|
||||
virtual const char *GetLogTag() =0;
|
||||
public:
|
||||
/**
|
||||
* @brief Called when all plugins have been loaded - API version 4
|
||||
* @brief Called when all plugins have been loaded.
|
||||
*
|
||||
* This is useful for knowing when it's safe to request things another plugin might have.
|
||||
* NOTE for API 7 - This is called after DLLInit().
|
||||
* This is called after DLLInit(), and thus the mod has been mostly initialized.
|
||||
* It is also safe to assume that all other (automatically loaded) plugins are now
|
||||
* ready to start interacting, because they are all loaded.
|
||||
*/
|
||||
virtual void AllPluginsLoaded()
|
||||
{
|
||||
@ -148,35 +169,45 @@ public:
|
||||
class IMetamodListener
|
||||
{
|
||||
public:
|
||||
virtual ~IMetamodListener() { }
|
||||
virtual ~IMetamodListener()
|
||||
{
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* @brief Called when a plugin is loaded.
|
||||
*
|
||||
* @param id Id of the plugin.
|
||||
*/
|
||||
virtual void OnPluginLoad(PluginId id) { }
|
||||
virtual void OnPluginLoad(PluginId id)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when a plugin is unloaded.
|
||||
*
|
||||
* @param id Id of the plugin.
|
||||
*/
|
||||
virtual void OnPluginUnload(PluginId id) { }
|
||||
virtual void OnPluginUnload(PluginId id)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when a plugin is paused.
|
||||
*
|
||||
* @param id Id of the plugin.
|
||||
*/
|
||||
virtual void OnPluginPause(PluginId id) { }
|
||||
virtual void OnPluginPause(PluginId id)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when a plugin is unpaused.
|
||||
*
|
||||
* @param id Id of the plugin.
|
||||
*/
|
||||
virtual void OnPluginUnpause(PluginId id) { }
|
||||
virtual void OnPluginUnpause(PluginId id)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when the level is loaded (after GameInit, before ServerActivate).
|
||||
@ -195,7 +226,9 @@ public:
|
||||
/**
|
||||
* @brief Called when the level is shut down. May be called more than once.
|
||||
*/
|
||||
virtual void OnLevelShutdown() { }
|
||||
virtual void OnLevelShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when engineFactory() is used through Metamod:Source's wrapper.
|
||||
@ -308,7 +341,8 @@ public:
|
||||
* This callback is provided to all plugins regardless of which (or how many)
|
||||
* called EnableVSPListener(), but only if at least one did in fact enable it.
|
||||
*
|
||||
* This callback is only available for plugins using API v1:5 (SourceMM 1.4+).
|
||||
* This callback is only available for plugins using API v1:5 (Metamod:Source 1.4+).
|
||||
* If a plugin loads lately, it may still call EnableVSPListener().
|
||||
*
|
||||
* @param iface Interface pointer. If NULL, then the VSP listening construct
|
||||
* failed to initialize and is not available.
|
||||
@ -322,6 +356,17 @@ public:
|
||||
* @param pCommand Pointer to concommand or convar that is being removed.
|
||||
*/
|
||||
virtual void OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand) { }
|
||||
|
||||
/**
|
||||
* @brief Called when Metamod:Source is about to remove a concommand or convar.
|
||||
* This can also be called if ISmmAPI::UnregisterConCmdBase is used by a plugin.
|
||||
*
|
||||
* @param id Id of the plugin that created the concommand or convar.
|
||||
* @param pCommand Pointer to concommand or convar that is being removed.
|
||||
*/
|
||||
virtual void OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#define PL_EXPOSURE CreateInterface
|
||||
@ -413,3 +458,4 @@ public:
|
||||
}
|
||||
|
||||
#endif //_INCLUDE_ISMM_PLUGIN_H
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#(C)2004-2007 SourceMM Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
HL2SDK = ../../hl2sdk
|
||||
HL2SDK = ../../../hl2sdk
|
||||
SMM_ROOT = ..
|
||||
SRCDS = ~/srcds
|
||||
|
||||
@ -16,10 +16,10 @@ BINARY = server_i486.so
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
|
||||
OBJECTS = oslink.cpp util.cpp concommands.cpp CSmmAPI.cpp \
|
||||
sourcemm.cpp CPlugin.cpp sourcehook.cpp vsp_listener.cpp
|
||||
OBJECTS = metamod.cpp metamod_util.cpp metamod_console.cpp metamod_oslink.cpp metamod_plugins.cpp \
|
||||
sourcehook.cpp episode1/console.cpp episode1/provider_ep1.cpp episode1/vsp_listener.cpp
|
||||
|
||||
LINK = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc
|
||||
LINK = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc
|
||||
|
||||
INCLUDE = -I. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
|
||||
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_ROOT) -I$(SMM_ROOT)/sourcehook
|
||||
@ -34,7 +34,9 @@ endif
|
||||
|
||||
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
||||
|
||||
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
|
||||
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \
|
||||
-Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca \
|
||||
-Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
|
||||
|
||||
ifeq "$(GCC_VERSION)" "4"
|
||||
CFLAGS += $(GCC4_FLAGS)
|
||||
@ -47,10 +49,11 @@ $(BIN_DIR)/%.o: %.cpp
|
||||
|
||||
all:
|
||||
mkdir -p $(BIN_DIR)
|
||||
mkdir -p $(BIN_DIR)/episode1
|
||||
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
|
||||
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
|
||||
ln -sf $(SMM_ROOT)/sourcehook/sourcehook.cpp sourcehook.cpp
|
||||
$(MAKE) sourcemm
|
||||
$(MAKE) -f Makefile.ep1 sourcemm
|
||||
rm -rf $(BINARY)
|
||||
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
|
||||
|
||||
@ -58,12 +61,15 @@ sourcemm: $(OBJ_LINUX)
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
|
||||
debug:
|
||||
$(MAKE) all DEBUG=true
|
||||
$(MAKE) -f Makefile.ep1 all DEBUG=true
|
||||
|
||||
default: all
|
||||
|
||||
clean:
|
||||
rm -rf Release/episode1/*.o
|
||||
rm -rf Release/*.o
|
||||
rm -rf Release/$(BINARY)
|
||||
rm -rf Debug/episode1/*.o
|
||||
rm -rf Debug/*.o
|
||||
rm -rf Debug/$(BINARY)
|
||||
|
@ -1,26 +1,29 @@
|
||||
#(C)2004-2007 SourceMM Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
HL2SDK = ../../../hl2sdk
|
||||
SMM_ROOT = ../..
|
||||
HL2SDK = ../../../hl2sdk-ob
|
||||
SMM_ROOT = ..
|
||||
SRCDS = ~/srcds
|
||||
|
||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||
|
||||
OPT_FLAGS = -O3 -funroll-loops -s -pipe
|
||||
OPT_FLAGS = -O2 -funroll-loops -s -pipe
|
||||
GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden
|
||||
DEBUG_FLAGS = -g -ggdb3
|
||||
CPP = gcc-4.1
|
||||
BINARY = stub_mm_i486.so
|
||||
BINARY = server_i486.so
|
||||
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
|
||||
OBJECTS = stub_mm.cpp
|
||||
OBJECTS = metamod.cpp metamod_util.cpp metamod_console.cpp metamod_oslink.cpp metamod_plugins.cpp \
|
||||
sourcehook.cpp episode2/console.cpp episode2/provider_ep2.cpp episode2/vsp_listener.cpp \
|
||||
episode2/convar.cpp
|
||||
|
||||
LINK = vstdlib_i486.so tier0_i486.so -static-libgcc
|
||||
|
||||
INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
|
||||
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_ROOT) -I$(SMM_ROOT)/sourcehook -I$(SMM_ROOT)/sourcemm
|
||||
INCLUDE = -I. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
|
||||
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_ROOT) -I$(SMM_ROOT)/sourcehook
|
||||
|
||||
ifeq "$(DEBUG)" "true"
|
||||
BIN_DIR = Debug
|
||||
@ -32,7 +35,10 @@ endif
|
||||
|
||||
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
||||
|
||||
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
|
||||
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \
|
||||
-Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca \
|
||||
-Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse \
|
||||
-fno-strict-aliasing
|
||||
|
||||
ifeq "$(GCC_VERSION)" "4"
|
||||
CFLAGS += $(GCC4_FLAGS)
|
||||
@ -45,9 +51,12 @@ $(BIN_DIR)/%.o: %.cpp
|
||||
|
||||
all:
|
||||
mkdir -p $(BIN_DIR)
|
||||
mkdir -p $(BIN_DIR)/episode2
|
||||
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
|
||||
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
|
||||
$(MAKE) sourcemm
|
||||
ln -sf $(SMM_ROOT)/sourcehook/sourcehook.cpp sourcehook.cpp
|
||||
ln -sf $(HL2SDK)/tier1/convar.cpp episode2/convar.cpp
|
||||
$(MAKE) -f Makefile.ep2 sourcemm
|
||||
rm -rf $(BINARY)
|
||||
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
|
||||
|
||||
@ -55,12 +64,15 @@ sourcemm: $(OBJ_LINUX)
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
|
||||
debug:
|
||||
$(MAKE) all DEBUG=true
|
||||
$(MAKE) -f Makefile.ep2 all DEBUG=true
|
||||
|
||||
default: all
|
||||
|
||||
clean:
|
||||
rm -rf Release/episode2/*.o
|
||||
rm -rf Release/*.o
|
||||
rm -rf Release/$(BINARY)
|
||||
rm -rf Debug/episode2/*.o
|
||||
rm -rf Debug/*.o
|
||||
rm -rf Debug/$(BINARY)
|
||||
|
@ -1,257 +0,0 @@
|
||||
# Doxyfile 1.4.2
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = SourceMM
|
||||
PROJECT_NUMBER = 1.00
|
||||
OUTPUT_DIRECTORY = c:\temp\smm-dox
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
USE_WINDOWS_ENCODING = YES
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH = "C:/Documents and Settings/dvander.WHITENIGHT/Desktop/code/"
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = YES
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = NO
|
||||
INHERIT_DOCS = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SUBGROUPING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 38
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = "C:/Documents and Settings/dvander.WHITENIGHT/Desktop/code/sourcemm"
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.d \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.idl \
|
||||
*.odl \
|
||||
*.cs \
|
||||
*.php \
|
||||
*.php3 \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.mm \
|
||||
*.dox
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS = test \
|
||||
sample_mm
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = NO
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
VERBATIM_HEADERS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = NO
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = YES
|
@ -1,11 +1,6 @@
|
||||
2007/??/?? 1.5.0:
|
||||
- Added new version of SourceHook with the following changes:
|
||||
- Added API for hooking functions on a virtual table to all instances.
|
||||
- SH_ADD_HOOK macros now return non-zero hook IDs. Additionally,
|
||||
the old hook adding/removing syntax is deprecated (but still supported).
|
||||
- Added SH_REMOVE_HOOK_ID to remove hooks by ID.
|
||||
- CallClasses have been deprecated. The SH_CALL macro can now take a class
|
||||
instance pointer rather than a callclass pointer.
|
||||
2007/??/?? 1.6.0:
|
||||
- Metamod:Source has no received a large internal rewrite to improve coding
|
||||
standards and to separate internal logic from engine specifics.
|
||||
- Added API for getting highest supported IServerPluginCallbacks interface
|
||||
version.
|
||||
- Added OnUnlinkConCommandBase to IMetamodListner to notify when Metamod:Source
|
||||
|
@ -1,53 +0,0 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_CONCOMMANDS_H
|
||||
#define _INCLUDE_CONCOMMANDS_H
|
||||
|
||||
/**
|
||||
* @brief Header for console commands
|
||||
* @file concommands.h
|
||||
*/
|
||||
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include "sourcemm.h"
|
||||
#include "convar_smm.h"
|
||||
#include "sh_list.h"
|
||||
|
||||
class SMConVarAccessor : public IConCommandBaseAccessor
|
||||
{
|
||||
SourceHook::List<ConCommandBase*> m_RegisteredCommands;
|
||||
public:
|
||||
virtual bool RegisterConCommandBase(ConCommandBase *pCommand);
|
||||
bool Register(ConCommandBase *pCommand);
|
||||
void MarkCommandsAsGameDLL();
|
||||
void Unregister(PluginId id, ConCommandBase *pCommand);
|
||||
void UnregisterGameDLLCommands();
|
||||
};
|
||||
|
||||
class CAlwaysRegisterableCommand : public ConCommandBase
|
||||
{
|
||||
ICvar *m_pICvar;
|
||||
public:
|
||||
CAlwaysRegisterableCommand();
|
||||
bool IsRegistered( void ) const;
|
||||
// If already registered, removes us
|
||||
// Then it registers us again
|
||||
void BringToFront();
|
||||
};
|
||||
|
||||
void ClientCommand_handler(edict_t *client);
|
||||
|
||||
const char *GetPluginsFile();
|
||||
|
||||
extern SMConVarAccessor g_SMConVarAccessor;
|
||||
|
||||
#endif //_INCLUDE_CONCOMMANDS_H
|
169
sourcemm/episode1/console.cpp
Normal file
169
sourcemm/episode1/console.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "console.h"
|
||||
#include "provider_ep1.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
SMConVarAccessor g_SMConVarAccessor;
|
||||
|
||||
class CAlwaysRegisterableCommand : public ConCommandBase
|
||||
{
|
||||
public:
|
||||
CAlwaysRegisterableCommand()
|
||||
{
|
||||
Create("metamod_eternal", NULL, FCVAR_UNREGISTERED|FCVAR_GAMEDLL);
|
||||
}
|
||||
bool IsRegistered( void ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void BringToFront()
|
||||
{
|
||||
// First, let's try to find us!
|
||||
ConCommandBase *pPtr = icvar->GetCommands();
|
||||
|
||||
if (pPtr == this)
|
||||
{
|
||||
// We are already at the beginning; Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
while (pPtr)
|
||||
{
|
||||
if (pPtr == this)
|
||||
{
|
||||
break;
|
||||
}
|
||||
ConCommandBase *pPrev = NULL;
|
||||
while (pPtr)
|
||||
{
|
||||
if (pPtr == this)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pPrev = pPtr;
|
||||
pPtr = const_cast<ConCommandBase*>(pPtr->GetNext());
|
||||
}
|
||||
if (pPrev && pPtr == this)
|
||||
{
|
||||
pPrev->SetNext(m_pNext); // Remove us from the list
|
||||
}
|
||||
// Now, register us
|
||||
SetNext(NULL);
|
||||
icvar->RegisterConCommandBase(this);
|
||||
}
|
||||
}
|
||||
} s_EternalCommand;
|
||||
|
||||
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
|
||||
{
|
||||
m_RegisteredCommands.push_back(pCommand);
|
||||
pCommand->SetNext(NULL);
|
||||
icvar->RegisterConCommandBase(pCommand);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SMConVarAccessor::Register(ConCommandBase *pCommand)
|
||||
{
|
||||
pCommand->SetNext(NULL);
|
||||
icvar->RegisterConCommandBase(pCommand);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SMConVarAccessor::MarkCommandsAsGameDLL()
|
||||
{
|
||||
for (List<ConCommandBase*>::iterator iter = m_RegisteredCommands.begin();
|
||||
iter != m_RegisteredCommands.end(); ++iter)
|
||||
{
|
||||
(*iter)->AddFlags(FCVAR_GAMEDLL);
|
||||
}
|
||||
}
|
||||
|
||||
void SMConVarAccessor::UnregisterGameDLLCommands()
|
||||
{
|
||||
ConCommandBase *begin = icvar->GetCommands();
|
||||
ConCommandBase *iter = begin;
|
||||
ConCommandBase *prev = NULL;
|
||||
while (iter)
|
||||
{
|
||||
/* Watch out for the ETERNAL COMMAND! */
|
||||
if (iter != &s_EternalCommand && iter->IsBitSet(FCVAR_GAMEDLL))
|
||||
{
|
||||
/* Remove it! */
|
||||
if (iter == begin)
|
||||
{
|
||||
s_EternalCommand.BringToFront();
|
||||
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
||||
s_EternalCommand.SetNext(iter);
|
||||
prev = &s_EternalCommand;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
||||
prev->SetNext(iter);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
prev = iter;
|
||||
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
||||
}
|
||||
}
|
||||
|
||||
void SMConVarAccessor::Unregister(ConCommandBase *pCommand)
|
||||
{
|
||||
ConCommandBase *ptr = icvar->GetCommands();
|
||||
|
||||
if (ptr == pCommand)
|
||||
{
|
||||
s_EternalCommand.BringToFront();
|
||||
s_EternalCommand.SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Find us and unregister us */
|
||||
ConCommandBase *pPrev = NULL;
|
||||
while (ptr)
|
||||
{
|
||||
if (ptr == pCommand)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pPrev = ptr;
|
||||
ptr = const_cast<ConCommandBase *>(ptr->GetNext());
|
||||
}
|
||||
if (pPrev && ptr == pCommand)
|
||||
{
|
||||
pPrev->SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
51
sourcemm/episode1/console.h
Normal file
51
sourcemm/episode1/console.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_CONSOLE_MMS_H_
|
||||
#define _INCLUDE_CONSOLE_MMS_H_
|
||||
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include "convar_smm.h"
|
||||
#include <sh_list.h>
|
||||
|
||||
class SMConVarAccessor : public IConCommandBaseAccessor
|
||||
{
|
||||
public:
|
||||
bool RegisterConCommandBase(ConCommandBase *pCommand);
|
||||
bool Register(ConCommandBase *pCommand);
|
||||
void MarkCommandsAsGameDLL();
|
||||
void Unregister(ConCommandBase *pCommand);
|
||||
void UnregisterGameDLLCommands();
|
||||
private:
|
||||
SourceHook::List<ConCommandBase*> m_RegisteredCommands;
|
||||
};
|
||||
|
||||
extern SMConVarAccessor g_SMConVarAccessor;
|
||||
|
||||
#endif //_INCLUDE_CONSOLE_MMS_H_
|
||||
|
@ -3,7 +3,7 @@
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date$
|
||||
// $Date: 2007-02-08 04:19:19 -0500 (Thu, 08 Feb 2007) $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $NoKeywords: $
|
@ -2,7 +2,7 @@
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="sourcemm"
|
||||
Name="metamodsource_ep1"
|
||||
ProjectGUID="{F7D47743-73B3-49B5-9D76-2333C5DFD565}"
|
||||
RootNamespace="sourcemm"
|
||||
Keyword="Win32Proj"
|
||||
@ -41,6 +41,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..;..\..\..;..\..\..\sourcehook"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
@ -62,7 +63,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
|
||||
AdditionalDependencies="tier1.lib tier0.lib vstdlib.lib"
|
||||
OutputFile="$(OutDir)/server.dll"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
|
||||
@ -128,6 +129,7 @@
|
||||
OmitFramePointers="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||
StringPooling="true"
|
||||
ExceptionHandling="1"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="false"
|
||||
RuntimeTypeInfo="false"
|
||||
@ -192,80 +194,12 @@
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\concommands.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CPlugin.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CSmmAPI.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\oslink.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sourcemm.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\util.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vsp_listener.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\concommands.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CPlugin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CSmmAPI.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\oslink.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sourcemm.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\svn_version.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\util.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vsp_listener.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
@ -273,7 +207,7 @@
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\version.rc"
|
||||
RelativePath="..\..\version.rc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
@ -281,75 +215,119 @@
|
||||
Name="Interfaces"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\IPluginManager.h"
|
||||
RelativePath="..\..\IPluginManager.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ISmmAPI.h"
|
||||
RelativePath="..\..\ISmmAPI.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ISmmPlugin.h"
|
||||
RelativePath="..\..\ISmmPlugin.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="SourceHook"
|
||||
Name="Metamod"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_list.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_stack.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_string.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_tinyhash.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_vector.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="Headers"
|
||||
Name="Source Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\FastDelegate.h"
|
||||
RelativePath="..\..\metamod.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_memfuncinfo.h"
|
||||
RelativePath="..\..\metamod_console.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_memory.h"
|
||||
RelativePath="..\..\metamod_oslink.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sourcehook.cpp"
|
||||
RelativePath="..\..\metamod_plugins.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sourcehook.h"
|
||||
RelativePath="..\..\metamod_util.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\metamod.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sourcehook_impl.h"
|
||||
RelativePath="..\..\metamod_console.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_oslink.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_plugins.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_provider.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_util.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="HL2SDK"
|
||||
Name="Provider"
|
||||
>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\console.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\convar_smm.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\provider_ep1.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vsp_listener.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\console.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\provider_ep1.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vsp_listener.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="SourceHook"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\convar_smm.h"
|
||||
RelativePath="..\..\..\sourcehook\sourcehook.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
590
sourcemm/episode1/provider_ep1.cpp
Normal file
590
sourcemm/episode1/provider_ep1.cpp
Normal file
@ -0,0 +1,590 @@
|
||||
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <sourcehook.h>
|
||||
#include "convar_smm.h"
|
||||
#include <eiface.h>
|
||||
#include <tier0/icommandline.h>
|
||||
#include <tier1/utldict.h>
|
||||
#include <sh_vector.h>
|
||||
#include <sh_string.h>
|
||||
#include "../metamod_util.h"
|
||||
#include "provider_ep1.h"
|
||||
#include "console.h"
|
||||
#include "metamod_console.h"
|
||||
#include "vsp_listener.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);
|
||||
void _ServerCommand();
|
||||
/* Variables */
|
||||
bool usermsgs_extracted = false;
|
||||
CVector<UsrMsgInfo> usermsgs_list;
|
||||
CONPRINTF_FUNC echo_msg_func = NULL;
|
||||
ICvar *icvar = NULL;
|
||||
ISmmAPI *metamod_api = NULL;
|
||||
IVEngineServer *engine = NULL;
|
||||
IServerGameClients *gameclients = NULL;
|
||||
VSPListener g_VspListener;
|
||||
BaseProvider g_Ep1Provider;
|
||||
IMetamodSourceProvider *provider = &g_Ep1Provider;
|
||||
|
||||
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
|
||||
|
||||
void BaseProvider::ConsolePrint(const char *str)
|
||||
{
|
||||
if (echo_msg_func != NULL)
|
||||
{
|
||||
echo_msg_func("%s", str);
|
||||
}
|
||||
else
|
||||
{
|
||||
Msg("%s", str);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseProvider::Notify_DLLInit_Pre(void *gamedll,
|
||||
CreateInterfaceFn engineFactory,
|
||||
CreateInterfaceFn serverFactory)
|
||||
{
|
||||
server = (IServerGameDLL *)gamedll;
|
||||
engine = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL));
|
||||
if (!engine)
|
||||
{
|
||||
Error("Could not find IVEngineServer! Metamod cannot load.");
|
||||
return;
|
||||
}
|
||||
icvar = (ICvar *)((engineFactory)(VENGINE_CVAR_INTERFACE_VERSION, NULL));
|
||||
if (!icvar)
|
||||
{
|
||||
Error("Could not find ICvar! Metamod cannot load.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((gameclients = (IServerGameClients *)(serverFactory("ServerGameClients003", NULL)))
|
||||
== NULL)
|
||||
{
|
||||
gameclients = (IServerGameClients *)(serverFactory("ServerGameClients004", NULL));
|
||||
}
|
||||
|
||||
echo_msg_func = ExtractRemotePrinter();
|
||||
usermsgs_extracted = CacheUserMessages();
|
||||
|
||||
if (gameclients)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false);
|
||||
}
|
||||
|
||||
ConCommandBaseMgr::OneTimeInit(&g_SMConVarAccessor);
|
||||
}
|
||||
|
||||
void BaseProvider::Notify_DLLShutdown_Pre()
|
||||
{
|
||||
g_SMConVarAccessor.MarkCommandsAsGameDLL();
|
||||
g_SMConVarAccessor.UnregisterGameDLLCommands();
|
||||
}
|
||||
|
||||
bool BaseProvider::IsRemotePrintingAvailable()
|
||||
{
|
||||
return (echo_msg_func != NULL);
|
||||
}
|
||||
|
||||
void BaseProvider::ClientConsolePrint(edict_t *client, const char *message)
|
||||
{
|
||||
engine->ClientPrintf(client, message);
|
||||
}
|
||||
|
||||
void BaseProvider::ServerCommand(const char *cmd)
|
||||
{
|
||||
engine->ServerCommand(cmd);
|
||||
}
|
||||
|
||||
const char *BaseProvider::GetConVarString(ConVar *convar)
|
||||
{
|
||||
return convar->GetString();
|
||||
}
|
||||
|
||||
bool BaseProvider::IsConCommandBaseACommand(ConCommandBase *pCommand)
|
||||
{
|
||||
return pCommand->IsCommand();
|
||||
}
|
||||
|
||||
|
||||
bool BaseProvider::IsSourceEngineBuildCompatible(int build)
|
||||
{
|
||||
return (build == SOURCE_ENGINE_ORIGINAL
|
||||
|| build == SOURCE_ENGINE_EPISODEONE);
|
||||
}
|
||||
|
||||
const char *BaseProvider::GetCommandLineValue(const char *key, const char *defval)
|
||||
{
|
||||
if (key[0] == '-' || key[0] == '+')
|
||||
{
|
||||
return CommandLine()->ParmValue(key, defval);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *val;
|
||||
if ((val = icvar->GetCommandLineValue(key)) == NULL)
|
||||
{
|
||||
return defval;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
int BaseProvider::TryServerGameDLL(const char *iface)
|
||||
{
|
||||
if (strncmp(iface, "ServerGameDLL", 13) != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return atoi(&iface[13]);
|
||||
}
|
||||
|
||||
bool BaseProvider::LogMessage(const char *buffer)
|
||||
{
|
||||
if (!engine)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
engine->LogPrint(buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo)
|
||||
{
|
||||
SourceHook::MemFuncInfo mfi = {true, -1, 0, 0};
|
||||
|
||||
if (hook == ProvidedHook_LevelInit)
|
||||
{
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::LevelInit, mfi);
|
||||
}
|
||||
else if (hook == ProvidedHook_LevelShutdown)
|
||||
{
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::LevelShutdown, mfi);
|
||||
}
|
||||
else if (hook == ProvidedHook_GameInit)
|
||||
{
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::GameInit, mfi);
|
||||
}
|
||||
else if (hook == ProvidedHook_DLLShutdown)
|
||||
{
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfi);
|
||||
}
|
||||
else if (hook == ProvidedHook_DLLInit)
|
||||
{
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::DLLInit, mfi);
|
||||
}
|
||||
|
||||
*pInfo = mfi;
|
||||
|
||||
return (mfi.thisptroffs >= 0);
|
||||
}
|
||||
|
||||
void BaseProvider::DisplayError(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[2048];
|
||||
|
||||
va_start(ap, fmt);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
Error(buffer);
|
||||
}
|
||||
|
||||
void BaseProvider::DisplayWarning(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[2048];
|
||||
|
||||
va_start(ap, fmt);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
Warning(buffer);
|
||||
}
|
||||
|
||||
IConCommandBaseAccessor *BaseProvider::GetConCommandBaseAccessor()
|
||||
{
|
||||
return &g_SMConVarAccessor;
|
||||
}
|
||||
|
||||
bool BaseProvider::RegisterConCommandBase(ConCommandBase *pCommand)
|
||||
{
|
||||
return g_SMConVarAccessor.Register(pCommand);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
ConVar *BaseProvider::CreateConVar(const char *name,
|
||||
const char *defval,
|
||||
const char *help,
|
||||
int flags)
|
||||
{
|
||||
int newflags = 0;
|
||||
if (flags & ConVarFlag_Notify)
|
||||
{
|
||||
newflags |= FCVAR_NOTIFY;
|
||||
}
|
||||
if (flags & ConVarFlag_Replicated)
|
||||
{
|
||||
newflags |= FCVAR_REPLICATED;
|
||||
}
|
||||
if (flags & ConVarFlag_SpOnly)
|
||||
{
|
||||
newflags |= FCVAR_SPONLY;
|
||||
}
|
||||
|
||||
return new ConVar(name, defval, newflags, help);
|
||||
}
|
||||
|
||||
IServerPluginCallbacks *BaseProvider::GetVSPCallbacks(const char *iface)
|
||||
{
|
||||
g_VspListener.SetLoadable(true);
|
||||
return &g_VspListener;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
CON_COMMAND(meta, "Metamod:Source control commands")
|
||||
{
|
||||
GlobCommand cmd;
|
||||
Command_Meta(&cmd);
|
||||
}
|
||||
|
||||
void ClientCommand(edict_t *pEdict)
|
||||
{
|
||||
GlobCommand cmd;
|
||||
|
||||
if (strcmp(cmd.GetArg(0), "meta") == 0)
|
||||
{
|
||||
Command_ClientMeta(pEdict, &cmd);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//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 //
|
||||
// "Echo text to console", you'll find the callback cmd pushed on the //
|
||||
// stack.) //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define SIGLEN 8
|
||||
#define ENGINE486_SIG "\x55\x89\xE5\x53\x83\xEC\x14\xBB"
|
||||
#define ENGINE486_OFFS 40
|
||||
#define ENGINE686_SIG "\x53\x83\xEC\x08\xBB\x01\x00\x00"
|
||||
#define ENGINE686_OFFS 50
|
||||
#define ENGINEAMD_SIG "\x53\x51\xBB\x01\x00\x00\x00\x51"
|
||||
#define ENGINEAMD_OFFS 47
|
||||
#define ENGINEW32_SIG "\xA1\x2A\x2A\x2A\x2A\x56\xBE\x01"
|
||||
#define ENGINEW32_OFFS 38
|
||||
#define IA32_CALL 0xE8
|
||||
|
||||
bool vcmp(const void *_addr1, const void *_addr2, size_t len)
|
||||
{
|
||||
unsigned char *addr1 = (unsigned char *)_addr1;
|
||||
unsigned char *addr2 = (unsigned char *)_addr2;
|
||||
|
||||
for (size_t i=0; i<len; i++)
|
||||
{
|
||||
if (addr2[i] == '*')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (addr1[i] != addr2[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Thanks to fysh for the idea of extracting info from "echo" and for
|
||||
// having the original offsets at hand!
|
||||
CONPRINTF_FUNC ExtractRemotePrinter()
|
||||
{
|
||||
ConCommandBase *pBase = icvar->GetCommands();
|
||||
unsigned char *ptr = NULL;
|
||||
FnCommandCallback callback = NULL;
|
||||
int offs = 0;
|
||||
|
||||
while (pBase)
|
||||
{
|
||||
if (strcmp(pBase->GetName(), "echo") == 0)
|
||||
{
|
||||
callback = ((ConCommand *)pBase)->GetCallback();
|
||||
ptr = (unsigned char *)callback;
|
||||
#ifdef OS_LINUX
|
||||
if (vcmp(ptr, ENGINE486_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINE486_OFFS;
|
||||
}
|
||||
else if (vcmp(ptr, ENGINE686_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINE686_OFFS;
|
||||
}
|
||||
else if (vcmp(ptr, ENGINEAMD_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINEAMD_OFFS;
|
||||
}
|
||||
#elif defined OS_WIN32 // Only one Windows engine binary so far...
|
||||
if (vcmp(ptr, ENGINEW32_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINEW32_OFFS;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!offs || ptr[offs - 1] != IA32_CALL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
//get the relative offset
|
||||
void *addr = *((void **)(ptr + offs));
|
||||
//add the base offset, to the ip (which is the address+offset + 4 bytes for next instruction)
|
||||
return (CONPRINTF_FUNC)((unsigned long)addr + (unsigned long)(ptr + offs) + 4);
|
||||
}
|
||||
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
|
||||
}
|
||||
|
||||
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 = (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;
|
||||
}
|
||||
|
81
sourcemm/episode1/provider_ep1.h
Normal file
81
sourcemm/episode1/provider_ep1.h
Normal file
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
|
||||
#define _INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
|
||||
|
||||
#include <sourcehook.h>
|
||||
#include <sh_memfuncinfo.h>
|
||||
#include <iserverplugin.h>
|
||||
#include "ISmmAPI.h"
|
||||
#include "metamod_provider.h"
|
||||
#include "metamod_oslink.h"
|
||||
|
||||
using namespace SourceMM;
|
||||
using namespace SourceHook;
|
||||
|
||||
class BaseProvider : public IMetamodSourceProvider
|
||||
{
|
||||
public:
|
||||
virtual bool IsSourceEngineBuildCompatible(int build);
|
||||
virtual bool GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo);
|
||||
virtual bool LogMessage(const char *buffer);
|
||||
virtual const char *GetCommandLineValue(const char *key, const char *defval);
|
||||
virtual void ConsolePrint(const char *msg);
|
||||
virtual bool IsRemotePrintingAvailable();
|
||||
virtual void ClientConsolePrint(edict_t *client, const char *msg);
|
||||
virtual IServerPluginCallbacks *GetVSPCallbacks(const char *iface);
|
||||
virtual void DisplayError(const char *fmt, ...);
|
||||
virtual void DisplayWarning(const char *fmt, ...);
|
||||
virtual int TryServerGameDLL(const char *iface);
|
||||
virtual void Notify_DLLInit_Pre(void *gamedll,
|
||||
CreateInterfaceFn engineFactory,
|
||||
CreateInterfaceFn serverFactory);
|
||||
void Notify_DLLShutdown_Pre();
|
||||
virtual void ServerCommand(const char *cmd);
|
||||
virtual ConVar *CreateConVar(const char *name,
|
||||
const char *defval,
|
||||
const char *help,
|
||||
int flags);
|
||||
virtual const char *GetConVarString(ConVar *convar);
|
||||
virtual const char *GetGameDescription();
|
||||
virtual IConCommandBaseAccessor *GetConCommandBaseAccessor();
|
||||
virtual bool RegisterConCommandBase(ConCommandBase *pCommand);
|
||||
virtual void UnregisterConCommandBase(ConCommandBase *pCommand);
|
||||
virtual bool IsConCommandBaseACommand(ConCommandBase *pCommand);
|
||||
virtual int GetUserMessageCount();
|
||||
virtual int FindUserMessage(const char *name, int *size=NULL);
|
||||
virtual const char *GetUserMessage(int index, int *size=NULL);
|
||||
};
|
||||
|
||||
extern IVEngineServer *engine;
|
||||
extern IServerGameDLL *server;
|
||||
extern IServerGameClients *gameclients;
|
||||
extern ICvar *icvar;
|
||||
|
||||
#endif //_INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
|
||||
|
@ -1,24 +1,40 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* License: zlib/libpng
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "vsp_listener.h"
|
||||
#include "CPlugin.h"
|
||||
#include "svn_version.h"
|
||||
#include "metamod.h"
|
||||
|
||||
using namespace SourceMM;
|
||||
|
||||
VSPListener g_VspListener;
|
||||
|
||||
VSPListener::VSPListener()
|
||||
{
|
||||
m_Loaded = false;
|
||||
m_Loadable = false;
|
||||
m_bLoaded = false;
|
||||
m_bLoadable = false;
|
||||
}
|
||||
|
||||
void VSPListener::ClientActive(edict_t *pEntity)
|
||||
@ -57,12 +73,12 @@ void VSPListener::GameFrame(bool simulating)
|
||||
|
||||
const char *VSPListener::GetPluginDescription()
|
||||
{
|
||||
return "Metamod:Source Interface v" SOURCEMM_VERSION;
|
||||
return "Metamod:Source Interface v" SVN_FILE_VERSION_STRING;
|
||||
}
|
||||
|
||||
bool VSPListener::IsLoaded()
|
||||
{
|
||||
return m_Loaded;
|
||||
return m_bLoaded;
|
||||
}
|
||||
|
||||
void VSPListener::LevelInit(char const *pMapName)
|
||||
@ -96,57 +112,27 @@ void VSPListener::Unload()
|
||||
|
||||
void VSPListener::SetLoadable(bool set)
|
||||
{
|
||||
m_Loadable = set;
|
||||
m_bLoadable = set;
|
||||
}
|
||||
|
||||
bool VSPListener::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory)
|
||||
{
|
||||
if (!g_GameDll.loaded)
|
||||
{
|
||||
Error("Metamod:Source is not a Valve Server Plugin\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_Loadable)
|
||||
if (!m_bLoadable)
|
||||
{
|
||||
Warning("Do not manually load Metamod:Source as a Valve Server Plugin\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_Loaded)
|
||||
if (m_bLoaded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Loaded = true;
|
||||
m_bLoaded = true;
|
||||
SetLoadable(false);
|
||||
|
||||
PluginIter iter;
|
||||
CPluginManager::CPlugin *pPlugin;
|
||||
SourceHook::List<IMetamodListener *>::iterator event;
|
||||
IMetamodListener *pML;
|
||||
for (iter=g_PluginMngr._begin(); iter!=g_PluginMngr._end(); iter++)
|
||||
{
|
||||
pPlugin = (*iter);
|
||||
if (pPlugin->m_Status < Pl_Paused)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* Only valid for plugins >= 10 (v1:5, SourceMM 1.4) */
|
||||
if (pPlugin->m_API->GetApiVersion() < 10)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (event=pPlugin->m_Events.begin();
|
||||
event!=pPlugin->m_Events.end();
|
||||
event++)
|
||||
{
|
||||
pML = (*event);
|
||||
pML->OnVSPListening(this);
|
||||
}
|
||||
}
|
||||
g_Metamod.NotifyVSPListening(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
64
sourcemm/episode1/vsp_listener.h
Normal file
64
sourcemm/episode1/vsp_listener.h
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_
|
||||
#define _INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_
|
||||
|
||||
#include "iserverplugin.h"
|
||||
|
||||
class VSPListener : public IServerPluginCallbacks
|
||||
{
|
||||
public:
|
||||
VSPListener();
|
||||
public:
|
||||
virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory);
|
||||
virtual void Unload();
|
||||
virtual void Pause();
|
||||
virtual void UnPause();
|
||||
virtual const char *GetPluginDescription();
|
||||
virtual void LevelInit(char const *pMapName);
|
||||
virtual void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
virtual void GameFrame(bool simulating);
|
||||
virtual void LevelShutdown(void);
|
||||
virtual void ClientActive(edict_t *pEntity);
|
||||
virtual void ClientDisconnect(edict_t *pEntity);
|
||||
virtual void ClientPutInServer(edict_t *pEntity, char const *playername);
|
||||
virtual void SetCommandClient(int index);
|
||||
virtual void ClientSettingsChanged(edict_t *pEdict);
|
||||
virtual PLUGIN_RESULT ClientConnect(bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||
virtual PLUGIN_RESULT ClientCommand(edict_t *pEntity);
|
||||
virtual PLUGIN_RESULT NetworkIDValidated(const char *pszUserName, const char *pszNetworkID);
|
||||
public:
|
||||
bool IsLoaded();
|
||||
void SetLoadable(bool loadable);
|
||||
private:
|
||||
bool m_bLoaded;
|
||||
bool m_bLoadable;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_
|
||||
|
55
sourcemm/episode2/console.cpp
Normal file
55
sourcemm/episode2/console.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "console.h"
|
||||
#include "provider_ep2.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
SMConVarAccessor g_SMConVarAccessor;
|
||||
|
||||
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
|
||||
{
|
||||
pCommand->SetNext(NULL);
|
||||
icvar->RegisterConCommand(pCommand);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SMConVarAccessor::Register(ConCommandBase *pCommand)
|
||||
{
|
||||
pCommand->SetNext(NULL);
|
||||
icvar->RegisterConCommand(pCommand);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SMConVarAccessor::Unregister(ConCommandBase *pCommand)
|
||||
{
|
||||
icvar->UnregisterConCommand(pCommand);
|
||||
}
|
||||
|
55
sourcemm/episode2/console.h
Normal file
55
sourcemm/episode2/console.h
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_CONSOLE_MMS_H_
|
||||
#define _INCLUDE_CONSOLE_MMS_H_
|
||||
|
||||
#if defined _DEBUG
|
||||
#define DEBUG2
|
||||
#undef _DEBUG
|
||||
#endif
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include "convar.h"
|
||||
#include <sh_list.h>
|
||||
#if defined DEBUG2
|
||||
#undef DEBUG2
|
||||
#define _DEBUG
|
||||
#endif
|
||||
|
||||
class SMConVarAccessor : public IConCommandBaseAccessor
|
||||
{
|
||||
public:
|
||||
bool RegisterConCommandBase(ConCommandBase *pCommand);
|
||||
bool Register(ConCommandBase *pCommand);
|
||||
void Unregister(ConCommandBase *pCommand);
|
||||
};
|
||||
|
||||
extern SMConVarAccessor g_SMConVarAccessor;
|
||||
|
||||
#endif //_INCLUDE_CONSOLE_MMS_H_
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stub_mm", "stub_mm.vcproj", "{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sourcemm", "sourcemm.vcproj", "{F7D47743-73B3-49B5-9D76-2333C5DFD565}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -9,10 +9,10 @@ Global
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Release|Win32.Build.0 = Release|Win32
|
||||
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
@ -2,9 +2,9 @@
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="sample_mm"
|
||||
ProjectGUID="{FAFF34FB-FE14-47B5-81BD-70D237392FB2}"
|
||||
RootNamespace="sample_mm"
|
||||
Name="metamodsource_ep1"
|
||||
ProjectGUID="{F7D47743-73B3-49B5-9D76-2333C5DFD565}"
|
||||
RootNamespace="sourcemm"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
@ -41,7 +41,8 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
|
||||
AdditionalIncludeDirectories="..\..;..\..\..;..\..\..\sourcehook"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
@ -62,14 +63,15 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
|
||||
OutputFile="$(OutDir)/sample_mm.dll"
|
||||
AdditionalDependencies="tier0.lib tier1.lib tier2.lib vstdlib.lib"
|
||||
OutputFile="$(OutDir)/server.dll"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
|
||||
GenerateDebugInformation="true"
|
||||
ProgramDatabaseFile="$(OutDir)/sample_mm.pdb"
|
||||
ProgramDatabaseFile="$(OutDir)/sourcemm.pdb"
|
||||
SubSystem="2"
|
||||
ImportLibrary="$(OutDir)/sample_mm.lib"
|
||||
EnableCOMDATFolding="1"
|
||||
ImportLibrary="$(OutDir)/sourcemm.lib"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
@ -122,11 +124,16 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||
StringPooling="true"
|
||||
ExceptionHandling="1"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="false"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="0"
|
||||
ExpandAttributedSource="true"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
@ -143,14 +150,14 @@
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
|
||||
OutputFile="$(OutDir)/sample_mm.dll"
|
||||
OutputFile="$(OutDir)/server.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="1"
|
||||
ImportLibrary="$(OutDir)/sample_mm.lib"
|
||||
EnableCOMDATFolding="2"
|
||||
ImportLibrary="$(OutDir)/sourcemm.lib"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
@ -187,34 +194,138 @@
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\cvars.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\SamplePlugin.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\cvars.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\SamplePlugin.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\version.rc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Interfaces"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\IPluginManager.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\ISmmAPI.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\ISmmPlugin.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Metamod"
|
||||
>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\metamod.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_console.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_oslink.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_plugins.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_util.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\metamod.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_console.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_oslink.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_plugins.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_provider.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\metamod_util.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Provider"
|
||||
>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\console.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\provider_ep2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vsp_listener.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\console.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\provider_ep2.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vsp_listener.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="SourceHook"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\..\sourcehook\sourcehook.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
548
sourcemm/episode2/provider_ep2.cpp
Normal file
548
sourcemm/episode2/provider_ep2.cpp
Normal file
@ -0,0 +1,548 @@
|
||||
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _DEBUG
|
||||
#define DEBUG2
|
||||
#undef _DEBUG
|
||||
#endif
|
||||
#include <sourcehook.h>
|
||||
#include <convar.h>
|
||||
#include <eiface.h>
|
||||
#include <tier0/icommandline.h>
|
||||
#include <tier1/utldict.h>
|
||||
#include <sh_vector.h>
|
||||
#include <sh_string.h>
|
||||
#include "../metamod_util.h"
|
||||
#include "provider_ep2.h"
|
||||
#include "console.h"
|
||||
#include "metamod_console.h"
|
||||
#include "vsp_listener.h"
|
||||
#if defined DEBUG2
|
||||
#undef DEBUG2
|
||||
#define _DEBUG
|
||||
#endif
|
||||
|
||||
/* Types */
|
||||
typedef void (*CONPRINTF_FUNC)(const char *, ...);
|
||||
struct UsrMsgInfo
|
||||
{
|
||||
int size;
|
||||
String name;
|
||||
};
|
||||
/* Imports */
|
||||
#undef CommandLine
|
||||
DLL_IMPORT ICommandLine *CommandLine();
|
||||
/* Functions */
|
||||
bool CacheUserMessages();
|
||||
void ClientCommand(edict_t *pEdict, const CCommand &args);
|
||||
void LocalCommand_Meta(const CCommand &args);
|
||||
void _ServerCommand();
|
||||
/* Variables */
|
||||
bool usermsgs_extracted = false;
|
||||
CVector<UsrMsgInfo> usermsgs_list;
|
||||
ICvar *icvar = NULL;
|
||||
ISmmAPI *metamod_api = NULL;
|
||||
IVEngineServer *engine = NULL;
|
||||
IServerGameClients *gameclients = NULL;
|
||||
VSPListener g_VspListener;
|
||||
BaseProvider g_Ep1Provider;
|
||||
IMetamodSourceProvider *provider = &g_Ep1Provider;
|
||||
List<ConCommandBase *> conbases_unreg;
|
||||
ConCommand meta_local_cmd("meta", LocalCommand_Meta, "Metamod:Source control options");
|
||||
|
||||
SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *, const CCommand &);
|
||||
|
||||
void BaseProvider::ConsolePrint(const char *str)
|
||||
{
|
||||
ConMsg("%s", str);
|
||||
}
|
||||
|
||||
void BaseProvider::Notify_DLLInit_Pre(void *gamedll,
|
||||
CreateInterfaceFn engineFactory,
|
||||
CreateInterfaceFn serverFactory)
|
||||
{
|
||||
server = (IServerGameDLL *)gamedll;
|
||||
engine = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL));
|
||||
if (!engine)
|
||||
{
|
||||
DisplayError("Could not find IVEngineServer! Metamod cannot load.");
|
||||
return;
|
||||
}
|
||||
icvar = (ICvar *)((engineFactory)(CVAR_INTERFACE_VERSION, NULL));
|
||||
if (!icvar)
|
||||
{
|
||||
DisplayError("Could not find ICvar! Metamod cannot load.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((gameclients = (IServerGameClients *)(serverFactory("ServerGameClients003", NULL)))
|
||||
== NULL)
|
||||
{
|
||||
gameclients = (IServerGameClients *)(serverFactory("ServerGameClients004", NULL));
|
||||
}
|
||||
|
||||
RegisterConCommandBase(&meta_local_cmd);
|
||||
conbases_unreg.push_back(&meta_local_cmd);
|
||||
|
||||
usermsgs_extracted = CacheUserMessages();
|
||||
|
||||
if (gameclients)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseProvider::Notify_DLLShutdown_Pre()
|
||||
{
|
||||
List<ConCommandBase *>::iterator iter;
|
||||
|
||||
for (iter = conbases_unreg.begin();
|
||||
iter != conbases_unreg.end();
|
||||
iter++)
|
||||
{
|
||||
UnregisterConCommandBase((*iter));
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseProvider::IsRemotePrintingAvailable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void BaseProvider::ClientConsolePrint(edict_t *client, const char *message)
|
||||
{
|
||||
engine->ClientPrintf(client, message);
|
||||
}
|
||||
|
||||
void BaseProvider::ServerCommand(const char *cmd)
|
||||
{
|
||||
engine->ServerCommand(cmd);
|
||||
}
|
||||
|
||||
const char *BaseProvider::GetConVarString(ConVar *convar)
|
||||
{
|
||||
if (convar == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return convar->GetString();
|
||||
}
|
||||
|
||||
bool BaseProvider::IsConCommandBaseACommand(ConCommandBase *pCommand)
|
||||
{
|
||||
return pCommand->IsCommand();
|
||||
}
|
||||
|
||||
|
||||
bool BaseProvider::IsSourceEngineBuildCompatible(int build)
|
||||
{
|
||||
return (build == SOURCE_ENGINE_ORIGINAL
|
||||
|| build == SOURCE_ENGINE_EPISODEONE);
|
||||
}
|
||||
|
||||
const char *BaseProvider::GetCommandLineValue(const char *key, const char *defval)
|
||||
{
|
||||
if (key[0] == '-' || key[0] == '+')
|
||||
{
|
||||
return CommandLine_Tier0()->ParmValue(key, defval);
|
||||
}
|
||||
else if (icvar)
|
||||
{
|
||||
const char *val;
|
||||
if ((val = icvar->GetCommandLineValue(key)) == NULL)
|
||||
{
|
||||
return defval;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int BaseProvider::TryServerGameDLL(const char *iface)
|
||||
{
|
||||
if (strncmp(iface, "ServerGameDLL", 13) != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return atoi(&iface[13]);
|
||||
}
|
||||
|
||||
bool BaseProvider::LogMessage(const char *buffer)
|
||||
{
|
||||
if (!engine)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
engine->LogPrint(buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo)
|
||||
{
|
||||
SourceHook::MemFuncInfo mfi = {true, -1, 0, 0};
|
||||
|
||||
if (hook == ProvidedHook_LevelInit)
|
||||
{
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::LevelInit, mfi);
|
||||
}
|
||||
else if (hook == ProvidedHook_LevelShutdown)
|
||||
{
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::LevelShutdown, mfi);
|
||||
}
|
||||
else if (hook == ProvidedHook_GameInit)
|
||||
{
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::GameInit, mfi);
|
||||
}
|
||||
else if (hook == ProvidedHook_DLLShutdown)
|
||||
{
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfi);
|
||||
}
|
||||
else if (hook == ProvidedHook_DLLInit)
|
||||
{
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::DLLInit, mfi);
|
||||
}
|
||||
|
||||
*pInfo = mfi;
|
||||
|
||||
return (mfi.thisptroffs >= 0);
|
||||
}
|
||||
|
||||
void BaseProvider::DisplayError(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[2048];
|
||||
|
||||
va_start(ap, fmt);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
Error(buffer);
|
||||
}
|
||||
|
||||
void BaseProvider::DisplayWarning(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[2048];
|
||||
|
||||
va_start(ap, fmt);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
Warning(buffer);
|
||||
}
|
||||
|
||||
IConCommandBaseAccessor *BaseProvider::GetConCommandBaseAccessor()
|
||||
{
|
||||
return &g_SMConVarAccessor;
|
||||
}
|
||||
|
||||
bool BaseProvider::RegisterConCommandBase(ConCommandBase *pCommand)
|
||||
{
|
||||
return g_SMConVarAccessor.Register(pCommand);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
ConVar *BaseProvider::CreateConVar(const char *name,
|
||||
const char *defval,
|
||||
const char *help,
|
||||
int flags)
|
||||
{
|
||||
int newflags = 0;
|
||||
if (flags & ConVarFlag_Notify)
|
||||
{
|
||||
newflags |= FCVAR_NOTIFY;
|
||||
}
|
||||
if (flags & ConVarFlag_Replicated)
|
||||
{
|
||||
newflags |= FCVAR_REPLICATED;
|
||||
}
|
||||
if (flags & ConVarFlag_SpOnly)
|
||||
{
|
||||
newflags |= FCVAR_SPONLY;
|
||||
}
|
||||
|
||||
ConVar *pVar = new ConVar(name, defval, newflags, help);
|
||||
|
||||
RegisterConCommandBase(pVar);
|
||||
conbases_unreg.push_back(pVar);
|
||||
|
||||
return pVar;
|
||||
}
|
||||
|
||||
IServerPluginCallbacks *BaseProvider::GetVSPCallbacks(const char *iface)
|
||||
{
|
||||
g_VspListener.SetLoadable(true);
|
||||
return &g_VspListener;
|
||||
}
|
||||
|
||||
class GlobCommand : public IMetamodSourceCommandInfo
|
||||
{
|
||||
public:
|
||||
GlobCommand(const CCommand *cmd) : m_cmd(cmd)
|
||||
{
|
||||
}
|
||||
public:
|
||||
unsigned int GetArgCount()
|
||||
{
|
||||
return m_cmd->ArgC();
|
||||
}
|
||||
|
||||
const char *GetArg(unsigned int num)
|
||||
{
|
||||
return m_cmd->Arg(num);
|
||||
}
|
||||
|
||||
const char *GetArgString()
|
||||
{
|
||||
return m_cmd->ArgS();
|
||||
}
|
||||
private:
|
||||
const CCommand *m_cmd;
|
||||
};
|
||||
|
||||
void LocalCommand_Meta(const CCommand &args)
|
||||
{
|
||||
GlobCommand cmd(&args);
|
||||
Command_Meta(&cmd);
|
||||
}
|
||||
|
||||
void ClientCommand(edict_t *pEdict, const CCommand &_cmd)
|
||||
{
|
||||
GlobCommand cmd(&_cmd);
|
||||
|
||||
if (strcmp(cmd.GetArg(0), "meta") == 0)
|
||||
{
|
||||
Command_ClientMeta(pEdict, &cmd);
|
||||
}
|
||||
}
|
||||
|
||||
bool vcmp(const void *_addr1, const void *_addr2, size_t len)
|
||||
{
|
||||
unsigned char *addr1 = (unsigned char *)_addr1;
|
||||
unsigned char *addr2 = (unsigned char *)_addr2;
|
||||
|
||||
for (size_t i=0; i<len; i++)
|
||||
{
|
||||
if (addr2[i] == '*')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (addr1[i] != addr2[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// 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 = (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;
|
||||
}
|
||||
|
89
sourcemm/episode2/provider_ep2.h
Normal file
89
sourcemm/episode2/provider_ep2.h
Normal file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
|
||||
#define _INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
|
||||
|
||||
#if defined _DEBUG
|
||||
#define DEBUG2
|
||||
#undef _DEBUG
|
||||
#endif
|
||||
#include <sourcehook.h>
|
||||
#include <sh_memfuncinfo.h>
|
||||
#include <iserverplugin.h>
|
||||
#include "ISmmAPI.h"
|
||||
#include "metamod_provider.h"
|
||||
#include "metamod_oslink.h"
|
||||
#if defined DEBUG2
|
||||
#undef DEBUG2
|
||||
#define _DEBUG
|
||||
#endif
|
||||
|
||||
using namespace SourceMM;
|
||||
using namespace SourceHook;
|
||||
|
||||
class BaseProvider : public IMetamodSourceProvider
|
||||
{
|
||||
public:
|
||||
virtual bool IsSourceEngineBuildCompatible(int build);
|
||||
virtual bool GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo);
|
||||
virtual bool LogMessage(const char *buffer);
|
||||
virtual const char *GetCommandLineValue(const char *key, const char *defval);
|
||||
virtual void ConsolePrint(const char *msg);
|
||||
virtual bool IsRemotePrintingAvailable();
|
||||
virtual void ClientConsolePrint(edict_t *client, const char *msg);
|
||||
virtual IServerPluginCallbacks *GetVSPCallbacks(const char *iface);
|
||||
virtual void DisplayError(const char *fmt, ...);
|
||||
virtual void DisplayWarning(const char *fmt, ...);
|
||||
virtual int TryServerGameDLL(const char *iface);
|
||||
virtual void Notify_DLLInit_Pre(void *gamedll,
|
||||
CreateInterfaceFn engineFactory,
|
||||
CreateInterfaceFn serverFactory);
|
||||
void Notify_DLLShutdown_Pre();
|
||||
virtual void ServerCommand(const char *cmd);
|
||||
virtual ConVar *CreateConVar(const char *name,
|
||||
const char *defval,
|
||||
const char *help,
|
||||
int flags);
|
||||
virtual const char *GetConVarString(ConVar *convar);
|
||||
virtual const char *GetGameDescription();
|
||||
virtual IConCommandBaseAccessor *GetConCommandBaseAccessor();
|
||||
virtual bool RegisterConCommandBase(ConCommandBase *pCommand);
|
||||
virtual void UnregisterConCommandBase(ConCommandBase *pCommand);
|
||||
virtual bool IsConCommandBaseACommand(ConCommandBase *pCommand);
|
||||
virtual int GetUserMessageCount();
|
||||
virtual int FindUserMessage(const char *name, int *size=NULL);
|
||||
virtual const char *GetUserMessage(int index, int *size=NULL);
|
||||
};
|
||||
|
||||
extern IVEngineServer *engine;
|
||||
extern IServerGameDLL *server;
|
||||
extern IServerGameClients *gameclients;
|
||||
extern ICvar *icvar;
|
||||
|
||||
#endif //_INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
|
||||
|
141
sourcemm/episode2/vsp_listener.cpp
Normal file
141
sourcemm/episode2/vsp_listener.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "vsp_listener.h"
|
||||
#include "svn_version.h"
|
||||
#include "metamod.h"
|
||||
|
||||
using namespace SourceMM;
|
||||
|
||||
VSPListener::VSPListener()
|
||||
{
|
||||
m_bLoaded = false;
|
||||
m_bLoadable = false;
|
||||
}
|
||||
|
||||
void VSPListener::ClientActive(edict_t *pEntity)
|
||||
{
|
||||
}
|
||||
|
||||
PLUGIN_RESULT VSPListener::ClientCommand(edict_t *pEntity, const CCommand &cmd)
|
||||
{
|
||||
return PLUGIN_CONTINUE;
|
||||
}
|
||||
|
||||
PLUGIN_RESULT VSPListener::ClientConnect(bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
|
||||
{
|
||||
return PLUGIN_CONTINUE;
|
||||
}
|
||||
|
||||
void VSPListener::ClientDisconnect(edict_t *pEntity)
|
||||
{
|
||||
}
|
||||
|
||||
void VSPListener::ClientPutInServer(edict_t *pEntity, char const *playername)
|
||||
{
|
||||
}
|
||||
|
||||
void VSPListener::ClientSettingsChanged(edict_t *pEdict)
|
||||
{
|
||||
}
|
||||
|
||||
void VSPListener::SetCommandClient(int index)
|
||||
{
|
||||
}
|
||||
|
||||
void VSPListener::GameFrame(bool simulating)
|
||||
{
|
||||
}
|
||||
|
||||
const char *VSPListener::GetPluginDescription()
|
||||
{
|
||||
return "Metamod:Source Interface v" SVN_FILE_VERSION_STRING;
|
||||
}
|
||||
|
||||
bool VSPListener::IsLoaded()
|
||||
{
|
||||
return m_bLoaded;
|
||||
}
|
||||
|
||||
void VSPListener::LevelInit(char const *pMapName)
|
||||
{
|
||||
}
|
||||
|
||||
void VSPListener::LevelShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
PLUGIN_RESULT VSPListener::NetworkIDValidated(const char *pszUserName, const char *pszNetworkID)
|
||||
{
|
||||
return PLUGIN_CONTINUE;
|
||||
}
|
||||
|
||||
void VSPListener::Pause()
|
||||
{
|
||||
}
|
||||
|
||||
void VSPListener::UnPause()
|
||||
{
|
||||
}
|
||||
|
||||
void VSPListener::ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
|
||||
{
|
||||
}
|
||||
|
||||
void VSPListener::Unload()
|
||||
{
|
||||
}
|
||||
|
||||
void VSPListener::SetLoadable(bool set)
|
||||
{
|
||||
m_bLoadable = set;
|
||||
}
|
||||
|
||||
bool VSPListener::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory)
|
||||
{
|
||||
if (!m_bLoadable)
|
||||
{
|
||||
provider->DisplayWarning("Do not manually load Metamod:Source as a Valve Server Plugin\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_bLoaded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bLoaded = true;
|
||||
SetLoadable(false);
|
||||
|
||||
g_Metamod.NotifyVSPListening(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VSPListener::OnQueryCvarValueFinished(QueryCvarCookie_t iCookie, edict_t *pPlayerEntity, EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue )
|
||||
{
|
||||
}
|
73
sourcemm/episode2/vsp_listener.h
Normal file
73
sourcemm/episode2/vsp_listener.h
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_
|
||||
#define _INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_
|
||||
|
||||
#if defined _DEBUG
|
||||
#define DEBUG2
|
||||
#undef _DEBUG
|
||||
#endif
|
||||
#include "iserverplugin.h"
|
||||
#if defined DEBUG2
|
||||
#undef DEBUG2
|
||||
#define _DEBUG
|
||||
#endif
|
||||
|
||||
class VSPListener : public IServerPluginCallbacks
|
||||
{
|
||||
public:
|
||||
VSPListener();
|
||||
public:
|
||||
virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory);
|
||||
virtual void Unload();
|
||||
virtual void Pause();
|
||||
virtual void UnPause();
|
||||
virtual const char *GetPluginDescription();
|
||||
virtual void LevelInit(char const *pMapName);
|
||||
virtual void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
virtual void GameFrame(bool simulating);
|
||||
virtual void LevelShutdown(void);
|
||||
virtual void ClientActive(edict_t *pEntity);
|
||||
virtual void ClientDisconnect(edict_t *pEntity);
|
||||
virtual void ClientPutInServer(edict_t *pEntity, char const *playername);
|
||||
virtual void SetCommandClient(int index);
|
||||
virtual void ClientSettingsChanged(edict_t *pEdict);
|
||||
virtual PLUGIN_RESULT ClientConnect(bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||
virtual PLUGIN_RESULT ClientCommand(edict_t *pEntity, const CCommand &cmd);
|
||||
virtual PLUGIN_RESULT NetworkIDValidated(const char *pszUserName, const char *pszNetworkID);
|
||||
virtual void OnQueryCvarValueFinished( QueryCvarCookie_t iCookie, edict_t *pPlayerEntity, EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue );
|
||||
public:
|
||||
bool IsLoaded();
|
||||
void SetLoadable(bool loadable);
|
||||
private:
|
||||
bool m_bLoaded;
|
||||
bool m_bLoadable;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_
|
||||
|
1244
sourcemm/metamod.cpp
Normal file
1244
sourcemm/metamod.cpp
Normal file
@ -0,0 +1,1244 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _DEBUG
|
||||
#define DEBUG2
|
||||
#undef _DEBUG
|
||||
#endif
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include "metamod.h"
|
||||
#include "metamod_provider.h"
|
||||
#include "metamod_plugins.h"
|
||||
#include "metamod_util.h"
|
||||
#include "metamod_console.h"
|
||||
#include "metamod_oslink.h"
|
||||
#if defined DEBUG2
|
||||
#undef DEBUG2
|
||||
#define _DEBUG
|
||||
#endif
|
||||
|
||||
using namespace SourceMM;
|
||||
using namespace SourceHook;
|
||||
|
||||
/**
|
||||
* @brief Implementation of main SourceMM GameDLL functionality
|
||||
* @file sourcemm.cpp
|
||||
*/
|
||||
|
||||
SH_DECL_MANUALHOOK4(SGD_DLLInit, 0, 0, 0, bool, CreateInterfaceFn, CreateInterfaceFn, CreateInterfaceFn, CGlobalVars *);
|
||||
SH_DECL_MANUALHOOK0(SGD_GameInit, 0, 0, 0, bool);
|
||||
SH_DECL_MANUALHOOK6(SGD_LevelInit, 0, 0, 0, bool, const char *, const char *, const char *, const char *, bool, bool);
|
||||
SH_DECL_MANUALHOOK0_void(SGD_LevelShutdown, 0, 0, 0);
|
||||
SH_DECL_MANUALHOOK0_void(SGD_DLLShutdown, 0, 0, 0);
|
||||
|
||||
bool Handler_DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals);
|
||||
bool Handler_DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals);
|
||||
void Handler_DLLShutdown();
|
||||
void Handler_LevelShutdown();
|
||||
bool Handler_LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
|
||||
bool Handler_GameInit();
|
||||
void InitializeVSP();
|
||||
|
||||
struct game_dll_t
|
||||
{
|
||||
HINSTANCE lib;
|
||||
CreateInterfaceFn factory;
|
||||
};
|
||||
|
||||
String mod_path;
|
||||
String metamod_path;
|
||||
String full_bin_path;
|
||||
bool parsed_game_info = false;
|
||||
int vsp_version = 0;
|
||||
int gamedll_version = 0;
|
||||
int engine_build = SOURCE_ENGINE_UNKNOWN;
|
||||
List<game_dll_t *> gamedll_list;
|
||||
bool is_gamedll_loaded = false;
|
||||
bool in_first_level = true;
|
||||
bool is_game_init = false;
|
||||
bool vsp_load_attempted = false;
|
||||
bool vsp_load_requested = false;
|
||||
bool vsp_loaded = false;
|
||||
game_dll_t gamedll_info;
|
||||
ConVar *metamod_version = NULL;
|
||||
ConVar *mm_pluginsfile = NULL;
|
||||
IServerGameDLL *server = NULL;
|
||||
CreateInterfaceFn engine_factory = NULL;
|
||||
CreateInterfaceFn physics_factory = NULL;
|
||||
CreateInterfaceFn filesystem_factory = NULL;
|
||||
CGlobalVars *gpGlobals = NULL;
|
||||
SourceHook::CSourceHookImpl g_SourceHook;
|
||||
SourceHook::ISourceHook *g_SHPtr = &g_SourceHook;
|
||||
PluginId g_PLID = Pl_Console;
|
||||
META_RES last_meta_res;
|
||||
IServerPluginCallbacks *vsp_callbacks = NULL;
|
||||
|
||||
MetamodSource g_Metamod;
|
||||
|
||||
void ClearGamedllList();
|
||||
|
||||
/* Helper Macro */
|
||||
#define IFACE_MACRO(orig,nam) \
|
||||
CPluginManager::CPlugin *pl; \
|
||||
SourceHook::List<IMetamodListener *>::iterator event; \
|
||||
IMetamodListener *api; \
|
||||
int mret = 0; \
|
||||
void *val = NULL; \
|
||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
||||
pl = (*iter); \
|
||||
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
|
||||
api = (*event); \
|
||||
mret = IFACE_FAILED; \
|
||||
if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \
|
||||
if (ret) *ret = mret; \
|
||||
return val; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
return (orig)(iface, ret);
|
||||
|
||||
#define ITER_EVENT(evn, args) \
|
||||
CPluginManager::CPlugin *pl; \
|
||||
SourceHook::List<IMetamodListener *>::iterator event; \
|
||||
IMetamodListener *api; \
|
||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
||||
pl = (*iter); \
|
||||
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
|
||||
api = (*event); \
|
||||
api->evn args; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Initialize everything here */
|
||||
void InitMainStates()
|
||||
{
|
||||
char full_path[PATH_SIZE] = {0};
|
||||
GetFileOfAddress((void *)gamedll_info.factory, full_path, sizeof(full_path));
|
||||
full_bin_path.assign(full_path);
|
||||
|
||||
/* Like Metamod, reload plugins at the end of the map.
|
||||
* This is so plugins can hook everything on load, BUT, new plugins will be reloaded
|
||||
* if the server is shut down (silly, but rare case).
|
||||
*/
|
||||
in_first_level = true;
|
||||
|
||||
SourceHook::MemFuncInfo info;
|
||||
|
||||
if (!provider->GetHookInfo(ProvidedHook_DLLInit, &info))
|
||||
{
|
||||
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::DLLInit");
|
||||
}
|
||||
SH_MANUALHOOK_RECONFIGURE(SGD_DLLInit, info.vtblindex, info.vtbloffs, info.thisptroffs);
|
||||
SH_ADD_MANUALHOOK_STATICFUNC(SGD_DLLInit, server, Handler_DLLInit, false);
|
||||
SH_ADD_MANUALHOOK_STATICFUNC(SGD_DLLInit, server, Handler_DLLInit_Post, true);
|
||||
|
||||
if (!provider->GetHookInfo(ProvidedHook_GameInit, &info))
|
||||
{
|
||||
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::GameInit");
|
||||
}
|
||||
SH_MANUALHOOK_RECONFIGURE(SGD_GameInit, info.vtblindex, info.vtbloffs, info.thisptroffs);
|
||||
SH_ADD_MANUALHOOK_STATICFUNC(SGD_GameInit, server, Handler_GameInit, false);
|
||||
|
||||
if (!provider->GetHookInfo(ProvidedHook_LevelInit, &info))
|
||||
{
|
||||
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::LevelInit");
|
||||
}
|
||||
SH_MANUALHOOK_RECONFIGURE(SGD_LevelInit, info.vtblindex, info.vtbloffs, info.thisptroffs);
|
||||
SH_ADD_MANUALHOOK_STATICFUNC(SGD_LevelInit, server, Handler_LevelInit, true);
|
||||
|
||||
if (!provider->GetHookInfo(ProvidedHook_LevelShutdown, &info))
|
||||
{
|
||||
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::LevelShutdown");
|
||||
}
|
||||
SH_MANUALHOOK_RECONFIGURE(SGD_LevelShutdown, info.vtblindex, info.vtbloffs, info.thisptroffs);
|
||||
SH_ADD_MANUALHOOK_STATICFUNC(SGD_LevelShutdown, server, Handler_LevelShutdown, true);
|
||||
|
||||
if (!provider->GetHookInfo(ProvidedHook_DLLShutdown, &info))
|
||||
{
|
||||
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::DLLShutdown");
|
||||
}
|
||||
SH_MANUALHOOK_RECONFIGURE(SGD_DLLShutdown, info.vtblindex, info.vtbloffs, info.thisptroffs);
|
||||
SH_ADD_MANUALHOOK_STATICFUNC(SGD_DLLShutdown, server, Handler_DLLShutdown, false);
|
||||
}
|
||||
|
||||
/* This is where the magic happens */
|
||||
SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
{
|
||||
/* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */
|
||||
if (strcmp(iface, PLAPI_NAME) == 0)
|
||||
{
|
||||
provider->DisplayWarning("Do not try loading Metamod:Source as a plugin.\n");
|
||||
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_FAILED;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strncmp(iface, "ISERVERPLUGINCALLBACKS", 22) == 0)
|
||||
{
|
||||
vsp_callbacks = provider->GetVSPCallbacks(iface);
|
||||
|
||||
if (vsp_callbacks != NULL && vsp_version == 0)
|
||||
{
|
||||
vsp_version = atoi(&iface[22]);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
*ret = (vsp_callbacks != NULL) ? IFACE_OK : IFACE_FAILED;
|
||||
}
|
||||
|
||||
return vsp_callbacks;
|
||||
}
|
||||
|
||||
if (!parsed_game_info)
|
||||
{
|
||||
parsed_game_info = true;
|
||||
const char *game_dir = NULL;
|
||||
char game_path[PATH_SIZE];
|
||||
char mm_path[PATH_SIZE];
|
||||
|
||||
/* Get path to SourceMM DLL */
|
||||
if (!GetFileOfAddress((void *)CreateInterface, mm_path, sizeof(mm_path)))
|
||||
{
|
||||
provider->DisplayError("GetFileOfAddress() failed! Metamod cannot load.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
metamod_path.assign(mm_path);
|
||||
|
||||
/* Get value of -game from command line, defaulting to hl2 as engine seems to do */
|
||||
game_dir = provider->GetCommandLineValue("-game", "hl2");
|
||||
|
||||
engine_build = SOURCE_ENGINE_ORANGEBOX;
|
||||
|
||||
/* Get absolute path */
|
||||
abspath(game_path, game_dir);
|
||||
mod_path.assign(game_path);
|
||||
|
||||
char temp_path[PATH_SIZE];
|
||||
|
||||
/* Path to gameinfo.txt */
|
||||
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s", mod_path.c_str(), "gameinfo.txt");
|
||||
|
||||
FILE *fp = fopen(temp_path, "rt");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
provider->DisplayError("Unable to open gameinfo.txt! Metamod cannot load.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char buffer[255];
|
||||
char key[128], val[128];
|
||||
bool search = false;
|
||||
bool gamebin = false;
|
||||
char *ptr;
|
||||
const char *lptr;
|
||||
char cur_path[PATH_SIZE];
|
||||
|
||||
getcwd(cur_path, PATH_SIZE);
|
||||
|
||||
while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL)
|
||||
{
|
||||
UTIL_TrimComments(buffer);
|
||||
UTIL_TrimLeft(buffer);
|
||||
UTIL_TrimRight(buffer);
|
||||
|
||||
if (stricmp(buffer, "SearchPaths") == 0)
|
||||
{
|
||||
search = true;
|
||||
}
|
||||
|
||||
if (!search)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UTIL_KeySplit(buffer, key, sizeof(key) - 1, val, sizeof(val) - 1);
|
||||
if (stricmp(key, "Game") == 0 || stricmp(key, "GameBin") == 0)
|
||||
{
|
||||
if (stricmp(key, "Game") == 0)
|
||||
{
|
||||
gamebin = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
gamebin = true;
|
||||
}
|
||||
|
||||
if (strncmp(val, "|gameinfo_path|", sizeof("|gameinfo_path|") - 1) == 0)
|
||||
{
|
||||
ptr = &(val[sizeof("|gameinfo_path|") - 1]);
|
||||
if (ptr[0] == '.')
|
||||
{
|
||||
ptr++;
|
||||
}
|
||||
lptr = mod_path.c_str();
|
||||
} else {
|
||||
ptr = val;
|
||||
lptr = cur_path;
|
||||
}
|
||||
|
||||
size_t ptr_len = strlen(ptr);
|
||||
if (ptr[ptr_len] == '/' || ptr[ptr_len] == '\\')
|
||||
{
|
||||
ptr[--ptr_len] = '\0';
|
||||
}
|
||||
|
||||
/* No need to append "bin" if key is GameBin */
|
||||
if (gamebin)
|
||||
{
|
||||
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s/%s", lptr, ptr, SERVER_DLL);
|
||||
}
|
||||
else if (!ptr[0])
|
||||
{
|
||||
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s/%s", lptr, "bin", SERVER_DLL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s/%s/%s", lptr, ptr, "bin", SERVER_DLL);
|
||||
}
|
||||
|
||||
/* If not path to SourceMM... */
|
||||
if (!UTIL_PathCmp(mm_path, temp_path))
|
||||
{
|
||||
FILE *temp_fp = fopen(temp_path, "rb");
|
||||
if (!temp_fp)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
fclose(temp_fp);
|
||||
|
||||
/* Search for a matching game dll */
|
||||
List<game_dll_t *>::iterator iter;
|
||||
game_dll_t *pCheck;
|
||||
bool found = false;
|
||||
for (iter = gamedll_list.begin(); iter != gamedll_list.end(); iter++)
|
||||
{
|
||||
pCheck = (*iter);
|
||||
if (GetFileOfAddress((void *)pCheck->factory, buffer, sizeof(buffer)))
|
||||
{
|
||||
if (UTIL_PathCmp(temp_path, buffer))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
HINSTANCE gamedll = dlmount(temp_path);
|
||||
if (gamedll == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CreateInterfaceFn fn = (CreateInterfaceFn)dlsym(gamedll, "CreateInterface");
|
||||
if (fn == NULL)
|
||||
{
|
||||
dlclose(gamedll);
|
||||
continue;
|
||||
}
|
||||
|
||||
game_dll_t *pInfo = new game_dll_t;
|
||||
pInfo->factory = fn;
|
||||
pInfo->lib = gamedll;
|
||||
gamedll_list.push_back(pInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (!is_gamedll_loaded)
|
||||
{
|
||||
if (strncmp(iface, "ServerGameDLL", 13) == 0)
|
||||
{
|
||||
List<game_dll_t *>::iterator iter;
|
||||
game_dll_t *pInfo;
|
||||
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
if ((server = (IServerGameDLL *)((pInfo->factory)(iface, ret))) != NULL)
|
||||
{
|
||||
if ((gamedll_version = provider->TryServerGameDLL(iface)) != 0)
|
||||
{
|
||||
/* We have a match. Erase us from the list and save our info. */
|
||||
gamedll_list.erase(iter);
|
||||
gamedll_info = *pInfo;
|
||||
delete pInfo;
|
||||
is_gamedll_loaded = true;
|
||||
break;
|
||||
}
|
||||
/* :TODO: error otherwise? */
|
||||
}
|
||||
}
|
||||
|
||||
if (is_gamedll_loaded)
|
||||
{
|
||||
ClearGamedllList();
|
||||
InitMainStates();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_FAILED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wtf do we do... */
|
||||
/* :TODO: .. something a bit more intelligent? */
|
||||
provider->DisplayError("Engine requested unknown interface before GameDLL was known!\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we got here, there's definitely a GameDLL */
|
||||
IFACE_MACRO(gamedll_info.factory, GameDLL);
|
||||
}
|
||||
|
||||
void ClearGamedllList()
|
||||
{
|
||||
List<game_dll_t *>::iterator iter;
|
||||
|
||||
game_dll_t *pInfo;
|
||||
for (iter = gamedll_list.begin(); iter != gamedll_list.end(); iter++)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
dlclose(pInfo->lib);
|
||||
delete pInfo;
|
||||
}
|
||||
|
||||
gamedll_list.clear();
|
||||
}
|
||||
|
||||
int LoadPluginsFromFile(const char *_file)
|
||||
{
|
||||
FILE *fp;
|
||||
int total = 0, skipped=0;
|
||||
PluginId id;
|
||||
bool already;
|
||||
|
||||
fp = fopen(_file, "rt");
|
||||
if (!fp)
|
||||
{
|
||||
LogMessage("[META] Could not open plugins file %s\n", _file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buffer[255], error[255], full_path[255];
|
||||
const char *ptr, *ext, *file;
|
||||
size_t length;
|
||||
while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL)
|
||||
{
|
||||
UTIL_TrimLeft(buffer);
|
||||
UTIL_TrimRight(buffer);
|
||||
|
||||
length = strlen(buffer);
|
||||
if (!length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buffer[0] == '\0' || buffer[0] == ';' || strncmp(buffer, "//", 2) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
file = buffer;
|
||||
if (buffer[0] == '"')
|
||||
{
|
||||
char *cptr = buffer;
|
||||
file = ++cptr;
|
||||
|
||||
while (*cptr)
|
||||
{
|
||||
if (*cptr == '"')
|
||||
{
|
||||
*cptr = '\0';
|
||||
break;
|
||||
}
|
||||
cptr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *cptr = buffer;
|
||||
while (*cptr)
|
||||
{
|
||||
if (isspace(*cptr))
|
||||
{
|
||||
char *optr = cptr;
|
||||
while (*cptr && isspace(*cptr))
|
||||
{
|
||||
cptr++;
|
||||
}
|
||||
*optr = '\0';
|
||||
UTIL_TrimRight(cptr);
|
||||
if (*cptr && isalpha(*cptr))
|
||||
{
|
||||
g_PluginMngr.SetAlias(buffer, cptr);
|
||||
file = cptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cptr++;
|
||||
}
|
||||
}
|
||||
if (!file[0])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* First find if it's an absolute path or not... */
|
||||
if (file[0] == '/' || strncmp(&(file[1]), ":\\", 2) == 0)
|
||||
{
|
||||
/* If we're in an absolute path, ignore our normal heuristics */
|
||||
id = g_PluginMngr.Load(file, Pl_File, already, error, sizeof(error));
|
||||
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
|
||||
{
|
||||
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (already)
|
||||
{
|
||||
skipped++;
|
||||
}
|
||||
else
|
||||
{
|
||||
total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Attempt to find a file extension */
|
||||
ptr = UTIL_GetExtension(file);
|
||||
/* Add an extension if there's none there */
|
||||
if (!ptr)
|
||||
{
|
||||
#if defined WIN32 || defined _WIN32
|
||||
ext = ".dll";
|
||||
#else
|
||||
ext = "_i486.so";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
ext = "";
|
||||
}
|
||||
/* Format the new path */
|
||||
g_Metamod.PathFormat(full_path, sizeof(full_path), "%s/%s%s", mod_path.c_str(), file, ext);
|
||||
id = g_PluginMngr.Load(full_path, Pl_File, already, error, sizeof(error));
|
||||
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
|
||||
{
|
||||
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (already)
|
||||
{
|
||||
skipped++;
|
||||
}
|
||||
else
|
||||
{
|
||||
total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (skipped)
|
||||
{
|
||||
LogMessage("[META] Loaded %d plugins from file (%d already loaded)", total, skipped);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMessage("[META] Loaded %d plugins from file.", total);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void InitializeVSP()
|
||||
{
|
||||
size_t len;
|
||||
char engine_file[PATH_SIZE];
|
||||
char engine_path[PATH_SIZE];
|
||||
char rel_path[PATH_SIZE * 2];
|
||||
|
||||
GetFileOfAddress((void *)engine_factory, engine_file, sizeof(engine_file));
|
||||
|
||||
/* Chop off the "engine" file part */
|
||||
len = strlen(engine_file);
|
||||
for (size_t i = len - 1; i >= 0 && i < len; i--)
|
||||
{
|
||||
if (engine_file[i] == '/' || engine_file[i] == '\\')
|
||||
{
|
||||
engine_file[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
abspath(engine_path, engine_file);
|
||||
|
||||
const char *usepath = metamod_path.c_str();
|
||||
if (UTIL_Relatize(rel_path, sizeof(rel_path), engine_path, metamod_path.c_str()))
|
||||
{
|
||||
usepath = rel_path;
|
||||
}
|
||||
|
||||
char command[PATH_SIZE * 2];
|
||||
UTIL_Format(command, sizeof(command), "plugin_load \"%s\"\n", usepath);
|
||||
provider->ServerCommand(command);
|
||||
}
|
||||
|
||||
/* Wrapper function. This is called when the GameDLL thinks it's using
|
||||
* the engine's real engineFactory.
|
||||
*/
|
||||
void *EngineFactory(const char *iface, int *ret)
|
||||
{
|
||||
IFACE_MACRO(engine_factory, Engine);
|
||||
}
|
||||
|
||||
/* Wrapper function. This is called when the GameDLL thinks it's using
|
||||
* the engine's real physicsFactory.
|
||||
*/
|
||||
void *PhysicsFactory(const char *iface, int *ret)
|
||||
{
|
||||
IFACE_MACRO(physics_factory, Physics);
|
||||
}
|
||||
|
||||
/* Wrapper function. This is called when the GameDLL thinks it's using
|
||||
* the engine's real fileSystemFactory.
|
||||
*/
|
||||
void *FileSystemFactory(const char *iface, int *ret)
|
||||
{
|
||||
IFACE_MACRO(filesystem_factory, FileSystem);
|
||||
}
|
||||
|
||||
void LogMessage(const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
static char buffer[2048];
|
||||
|
||||
va_start(ap, msg);
|
||||
size_t len = vsnprintf(buffer, sizeof(buffer) - 2, msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
buffer[len++] = '\n';
|
||||
buffer[len] = '\0';
|
||||
|
||||
if (!provider->LogMessage(buffer))
|
||||
{
|
||||
fprintf(stdout, "%s", buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool Handler_DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
|
||||
{
|
||||
engine_factory = engineFactory;
|
||||
filesystem_factory = filesystemFactory;
|
||||
physics_factory = physicsFactory;
|
||||
gpGlobals = pGlobals;
|
||||
|
||||
provider->Notify_DLLInit_Pre(server, engineFactory, gamedll_info.factory);
|
||||
|
||||
metamod_version = provider->CreateConVar("metamod_version",
|
||||
SOURCEMM_VERSION,
|
||||
"Metamod:Source Version",
|
||||
ConVarFlag_Notify|ConVarFlag_Replicated|ConVarFlag_SpOnly);
|
||||
|
||||
mm_pluginsfile = provider->CreateConVar("mm_pluginsfile",
|
||||
#if defined WIN32 || defined _WIN32
|
||||
"addons\\metamod\\metaplugins.ini",
|
||||
#else
|
||||
"addons/metamod/metaplugins.ini",
|
||||
#endif
|
||||
"Metamod:Source Plugins File",
|
||||
ConVarFlag_SpOnly);
|
||||
|
||||
const char *pluginFile = provider->GetCommandLineValue("mm_pluginsfile", NULL);
|
||||
if (!pluginFile)
|
||||
{
|
||||
pluginFile = provider->GetConVarString(mm_pluginsfile);
|
||||
if (pluginFile == NULL)
|
||||
{
|
||||
pluginFile = "addons/metamod/metaplugins.ini";
|
||||
}
|
||||
}
|
||||
|
||||
char full_path[260];
|
||||
g_Metamod.PathFormat(full_path, sizeof(full_path), "%s/%s", mod_path.c_str(), pluginFile);
|
||||
|
||||
LoadPluginsFromFile(full_path);
|
||||
|
||||
in_first_level = true;
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
bool Handler_GameInit()
|
||||
{
|
||||
if (is_game_init)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (vsp_load_requested)
|
||||
{
|
||||
InitializeVSP();
|
||||
}
|
||||
|
||||
is_game_init = true;
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
bool Handler_DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
|
||||
{
|
||||
g_PluginMngr.SetAllLoaded();
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
void Handler_DLLShutdown()
|
||||
{
|
||||
/* Unload plugins */
|
||||
g_PluginMngr.UnloadAll();
|
||||
|
||||
provider->Notify_DLLShutdown_Pre();
|
||||
|
||||
SH_CALL(server, &IServerGameDLL::DLLShutdown)();
|
||||
|
||||
g_SourceHook.CompleteShutdown();
|
||||
|
||||
if (is_gamedll_loaded && gamedll_info.lib)
|
||||
{
|
||||
dlclose(gamedll_info.lib);
|
||||
is_gamedll_loaded = false;
|
||||
}
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
void Handler_LevelShutdown(void)
|
||||
{
|
||||
if (!in_first_level)
|
||||
{
|
||||
char full_path[255];
|
||||
g_Metamod.PathFormat(full_path,
|
||||
sizeof(full_path),
|
||||
"%s/%s",
|
||||
mod_path.c_str(),
|
||||
provider->GetConVarString(mm_pluginsfile));
|
||||
|
||||
LoadPluginsFromFile(full_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
in_first_level = false;
|
||||
}
|
||||
|
||||
ITER_EVENT(OnLevelShutdown, ());
|
||||
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
bool Handler_LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
|
||||
{
|
||||
ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background));
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
void MetamodSource::LogMsg(ISmmPlugin *pl, const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[2048];
|
||||
|
||||
va_start(ap, msg);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
LogMessage("[%s] %s", pl->GetLogTag(), buffer);
|
||||
}
|
||||
|
||||
CreateInterfaceFn MetamodSource::engineFactory(bool syn/* =true */)
|
||||
{
|
||||
if (syn)
|
||||
{
|
||||
return EngineFactory;
|
||||
}
|
||||
|
||||
return engine_factory;
|
||||
}
|
||||
|
||||
CreateInterfaceFn MetamodSource::physicsFactory(bool syn/* =true */)
|
||||
{
|
||||
if (syn)
|
||||
{
|
||||
return PhysicsFactory;
|
||||
}
|
||||
|
||||
return physics_factory;
|
||||
}
|
||||
|
||||
CreateInterfaceFn MetamodSource::fileSystemFactory(bool syn/* =true */)
|
||||
{
|
||||
if (syn)
|
||||
{
|
||||
return FileSystemFactory;
|
||||
}
|
||||
|
||||
return filesystem_factory;
|
||||
}
|
||||
|
||||
CreateInterfaceFn MetamodSource::serverFactory(bool syn/* =true */)
|
||||
{
|
||||
if (syn)
|
||||
{
|
||||
return CreateInterface;
|
||||
}
|
||||
|
||||
return gamedll_info.factory;
|
||||
}
|
||||
|
||||
CGlobalVars *MetamodSource::pGlobals()
|
||||
{
|
||||
return gpGlobals;
|
||||
}
|
||||
|
||||
void MetamodSource::SetLastMetaReturn(META_RES res)
|
||||
{
|
||||
last_meta_res = res;
|
||||
}
|
||||
|
||||
META_RES MetamodSource::GetLastMetaReturn()
|
||||
{
|
||||
return last_meta_res;
|
||||
}
|
||||
|
||||
void MetamodSource::ConPrint(const char *str)
|
||||
{
|
||||
provider->ConsolePrint(str);
|
||||
}
|
||||
|
||||
void MetamodSource::ConPrintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[2048];
|
||||
|
||||
va_start(ap, fmt);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
provider->ConsolePrint(buffer);
|
||||
}
|
||||
|
||||
void MetamodSource::GetApiVersions(int &major, int &minor, int &plvers, int &plmin)
|
||||
{
|
||||
major = SM_VERS_API_MAJOR;
|
||||
minor = SM_VERS_API_MINOR;
|
||||
plvers = PLAPI_VERSION;
|
||||
plmin = PLAPI_MIN_VERSION;
|
||||
}
|
||||
|
||||
void MetamodSource::GetShVersions(int &shvers, int &shimpl)
|
||||
{
|
||||
shvers = SH_IFACE_VERSION;
|
||||
shimpl = SH_IMPL_VERSION;
|
||||
}
|
||||
|
||||
int MetamodSource::FormatIface(char iface[], unsigned int maxlength)
|
||||
{
|
||||
int length = (int)strlen(iface);
|
||||
int i;
|
||||
int num = 0;
|
||||
|
||||
for (i = length - 1; i >= 0; i--)
|
||||
{
|
||||
if (!isdigit(iface[i]))
|
||||
{
|
||||
if (i != length - 1)
|
||||
{
|
||||
num = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (num && ((int)maxlength <= length)) || (!num && ((int)maxlength <= length + 3)) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i != length - 1)
|
||||
{
|
||||
num = atoi(&(iface[++i]));
|
||||
}
|
||||
|
||||
num++;
|
||||
|
||||
snprintf(&(iface[i]), 4, "%03d", num);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
void *MetamodSource::InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, int *ret)
|
||||
{
|
||||
char _if[256]; /* assume no interface goes beyond this */
|
||||
size_t len = strlen(iface);
|
||||
int num = 0;
|
||||
void *pf = NULL;
|
||||
|
||||
if (max > 999)
|
||||
{
|
||||
max = 999;
|
||||
}
|
||||
|
||||
if (len + 4 > sizeof(_if))
|
||||
{
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_FAILED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(_if, iface);
|
||||
|
||||
do
|
||||
{
|
||||
if ((pf = (fn)(_if, ret)) != NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (num > max)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while ((num = FormatIface(_if, len+1)));
|
||||
|
||||
return pf;
|
||||
}
|
||||
|
||||
void *MetamodSource::VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min)
|
||||
{
|
||||
char buffer[256]; /* assume no interface will go beyond this */
|
||||
size_t len = strlen(iface);
|
||||
int ret; /* just in case something doesn't handle NULL properly */
|
||||
|
||||
if (len > sizeof(buffer) - 4)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(buffer, iface);
|
||||
|
||||
if (min != -1)
|
||||
{
|
||||
char *ptr = &buffer[len - 1];
|
||||
int digits = 0;
|
||||
while (isdigit(*ptr) && digits <=3)
|
||||
{
|
||||
*ptr = '\0';
|
||||
digits++;
|
||||
ptr--;
|
||||
}
|
||||
if (digits != 3)
|
||||
{
|
||||
/* for now, assume this is an error */
|
||||
strcpy(buffer, iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
char num[4];
|
||||
min = (min == 0) ? 1 : min;
|
||||
snprintf(num, sizeof(num), "%03d", min);
|
||||
strcat(buffer, num);
|
||||
}
|
||||
}
|
||||
|
||||
return InterfaceSearch(fn, buffer, IFACE_MAXNUM, &ret);
|
||||
}
|
||||
|
||||
const char *MetamodSource::GetBaseDir()
|
||||
{
|
||||
return mod_path.c_str();
|
||||
}
|
||||
|
||||
void MetamodSource::PathFormat(char *buffer, size_t len, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
size_t mylen = UTIL_FormatArgs(buffer, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
for (size_t i = 0; i < mylen; i++)
|
||||
{
|
||||
if (buffer[i] == ALT_SEP_CHAR)
|
||||
{
|
||||
buffer[i] = PATH_SEP_CHAR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetamodSource::ClientConPrintf(edict_t *client, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[2048];
|
||||
|
||||
va_start(ap, fmt);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
provider->ClientConsolePrint(client, buffer);
|
||||
}
|
||||
|
||||
void MetamodSource::EnableVSPListener()
|
||||
{
|
||||
if (is_game_init && !vsp_load_requested && !vsp_loaded)
|
||||
{
|
||||
InitializeVSP();
|
||||
}
|
||||
|
||||
vsp_load_requested = true;
|
||||
}
|
||||
|
||||
int MetamodSource::GetVSPVersion()
|
||||
{
|
||||
return vsp_version;
|
||||
}
|
||||
|
||||
int MetamodSource::GetGameDLLVersion()
|
||||
{
|
||||
return gamedll_version;
|
||||
}
|
||||
|
||||
bool MetamodSource::RemotePrintingAvailable()
|
||||
{
|
||||
return provider->IsRemotePrintingAvailable();
|
||||
}
|
||||
|
||||
void *MetamodSource::MetaFactory(const char *iface, int *ret, PluginId *id)
|
||||
{
|
||||
if (id)
|
||||
{
|
||||
*id = 0;
|
||||
}
|
||||
|
||||
if (!iface)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* First check ours... we get first chance! */
|
||||
if (strcmp(iface, MMIFACE_SOURCEHOOK) == 0)
|
||||
{
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_OK;
|
||||
}
|
||||
return static_cast<void *>(static_cast<SourceHook::ISourceHook *>(&g_SourceHook));
|
||||
}
|
||||
else if (strcmp(iface, MMIFACE_PLMANAGER) == 0)
|
||||
{
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_OK;
|
||||
}
|
||||
return static_cast<void *>(static_cast<ISmmPluginManager *>(&g_PluginMngr));
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin *pl;
|
||||
List<IMetamodListener *>::iterator event;
|
||||
IMetamodListener *api;
|
||||
void *value;
|
||||
|
||||
int subret = 0;
|
||||
for (PluginIter iter = g_PluginMngr._begin();
|
||||
iter != g_PluginMngr._end();
|
||||
iter++)
|
||||
{
|
||||
pl = (*iter);
|
||||
for (event = pl->m_Events.begin(); event != pl->m_Events.end(); event++)
|
||||
{
|
||||
api = (*event);
|
||||
subret = IFACE_FAILED;
|
||||
if ((value = api->OnMetamodQuery(iface, &subret)) != NULL)
|
||||
{
|
||||
if (ret)
|
||||
{
|
||||
*ret = subret;
|
||||
}
|
||||
if (id)
|
||||
{
|
||||
*id = pl->m_Id;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_FAILED;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void MetamodSource::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener)
|
||||
{
|
||||
CPluginManager::CPlugin *pl = g_PluginMngr.FindByAPI(plugin);
|
||||
|
||||
pl->m_Events.push_back(pListener);
|
||||
}
|
||||
|
||||
const char *MetamodSource::GetGameBinaryPath()
|
||||
{
|
||||
return full_bin_path.c_str();
|
||||
}
|
||||
|
||||
const char *MetamodSource::GetPluginsFile()
|
||||
{
|
||||
return provider->GetConVarString(mm_pluginsfile);
|
||||
}
|
||||
|
||||
IConCommandBaseAccessor *MetamodSource::GetCvarBaseAccessor()
|
||||
{
|
||||
return provider->GetConCommandBaseAccessor();
|
||||
}
|
||||
|
||||
bool MetamodSource::RegisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand)
|
||||
{
|
||||
if (provider->IsConCommandBaseACommand(pCommand))
|
||||
{
|
||||
g_PluginMngr.AddPluginCmd(plugin, pCommand);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_PluginMngr.AddPluginCvar(plugin, pCommand);
|
||||
}
|
||||
|
||||
return provider->RegisterConCommandBase(pCommand);
|
||||
}
|
||||
|
||||
void MetamodSource::UnregisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand)
|
||||
{
|
||||
if (provider->IsConCommandBaseACommand(pCommand))
|
||||
{
|
||||
g_PluginMngr.RemovePluginCmd(plugin, pCommand);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_PluginMngr.RemovePluginCvar(plugin, pCommand);
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin *pOrig = g_PluginMngr.FindByAPI(plugin);
|
||||
UnregisterConCommandBase(pOrig ? pOrig->m_Id : 0, pCommand);
|
||||
}
|
||||
|
||||
void MetamodSource::UnregisterConCommandBase(PluginId id, ConCommandBase *pCommand)
|
||||
{
|
||||
PluginIter iter;
|
||||
CPluginManager::CPlugin *pPlugin;
|
||||
List<IMetamodListener *>::iterator event;
|
||||
IMetamodListener *pML;
|
||||
for (iter=g_PluginMngr._begin(); iter!=g_PluginMngr._end(); iter++)
|
||||
{
|
||||
pPlugin = (*iter);
|
||||
if (pPlugin->m_Status < Pl_Paused)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* Only valid for plugins >= 12 (v1:6, SourceMM 1.5) */
|
||||
if (pPlugin->m_API->GetApiVersion() < 12)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (event=pPlugin->m_Events.begin();
|
||||
event!=pPlugin->m_Events.end();
|
||||
event++)
|
||||
{
|
||||
pML = (*event);
|
||||
pML->OnUnlinkConCommandBase(id, pCommand);
|
||||
}
|
||||
}
|
||||
|
||||
return provider->UnregisterConCommandBase(pCommand);
|
||||
}
|
||||
|
||||
int MetamodSource::GetUserMessageCount()
|
||||
{
|
||||
return provider->GetUserMessageCount();
|
||||
}
|
||||
|
||||
int MetamodSource::FindUserMessage(const char *name, int *size/* =NULL */)
|
||||
{
|
||||
return provider->FindUserMessage(name, size);
|
||||
}
|
||||
|
||||
const char *MetamodSource::GetUserMessage(int index, int *size/* =NULL */)
|
||||
{
|
||||
return provider->GetUserMessage(index, size);
|
||||
}
|
||||
|
||||
int MetamodSource::GetSourceEngineBuild()
|
||||
{
|
||||
return engine_build;
|
||||
}
|
||||
|
||||
void MetamodSource::NotifyVSPListening(IServerPluginCallbacks *callbacks)
|
||||
{
|
||||
ITER_EVENT(OnVSPListening, (callbacks));
|
||||
}
|
||||
|
||||
IServerPluginCallbacks *MetamodSource::GetVSPInfo(int *pVersion)
|
||||
{
|
||||
if (pVersion)
|
||||
{
|
||||
*pVersion = vsp_version;
|
||||
}
|
||||
|
||||
return vsp_callbacks;
|
||||
}
|
||||
|
105
sourcemm/metamod.h
Normal file
105
sourcemm/metamod.h
Normal file
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMM_H
|
||||
#define _INCLUDE_SOURCEMM_H
|
||||
|
||||
/**
|
||||
* @brief SourceMM main functionality for GameDLL interception
|
||||
* @file sourcemm.h
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include <sourcehook/sourcehook_impl.h>
|
||||
#include <sourcehook/sourcehook.h>
|
||||
#include "ISmmAPI.h"
|
||||
#include "metamod_provider.h"
|
||||
#include "svn_version.h"
|
||||
|
||||
using namespace SourceMM;
|
||||
|
||||
/**
|
||||
* Versioning
|
||||
* increase api_major when API breaks
|
||||
* increase api_minor when new functions are added (non-breaking)
|
||||
*/
|
||||
#define SOURCEMM_VERSION SVN_FILE_VERSION_STRING
|
||||
#define SOURCEMM_DATE __DATE__
|
||||
#define SM_VERS_API_MAJOR 1 //increase this on a breaking change
|
||||
#define SM_VERS_API_MINOR 7 //increase this on a non-breaking API change
|
||||
|
||||
class MetamodSource : public ISmmAPI
|
||||
{
|
||||
public:
|
||||
void LogMsg(ISmmPlugin *pl, const char *msg, ...);
|
||||
CreateInterfaceFn engineFactory(bool syn=true);
|
||||
CreateInterfaceFn physicsFactory(bool syn=true);
|
||||
CreateInterfaceFn fileSystemFactory(bool syn=true);
|
||||
CreateInterfaceFn serverFactory(bool syn=true);
|
||||
CGlobalVars *pGlobals();
|
||||
void SetLastMetaReturn(META_RES res);
|
||||
META_RES GetLastMetaReturn();
|
||||
IConCommandBaseAccessor *GetCvarBaseAccessor();
|
||||
bool RegisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand);
|
||||
void UnregisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand);
|
||||
void ConPrint(const char *str);
|
||||
void ConPrintf(const char *fmt, ...);
|
||||
bool RemotePrintingAvailable();
|
||||
void GetApiVersions(int &major, int &minor, int &plvers, int &plmin);
|
||||
void GetShVersions(int &shvers, int &shimpl);
|
||||
void AddListener(ISmmPlugin *plugin, IMetamodListener *pListener);
|
||||
void *MetaFactory(const char *iface, int *ret, PluginId *id);
|
||||
int FormatIface(char iface[], unsigned int maxlength);
|
||||
void *InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, int *ret);
|
||||
const char *GetBaseDir();
|
||||
void PathFormat(char *buffer, size_t len, const char *fmt, ...);
|
||||
void ClientConPrintf(edict_t *client, const char *fmt, ...);
|
||||
void *VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min=-1);
|
||||
void EnableVSPListener();
|
||||
int GetGameDLLVersion();
|
||||
int GetUserMessageCount();
|
||||
int FindUserMessage(const char *name, int *size=NULL);
|
||||
const char *GetUserMessage(int index, int *size=NULL);
|
||||
int GetVSPVersion();
|
||||
int GetSourceEngineBuild();
|
||||
IServerPluginCallbacks *GetVSPInfo(int *pVersion);
|
||||
public:
|
||||
const char *GetGameBinaryPath();
|
||||
const char *GetPluginsFile();
|
||||
void UnregisterConCommandBase(PluginId id, ConCommandBase *pCommand);
|
||||
void NotifyVSPListening(IServerPluginCallbacks *callbacks);
|
||||
};
|
||||
|
||||
void LogMessage(const char *msg, ...);
|
||||
int LoadPluginsFromFile(const char *_file);
|
||||
|
||||
extern SourceHook::CSourceHookImpl g_SourceHook;
|
||||
extern MetamodSource g_Metamod;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMM_H
|
@ -1,19 +1,43 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* License: zlib/libpng
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _DEBUG
|
||||
#define DEBUG2
|
||||
#undef _DEBUG
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include "CSmmAPI.h"
|
||||
#include "concommands.h"
|
||||
#include "CPlugin.h"
|
||||
#include "sh_string.h"
|
||||
#include "sh_list.h"
|
||||
#include "metamod.h"
|
||||
#include "metamod_util.h"
|
||||
#include "metamod_console.h"
|
||||
#include "metamod_plugins.h"
|
||||
#if defined DEBUG2
|
||||
#undef DEBUG2
|
||||
#define _DEBUG
|
||||
#endif
|
||||
|
||||
using namespace SourceMM;
|
||||
using namespace SourceHook;
|
||||
@ -23,143 +47,16 @@ using namespace SourceHook;
|
||||
* @file concommands.cpp
|
||||
*/
|
||||
|
||||
CAlwaysRegisterableCommand g_EternalCommand;
|
||||
SMConVarAccessor g_SMConVarAccessor;
|
||||
#define CONMSG g_Metamod.ConPrintf
|
||||
#define CLIENT_CONMSG g_Metamod.ClientConPrintf
|
||||
|
||||
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
|
||||
bool Command_Meta(IMetamodSourceCommandInfo *info)
|
||||
{
|
||||
// Add the FCVAR_GAMEDLL flag
|
||||
// => No crash on exit!
|
||||
// UPDATE: Do _not_ add the FCVAR_GAMEDLL flag here, as it
|
||||
// causes the command to be unusable on listenservers until you load a map
|
||||
// We will set the FCVAR_GAMEDLL flag on all commands we have registered once we are being unloaded
|
||||
//pCommand->AddFlags(FCVAR_GAMEDLL);
|
||||
m_RegisteredCommands.push_back(pCommand);
|
||||
unsigned int args = info->GetArgCount();
|
||||
|
||||
pCommand->SetNext( NULL );
|
||||
g_Engine.icvar->RegisterConCommandBase(pCommand);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SMConVarAccessor::Register(ConCommandBase *pCommand)
|
||||
{
|
||||
//simple, don't mark as part of sourcemm!
|
||||
pCommand->SetNext( NULL );
|
||||
g_Engine.icvar->RegisterConCommandBase(pCommand);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SMConVarAccessor::MarkCommandsAsGameDLL()
|
||||
{
|
||||
for (List<ConCommandBase*>::iterator iter = m_RegisteredCommands.begin();
|
||||
iter != m_RegisteredCommands.end(); ++iter)
|
||||
if (args >= 1)
|
||||
{
|
||||
(*iter)->AddFlags(FCVAR_GAMEDLL);
|
||||
}
|
||||
}
|
||||
|
||||
void SMConVarAccessor::Unregister(PluginId id, ConCommandBase *pCommand)
|
||||
{
|
||||
/* Notify via IMetamodListener */
|
||||
PluginIter iter;
|
||||
CPluginManager::CPlugin *pPlugin;
|
||||
List<IMetamodListener *>::iterator event;
|
||||
IMetamodListener *pML;
|
||||
for (iter=g_PluginMngr._begin(); iter!=g_PluginMngr._end(); iter++)
|
||||
{
|
||||
pPlugin = (*iter);
|
||||
if (pPlugin->m_Status < Pl_Paused)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* Only valid for plugins >= 12 (v1:6, SourceMM 1.5) */
|
||||
if (pPlugin->m_API->GetApiVersion() < 12)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (event=pPlugin->m_Events.begin();
|
||||
event!=pPlugin->m_Events.end();
|
||||
event++)
|
||||
{
|
||||
pML = (*event);
|
||||
pML->OnUnlinkConCommandBase(id, pCommand);
|
||||
}
|
||||
}
|
||||
|
||||
ICvar *cv = g_Engine.icvar;
|
||||
ConCommandBase *ptr = cv->GetCommands();
|
||||
|
||||
if (ptr == pCommand)
|
||||
{
|
||||
/* First in list */
|
||||
g_EternalCommand.BringToFront();
|
||||
g_EternalCommand.SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
|
||||
} else {
|
||||
/* Find us and unregister us */
|
||||
ConCommandBase *pPrev = NULL;
|
||||
while (ptr)
|
||||
{
|
||||
if (ptr == pCommand)
|
||||
break;
|
||||
pPrev = ptr;
|
||||
ptr = const_cast<ConCommandBase *>(ptr->GetNext());
|
||||
}
|
||||
if (pPrev && ptr == pCommand)
|
||||
{
|
||||
pPrev->SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SMConVarAccessor::UnregisterGameDLLCommands()
|
||||
{
|
||||
ConCommandBase *begin = g_Engine.icvar->GetCommands();
|
||||
ConCommandBase *iter = begin;
|
||||
ConCommandBase *prev = NULL;
|
||||
while (iter)
|
||||
{
|
||||
/* Watch out for the ETERNAL COMMAND! */
|
||||
if (iter != &g_EternalCommand && iter->IsBitSet(FCVAR_GAMEDLL))
|
||||
{
|
||||
/* Remove it! */
|
||||
if (iter == begin)
|
||||
{
|
||||
g_EternalCommand.BringToFront();
|
||||
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
||||
g_EternalCommand.SetNext(iter);
|
||||
prev = &g_EternalCommand;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
||||
prev->SetNext(iter);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
prev = iter;
|
||||
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
||||
}
|
||||
}
|
||||
|
||||
ConVar metamod_version("metamod_version", SOURCEMM_VERSION, FCVAR_REPLICATED | FCVAR_SPONLY | FCVAR_NOTIFY, "Metamod:Source Version");
|
||||
#if defined WIN32 || defined _WIN32
|
||||
ConVar mm_pluginsfile("mm_pluginsfile", "addons\\metamod\\metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File");
|
||||
#else
|
||||
ConVar mm_pluginsfile("mm_pluginsfile", "addons/metamod/metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File");
|
||||
#endif
|
||||
|
||||
CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
{
|
||||
IVEngineServer *e = g_Engine.engine;
|
||||
|
||||
int args = e->Cmd_Argc();
|
||||
|
||||
if (args >= 2)
|
||||
{
|
||||
const char *command = e->Cmd_Argv(1);
|
||||
const char *command = info->GetArg(1);
|
||||
if (strcmp(command, "credits") == 0)
|
||||
{
|
||||
CONMSG("Metamod:Source was developed by:\n");
|
||||
@ -169,57 +66,73 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
CONMSG("For more information, see the official website\n");
|
||||
CONMSG("http://www.sourcemm.net/\n");
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "version") == 0) {
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(command, "version") == 0)
|
||||
{
|
||||
CONMSG("Metamod:Source version %s\n", SOURCEMM_VERSION);
|
||||
CONMSG("Compiled on: %s\n", SOURCEMM_DATE);
|
||||
CONMSG("Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION);
|
||||
CONMSG("SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
|
||||
CONMSG("http://www.sourcemm.net/\n");
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "game") == 0) {
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(command, "game") == 0)
|
||||
{
|
||||
CONMSG("GameDLL Information\n");
|
||||
CONMSG(" Description: %s\n", g_GameDll.pGameDLL->GetGameDescription());
|
||||
CONMSG(" Mod Path: %s\n", g_ModPath.c_str());
|
||||
CONMSG(" DLL Path: %s\n", g_BinPath.c_str());
|
||||
CONMSG(" Interface: ServerGameDLL%03d, ServerGameClients%03d\n", g_GameDllVersion, g_GameClientsVersion);
|
||||
CONMSG(" Description: %s\n", provider->GetGameDescription());
|
||||
CONMSG(" Mod Path: %s\n", g_Metamod.GetBaseDir());
|
||||
CONMSG(" DLL Path: %s\n", g_Metamod.GetGameBinaryPath());
|
||||
CONMSG(" Interface: ServerGameDLL%03d\n", g_Metamod.GetGameDLLVersion());
|
||||
|
||||
// Display user messages
|
||||
if (g_SmmAPI.MsgCacheSuccessful())
|
||||
int messages = g_Metamod.GetUserMessageCount();
|
||||
if (messages != -1)
|
||||
{
|
||||
const char *msgname;
|
||||
int msgsize;
|
||||
int msgcount = g_SmmAPI.GetUserMessageCount();
|
||||
|
||||
if (msgcount > 0)
|
||||
if (messages > 0)
|
||||
{
|
||||
CONMSG(" User Messages: %-32.31s %-5s %-5s\n", "Name", "Index", "Size");
|
||||
|
||||
for (int i = 0; i < msgcount; i++)
|
||||
for (int i = 0; i < messages; i++)
|
||||
{
|
||||
msgname = g_SmmAPI.GetUserMessage(i, &msgsize);
|
||||
msgname = g_Metamod.GetUserMessage(i, &msgsize);
|
||||
|
||||
CONMSG(" %-32.31s %-5d %-5d\n", msgname, i, msgsize);
|
||||
}
|
||||
|
||||
CONMSG(" %d user message%s in total\n", msgcount, (msgcount > 1) ? "s" : "");
|
||||
} else {
|
||||
CONMSG(" %d user message%s in total\n", messages, (messages > 1) ? "s" : "");
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG(" User Messages: None\n");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG(" User Messages: Failed to get list of user messages\n");
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "refresh") == 0) {
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(command, "refresh") == 0)
|
||||
{
|
||||
char full_path[255];
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile());
|
||||
g_Metamod.PathFormat(full_path,
|
||||
sizeof(full_path),
|
||||
"%s/%s",
|
||||
g_Metamod.GetBaseDir(),
|
||||
g_Metamod.GetPluginsFile());
|
||||
|
||||
LoadPluginsFromFile(full_path);
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "list") == 0) {
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(command, "list") == 0)
|
||||
{
|
||||
CPluginManager::CPlugin *pl;
|
||||
ISmmPlugin *plapi;
|
||||
const char *plname;
|
||||
@ -231,7 +144,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
if (!plnum)
|
||||
{
|
||||
CONMSG("No plugins loaded.\n");
|
||||
return;
|
||||
return true;
|
||||
} else {
|
||||
CONMSG("Listing %d plugin%s:\n", plnum, (plnum > 1) ? "s" : "");
|
||||
}
|
||||
@ -271,23 +184,27 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
CONMSG("%s\n", buffer);
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "cmds") == 0) {
|
||||
if (args >= 3)
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(command, "cmds") == 0)
|
||||
{
|
||||
if (args >= 2)
|
||||
{
|
||||
int id = atoi(e->Cmd_Argv(2));
|
||||
int id = atoi(info->GetArg(2));
|
||||
CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
CONMSG("Plugin %d not found.\n", id);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!pl->m_API)
|
||||
{
|
||||
CONMSG("Plugin %d is not loaded.\n", id);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Console commands for %s:\n", pl->m_API->GetName());
|
||||
List<ConCommandBase *>::iterator ci;
|
||||
size_t count = 0;
|
||||
@ -298,27 +215,33 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
CONMSG(" [%5d] %-s\n", count, (*ci)->GetName());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Usage: meta cmds <id>\n");
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "cvars") == 0) {
|
||||
if (args >= 3)
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(command, "cvars") == 0)
|
||||
{
|
||||
if (args >= 2)
|
||||
{
|
||||
int id = atoi(e->Cmd_Argv(2));
|
||||
int id = atoi(info->GetArg(2));
|
||||
CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
CONMSG("Plugin %d not found.\n", id);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!pl->m_API)
|
||||
{
|
||||
CONMSG("Plugin %d is not loaded.\n", id);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Registered cvars for %s:\n", pl->m_API->GetName());
|
||||
List<ConCommandBase *>::iterator ci;
|
||||
size_t count = 0;
|
||||
@ -329,38 +252,50 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
CONMSG(" [%5d] %-s\n", count, (*ci)->GetName());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Usage: meta cvars <id>\n");
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "info") == 0) {
|
||||
if (args >= 3)
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(command, "info") == 0)
|
||||
{
|
||||
if (args >= 2)
|
||||
{
|
||||
int id = atoi(e->Cmd_Argv(2));
|
||||
int id = atoi(info->GetArg(2));
|
||||
CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
|
||||
if (!pl)
|
||||
{
|
||||
CONMSG("Plugin %d not found.\n", id);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!pl->m_API)
|
||||
{
|
||||
CONMSG("Plugin %d is not loaded.\n", id);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pl->m_Status == Pl_Paused)
|
||||
{
|
||||
CONMSG("Plugin %d is paused.\n", id);
|
||||
} else if (pl->m_Status == Pl_Running) {
|
||||
}
|
||||
else if (pl->m_Status == Pl_Running)
|
||||
{
|
||||
char run_msg[255];
|
||||
bool run = false;
|
||||
if (pl->m_API && pl->m_API->QueryRunning(run_msg, sizeof(run_msg)-1))
|
||||
{
|
||||
run = true;
|
||||
}
|
||||
if (run)
|
||||
{
|
||||
CONMSG("Plugin %d is running.\n", id);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Plugin %d is stopped: %s\n", id, run_msg);
|
||||
}
|
||||
}
|
||||
@ -373,57 +308,69 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
}
|
||||
CONMSG("File: %s\n\n", pl->m_File.c_str());
|
||||
|
||||
return;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Usage: meta info <id>\n");
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
} else if (strcmp(command, "pause") == 0) {
|
||||
if (args >= 3)
|
||||
}
|
||||
else if (strcmp(command, "pause") == 0)
|
||||
{
|
||||
if (args >= 2)
|
||||
{
|
||||
int id = atoi(e->Cmd_Argv(2));
|
||||
int id = atoi(info->GetArg(2));
|
||||
|
||||
char error[255];
|
||||
|
||||
if (!g_PluginMngr.Pause(id, error, sizeof(error)))
|
||||
{
|
||||
CONMSG("Pause failed: %s\n", error);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
CONMSG("Plugin %d has been paused.\n", id);
|
||||
|
||||
return;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Usage: meta pause <id>\n");
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
} else if (strcmp(command, "unpause") == 0) {
|
||||
if (args >= 3)
|
||||
}
|
||||
else if (strcmp(command, "unpause") == 0)
|
||||
{
|
||||
if (args >= 2)
|
||||
{
|
||||
int id = atoi(e->Cmd_Argv(2));
|
||||
int id = atoi(info->GetArg(2));
|
||||
char error[255];
|
||||
|
||||
if (!g_PluginMngr.Unpause(id, error, sizeof(error)))
|
||||
{
|
||||
CONMSG("Unpause failed: %s\n", error);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
CONMSG("Plugin %d has been unpaused.\n", id);
|
||||
|
||||
return;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Usage: meta unpause <id>\n");
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
} else if (strcmp(command, "load") == 0) {
|
||||
if (args >= 3)
|
||||
}
|
||||
else if (strcmp(command, "load") == 0)
|
||||
{
|
||||
if (args >= 2)
|
||||
{
|
||||
const char *file = e->Cmd_Argv(2);
|
||||
const char *file = info->GetArg(2);
|
||||
char full_path[255];
|
||||
|
||||
const char *alias = g_PluginMngr.LookupAlias(file);
|
||||
@ -434,15 +381,22 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
|
||||
if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0)
|
||||
{
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s", file);
|
||||
} else {
|
||||
g_Metamod.PathFormat(full_path, sizeof(full_path), "%s", file);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *ext = UTIL_GetExtension(file);
|
||||
#if defined WIN32 || defined _WIN32
|
||||
ext = ext ? "" : ".dll";
|
||||
#else
|
||||
ext = ext ? "" : "_i486.so";
|
||||
#endif
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext);
|
||||
g_Metamod.PathFormat(full_path,
|
||||
sizeof(full_path),
|
||||
"%s/%s%s",
|
||||
g_Metamod.GetBaseDir(),
|
||||
file,
|
||||
ext);
|
||||
}
|
||||
|
||||
char error[255]={0};
|
||||
@ -454,7 +408,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
if (!pl || id < Pl_MinId || (pl->m_Status < Pl_Paused))
|
||||
{
|
||||
CONMSG("Failed to load plugin %s (%s).\n", file, error);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!already)
|
||||
@ -464,28 +418,34 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
CONMSG("Plugin \"%s\" is already loaded as %d.\n", pl->m_API->GetName(), pl->m_Id);
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Usage: meta load <path>\n");
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
} else if ( (strcmp(command, "alias") == 0) ||
|
||||
(strcmp(command, "aliases") == 0) ) {
|
||||
if (args >= 4)
|
||||
}
|
||||
else if ( (strcmp(command, "alias") == 0) ||
|
||||
(strcmp(command, "aliases") == 0) )
|
||||
{
|
||||
if (args >= 3)
|
||||
{
|
||||
const char *alias = e->Cmd_Argv(2);
|
||||
const char *value = e->Cmd_Argv(3);
|
||||
const char *alias = info->GetArg(2);
|
||||
const char *value = info->GetArg(3);
|
||||
|
||||
g_PluginMngr.SetAlias(alias, value);
|
||||
if (value[0] == '\0')
|
||||
if (value == NULL || value[0] == '\0')
|
||||
{
|
||||
CONMSG("Deleted alias: %s.\n", alias);
|
||||
} else {
|
||||
CONMSG("Set alias \"%s\" to: %s\n", alias, value);
|
||||
}
|
||||
} else if (args >= 3) {
|
||||
const char *alias = e->Cmd_Argv(2);
|
||||
}
|
||||
else if (args >= 2)
|
||||
{
|
||||
const char *alias = info->GetArg(2);
|
||||
const char *value = g_PluginMngr.LookupAlias(alias);
|
||||
if (value)
|
||||
{
|
||||
@ -493,7 +453,9 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
} else {
|
||||
CONMSG("Alias \"%s\" was not found.\n", alias);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
List<CNameAlias *>::iterator iter, end;
|
||||
CNameAlias *p;
|
||||
|
||||
@ -512,15 +474,19 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
}
|
||||
CONMSG(" --- \n");
|
||||
CONMSG("%d aliases total.\n", total);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("No aliases found.\n");
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (strcmp(command, "unload") == 0) {
|
||||
if (args >= 3)
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(command, "unload") == 0)
|
||||
{
|
||||
if (args >= 2)
|
||||
{
|
||||
const char *file = e->Cmd_Argv(2);
|
||||
const char *file = info->GetArg(2);
|
||||
int id = atoi(file);
|
||||
char error[255]={0};
|
||||
|
||||
@ -537,15 +503,22 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
/* first check if it's a known filename */
|
||||
if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0)
|
||||
{
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s", file);
|
||||
} else {
|
||||
g_Metamod.PathFormat(full_path, sizeof(full_path), "%s", file);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *ext = UTIL_GetExtension(file);
|
||||
#if defined WIN32 || defined _WIN32
|
||||
ext = ext ? "" : ".dll";
|
||||
#else
|
||||
ext = ext ? "" : "_i486.so";
|
||||
#endif
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext);
|
||||
g_Metamod.PathFormat(full_path,
|
||||
sizeof(full_path),
|
||||
"%s/%s%s",
|
||||
g_Metamod.GetBaseDir(),
|
||||
file,
|
||||
ext);
|
||||
}
|
||||
|
||||
List<CPluginManager::CPlugin *>::iterator iter, end;
|
||||
@ -564,70 +537,82 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
if (id == 0)
|
||||
{
|
||||
CONMSG("Plugin \"%s\" not found.\n", full_path);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)))
|
||||
{
|
||||
CONMSG("Unload failed: %s\n", error);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
CONMSG("Plugin %d unloaded.\n", id);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Usage: meta unload <id>\n");
|
||||
}
|
||||
return;
|
||||
} else if (strcmp(command, "force_unload") == 0) {
|
||||
if (args >= 3)
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(command, "force_unload") == 0)
|
||||
{
|
||||
if (args >= 2)
|
||||
{
|
||||
int id = atoi(e->Cmd_Argv(2));
|
||||
int id = atoi(info->GetArg(2));
|
||||
char error[255]={0};
|
||||
|
||||
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)))
|
||||
{
|
||||
CONMSG("Force unload failed: %s\n", error);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
CONMSG("Plugin %d force unloaded.\n", id);
|
||||
|
||||
return;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Usage: meta force_unload <id>\n");
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
} else if (strcmp(command, "clear") == 0) {
|
||||
}
|
||||
else if (strcmp(command, "clear") == 0)
|
||||
{
|
||||
if (!g_PluginMngr.UnloadAll())
|
||||
{
|
||||
CONMSG("One or more plugins resisted removal (cleaned anyway).\n");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
CONMSG("All plugins unloaded.\n");
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "retry") == 0) {
|
||||
if (args >= 3)
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(command, "retry") == 0)
|
||||
{
|
||||
if (args >= 2)
|
||||
{
|
||||
int id = atoi(e->Cmd_Argv(2));
|
||||
int id = atoi(info->GetArg(2));
|
||||
char error[255];
|
||||
|
||||
if (!g_PluginMngr.Retry(id, error, sizeof(error)))
|
||||
{
|
||||
CONMSG("Error reloading plugin: %s\n", error);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
CONMSG("Plugin %d successfully reloaded.\n", id);
|
||||
|
||||
return;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Usage: meta retry <id>\n");
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -650,66 +635,20 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
CONMSG(" unload - Unload a loaded plugin\n");
|
||||
CONMSG(" unpause - Unpause a paused plugin\n");
|
||||
CONMSG(" version - Version information\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CAlwaysRegisterableCommand::CAlwaysRegisterableCommand()
|
||||
bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info)
|
||||
{
|
||||
Create("", NULL, FCVAR_UNREGISTERED|FCVAR_GAMEDLL);
|
||||
m_pICvar = NULL;
|
||||
}
|
||||
|
||||
bool CAlwaysRegisterableCommand::IsRegistered( void ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CAlwaysRegisterableCommand::BringToFront()
|
||||
{
|
||||
if (!m_pICvar)
|
||||
m_pICvar = g_Engine.icvar;
|
||||
|
||||
// First, let's try to find us!
|
||||
ConCommandBase *pPtr = m_pICvar->GetCommands();
|
||||
|
||||
if (pPtr == this)
|
||||
{
|
||||
// We are already at the beginning; Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
while (pPtr)
|
||||
{
|
||||
if (pPtr == this && pPtr->IsCommand() && stricmp(GetName(), pPtr->GetName()) == 0)
|
||||
break;
|
||||
ConCommandBase *pPrev = NULL;
|
||||
while (pPtr)
|
||||
{
|
||||
if (pPtr == this)
|
||||
break;
|
||||
pPrev = pPtr;
|
||||
pPtr = const_cast<ConCommandBase*>(pPtr->GetNext());
|
||||
}
|
||||
if (pPrev && pPtr == this)
|
||||
{
|
||||
pPrev->SetNext(m_pNext); // Remove us from the list
|
||||
}
|
||||
// Now, register us
|
||||
SetNext(NULL);
|
||||
m_pICvar->RegisterConCommandBase(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientCommand_handler(edict_t *client)
|
||||
{
|
||||
IVEngineServer *e = g_Engine.engine;
|
||||
const char *cmd = e->Cmd_Argv(0);
|
||||
const char *cmd = info->GetArg(0);
|
||||
|
||||
if (strcmp(cmd, "meta") == 0)
|
||||
{
|
||||
int args = e->Cmd_Argc();
|
||||
if (args == 2)
|
||||
unsigned int args = info->GetArgCount();
|
||||
if (args == 1)
|
||||
{
|
||||
const char *subcmd = e->Cmd_Argv(1);
|
||||
const char *subcmd = info->GetArg(1);
|
||||
|
||||
if (strcmp(subcmd, "credits") == 0)
|
||||
{
|
||||
@ -720,16 +659,20 @@ void ClientCommand_handler(edict_t *client)
|
||||
CLIENT_CONMSG(client, "For more information, see the official website\n");
|
||||
CLIENT_CONMSG(client, "http://www.sourcemm.net/\n");
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
} else if(strcmp(subcmd, "version") == 0) {
|
||||
return true;
|
||||
}
|
||||
else if(strcmp(subcmd, "version") == 0)
|
||||
{
|
||||
CLIENT_CONMSG(client, "Metamod:Source version %s\n", SOURCEMM_VERSION);
|
||||
CLIENT_CONMSG(client, "Compiled on: %s\n", SOURCEMM_DATE);
|
||||
CLIENT_CONMSG(client, "Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION);
|
||||
CLIENT_CONMSG(client, "SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
|
||||
CLIENT_CONMSG(client, "http://www.sourcemm.net/\n");
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
} else if(strcmp(subcmd, "list") == 0) {
|
||||
return true;
|
||||
}
|
||||
else if(strcmp(subcmd, "list") == 0)
|
||||
{
|
||||
CPluginManager::CPlugin *pl;
|
||||
ISmmPlugin *plapi;
|
||||
const char *plname;
|
||||
@ -773,7 +716,7 @@ void ClientCommand_handler(edict_t *client)
|
||||
CLIENT_CONMSG(client, "No active plugins loaded.\n");
|
||||
}
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -783,13 +726,8 @@ void ClientCommand_handler(edict_t *client)
|
||||
CLIENT_CONMSG(client, " list - List plugins\n");
|
||||
CLIENT_CONMSG(client, " version - Version information\n");
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
return true;
|
||||
}
|
||||
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
const char *GetPluginsFile()
|
||||
{
|
||||
return mm_pluginsfile.GetString();
|
||||
return false;
|
||||
}
|
36
sourcemm/metamod_console.h
Normal file
36
sourcemm/metamod_console.h
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_CONCOMMANDS_H
|
||||
#define _INCLUDE_CONCOMMANDS_H
|
||||
|
||||
#include "metamod_provider.h"
|
||||
|
||||
bool Command_Meta(IMetamodSourceCommandInfo *info);
|
||||
bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info);
|
||||
|
||||
#endif //_INCLUDE_CONCOMMANDS_H
|
101
sourcemm/metamod_oslink.cpp
Normal file
101
sourcemm/metamod_oslink.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "metamod_oslink.h"
|
||||
#include <malloc.h>
|
||||
#ifdef __linux
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
const char *dlerror()
|
||||
{
|
||||
static char buf[1024];
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &buf, 0, NULL);
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined __linux__
|
||||
int GetLastError()
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_acquire(void)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_release(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
|
||||
{
|
||||
#if defined WIN32 || defined _WIN32
|
||||
MEMORY_BASIC_INFORMATION mem;
|
||||
if (!VirtualQuery(pAddr, &mem, sizeof(mem)))
|
||||
return false;
|
||||
if (mem.AllocationBase == NULL)
|
||||
return false;
|
||||
HMODULE dll = (HMODULE)mem.AllocationBase;
|
||||
GetModuleFileName(dll, (LPTSTR)buffer, maxlength);
|
||||
#elif defined __linux__
|
||||
Dl_info info;
|
||||
if (!dladdr(pAddr, &info))
|
||||
return false;
|
||||
if (!info.dli_fbase || !info.dli_fname)
|
||||
return false;
|
||||
const char *dllpath = info.dli_fname;
|
||||
snprintf(buffer, maxlength, "%s", dllpath);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined __GNUC__ && (__GNUC__ == 3 || __GNUC__ == 4)
|
||||
void * operator new(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void * operator new[](size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void * ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void * ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
@ -1,11 +1,28 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* License: zlib/libpng
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_OSLINK_H
|
||||
@ -37,6 +54,7 @@
|
||||
#define ALT_SEP_CHAR '/'
|
||||
#define PATH_SIZE MAX_PATH
|
||||
#define SERVER_DLL "server.dll"
|
||||
#define strcasecmp stricmp
|
||||
#elif defined __linux__
|
||||
#define OS_LINUX
|
||||
#include <dlfcn.h>
|
@ -1,647 +1,747 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#include "CPlugin.h"
|
||||
#include "CSmmAPI.h"
|
||||
#include "sourcemm.h"
|
||||
#include "concommands.h"
|
||||
|
||||
/**
|
||||
* @brief Implements functions from CPlugin.h
|
||||
* @file CPlugin.cpp
|
||||
*/
|
||||
|
||||
using namespace SourceMM;
|
||||
|
||||
#define ITER_PLEVENT(evn, plid) \
|
||||
CPluginManager::CPlugin *_Xpl; \
|
||||
SourceHook::List<IMetamodListener *>::iterator event; \
|
||||
IMetamodListener *api; \
|
||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
||||
_Xpl = (*iter); \
|
||||
if (_Xpl->m_Id == plid) \
|
||||
continue; \
|
||||
for (event=_Xpl->m_Events.begin(); event!=_Xpl->m_Events.end(); event++) { \
|
||||
api = (*event); \
|
||||
api->evn(plid); \
|
||||
} \
|
||||
}
|
||||
|
||||
CPluginManager g_PluginMngr;
|
||||
|
||||
CPluginManager::CPluginManager()
|
||||
{
|
||||
m_LastId = Pl_MinId;
|
||||
m_AllLoaded = false;
|
||||
}
|
||||
|
||||
CPluginManager::~CPluginManager()
|
||||
{
|
||||
SourceHook::List<CNameAlias *>::iterator iter;
|
||||
|
||||
for (iter=m_Aliases.begin(); iter!=m_Aliases.end(); iter++)
|
||||
{
|
||||
delete (*iter);
|
||||
}
|
||||
|
||||
m_Aliases.clear();
|
||||
}
|
||||
|
||||
const char *CPluginManager::LookupAlias(const char *alias)
|
||||
{
|
||||
SourceHook::List<CNameAlias *>::iterator iter;
|
||||
CNameAlias *p;
|
||||
|
||||
for (iter=m_Aliases.begin(); iter!=m_Aliases.end(); iter++)
|
||||
{
|
||||
p = (*iter);
|
||||
if (p->alias.compare(alias) == 0)
|
||||
{
|
||||
return p->value.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SourceHook::List<SourceMM::CNameAlias *>::iterator CPluginManager::_alias_begin()
|
||||
{
|
||||
return m_Aliases.begin();
|
||||
}
|
||||
|
||||
SourceHook::List<SourceMM::CNameAlias *>::iterator CPluginManager::_alias_end()
|
||||
{
|
||||
return m_Aliases.end();
|
||||
}
|
||||
|
||||
void CPluginManager::SetAlias(const char *alias, const char *value)
|
||||
{
|
||||
SourceHook::List<CNameAlias *>::iterator iter;
|
||||
CNameAlias *p;
|
||||
|
||||
for (iter=m_Aliases.begin(); iter!=m_Aliases.end(); iter++)
|
||||
{
|
||||
p = (*iter);
|
||||
if (p->alias.compare(alias) == 0)
|
||||
{
|
||||
if (value[0] == '\0')
|
||||
{
|
||||
iter = m_Aliases.erase(iter);
|
||||
return;
|
||||
} else {
|
||||
p->value.assign(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value[0] != '\0')
|
||||
{
|
||||
p = new CNameAlias;
|
||||
|
||||
p->alias.assign(alias);
|
||||
p->value.assign(value);
|
||||
|
||||
m_Aliases.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin::CPlugin() : m_Id(0), m_Source(0), m_API(NULL), m_Lib(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PluginId CPluginManager::Load(const char *file, PluginId source, bool &already, char *error, size_t maxlen)
|
||||
{
|
||||
already = false;
|
||||
//Check if we're about to reload an old plugin
|
||||
PluginIter i = m_Plugins.begin();
|
||||
while (i != m_Plugins.end())
|
||||
{
|
||||
if ( (*i) && UTIL_PathCmp(file, (*i)->m_File.c_str()) )
|
||||
{
|
||||
if ( (*i)->m_Status < Pl_Paused )
|
||||
{
|
||||
//Attempt to load the plugin again
|
||||
already = true;
|
||||
i = m_Plugins.erase(i);
|
||||
continue;
|
||||
} else {
|
||||
//No need to load it
|
||||
already = true;
|
||||
return (*i)->m_Id;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
CPlugin *pl = _Load(file, source, error, maxlen);
|
||||
|
||||
if (!pl)
|
||||
return Pl_BadLoad;
|
||||
|
||||
ITER_PLEVENT(OnPluginLoad, pl->m_Id);
|
||||
|
||||
return pl->m_Id;
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin *CPluginManager::FindById(PluginId id)
|
||||
{
|
||||
PluginIter i;
|
||||
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i)->m_Id == id )
|
||||
return (*i);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CPluginManager::SetAllLoaded()
|
||||
{
|
||||
m_AllLoaded = true;
|
||||
PluginIter i;
|
||||
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i) && (*i)->m_Status == Pl_Running && (*i)->m_API )
|
||||
{
|
||||
//API 4 is when we added this callback
|
||||
//Min version is now 5, so we ignore this check
|
||||
//if ( (*i)->m_API->GetApiVersion() >= 004 )
|
||||
(*i)->m_API->AllPluginsLoaded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CPluginManager::Pause(PluginId id, char *error, size_t maxlen)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Plugin id not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret;
|
||||
|
||||
if ( (ret=_Pause(pl, error, maxlen)) == true )
|
||||
{
|
||||
ITER_PLEVENT(OnPluginPause, pl->m_Id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CPluginManager::Unpause(PluginId id, char *error, size_t maxlen)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Plugin id not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret;
|
||||
|
||||
if ( (ret=_Unpause(pl, error, maxlen)) == true )
|
||||
{
|
||||
ITER_PLEVENT(OnPluginUnpause, pl->m_Id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CPluginManager::Unload(PluginId id, bool force, char *error, size_t maxlen)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Plugin %d not found", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret;
|
||||
PluginId old_id = pl->m_Id;
|
||||
if ( (ret=_Unload(pl, force, error, maxlen)) == true )
|
||||
{
|
||||
ITER_PLEVENT(OnPluginUnload, old_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CPluginManager::Retry(PluginId id, char *error, size_t len)
|
||||
{
|
||||
PluginIter i;
|
||||
char buffer[64];
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i) && (*i)->m_Id == id )
|
||||
{
|
||||
if ( (*i)->m_Status >= Pl_Paused)
|
||||
{
|
||||
UTIL_Format(error, len, "Plugin %d is already running.", id);
|
||||
return false;
|
||||
}
|
||||
CPlugin *pl = _Load((*i)->m_File.c_str(), Pl_Console, error, len);
|
||||
if (!pl)
|
||||
return false;
|
||||
if (pl->m_Status >= Pl_Paused)
|
||||
{
|
||||
//Now it gets crazy... unload the original copy.
|
||||
_Unload( (*i), true, buffer, sizeof(buffer)-1 );
|
||||
|
||||
//Set the new copy's id
|
||||
pl->m_Id = id;
|
||||
|
||||
//We just wasted an id... reclaim it
|
||||
m_LastId--;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
//don't really care about the buffer here
|
||||
_Unload(pl, true, buffer, sizeof(buffer)-1);
|
||||
|
||||
//We just wasted an id... reclaim it
|
||||
m_LastId--;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UTIL_Format(error, len, "Plugin %d not found,", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin *CPluginManager::FindByAPI(ISmmPlugin *api)
|
||||
{
|
||||
PluginIter i;
|
||||
|
||||
//don't find bad plugins!
|
||||
if (!api)
|
||||
return NULL;
|
||||
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i)->m_API == api )
|
||||
return (*i);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CPluginManager::GetPluginCount()
|
||||
{
|
||||
return (int)m_Plugins.size();
|
||||
}
|
||||
|
||||
const char *CPluginManager::GetStatusText(CPlugin *pl)
|
||||
{
|
||||
switch (pl->m_Status)
|
||||
{
|
||||
case Pl_NotFound:
|
||||
return "NOFILE";
|
||||
case Pl_Error:
|
||||
return "ERROR";
|
||||
case Pl_Refused:
|
||||
return "FAILED";
|
||||
case Pl_Paused:
|
||||
return "PAUSED";
|
||||
case Pl_Running:
|
||||
{
|
||||
if (pl->m_API && pl->m_API->QueryRunning(NULL, 0))
|
||||
{
|
||||
return "STOPPED";
|
||||
} else {
|
||||
return "RUNNING";
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "-";
|
||||
}
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source, char *error, size_t maxlen)
|
||||
{
|
||||
FILE *fp;
|
||||
CPlugin *pl;
|
||||
|
||||
pl = new CPlugin();
|
||||
*error = '\0';
|
||||
|
||||
//Add plugin to list
|
||||
pl->m_Id = m_LastId;
|
||||
pl->m_File.assign(file);
|
||||
m_Plugins.push_back(pl);
|
||||
m_LastId++;
|
||||
|
||||
//Check if the file even exists
|
||||
fp = fopen(file, "r");
|
||||
if (!fp)
|
||||
{
|
||||
if (error)
|
||||
UTIL_Format(error, maxlen, "File not found: %s", file);
|
||||
pl->m_Status = Pl_NotFound;
|
||||
}
|
||||
|
||||
if (fp)
|
||||
{
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
|
||||
//Load the file
|
||||
pl->m_Lib = dlmount(file);
|
||||
if (!pl->m_Lib)
|
||||
{
|
||||
if (error)
|
||||
UTIL_Format(error, maxlen, "%s", dlerror());
|
||||
pl->m_Status = Pl_Error;
|
||||
} else {
|
||||
CreateInterfaceFn pfn = (CreateInterfaceFn)(dlsym(pl->m_Lib, PL_EXPOSURE_C));
|
||||
if (!pfn)
|
||||
{
|
||||
if (error)
|
||||
UTIL_Format(error, maxlen, "Function %s not found", PL_EXPOSURE_C);
|
||||
pl->m_Status = Pl_Error;
|
||||
} else {
|
||||
pl->m_API = static_cast<ISmmPlugin *>((pfn)(PLAPI_NAME, NULL));
|
||||
if (!pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
UTIL_Format(error, maxlen, "Failed to get API");
|
||||
pl->m_Status = Pl_Error;
|
||||
} else {
|
||||
int api = pl->m_API->GetApiVersion();
|
||||
if (api < PLAPI_MIN_VERSION)
|
||||
{
|
||||
if (error)
|
||||
UTIL_Format(error, maxlen, "Plugin API %d is out of date with required minimum (%d)", api, PLAPI_MIN_VERSION);
|
||||
pl->m_Status = Pl_Error;
|
||||
} else if (api > PLAPI_VERSION) {
|
||||
if (error)
|
||||
UTIL_Format(error, maxlen, "Plugin API %d is newer than internal version (%d)", api, PLAPI_VERSION);
|
||||
pl->m_Status = Pl_Error;
|
||||
} else {
|
||||
if (pl->m_API->Load(pl->m_Id, static_cast<ISmmAPI *>(&g_SmmAPI), error, maxlen, m_AllLoaded))
|
||||
{
|
||||
pl->m_Status = Pl_Running;
|
||||
if (m_AllLoaded)
|
||||
{
|
||||
//API 4 is when we added this callback
|
||||
//Removing this code as the min version is now 5
|
||||
//if (pl->m_API->GetApiVersion() >= 4)
|
||||
pl->m_API->AllPluginsLoaded();
|
||||
}
|
||||
} else {
|
||||
pl->m_Status = Pl_Refused;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pl->m_Lib && (pl->m_Status < Pl_Paused))
|
||||
{
|
||||
pl->m_Events.clear();
|
||||
g_SourceHook.UnloadPlugin(pl->m_Id);
|
||||
UnregAllConCmds(pl);
|
||||
|
||||
dlclose(pl->m_Lib);
|
||||
pl->m_Lib = NULL;
|
||||
pl->m_API = NULL;
|
||||
}
|
||||
|
||||
return pl;
|
||||
}
|
||||
|
||||
bool CPluginManager::_Unload(CPluginManager::CPlugin *pl, bool force, char *error, size_t maxlen)
|
||||
{
|
||||
if (error)
|
||||
*error = '\0';
|
||||
if (pl->m_API && pl->m_Lib)
|
||||
{
|
||||
//Note, we'll always tell the plugin it will be unloading...
|
||||
if (pl->m_API->Unload(error, maxlen) || force)
|
||||
{
|
||||
//Make sure to detach it from sourcehook!
|
||||
g_SourceHook.UnloadPlugin(pl->m_Id);
|
||||
|
||||
UnregAllConCmds(pl);
|
||||
|
||||
//Clean up the DLL
|
||||
dlclose(pl->m_Lib);
|
||||
pl->m_Lib = NULL;
|
||||
pl->m_API = NULL;
|
||||
|
||||
//Remove the plugin from the list
|
||||
PluginIter i;
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i)->m_Id == pl->m_Id )
|
||||
{
|
||||
i = m_Plugins.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Free its memory
|
||||
delete pl;
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
//The plugin is not valid, and let's just remove it from the list anyway
|
||||
PluginIter i;
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i)->m_Id == pl->m_Id )
|
||||
{
|
||||
i = m_Plugins.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete pl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPluginManager::_Pause(CPluginManager::CPlugin *pl, char *error, size_t maxlen)
|
||||
{
|
||||
if (error)
|
||||
*error = '\0';
|
||||
if (pl->m_Status != Pl_Running || !pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
UTIL_Format(error, maxlen, "Plugin cannot be paused");
|
||||
} else {
|
||||
if (pl->m_API->Pause(error, maxlen))
|
||||
{
|
||||
g_SourceHook.PausePlugin(pl->m_Id);
|
||||
pl->m_Status = Pl_Paused;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPluginManager::_Unpause(CPluginManager::CPlugin *pl, char *error, size_t maxlen)
|
||||
{
|
||||
if (error)
|
||||
*error = '\0';
|
||||
|
||||
if (pl->m_Status != Pl_Paused || !pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
UTIL_Format(error, maxlen, "Plugin cannot be unpaused");
|
||||
} else {
|
||||
if (pl->m_API->Unpause(error, maxlen))
|
||||
{
|
||||
g_SourceHook.UnpausePlugin(pl->m_Id);
|
||||
pl->m_Status = Pl_Running;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPluginManager::UnloadAll()
|
||||
{
|
||||
PluginIter i;
|
||||
|
||||
char error[128];
|
||||
bool status = true;
|
||||
|
||||
while ((i = m_Plugins.begin()) != m_Plugins.end())
|
||||
{
|
||||
if ( !_Unload( (*i), true, error, sizeof(error)) )
|
||||
status = false;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool CPluginManager::Query(PluginId id, const char *&file, Pl_Status &status, PluginId &source)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl)
|
||||
return false;
|
||||
|
||||
file = pl->m_File.c_str();
|
||||
status = pl->m_Status;
|
||||
source = pl->m_Source;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginManager::QueryRunning(PluginId id, char *error, size_t maxlength)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl || !pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
UTIL_Format(error, maxlength, "Plugin not valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
return pl->m_API->QueryRunning(error, maxlength);
|
||||
}
|
||||
|
||||
bool CPluginManager::QueryHandle(PluginId id, void *&handle)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
handle = static_cast<void *>(pl->m_Lib);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PluginIter CPluginManager::_begin()
|
||||
{
|
||||
return m_Plugins.begin();
|
||||
}
|
||||
|
||||
PluginIter CPluginManager::_end()
|
||||
{
|
||||
return m_Plugins.end();
|
||||
}
|
||||
|
||||
void CPluginManager::AddPluginCvar(ISmmPlugin *api, ConCommandBase *pCvar)
|
||||
{
|
||||
CPlugin *pl = FindByAPI(api);
|
||||
|
||||
if (!pl)
|
||||
return;
|
||||
|
||||
pl->m_Cvars.push_back(pCvar);
|
||||
}
|
||||
|
||||
void CPluginManager::AddPluginCmd(ISmmPlugin *api, ConCommandBase *pCmd)
|
||||
{
|
||||
CPlugin *pl = FindByAPI(api);
|
||||
|
||||
if (!pl)
|
||||
return;
|
||||
|
||||
pl->m_Cmds.push_back(pCmd);
|
||||
}
|
||||
|
||||
void CPluginManager::RemovePluginCvar(ISmmPlugin *api, ConCommandBase *pCvar)
|
||||
{
|
||||
CPlugin *pl = FindByAPI(api);
|
||||
|
||||
if (!pl)
|
||||
return;
|
||||
|
||||
pl->m_Cvars.remove(pCvar);
|
||||
}
|
||||
|
||||
void CPluginManager::RemovePluginCmd(ISmmPlugin *api, ConCommandBase *pCmd)
|
||||
{
|
||||
CPlugin *pl = FindByAPI(api);
|
||||
|
||||
if (!pl)
|
||||
return;
|
||||
|
||||
pl->m_Cmds.remove(pCmd);
|
||||
}
|
||||
|
||||
void CPluginManager::UnregAllConCmds(CPlugin *pl)
|
||||
{
|
||||
SourceHook::List<ConCommandBase *>::iterator i;
|
||||
|
||||
for (i=pl->m_Cvars.begin(); i!=pl->m_Cvars.end(); i++)
|
||||
g_SMConVarAccessor.Unregister(pl->m_Id, (*i) );
|
||||
|
||||
pl->m_Cvars.clear();
|
||||
|
||||
for (i=pl->m_Cmds.begin(); i!=pl->m_Cmds.end(); i++)
|
||||
g_SMConVarAccessor.Unregister(pl->m_Id, (*i) );
|
||||
|
||||
pl->m_Cmds.clear();
|
||||
}
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _DEBUG
|
||||
#define DEBUG2
|
||||
#undef _DEBUG
|
||||
#endif
|
||||
#include "metamod.h"
|
||||
#include "metamod_plugins.h"
|
||||
#include "metamod_util.h"
|
||||
#if defined DEBUG2
|
||||
#undef DEBUG2
|
||||
#define _DEBUG
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Implements functions from CPlugin.h
|
||||
* @file CPlugin.cpp
|
||||
*/
|
||||
|
||||
using namespace SourceMM;
|
||||
|
||||
#define ITER_PLEVENT(evn, plid) \
|
||||
CPluginManager::CPlugin *_Xpl; \
|
||||
SourceHook::List<IMetamodListener *>::iterator event; \
|
||||
IMetamodListener *api; \
|
||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
||||
_Xpl = (*iter); \
|
||||
if (_Xpl->m_Id == plid) \
|
||||
continue; \
|
||||
for (event=_Xpl->m_Events.begin(); event!=_Xpl->m_Events.end(); event++) { \
|
||||
api = (*event); \
|
||||
api->evn(plid); \
|
||||
} \
|
||||
}
|
||||
|
||||
CPluginManager g_PluginMngr;
|
||||
|
||||
CPluginManager::CPluginManager()
|
||||
{
|
||||
m_LastId = Pl_MinId;
|
||||
m_AllLoaded = false;
|
||||
}
|
||||
|
||||
CPluginManager::~CPluginManager()
|
||||
{
|
||||
SourceHook::List<CNameAlias *>::iterator iter;
|
||||
|
||||
for (iter = m_Aliases.begin(); iter != m_Aliases.end(); iter++)
|
||||
{
|
||||
delete (*iter);
|
||||
}
|
||||
|
||||
m_Aliases.clear();
|
||||
}
|
||||
|
||||
const char *CPluginManager::LookupAlias(const char *alias)
|
||||
{
|
||||
SourceHook::List<CNameAlias *>::iterator iter;
|
||||
CNameAlias *p;
|
||||
|
||||
for (iter = m_Aliases.begin(); iter != m_Aliases.end(); iter++)
|
||||
{
|
||||
p = (*iter);
|
||||
if (p->alias.compare(alias) == 0)
|
||||
{
|
||||
return p->value.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SourceHook::List<SourceMM::CNameAlias *>::iterator CPluginManager::_alias_begin()
|
||||
{
|
||||
return m_Aliases.begin();
|
||||
}
|
||||
|
||||
SourceHook::List<SourceMM::CNameAlias *>::iterator CPluginManager::_alias_end()
|
||||
{
|
||||
return m_Aliases.end();
|
||||
}
|
||||
|
||||
void CPluginManager::SetAlias(const char *alias, const char *value)
|
||||
{
|
||||
SourceHook::List<CNameAlias *>::iterator iter;
|
||||
CNameAlias *p;
|
||||
|
||||
for (iter = m_Aliases.begin(); iter != m_Aliases.end(); iter++)
|
||||
{
|
||||
p = (*iter);
|
||||
if (p->alias.compare(alias) == 0)
|
||||
{
|
||||
if (value[0] == '\0')
|
||||
{
|
||||
iter = m_Aliases.erase(iter);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->value.assign(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value[0] != '\0')
|
||||
{
|
||||
p = new CNameAlias;
|
||||
|
||||
p->alias.assign(alias);
|
||||
p->value.assign(value);
|
||||
|
||||
m_Aliases.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin::CPlugin() : m_Id(0), m_Source(0), m_API(NULL), m_Lib(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PluginId CPluginManager::Load(const char *file, PluginId source, bool &already, char *error, size_t maxlen)
|
||||
{
|
||||
already = false;
|
||||
//Check if we're about to reload an old plugin
|
||||
PluginIter i = m_Plugins.begin();
|
||||
while (i != m_Plugins.end())
|
||||
{
|
||||
if ((*i) && UTIL_PathCmp(file, (*i)->m_File.c_str()))
|
||||
{
|
||||
if ((*i)->m_Status < Pl_Paused)
|
||||
{
|
||||
//Attempt to load the plugin again
|
||||
already = true;
|
||||
i = m_Plugins.erase(i);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
//No need to load it
|
||||
already = true;
|
||||
return (*i)->m_Id;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
CPlugin *pl = _Load(file, source, error, maxlen);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
return Pl_BadLoad;
|
||||
}
|
||||
|
||||
ITER_PLEVENT(OnPluginLoad, pl->m_Id);
|
||||
|
||||
return pl->m_Id;
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin *CPluginManager::FindById(PluginId id)
|
||||
{
|
||||
PluginIter i;
|
||||
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i)->m_Id == id )\
|
||||
{
|
||||
return (*i);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CPluginManager::SetAllLoaded()
|
||||
{
|
||||
m_AllLoaded = true;
|
||||
PluginIter i;
|
||||
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i) && (*i)->m_Status == Pl_Running && (*i)->m_API )
|
||||
{
|
||||
//API 4 is when we added this callback
|
||||
//Min version is now 5, so we ignore this check
|
||||
//if ( (*i)->m_API->GetApiVersion() >= 004 )
|
||||
(*i)->m_API->AllPluginsLoaded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CPluginManager::Pause(PluginId id, char *error, size_t maxlen)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Plugin id not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret;
|
||||
|
||||
if ((ret=_Pause(pl, error, maxlen)) == true)
|
||||
{
|
||||
ITER_PLEVENT(OnPluginPause, pl->m_Id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CPluginManager::Unpause(PluginId id, char *error, size_t maxlen)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Plugin id not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret;
|
||||
|
||||
if ( (ret=_Unpause(pl, error, maxlen)) == true )
|
||||
{
|
||||
ITER_PLEVENT(OnPluginUnpause, pl->m_Id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CPluginManager::Unload(PluginId id, bool force, char *error, size_t maxlen)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Plugin %d not found", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret;
|
||||
PluginId old_id = pl->m_Id;
|
||||
if ( (ret=_Unload(pl, force, error, maxlen)) == true )
|
||||
{
|
||||
ITER_PLEVENT(OnPluginUnload, old_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CPluginManager::Retry(PluginId id, char *error, size_t len)
|
||||
{
|
||||
PluginIter i;
|
||||
char buffer[64];
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i) && (*i)->m_Id == id )
|
||||
{
|
||||
if ( (*i)->m_Status >= Pl_Paused)
|
||||
{
|
||||
UTIL_Format(error, len, "Plugin %d is already running.", id);
|
||||
return false;
|
||||
}
|
||||
CPlugin *pl = _Load((*i)->m_File.c_str(), Pl_Console, error, len);
|
||||
if (!pl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (pl->m_Status >= Pl_Paused)
|
||||
{
|
||||
//Now it gets crazy... unload the original copy.
|
||||
_Unload( (*i), true, buffer, sizeof(buffer)-1 );
|
||||
|
||||
//Set the new copy's id
|
||||
pl->m_Id = id;
|
||||
|
||||
//We just wasted an id... reclaim it
|
||||
m_LastId--;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//don't really care about the buffer here
|
||||
_Unload(pl, true, buffer, sizeof(buffer)-1);
|
||||
|
||||
//We just wasted an id... reclaim it
|
||||
m_LastId--;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UTIL_Format(error, len, "Plugin %d not found,", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin *CPluginManager::FindByAPI(ISmmPlugin *api)
|
||||
{
|
||||
PluginIter i;
|
||||
|
||||
//don't find bad plugins!
|
||||
if (!api)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ((*i)->m_API == api)
|
||||
{
|
||||
return (*i);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CPluginManager::GetPluginCount()
|
||||
{
|
||||
return (int)m_Plugins.size();
|
||||
}
|
||||
|
||||
const char *CPluginManager::GetStatusText(CPlugin *pl)
|
||||
{
|
||||
switch (pl->m_Status)
|
||||
{
|
||||
case Pl_NotFound:
|
||||
return "NOFILE";
|
||||
case Pl_Error:
|
||||
return "ERROR";
|
||||
case Pl_Refused:
|
||||
return "FAILED";
|
||||
case Pl_Paused:
|
||||
return "PAUSED";
|
||||
case Pl_Running:
|
||||
{
|
||||
if (pl->m_API && pl->m_API->QueryRunning(NULL, 0))
|
||||
{
|
||||
return "STOPPED";
|
||||
} else {
|
||||
return "RUNNING";
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "-";
|
||||
}
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source, char *error, size_t maxlen)
|
||||
{
|
||||
FILE *fp;
|
||||
CPlugin *pl;
|
||||
|
||||
pl = new CPlugin();
|
||||
*error = '\0';
|
||||
|
||||
//Add plugin to list
|
||||
pl->m_Id = m_LastId;
|
||||
pl->m_File.assign(file);
|
||||
m_Plugins.push_back(pl);
|
||||
m_LastId++;
|
||||
|
||||
//Check if the file even exists
|
||||
fp = fopen(file, "r");
|
||||
if (!fp)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "File not found: %s", file);
|
||||
}
|
||||
pl->m_Status = Pl_NotFound;
|
||||
}
|
||||
|
||||
if (fp)
|
||||
{
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
|
||||
//Load the file
|
||||
pl->m_Lib = dlmount(file);
|
||||
if (!pl->m_Lib)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "%s", dlerror());
|
||||
}
|
||||
pl->m_Status = Pl_Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateInterfaceFn pfn = (CreateInterfaceFn)(dlsym(pl->m_Lib, PL_EXPOSURE_C));
|
||||
if (!pfn)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Function %s not found", PL_EXPOSURE_C);
|
||||
}
|
||||
pl->m_Status = Pl_Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
pl->m_API = static_cast<ISmmPlugin *>((pfn)(PLAPI_NAME, NULL));
|
||||
if (!pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Failed to get API");
|
||||
}
|
||||
pl->m_Status = Pl_Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
int api = pl->m_API->GetApiVersion();
|
||||
if (api < PLAPI_MIN_VERSION)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Plugin API %d is out of date with required minimum (%d)", api, PLAPI_MIN_VERSION);
|
||||
}
|
||||
pl->m_Status = Pl_Error;
|
||||
}
|
||||
else if (api > PLAPI_VERSION)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Plugin API %d is newer than internal version (%d)", api, PLAPI_VERSION);
|
||||
}
|
||||
pl->m_Status = Pl_Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pl->m_API->Load(pl->m_Id, &g_Metamod, error, maxlen, m_AllLoaded))
|
||||
{
|
||||
pl->m_Status = Pl_Running;
|
||||
if (m_AllLoaded)
|
||||
{
|
||||
//API 4 is when we added this callback
|
||||
//Removing this code as the min version is now 5
|
||||
//if (pl->m_API->GetApiVersion() >= 4)
|
||||
pl->m_API->AllPluginsLoaded();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pl->m_Status = Pl_Refused;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pl->m_Lib && (pl->m_Status < Pl_Paused))
|
||||
{
|
||||
pl->m_Events.clear();
|
||||
g_SourceHook.UnloadPlugin(pl->m_Id);
|
||||
UnregAllConCmds(pl);
|
||||
|
||||
dlclose(pl->m_Lib);
|
||||
pl->m_Lib = NULL;
|
||||
pl->m_API = NULL;
|
||||
}
|
||||
|
||||
return pl;
|
||||
}
|
||||
|
||||
bool CPluginManager::_Unload(CPluginManager::CPlugin *pl, bool force, char *error, size_t maxlen)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
*error = '\0';
|
||||
}
|
||||
|
||||
if (pl->m_API && pl->m_Lib)
|
||||
{
|
||||
//Note, we'll always tell the plugin it will be unloading...
|
||||
if (pl->m_API->Unload(error, maxlen) || force)
|
||||
{
|
||||
//Make sure to detach it from sourcehook!
|
||||
g_SourceHook.UnloadPlugin(pl->m_Id);
|
||||
|
||||
pl->m_Events.clear();
|
||||
|
||||
UnregAllConCmds(pl);
|
||||
|
||||
//Clean up the DLL
|
||||
dlclose(pl->m_Lib);
|
||||
pl->m_Lib = NULL;
|
||||
pl->m_API = NULL;
|
||||
|
||||
//Remove the plugin from the list
|
||||
PluginIter i;
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i)->m_Id == pl->m_Id )
|
||||
{
|
||||
i = m_Plugins.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Free its memory
|
||||
delete pl;
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
//The plugin is not valid, and let's just remove it from the list anyway
|
||||
PluginIter i;
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
{
|
||||
if ( (*i)->m_Id == pl->m_Id )
|
||||
{
|
||||
i = m_Plugins.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete pl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPluginManager::_Pause(CPluginManager::CPlugin *pl, char *error, size_t maxlen)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
*error = '\0';
|
||||
}
|
||||
|
||||
if (pl->m_Status != Pl_Running || !pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Plugin cannot be paused");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pl->m_API->Pause(error, maxlen))
|
||||
{
|
||||
g_SourceHook.PausePlugin(pl->m_Id);
|
||||
pl->m_Status = Pl_Paused;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPluginManager::_Unpause(CPluginManager::CPlugin *pl, char *error, size_t maxlen)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
*error = '\0';
|
||||
}
|
||||
|
||||
if (pl->m_Status != Pl_Paused || !pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
UTIL_Format(error, maxlen, "Plugin cannot be unpaused");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pl->m_API->Unpause(error, maxlen))
|
||||
{
|
||||
g_SourceHook.UnpausePlugin(pl->m_Id);
|
||||
pl->m_Status = Pl_Running;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPluginManager::UnloadAll()
|
||||
{
|
||||
PluginIter i;
|
||||
|
||||
char error[128];
|
||||
bool status = true;
|
||||
|
||||
while ((i = m_Plugins.begin()) != m_Plugins.end())
|
||||
{
|
||||
if ( !_Unload( (*i), true, error, sizeof(error)) )
|
||||
{
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool CPluginManager::Query(PluginId id, const char *&file, Pl_Status &status, PluginId &source)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
file = pl->m_File.c_str();
|
||||
status = pl->m_Status;
|
||||
source = pl->m_Source;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginManager::QueryRunning(PluginId id, char *error, size_t maxlength)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl || !pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
UTIL_Format(error, maxlength, "Plugin not valid");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return pl->m_API->QueryRunning(error, maxlength);
|
||||
}
|
||||
|
||||
bool CPluginManager::QueryHandle(PluginId id, void *&handle)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
handle = static_cast<void *>(pl->m_Lib);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PluginIter CPluginManager::_begin()
|
||||
{
|
||||
return m_Plugins.begin();
|
||||
}
|
||||
|
||||
PluginIter CPluginManager::_end()
|
||||
{
|
||||
return m_Plugins.end();
|
||||
}
|
||||
|
||||
void CPluginManager::AddPluginCvar(ISmmPlugin *api, ConCommandBase *pCvar)
|
||||
{
|
||||
CPlugin *pl = FindByAPI(api);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pl->m_Cvars.push_back(pCvar);
|
||||
}
|
||||
|
||||
void CPluginManager::AddPluginCmd(ISmmPlugin *api, ConCommandBase *pCmd)
|
||||
{
|
||||
CPlugin *pl = FindByAPI(api);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pl->m_Cmds.push_back(pCmd);
|
||||
}
|
||||
|
||||
void CPluginManager::RemovePluginCvar(ISmmPlugin *api, ConCommandBase *pCvar)
|
||||
{
|
||||
CPlugin *pl = FindByAPI(api);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pl->m_Cvars.remove(pCvar);
|
||||
}
|
||||
|
||||
void CPluginManager::RemovePluginCmd(ISmmPlugin *api, ConCommandBase *pCmd)
|
||||
{
|
||||
CPlugin *pl = FindByAPI(api);
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pl->m_Cmds.remove(pCmd);
|
||||
}
|
||||
|
||||
void CPluginManager::UnregAllConCmds(CPlugin *pl)
|
||||
{
|
||||
SourceHook::List<ConCommandBase *>::iterator i;
|
||||
|
||||
/* :TODO: */
|
||||
for (i=pl->m_Cvars.begin(); i!=pl->m_Cvars.end(); i++)
|
||||
{
|
||||
g_Metamod.UnregisterConCommandBase(pl->m_Id, (*i) );
|
||||
}
|
||||
pl->m_Cvars.clear();
|
||||
|
||||
for (i=pl->m_Cmds.begin(); i!=pl->m_Cmds.end(); i++)
|
||||
{
|
||||
g_Metamod.UnregisterConCommandBase(pl->m_Id, (*i) );
|
||||
}
|
||||
pl->m_Cmds.clear();
|
||||
}
|
||||
|
@ -1,12 +1,29 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_CPLUGIN_H
|
||||
#define _INCLUDE_CPLUGIN_H
|
||||
@ -18,11 +35,10 @@
|
||||
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include "convar_smm.h"
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include "IPluginManager.h"
|
||||
#include "oslink.h"
|
||||
#include "sh_list.h"
|
||||
#include "sh_string.h"
|
||||
#include "metamod_oslink.h"
|
||||
|
||||
/**
|
||||
* History of plugin versions: (M=min, C=current)
|
||||
@ -38,7 +54,7 @@
|
||||
* 8: New SourceHook version (2005-12-23)
|
||||
* New ISmmAPI additions
|
||||
* 9: New ISmmPluginManager additions
|
||||
* 10: Added VSP listen functions to ISmmAPI and IMetamodListener (2007-02-09)
|
||||
* C 10: Added VSP listen functions to ISmmAPI and IMetamodListener (2007-02-09)
|
||||
* C 11: New SourceHook version V5 (May, 2007)
|
||||
*/
|
||||
|
||||
@ -148,3 +164,4 @@ typedef SourceHook::List<SourceMM::CPluginManager::CPlugin *>::iterator PluginIt
|
||||
extern SourceMM::CPluginManager g_PluginMngr;
|
||||
|
||||
#endif //_INCLUDE_CPLUGIN_H
|
||||
|
294
sourcemm/metamod_provider.h
Normal file
294
sourcemm/metamod_provider.h
Normal file
@ -0,0 +1,294 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_METAMOD_SOURCE_SUPPORT_H_
|
||||
#define _INCLUDE_METAMOD_SOURCE_SUPPORT_H_
|
||||
|
||||
namespace SourceMM
|
||||
{
|
||||
enum
|
||||
{
|
||||
ConVarFlag_None,
|
||||
ConVarFlag_Notify,
|
||||
ConVarFlag_Replicated,
|
||||
ConVarFlag_SpOnly
|
||||
};
|
||||
|
||||
enum ProvidedHooks
|
||||
{
|
||||
ProvidedHook_LevelInit = 0, /**< IServerGameDLL::LevelInit */
|
||||
ProvidedHook_LevelShutdown = 1, /**< IServerGameDLL::LevelShutdown */
|
||||
ProvidedHook_DLLInit = 2, /**< IServerGameDLL::DLLInit */
|
||||
ProvidedHook_DLLShutdown = 3, /**< IServerGameDLL::DLLShutdown */
|
||||
ProvidedHook_GameInit = 4, /**< IServerGameDLL::GameInit */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Abstracts command information, since the new engine fixes the
|
||||
* re-entrancy problems in the tokenization system.
|
||||
*/
|
||||
class IMetamodSourceCommandInfo
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Returns the argument count such that arguments
|
||||
* 1 to N are valid arguments, and 0 is the command name.
|
||||
*
|
||||
* @return Argument count.
|
||||
*/
|
||||
virtual unsigned int GetArgCount() =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the string of an argument number.
|
||||
*
|
||||
* @param num Argument number.
|
||||
* @return Argument text.
|
||||
*/
|
||||
virtual const char *GetArg(unsigned int num) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the entire command argument string.
|
||||
*
|
||||
* @return Argument string.
|
||||
*/
|
||||
virtual const char *GetArgString() =0;
|
||||
};
|
||||
|
||||
class IMetamodSourceProvider
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Returns whether source engine build is compatible.
|
||||
*
|
||||
* @param build Source engine build.
|
||||
* @return True if compatible, false otherwise.
|
||||
*/
|
||||
virtual bool IsSourceEngineBuildCompatible(int build) =0;
|
||||
|
||||
/**
|
||||
* @brief Retrieves hook information for each callback. Each hook
|
||||
* must be implemented.
|
||||
*
|
||||
* @param hook Hook information to provide.
|
||||
* @param pInfo Non-NULL pointer to fill with information
|
||||
* about the hook's virtual location.
|
||||
* @return True if supported, false to fail, which
|
||||
* will cause Metamod:Source to fail.
|
||||
*/
|
||||
virtual bool GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo) =0;
|
||||
|
||||
/**
|
||||
* @brief Logs a message via IVEngineServer::LogPrint.
|
||||
*
|
||||
* @param buffer Buffer to print.
|
||||
* @return True on success, false if not supported,
|
||||
* or IVEngineServer is not yet known.
|
||||
*/
|
||||
virtual bool LogMessage(const char *buffer) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the command line value of a parameter. If ICvar
|
||||
* is not yet loaded, this uses an equivalent function.
|
||||
*
|
||||
* @param key Parameter to look up.
|
||||
* @param val Default string to return if none found.
|
||||
* @return Parameter value.
|
||||
*/
|
||||
virtual const char *GetCommandLineValue(const char *key, const char *defval) =0;
|
||||
|
||||
/**
|
||||
* @brief Prints a string to the remote server console.
|
||||
*
|
||||
* Note: new lines are not appended.
|
||||
*
|
||||
* @param msg Message string.
|
||||
*/
|
||||
virtual void ConsolePrint(const char *msg) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns whether remote printing is available.
|
||||
*
|
||||
* @return True if remote printing is available,
|
||||
* otherwise returns false.
|
||||
*/
|
||||
virtual bool IsRemotePrintingAvailable() =0;
|
||||
|
||||
/**
|
||||
* @brief Prints text in the specified client's console.
|
||||
*
|
||||
* @param client Client edict pointer.
|
||||
* @param msg Message string.
|
||||
*/
|
||||
virtual void ClientConsolePrint(edict_t *client, const char *msg) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns a server plugin helper for the given interface
|
||||
* string.
|
||||
*
|
||||
* @param iface Interface version
|
||||
* @return IServerPluginCallbacks pointer.
|
||||
*/
|
||||
virtual IServerPluginCallbacks *GetVSPCallbacks(const char *iface) =0;
|
||||
|
||||
/**
|
||||
* @brief Halts the server with a fatal error message.
|
||||
*
|
||||
* No newline is appended.
|
||||
*
|
||||
* @param fmt Formatted message string.
|
||||
* @param ... Format parameters.
|
||||
*/
|
||||
virtual void DisplayError(const char *fmt, ...) =0;
|
||||
|
||||
/**
|
||||
* @brief Sends the server a warning message.
|
||||
*
|
||||
* No newline is appended.
|
||||
*
|
||||
* @param fmt Formatted message string.
|
||||
* @param ... Format parameters.
|
||||
*/
|
||||
virtual void DisplayWarning(const char *fmt, ...) =0;
|
||||
|
||||
/**
|
||||
* @brief Attempts to notify the provider of the gamedll version being
|
||||
* used.
|
||||
*
|
||||
* @param iface Interface string.
|
||||
* @return Version number on success, 0 otherwise.
|
||||
*/
|
||||
virtual int TryServerGameDLL(const char *iface) =0;
|
||||
|
||||
/**
|
||||
* @brief Notifies the provider that the DLLInit pre-hook is almost done.
|
||||
*/
|
||||
virtual void Notify_DLLInit_Pre(void *gamedll,
|
||||
CreateInterfaceFn engineFactory,
|
||||
CreateInterfaceFn serverFactory) =0;
|
||||
|
||||
virtual void Notify_DLLShutdown_Pre() =0;
|
||||
|
||||
/**
|
||||
* @brief Wrapper around IVEngineServer::ServerCommand()
|
||||
*
|
||||
* @param cmd Command string.
|
||||
*/
|
||||
virtual void ServerCommand(const char *cmd) =0;
|
||||
|
||||
/**
|
||||
* @brief Creates a ConVar pointer.
|
||||
*
|
||||
* @param name ConVar name.
|
||||
* @param defval Default value string.
|
||||
* @param flags ConVar flags.
|
||||
* @param help Help text.
|
||||
* @return ConVar pointer.
|
||||
*/
|
||||
virtual ConVar *CreateConVar(const char *name,
|
||||
const char *defval,
|
||||
const char *help,
|
||||
int flags) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the string value of a ConVar.
|
||||
*
|
||||
* @param convar ConVar pointer.
|
||||
* @return String value.
|
||||
*/
|
||||
virtual const char *GetConVarString(ConVar *convar) =0;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the game description.
|
||||
*
|
||||
* @return Game description.
|
||||
*/
|
||||
virtual const char *GetGameDescription() =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the ConCommandBase accessor.
|
||||
*
|
||||
* @return An IConCommandBaseAccessor pointer.
|
||||
*/
|
||||
virtual IConCommandBaseAccessor *GetConCommandBaseAccessor() =0;
|
||||
|
||||
/**
|
||||
* @brief Registers a ConCommandBase.
|
||||
*
|
||||
* @param pCommand ConCommandBase to register.
|
||||
* @return True if successful, false otherwise.
|
||||
*/
|
||||
virtual bool RegisterConCommandBase(ConCommandBase *pCommand) =0;
|
||||
|
||||
/**
|
||||
* @brief Unregisters a ConCommandBase.
|
||||
*
|
||||
* @param pCommand ConCommandBase to unlink.
|
||||
*/
|
||||
virtual void UnregisterConCommandBase(ConCommandBase *pCommand) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns whether a ConCommandBase is a command or not.
|
||||
*
|
||||
* @param pCommand ConCommandBase pointer.
|
||||
* @return True if a command, false otherwise.
|
||||
*/
|
||||
virtual bool IsConCommandBaseACommand(ConCommandBase *pCommand) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of user messages in the GameDLL.
|
||||
*
|
||||
* @return Number of user messages, or -1 if SourceMM has
|
||||
* failed to get user message list.
|
||||
*/
|
||||
virtual int GetUserMessageCount() =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the index of the specified user message.
|
||||
*
|
||||
* @param name User message name.
|
||||
* @param size Optional pointer to store size of user message.
|
||||
* @return Message index, or -1 on failure.
|
||||
*/
|
||||
virtual int FindUserMessage(const char *name, int *size=NULL) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the name of the specified user message.
|
||||
*
|
||||
* @param index User message index.
|
||||
* @param size Optional pointer to store size of user message.
|
||||
* @return Message name, or NULL on failure.
|
||||
*/
|
||||
virtual const char *GetUserMessage(int index, int *size=NULL) =0;
|
||||
};
|
||||
};
|
||||
|
||||
extern PluginId g_PLID;
|
||||
extern SourceHook::ISourceHook *g_SHPtr;
|
||||
extern SourceMM::IMetamodSourceProvider *provider;
|
||||
|
||||
#endif //_INCLUDE_METAMOD_SOURCE_SUPPORT_H_
|
||||
|
@ -1,18 +1,35 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* License: zlib/libpng
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "util.h"
|
||||
#include "oslink.h"
|
||||
#include "metamod_util.h"
|
||||
#include "metamod_oslink.h"
|
||||
|
||||
/**
|
||||
* @brief Utility functions
|
@ -1,11 +1,28 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ======================================================
|
||||
* Metamod:Source
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
|
||||
* All rights reserved.
|
||||
* ======================================================
|
||||
*
|
||||
* License: zlib/libpng
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in a
|
||||
* product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_UTIL_H
|
@ -1,21 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sourcemm", "sourcemm.vcproj", "{F7D47743-73B3-49B5-9D76-2333C5DFD565}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Debug = Debug
|
||||
Release = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Debug.ActiveCfg = Debug|Win32
|
||||
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Debug.Build.0 = Debug|Win32
|
||||
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Release.ActiveCfg = Release|Win32
|
||||
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Release.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,256 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="sourcemm"
|
||||
ProjectGUID="{F7D47743-73B3-49B5-9D76-2333C5DFD565}"
|
||||
RootNamespace="sourcemm"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier1.lib vstdlib.lib tier0.lib"
|
||||
OutputFile="$(OutDir)/server.dll"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcmt.lib;libcmtd.lib"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/sourcemm.pdb"
|
||||
SubSystem="2"
|
||||
EnableCOMDATFolding="1"
|
||||
ImportLibrary="$(OutDir)/sourcemm.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="TRUE"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS"
|
||||
StringPooling="TRUE"
|
||||
BufferSecurityCheck="FALSE"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
|
||||
OutputFile="$(OutDir)/server.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="libcd.lib;libcmt.lib;libcmtd.lib"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
ImportLibrary="$(OutDir)/sourcemm.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath="..\concommands.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CPlugin.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CSmmAPI.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\oslink.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sourcemm.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Detect64BitPortabilityProblems="FALSE"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\util.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vsp_listener.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath="..\concommands.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CPlugin.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CSmmAPI.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\oslink.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\resource.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sourcemm.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\util.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vsp_listener.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
<File
|
||||
RelativePath="..\version.rc">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Interfaces"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="..\IPluginManager.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ISmmAPI.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ISmmPlugin.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="SourceHook"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_list.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_stack.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_string.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_tinyhash.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_vector.h">
|
||||
</File>
|
||||
<Filter
|
||||
Name="Headers"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\FastDelegate.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_memfuncinfo.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sh_memory.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sourcehook.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sourcehook.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sourcehook\sourcehook_impl.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="HL2SDK"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="..\convar_smm.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -1,69 +0,0 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Implements OS-dependant functions from oslink.h
|
||||
* @file oslink.cpp
|
||||
*/
|
||||
|
||||
#include "oslink.h"
|
||||
#ifdef __linux
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
const char *dlerror()
|
||||
{
|
||||
static char buf[1024];
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &buf, 0, NULL);
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined __linux__
|
||||
int GetLastError()
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_acquire(void)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_release(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
|
||||
{
|
||||
#if defined WIN32 || defined _WIN32
|
||||
MEMORY_BASIC_INFORMATION mem;
|
||||
if (!VirtualQuery(pAddr, &mem, sizeof(mem)))
|
||||
return false;
|
||||
if (mem.AllocationBase == NULL)
|
||||
return false;
|
||||
HMODULE dll = (HMODULE)mem.AllocationBase;
|
||||
GetModuleFileName(dll, (LPTSTR)buffer, maxlength);
|
||||
#elif defined __linux__
|
||||
Dl_info info;
|
||||
if (!dladdr(pAddr, &info))
|
||||
return false;
|
||||
if (!info.dli_fbase || !info.dli_fname)
|
||||
return false;
|
||||
const char *dllpath = info.dli_fname;
|
||||
snprintf(buffer, maxlength, "%s", dllpath);
|
||||
#endif
|
||||
return true;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
The software is Copyright (C) 2004-2007, Metamod:Source Development Team.
|
||||
|
||||
Metamod:Source is distributed under the "zLib/libpng" license, which is reproduced
|
||||
below:
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
This software is provided "as-is", without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from
|
||||
the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software in
|
||||
a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not
|
||||
be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
The zLib/libpng license has been approved by the "Open Source Initiative"
|
||||
organization.
|
@ -1,67 +0,0 @@
|
||||
#(C)2004-2007 SourceMM Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
HL2SDK = ../../../hl2sdk
|
||||
SMM_ROOT = ../..
|
||||
SRCDS = ~/srcds
|
||||
|
||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||
|
||||
OPT_FLAGS = -O3 -funroll-loops -s -pipe
|
||||
GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden
|
||||
DEBUG_FLAGS = -g -ggdb3
|
||||
CPP = gcc-4.1
|
||||
BINARY = sample_mm_i486.so
|
||||
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
|
||||
OBJECTS = SamplePlugin.cpp cvars.cpp
|
||||
|
||||
LINK = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc
|
||||
|
||||
INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
|
||||
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_ROOT) -I$(SMM_ROOT)/sourcehook -I$(SMM_ROOT)/sourcemm
|
||||
|
||||
ifeq "$(DEBUG)" "true"
|
||||
BIN_DIR = Debug
|
||||
CFLAGS = $(DEBUG_FLAGS)
|
||||
else
|
||||
BIN_DIR = Release
|
||||
CFLAGS = $(OPT_FLAGS)
|
||||
endif
|
||||
|
||||
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
||||
|
||||
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
|
||||
|
||||
ifeq "$(GCC_VERSION)" "4"
|
||||
CFLAGS += $(GCC4_FLAGS)
|
||||
endif
|
||||
|
||||
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
|
||||
|
||||
$(BIN_DIR)/%.o: %.cpp
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
all:
|
||||
mkdir -p $(BIN_DIR)
|
||||
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
|
||||
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
|
||||
$(MAKE) sourcemm
|
||||
rm -rf $(BINARY)
|
||||
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
|
||||
|
||||
sourcemm: $(OBJ_LINUX)
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
|
||||
debug:
|
||||
$(MAKE) all DEBUG=true
|
||||
|
||||
default: all
|
||||
|
||||
clean:
|
||||
rm -rf Release/*.o
|
||||
rm -rf Release/$(BINARY)
|
||||
rm -rf Debug/*.o
|
||||
rm -rf Debug/$(BINARY)
|
@ -1,237 +0,0 @@
|
||||
/* ======== sample_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#include <oslink.h>
|
||||
#include "SamplePlugin.h"
|
||||
#include "cvars.h"
|
||||
|
||||
//Declare the hooks we will be using in this file. Hooking will not compile without these.
|
||||
//The macro naming scheme is SH_DECL_HOOKn[_void].
|
||||
//If you have 5 parameters, it would be HOOK5. If the function is void, add _void.
|
||||
//It stands for "SourceHook, Declare Hook".
|
||||
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, char const *, char const *, char const *, char const *, bool, bool);
|
||||
SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
|
||||
SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, 0, bool);
|
||||
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, 0);
|
||||
SH_DECL_HOOK2_void(IServerGameClients, ClientActive, SH_NOATTRIB, 0, edict_t *, bool);
|
||||
SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *);
|
||||
SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, char const *);
|
||||
SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, 0, int);
|
||||
SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
|
||||
SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char*, const char *, char *, int);
|
||||
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
|
||||
SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool);
|
||||
|
||||
SamplePlugin g_SamplePlugin;
|
||||
MyListener g_Listener;
|
||||
|
||||
PLUGIN_EXPOSE(SamplePlugin, g_SamplePlugin);
|
||||
|
||||
bool SamplePlugin::LevelInit(const char *pMapName, const char *pMapEntities, const char *pOldLevel, const char *pLandmarkName, bool loadGame, bool background)
|
||||
{
|
||||
META_LOG(g_PLAPI, "LevelInit() called: pMapName=%s", pMapName);
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
void SamplePlugin::OnLevelShutdown()
|
||||
{
|
||||
META_LOG(g_PLAPI, "OnLevelShutdown() called from listener");
|
||||
}
|
||||
|
||||
void SamplePlugin::ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ServerActivate() called: edictCount=%d, clientMax=%d", edictCount, clientMax);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::GameFrame(bool simulating)
|
||||
{
|
||||
//don't log this, it just pumps stuff to the screen ;]
|
||||
//META_LOG(g_PLAPI, "GameFrame() called: simulating=%d", simulating);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::LevelShutdown( void )
|
||||
{
|
||||
META_LOG(g_PLAPI, "LevelShutdown() called");
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::ClientActive(edict_t *pEntity, bool bLoadGame)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientActive called: pEntity=%d", pEntity ? m_Engine->IndexOfEdict(pEntity) : 0);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::ClientDisconnect(edict_t *pEntity)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientDisconnect called: pEntity=%d", pEntity ? m_Engine->IndexOfEdict(pEntity) : 0);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::ClientPutInServer(edict_t *pEntity, char const *playername)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientPutInServer called: pEntity=%d, playername=%s", pEntity ? m_Engine->IndexOfEdict(pEntity) : 0, playername);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::SetCommandClient(int index)
|
||||
{
|
||||
META_LOG(g_PLAPI, "SetCommandClient() called: index=%d", index);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::ClientSettingsChanged(edict_t *pEdict)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientSettingsChanged called: pEdict=%d", pEdict ? m_Engine->IndexOfEdict(pEdict) : 0);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
bool SamplePlugin::ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientConnect called: pEntity=%d, pszName=%s, pszAddress=%s", pEntity ? m_Engine->IndexOfEdict(pEntity) : 0, pszName, pszAddress);
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
void SamplePlugin::ClientCommand(edict_t *pEntity)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientCommand called: pEntity=%d (commandString=%s)", pEntity ? m_Engine->IndexOfEdict(pEntity) : 0, m_Engine->Cmd_Args() ? m_Engine->Cmd_Args() : "");
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
bool FireEvent_Handler(IGameEvent *event, bool bDontBroadcast)
|
||||
{
|
||||
if (!event || !event->GetName())
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
|
||||
/**
|
||||
* Note that this will only fire on game events that are already being listened to.
|
||||
* For events that are not firing (such as item_pickup), you must actually
|
||||
* register an event listener in the event manager. This hook is provided
|
||||
* as an example for non-eiface hooks only.
|
||||
*/
|
||||
|
||||
const char *name = event->GetName();
|
||||
|
||||
META_LOG(g_PLAPI, "FireGameEvent called: name=%s", name);
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
bool SamplePlugin::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
|
||||
{
|
||||
PLUGIN_SAVEVARS();
|
||||
|
||||
GET_V_IFACE_ANY(serverFactory, m_ServerDll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
|
||||
GET_V_IFACE_CURRENT(engineFactory, m_Engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
|
||||
GET_V_IFACE_ANY(serverFactory, m_ServerClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS);
|
||||
GET_V_IFACE_CURRENT(engineFactory, m_GameEventManager, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2);
|
||||
|
||||
META_LOG(g_PLAPI, "Starting plugin.\n");
|
||||
|
||||
ismm->AddListener(this, &g_Listener);
|
||||
|
||||
//Init our cvars/concmds
|
||||
ConCommandBaseMgr::OneTimeInit(&g_Accessor);
|
||||
|
||||
//We're hooking the following things as POST, in order to seem like Server Plugins.
|
||||
//However, I don't actually know if Valve has done server plugins as POST or not.
|
||||
//Change the last parameter to 'false' in order to change this to PRE.
|
||||
//SH_ADD_HOOK_MEMFUNC means "SourceHook, Add Hook, Member Function".
|
||||
|
||||
//Hook LevelInit to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, m_ServerDll, &g_SamplePlugin, &SamplePlugin::LevelInit, true);
|
||||
//Hook ServerActivate to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, m_ServerDll, &g_SamplePlugin, &SamplePlugin::ServerActivate, true);
|
||||
//Hook GameFrame to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, m_ServerDll, &g_SamplePlugin, &SamplePlugin::GameFrame, true);
|
||||
//Hook LevelShutdown to our function -- this makes more sense as pre I guess
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, m_ServerDll, &g_SamplePlugin, &SamplePlugin::LevelShutdown, false);
|
||||
//Hook ClientActivate to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientActive, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientActive, true);
|
||||
//Hook ClientDisconnect to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientDisconnect, true);
|
||||
//Hook ClientPutInServer to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientPutInServer, true);
|
||||
//Hook SetCommandClient to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, m_ServerClients, &g_SamplePlugin, &SamplePlugin::SetCommandClient, true);
|
||||
//Hook ClientSettingsChanged to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientSettingsChanged, true);
|
||||
|
||||
//The following functions are pre handled, because that's how they are in IServerPluginCallbacks
|
||||
|
||||
//Hook ClientConnect to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientConnect, false);
|
||||
//Hook ClientCommand to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientCommand, false);
|
||||
|
||||
//This hook is a static hook, no member function
|
||||
SH_ADD_HOOK_STATICFUNC(IGameEventManager2, FireEvent, m_GameEventManager, FireEvent_Handler, false);
|
||||
|
||||
//Get the call class for IVServerEngine so we can safely call functions without
|
||||
// invoking their hooks (when needed).
|
||||
m_Engine_CC = SH_GET_CALLCLASS(m_Engine);
|
||||
|
||||
SH_CALL(m_Engine_CC, &IVEngineServer::LogPrint)("All hooks started!\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SamplePlugin::Unload(char *error, size_t maxlen)
|
||||
{
|
||||
//IT IS CRUCIAL THAT YOU REMOVE CVARS.
|
||||
//As of Metamod:Source 1.00-RC2, it will automatically remove them for you.
|
||||
//But this is only if you've registered them correctly!
|
||||
|
||||
//Make sure we remove any hooks we did... this may not be necessary since
|
||||
//SourceHook is capable of unloading plugins' hooks itself, but just to be safe.
|
||||
|
||||
SH_REMOVE_HOOK_STATICFUNC(IGameEventManager2, FireEvent, m_GameEventManager, FireEvent_Handler, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, m_ServerDll, &g_SamplePlugin, &SamplePlugin::LevelInit, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, m_ServerDll, &g_SamplePlugin, &SamplePlugin::ServerActivate, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, m_ServerDll, &g_SamplePlugin, &SamplePlugin::GameFrame, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, m_ServerDll, &g_SamplePlugin, &SamplePlugin::LevelShutdown, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientActive, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientActive, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientDisconnect, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientPutInServer, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, m_ServerClients, &g_SamplePlugin, &SamplePlugin::SetCommandClient, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientSettingsChanged, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientConnect, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientConnect, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, m_ServerClients, &g_SamplePlugin, &SamplePlugin::ClientCommand, false);
|
||||
|
||||
//this, sourcehook does not keep track of. we must do this.
|
||||
SH_RELEASE_CALLCLASS(m_Engine_CC);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SamplePlugin::AllPluginsLoaded()
|
||||
{
|
||||
//we don't really need this for anything other than interplugin communication
|
||||
//and that's not used in this plugin.
|
||||
//If we really wanted, we could override the factories so other plugins can request
|
||||
// interfaces we make. In this callback, the plugin could be assured that either
|
||||
// the interfaces it requires were either loaded in another plugin or not.
|
||||
}
|
||||
|
||||
void *MyListener::OnMetamodQuery(const char *iface, int *ret)
|
||||
{
|
||||
if (strcmp(iface, "SamplePlugin")==0)
|
||||
{
|
||||
if (ret)
|
||||
*ret = IFACE_OK;
|
||||
return static_cast<void *>(&g_SamplePlugin);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = IFACE_FAILED;
|
||||
|
||||
return NULL;
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
/* ======== sample_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SAMPLEPLUGIN_H
|
||||
#define _INCLUDE_SAMPLEPLUGIN_H
|
||||
|
||||
#include <ISmmPlugin.h>
|
||||
#include <sourcehook/sourcehook.h>
|
||||
#include <igameevents.h>
|
||||
|
||||
#define SAMPLE_VERSION "1.10"
|
||||
|
||||
class SamplePlugin : public ISmmPlugin, public IMetamodListener
|
||||
{
|
||||
public:
|
||||
bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late);
|
||||
bool Unload(char *error, size_t maxlen);
|
||||
void AllPluginsLoaded();
|
||||
bool Pause(char *error, size_t maxlen)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool Unpause(char *error, size_t maxlen)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
int GetApiVersion() { return PLAPI_VERSION; }
|
||||
public:
|
||||
const char *GetAuthor()
|
||||
{
|
||||
return "BAILOPAN";
|
||||
}
|
||||
const char *GetName()
|
||||
{
|
||||
return "Sample Plugin";
|
||||
}
|
||||
const char *GetDescription()
|
||||
{
|
||||
return "Sample plugin that hooks basic things";
|
||||
}
|
||||
const char *GetURL()
|
||||
{
|
||||
return "http://www.sourcemm.net/";
|
||||
}
|
||||
const char *GetLicense()
|
||||
{
|
||||
return "zlib/libpng";
|
||||
}
|
||||
const char *GetVersion()
|
||||
{
|
||||
return SAMPLE_VERSION;
|
||||
}
|
||||
const char *GetDate()
|
||||
{
|
||||
return __DATE__;
|
||||
}
|
||||
const char *GetLogTag()
|
||||
{
|
||||
return "SAMPLE";
|
||||
}
|
||||
public:
|
||||
//These functions are from IServerPluginCallbacks
|
||||
//Note, the parameters might be a little different to match the actual calls!
|
||||
|
||||
//Called on LevelInit. Server plugins only have pMapName
|
||||
bool LevelInit(const char *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
|
||||
|
||||
//Called on ServerActivate. Same definition as server plugins
|
||||
void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
|
||||
//Called on a game tick. Same definition as server plugins
|
||||
void GameFrame(bool simulating);
|
||||
|
||||
//Called on level shutdown. Same definition as server plugins
|
||||
void LevelShutdown(void);
|
||||
|
||||
//Client is activate (whatever that means). We get an extra parameter...
|
||||
// "If bLoadGame is true, don't spawn the player because its state is already setup."
|
||||
void ClientActive(edict_t *pEntity, bool bLoadGame);
|
||||
|
||||
//Client disconnects - same as server plugins
|
||||
void ClientDisconnect(edict_t *pEntity);
|
||||
|
||||
//Client is put in server - same as server plugins
|
||||
void ClientPutInServer(edict_t *pEntity, char const *playername);
|
||||
|
||||
//Sets the client index - same as server plugins
|
||||
void SetCommandClient(int index);
|
||||
|
||||
//Called on client settings changed (duh) - same as server plugins
|
||||
void ClientSettingsChanged(edict_t *pEdict);
|
||||
|
||||
//Called on client connect. Unlike server plugins, we return whether the
|
||||
// connection is allowed rather than set it through a pointer in the first parameter.
|
||||
// You can still supercede the GameDLL through RETURN_META_VALUE(MRES_SUPERCEDE, true/false)
|
||||
bool ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||
|
||||
//Called when a client uses a command. Unlike server plugins, it's void.
|
||||
// You can still supercede the gamedll through RETURN_META(MRES_SUPERCEDE).
|
||||
void ClientCommand(edict_t *pEntity);
|
||||
|
||||
//From IMetamodListener
|
||||
virtual void OnLevelShutdown();
|
||||
|
||||
private:
|
||||
IGameEventManager2 *m_GameEventManager;
|
||||
IVEngineServer *m_Engine;
|
||||
IServerGameDLL *m_ServerDll;
|
||||
IServerGameClients *m_ServerClients;
|
||||
SourceHook::CallClass<IVEngineServer> *m_Engine_CC;
|
||||
};
|
||||
|
||||
class MyListener : public IMetamodListener
|
||||
{
|
||||
public:
|
||||
virtual void *OnMetamodQuery(const char *iface, int *ret);
|
||||
};
|
||||
|
||||
extern SamplePlugin g_SamplePlugin;
|
||||
PLUGIN_GLOBALVARS();
|
||||
|
||||
bool FireEvent_Handler(IGameEvent *event, bool bDontBroadcast);
|
||||
|
||||
#endif //_INCLUDE_SAMPLEPLUGIN_H
|
@ -1,27 +0,0 @@
|
||||
/* ======== sample_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#include "SamplePlugin.h"
|
||||
#include "cvars.h"
|
||||
|
||||
SampleAccessor g_Accessor;
|
||||
|
||||
ConVar g_MyConVar("sample_version", SAMPLE_VERSION, FCVAR_SPONLY, "Sample Plugin version");
|
||||
|
||||
bool SampleAccessor::RegisterConCommandBase(ConCommandBase *pVar)
|
||||
{
|
||||
//this will work on any type of concmd!
|
||||
return META_REGCVAR(pVar);
|
||||
}
|
||||
|
||||
CON_COMMAND(sample_cmd, "Sample Plugin command")
|
||||
{
|
||||
META_LOG(g_PLAPI, "This sentence is in Spanish when you're not looking.");
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
/* ======== sample_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_CVARS_H
|
||||
#define _INCLUDE_CVARS_H
|
||||
|
||||
#include <convar.h>
|
||||
|
||||
class SampleAccessor : public IConCommandBaseAccessor
|
||||
{
|
||||
public:
|
||||
virtual bool RegisterConCommandBase(ConCommandBase *pVar);
|
||||
};
|
||||
|
||||
extern SampleAccessor g_Accessor;
|
||||
|
||||
#endif //_INCLUDE_CVARS_H
|
@ -1,21 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_mm", "sample_mm.vcproj", "{FAFF34FB-FE14-47B5-81BD-70D237392FB2}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Debug = Debug
|
||||
Release = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Debug.ActiveCfg = Debug|Win32
|
||||
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Debug.Build.0 = Debug|Win32
|
||||
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Release.ActiveCfg = Release|Win32
|
||||
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Release.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,149 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="sample_mm"
|
||||
ProjectGUID="{FAFF34FB-FE14-47B5-81BD-70D237392FB2}"
|
||||
RootNamespace="sample_mm"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
|
||||
OutputFile="$(OutDir)/sample_mm.dll"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcmt.lib;libcmtd.lib"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/sample_mm.pdb"
|
||||
SubSystem="2"
|
||||
ImportLibrary="$(OutDir)/sample_mm.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
|
||||
RuntimeLibrary="4"
|
||||
UsePrecompiledHeader="0"
|
||||
ExpandAttributedSource="TRUE"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
|
||||
OutputFile="$(OutDir)/sample_mm.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="libcd.lib;libcmt.lib;libcmtd.lib"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="1"
|
||||
ImportLibrary="$(OutDir)/sample_mm.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath="..\cvars.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\SamplePlugin.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath="..\cvars.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\SamplePlugin.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -1,20 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_mm", "sample_mm.vcproj", "{FAFF34FB-FE14-47B5-81BD-70D237392FB2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,710 +0,0 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* Contributor(s): Scott "Damaged Soul" Ehlert
|
||||
* : Pavol "PM OnoTo" Marko
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include <tier0/icommandline.h>
|
||||
#include "sourcemm.h"
|
||||
#include "concommands.h"
|
||||
#include "CSmmAPI.h"
|
||||
#include "CPlugin.h"
|
||||
#include "util.h"
|
||||
#include "vsp_listener.h"
|
||||
|
||||
using namespace SourceMM;
|
||||
|
||||
/**
|
||||
* @brief Implementation of main SourceMM GameDLL functionality
|
||||
* @file sourcemm.cpp
|
||||
*/
|
||||
|
||||
#undef CommandLine
|
||||
DLL_IMPORT ICommandLine *CommandLine();
|
||||
|
||||
SH_DECL_HOOK4(IServerGameDLL, DLLInit, SH_NOATTRIB, false, bool, CreateInterfaceFn, CreateInterfaceFn, CreateInterfaceFn, CGlobalVars *);
|
||||
SH_DECL_HOOK0_void(IServerGameDLL, DLLShutdown, SH_NOATTRIB, false);
|
||||
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
|
||||
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
|
||||
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
|
||||
SH_DECL_HOOK0(IServerGameDLL, GameInit, SH_NOATTRIB, false, bool);
|
||||
|
||||
bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals);
|
||||
bool DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals);
|
||||
void DLLShutdown_handler();
|
||||
void LevelShutdown_handler();
|
||||
bool LevelInit_handler(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
|
||||
bool GameInit_handler();
|
||||
|
||||
GameDllInfo g_GameDll = {false, NULL, NULL, NULL, NULL};
|
||||
EngineInfo g_Engine;
|
||||
SourceHook::CSourceHookImpl g_SourceHook;
|
||||
SourceHook::ISourceHook *g_SHPtr = &g_SourceHook;
|
||||
SourceHook::String g_ModPath;
|
||||
SourceHook::String g_BinPath;
|
||||
SourceHook::String g_SmmPath;
|
||||
PluginId g_PLID = Pl_Console; /* Technically, SourceMM is the "Console" plugin... :p */
|
||||
bool bInFirstLevel = true;
|
||||
bool gParsedGameInfo = false;
|
||||
bool bGameInit = false;
|
||||
SourceHook::List<GameDllInfo *> gamedll_list;
|
||||
int g_GameDllVersion = 0;
|
||||
int g_GameClientsVersion = 0;
|
||||
int g_VspVersion = 0;
|
||||
const char VSPIFACE[] = "ISERVERPLUGINCALLBACKS";
|
||||
const char GAMEINFO_PATH[] = "|gameinfo_path|";
|
||||
|
||||
void ClearGamedllList();
|
||||
|
||||
/* Helper Macro */
|
||||
#define IFACE_MACRO(orig,nam) \
|
||||
CPluginManager::CPlugin *pl; \
|
||||
SourceHook::List<IMetamodListener *>::iterator event; \
|
||||
IMetamodListener *api; \
|
||||
int mret = 0; \
|
||||
void *val = NULL; \
|
||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
||||
pl = (*iter); \
|
||||
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
|
||||
api = (*event); \
|
||||
mret = IFACE_FAILED; \
|
||||
if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \
|
||||
if (ret) *ret = mret; \
|
||||
return val; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
return (orig)(iface, ret);
|
||||
|
||||
#define ITER_EVENT(evn, args) \
|
||||
CPluginManager::CPlugin *pl; \
|
||||
SourceHook::List<IMetamodListener *>::iterator event; \
|
||||
IMetamodListener *api; \
|
||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
||||
pl = (*iter); \
|
||||
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
|
||||
api = (*event); \
|
||||
api->evn args; \
|
||||
} \
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
// Main code for HL2 Interaction //
|
||||
///////////////////////////////////
|
||||
|
||||
/* Initialize everything here */
|
||||
void InitMainStates()
|
||||
{
|
||||
char full_path[PATH_SIZE] = {0};
|
||||
GetFileOfAddress((void *)g_GameDll.factory, full_path, sizeof(full_path));
|
||||
g_BinPath.assign(full_path);
|
||||
|
||||
/* Like Metamod, reload plugins at the end of the map.
|
||||
* This is so plugins can hook everything on load, BUT, new plugins will be reloaded
|
||||
* if the server is shut down (silly, but rare case).
|
||||
*/
|
||||
bInFirstLevel = true;
|
||||
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLInit, g_GameDll.pGameDLL, DLLInit, false);
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLInit, g_GameDll.pGameDLL, DLLInit_Post, true);
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLShutdown, g_GameDll.pGameDLL, DLLShutdown_handler, false);
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelShutdown, g_GameDll.pGameDLL, LevelShutdown_handler, true);
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelInit, g_GameDll.pGameDLL, LevelInit_handler, true);
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, GameInit, g_GameDll.pGameDLL, GameInit_handler, false);
|
||||
}
|
||||
|
||||
bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
|
||||
{
|
||||
g_Engine.engineFactory = engineFactory;
|
||||
g_Engine.fileSystemFactory = filesystemFactory;
|
||||
g_Engine.physicsFactory = physicsFactory;
|
||||
g_Engine.pGlobals = pGlobals;
|
||||
|
||||
g_Engine.engine = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL));
|
||||
if (!g_Engine.engine)
|
||||
{
|
||||
Error("Could not find IVEngineServer! Metamod cannot load.");
|
||||
return false;
|
||||
}
|
||||
g_Engine.icvar = (ICvar *)((engineFactory)(VENGINE_CVAR_INTERFACE_VERSION , NULL));
|
||||
if (!g_Engine.icvar)
|
||||
{
|
||||
Error("Could not find ICvar! Metamod cannot load.");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_Engine.loaded = true;
|
||||
|
||||
/* Initialize our console hooks */
|
||||
ConCommandBaseMgr::OneTimeInit(static_cast<IConCommandBaseAccessor *>(&g_SMConVarAccessor));
|
||||
|
||||
if (g_GameDll.pGameClients)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, g_GameDll.pGameClients, ClientCommand_handler, false);
|
||||
} else {
|
||||
/* If IServerGameClients isn't found, this really isn't a fatal error so... */
|
||||
LogMessage("[META] Warning: Could not find IServerGameClients!");
|
||||
LogMessage("[META] Warning: The 'meta' command will not be available to clients.");
|
||||
}
|
||||
|
||||
if (!g_SmmAPI.CacheCmds())
|
||||
{
|
||||
LogMessage("[META] Warning: Failed to initialize Con_Printf. Defaulting to Msg().");
|
||||
LogMessage("[META] Warning: Console messages will not be redirected to rcon console.");
|
||||
}
|
||||
|
||||
if (!g_SmmAPI.CacheUserMessages())
|
||||
{
|
||||
/* Don't know of a mod that has stripped out user messages completely,
|
||||
* but perhaps should do something different here?
|
||||
*/
|
||||
LogMessage("[META] Warning: Failed to get list of user messages.");
|
||||
LogMessage("[META] Warning: The 'meta game' command will not display user messages.");
|
||||
}
|
||||
|
||||
const char *pluginFile = g_Engine.icvar->GetCommandLineValue("mm_pluginsfile");
|
||||
if (!pluginFile)
|
||||
{
|
||||
pluginFile = GetPluginsFile();
|
||||
}
|
||||
|
||||
char full_path[260];
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), pluginFile);
|
||||
|
||||
LoadPluginsFromFile(full_path);
|
||||
|
||||
bInFirstLevel = true;
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
bool GameInit_handler()
|
||||
{
|
||||
if (bGameInit)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (g_SmmAPI.VSPEnabled())
|
||||
{
|
||||
g_SmmAPI.LoadAsVSP();
|
||||
}
|
||||
|
||||
bGameInit = true;
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
bool DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
|
||||
{
|
||||
g_PluginMngr.SetAllLoaded();
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
/* This is where the magic happens */
|
||||
SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
{
|
||||
/* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */
|
||||
if (strcmp(iface, PLAPI_NAME) == 0)
|
||||
{
|
||||
Warning("Do not try loading Metamod:Source as a SourceMM or Valve server plugin.\n");
|
||||
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_FAILED;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strncmp(iface, VSPIFACE, 22) == 0)
|
||||
{
|
||||
g_VspVersion = atoi(&(iface[22]));
|
||||
|
||||
if (g_VspVersion <= MAX_VSP_VERSION)
|
||||
{
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_OK;
|
||||
}
|
||||
return &g_VspListener;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gParsedGameInfo)
|
||||
{
|
||||
gParsedGameInfo = true;
|
||||
const char *gameDir = NULL;
|
||||
char gamePath[PATH_SIZE];
|
||||
char smmPath[PATH_SIZE];
|
||||
|
||||
/* Get path to SourceMM DLL */
|
||||
if (!GetFileOfAddress((void *)CreateInterface, smmPath, sizeof(smmPath)))
|
||||
{
|
||||
Error("GetFileOfAddress() failed! Metamod cannot load.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_SmmPath.assign(smmPath);
|
||||
|
||||
/* Get value of -game from command line, defaulting to hl2 as engine seems to do */
|
||||
gameDir = CommandLine()->ParmValue("-game", "hl2");
|
||||
|
||||
/* Get absolute path */
|
||||
abspath(gamePath, gameDir);
|
||||
g_ModPath.assign(gamePath);
|
||||
|
||||
char tempPath[PATH_SIZE];
|
||||
|
||||
/* Path to gameinfo.txt */
|
||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s", g_ModPath.c_str(), "gameinfo.txt");
|
||||
|
||||
FILE *fp = fopen(tempPath, "rt");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
Error("Unable to open gameinfo.txt! Metamod cannot load.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char buffer[255];
|
||||
char key[128], val[128];
|
||||
bool search = false;
|
||||
bool gamebin = false;
|
||||
char *ptr;
|
||||
const char *lptr;
|
||||
char curPath[PATH_SIZE];
|
||||
|
||||
getcwd(curPath, PATH_SIZE);
|
||||
|
||||
while (!feof(fp))
|
||||
{
|
||||
buffer[0] = '\0';
|
||||
fgets(buffer, sizeof(buffer), fp);
|
||||
UTIL_TrimComments(buffer);
|
||||
UTIL_TrimLeft(buffer);
|
||||
UTIL_TrimRight(buffer);
|
||||
if (stricmp(buffer, "SearchPaths") == 0)
|
||||
search = true;
|
||||
if (!search)
|
||||
continue;
|
||||
UTIL_KeySplit(buffer, key, sizeof(key) - 1, val, sizeof(val) - 1);
|
||||
if (stricmp(key, "Game") == 0 || stricmp(key, "GameBin") == 0)
|
||||
{
|
||||
if (stricmp(key, "Game") == 0)
|
||||
gamebin = false;
|
||||
else
|
||||
gamebin = true;
|
||||
|
||||
if (strncmp(val, GAMEINFO_PATH, sizeof(GAMEINFO_PATH) - 1) == 0)
|
||||
{
|
||||
ptr = &(val[sizeof(GAMEINFO_PATH) - 1]);
|
||||
if (ptr[0] == '.')
|
||||
ptr++;
|
||||
lptr = g_ModPath.c_str();
|
||||
} else {
|
||||
ptr = val;
|
||||
lptr = curPath;
|
||||
}
|
||||
|
||||
size_t ptr_len = strlen(ptr);
|
||||
if (ptr[ptr_len] == '/' || ptr[ptr_len] == '\\')
|
||||
ptr[--ptr_len] = '\0';
|
||||
|
||||
/* No need to append "bin" if key is GameBin */
|
||||
if (gamebin)
|
||||
{
|
||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s", lptr, ptr, SERVER_DLL);
|
||||
} else if (!ptr[0]) {
|
||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s", lptr, "bin", SERVER_DLL);
|
||||
} else {
|
||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s/%s", lptr, ptr, "bin", SERVER_DLL);
|
||||
}
|
||||
|
||||
/* If not path to SourceMM... */
|
||||
if (!UTIL_PathCmp(smmPath, tempPath))
|
||||
{
|
||||
FILE *fp = fopen(tempPath, "rb");
|
||||
if (!fp)
|
||||
continue;
|
||||
//:TODO: Optimize this a bit!
|
||||
SourceHook::List<GameDllInfo *>::iterator iter;
|
||||
GameDllInfo *pCheck;
|
||||
bool found = false;
|
||||
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
|
||||
{
|
||||
pCheck = (*iter);
|
||||
if (GetFileOfAddress((void *)pCheck->factory, buffer, sizeof(buffer)))
|
||||
{
|
||||
if (UTIL_PathCmp(tempPath, buffer))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
continue;
|
||||
fclose(fp);
|
||||
HINSTANCE gamedll = dlmount(tempPath);
|
||||
if (gamedll == NULL)
|
||||
continue;
|
||||
CreateInterfaceFn fn = (CreateInterfaceFn)dlsym(gamedll, "CreateInterface");
|
||||
if (fn == NULL)
|
||||
{
|
||||
dlclose(gamedll);
|
||||
continue;
|
||||
}
|
||||
GameDllInfo *pInfo = new GameDllInfo;
|
||||
pInfo->factory = fn;
|
||||
pInfo->lib = gamedll;
|
||||
pInfo->loaded = true;
|
||||
pInfo->pGameDLL = NULL;
|
||||
gamedll_list.push_back(pInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (!g_GameDll.loaded)
|
||||
{
|
||||
const char *str = "ServerGameDLL";
|
||||
size_t len = strlen(str);
|
||||
|
||||
if (strncmp(iface, str, len) == 0)
|
||||
{
|
||||
/* This is the interface we want! Right now we support versions 3 through 8 */
|
||||
g_GameDllVersion = atoi(&(iface[len]));
|
||||
int sizeTooBig = 0; //rename this to sizeWrong in the future!
|
||||
if (g_GameDllVersion < MIN_GAMEDLL_VERSION || g_GameDllVersion > MAX_GAMEDLL_VERSION)
|
||||
{
|
||||
/* Maybe this will get used in the future */
|
||||
sizeTooBig = g_GameDllVersion;
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_FAILED;
|
||||
}
|
||||
}
|
||||
SourceHook::List<GameDllInfo *>::iterator iter;
|
||||
GameDllInfo *pInfo = NULL;
|
||||
void *ptr;
|
||||
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
ptr = (pInfo->factory)(iface, ret);
|
||||
if (ptr)
|
||||
{
|
||||
/* This is our GameDLL. Unload the others. */
|
||||
gamedll_list.erase(iter);
|
||||
ClearGamedllList();
|
||||
pInfo->pGameDLL = static_cast<IServerGameDLL *>(ptr);
|
||||
g_GameDll = *pInfo;
|
||||
delete pInfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (g_GameDll.loaded)
|
||||
{
|
||||
if (sizeTooBig)
|
||||
{
|
||||
Error("This mod version requires a SourceMM update (ServerGameDLL%03d)!\n", sizeTooBig);
|
||||
if (ret)
|
||||
{
|
||||
*ret = IFACE_FAILED;
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
InitMainStates();
|
||||
}
|
||||
} else {
|
||||
sizeTooBig = 0;
|
||||
if (ret)
|
||||
*ret = IFACE_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* wtf do we do... */
|
||||
/* :TODO: .. something a bit more intelligent? */
|
||||
Error("Engine requested unknown interface before GameDLL was known!\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* We use this interface for responding to the meta client command */
|
||||
if (strncmp(iface, "ServerGameClients", 17) == 0)
|
||||
{
|
||||
void *ptr = (g_GameDll.factory)(iface, ret);
|
||||
g_GameDll.pGameClients = static_cast<IServerGameClients *>(ptr);
|
||||
g_GameClientsVersion = atoi(&iface[17]);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* If we got here, there's definitely a GameDLL */
|
||||
IFACE_MACRO(g_GameDll.factory, GameDLL);
|
||||
}
|
||||
|
||||
void ClearGamedllList()
|
||||
{
|
||||
SourceHook::List<GameDllInfo *>::iterator iter;
|
||||
|
||||
GameDllInfo *pInfo;
|
||||
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
dlclose(pInfo->lib);
|
||||
delete pInfo;
|
||||
}
|
||||
|
||||
gamedll_list.clear();
|
||||
}
|
||||
|
||||
void DLLShutdown_handler()
|
||||
{
|
||||
/* Unload plugins */
|
||||
g_PluginMngr.UnloadAll();
|
||||
|
||||
/* Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly */
|
||||
g_SMConVarAccessor.MarkCommandsAsGameDLL();
|
||||
g_SMConVarAccessor.UnregisterGameDLLCommands();
|
||||
|
||||
SH_CALL(g_GameDll.pGameDLL, &IServerGameDLL::DLLShutdown)();
|
||||
|
||||
g_SourceHook.CompleteShutdown();
|
||||
|
||||
if (g_GameDll.lib && g_GameDll.loaded)
|
||||
dlclose(g_GameDll.lib);
|
||||
memset(&g_GameDll, 0, sizeof(GameDllInfo));
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
int LoadPluginsFromFile(const char *_file)
|
||||
{
|
||||
FILE *fp;
|
||||
int total = 0, skipped=0;
|
||||
PluginId id;
|
||||
bool already;
|
||||
|
||||
fp = fopen(_file, "rt");
|
||||
if (!fp)
|
||||
{
|
||||
LogMessage("[META] Could not open plugins file %s\n", _file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buffer[255], error[255], full_path[255];
|
||||
const char *ptr, *ext, *file;
|
||||
size_t length;
|
||||
while (!feof(fp))
|
||||
{
|
||||
buffer[0] = '\0';
|
||||
fgets(buffer, sizeof(buffer), fp);
|
||||
length = strlen(buffer);
|
||||
if (!length)
|
||||
continue;
|
||||
if (buffer[length-1] == '\n')
|
||||
buffer[--length] = '\0';
|
||||
|
||||
UTIL_TrimLeft(buffer);
|
||||
UTIL_TrimRight(buffer);
|
||||
|
||||
if (buffer[0] == '\0' || buffer[0] == ';' || strncmp(buffer, "//", 2) == 0)
|
||||
continue;
|
||||
file = buffer;
|
||||
if (buffer[0] == '"')
|
||||
{
|
||||
char *cptr = buffer;
|
||||
file = ++cptr;
|
||||
|
||||
while (*cptr)
|
||||
{
|
||||
if (*cptr == '"')
|
||||
{
|
||||
*cptr = '\0';
|
||||
break;
|
||||
}
|
||||
cptr++;
|
||||
}
|
||||
} else {
|
||||
char *cptr = buffer;
|
||||
while (*cptr)
|
||||
{
|
||||
if (isspace(*cptr))
|
||||
{
|
||||
char *optr = cptr;
|
||||
while (*cptr && isspace(*cptr))
|
||||
cptr++;
|
||||
*optr = '\0';
|
||||
UTIL_TrimRight(cptr);
|
||||
if (*cptr && isalpha(*cptr))
|
||||
{
|
||||
g_PluginMngr.SetAlias(buffer, cptr);
|
||||
file = cptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cptr++;
|
||||
}
|
||||
}
|
||||
if (!file[0])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* First find if it's an absolute path or not... */
|
||||
if (file[0] == '/' || strncmp(&(file[1]), ":\\", 2) == 0)
|
||||
{
|
||||
/* If we're in an absolute path, ignore our normal heuristics */
|
||||
id = g_PluginMngr.Load(file, Pl_File, already, error, sizeof(error));
|
||||
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
|
||||
{
|
||||
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
|
||||
} else {
|
||||
if (already)
|
||||
skipped++;
|
||||
else
|
||||
total++;
|
||||
}
|
||||
} else {
|
||||
/* Attempt to find a file extension */
|
||||
ptr = UTIL_GetExtension(file);
|
||||
/* Add an extension if there's none there */
|
||||
if (!ptr)
|
||||
{
|
||||
#if defined WIN32 || defined _WIN32
|
||||
ext = ".dll";
|
||||
#else
|
||||
ext = "_i486.so";
|
||||
#endif
|
||||
} else {
|
||||
ext = "";
|
||||
}
|
||||
/* Format the new path */
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext);
|
||||
id = g_PluginMngr.Load(full_path, Pl_File, already, error, sizeof(error));
|
||||
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
|
||||
{
|
||||
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
|
||||
} else {
|
||||
if (already)
|
||||
skipped++;
|
||||
else
|
||||
total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (skipped)
|
||||
{
|
||||
LogMessage("[META] Loaded %d plugins from file (%d already loaded)", total, skipped);
|
||||
} else {
|
||||
LogMessage("[META] Loaded %d plugins from file.", total);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/* Wrapper function. This is called when the GameDLL thinks it's using
|
||||
* the engine's real engineFactory.
|
||||
*/
|
||||
void *EngineFactory(const char *iface, int *ret)
|
||||
{
|
||||
IFACE_MACRO(g_Engine.engineFactory, Engine);
|
||||
}
|
||||
|
||||
/* Wrapper function. This is called when the GameDLL thinks it's using
|
||||
* the engine's real physicsFactory.
|
||||
*/
|
||||
void *PhysicsFactory(const char *iface, int *ret)
|
||||
{
|
||||
IFACE_MACRO(g_Engine.physicsFactory, Physics);
|
||||
}
|
||||
|
||||
/* Wrapper function. This is called when the GameDLL thinks it's using
|
||||
* the engine's real fileSystemFactory.
|
||||
*/
|
||||
void *FileSystemFactory(const char *iface, int *ret)
|
||||
{
|
||||
IFACE_MACRO(g_Engine.fileSystemFactory, FileSystem);
|
||||
}
|
||||
|
||||
void LogMessage(const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
static char buffer[2048];
|
||||
|
||||
va_start(ap, msg);
|
||||
size_t len = vsnprintf(buffer, sizeof(buffer) - 2, msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
buffer[len++] = '\n';
|
||||
buffer[len] = '\0';
|
||||
|
||||
if (!g_Engine.engine)
|
||||
{
|
||||
fprintf(stdout, "%s", buffer);
|
||||
} else {
|
||||
g_Engine.engine->LogPrint(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelShutdown_handler(void)
|
||||
{
|
||||
if (!bInFirstLevel)
|
||||
{
|
||||
char full_path[255];
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile());
|
||||
|
||||
LoadPluginsFromFile(full_path);
|
||||
} else {
|
||||
bInFirstLevel = false;
|
||||
}
|
||||
|
||||
ITER_EVENT(OnLevelShutdown, ());
|
||||
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
bool LevelInit_handler(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
|
||||
{
|
||||
if (!g_SmmAPI.CmdCacheSuccessful())
|
||||
{
|
||||
LogMessage("[META] Warning: Failed to initialize Con_Printf. Defaulting to Msg().");
|
||||
LogMessage("[META] Warning: Console messages will not be redirected to rcon console.");
|
||||
}
|
||||
|
||||
ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background));
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
#if defined __GNUC__ && (__GNUC__ == 3 || __GNUC__ == 4)
|
||||
void * operator new(size_t size) {
|
||||
return(calloc(1, size));
|
||||
}
|
||||
|
||||
void * operator new[](size_t size) {
|
||||
return(calloc(1, size));
|
||||
}
|
||||
|
||||
void operator delete(void * ptr) {
|
||||
if(ptr)
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void * ptr) {
|
||||
if(ptr)
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
@ -1,128 +0,0 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMM_H
|
||||
#define _INCLUDE_SOURCEMM_H
|
||||
|
||||
/**
|
||||
* @brief SourceMM main functionality for GameDLL interception
|
||||
* @file sourcemm.h
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include <sourcehook/sourcehook_impl.h>
|
||||
#include <sourcehook/sourcehook.h>
|
||||
#include "ISmmAPI.h"
|
||||
#include "CPlugin.h"
|
||||
#include "oslink.h"
|
||||
#include "util.h"
|
||||
#include "svn_version.h"
|
||||
|
||||
/**
|
||||
* Versioning
|
||||
* increase api_major when API breaks
|
||||
* increase api_minor when new functions are added (non-breaking)
|
||||
*/
|
||||
#define SOURCEMM_VERSION SVN_FILE_VERSION_STRING
|
||||
#define SOURCEMM_DATE __DATE__
|
||||
#define SM_VERS_API_MAJOR 1 //increase this on a breaking change
|
||||
#define SM_VERS_API_MINOR 6 //increase this on a non-breaking API change
|
||||
|
||||
/* We need a good CServerGameDLL version to work properly. We support these inclusively. */
|
||||
#define MIN_GAMEDLL_VERSION 3
|
||||
#define MAX_GAMEDLL_VERSION 8
|
||||
|
||||
/* Maximum version of IServerPluginCallbacks that SourceMM supports */
|
||||
#define MAX_VSP_VERSION 2
|
||||
|
||||
/**
|
||||
* @brief Entry point for HL2 Engine
|
||||
*/
|
||||
SMM_API void *CreateInterface(const char *name, int *code);
|
||||
|
||||
/** @brief Wrapper to catch GameDLL calls */
|
||||
void *EngineFactory(const char *name, int *code);
|
||||
|
||||
/** @brief Wrapper to catch GameDLL calls */
|
||||
void *PhysicsFactory(const char *name, int *code);
|
||||
|
||||
/** @brief Wrapper to catch GameDLL calls */
|
||||
void *FileSystemFactory(const char *name, int *code);
|
||||
|
||||
/** @brief Loads all plugins found in a file */
|
||||
int LoadPluginsFromFile(const char *file);
|
||||
|
||||
/** @brief Logs a message to the standard log file */
|
||||
void LogMessage(const char *msg, ...);
|
||||
|
||||
/** @brief Stores information about the GameDLL */
|
||||
struct GameDllInfo
|
||||
{
|
||||
bool loaded;
|
||||
HINSTANCE lib;
|
||||
CreateInterfaceFn factory;
|
||||
IServerGameDLL *pGameDLL;
|
||||
IServerGameClients *pGameClients;
|
||||
};
|
||||
|
||||
/** @brief Stores information about the HL2 Engine pointers */
|
||||
struct EngineInfo
|
||||
{
|
||||
EngineInfo() : loaded(false),
|
||||
engineFactory(NULL), physicsFactory(NULL), fileSystemFactory(NULL),
|
||||
pGlobals(NULL), icvar(NULL), engine(NULL)
|
||||
{ };
|
||||
bool loaded;
|
||||
CreateInterfaceFn engineFactory;
|
||||
CreateInterfaceFn physicsFactory;
|
||||
CreateInterfaceFn fileSystemFactory;
|
||||
CGlobalVars *pGlobals;
|
||||
ICvar *icvar;
|
||||
IVEngineServer *engine;
|
||||
};
|
||||
|
||||
/** @brief Global variable for GameDLL info */
|
||||
extern GameDllInfo g_GameDll;
|
||||
|
||||
/** @brief Global variable for Engine info */
|
||||
extern EngineInfo g_Engine;
|
||||
|
||||
/** @brief Global singleton for SourceHook */
|
||||
extern SourceHook::CSourceHookImpl g_SourceHook;
|
||||
|
||||
/** @brief Mod path (important!)*/
|
||||
extern SourceHook::String g_ModPath;
|
||||
|
||||
/** @brief Path to server binary */
|
||||
extern SourceHook::String g_BinPath;
|
||||
|
||||
/** @brief Path to SourceMM binary */
|
||||
extern SourceHook::String g_SmmPath;
|
||||
|
||||
/** @brief Global variable for SourceHook macros */
|
||||
extern SourceHook::ISourceHook *g_SHPtr;
|
||||
|
||||
/** @brief We have our own internal plugin id... */
|
||||
extern PluginId g_PLID;
|
||||
|
||||
/** @brief ServerGameDLL version that is currently loaded */
|
||||
extern int g_GameDllVersion;
|
||||
|
||||
/** @brief Highest IServerPluginCallbacks version that is supported by engine */
|
||||
extern int g_VspVersion;
|
||||
|
||||
/** @brief IServerGameClients version the mod uses */
|
||||
extern int g_GameClientsVersion;
|
||||
|
||||
extern bool bGameInit;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMM_H
|
@ -1,29 +0,0 @@
|
||||
The software is Copyright (C) 2004-2007, Metamod:Source Development Team.
|
||||
|
||||
Metamod:Source is distributed under the "zLib/libpng" license, which is reproduced
|
||||
below:
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
This software is provided "as-is", without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from
|
||||
the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software in
|
||||
a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not
|
||||
be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
The zLib/libpng license has been approved by the "Open Source Initiative"
|
||||
organization.
|
@ -1,21 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stub_mm", "stub_mm.vcproj", "{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Debug = Debug
|
||||
Release = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Debug.ActiveCfg = Debug|Win32
|
||||
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Debug.Build.0 = Debug|Win32
|
||||
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Release.ActiveCfg = Release|Win32
|
||||
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Release.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,142 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="stub_mm"
|
||||
ProjectGUID="{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib"
|
||||
ShowProgress="0"
|
||||
OutputFile="$(OutDir)/stub_mm.dll"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcmt.lib;libcmtd.lib"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/stub_mm.pdb"
|
||||
SubSystem="2"
|
||||
ImportLibrary="$(OutDir)/stub_mm.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS"
|
||||
RuntimeLibrary="4"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib"
|
||||
OutputFile="$(OutDir)/stub_mm.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="libcd.lib;libcmt.lib;libcmtd.lib"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
ImportLibrary="$(OutDir)/stub_mm.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath="..\stub_mm.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath="..\stub_mm.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -1,214 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="stub_mm"
|
||||
ProjectGUID="{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}"
|
||||
RootNamespace="stub_mm"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib"
|
||||
ShowProgress="0"
|
||||
OutputFile="$(OutDir)/stub_mm.dll"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
|
||||
GenerateDebugInformation="true"
|
||||
ProgramDatabaseFile="$(OutDir)/stub_mm.pdb"
|
||||
SubSystem="2"
|
||||
ImportLibrary="$(OutDir)/stub_mm.lib"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS"
|
||||
RuntimeLibrary="0"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib"
|
||||
OutputFile="$(OutDir)/stub_mm.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
ImportLibrary="$(OutDir)/stub_mm.lib"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\stub_mm.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\stub_mm.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -1,105 +0,0 @@
|
||||
/* ======== stub_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#include <oslink.h>
|
||||
#include "stub_mm.h"
|
||||
|
||||
SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
|
||||
|
||||
StubPlugin g_StubPlugin;
|
||||
|
||||
PLUGIN_EXPOSE(SamplePlugin, g_StubPlugin);
|
||||
|
||||
void ServerActivate_handler(edict_t *pEdictList, int edictCount, int clientMax)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ServerActivate() called: edictCount=%d, clientMax=%d", edictCount, clientMax);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
bool StubPlugin::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
|
||||
{
|
||||
PLUGIN_SAVEVARS();
|
||||
|
||||
GET_V_IFACE_ANY(serverFactory, m_ServerDll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
|
||||
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, ServerActivate, m_ServerDll, ServerActivate_handler, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StubPlugin::Unload(char *error, size_t maxlen)
|
||||
{
|
||||
SH_REMOVE_HOOK_STATICFUNC(IServerGameDLL, ServerActivate, m_ServerDll, ServerActivate_handler, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StubPlugin::Pause(char *error, size_t maxlen)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StubPlugin::Unpause(char *error, size_t maxlen)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void StubPlugin::AllPluginsLoaded()
|
||||
{
|
||||
//This is an example of inter-plugin communication
|
||||
PluginId id;
|
||||
void *ptr = g_SMAPI->MetaFactory("SamplePlugin", NULL, &id);
|
||||
if (ptr)
|
||||
{
|
||||
META_LOG(g_PLAPI, "Found Sample Plugin[%d] at (%p)!", id, ptr);
|
||||
} else {
|
||||
META_LOG(g_PLAPI, "Did not find Sample Plugin!");
|
||||
}
|
||||
}
|
||||
|
||||
const char *StubPlugin::GetAuthor()
|
||||
{
|
||||
return "AUTHOR";
|
||||
}
|
||||
|
||||
const char *StubPlugin::GetName()
|
||||
{
|
||||
return "Stub Plugin";
|
||||
}
|
||||
|
||||
const char *StubPlugin::GetDescription()
|
||||
{
|
||||
return "Stub Plugin";
|
||||
}
|
||||
|
||||
const char *StubPlugin::GetURL()
|
||||
{
|
||||
return "http://www.mysite.com/";
|
||||
}
|
||||
|
||||
const char *StubPlugin::GetLicense()
|
||||
{
|
||||
return "zlib/libpng";
|
||||
}
|
||||
|
||||
const char *StubPlugin::GetVersion()
|
||||
{
|
||||
return "1.00";
|
||||
}
|
||||
|
||||
const char *StubPlugin::GetDate()
|
||||
{
|
||||
return __DATE__;
|
||||
}
|
||||
|
||||
const char *StubPlugin::GetLogTag()
|
||||
{
|
||||
return "STUB";
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/* ======== stub_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SAMPLEPLUGIN_H
|
||||
#define _INCLUDE_SAMPLEPLUGIN_H
|
||||
|
||||
#include <ISmmPlugin.h>
|
||||
|
||||
class StubPlugin : public ISmmPlugin
|
||||
{
|
||||
public:
|
||||
bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late);
|
||||
bool Unload(char *error, size_t maxlen);
|
||||
bool Pause(char *error, size_t maxlen);
|
||||
bool Unpause(char *error, size_t maxlen);
|
||||
void AllPluginsLoaded();
|
||||
public:
|
||||
const char *GetAuthor();
|
||||
const char *GetName();
|
||||
const char *GetDescription();
|
||||
const char *GetURL();
|
||||
const char *GetLicense();
|
||||
const char *GetVersion();
|
||||
const char *GetDate();
|
||||
const char *GetLogTag();
|
||||
private:
|
||||
IServerGameDLL *m_ServerDll;
|
||||
IServerGameDLL *m_ServerDll_CC;
|
||||
};
|
||||
|
||||
extern StubPlugin g_StubPlugin;
|
||||
|
||||
PLUGIN_GLOBALVARS();
|
||||
|
||||
//Called on ServerActivate. Same definition as server plugins
|
||||
void ServerActivate_handler(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
|
||||
#endif //_INCLUDE_SAMPLEPLUGIN_H
|
@ -3,11 +3,11 @@
|
||||
#ifndef _INCLUDE_SVN_VERSION_H_
|
||||
#define _INCLUDE_SVN_VERSION_H_
|
||||
|
||||
#define SVN_PRODUCT_VERSION "1.4.0"
|
||||
#define SVN_PRODUCT_VERSION "1.6.0"
|
||||
|
||||
#define SVN_REVISION 346
|
||||
#define SVN_REVISION_STRING "346"
|
||||
#define SVN_FILE_VERSION 1,4,0,346
|
||||
#define SVN_FILE_VERSION_STRING "1.4.0.346"
|
||||
#define SVN_REVISION 423
|
||||
#define SVN_REVISION_STRING "423"
|
||||
#define SVN_FILE_VERSION 1,6,0,423
|
||||
#define SVN_FILE_VERSION_STRING "1.6.0.423"
|
||||
|
||||
#endif //_INCLUDE_SVN_VERSION_H_
|
||||
|
@ -1,49 +0,0 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMM_VSPLISTENER_H_
|
||||
#define _INCLUDE_SOURCEMM_VSPLISTENER_H_
|
||||
|
||||
#include "sourcemm.h"
|
||||
#include "iserverplugin.h"
|
||||
|
||||
class VSPListener : public IServerPluginCallbacks
|
||||
{
|
||||
public:
|
||||
VSPListener();
|
||||
public:
|
||||
virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory);
|
||||
virtual void Unload();
|
||||
virtual void Pause();
|
||||
virtual void UnPause();
|
||||
virtual const char *GetPluginDescription();
|
||||
virtual void LevelInit(char const *pMapName);
|
||||
virtual void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
virtual void GameFrame(bool simulating);
|
||||
virtual void LevelShutdown(void);
|
||||
virtual void ClientActive(edict_t *pEntity);
|
||||
virtual void ClientDisconnect(edict_t *pEntity);
|
||||
virtual void ClientPutInServer(edict_t *pEntity, char const *playername);
|
||||
virtual void SetCommandClient(int index);
|
||||
virtual void ClientSettingsChanged(edict_t *pEdict);
|
||||
virtual PLUGIN_RESULT ClientConnect(bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||
virtual PLUGIN_RESULT ClientCommand(edict_t *pEntity);
|
||||
virtual PLUGIN_RESULT NetworkIDValidated(const char *pszUserName, const char *pszNetworkID);
|
||||
public:
|
||||
bool IsLoaded();
|
||||
void SetLoadable(bool loadable);
|
||||
private:
|
||||
bool m_Loaded;
|
||||
bool m_Loadable;
|
||||
};
|
||||
|
||||
extern VSPListener g_VspListener;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMM_VSPLISTENER_H_
|
Loading…
x
Reference in New Issue
Block a user