1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-01-19 08:52:34 +01:00

nearly complete rewrite of Metamod:Source, API is the same but internally all engine/game functionality is abstracted. i also renamed files to make everything look a bit more conformant

--HG--
branch : sourcemm-1.6.0
rename : sourcemm/sourcemm.cpp => sourcemm/metamod.cpp
rename : sourcemm/sourcemm.h => sourcemm/metamod.h
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/branches/sourcemm-1.6.0%40427
This commit is contained in:
David Anderson 2007-09-22 18:08:30 +00:00
parent cf6dbdb1fe
commit c52389ea22
33 changed files with 1569 additions and 4643 deletions

View File

@ -1,649 +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 "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();
}

View File

@ -1,680 +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()
{
SourceHook::MemFuncInfo info = {true, -1, 0, 0};
SourceHook::GetFuncInfo(&IServerGameDLL::GetUserMessageInfo, info);
/* Get address of original GetUserMessageInfo() */
char *vfunc = reinterpret_cast<char *>(g_GameDllPatch->GetOrigFunc(info.vtbloffs, info.vtblindex));
/* If we can't get original function, that means there's no hook */
if (vfunc == NULL)
{
/* Get virtual function address 'manually' then */
char *adjustedptr = reinterpret_cast<char *>(g_GameDll.pGameDLL) + info.thisptroffs + info.vtbloffs;
char **vtable = *reinterpret_cast<char ***>(adjustedptr);
vfunc = vtable[info.vtblindex];
}
/* 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 = 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;
}
int CSmmAPI::GetSourceEngineBuild()
{
return g_SourceEngineVersion;
}

View File

@ -1,97 +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 *, ...);
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();
int GetSourceEngineBuild();
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 CSmmAPI g_SmmAPI;
#define CONMSG g_SmmAPI.ConPrintf
#define CLIENT_CONMSG g_SmmAPI.ClientConPrintf
#endif //_INCLUDE_CSMM_API_H

View File

@ -35,9 +35,10 @@ class ISmmPlugin;
#define MMIFACE_PLMANAGER "IPluginManager" /**< SourceMM Plugin Functions */ #define MMIFACE_PLMANAGER "IPluginManager" /**< SourceMM Plugin Functions */
#define IFACE_MAXNUM 999 /**< Maximum interface version */ #define IFACE_MAXNUM 999 /**< Maximum interface version */
#define SOURCE_ENGINE_ORIGINAL 0 /**< Original Source Engine (used by The Ship) */ #define SOURCE_ENGINE_UNKNOWN 0 /**< Could not determine the engine version */
#define SOURCE_ENGINE_EPISODEONE 1 /**< Episode 1 Source Engine (second major SDK) */ #define SOURCE_ENGINE_ORIGINAL 1 /**< Original Source Engine (used by The Ship) */
#define SOURCE_ENGINE_ORANGEBOX 2 /**< Orange Box Source Engine (third major SDK) */ #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 class ISmmAPI
{ {

View File

@ -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

View File

@ -1,523 +0,0 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date$
//
//-----------------------------------------------------------------------------
// $NoKeywords: $
//=============================================================================//
#ifndef CONVAR_H
#define CONVAR_H
#if _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#ifdef _WIN32
#define FORCEINLINE_CVAR FORCEINLINE
#elif _LINUX
#define FORCEINLINE_CVAR __inline__ FORCEINLINE
#else
#error "implement me"
#endif
// The default, no flags at all
#define FCVAR_NONE 0
// Command to ConVars and ConCommands
// ConVar Systems
#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc.
#define FCVAR_LAUNCHER (1<<1) // defined by launcher
#define FCVAR_GAMEDLL (1<<2) // defined by the game DLL
#define FCVAR_CLIENTDLL (1<<3) // defined by the client DLL
#define FCVAR_MATERIAL_SYSTEM (1<<4) // Defined by the material system.
#define FCVAR_DATACACHE (1<<19) // Defined by the datacache system.
#define FCVAR_STUDIORENDER (1<<15) // Defined by the studiorender system.
#define FCVAR_FILESYSTEM (1<<21) // Defined by the file system.
#define FCVAR_PLUGIN (1<<18) // Defined by a 3rd party plugin.
#define FCVAR_TOOLSYSTEM (1<<20) // Defined by an IToolSystem library
#define FCVAR_SOUNDSYSTEM (1<<23) // Defined by the soundsystem library
#define FCVAR_INPUTSYSTEM (1<<25) // Defined by the inputsystem dll
#define FCVAR_NETWORKSYSTEM (1<<26) // Defined by the network system
// NOTE!! if you add a cvar system, add it here too!!!!
// the engine lacks a cvar flag, but needs it for xbox
// an engine cvar is thus a cvar not marked with any other system
#define FCVAR_NON_ENGINE ((FCVAR_LAUNCHER|FCVAR_GAMEDLL|FCVAR_CLIENTDLL|FCVAR_MATERIAL_SYSTEM|FCVAR_DATACACHE|FCVAR_STUDIORENDER|FCVAR_FILESYSTEM|FCVAR_PLUGIN|FCVAR_TOOLSYSTEM|FCVAR_SOUNDSYSTEM|FCVAR_INPUTSYSTEM|FCVAR_NETWORKSYSTEM))
// ConVar only
#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server.
#define FCVAR_ARCHIVE (1<<7) // set to cause it to be saved to vars.rc
#define FCVAR_NOTIFY (1<<8) // notifies players when changed
#define FCVAR_USERINFO (1<<9) // changes the client's info string
#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats
#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
#define FCVAR_NEVER_AS_STRING (1<<12) // never try to print that cvar
// It's a ConVar that's shared between the client and the server.
// At signon, the values of all such ConVars are sent from the server to the client (skipped for local
// client, of course )
// If a change is requested it must come from the console (i.e., no remote client changes)
// If a value is changed while a server is active, it's replicated to all connected clients
#define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time
#define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file
#define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles
#define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server
#define FCVAR_ARCHIVE_XBOX (1<<24) // cvar written to config.cfg on the Xbox
// #define FCVAR_AVAILABLE (1<<27)
// #define FCVAR_AVAILABLE (1<<28)
// #define FCVAR_AVAILABLE (1<<29)
// #define FCVAR_AVAILABLE (1<<30)
// #define FCVAR_AVAILABLE (1<<31)
class ConVar;
class ConCommand;
class ConCommandBase;
// Any executable that wants to use ConVars need to implement one of
// these to hook up access to console variables.
class IConCommandBaseAccessor
{
public:
// Flags is a combination of FCVAR flags in cvar.h.
// hOut is filled in with a handle to the variable.
virtual bool RegisterConCommandBase( ConCommandBase *pVar )=0;
};
// You don't have to instantiate one of these, just call its
// OneTimeInit function when your executable is initializing.
class ConCommandBaseMgr
{
public:
// Call this ONCE when the executable starts up.
static void OneTimeInit( IConCommandBaseAccessor *pAccessor );
#ifdef _XBOX
static bool Fixup( ConCommandBase* pConCommandBase );
#ifndef _RETAIL
static void PublishCommands( bool bForce );
#endif
#endif
};
// Called when a ConVar changes value
typedef void ( *FnChangeCallback )( ConVar *var, char const *pOldString );
// Called when a ConCommand needs to execute
typedef void ( *FnCommandCallback )( void );
#define COMMAND_COMPLETION_MAXITEMS 64
#define COMMAND_COMPLETION_ITEM_LENGTH 64
// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings
typedef int ( *FnCommandCompletionCallback )( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
//-----------------------------------------------------------------------------
// Purpose: The base console invoked command/cvar interface
//-----------------------------------------------------------------------------
class ConCommandBase
{
friend class ConCommandBaseMgr;
friend class CCvar;
friend class ConVar;
friend class ConCommand;
public:
ConCommandBase( void );
ConCommandBase( char const *pName, char const *pHelpString = 0,
int flags = 0 );
virtual ~ConCommandBase( void );
virtual bool IsCommand( void ) const;
// Check flag
virtual bool IsBitSet( int flag ) const;
// Set flag
virtual void AddFlags( int flags );
// Return name of cvar
virtual char const *GetName( void ) const;
// Return help text for cvar
virtual char const *GetHelpText( void ) const;
// Deal with next pointer
const ConCommandBase *GetNext( void ) const;
void SetNext( ConCommandBase *next );
virtual bool IsRegistered( void ) const;
// Global methods
static ConCommandBase const *GetCommands( void );
static void AddToList( ConCommandBase *var );
static void RemoveFlaggedCommands( int flag );
static void RevertFlaggedCvars( int flag );
static ConCommandBase const *FindCommand( char const *name );
protected:
virtual void Create( char const *pName, char const *pHelpString = 0,
int flags = 0 );
// Used internally by OneTimeInit to initialize.
virtual void Init();
// Internal copy routine ( uses new operator from correct module )
char *CopyString( char const *from );
// Next ConVar in chain
ConCommandBase *m_pNext;
private:
// Has the cvar been added to the global list?
bool m_bRegistered;
// Static data
char const *m_pszName;
char const *m_pszHelpString;
// ConVar flags
int m_nFlags;
protected:
// ConVars add themselves to this list for the executable. Then ConVarMgr::Init() runs through
// all the console variables and registers them.
static ConCommandBase *s_pConCommandBases;
// ConVars in this executable use this 'global' to access values.
static IConCommandBaseAccessor *s_pAccessor;
};
//-----------------------------------------------------------------------------
// Purpose: The console invoked command
//-----------------------------------------------------------------------------
class ConCommand : public ConCommandBase
{
friend class ConCommandBaseMgr;
friend class CCvar;
#ifdef _STATIC_LINKED
friend class G_ConCommand;
friend class C_ConCommand;
friend class M_ConCommand;
friend class S_ConCommand;
friend class D_ConCommand;
#endif
public:
typedef ConCommandBase BaseClass;
ConCommand( void );
ConCommand( char const *pName, FnCommandCallback callback,
char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
virtual ~ConCommand( void );
virtual bool IsCommand( void ) const;
virtual int AutoCompleteSuggest( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
virtual bool CanAutoComplete( void );
// Invoke the function
virtual void Dispatch( void );
private:
virtual void Create( char const *pName, FnCommandCallback callback,
char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
// Call this function when executing the command
FnCommandCallback m_fnCommandCallback;
FnCommandCompletionCallback m_fnCompletionCallback;
bool m_bHasCompletionCallback;
public:
FnCommandCallback GetCallback() { return m_fnCommandCallback; }
};
//-----------------------------------------------------------------------------
// Purpose: A console variable
//-----------------------------------------------------------------------------
class ConVar : public ConCommandBase
{
friend class ConCommandBaseMgr;
friend class CCvar;
friend class CDefaultCvar;
#ifdef _STATIC_LINKED
friend class G_ConVar;
friend class C_ConVar;
friend class M_ConVar;
friend class S_ConVar;
friend class D_ConVar;
#endif
public:
typedef ConCommandBase BaseClass;
ConVar( char const *pName, char const *pDefaultValue, int flags = 0);
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString );
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax );
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString, FnChangeCallback callback );
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax,
FnChangeCallback callback );
virtual ~ConVar( void );
virtual bool IsBitSet( int flag ) const;
virtual char const* GetHelpText( void ) const;
virtual bool IsRegistered( void ) const;
virtual char const *GetName( void ) const;
virtual void AddFlags( int flags );
virtual bool IsCommand( void ) const;
// Install a change callback (there shouldn't already be one....)
void InstallChangeCallback( FnChangeCallback callback );
// Retrieve value
FORCEINLINE_CVAR float GetFloat( void ) const;
FORCEINLINE_CVAR int GetInt( void ) const;
FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); }
FORCEINLINE_CVAR char const *GetString( void ) const;
// Any function that allocates/frees memory needs to be virtual or else you'll have crashes
// from alloc/free across dll/exe boundaries.
// These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue).
virtual void SetValue( char const *value );
virtual void SetValue( float value );
virtual void SetValue( int value );
// Reset to default value
void Revert( void );
// True if it has a min/max setting
bool GetMin( float& minVal ) const;
bool GetMax( float& maxVal ) const;
char const *GetDefault( void ) const;
static void RevertAll( void );
private:
// Called by CCvar when the value of a var is changing.
virtual void InternalSetValue(char const *value);
// For CVARs marked FCVAR_NEVER_AS_STRING
virtual void InternalSetFloatValue( float fNewValue );
virtual void InternalSetIntValue( int nValue );
virtual bool ClampValue( float& value );
virtual void ChangeStringValue( char const *tempVal );
virtual void Create( char const *pName, char const *pDefaultValue, int flags = 0,
char const *pHelpString = 0, bool bMin = false, float fMin = 0.0,
bool bMax = false, float fMax = false, FnChangeCallback callback = 0 );
// Used internally by OneTimeInit to initialize.
virtual void Init();
private:
// This either points to "this" or it points to the original declaration of a ConVar.
// This allows ConVars to exist in separate modules, and they all use the first one to be declared.
// m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar).
ConVar *m_pParent;
// Static data
char const *m_pszDefaultValue;
// Value
// Dynamically allocated
char *m_pszString;
int m_StringLength;
// Values
float m_fValue;
int m_nValue;
// Min/Max values
bool m_bHasMin;
float m_fMinVal;
bool m_bHasMax;
float m_fMaxVal;
// Call this function when ConVar changes
FnChangeCallback m_fnChangeCallback;
};
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as a float
// Output : float
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR float ConVar::GetFloat( void ) const
{
return m_pParent->m_fValue;
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as an int
// Output : int
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR int ConVar::GetInt( void ) const
{
return m_pParent->m_nValue;
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
// Output : char const *
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR char const *ConVar::GetString( void ) const
{
if ( m_nFlags & FCVAR_NEVER_AS_STRING )
{
return "FCVAR_NEVER_AS_STRING";
}
return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : "";
}
#ifdef _STATIC_LINKED
// identifies subsystem via piggybacking constructors with flags
class G_ConCommand : public ConCommand
{
public:
G_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_GAMEDLL, completionFunc) {}
};
class C_ConCommand : public ConCommand
{
public:
C_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_CLIENTDLL, completionFunc) {}
};
class M_ConCommand : public ConCommand
{
public:
M_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_MATERIAL_SYSTEM, completionFunc) {}
};
class S_ConCommand : public ConCommand
{
public:
S_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_STUDIORENDER, completionFunc) {}
};
class D_ConCommand : public ConCommand
{
public:
D_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_DATACACHE, completionFunc) {}
};
typedef void ( *G_FnChangeCallback )( G_ConVar *var, char const *pOldString );
typedef void ( *C_FnChangeCallback )( C_ConVar *var, char const *pOldString );
typedef void ( *M_FnChangeCallback )( M_ConVar *var, char const *pOldString );
typedef void ( *S_FnChangeCallback )( S_ConVar *var, char const *pOldString );
typedef void ( *D_FnChangeCallback )( D_ConVar *var, char const *pOldString );
class G_ConVar : public ConVar
{
public:
G_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString ) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, bMin, fMin, bMax, fMax) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, G_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, (FnChangeCallback)callback ) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, G_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class C_ConVar : public ConVar
{
public:
C_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString ) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, bMin, fMin, bMax, fMax) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, C_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, (FnChangeCallback)callback ) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, C_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class M_ConVar : public ConVar
{
public:
M_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString ) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, bMin, fMin, bMax, fMax) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, (FnChangeCallback)callback ) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class S_ConVar : public ConVar
{
public:
S_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString ) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, bMin, fMin, bMax, fMax) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, (FnChangeCallback)callback ) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, S_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class D_ConVar : public ConVar
{
public:
D_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString ) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, bMin, fMin, bMax, fMax) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, (FnChangeCallback)callback ) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, D_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
// redirect these declarations to their specific subsystem
#ifdef GAME_DLL
#define ConCommand G_ConCommand
#define ConVar G_ConVar
#endif
#ifdef CLIENT_DLL
#define ConCommand C_ConCommand
#define ConVar C_ConVar
#endif
#ifdef MATERIALSYSTEM_DLL
#define ConCommand M_ConCommand
#define ConVar M_ConVar
#endif
#ifdef STUDIORENDER_DLL
#define ConCommand S_ConCommand
#define ConVar S_ConVar
#endif
#ifdef DATACACHE_DLL
#define ConCommand D_ConCommand
#define ConVar D_ConVar
#endif
#endif // _STATIC_LINKED
//-----------------------------------------------------------------------------
// Purpose: Utility to quicky generate a simple console command
//-----------------------------------------------------------------------------
#define CON_COMMAND( name, description ) \
static void name(); \
static ConCommand name##_command( #name, name, description ); \
static void name()
//-----------------------------------------------------------------------------
// Purpose: Utility to quicky generate a simple console command
//-----------------------------------------------------------------------------
#define CON_COMMAND_F( name, description, flags ) \
static void name(); \
static ConCommand name##_command( #name, name, description, flags ); \
static void name()
#endif // CONVAR_H

1182
sourcemm/metamod.cpp Normal file
View File

@ -0,0 +1,1182 @@
/* ======== 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
* ============================
*/
#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"
#if defined DEBUG2
#undef DEBUG2
#define _DEBUG
#endif
using namespace SourceMM;
using namespace SourceHook;
/**
* @brief Implementation of main SourceMM GameDLL functionality
* @file sourcemm.cpp
*/
IMetamodSourceProvider *provider = NULL;
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;
};
SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
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;
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)
{
IServerPluginCallbacks *pCallbacks = provider->GetVSPCallbacks(iface);
if (pCallbacks && vsp_version == 0)
{
vsp_version = atoi(&iface[22]);
}
if (pCallbacks && ret)
{
*ret = pCallbacks ? IFACE_OK : IFACE_FAILED;
}
return pCallbacks;
}
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");
/* 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(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;
g_GameDllPatch = SH_GET_CALLCLASS(server);
provider->Notify_DLLInit_Pre();
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);
provider->CreateCommand("meta", Command_Meta, "Metamod:Source Menu");
provider->SetClientCommandHandler(Command_ClientMeta);
const char *pluginFile = provider->GetCommandLineValue("mm_pluginsfile", NULL);
if (!pluginFile)
{
pluginFile = provider->GetConVarString(mm_pluginsfile);
}
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();
SH_CALL(g_GameDllPatch, &IServerGameDLL::DLLShutdown)();
SH_RELEASE_CALLCLASS(g_GameDllPatch);
g_GameDllPatch = NULL;
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.AddPluginCmd(plugin, pCommand);
}
else
{
g_PluginMngr.AddPluginCvar(plugin, 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;
}

88
sourcemm/metamod.h Normal file
View File

@ -0,0 +1,88 @@
/* ======== 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 "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();
public:
const char *GetGameBinaryPath();
const char *GetPluginsFile();
};
void LogMessage(const char *msg, ...);
int LoadPluginsFromFile(const char *_file);
extern PluginId g_PLID;
extern SourceHook::ISourceHook *g_SHPtr;
extern SourceHook::CSourceHookImpl g_SourceHook;
extern MetamodSource g_Metamod;
extern IMetamodSourceProvider *provider;
#endif //_INCLUDE_SOURCEMM_H

View File

@ -8,12 +8,19 @@
* ============================ * ============================
*/ */
#if defined _DEBUG
#define DEBUG2
#undef _DEBUG
#endif
#include <ctype.h> #include <ctype.h>
#include "CSmmAPI.h" #include "metamod.h"
#include "concommands.h" #include "metamod_util.h"
#include "CPlugin.h" #include "metamod_console.h"
#include "sh_string.h" #include "metamod_plugins.h"
#include "sh_list.h" #if defined DEBUG2
#undef DEBUG2
#define _DEBUG
#endif
using namespace SourceMM; using namespace SourceMM;
using namespace SourceHook; using namespace SourceHook;
@ -23,143 +30,16 @@ using namespace SourceHook;
* @file concommands.cpp * @file concommands.cpp
*/ */
CAlwaysRegisterableCommand g_EternalCommand; #define CONMSG g_Metamod.ConPrintf
SMConVarAccessor g_SMConVarAccessor; #define CLIENT_CONMSG g_Metamod.ClientConPrintf
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand) bool Command_Meta(edict_t *pEdict, IMetamodSourceCommandInfo *info)
{ {
// Add the FCVAR_GAMEDLL flag unsigned int args = info->GetArgCount();
// => 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);
pCommand->SetNext( NULL ); if (args >= 1)
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)
{ {
(*iter)->AddFlags(FCVAR_GAMEDLL); const char *command = info->GetArg(1);
}
}
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);
if (strcmp(command, "credits") == 0) if (strcmp(command, "credits") == 0)
{ {
CONMSG("Metamod:Source was developed by:\n"); CONMSG("Metamod:Source was developed by:\n");
@ -169,57 +49,73 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG("For more information, see the official website\n"); CONMSG("For more information, see the official website\n");
CONMSG("http://www.sourcemm.net/\n"); CONMSG("http://www.sourcemm.net/\n");
return; return true;
} else if (strcmp(command, "version") == 0) { }
else if (strcmp(command, "version") == 0)
{
CONMSG("Metamod:Source version %s\n", SOURCEMM_VERSION); CONMSG("Metamod:Source version %s\n", SOURCEMM_VERSION);
CONMSG("Compiled on: %s\n", SOURCEMM_DATE); CONMSG("Compiled on: %s\n", SOURCEMM_DATE);
CONMSG("Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION); 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("SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
CONMSG("http://www.sourcemm.net/\n"); CONMSG("http://www.sourcemm.net/\n");
return; return true;
} else if (strcmp(command, "game") == 0) { }
else if (strcmp(command, "game") == 0)
{
CONMSG("GameDLL Information\n"); CONMSG("GameDLL Information\n");
CONMSG(" Description: %s\n", g_GameDll.pGameDLL->GetGameDescription()); CONMSG(" Description: %s\n", provider->GetGameDescription());
CONMSG(" Mod Path: %s\n", g_ModPath.c_str()); CONMSG(" Mod Path: %s\n", g_Metamod.GetBaseDir());
CONMSG(" DLL Path: %s\n", g_BinPath.c_str()); CONMSG(" DLL Path: %s\n", g_Metamod.GetGameBinaryPath());
CONMSG(" Interface: ServerGameDLL%03d, ServerGameClients%03d\n", g_GameDllVersion, g_GameClientsVersion); CONMSG(" Interface: ServerGameDLL%03d\n", g_Metamod.GetGameDLLVersion());
// Display user messages // Display user messages
if (g_SmmAPI.MsgCacheSuccessful()) int messages = g_Metamod.GetUserMessageCount();
if (messages == -1)
{ {
const char *msgname; const char *msgname;
int msgsize; int msgsize;
int msgcount = g_SmmAPI.GetUserMessageCount();
if (msgcount > 0) if (messages > 0)
{ {
CONMSG(" User Messages: %-32.31s %-5s %-5s\n", "Name", "Index", "Size"); 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(" %-32.31s %-5d %-5d\n", msgname, i, msgsize);
} }
CONMSG(" %d user message%s in total\n", msgcount, (msgcount > 1) ? "s" : ""); CONMSG(" %d user message%s in total\n", messages, (messages > 1) ? "s" : "");
} else { }
else
{
CONMSG(" User Messages: None\n"); CONMSG(" User Messages: None\n");
} }
} else { }
else
{
CONMSG(" User Messages: Failed to get list of user messages\n"); CONMSG(" User Messages: Failed to get list of user messages\n");
} }
return; return true;
} else if (strcmp(command, "refresh") == 0) { }
else if (strcmp(command, "refresh") == 0)
{
char full_path[255]; 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); LoadPluginsFromFile(full_path);
return; return true;
} else if (strcmp(command, "list") == 0) { }
else if (strcmp(command, "list") == 0)
{
CPluginManager::CPlugin *pl; CPluginManager::CPlugin *pl;
ISmmPlugin *plapi; ISmmPlugin *plapi;
const char *plname; const char *plname;
@ -231,7 +127,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
if (!plnum) if (!plnum)
{ {
CONMSG("No plugins loaded.\n"); CONMSG("No plugins loaded.\n");
return; return true;
} else { } else {
CONMSG("Listing %d plugin%s:\n", plnum, (plnum > 1) ? "s" : ""); CONMSG("Listing %d plugin%s:\n", plnum, (plnum > 1) ? "s" : "");
} }
@ -271,23 +167,27 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG("%s\n", buffer); CONMSG("%s\n", buffer);
} }
return; return true;
} else if (strcmp(command, "cmds") == 0) { }
if (args >= 3) 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); CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
if (!pl) if (!pl)
{ {
CONMSG("Plugin %d not found.\n", id); CONMSG("Plugin %d not found.\n", id);
return; return true;
} }
if (!pl->m_API) if (!pl->m_API)
{ {
CONMSG("Plugin %d is not loaded.\n", id); CONMSG("Plugin %d is not loaded.\n", id);
} else { }
else
{
CONMSG("Console commands for %s:\n", pl->m_API->GetName()); CONMSG("Console commands for %s:\n", pl->m_API->GetName());
List<ConCommandBase *>::iterator ci; List<ConCommandBase *>::iterator ci;
size_t count = 0; size_t count = 0;
@ -298,27 +198,33 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG(" [%5d] %-s\n", count, (*ci)->GetName()); CONMSG(" [%5d] %-s\n", count, (*ci)->GetName());
} }
} }
} else { }
else
{
CONMSG("Usage: meta cmds <id>\n"); CONMSG("Usage: meta cmds <id>\n");
} }
return; return true;
} else if (strcmp(command, "cvars") == 0) { }
if (args >= 3) 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); CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
if (!pl) if (!pl)
{ {
CONMSG("Plugin %d not found.\n", id); CONMSG("Plugin %d not found.\n", id);
return; return true;
} }
if (!pl->m_API) if (!pl->m_API)
{ {
CONMSG("Plugin %d is not loaded.\n", id); CONMSG("Plugin %d is not loaded.\n", id);
} else { }
else
{
CONMSG("Registered cvars for %s:\n", pl->m_API->GetName()); CONMSG("Registered cvars for %s:\n", pl->m_API->GetName());
List<ConCommandBase *>::iterator ci; List<ConCommandBase *>::iterator ci;
size_t count = 0; size_t count = 0;
@ -329,38 +235,50 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG(" [%5d] %-s\n", count, (*ci)->GetName()); CONMSG(" [%5d] %-s\n", count, (*ci)->GetName());
} }
} }
} else { }
else
{
CONMSG("Usage: meta cvars <id>\n"); CONMSG("Usage: meta cvars <id>\n");
} }
return; return true;
} else if (strcmp(command, "info") == 0) { }
if (args >= 3) 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); CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
if (!pl) if (!pl)
{ {
CONMSG("Plugin %d not found.\n", id); CONMSG("Plugin %d not found.\n", id);
return; return true;
} }
if (!pl->m_API) if (!pl->m_API)
{ {
CONMSG("Plugin %d is not loaded.\n", id); CONMSG("Plugin %d is not loaded.\n", id);
} else { }
else
{
if (pl->m_Status == Pl_Paused) if (pl->m_Status == Pl_Paused)
{ {
CONMSG("Plugin %d is paused.\n", id); 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]; char run_msg[255];
bool run = false; bool run = false;
if (pl->m_API && pl->m_API->QueryRunning(run_msg, sizeof(run_msg)-1)) if (pl->m_API && pl->m_API->QueryRunning(run_msg, sizeof(run_msg)-1))
{
run = true; run = true;
}
if (run) if (run)
{ {
CONMSG("Plugin %d is running.\n", id); CONMSG("Plugin %d is running.\n", id);
} else { }
else
{
CONMSG("Plugin %d is stopped: %s\n", id, run_msg); CONMSG("Plugin %d is stopped: %s\n", id, run_msg);
} }
} }
@ -373,57 +291,69 @@ CON_COMMAND(meta, "Metamod:Source Menu")
} }
CONMSG("File: %s\n\n", pl->m_File.c_str()); CONMSG("File: %s\n\n", pl->m_File.c_str());
return; return true;
} else { }
else
{
CONMSG("Usage: meta info <id>\n"); 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]; char error[255];
if (!g_PluginMngr.Pause(id, error, sizeof(error))) if (!g_PluginMngr.Pause(id, error, sizeof(error)))
{ {
CONMSG("Pause failed: %s\n", error); CONMSG("Pause failed: %s\n", error);
return; return true;
} }
CONMSG("Plugin %d has been paused.\n", id); CONMSG("Plugin %d has been paused.\n", id);
return; return true;
} else { }
else
{
CONMSG("Usage: meta pause <id>\n"); 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]; char error[255];
if (!g_PluginMngr.Unpause(id, error, sizeof(error))) if (!g_PluginMngr.Unpause(id, error, sizeof(error)))
{ {
CONMSG("Unpause failed: %s\n", error); CONMSG("Unpause failed: %s\n", error);
return; return true;
} }
CONMSG("Plugin %d has been unpaused.\n", id); CONMSG("Plugin %d has been unpaused.\n", id);
return; return true;
} else { }
else
{
CONMSG("Usage: meta unpause <id>\n"); 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]; char full_path[255];
const char *alias = g_PluginMngr.LookupAlias(file); const char *alias = g_PluginMngr.LookupAlias(file);
@ -434,15 +364,22 @@ CON_COMMAND(meta, "Metamod:Source Menu")
if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0) if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0)
{ {
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s", file); g_Metamod.PathFormat(full_path, sizeof(full_path), "%s", file);
} else { }
else
{
const char *ext = UTIL_GetExtension(file); const char *ext = UTIL_GetExtension(file);
#if defined WIN32 || defined _WIN32 #if defined WIN32 || defined _WIN32
ext = ext ? "" : ".dll"; ext = ext ? "" : ".dll";
#else #else
ext = ext ? "" : "_i486.so"; ext = ext ? "" : "_i486.so";
#endif #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}; char error[255]={0};
@ -454,7 +391,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
if (!pl || id < Pl_MinId || (pl->m_Status < Pl_Paused)) if (!pl || id < Pl_MinId || (pl->m_Status < Pl_Paused))
{ {
CONMSG("Failed to load plugin %s (%s).\n", file, error); CONMSG("Failed to load plugin %s (%s).\n", file, error);
return; return true;
} }
if (!already) if (!already)
@ -464,28 +401,34 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG("Plugin \"%s\" is already loaded as %d.\n", pl->m_API->GetName(), pl->m_Id); CONMSG("Plugin \"%s\" is already loaded as %d.\n", pl->m_API->GetName(), pl->m_Id);
} }
return; return true;
} else { }
else
{
CONMSG("Usage: meta load <path>\n"); CONMSG("Usage: meta load <path>\n");
return; return true;
} }
} else if ( (strcmp(command, "alias") == 0) || }
(strcmp(command, "aliases") == 0) ) { else if ( (strcmp(command, "alias") == 0) ||
if (args >= 4) (strcmp(command, "aliases") == 0) )
{
if (args >= 3)
{ {
const char *alias = e->Cmd_Argv(2); const char *alias = info->GetArg(2);
const char *value = e->Cmd_Argv(3); const char *value = info->GetArg(3);
g_PluginMngr.SetAlias(alias, value); g_PluginMngr.SetAlias(alias, value);
if (value[0] == '\0') if (value == NULL || value[0] == '\0')
{ {
CONMSG("Deleted alias: %s.\n", alias); CONMSG("Deleted alias: %s.\n", alias);
} else { } else {
CONMSG("Set alias \"%s\" to: %s\n", alias, value); 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); const char *value = g_PluginMngr.LookupAlias(alias);
if (value) if (value)
{ {
@ -493,7 +436,9 @@ CON_COMMAND(meta, "Metamod:Source Menu")
} else { } else {
CONMSG("Alias \"%s\" was not found.\n", alias); CONMSG("Alias \"%s\" was not found.\n", alias);
} }
} else { }
else
{
List<CNameAlias *>::iterator iter, end; List<CNameAlias *>::iterator iter, end;
CNameAlias *p; CNameAlias *p;
@ -512,15 +457,19 @@ CON_COMMAND(meta, "Metamod:Source Menu")
} }
CONMSG(" --- \n"); CONMSG(" --- \n");
CONMSG("%d aliases total.\n", total); CONMSG("%d aliases total.\n", total);
} else { }
else
{
CONMSG("No aliases found.\n"); CONMSG("No aliases found.\n");
} }
} }
return; return true;
} else if (strcmp(command, "unload") == 0) { }
if (args >= 3) 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); int id = atoi(file);
char error[255]={0}; char error[255]={0};
@ -537,15 +486,22 @@ CON_COMMAND(meta, "Metamod:Source Menu")
/* first check if it's a known filename */ /* first check if it's a known filename */
if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0) if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0)
{ {
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s", file); g_Metamod.PathFormat(full_path, sizeof(full_path), "%s", file);
} else { }
else
{
const char *ext = UTIL_GetExtension(file); const char *ext = UTIL_GetExtension(file);
#if defined WIN32 || defined _WIN32 #if defined WIN32 || defined _WIN32
ext = ext ? "" : ".dll"; ext = ext ? "" : ".dll";
#else #else
ext = ext ? "" : "_i486.so"; ext = ext ? "" : "_i486.so";
#endif #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; List<CPluginManager::CPlugin *>::iterator iter, end;
@ -564,70 +520,82 @@ CON_COMMAND(meta, "Metamod:Source Menu")
if (id == 0) if (id == 0)
{ {
CONMSG("Plugin \"%s\" not found.\n", full_path); CONMSG("Plugin \"%s\" not found.\n", full_path);
return; return true;
} }
} }
if (!g_PluginMngr.Unload(id, false, error, sizeof(error))) if (!g_PluginMngr.Unload(id, false, error, sizeof(error)))
{ {
CONMSG("Unload failed: %s\n", error); CONMSG("Unload failed: %s\n", error);
return; return true;
} }
CONMSG("Plugin %d unloaded.\n", id); CONMSG("Plugin %d unloaded.\n", id);
} else { }
else
{
CONMSG("Usage: meta unload <id>\n"); CONMSG("Usage: meta unload <id>\n");
} }
return; return true;
} else if (strcmp(command, "force_unload") == 0) { }
if (args >= 3) 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}; char error[255]={0};
if (!g_PluginMngr.Unload(id, false, error, sizeof(error))) if (!g_PluginMngr.Unload(id, false, error, sizeof(error)))
{ {
CONMSG("Force unload failed: %s\n", error); CONMSG("Force unload failed: %s\n", error);
return; return true;
} }
CONMSG("Plugin %d force unloaded.\n", id); CONMSG("Plugin %d force unloaded.\n", id);
return; return true;
} else { }
else
{
CONMSG("Usage: meta force_unload <id>\n"); 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()) if (!g_PluginMngr.UnloadAll())
{ {
CONMSG("One or more plugins resisted removal (cleaned anyway).\n"); CONMSG("One or more plugins resisted removal (cleaned anyway).\n");
return; return true;
} }
CONMSG("All plugins unloaded.\n"); CONMSG("All plugins unloaded.\n");
return; return true;
} else if (strcmp(command, "retry") == 0) { }
if (args >= 3) 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]; char error[255];
if (!g_PluginMngr.Retry(id, error, sizeof(error))) if (!g_PluginMngr.Retry(id, error, sizeof(error)))
{ {
CONMSG("Error reloading plugin: %s\n", error); CONMSG("Error reloading plugin: %s\n", error);
return; return true;
} }
CONMSG("Plugin %d successfully reloaded.\n", id); CONMSG("Plugin %d successfully reloaded.\n", id);
return; return true;
} else { }
else
{
CONMSG("Usage: meta retry <id>\n"); CONMSG("Usage: meta retry <id>\n");
return; return true;
} }
} }
} }
@ -650,66 +618,20 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG(" unload - Unload a loaded plugin\n"); CONMSG(" unload - Unload a loaded plugin\n");
CONMSG(" unpause - Unpause a paused plugin\n"); CONMSG(" unpause - Unpause a paused plugin\n");
CONMSG(" version - Version information\n"); CONMSG(" version - Version information\n");
return true;
} }
CAlwaysRegisterableCommand::CAlwaysRegisterableCommand() bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info)
{ {
Create("", NULL, FCVAR_UNREGISTERED|FCVAR_GAMEDLL); const char *cmd = info->GetArg(0);
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);
if (strcmp(cmd, "meta") == 0) if (strcmp(cmd, "meta") == 0)
{ {
int args = e->Cmd_Argc(); unsigned int args = info->GetArgCount();
if (args == 2) if (args == 1)
{ {
const char *subcmd = e->Cmd_Argv(1); const char *subcmd = info->GetArg(1);
if (strcmp(subcmd, "credits") == 0) if (strcmp(subcmd, "credits") == 0)
{ {
@ -720,16 +642,20 @@ void ClientCommand_handler(edict_t *client)
CLIENT_CONMSG(client, "For more information, see the official website\n"); CLIENT_CONMSG(client, "For more information, see the official website\n");
CLIENT_CONMSG(client, "http://www.sourcemm.net/\n"); CLIENT_CONMSG(client, "http://www.sourcemm.net/\n");
RETURN_META(MRES_SUPERCEDE); return true;
} else if(strcmp(subcmd, "version") == 0) { }
else if(strcmp(subcmd, "version") == 0)
{
CLIENT_CONMSG(client, "Metamod:Source version %s\n", SOURCEMM_VERSION); CLIENT_CONMSG(client, "Metamod:Source version %s\n", SOURCEMM_VERSION);
CLIENT_CONMSG(client, "Compiled on: %s\n", SOURCEMM_DATE); 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, "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, "SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
CLIENT_CONMSG(client, "http://www.sourcemm.net/\n"); CLIENT_CONMSG(client, "http://www.sourcemm.net/\n");
RETURN_META(MRES_SUPERCEDE); return true;
} else if(strcmp(subcmd, "list") == 0) { }
else if(strcmp(subcmd, "list") == 0)
{
CPluginManager::CPlugin *pl; CPluginManager::CPlugin *pl;
ISmmPlugin *plapi; ISmmPlugin *plapi;
const char *plname; const char *plname;
@ -773,7 +699,7 @@ void ClientCommand_handler(edict_t *client)
CLIENT_CONMSG(client, "No active plugins loaded.\n"); CLIENT_CONMSG(client, "No active plugins loaded.\n");
} }
RETURN_META(MRES_SUPERCEDE); return true;
} }
} }
@ -783,13 +709,8 @@ void ClientCommand_handler(edict_t *client)
CLIENT_CONMSG(client, " list - List plugins\n"); CLIENT_CONMSG(client, " list - List plugins\n");
CLIENT_CONMSG(client, " version - Version information\n"); CLIENT_CONMSG(client, " version - Version information\n");
RETURN_META(MRES_SUPERCEDE); return true;
} }
RETURN_META(MRES_IGNORED); return false;
}
const char *GetPluginsFile()
{
return mm_pluginsfile.GetString();
} }

View File

@ -0,0 +1,19 @@
/* ======== 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
#include "metamod_provider.h"
bool Command_Meta(edict_t *pEdict, IMetamodSourceCommandInfo *info);
bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info);
#endif //_INCLUDE_CONCOMMANDS_H

View File

@ -18,11 +18,10 @@
#include <interface.h> #include <interface.h>
#include <eiface.h> #include <eiface.h>
#include "convar_smm.h" #include <sh_list.h>
#include <sh_string.h>
#include "IPluginManager.h" #include "IPluginManager.h"
#include "oslink.h" #include "oslink.h"
#include "sh_list.h"
#include "sh_string.h"
/** /**
* History of plugin versions: (M=min, C=current) * History of plugin versions: (M=min, C=current)

View File

@ -11,7 +11,7 @@
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "util.h" #include "metamod_util.h"
#include "oslink.h" #include "oslink.h"
/** /**

View File

@ -41,6 +41,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="..;..\..;..\..\sourcehook"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
@ -62,7 +63,6 @@
/> />
<Tool <Tool
Name="VCLinkerTool" Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
OutputFile="$(OutDir)/server.dll" OutputFile="$(OutDir)/server.dll"
LinkIncremental="2" LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib" IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
@ -194,41 +194,25 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
> >
<File <File
RelativePath="..\concommands.cpp" RelativePath="..\metamod.cpp"
> >
</File> </File>
<File <File
RelativePath="..\CPlugin.cpp" RelativePath="..\metamod_console.cpp"
> >
</File> </File>
<File <File
RelativePath="..\CSmmAPI.cpp" RelativePath="..\metamod_plugins.cpp"
>
</File>
<File
RelativePath="..\metamod_util.cpp"
> >
</File> </File>
<File <File
RelativePath="..\oslink.cpp" RelativePath="..\oslink.cpp"
> >
</File> </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>
<Filter <Filter
Name="Header Files" Name="Header Files"
@ -236,37 +220,25 @@
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
> >
<File <File
RelativePath="..\concommands.h" RelativePath="..\metamod.h"
> >
</File> </File>
<File <File
RelativePath="..\CPlugin.h" RelativePath="..\metamod_console.h"
> >
</File> </File>
<File <File
RelativePath="..\CSmmAPI.h" RelativePath="..\metamod_plugins.h"
>
</File>
<File
RelativePath="..\metamod_util.h"
> >
</File> </File>
<File <File
RelativePath="..\oslink.h" RelativePath="..\oslink.h"
> >
</File> </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>
<Filter <Filter
Name="Resource Files" Name="Resource Files"
@ -293,6 +265,10 @@
RelativePath="..\ISmmPlugin.h" RelativePath="..\ISmmPlugin.h"
> >
</File> </File>
<File
RelativePath="..\metamod_provider.h"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="SourceHook" Name="SourceHook"

View File

@ -67,3 +67,24 @@ bool GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
#endif #endif
return true; return true;
} }
#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

View File

@ -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.

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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.");
}

View File

@ -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

View File

@ -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

View File

@ -1,222 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="sample_mm"
ProjectGUID="{FAFF34FB-FE14-47B5-81BD-70D237392FB2}"
RootNamespace="sample_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;SAMPLE_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 tier1.lib vstdlib.lib"
OutputFile="$(OutDir)/sample_mm.dll"
LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/sample_mm.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/sample_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;SAMPLE_MM_EXPORTS"
RuntimeLibrary="0"
RuntimeTypeInfo="false"
UsePrecompiledHeader="0"
ExpandAttributedSource="true"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
OutputFile="$(OutDir)/sample_mm.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="1"
ImportLibrary="$(OutDir)/sample_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="..\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>

View File

@ -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;
SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
int g_GameDllVersion = 0;
int g_GameClientsVersion = 0;
int g_VspVersion = 0;
int g_SourceEngineVersion = SOURCE_ENGINE_ORIGINAL;
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));
g_GameDllPatch = SH_GET_CALLCLASS(g_GameDll.pGameDLL);
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 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]));
if (g_GameDllVersion < MIN_GAMEDLL_VERSION)
{
if (ret)
{
*ret = IFACE_FAILED;
}
}
else if (g_GameDllVersion > 3)
{
/* The engine is at least episode 1 */
g_SourceEngineVersion = SOURCE_ENGINE_EPISODEONE;
}
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)
{
InitMainStates();
} else {
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_GameDllPatch, &IServerGameDLL::DLLShutdown)();
SH_RELEASE_CALLCLASS(g_GameDllPatch);
g_GameDllPatch = NULL;
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

View File

@ -1,131 +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 7 //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
/* 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;
/** @brief Source Engine version */
extern int g_SourceEngineVersion;
extern bool bGameInit;
/** @brief Global CallClass for IServerGameDLL */
extern SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
#endif //_INCLUDE_SOURCEMM_H

View File

@ -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.

View File

@ -1,66 +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 = stub_mm_i486.so
HL2PUB = $(HL2SDK)/public
OBJECTS = stub_mm.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
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)

View File

@ -1,20 +0,0 @@

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}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -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>

View File

@ -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";
}

View File

@ -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

View File

@ -1,152 +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 "vsp_listener.h"
#include "CPlugin.h"
using namespace SourceMM;
VSPListener g_VspListener;
VSPListener::VSPListener()
{
m_Loaded = false;
m_Loadable = false;
}
void VSPListener::ClientActive(edict_t *pEntity)
{
}
PLUGIN_RESULT VSPListener::ClientCommand(edict_t *pEntity)
{
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" SOURCEMM_VERSION;
}
bool VSPListener::IsLoaded()
{
return m_Loaded;
}
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_Loadable = 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)
{
Warning("Do not manually load Metamod:Source as a Valve Server Plugin\n");
return false;
}
if (m_Loaded)
{
return false;
}
m_Loaded = 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);
}
}
return true;
}

View File

@ -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_