1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-02-20 13:54:14 +01:00

merged 1.6.0 -> trunk

--HG--
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40456
This commit is contained in:
David Anderson 2007-10-04 20:15:25 +00:00
parent afbd6cc123
commit 6fea65ae4b
61 changed files with 5313 additions and 4862 deletions

View File

@ -1,6 +1,6 @@
[PRODUCT]
major = 1
minor = 5
minor = 6
revision = 0
[sourcemm]

View File

@ -1,662 +0,0 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
#include "convar_smm.h"
#include "CSmmAPI.h"
#include "sourcemm.h"
#include "concommands.h"
#include "CPlugin.h"
#include "vsp_listener.h"
/**
* @brief Implementation of main API interface
* @file CSmmAPI.cpp
*/
using namespace SourceMM;
CSmmAPI g_SmmAPI;
CSmmAPI::CSmmAPI()
{
m_ConPrintf = NULL;
m_CmdCache = false;
m_MsgCount = -1;
m_VSP = false;
}
CSmmAPI::~CSmmAPI()
{
m_UserMessages.RemoveAll();
}
void CSmmAPI::LogMsg(ISmmPlugin *pl, const char *msg, ...)
{
va_list ap;
static char buffer[2048];
va_start(ap, msg);
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
va_end(ap);
LogMessage("[%s] %s", pl->GetLogTag(), buffer);
}
CreateInterfaceFn CSmmAPI::engineFactory(bool syn)
{
if (syn)
return EngineFactory;
return g_Engine.engineFactory;
}
CreateInterfaceFn CSmmAPI::physicsFactory(bool syn)
{
if (syn)
return PhysicsFactory;
return g_Engine.physicsFactory;
}
CreateInterfaceFn CSmmAPI::fileSystemFactory(bool syn)
{
if (syn)
return FileSystemFactory;
return g_Engine.fileSystemFactory;
}
CreateInterfaceFn CSmmAPI::serverFactory(bool syn)
{
if (syn)
return CreateInterface;
return g_GameDll.factory;
}
CGlobalVars *CSmmAPI::pGlobals()
{
return g_Engine.pGlobals;
}
void CSmmAPI::SetLastMetaReturn(META_RES res)
{
m_Res = res;
}
META_RES CSmmAPI::GetLastMetaReturn()
{
return m_Res;
}
IConCommandBaseAccessor *CSmmAPI::GetCvarBaseAccessor()
{
return static_cast<IConCommandBaseAccessor *>(&g_SMConVarAccessor);
}
bool CSmmAPI::RegisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand)
{
if (pCommand->IsCommand())
{
g_PluginMngr.AddPluginCmd(plugin, pCommand);
} else {
g_PluginMngr.AddPluginCvar(plugin, pCommand);
}
return g_SMConVarAccessor.Register(pCommand);
}
void CSmmAPI::UnregisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand)
{
if (pCommand->IsCommand())
{
g_PluginMngr.RemovePluginCmd(plugin, pCommand);
} else {
g_PluginMngr.RemovePluginCvar(plugin, pCommand);
}
g_SMConVarAccessor.Unregister(g_PluginMngr.FindByAPI(plugin)->m_Id, pCommand);
}
void CSmmAPI::ConPrint(const char *fmt)
{
(m_ConPrintf)("%s", fmt);
}
void CSmmAPI::ConPrintf(const char *fmt, ...)
{
va_list ap;
static char buffer[4096];
va_start(ap, fmt);
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
(m_ConPrintf)("%s", buffer);
}
void CSmmAPI::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener)
{
CPluginManager::CPlugin *pl = g_PluginMngr.FindByAPI(plugin);
pl->m_Events.push_back(pListener);
}
void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
{
if (id)
{
*id = 0;
}
if (!iface)
{
return NULL;
}
//first check ours... we get first chance!
if (strcmp(iface, MMIFACE_SOURCEHOOK) == 0)
{
if (_ret)
{
*_ret = IFACE_OK;
}
return static_cast<void *>(static_cast<SourceHook::ISourceHook *>(&g_SourceHook));
} else if (strcmp(iface, MMIFACE_PLMANAGER) == 0) {
if (_ret)
{
*_ret = IFACE_OK;
}
return static_cast<void *>(static_cast<ISmmPluginManager *>(&g_PluginMngr));
}
CPluginManager::CPlugin *pl;
SourceHook::List<IMetamodListener *>::iterator event;
IMetamodListener *api;
int ret = 0;
void *val = NULL;
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++)
{
pl = (*iter);
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++)
{
api = (*event);
ret = IFACE_FAILED;
if ( (val=api->OnMetamodQuery(iface, &ret)) != NULL )
{
if (_ret)
*_ret = ret;
if (id)
*id = pl->m_Id;
return val;
}
}
}
if (_ret)
*_ret = IFACE_FAILED;
return NULL;
}
//////////////////////////////////////////////////////////////////////////
//THERE BE HAX HERE!!!! DON'T TELL ALFRED, BUT GABE WANTED IT THAT WAY. //
// (note: you can find the offset by looking for the text //
// "Echo text to console", you'll find the callback cmd pushed on the //
// stack.) //
//////////////////////////////////////////////////////////////////////////
#define SIGLEN 8
#define ENGINE486_SIG "\x55\x89\xE5\x53\x83\xEC\x14\xBB"
#define ENGINE486_OFFS 40
#define ENGINE686_SIG "\x53\x83\xEC\x08\xBB\x01\x00\x00"
#define ENGINE686_OFFS 50
#define ENGINEAMD_SIG "\x53\x51\xBB\x01\x00\x00\x00\x51"
#define ENGINEAMD_OFFS 47
#define ENGINEW32_SIG "\xA1\x2A\x2A\x2A\x2A\x56\xBE\x01"
#define ENGINEW32_OFFS 38
#define IA32_CALL 0xE8
bool vcmp(const void *_addr1, const void *_addr2, size_t len)
{
unsigned char *addr1 = (unsigned char *)_addr1;
unsigned char *addr2 = (unsigned char *)_addr2;
for (size_t i=0; i<len; i++)
{
if (addr2[i] == '*')
continue;
if (addr1[i] != addr2[i])
return false;
}
return true;
}
//Thanks to fysh for the idea of extracting info from "echo" and for
// having the original offsets at hand!
bool CSmmAPI::CacheCmds()
{
ICvar *pCvar = g_Engine.icvar;
ConCommandBase *pBase = pCvar->GetCommands();
unsigned char *ptr = NULL;
FnCommandCallback callback = NULL;
int offs = 0;
while (pBase)
{
if ( strcmp(pBase->GetName(), "echo") == 0 )
{
//callback = //*((FnCommandCallback *)((char *)pBase + offsetof(ConCommand, m_fnCommandCallback)));
callback = ((ConCommand *)pBase)->GetCallback();
ptr = (unsigned char *)callback;
#ifdef OS_LINUX
if (vcmp(ptr, ENGINE486_SIG, SIGLEN))
{
offs = ENGINE486_OFFS;
}
else if (vcmp(ptr, ENGINE686_SIG, SIGLEN))
{
offs = ENGINE686_OFFS;
}
else if (vcmp(ptr, ENGINEAMD_SIG, SIGLEN))
{
offs = ENGINEAMD_OFFS;
}
#elif defined OS_WIN32 // Only one Windows engine binary so far...
if (vcmp(ptr, ENGINEW32_SIG, SIGLEN))
{
offs = ENGINEW32_OFFS;
}
#endif
if (!offs || ptr[offs - 1] != IA32_CALL)
{
m_ConPrintf = (CONPRINTF_FUNC)Msg;
return false;
}
//get the relative offset
m_ConPrintf = *((CONPRINTF_FUNC *)(ptr + offs));
//add the base offset, to the ip (which is the address+offset + 4 bytes for next instruction)
m_ConPrintf = (CONPRINTF_FUNC)((unsigned long)m_ConPrintf + (unsigned long)(ptr + offs) + 4);
m_CmdCache = true;
return true;
}
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
}
m_ConPrintf = (CONPRINTF_FUNC)Msg;
return false;
}
bool CSmmAPI::CmdCacheSuccessful()
{
return m_CmdCache;
}
void CSmmAPI::GetApiVersions(int &major, int &minor, int &plvers, int &plmin)
{
major = SM_VERS_API_MAJOR;
minor = SM_VERS_API_MINOR;
plvers = PLAPI_VERSION;
plmin = PLAPI_MIN_VERSION;
}
void CSmmAPI::GetShVersions(int &shvers, int &shimpl)
{
shvers = SH_IFACE_VERSION;
shimpl = SH_IMPL_VERSION;
}
int CSmmAPI::FormatIface(char iface[], unsigned int maxlength)
{
int length = (int)strlen(iface);
int i;
int num = 0;
for (i = length - 1; i >= 0; i--)
{
if (!isdigit(iface[i]))
{
if (i != length - 1)
{
num = 1;
}
break;
}
}
if ( (num && ((int)maxlength <= length)) || (!num && ((int)maxlength <= length + 3)) )
{
return -1;
}
if (i != length - 1)
num = atoi(&(iface[++i]));
num++;
snprintf(&(iface[i]), 4, "%03d", num);
return num;
}
void *CSmmAPI::InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, int *ret)
{
char _if[256]; /* assume no interface goes beyond this */
size_t len = strlen(iface);
int num = 0;
void *pf = NULL;
if (max > 999)
max = 999;
if (len + 4 > sizeof(_if))
{
if (ret)
{
*ret = IFACE_FAILED;
}
return NULL;
}
strcpy(_if, iface);
do
{
if ( (pf = (fn)(_if, ret)) != NULL )
break;
if (num > max)
break;
} while (( num = FormatIface(_if, len+1) ));
return pf;
}
void *CSmmAPI::VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min)
{
char buffer[256]; /* assume no interface will go beyond this */
size_t len = strlen(iface);
int ret; /* just in case something doesn't handle NULL properly */
if (len > sizeof(buffer) - 4)
{
return NULL;
}
strcpy(buffer, iface);
if (min != -1)
{
char *ptr = &buffer[len - 1];
int digits = 0;
while (isdigit(*ptr) && digits <=3)
{
*ptr = '\0';
digits++;
ptr--;
}
if (digits != 3)
{
/* for now, assume this is an error */
strcpy(buffer, iface);
} else {
char num[4];
min = (min == 0) ? 1 : min;
snprintf(num, sizeof(num), "%03d", min);
strcat(buffer, num);
}
}
return InterfaceSearch(fn, buffer, IFACE_MAXNUM, &ret);
}
const char *CSmmAPI::GetBaseDir()
{
return g_ModPath.c_str();
}
void CSmmAPI::PathFormat(char *buffer, size_t len, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
size_t mylen = UTIL_FormatArgs(buffer, len, fmt, ap);
va_end(ap);
for (size_t i = 0; i < mylen; i++)
{
if (buffer[i] == ALT_SEP_CHAR)
{
buffer[i] = PATH_SEP_CHAR;
}
}
}
void CSmmAPI::ClientConPrintf(edict_t *client, const char *fmt, ...)
{
va_list ap;
static char buffer[4096];
va_start(ap, fmt);
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
g_Engine.engine->ClientPrintf(client, buffer);
}
void CSmmAPI::LoadAsVSP()
{
size_t len;
char engine_file[PATH_SIZE];
char engine_path[PATH_SIZE];
char rel_path[PATH_SIZE * 2];
GetFileOfAddress(g_Engine.engine, engine_file, sizeof(engine_file));
/* Chop off the "engine" file part */
len = strlen(engine_file);
for (size_t i = len - 1; i >= 0 && i < len; i--)
{
if (engine_file[i] == '/'
|| engine_file[i] == '\\')
{
engine_file[i] = '\0';
break;
}
}
abspath(engine_path, engine_file);
const char *usepath = g_SmmPath.c_str();
if (UTIL_Relatize(rel_path, sizeof(rel_path), engine_path, g_SmmPath.c_str()))
{
usepath = rel_path;
}
char command[PATH_SIZE * 2];
g_VspListener.SetLoadable(true);
UTIL_Format(command, sizeof(command), "plugin_load \"%s\"\n", usepath);
g_Engine.engine->ServerCommand(command);
}
void CSmmAPI::EnableVSPListener()
{
/* If GameInit already passed and we're not already enabled or loaded, go ahead and LoadAsVSP load */
if (bGameInit && !m_VSP && !g_VspListener.IsLoaded())
{
LoadAsVSP();
}
m_VSP = true;
}
int CSmmAPI::GetGameDLLVersion()
{
return g_GameDllVersion;
}
//////////////////////////////////////////////////////////////////////
// EVEN MORE HACKS HERE! YOU HAVE BEEN WARNED! //
// Signatures necessary in finding the pointer to the CUtlDict that //
// stores user message information. //
// IServerGameDLL::GetUserMessageInfo() normally crashes with bad //
// message indices. This is our answer to it. Yuck! <:-( //
//////////////////////////////////////////////////////////////////////
#ifdef OS_WIN32
/* General Windows sig */
#define MSGCLASS_SIGLEN 7
#define MSGCLASS_SIG "\x8B\x0D\x2A\x2A\x2A\x2A\x56"
#define MSGCLASS_OFFS 2
/* Dystopia Wimdows hack */
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x56\x8B\x74\x24\x2A\x85\xF6\x7C\x2A\x3B\x35\x2A\x2A\x2A\x2A\x7D"
#define MSGCLASS2_OFFS 11
/* Windows frame pointer sig */
#define MSGCLASS3_SIGLEN 18
#define MSGCLASS3_SIG "\x55\x8B\xEC\x51\x89\x2A\x2A\x8B\x2A\x2A\x50\x8B\x0D\x2A\x2A\x2A\x2A\xE8"
#define MSGCLASS3_OFFS 13
#elif defined OS_LINUX
/* No frame pointer sig */
#define MSGCLASS_SIGLEN 14
#define MSGCLASS_SIG "\x53\x83\xEC\x2A\x8B\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x89"
#define MSGCLASS_OFFS 9
/* Frame pointer sig */
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x55\x89\xE5\x53\x83\xEC\x2A\x8B\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x89"
#define MSGCLASS2_OFFS 11
#endif
/* This is the ugliest function in all of SourceMM */
/* :TODO: Make this prettier */
bool CSmmAPI::CacheUserMessages()
{
/* Get address of original GetUserMessageInfo() */
char *vfunc = (char *)SH_GET_ORIG_VFNPTR_ENTRY(g_GameDll.pGameDLL, &IServerGameDLL::GetUserMessageInfo);
/* Oh dear, we have a relative jump on our hands
* PVK II on Windows made me do this, but I suppose it doesn't hurt to check this on Linux too...
*/
if (*vfunc == '\xE9')
{
/* Get address from displacement...
*
* Add 5 because it's relative to next instruction:
* Opcode <1 byte> + 32-bit displacement <4 bytes>
*/
vfunc += *reinterpret_cast<int *>(vfunc + 1) + 5;
}
UserMsgDict *dict = NULL;
if (vcmp(vfunc, MSGCLASS_SIG, MSGCLASS_SIGLEN))
{
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
} else if (vcmp(vfunc, MSGCLASS2_SIG, MSGCLASS2_SIGLEN)) {
#ifdef OS_WIN32
/* If we get here, the code is possibly inlined like in Dystopia */
/* Get the address of the CUtlRBTree */
char *rbtree = *reinterpret_cast<char **>(vfunc + MSGCLASS2_OFFS);
/* CUtlDict should be 8 bytes before the CUtlRBTree (hacktacular!) */
dict = reinterpret_cast<UserMsgDict *>(rbtree - 8);
#elif defined OS_LINUX
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS2_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
#ifdef OS_WIN32
} else if (vcmp(vfunc, MSGCLASS3_SIG, MSGCLASS3_SIGLEN)) {
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS3_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
}
if (dict)
{
m_MsgCount = dict->Count();
/* Ensure that count is within bounds of an unsigned byte, because that's what engine supports */
if (m_MsgCount < 0 || m_MsgCount > 255)
{
m_MsgCount = -1;
return false;
}
UserMessage *msg;
/* Cache messages in our CUtlDict */
for (int i = 0; i < m_MsgCount; i++)
{
msg = dict->Element(i);
m_UserMessages.Insert(msg->name, msg);
}
return true;
}
return false;
}
bool CSmmAPI::MsgCacheSuccessful()
{
return m_MsgCount > -1;
}
int CSmmAPI::GetUserMessageCount()
{
return m_MsgCount;
}
int CSmmAPI::FindUserMessage(const char *name, int *size)
{
int index = m_UserMessages.Find(name);
if (size && index > -1)
{
UserMessage *msg = m_UserMessages.Element(index);
*size = msg->size;
}
return index;
}
const char *CSmmAPI::GetUserMessage(int index, int *size)
{
if (m_MsgCount <= 0 || index < 0 || index >= m_MsgCount)
{
return NULL;
}
UserMessage *msg = m_UserMessages.Element(index);
if (size)
{
*size = msg->size;
}
return msg->name;
}
int CSmmAPI::GetVSPVersion()
{
return g_VspVersion;
}

View File

@ -1,99 +0,0 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
#ifndef _INCLUDE_CSMM_API_H
#define _INCLUDE_CSMM_API_H
/**
* @brief Header for CSmmAPI implementation
* @file CSmmAPI.h
*/
#include "ISmmAPI.h"
#include <tier1/utldict.h>
struct UserMessage
{
int size;
const char *name;
};
typedef CUtlDict<UserMessage *, int> UserMsgDict;
typedef void (*CONPRINTF_FUNC)(const char *, ...);
namespace SourceMM
{
class CSmmAPI : public ISmmAPI
{
public:
CSmmAPI();
~CSmmAPI();
public:
void LogMsg(ISmmPlugin *pl, const char *msg, ...);
public:
CreateInterfaceFn engineFactory(bool syn=true);
CreateInterfaceFn physicsFactory(bool syn=true);
CreateInterfaceFn fileSystemFactory(bool syn=true);
CreateInterfaceFn serverFactory(bool syn=true);
CGlobalVars *pGlobals();
void SetLastMetaReturn(META_RES res);
META_RES GetLastMetaReturn();
IConCommandBaseAccessor *GetCvarBaseAccessor();
bool RegisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand);
void UnregisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand);
void ConPrint(const char *fmt);
void ConPrintf(const char *fmt, ...);
bool RemotePrintingAvailable()
{
return CmdCacheSuccessful();
}
virtual void GetApiVersions(int &major, int &minor, int &plvers, int &plmin);
virtual void GetShVersions(int &shvers, int &shimpl);
virtual void AddListener(ISmmPlugin *plugin, IMetamodListener *pListener);
virtual void *MetaFactory(const char *iface, int *ret, PluginId *id);
virtual int FormatIface(char buffer[], unsigned int maxlength);
virtual void *InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, int *ret);
virtual const char *GetBaseDir();
virtual void PathFormat(char *buffer, size_t len, const char *fmt, ...);
void ClientConPrintf(edict_t *client, const char *fmt, ...);
void *VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min=-1);
void EnableVSPListener();
int GetGameDLLVersion();
int GetUserMessageCount();
int FindUserMessage(const char *name, int *size=NULL);
const char *GetUserMessage(int index, int *size=NULL);
int GetVSPVersion();
public:
bool CacheCmds();
bool CmdCacheSuccessful();
void LoadAsVSP();
bool VSPEnabled()
{
return m_VSP;
}
bool CacheUserMessages();
bool MsgCacheSuccessful();
private:
META_RES m_Res;
CONPRINTF_FUNC m_ConPrintf;
bool m_CmdCache;
bool m_VSP;
int m_MsgCount;
UserMsgDict m_UserMessages;
};
};
extern SourceMM::CSmmAPI g_SmmAPI;
#define CONMSG g_SmmAPI.ConPrintf
#define CLIENT_CONMSG g_SmmAPI.ClientConPrintf
#endif //_INCLUDE_CSMM_API_H

View File

@ -1,12 +1,29 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_PLUGINMANAGER_H
#define _INCLUDE_PLUGINMANAGER_H

View File

@ -1,12 +1,29 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_ISMM_API_H
#define _INCLUDE_ISMM_API_H
@ -18,7 +35,7 @@
#include <interface.h>
#include <eiface.h>
#include <sourcehook/sourcehook.h>
#include <sourcehook.h>
#include "IPluginManager.h"
#if defined __GNUC__
@ -33,7 +50,12 @@ class ISmmPlugin;
#define MMIFACE_SOURCEHOOK "ISourceHook" /**< ISourceHook Pointer */
#define MMIFACE_PLMANAGER "IPluginManager" /**< SourceMM Plugin Functions */
#define IFACE_MAXNUM 999
#define IFACE_MAXNUM 999 /**< Maximum interface version */
#define SOURCE_ENGINE_UNKNOWN 0 /**< Could not determine the engine version */
#define SOURCE_ENGINE_ORIGINAL 1 /**< Original Source Engine (used by The Ship) */
#define SOURCE_ENGINE_EPISODEONE 2 /**< Episode 1 Source Engine (second major SDK) */
#define SOURCE_ENGINE_ORANGEBOX 3 /**< Orange Box Source Engine (third major SDK) */
class ISmmAPI
{
@ -119,7 +141,7 @@ public: // Added in 1.00-RC2 (0:0)
*
* @param plugin Parent plugin API pointer.
* @param pCommand ConCommandBase to register.
* @return True if successful, false otherwise. Does not return false yet.
* @return True if successful, false otherwise.
*/
virtual bool RegisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand) =0;
@ -133,6 +155,7 @@ public: // Added in 1.00-RC2 (0:0)
/**
* @brief Prints an unformatted string to the remote server console.
*
* Note: Newlines are not added automatically.
*
* @param str Message string.
@ -141,6 +164,7 @@ public: // Added in 1.00-RC2 (0:0)
/**
* @brief Prints a formatted message to the remote server console.
*
* Note: Newlines are not added automatically.
*
* @param fmt Formatted message.
@ -205,9 +229,9 @@ public: // Added in 1.1.2 (1:1)
*/
virtual int FormatIface(char iface[], unsigned int maxlength) =0;
public: // Added in 1.2.0 (1:2)
public: // Added in 1.2 (1:2)
/**
* @brief Searches for an interface for you.
* @brief Searches for an interface, eliminating the need to loop through FormatIface().
*
* @param fn InterfaceFactory function.
* @param iface Interface string name.
@ -219,15 +243,17 @@ public: // Added in 1.2.0 (1:2)
/**
* @brief Returns the base directory of the game/server, equivalent to
* IVEngineServer::GetGameDir(), except the path is absolute.
* IVEngineServer::GetGameDir(), except the path is absolute.
*
* @return Static pointer to game's absolute basedir.
*/
virtual const char *GetBaseDir() =0;
/**
* @brief Formats a file path to the local OS. Does not include any base directories.
* Note that all slashes and black slashes are reverted to the local OS's expectancy.
* @brief Formats a file path to the local OS.
*
* Does not include any base directories. Note that all slashes and black
* slashes are reverted to the local OS's expectancy.
*
* @param buffer Destination buffer to store path.
* @param len Maximum length of buffer, including null terminator.
@ -237,15 +263,15 @@ public: // Added in 1.2.0 (1:2)
public: // Added in 1.2.2 (1:3)
/**
* @brief Prints text in the specified client's console. Same as IVEngineServer::ClientPrintf
* except that it allows for string formatting.
* @brief Prints text in the specified client's console. Same as
* IVEngineServer::ClientPrintf except that it allows for string formatting.
*
* @param client Client edict pointer.
* @param fmt Formatted string to print to the client.
*/
virtual void ClientConPrintf(edict_t *client, const char *fmt, ...) =0;
public: // Added in 1.3.0 (1:4)
public: // Added in 1.3 (1:4)
/**
* @brief Wrapper around InterfaceSearch(). Assumes no maximum.
* This is designed to replace the fact that searches only went upwards.
@ -253,27 +279,34 @@ public: // Added in 1.3.0 (1:4)
*
* @param fn Interface factory function.
* @param iface Interface string.
* @param min Minimum value to search from. If zero, searching begins from the
* first available version regardless of the interface.
* Note that this can return interfaces EARLIER than the version specified.
* A value of -1 (default) specifies the string version as the minimum.
* Any other value specifices the minimum value to search from.
* @param min Minimum value to search from. If zero, searching
* begins from the first available version regardless
* of the interface. Note that this can return
* interfaces EARLIER than the version specified. A
* value of -1 (default) specifies the string version
* as the minimum. Any other value specifices the
* minimum value to search from.
* @return Interface pointer, or NULL if not found.
*/
virtual void *VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min=-1) =0;
public: // Added in 1.4.0 (1:5)
public: // Added in 1.4 (1:5)
/**
* @brief Tells SourceMM to add VSP hooking capability to plugins.
*
* Since this potentially uses more resources than it would otherwise, plugins have to
* explicitly enable the feature. Whether requested or not, if it is enabled, all plugins
* will get a pointer to the VSP listener through IMetamodListener.
* Since this potentially uses more resources than it would otherwise,
* plugins have to explicitly enable the feature. Whether requested or
* not, if it is enabled, all plugins will get a pointer to the VSP
* listener through IMetamodListener. This will not be called more than
* once for a given plugin; if it is requested more than once, each
* successive call will only give the pointer to plugins which have not
* yet received it.
*/
virtual void EnableVSPListener() =0;
/**
* @brief Returns the interface version of the GameDLL's IServerGameDLL implementation.
* @brief Returns the interface version of the GameDLL's IServerGameDLL
* implementation.
*
* @return Interface version of the loaded IServerGameDLL.
*/
@ -282,7 +315,8 @@ public: // Added in 1.4.0 (1:5)
/**
* @brief Returns the number of user messages in the GameDLL.
*
* @return Number of user messages, or -1 if SourceMM has failed to get user message list.
* @return Number of user messages, or -1 if SourceMM has
* failed to get user message list.
*/
virtual int GetUserMessageCount() =0;
@ -303,15 +337,42 @@ public: // Added in 1.4.0 (1:5)
* @return Message name, or NULL on failure.
*/
virtual const char *GetUserMessage(int index, int *size=NULL) =0;
public: // Added in 1.5.0 (1:6)
/**
* @brief Returns the highest interface version of IServerPluginCallbacks that the engine supports.
* This is useful for games that run on older versions of the Source engine, such as The Ship.
* @brief Returns the highest interface version of IServerPluginCallbacks
* that the engine supports. This is useful for games that run on older
* versions of the Source engine, such as The Ship.
*
* @return Highest interface version of IServerPluginCallbacks.
* Returns 0 if SourceMM's VSP listener isn't currently enabled.
* Returns 0 if SourceMM's VSP listener isn't currently
* enabled.
*/
virtual int GetVSPVersion() =0;
public: // Added in 1.6.0 (1:7)
/**
* @brief Returns the engine interface that MM:S is using as a backend.
*
* The values will be one of the SOURCE_ENGINE_* constants from the top
* of this file.
*
* @return A SOURCE_ENGINE_* constant value.
*/
virtual int GetSourceEngineBuild() =0;
/**
* @brief Returns the VSP listener loaded.
*
* This is useful for late-loading plugins which need to decide whether
* to add a listener or not (or need to get the pointer at all).
*
* @param Optional pointer to store the VSP version.
* @return IServerPluginCallbacks pointer, or NULL if an
* IMetamodListener event has yet to occur for
* EnableVSPListener().
*/
virtual IServerPluginCallbacks *GetVSPInfo(int *pVersion) =0;
};
@ -320,11 +381,13 @@ public: // Added in 1.5.0 (1:6)
*
* 1.1.0 Bumped API to 1:0. The breaking changes occurred in SourceHook and the plugin API.
* 1.1.2 Added API call for generating iface names.
* 1.2.0 Added API more helper functions and new SourceHook version.
* 1.2 Added API more helper functions and new SourceHook version.
* 1.2.2 Added API for printing to client console (with string formatting).
* 1.3.0 Added new interface search API.
* 1.4.0 Added VSP listener and user message API.
* 1.3 Added new interface search API.
* 1.4 Added VSP listener and user message API.
* 1.5.0 Added API for getting highest supported version of IServerPluginCallbacks.
* 1.6.0 Added API for Orange Box.
*/
#endif //_INCLUDE_ISMM_API_H

View File

@ -1,12 +1,29 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_ISMM_PLUGIN_H
#define _INCLUDE_ISMM_PLUGIN_H
@ -17,7 +34,7 @@
*/
#include <interface.h>
#include <sourcehook/sourcehook.h>
#include <sourcehook.h>
#include "ISmmAPI.h"
#define PLAPI_VERSION 12
@ -33,6 +50,7 @@ public:
public:
/**
* @brief Called on plugin load.
*
* NOTE - As of API 7, this is called as DLLInit() executes - after the parameters are known, but before
* the original GameDLL function is called. Therefore, you cannot hook it, but you don't need to -
* Load() is basically your hook.
@ -40,22 +58,24 @@ public:
* However, take care to note that if your plugin is unloaded, and the gamedll/engine have cached
* an interface you've passed, something will definitely crash. Be careful.
*
* @param id Internal id of plugin. Saved globally by PLUGIN_SAVEVARS()
* @param ismm External API for SourceMM. Saved globally by PLUGIN_SAVEVARS()
* @param list Contains a list of factories. Hook a factory call by setting one equal to your own function.
* @param late Set to true if your plugin was loaded late (not at server load).
* @param error Error message buffer
* @param maxlen Size of error message buffer
* @return True if successful, return false to reject the load.
* @param id Internal id of plugin. Saved globally by PLUGIN_SAVEVARS()
* @param ismm External API for SourceMM. Saved globally by PLUGIN_SAVEVARS()
* @param list Contains a list of factories. Hook a factory call by setting one equal to your own function.
* @param late Set to true if your plugin was loaded late (not at server load).
* @param error Error message buffer
* @param maxlen Size of error message buffer
* @return True if successful, return false to reject the load.
*/
virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late) =0;
/**
* @brief Called when your plugin is "queried". This is useful for rejecting a loaded
* state. For example, if your plugin wants to stop operating, it can simply return
* false and copy an error message. This will notify other plugins or MM:S of something
* bad that happened. NOTE - MM:S will not cache the return state, so if you return false,
* your plugin will not actually be paused or unloaded. This callback will be called when:
* @brief Called when your plugin is "queried".
*
* This is useful for rejecting a loaded state. For example, if your plugin wants
* to stop operating, it can simply return false and copy an error message. This
* will notify other plugins or MM:S of something bad that happened. NOTE - MM:S
* will not cache the return state, so if you return false, your plugin will not
* actually be paused or unloaded. This callback will be called when:
* - Another plugin requests it
* - Someone types "meta list", it will show up as "REFUSED"
* - When Metamod need to re-check the plugin's status
@ -132,10 +152,11 @@ public:
virtual const char *GetLogTag() =0;
public:
/**
* @brief Called when all plugins have been loaded - API version 4
* @brief Called when all plugins have been loaded.
*
* This is useful for knowing when it's safe to request things another plugin might have.
* NOTE for API 7 - This is called after DLLInit().
* This is called after DLLInit(), and thus the mod has been mostly initialized.
* It is also safe to assume that all other (automatically loaded) plugins are now
* ready to start interacting, because they are all loaded.
*/
virtual void AllPluginsLoaded()
{
@ -148,35 +169,45 @@ public:
class IMetamodListener
{
public:
virtual ~IMetamodListener() { }
virtual ~IMetamodListener()
{
}
public:
/**
* @brief Called when a plugin is loaded.
*
* @param id Id of the plugin.
*/
virtual void OnPluginLoad(PluginId id) { }
virtual void OnPluginLoad(PluginId id)
{
}
/**
* @brief Called when a plugin is unloaded.
*
* @param id Id of the plugin.
*/
virtual void OnPluginUnload(PluginId id) { }
virtual void OnPluginUnload(PluginId id)
{
}
/**
* @brief Called when a plugin is paused.
*
* @param id Id of the plugin.
*/
virtual void OnPluginPause(PluginId id) { }
virtual void OnPluginPause(PluginId id)
{
}
/**
* @brief Called when a plugin is unpaused.
*
* @param id Id of the plugin.
*/
virtual void OnPluginUnpause(PluginId id) { }
virtual void OnPluginUnpause(PluginId id)
{
}
/**
* @brief Called when the level is loaded (after GameInit, before ServerActivate).
@ -195,7 +226,9 @@ public:
/**
* @brief Called when the level is shut down. May be called more than once.
*/
virtual void OnLevelShutdown() { }
virtual void OnLevelShutdown()
{
}
/**
* @brief Called when engineFactory() is used through Metamod:Source's wrapper.
@ -308,7 +341,8 @@ public:
* This callback is provided to all plugins regardless of which (or how many)
* called EnableVSPListener(), but only if at least one did in fact enable it.
*
* This callback is only available for plugins using API v1:5 (SourceMM 1.4+).
* This callback is only available for plugins using API v1:5 (Metamod:Source 1.4+).
* If a plugin loads lately, it may still call EnableVSPListener().
*
* @param iface Interface pointer. If NULL, then the VSP listening construct
* failed to initialize and is not available.
@ -322,6 +356,17 @@ public:
* @param pCommand Pointer to concommand or convar that is being removed.
*/
virtual void OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand) { }
/**
* @brief Called when Metamod:Source is about to remove a concommand or convar.
* This can also be called if ISmmAPI::UnregisterConCmdBase is used by a plugin.
*
* @param id Id of the plugin that created the concommand or convar.
* @param pCommand Pointer to concommand or convar that is being removed.
*/
virtual void OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand)
{
}
};
#define PL_EXPOSURE CreateInterface
@ -413,3 +458,4 @@ public:
}
#endif //_INCLUDE_ISMM_PLUGIN_H

View File

@ -1,7 +1,7 @@
#(C)2004-2007 SourceMM Development Team
# Makefile written by David "BAILOPAN" Anderson
HL2SDK = ../../hl2sdk
HL2SDK = ../../../hl2sdk
SMM_ROOT = ..
SRCDS = ~/srcds
@ -16,10 +16,10 @@ BINARY = server_i486.so
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/linux_sdk
OBJECTS = oslink.cpp util.cpp concommands.cpp CSmmAPI.cpp \
sourcemm.cpp CPlugin.cpp sourcehook.cpp vsp_listener.cpp
OBJECTS = metamod.cpp metamod_util.cpp metamod_console.cpp metamod_oslink.cpp metamod_plugins.cpp \
sourcehook.cpp episode1/console.cpp episode1/provider_ep1.cpp episode1/vsp_listener.cpp
LINK = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc
LINK = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc
INCLUDE = -I. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_ROOT) -I$(SMM_ROOT)/sourcehook
@ -34,7 +34,9 @@ endif
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \
-Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca \
-Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
ifeq "$(GCC_VERSION)" "4"
CFLAGS += $(GCC4_FLAGS)
@ -47,10 +49,11 @@ $(BIN_DIR)/%.o: %.cpp
all:
mkdir -p $(BIN_DIR)
mkdir -p $(BIN_DIR)/episode1
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
ln -sf $(SMM_ROOT)/sourcehook/sourcehook.cpp sourcehook.cpp
$(MAKE) sourcemm
$(MAKE) -f Makefile.ep1 sourcemm
rm -rf $(BINARY)
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
@ -58,12 +61,15 @@ sourcemm: $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
debug:
$(MAKE) all DEBUG=true
$(MAKE) -f Makefile.ep1 all DEBUG=true
default: all
clean:
rm -rf Release/episode1/*.o
rm -rf Release/*.o
rm -rf Release/$(BINARY)
rm -rf Debug/episode1/*.o
rm -rf Debug/*.o
rm -rf Debug/$(BINARY)

View File

@ -1,26 +1,29 @@
#(C)2004-2007 SourceMM Development Team
# Makefile written by David "BAILOPAN" Anderson
HL2SDK = ../../../hl2sdk
SMM_ROOT = ../..
HL2SDK = ../../../hl2sdk-ob
SMM_ROOT = ..
SRCDS = ~/srcds
### EDIT BELOW FOR OTHER PROJECTS ###
OPT_FLAGS = -O3 -funroll-loops -s -pipe
OPT_FLAGS = -O2 -funroll-loops -s -pipe
GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden
DEBUG_FLAGS = -g -ggdb3
CPP = gcc-4.1
BINARY = stub_mm_i486.so
BINARY = server_i486.so
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/linux_sdk
OBJECTS = stub_mm.cpp
OBJECTS = metamod.cpp metamod_util.cpp metamod_console.cpp metamod_oslink.cpp metamod_plugins.cpp \
sourcehook.cpp episode2/console.cpp episode2/provider_ep2.cpp episode2/vsp_listener.cpp \
episode2/convar.cpp
LINK = vstdlib_i486.so tier0_i486.so -static-libgcc
INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_ROOT) -I$(SMM_ROOT)/sourcehook -I$(SMM_ROOT)/sourcemm
INCLUDE = -I. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_ROOT) -I$(SMM_ROOT)/sourcehook
ifeq "$(DEBUG)" "true"
BIN_DIR = Debug
@ -32,7 +35,10 @@ endif
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \
-Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca \
-Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse \
-fno-strict-aliasing
ifeq "$(GCC_VERSION)" "4"
CFLAGS += $(GCC4_FLAGS)
@ -45,9 +51,12 @@ $(BIN_DIR)/%.o: %.cpp
all:
mkdir -p $(BIN_DIR)
mkdir -p $(BIN_DIR)/episode2
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
$(MAKE) sourcemm
ln -sf $(SMM_ROOT)/sourcehook/sourcehook.cpp sourcehook.cpp
ln -sf $(HL2SDK)/tier1/convar.cpp episode2/convar.cpp
$(MAKE) -f Makefile.ep2 sourcemm
rm -rf $(BINARY)
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
@ -55,12 +64,15 @@ sourcemm: $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
debug:
$(MAKE) all DEBUG=true
$(MAKE) -f Makefile.ep2 all DEBUG=true
default: all
clean:
rm -rf Release/episode2/*.o
rm -rf Release/*.o
rm -rf Release/$(BINARY)
rm -rf Debug/episode2/*.o
rm -rf Debug/*.o
rm -rf Debug/$(BINARY)

View File

@ -1,257 +0,0 @@
# Doxyfile 1.4.2
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = SourceMM
PROJECT_NUMBER = 1.00
OUTPUT_DIRECTORY = c:\temp\smm-dox
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = YES
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH = "C:/Documents and Settings/dvander.WHITENIGHT/Desktop/code/"
STRIP_FROM_INC_PATH =
SHORT_NAMES = YES
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 8
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = NO
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 38
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = "C:/Documents and Settings/dvander.WHITENIGHT/Desktop/code/sourcemm"
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.d \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.idl \
*.odl \
*.cs \
*.php \
*.php3 \
*.inc \
*.m \
*.mm \
*.dox
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS = test \
sample_mm
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = NO
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = NO
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = YES

View File

@ -1,11 +1,6 @@
2007/??/?? 1.5.0:
- Added new version of SourceHook with the following changes:
- Added API for hooking functions on a virtual table to all instances.
- SH_ADD_HOOK macros now return non-zero hook IDs. Additionally,
the old hook adding/removing syntax is deprecated (but still supported).
- Added SH_REMOVE_HOOK_ID to remove hooks by ID.
- CallClasses have been deprecated. The SH_CALL macro can now take a class
instance pointer rather than a callclass pointer.
2007/??/?? 1.6.0:
- Metamod:Source has no received a large internal rewrite to improve coding
standards and to separate internal logic from engine specifics.
- Added API for getting highest supported IServerPluginCallbacks interface
version.
- Added OnUnlinkConCommandBase to IMetamodListner to notify when Metamod:Source

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

@ -0,0 +1,169 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#include "console.h"
#include "provider_ep1.h"
using namespace SourceHook;
SMConVarAccessor g_SMConVarAccessor;
class CAlwaysRegisterableCommand : public ConCommandBase
{
public:
CAlwaysRegisterableCommand()
{
Create("metamod_eternal", NULL, FCVAR_UNREGISTERED|FCVAR_GAMEDLL);
}
bool IsRegistered( void ) const
{
return false;
}
void BringToFront()
{
// First, let's try to find us!
ConCommandBase *pPtr = icvar->GetCommands();
if (pPtr == this)
{
// We are already at the beginning; Nothing to do
return;
}
while (pPtr)
{
if (pPtr == this)
{
break;
}
ConCommandBase *pPrev = NULL;
while (pPtr)
{
if (pPtr == this)
{
break;
}
pPrev = pPtr;
pPtr = const_cast<ConCommandBase*>(pPtr->GetNext());
}
if (pPrev && pPtr == this)
{
pPrev->SetNext(m_pNext); // Remove us from the list
}
// Now, register us
SetNext(NULL);
icvar->RegisterConCommandBase(this);
}
}
} s_EternalCommand;
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
{
m_RegisteredCommands.push_back(pCommand);
pCommand->SetNext(NULL);
icvar->RegisterConCommandBase(pCommand);
return true;
}
bool SMConVarAccessor::Register(ConCommandBase *pCommand)
{
pCommand->SetNext(NULL);
icvar->RegisterConCommandBase(pCommand);
return true;
}
void SMConVarAccessor::MarkCommandsAsGameDLL()
{
for (List<ConCommandBase*>::iterator iter = m_RegisteredCommands.begin();
iter != m_RegisteredCommands.end(); ++iter)
{
(*iter)->AddFlags(FCVAR_GAMEDLL);
}
}
void SMConVarAccessor::UnregisterGameDLLCommands()
{
ConCommandBase *begin = icvar->GetCommands();
ConCommandBase *iter = begin;
ConCommandBase *prev = NULL;
while (iter)
{
/* Watch out for the ETERNAL COMMAND! */
if (iter != &s_EternalCommand && iter->IsBitSet(FCVAR_GAMEDLL))
{
/* Remove it! */
if (iter == begin)
{
s_EternalCommand.BringToFront();
iter = const_cast<ConCommandBase*>(iter->GetNext());
s_EternalCommand.SetNext(iter);
prev = &s_EternalCommand;
continue;
}
else
{
iter = const_cast<ConCommandBase*>(iter->GetNext());
prev->SetNext(iter);
continue;
}
}
prev = iter;
iter = const_cast<ConCommandBase*>(iter->GetNext());
}
}
void SMConVarAccessor::Unregister(ConCommandBase *pCommand)
{
ConCommandBase *ptr = icvar->GetCommands();
if (ptr == pCommand)
{
s_EternalCommand.BringToFront();
s_EternalCommand.SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
}
else
{
/* Find us and unregister us */
ConCommandBase *pPrev = NULL;
while (ptr)
{
if (ptr == pCommand)
{
break;
}
pPrev = ptr;
ptr = const_cast<ConCommandBase *>(ptr->GetNext());
}
if (pPrev && ptr == pCommand)
{
pPrev->SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
}
}
}

View File

@ -0,0 +1,51 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_CONSOLE_MMS_H_
#define _INCLUDE_CONSOLE_MMS_H_
#include <interface.h>
#include <eiface.h>
#include "convar_smm.h"
#include <sh_list.h>
class SMConVarAccessor : public IConCommandBaseAccessor
{
public:
bool RegisterConCommandBase(ConCommandBase *pCommand);
bool Register(ConCommandBase *pCommand);
void MarkCommandsAsGameDLL();
void Unregister(ConCommandBase *pCommand);
void UnregisterGameDLLCommands();
private:
SourceHook::List<ConCommandBase*> m_RegisteredCommands;
};
extern SMConVarAccessor g_SMConVarAccessor;
#endif //_INCLUDE_CONSOLE_MMS_H_

View File

@ -3,7 +3,7 @@
// Purpose:
//
// $Workfile: $
// $Date$
// $Date: 2007-02-08 04:19:19 -0500 (Thu, 08 Feb 2007) $
//
//-----------------------------------------------------------------------------
// $NoKeywords: $

View File

@ -2,7 +2,7 @@
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="sourcemm"
Name="metamodsource_ep1"
ProjectGUID="{F7D47743-73B3-49B5-9D76-2333C5DFD565}"
RootNamespace="sourcemm"
Keyword="Win32Proj"
@ -41,6 +41,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..;..\..\..;..\..\..\sourcehook"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@ -62,7 +63,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
AdditionalDependencies="tier1.lib tier0.lib vstdlib.lib"
OutputFile="$(OutDir)/server.dll"
LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
@ -128,6 +129,7 @@
OmitFramePointers="true"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
RuntimeTypeInfo="false"
@ -192,80 +194,12 @@
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\concommands.cpp"
>
</File>
<File
RelativePath="..\CPlugin.cpp"
>
</File>
<File
RelativePath="..\CSmmAPI.cpp"
>
</File>
<File
RelativePath="..\oslink.cpp"
>
</File>
<File
RelativePath="..\sourcemm.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
Detect64BitPortabilityProblems="false"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\util.cpp"
>
</File>
<File
RelativePath="..\vsp_listener.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\concommands.h"
>
</File>
<File
RelativePath="..\CPlugin.h"
>
</File>
<File
RelativePath="..\CSmmAPI.h"
>
</File>
<File
RelativePath="..\oslink.h"
>
</File>
<File
RelativePath="..\sourcemm.h"
>
</File>
<File
RelativePath="..\svn_version.h"
>
</File>
<File
RelativePath="..\util.h"
>
</File>
<File
RelativePath="..\vsp_listener.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
@ -273,7 +207,7 @@
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath="..\version.rc"
RelativePath="..\..\version.rc"
>
</File>
</Filter>
@ -281,75 +215,119 @@
Name="Interfaces"
>
<File
RelativePath="..\IPluginManager.h"
RelativePath="..\..\IPluginManager.h"
>
</File>
<File
RelativePath="..\ISmmAPI.h"
RelativePath="..\..\ISmmAPI.h"
>
</File>
<File
RelativePath="..\ISmmPlugin.h"
RelativePath="..\..\ISmmPlugin.h"
>
</File>
</Filter>
<Filter
Name="SourceHook"
Name="Metamod"
>
<File
RelativePath="..\..\sourcehook\sh_list.h"
>
</File>
<File
RelativePath="..\..\sourcehook\sh_stack.h"
>
</File>
<File
RelativePath="..\..\sourcehook\sh_string.h"
>
</File>
<File
RelativePath="..\..\sourcehook\sh_tinyhash.h"
>
</File>
<File
RelativePath="..\..\sourcehook\sh_vector.h"
>
</File>
<Filter
Name="Headers"
Name="Source Files"
>
<File
RelativePath="..\..\sourcehook\FastDelegate.h"
RelativePath="..\..\metamod.cpp"
>
</File>
<File
RelativePath="..\..\sourcehook\sh_memfuncinfo.h"
RelativePath="..\..\metamod_console.cpp"
>
</File>
<File
RelativePath="..\..\sourcehook\sh_memory.h"
RelativePath="..\..\metamod_oslink.cpp"
>
</File>
<File
RelativePath="..\..\sourcehook\sourcehook.cpp"
RelativePath="..\..\metamod_plugins.cpp"
>
</File>
<File
RelativePath="..\..\sourcehook\sourcehook.h"
RelativePath="..\..\metamod_util.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
>
<File
RelativePath="..\..\metamod.h"
>
</File>
<File
RelativePath="..\..\sourcehook\sourcehook_impl.h"
RelativePath="..\..\metamod_console.h"
>
</File>
<File
RelativePath="..\..\metamod_oslink.h"
>
</File>
<File
RelativePath="..\..\metamod_plugins.h"
>
</File>
<File
RelativePath="..\..\metamod_provider.h"
>
</File>
<File
RelativePath="..\..\metamod_util.h"
>
</File>
</Filter>
</Filter>
<Filter
Name="HL2SDK"
Name="Provider"
>
<Filter
Name="Header Files"
>
<File
RelativePath="..\console.h"
>
</File>
<File
RelativePath="..\convar_smm.h"
>
</File>
<File
RelativePath="..\provider_ep1.h"
>
</File>
<File
RelativePath="..\vsp_listener.h"
>
</File>
</Filter>
<Filter
Name="Source Files"
>
<File
RelativePath="..\console.cpp"
>
</File>
<File
RelativePath="..\provider_ep1.cpp"
>
</File>
<File
RelativePath="..\vsp_listener.cpp"
>
</File>
</Filter>
</Filter>
<Filter
Name="SourceHook"
>
<File
RelativePath="..\convar_smm.h"
RelativePath="..\..\..\sourcehook\sourcehook.cpp"
>
</File>
</Filter>

View File

@ -0,0 +1,590 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#include <sourcehook.h>
#include "convar_smm.h"
#include <eiface.h>
#include <tier0/icommandline.h>
#include <tier1/utldict.h>
#include <sh_vector.h>
#include <sh_string.h>
#include "../metamod_util.h"
#include "provider_ep1.h"
#include "console.h"
#include "metamod_console.h"
#include "vsp_listener.h"
/* Types */
typedef void (*CONPRINTF_FUNC)(const char *, ...);
struct UsrMsgInfo
{
int size;
String name;
};
/* Imports */
#undef CommandLine
DLL_IMPORT ICommandLine *CommandLine();
/* Functions */
CONPRINTF_FUNC ExtractRemotePrinter();
bool CacheUserMessages();
void ClientCommand(edict_t *pEdict);
void _ServerCommand();
/* Variables */
bool usermsgs_extracted = false;
CVector<UsrMsgInfo> usermsgs_list;
CONPRINTF_FUNC echo_msg_func = NULL;
ICvar *icvar = NULL;
ISmmAPI *metamod_api = NULL;
IVEngineServer *engine = NULL;
IServerGameClients *gameclients = NULL;
VSPListener g_VspListener;
BaseProvider g_Ep1Provider;
IMetamodSourceProvider *provider = &g_Ep1Provider;
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
void BaseProvider::ConsolePrint(const char *str)
{
if (echo_msg_func != NULL)
{
echo_msg_func("%s", str);
}
else
{
Msg("%s", str);
}
}
void BaseProvider::Notify_DLLInit_Pre(void *gamedll,
CreateInterfaceFn engineFactory,
CreateInterfaceFn serverFactory)
{
server = (IServerGameDLL *)gamedll;
engine = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL));
if (!engine)
{
Error("Could not find IVEngineServer! Metamod cannot load.");
return;
}
icvar = (ICvar *)((engineFactory)(VENGINE_CVAR_INTERFACE_VERSION, NULL));
if (!icvar)
{
Error("Could not find ICvar! Metamod cannot load.");
return;
}
if ((gameclients = (IServerGameClients *)(serverFactory("ServerGameClients003", NULL)))
== NULL)
{
gameclients = (IServerGameClients *)(serverFactory("ServerGameClients004", NULL));
}
echo_msg_func = ExtractRemotePrinter();
usermsgs_extracted = CacheUserMessages();
if (gameclients)
{
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false);
}
ConCommandBaseMgr::OneTimeInit(&g_SMConVarAccessor);
}
void BaseProvider::Notify_DLLShutdown_Pre()
{
g_SMConVarAccessor.MarkCommandsAsGameDLL();
g_SMConVarAccessor.UnregisterGameDLLCommands();
}
bool BaseProvider::IsRemotePrintingAvailable()
{
return (echo_msg_func != NULL);
}
void BaseProvider::ClientConsolePrint(edict_t *client, const char *message)
{
engine->ClientPrintf(client, message);
}
void BaseProvider::ServerCommand(const char *cmd)
{
engine->ServerCommand(cmd);
}
const char *BaseProvider::GetConVarString(ConVar *convar)
{
return convar->GetString();
}
bool BaseProvider::IsConCommandBaseACommand(ConCommandBase *pCommand)
{
return pCommand->IsCommand();
}
bool BaseProvider::IsSourceEngineBuildCompatible(int build)
{
return (build == SOURCE_ENGINE_ORIGINAL
|| build == SOURCE_ENGINE_EPISODEONE);
}
const char *BaseProvider::GetCommandLineValue(const char *key, const char *defval)
{
if (key[0] == '-' || key[0] == '+')
{
return CommandLine()->ParmValue(key, defval);
}
else
{
const char *val;
if ((val = icvar->GetCommandLineValue(key)) == NULL)
{
return defval;
}
return val;
}
}
int BaseProvider::TryServerGameDLL(const char *iface)
{
if (strncmp(iface, "ServerGameDLL", 13) != 0)
{
return 0;
}
return atoi(&iface[13]);
}
bool BaseProvider::LogMessage(const char *buffer)
{
if (!engine)
{
return false;
}
engine->LogPrint(buffer);
return true;
}
bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo)
{
SourceHook::MemFuncInfo mfi = {true, -1, 0, 0};
if (hook == ProvidedHook_LevelInit)
{
SourceHook::GetFuncInfo(&IServerGameDLL::LevelInit, mfi);
}
else if (hook == ProvidedHook_LevelShutdown)
{
SourceHook::GetFuncInfo(&IServerGameDLL::LevelShutdown, mfi);
}
else if (hook == ProvidedHook_GameInit)
{
SourceHook::GetFuncInfo(&IServerGameDLL::GameInit, mfi);
}
else if (hook == ProvidedHook_DLLShutdown)
{
SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfi);
}
else if (hook == ProvidedHook_DLLInit)
{
SourceHook::GetFuncInfo(&IServerGameDLL::DLLInit, mfi);
}
*pInfo = mfi;
return (mfi.thisptroffs >= 0);
}
void BaseProvider::DisplayError(const char *fmt, ...)
{
va_list ap;
char buffer[2048];
va_start(ap, fmt);
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
Error(buffer);
}
void BaseProvider::DisplayWarning(const char *fmt, ...)
{
va_list ap;
char buffer[2048];
va_start(ap, fmt);
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
Warning(buffer);
}
IConCommandBaseAccessor *BaseProvider::GetConCommandBaseAccessor()
{
return &g_SMConVarAccessor;
}
bool BaseProvider::RegisterConCommandBase(ConCommandBase *pCommand)
{
return g_SMConVarAccessor.Register(pCommand);
}
void BaseProvider::UnregisterConCommandBase(ConCommandBase *pCommand)
{
return g_SMConVarAccessor.Unregister(pCommand);
}
int BaseProvider::GetUserMessageCount()
{
if (!usermsgs_extracted)
{
return -1;
}
return (int)usermsgs_list.size();
}
int BaseProvider::FindUserMessage(const char *name, int *size)
{
for (size_t i = 0; i < usermsgs_list.size(); i++)
{
if (usermsgs_list[i].name.compare(name) == 0)
{
if (size)
{
*size = usermsgs_list[i].size;
}
return (int)i;
}
}
return -1;
}
const char *BaseProvider::GetUserMessage(int index, int *size)
{
if (!usermsgs_extracted || index < 0 || index >= (int)usermsgs_list.size())
{
return NULL;
}
if (size)
{
*size = usermsgs_list[index].size;
}
return usermsgs_list[index].name.c_str();
}
const char *BaseProvider::GetGameDescription()
{
return server->GetGameDescription();
}
ConVar *BaseProvider::CreateConVar(const char *name,
const char *defval,
const char *help,
int flags)
{
int newflags = 0;
if (flags & ConVarFlag_Notify)
{
newflags |= FCVAR_NOTIFY;
}
if (flags & ConVarFlag_Replicated)
{
newflags |= FCVAR_REPLICATED;
}
if (flags & ConVarFlag_SpOnly)
{
newflags |= FCVAR_SPONLY;
}
return new ConVar(name, defval, newflags, help);
}
IServerPluginCallbacks *BaseProvider::GetVSPCallbacks(const char *iface)
{
g_VspListener.SetLoadable(true);
return &g_VspListener;
}
class GlobCommand : public IMetamodSourceCommandInfo
{
public:
unsigned int GetArgCount()
{
return engine->Cmd_Argc() - 1;
}
const char *GetArg(unsigned int num)
{
return engine->Cmd_Argv(num);
}
const char *GetArgString()
{
return engine->Cmd_Args();
}
};
CON_COMMAND(meta, "Metamod:Source control commands")
{
GlobCommand cmd;
Command_Meta(&cmd);
}
void ClientCommand(edict_t *pEdict)
{
GlobCommand cmd;
if (strcmp(cmd.GetArg(0), "meta") == 0)
{
Command_ClientMeta(pEdict, &cmd);
}
}
//////////////////////////////////////////////////////////////////////////
//THERE BE HAX HERE!!!! DON'T TELL ALFRED, BUT GABE WANTED IT THAT WAY. //
// (note: you can find the offset by looking for the text //
// "Echo text to console", you'll find the callback cmd pushed on the //
// stack.) //
//////////////////////////////////////////////////////////////////////////
#define SIGLEN 8
#define ENGINE486_SIG "\x55\x89\xE5\x53\x83\xEC\x14\xBB"
#define ENGINE486_OFFS 40
#define ENGINE686_SIG "\x53\x83\xEC\x08\xBB\x01\x00\x00"
#define ENGINE686_OFFS 50
#define ENGINEAMD_SIG "\x53\x51\xBB\x01\x00\x00\x00\x51"
#define ENGINEAMD_OFFS 47
#define ENGINEW32_SIG "\xA1\x2A\x2A\x2A\x2A\x56\xBE\x01"
#define ENGINEW32_OFFS 38
#define IA32_CALL 0xE8
bool vcmp(const void *_addr1, const void *_addr2, size_t len)
{
unsigned char *addr1 = (unsigned char *)_addr1;
unsigned char *addr2 = (unsigned char *)_addr2;
for (size_t i=0; i<len; i++)
{
if (addr2[i] == '*')
{
continue;
}
if (addr1[i] != addr2[i])
{
return false;
}
}
return true;
}
//Thanks to fysh for the idea of extracting info from "echo" and for
// having the original offsets at hand!
CONPRINTF_FUNC ExtractRemotePrinter()
{
ConCommandBase *pBase = icvar->GetCommands();
unsigned char *ptr = NULL;
FnCommandCallback callback = NULL;
int offs = 0;
while (pBase)
{
if (strcmp(pBase->GetName(), "echo") == 0)
{
callback = ((ConCommand *)pBase)->GetCallback();
ptr = (unsigned char *)callback;
#ifdef OS_LINUX
if (vcmp(ptr, ENGINE486_SIG, SIGLEN))
{
offs = ENGINE486_OFFS;
}
else if (vcmp(ptr, ENGINE686_SIG, SIGLEN))
{
offs = ENGINE686_OFFS;
}
else if (vcmp(ptr, ENGINEAMD_SIG, SIGLEN))
{
offs = ENGINEAMD_OFFS;
}
#elif defined OS_WIN32 // Only one Windows engine binary so far...
if (vcmp(ptr, ENGINEW32_SIG, SIGLEN))
{
offs = ENGINEW32_OFFS;
}
#endif
if (!offs || ptr[offs - 1] != IA32_CALL)
{
return NULL;
}
//get the relative offset
void *addr = *((void **)(ptr + offs));
//add the base offset, to the ip (which is the address+offset + 4 bytes for next instruction)
return (CONPRINTF_FUNC)((unsigned long)addr + (unsigned long)(ptr + offs) + 4);
}
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
}
return NULL;
}
//////////////////////////////////////////////////////////////////////
// EVEN MORE HACKS HERE! YOU HAVE BEEN WARNED! //
// Signatures necessary in finding the pointer to the CUtlDict that //
// stores user message information. //
// IServerGameDLL::GetUserMessageInfo() normally crashes with bad //
// message indices. This is our answer to it. Yuck! <:-( //
//////////////////////////////////////////////////////////////////////
#ifdef OS_WIN32
/* General Windows sig */
#define MSGCLASS_SIGLEN 7
#define MSGCLASS_SIG "\x8B\x0D\x2A\x2A\x2A\x2A\x56"
#define MSGCLASS_OFFS 2
/* Dystopia Wimdows hack */
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x56\x8B\x74\x24\x2A\x85\xF6\x7C\x2A\x3B\x35\x2A\x2A\x2A\x2A\x7D"
#define MSGCLASS2_OFFS 11
/* Windows frame pointer sig */
#define MSGCLASS3_SIGLEN 18
#define MSGCLASS3_SIG "\x55\x8B\xEC\x51\x89\x2A\x2A\x8B\x2A\x2A\x50\x8B\x0D\x2A\x2A\x2A\x2A\xE8"
#define MSGCLASS3_OFFS 13
#elif defined OS_LINUX
/* No frame pointer sig */
#define MSGCLASS_SIGLEN 14
#define MSGCLASS_SIG "\x53\x83\xEC\x2A\x8B\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x89"
#define MSGCLASS_OFFS 9
/* Frame pointer sig */
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x55\x89\xE5\x53\x83\xEC\x2A\x8B\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x89"
#define MSGCLASS2_OFFS 11
#endif
struct UserMessage
{
int size;
const char *name;
};
typedef CUtlDict<UserMessage *, int> UserMsgDict;
/* This is the ugliest function in all of SourceMM */
bool CacheUserMessages()
{
/* Get address of original GetUserMessageInfo() */
char *vfunc = (char *)SH_GET_ORIG_VFNPTR_ENTRY(server, &IServerGameDLL::GetUserMessageInfo);
/* Oh dear, we have a relative jump on our hands
* PVK II on Windows made me do this, but I suppose it doesn't hurt to check this on Linux too...
*/
if (*vfunc == '\xE9')
{
/* Get address from displacement...
*
* Add 5 because it's relative to next instruction:
* Opcode <1 byte> + 32-bit displacement <4 bytes>
*/
vfunc += *reinterpret_cast<int *>(vfunc + 1) + 5;
}
CUtlDict<UserMessage *, int> *dict = NULL;
if (vcmp(vfunc, MSGCLASS_SIG, MSGCLASS_SIGLEN))
{
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
}
else if (vcmp(vfunc, MSGCLASS2_SIG, MSGCLASS2_SIGLEN))
{
#ifdef OS_WIN32
/* If we get here, the code is possibly inlined like in Dystopia */
/* Get the address of the CUtlRBTree */
char *rbtree = *reinterpret_cast<char **>(vfunc + MSGCLASS2_OFFS);
/* CUtlDict should be 8 bytes before the CUtlRBTree (hacktacular!) */
dict = reinterpret_cast<UserMsgDict *>(rbtree - 8);
#elif defined OS_LINUX
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS2_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
#ifdef OS_WIN32
}
else if (vcmp(vfunc, MSGCLASS3_SIG, MSGCLASS3_SIGLEN))
{
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS3_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
}
if (dict)
{
int msg_count = dict->Count();
/* Ensure that count is within bounds of an unsigned byte, because that's what engine supports */
if (msg_count < 0 || msg_count > 255)
{
return false;
}
UserMessage *msg;
UsrMsgInfo u_msg;
/* Cache messages in our CUtlDict */
for (int i = 0; i < msg_count; i++)
{
msg = dict->Element(i);
u_msg.name = msg->name;
u_msg.size = msg->size;
usermsgs_list.push_back(u_msg);
}
return true;
}
return false;
}

View File

@ -0,0 +1,81 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
#define _INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
#include <sourcehook.h>
#include <sh_memfuncinfo.h>
#include <iserverplugin.h>
#include "ISmmAPI.h"
#include "metamod_provider.h"
#include "metamod_oslink.h"
using namespace SourceMM;
using namespace SourceHook;
class BaseProvider : public IMetamodSourceProvider
{
public:
virtual bool IsSourceEngineBuildCompatible(int build);
virtual bool GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo);
virtual bool LogMessage(const char *buffer);
virtual const char *GetCommandLineValue(const char *key, const char *defval);
virtual void ConsolePrint(const char *msg);
virtual bool IsRemotePrintingAvailable();
virtual void ClientConsolePrint(edict_t *client, const char *msg);
virtual IServerPluginCallbacks *GetVSPCallbacks(const char *iface);
virtual void DisplayError(const char *fmt, ...);
virtual void DisplayWarning(const char *fmt, ...);
virtual int TryServerGameDLL(const char *iface);
virtual void Notify_DLLInit_Pre(void *gamedll,
CreateInterfaceFn engineFactory,
CreateInterfaceFn serverFactory);
void Notify_DLLShutdown_Pre();
virtual void ServerCommand(const char *cmd);
virtual ConVar *CreateConVar(const char *name,
const char *defval,
const char *help,
int flags);
virtual const char *GetConVarString(ConVar *convar);
virtual const char *GetGameDescription();
virtual IConCommandBaseAccessor *GetConCommandBaseAccessor();
virtual bool RegisterConCommandBase(ConCommandBase *pCommand);
virtual void UnregisterConCommandBase(ConCommandBase *pCommand);
virtual bool IsConCommandBaseACommand(ConCommandBase *pCommand);
virtual int GetUserMessageCount();
virtual int FindUserMessage(const char *name, int *size=NULL);
virtual const char *GetUserMessage(int index, int *size=NULL);
};
extern IVEngineServer *engine;
extern IServerGameDLL *server;
extern IServerGameClients *gameclients;
extern ICvar *icvar;
#endif //_INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_

View File

@ -1,24 +1,40 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* License: zlib/libpng
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Author(s): David "BAILOPAN" Anderson
* ============================
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#include "vsp_listener.h"
#include "CPlugin.h"
#include "svn_version.h"
#include "metamod.h"
using namespace SourceMM;
VSPListener g_VspListener;
VSPListener::VSPListener()
{
m_Loaded = false;
m_Loadable = false;
m_bLoaded = false;
m_bLoadable = false;
}
void VSPListener::ClientActive(edict_t *pEntity)
@ -57,12 +73,12 @@ void VSPListener::GameFrame(bool simulating)
const char *VSPListener::GetPluginDescription()
{
return "Metamod:Source Interface v" SOURCEMM_VERSION;
return "Metamod:Source Interface v" SVN_FILE_VERSION_STRING;
}
bool VSPListener::IsLoaded()
{
return m_Loaded;
return m_bLoaded;
}
void VSPListener::LevelInit(char const *pMapName)
@ -96,57 +112,27 @@ void VSPListener::Unload()
void VSPListener::SetLoadable(bool set)
{
m_Loadable = set;
m_bLoadable = set;
}
bool VSPListener::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory)
{
if (!g_GameDll.loaded)
{
Error("Metamod:Source is not a Valve Server Plugin\n");
return false;
}
if (!m_Loadable)
if (!m_bLoadable)
{
Warning("Do not manually load Metamod:Source as a Valve Server Plugin\n");
return false;
}
if (m_Loaded)
if (m_bLoaded)
{
return false;
}
m_Loaded = true;
m_bLoaded = true;
SetLoadable(false);
PluginIter iter;
CPluginManager::CPlugin *pPlugin;
SourceHook::List<IMetamodListener *>::iterator event;
IMetamodListener *pML;
for (iter=g_PluginMngr._begin(); iter!=g_PluginMngr._end(); iter++)
{
pPlugin = (*iter);
if (pPlugin->m_Status < Pl_Paused)
{
continue;
}
/* Only valid for plugins >= 10 (v1:5, SourceMM 1.4) */
if (pPlugin->m_API->GetApiVersion() < 10)
{
continue;
}
for (event=pPlugin->m_Events.begin();
event!=pPlugin->m_Events.end();
event++)
{
pML = (*event);
pML->OnVSPListening(this);
}
}
g_Metamod.NotifyVSPListening(this);
return true;
}

View File

@ -0,0 +1,64 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_
#define _INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_
#include "iserverplugin.h"
class VSPListener : public IServerPluginCallbacks
{
public:
VSPListener();
public:
virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory);
virtual void Unload();
virtual void Pause();
virtual void UnPause();
virtual const char *GetPluginDescription();
virtual void LevelInit(char const *pMapName);
virtual void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
virtual void GameFrame(bool simulating);
virtual void LevelShutdown(void);
virtual void ClientActive(edict_t *pEntity);
virtual void ClientDisconnect(edict_t *pEntity);
virtual void ClientPutInServer(edict_t *pEntity, char const *playername);
virtual void SetCommandClient(int index);
virtual void ClientSettingsChanged(edict_t *pEdict);
virtual PLUGIN_RESULT ClientConnect(bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
virtual PLUGIN_RESULT ClientCommand(edict_t *pEntity);
virtual PLUGIN_RESULT NetworkIDValidated(const char *pszUserName, const char *pszNetworkID);
public:
bool IsLoaded();
void SetLoadable(bool loadable);
private:
bool m_bLoaded;
bool m_bLoadable;
};
#endif //_INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_

View File

@ -0,0 +1,55 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#include "console.h"
#include "provider_ep2.h"
using namespace SourceHook;
SMConVarAccessor g_SMConVarAccessor;
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
{
pCommand->SetNext(NULL);
icvar->RegisterConCommand(pCommand);
return true;
}
bool SMConVarAccessor::Register(ConCommandBase *pCommand)
{
pCommand->SetNext(NULL);
icvar->RegisterConCommand(pCommand);
return true;
}
void SMConVarAccessor::Unregister(ConCommandBase *pCommand)
{
icvar->UnregisterConCommand(pCommand);
}

View File

@ -0,0 +1,55 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_CONSOLE_MMS_H_
#define _INCLUDE_CONSOLE_MMS_H_
#if defined _DEBUG
#define DEBUG2
#undef _DEBUG
#endif
#include <interface.h>
#include <eiface.h>
#include "convar.h"
#include <sh_list.h>
#if defined DEBUG2
#undef DEBUG2
#define _DEBUG
#endif
class SMConVarAccessor : public IConCommandBaseAccessor
{
public:
bool RegisterConCommandBase(ConCommandBase *pCommand);
bool Register(ConCommandBase *pCommand);
void Unregister(ConCommandBase *pCommand);
};
extern SMConVarAccessor g_SMConVarAccessor;
#endif //_INCLUDE_CONSOLE_MMS_H_

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stub_mm", "stub_mm.vcproj", "{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sourcemm", "sourcemm.vcproj", "{F7D47743-73B3-49B5-9D76-2333C5DFD565}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -9,10 +9,10 @@ Global
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Debug|Win32.ActiveCfg = Debug|Win32
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Debug|Win32.Build.0 = Debug|Win32
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Release|Win32.ActiveCfg = Release|Win32
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Release|Win32.Build.0 = Release|Win32
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Debug|Win32.ActiveCfg = Debug|Win32
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Debug|Win32.Build.0 = Debug|Win32
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Release|Win32.ActiveCfg = Release|Win32
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -2,9 +2,9 @@
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="sample_mm"
ProjectGUID="{FAFF34FB-FE14-47B5-81BD-70D237392FB2}"
RootNamespace="sample_mm"
Name="metamodsource_ep1"
ProjectGUID="{F7D47743-73B3-49B5-9D76-2333C5DFD565}"
RootNamespace="sourcemm"
Keyword="Win32Proj"
>
<Platforms>
@ -41,7 +41,8 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
AdditionalIncludeDirectories="..\..;..\..\..;..\..\..\sourcehook"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@ -62,14 +63,15 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
OutputFile="$(OutDir)/sample_mm.dll"
AdditionalDependencies="tier0.lib tier1.lib tier2.lib vstdlib.lib"
OutputFile="$(OutDir)/server.dll"
LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/sample_mm.pdb"
ProgramDatabaseFile="$(OutDir)/sourcemm.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/sample_mm.lib"
EnableCOMDATFolding="1"
ImportLibrary="$(OutDir)/sourcemm.lib"
TargetMachine="1"
/>
<Tool
@ -122,11 +124,16 @@
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
Optimization="3"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
RuntimeTypeInfo="false"
UsePrecompiledHeader="0"
ExpandAttributedSource="true"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
@ -143,14 +150,14 @@
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
OutputFile="$(OutDir)/sample_mm.dll"
OutputFile="$(OutDir)/server.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="1"
ImportLibrary="$(OutDir)/sample_mm.lib"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/sourcemm.lib"
TargetMachine="1"
/>
<Tool
@ -187,34 +194,138 @@
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\cvars.cpp"
>
</File>
<File
RelativePath="..\SamplePlugin.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\cvars.h"
>
</File>
<File
RelativePath="..\SamplePlugin.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath="..\..\version.rc"
>
</File>
</Filter>
<Filter
Name="Interfaces"
>
<File
RelativePath="..\..\IPluginManager.h"
>
</File>
<File
RelativePath="..\..\ISmmAPI.h"
>
</File>
<File
RelativePath="..\..\ISmmPlugin.h"
>
</File>
</Filter>
<Filter
Name="Metamod"
>
<Filter
Name="Source Files"
>
<File
RelativePath="..\..\metamod.cpp"
>
</File>
<File
RelativePath="..\..\metamod_console.cpp"
>
</File>
<File
RelativePath="..\..\metamod_oslink.cpp"
>
</File>
<File
RelativePath="..\..\metamod_plugins.cpp"
>
</File>
<File
RelativePath="..\..\metamod_util.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
>
<File
RelativePath="..\..\metamod.h"
>
</File>
<File
RelativePath="..\..\metamod_console.h"
>
</File>
<File
RelativePath="..\..\metamod_oslink.h"
>
</File>
<File
RelativePath="..\..\metamod_plugins.h"
>
</File>
<File
RelativePath="..\..\metamod_provider.h"
>
</File>
<File
RelativePath="..\..\metamod_util.h"
>
</File>
</Filter>
</Filter>
<Filter
Name="Provider"
>
<Filter
Name="Header Files"
>
<File
RelativePath="..\console.h"
>
</File>
<File
RelativePath="..\provider_ep2.h"
>
</File>
<File
RelativePath="..\vsp_listener.h"
>
</File>
</Filter>
<Filter
Name="Source Files"
>
<File
RelativePath="..\console.cpp"
>
</File>
<File
RelativePath="..\provider_ep2.cpp"
>
</File>
<File
RelativePath="..\vsp_listener.cpp"
>
</File>
</Filter>
</Filter>
<Filter
Name="SourceHook"
>
<File
RelativePath="..\..\..\sourcehook\sourcehook.cpp"
>
</File>
</Filter>
</Files>
<Globals>

View File

@ -0,0 +1,548 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#if defined _DEBUG
#define DEBUG2
#undef _DEBUG
#endif
#include <sourcehook.h>
#include <convar.h>
#include <eiface.h>
#include <tier0/icommandline.h>
#include <tier1/utldict.h>
#include <sh_vector.h>
#include <sh_string.h>
#include "../metamod_util.h"
#include "provider_ep2.h"
#include "console.h"
#include "metamod_console.h"
#include "vsp_listener.h"
#if defined DEBUG2
#undef DEBUG2
#define _DEBUG
#endif
/* Types */
typedef void (*CONPRINTF_FUNC)(const char *, ...);
struct UsrMsgInfo
{
int size;
String name;
};
/* Imports */
#undef CommandLine
DLL_IMPORT ICommandLine *CommandLine();
/* Functions */
bool CacheUserMessages();
void ClientCommand(edict_t *pEdict, const CCommand &args);
void LocalCommand_Meta(const CCommand &args);
void _ServerCommand();
/* Variables */
bool usermsgs_extracted = false;
CVector<UsrMsgInfo> usermsgs_list;
ICvar *icvar = NULL;
ISmmAPI *metamod_api = NULL;
IVEngineServer *engine = NULL;
IServerGameClients *gameclients = NULL;
VSPListener g_VspListener;
BaseProvider g_Ep1Provider;
IMetamodSourceProvider *provider = &g_Ep1Provider;
List<ConCommandBase *> conbases_unreg;
ConCommand meta_local_cmd("meta", LocalCommand_Meta, "Metamod:Source control options");
SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *, const CCommand &);
void BaseProvider::ConsolePrint(const char *str)
{
ConMsg("%s", str);
}
void BaseProvider::Notify_DLLInit_Pre(void *gamedll,
CreateInterfaceFn engineFactory,
CreateInterfaceFn serverFactory)
{
server = (IServerGameDLL *)gamedll;
engine = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL));
if (!engine)
{
DisplayError("Could not find IVEngineServer! Metamod cannot load.");
return;
}
icvar = (ICvar *)((engineFactory)(CVAR_INTERFACE_VERSION, NULL));
if (!icvar)
{
DisplayError("Could not find ICvar! Metamod cannot load.");
return;
}
if ((gameclients = (IServerGameClients *)(serverFactory("ServerGameClients003", NULL)))
== NULL)
{
gameclients = (IServerGameClients *)(serverFactory("ServerGameClients004", NULL));
}
RegisterConCommandBase(&meta_local_cmd);
conbases_unreg.push_back(&meta_local_cmd);
usermsgs_extracted = CacheUserMessages();
if (gameclients)
{
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false);
}
}
void BaseProvider::Notify_DLLShutdown_Pre()
{
List<ConCommandBase *>::iterator iter;
for (iter = conbases_unreg.begin();
iter != conbases_unreg.end();
iter++)
{
UnregisterConCommandBase((*iter));
}
}
bool BaseProvider::IsRemotePrintingAvailable()
{
return true;
}
void BaseProvider::ClientConsolePrint(edict_t *client, const char *message)
{
engine->ClientPrintf(client, message);
}
void BaseProvider::ServerCommand(const char *cmd)
{
engine->ServerCommand(cmd);
}
const char *BaseProvider::GetConVarString(ConVar *convar)
{
if (convar == NULL)
{
return NULL;
}
return convar->GetString();
}
bool BaseProvider::IsConCommandBaseACommand(ConCommandBase *pCommand)
{
return pCommand->IsCommand();
}
bool BaseProvider::IsSourceEngineBuildCompatible(int build)
{
return (build == SOURCE_ENGINE_ORIGINAL
|| build == SOURCE_ENGINE_EPISODEONE);
}
const char *BaseProvider::GetCommandLineValue(const char *key, const char *defval)
{
if (key[0] == '-' || key[0] == '+')
{
return CommandLine_Tier0()->ParmValue(key, defval);
}
else if (icvar)
{
const char *val;
if ((val = icvar->GetCommandLineValue(key)) == NULL)
{
return defval;
}
return val;
}
return NULL;
}
int BaseProvider::TryServerGameDLL(const char *iface)
{
if (strncmp(iface, "ServerGameDLL", 13) != 0)
{
return 0;
}
return atoi(&iface[13]);
}
bool BaseProvider::LogMessage(const char *buffer)
{
if (!engine)
{
return false;
}
engine->LogPrint(buffer);
return true;
}
bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo)
{
SourceHook::MemFuncInfo mfi = {true, -1, 0, 0};
if (hook == ProvidedHook_LevelInit)
{
SourceHook::GetFuncInfo(&IServerGameDLL::LevelInit, mfi);
}
else if (hook == ProvidedHook_LevelShutdown)
{
SourceHook::GetFuncInfo(&IServerGameDLL::LevelShutdown, mfi);
}
else if (hook == ProvidedHook_GameInit)
{
SourceHook::GetFuncInfo(&IServerGameDLL::GameInit, mfi);
}
else if (hook == ProvidedHook_DLLShutdown)
{
SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfi);
}
else if (hook == ProvidedHook_DLLInit)
{
SourceHook::GetFuncInfo(&IServerGameDLL::DLLInit, mfi);
}
*pInfo = mfi;
return (mfi.thisptroffs >= 0);
}
void BaseProvider::DisplayError(const char *fmt, ...)
{
va_list ap;
char buffer[2048];
va_start(ap, fmt);
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
Error(buffer);
}
void BaseProvider::DisplayWarning(const char *fmt, ...)
{
va_list ap;
char buffer[2048];
va_start(ap, fmt);
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
Warning(buffer);
}
IConCommandBaseAccessor *BaseProvider::GetConCommandBaseAccessor()
{
return &g_SMConVarAccessor;
}
bool BaseProvider::RegisterConCommandBase(ConCommandBase *pCommand)
{
return g_SMConVarAccessor.Register(pCommand);
}
void BaseProvider::UnregisterConCommandBase(ConCommandBase *pCommand)
{
return g_SMConVarAccessor.Unregister(pCommand);
}
int BaseProvider::GetUserMessageCount()
{
if (!usermsgs_extracted)
{
return -1;
}
return (int)usermsgs_list.size();
}
int BaseProvider::FindUserMessage(const char *name, int *size)
{
for (size_t i = 0; i < usermsgs_list.size(); i++)
{
if (usermsgs_list[i].name.compare(name) == 0)
{
if (size)
{
*size = usermsgs_list[i].size;
}
return (int)i;
}
}
return -1;
}
const char *BaseProvider::GetUserMessage(int index, int *size)
{
if (!usermsgs_extracted || index < 0 || index >= (int)usermsgs_list.size())
{
return NULL;
}
if (size)
{
*size = usermsgs_list[index].size;
}
return usermsgs_list[index].name.c_str();
}
const char *BaseProvider::GetGameDescription()
{
return server->GetGameDescription();
}
ConVar *BaseProvider::CreateConVar(const char *name,
const char *defval,
const char *help,
int flags)
{
int newflags = 0;
if (flags & ConVarFlag_Notify)
{
newflags |= FCVAR_NOTIFY;
}
if (flags & ConVarFlag_Replicated)
{
newflags |= FCVAR_REPLICATED;
}
if (flags & ConVarFlag_SpOnly)
{
newflags |= FCVAR_SPONLY;
}
ConVar *pVar = new ConVar(name, defval, newflags, help);
RegisterConCommandBase(pVar);
conbases_unreg.push_back(pVar);
return pVar;
}
IServerPluginCallbacks *BaseProvider::GetVSPCallbacks(const char *iface)
{
g_VspListener.SetLoadable(true);
return &g_VspListener;
}
class GlobCommand : public IMetamodSourceCommandInfo
{
public:
GlobCommand(const CCommand *cmd) : m_cmd(cmd)
{
}
public:
unsigned int GetArgCount()
{
return m_cmd->ArgC();
}
const char *GetArg(unsigned int num)
{
return m_cmd->Arg(num);
}
const char *GetArgString()
{
return m_cmd->ArgS();
}
private:
const CCommand *m_cmd;
};
void LocalCommand_Meta(const CCommand &args)
{
GlobCommand cmd(&args);
Command_Meta(&cmd);
}
void ClientCommand(edict_t *pEdict, const CCommand &_cmd)
{
GlobCommand cmd(&_cmd);
if (strcmp(cmd.GetArg(0), "meta") == 0)
{
Command_ClientMeta(pEdict, &cmd);
}
}
bool vcmp(const void *_addr1, const void *_addr2, size_t len)
{
unsigned char *addr1 = (unsigned char *)_addr1;
unsigned char *addr2 = (unsigned char *)_addr2;
for (size_t i=0; i<len; i++)
{
if (addr2[i] == '*')
{
continue;
}
if (addr1[i] != addr2[i])
{
return false;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////
// EVEN MORE HACKS HERE! YOU HAVE BEEN WARNED! //
// Signatures necessary in finding the pointer to the CUtlDict that //
// stores user message information. //
// IServerGameDLL::GetUserMessageInfo() normally crashes with bad //
// message indices. This is our answer to it. Yuck! <:-( //
//////////////////////////////////////////////////////////////////////
#ifdef OS_WIN32
/* General Windows sig */
#define MSGCLASS_SIGLEN 7
#define MSGCLASS_SIG "\x8B\x0D\x2A\x2A\x2A\x2A\x56"
#define MSGCLASS_OFFS 2
/* Dystopia Wimdows hack */
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x56\x8B\x74\x24\x2A\x85\xF6\x7C\x2A\x3B\x35\x2A\x2A\x2A\x2A\x7D"
#define MSGCLASS2_OFFS 11
/* Windows frame pointer sig */
#define MSGCLASS3_SIGLEN 18
#define MSGCLASS3_SIG "\x55\x8B\xEC\x51\x89\x2A\x2A\x8B\x2A\x2A\x50\x8B\x0D\x2A\x2A\x2A\x2A\xE8"
#define MSGCLASS3_OFFS 13
#elif defined OS_LINUX
/* No frame pointer sig */
#define MSGCLASS_SIGLEN 14
#define MSGCLASS_SIG "\x53\x83\xEC\x2A\x8B\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x89"
#define MSGCLASS_OFFS 9
/* Frame pointer sig */
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x55\x89\xE5\x53\x83\xEC\x2A\x8B\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x89"
#define MSGCLASS2_OFFS 11
#endif
struct UserMessage
{
int size;
const char *name;
};
typedef CUtlDict<UserMessage *, int> UserMsgDict;
/* This is the ugliest function in all of SourceMM */
bool CacheUserMessages()
{
/* Get address of original GetUserMessageInfo() */
char *vfunc = (char *)SH_GET_ORIG_VFNPTR_ENTRY(server, &IServerGameDLL::GetUserMessageInfo);
/* Oh dear, we have a relative jump on our hands
* PVK II on Windows made me do this, but I suppose it doesn't hurt to check this on Linux too...
*/
if (*vfunc == '\xE9')
{
/* Get address from displacement...
*
* Add 5 because it's relative to next instruction:
* Opcode <1 byte> + 32-bit displacement <4 bytes>
*/
vfunc += *reinterpret_cast<int *>(vfunc + 1) + 5;
}
CUtlDict<UserMessage *, int> *dict = NULL;
if (vcmp(vfunc, MSGCLASS_SIG, MSGCLASS_SIGLEN))
{
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
}
else if (vcmp(vfunc, MSGCLASS2_SIG, MSGCLASS2_SIGLEN))
{
#ifdef OS_WIN32
/* If we get here, the code is possibly inlined like in Dystopia */
/* Get the address of the CUtlRBTree */
char *rbtree = *reinterpret_cast<char **>(vfunc + MSGCLASS2_OFFS);
/* CUtlDict should be 8 bytes before the CUtlRBTree (hacktacular!) */
dict = reinterpret_cast<UserMsgDict *>(rbtree - 8);
#elif defined OS_LINUX
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS2_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
#ifdef OS_WIN32
}
else if (vcmp(vfunc, MSGCLASS3_SIG, MSGCLASS3_SIGLEN))
{
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS3_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
}
if (dict)
{
int msg_count = dict->Count();
/* Ensure that count is within bounds of an unsigned byte, because that's what engine supports */
if (msg_count < 0 || msg_count > 255)
{
return false;
}
UserMessage *msg;
UsrMsgInfo u_msg;
/* Cache messages in our CUtlDict */
for (int i = 0; i < msg_count; i++)
{
msg = dict->Element(i);
u_msg.name = msg->name;
u_msg.size = msg->size;
usermsgs_list.push_back(u_msg);
}
return true;
}
return false;
}

View File

@ -0,0 +1,89 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
#define _INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
#if defined _DEBUG
#define DEBUG2
#undef _DEBUG
#endif
#include <sourcehook.h>
#include <sh_memfuncinfo.h>
#include <iserverplugin.h>
#include "ISmmAPI.h"
#include "metamod_provider.h"
#include "metamod_oslink.h"
#if defined DEBUG2
#undef DEBUG2
#define _DEBUG
#endif
using namespace SourceMM;
using namespace SourceHook;
class BaseProvider : public IMetamodSourceProvider
{
public:
virtual bool IsSourceEngineBuildCompatible(int build);
virtual bool GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo);
virtual bool LogMessage(const char *buffer);
virtual const char *GetCommandLineValue(const char *key, const char *defval);
virtual void ConsolePrint(const char *msg);
virtual bool IsRemotePrintingAvailable();
virtual void ClientConsolePrint(edict_t *client, const char *msg);
virtual IServerPluginCallbacks *GetVSPCallbacks(const char *iface);
virtual void DisplayError(const char *fmt, ...);
virtual void DisplayWarning(const char *fmt, ...);
virtual int TryServerGameDLL(const char *iface);
virtual void Notify_DLLInit_Pre(void *gamedll,
CreateInterfaceFn engineFactory,
CreateInterfaceFn serverFactory);
void Notify_DLLShutdown_Pre();
virtual void ServerCommand(const char *cmd);
virtual ConVar *CreateConVar(const char *name,
const char *defval,
const char *help,
int flags);
virtual const char *GetConVarString(ConVar *convar);
virtual const char *GetGameDescription();
virtual IConCommandBaseAccessor *GetConCommandBaseAccessor();
virtual bool RegisterConCommandBase(ConCommandBase *pCommand);
virtual void UnregisterConCommandBase(ConCommandBase *pCommand);
virtual bool IsConCommandBaseACommand(ConCommandBase *pCommand);
virtual int GetUserMessageCount();
virtual int FindUserMessage(const char *name, int *size=NULL);
virtual const char *GetUserMessage(int index, int *size=NULL);
};
extern IVEngineServer *engine;
extern IServerGameDLL *server;
extern IServerGameClients *gameclients;
extern ICvar *icvar;
#endif //_INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_

View File

@ -0,0 +1,141 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#include "vsp_listener.h"
#include "svn_version.h"
#include "metamod.h"
using namespace SourceMM;
VSPListener::VSPListener()
{
m_bLoaded = false;
m_bLoadable = false;
}
void VSPListener::ClientActive(edict_t *pEntity)
{
}
PLUGIN_RESULT VSPListener::ClientCommand(edict_t *pEntity, const CCommand &cmd)
{
return PLUGIN_CONTINUE;
}
PLUGIN_RESULT VSPListener::ClientConnect(bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
{
return PLUGIN_CONTINUE;
}
void VSPListener::ClientDisconnect(edict_t *pEntity)
{
}
void VSPListener::ClientPutInServer(edict_t *pEntity, char const *playername)
{
}
void VSPListener::ClientSettingsChanged(edict_t *pEdict)
{
}
void VSPListener::SetCommandClient(int index)
{
}
void VSPListener::GameFrame(bool simulating)
{
}
const char *VSPListener::GetPluginDescription()
{
return "Metamod:Source Interface v" SVN_FILE_VERSION_STRING;
}
bool VSPListener::IsLoaded()
{
return m_bLoaded;
}
void VSPListener::LevelInit(char const *pMapName)
{
}
void VSPListener::LevelShutdown()
{
}
PLUGIN_RESULT VSPListener::NetworkIDValidated(const char *pszUserName, const char *pszNetworkID)
{
return PLUGIN_CONTINUE;
}
void VSPListener::Pause()
{
}
void VSPListener::UnPause()
{
}
void VSPListener::ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
{
}
void VSPListener::Unload()
{
}
void VSPListener::SetLoadable(bool set)
{
m_bLoadable = set;
}
bool VSPListener::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory)
{
if (!m_bLoadable)
{
provider->DisplayWarning("Do not manually load Metamod:Source as a Valve Server Plugin\n");
return false;
}
if (m_bLoaded)
{
return false;
}
m_bLoaded = true;
SetLoadable(false);
g_Metamod.NotifyVSPListening(this);
return true;
}
void VSPListener::OnQueryCvarValueFinished(QueryCvarCookie_t iCookie, edict_t *pPlayerEntity, EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue )
{
}

View File

@ -0,0 +1,73 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_
#define _INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_
#if defined _DEBUG
#define DEBUG2
#undef _DEBUG
#endif
#include "iserverplugin.h"
#if defined DEBUG2
#undef DEBUG2
#define _DEBUG
#endif
class VSPListener : public IServerPluginCallbacks
{
public:
VSPListener();
public:
virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory);
virtual void Unload();
virtual void Pause();
virtual void UnPause();
virtual const char *GetPluginDescription();
virtual void LevelInit(char const *pMapName);
virtual void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
virtual void GameFrame(bool simulating);
virtual void LevelShutdown(void);
virtual void ClientActive(edict_t *pEntity);
virtual void ClientDisconnect(edict_t *pEntity);
virtual void ClientPutInServer(edict_t *pEntity, char const *playername);
virtual void SetCommandClient(int index);
virtual void ClientSettingsChanged(edict_t *pEdict);
virtual PLUGIN_RESULT ClientConnect(bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
virtual PLUGIN_RESULT ClientCommand(edict_t *pEntity, const CCommand &cmd);
virtual PLUGIN_RESULT NetworkIDValidated(const char *pszUserName, const char *pszNetworkID);
virtual void OnQueryCvarValueFinished( QueryCvarCookie_t iCookie, edict_t *pPlayerEntity, EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue );
public:
bool IsLoaded();
void SetLoadable(bool loadable);
private:
bool m_bLoaded;
bool m_bLoadable;
};
#endif //_INCLUDE_METAMOD_SOURCE_VSP_LISTENER_H_

1244
sourcemm/metamod.cpp Normal file
View File

@ -0,0 +1,1244 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#if defined _DEBUG
#define DEBUG2
#undef _DEBUG
#endif
#include <interface.h>
#include <eiface.h>
#include "metamod.h"
#include "metamod_provider.h"
#include "metamod_plugins.h"
#include "metamod_util.h"
#include "metamod_console.h"
#include "metamod_oslink.h"
#if defined DEBUG2
#undef DEBUG2
#define _DEBUG
#endif
using namespace SourceMM;
using namespace SourceHook;
/**
* @brief Implementation of main SourceMM GameDLL functionality
* @file sourcemm.cpp
*/
SH_DECL_MANUALHOOK4(SGD_DLLInit, 0, 0, 0, bool, CreateInterfaceFn, CreateInterfaceFn, CreateInterfaceFn, CGlobalVars *);
SH_DECL_MANUALHOOK0(SGD_GameInit, 0, 0, 0, bool);
SH_DECL_MANUALHOOK6(SGD_LevelInit, 0, 0, 0, bool, const char *, const char *, const char *, const char *, bool, bool);
SH_DECL_MANUALHOOK0_void(SGD_LevelShutdown, 0, 0, 0);
SH_DECL_MANUALHOOK0_void(SGD_DLLShutdown, 0, 0, 0);
bool Handler_DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals);
bool Handler_DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals);
void Handler_DLLShutdown();
void Handler_LevelShutdown();
bool Handler_LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
bool Handler_GameInit();
void InitializeVSP();
struct game_dll_t
{
HINSTANCE lib;
CreateInterfaceFn factory;
};
String mod_path;
String metamod_path;
String full_bin_path;
bool parsed_game_info = false;
int vsp_version = 0;
int gamedll_version = 0;
int engine_build = SOURCE_ENGINE_UNKNOWN;
List<game_dll_t *> gamedll_list;
bool is_gamedll_loaded = false;
bool in_first_level = true;
bool is_game_init = false;
bool vsp_load_attempted = false;
bool vsp_load_requested = false;
bool vsp_loaded = false;
game_dll_t gamedll_info;
ConVar *metamod_version = NULL;
ConVar *mm_pluginsfile = NULL;
IServerGameDLL *server = NULL;
CreateInterfaceFn engine_factory = NULL;
CreateInterfaceFn physics_factory = NULL;
CreateInterfaceFn filesystem_factory = NULL;
CGlobalVars *gpGlobals = NULL;
SourceHook::CSourceHookImpl g_SourceHook;
SourceHook::ISourceHook *g_SHPtr = &g_SourceHook;
PluginId g_PLID = Pl_Console;
META_RES last_meta_res;
IServerPluginCallbacks *vsp_callbacks = NULL;
MetamodSource g_Metamod;
void ClearGamedllList();
/* Helper Macro */
#define IFACE_MACRO(orig,nam) \
CPluginManager::CPlugin *pl; \
SourceHook::List<IMetamodListener *>::iterator event; \
IMetamodListener *api; \
int mret = 0; \
void *val = NULL; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
pl = (*iter); \
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
api = (*event); \
mret = IFACE_FAILED; \
if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \
if (ret) *ret = mret; \
return val; \
} \
} \
} \
return (orig)(iface, ret);
#define ITER_EVENT(evn, args) \
CPluginManager::CPlugin *pl; \
SourceHook::List<IMetamodListener *>::iterator event; \
IMetamodListener *api; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
pl = (*iter); \
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
api = (*event); \
api->evn args; \
} \
}
/* Initialize everything here */
void InitMainStates()
{
char full_path[PATH_SIZE] = {0};
GetFileOfAddress((void *)gamedll_info.factory, full_path, sizeof(full_path));
full_bin_path.assign(full_path);
/* Like Metamod, reload plugins at the end of the map.
* This is so plugins can hook everything on load, BUT, new plugins will be reloaded
* if the server is shut down (silly, but rare case).
*/
in_first_level = true;
SourceHook::MemFuncInfo info;
if (!provider->GetHookInfo(ProvidedHook_DLLInit, &info))
{
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::DLLInit");
}
SH_MANUALHOOK_RECONFIGURE(SGD_DLLInit, info.vtblindex, info.vtbloffs, info.thisptroffs);
SH_ADD_MANUALHOOK_STATICFUNC(SGD_DLLInit, server, Handler_DLLInit, false);
SH_ADD_MANUALHOOK_STATICFUNC(SGD_DLLInit, server, Handler_DLLInit_Post, true);
if (!provider->GetHookInfo(ProvidedHook_GameInit, &info))
{
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::GameInit");
}
SH_MANUALHOOK_RECONFIGURE(SGD_GameInit, info.vtblindex, info.vtbloffs, info.thisptroffs);
SH_ADD_MANUALHOOK_STATICFUNC(SGD_GameInit, server, Handler_GameInit, false);
if (!provider->GetHookInfo(ProvidedHook_LevelInit, &info))
{
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::LevelInit");
}
SH_MANUALHOOK_RECONFIGURE(SGD_LevelInit, info.vtblindex, info.vtbloffs, info.thisptroffs);
SH_ADD_MANUALHOOK_STATICFUNC(SGD_LevelInit, server, Handler_LevelInit, true);
if (!provider->GetHookInfo(ProvidedHook_LevelShutdown, &info))
{
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::LevelShutdown");
}
SH_MANUALHOOK_RECONFIGURE(SGD_LevelShutdown, info.vtblindex, info.vtbloffs, info.thisptroffs);
SH_ADD_MANUALHOOK_STATICFUNC(SGD_LevelShutdown, server, Handler_LevelShutdown, true);
if (!provider->GetHookInfo(ProvidedHook_DLLShutdown, &info))
{
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::DLLShutdown");
}
SH_MANUALHOOK_RECONFIGURE(SGD_DLLShutdown, info.vtblindex, info.vtbloffs, info.thisptroffs);
SH_ADD_MANUALHOOK_STATICFUNC(SGD_DLLShutdown, server, Handler_DLLShutdown, false);
}
/* This is where the magic happens */
SMM_API void *CreateInterface(const char *iface, int *ret)
{
/* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */
if (strcmp(iface, PLAPI_NAME) == 0)
{
provider->DisplayWarning("Do not try loading Metamod:Source as a plugin.\n");
if (ret)
{
*ret = IFACE_FAILED;
}
return NULL;
}
if (strncmp(iface, "ISERVERPLUGINCALLBACKS", 22) == 0)
{
vsp_callbacks = provider->GetVSPCallbacks(iface);
if (vsp_callbacks != NULL && vsp_version == 0)
{
vsp_version = atoi(&iface[22]);
}
if (ret)
{
*ret = (vsp_callbacks != NULL) ? IFACE_OK : IFACE_FAILED;
}
return vsp_callbacks;
}
if (!parsed_game_info)
{
parsed_game_info = true;
const char *game_dir = NULL;
char game_path[PATH_SIZE];
char mm_path[PATH_SIZE];
/* Get path to SourceMM DLL */
if (!GetFileOfAddress((void *)CreateInterface, mm_path, sizeof(mm_path)))
{
provider->DisplayError("GetFileOfAddress() failed! Metamod cannot load.\n");
return NULL;
}
metamod_path.assign(mm_path);
/* Get value of -game from command line, defaulting to hl2 as engine seems to do */
game_dir = provider->GetCommandLineValue("-game", "hl2");
engine_build = SOURCE_ENGINE_ORANGEBOX;
/* Get absolute path */
abspath(game_path, game_dir);
mod_path.assign(game_path);
char temp_path[PATH_SIZE];
/* Path to gameinfo.txt */
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s", mod_path.c_str(), "gameinfo.txt");
FILE *fp = fopen(temp_path, "rt");
if (!fp)
{
provider->DisplayError("Unable to open gameinfo.txt! Metamod cannot load.\n");
return NULL;
}
char buffer[255];
char key[128], val[128];
bool search = false;
bool gamebin = false;
char *ptr;
const char *lptr;
char cur_path[PATH_SIZE];
getcwd(cur_path, PATH_SIZE);
while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL)
{
UTIL_TrimComments(buffer);
UTIL_TrimLeft(buffer);
UTIL_TrimRight(buffer);
if (stricmp(buffer, "SearchPaths") == 0)
{
search = true;
}
if (!search)
{
continue;
}
UTIL_KeySplit(buffer, key, sizeof(key) - 1, val, sizeof(val) - 1);
if (stricmp(key, "Game") == 0 || stricmp(key, "GameBin") == 0)
{
if (stricmp(key, "Game") == 0)
{
gamebin = false;
}
else
{
gamebin = true;
}
if (strncmp(val, "|gameinfo_path|", sizeof("|gameinfo_path|") - 1) == 0)
{
ptr = &(val[sizeof("|gameinfo_path|") - 1]);
if (ptr[0] == '.')
{
ptr++;
}
lptr = mod_path.c_str();
} else {
ptr = val;
lptr = cur_path;
}
size_t ptr_len = strlen(ptr);
if (ptr[ptr_len] == '/' || ptr[ptr_len] == '\\')
{
ptr[--ptr_len] = '\0';
}
/* No need to append "bin" if key is GameBin */
if (gamebin)
{
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s/%s", lptr, ptr, SERVER_DLL);
}
else if (!ptr[0])
{
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s/%s", lptr, "bin", SERVER_DLL);
}
else
{
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s/%s/%s", lptr, ptr, "bin", SERVER_DLL);
}
/* If not path to SourceMM... */
if (!UTIL_PathCmp(mm_path, temp_path))
{
FILE *temp_fp = fopen(temp_path, "rb");
if (!temp_fp)
{
continue;
}
fclose(temp_fp);
/* Search for a matching game dll */
List<game_dll_t *>::iterator iter;
game_dll_t *pCheck;
bool found = false;
for (iter = gamedll_list.begin(); iter != gamedll_list.end(); iter++)
{
pCheck = (*iter);
if (GetFileOfAddress((void *)pCheck->factory, buffer, sizeof(buffer)))
{
if (UTIL_PathCmp(temp_path, buffer))
{
found = true;
break;
}
}
}
if (found)
{
continue;
}
HINSTANCE gamedll = dlmount(temp_path);
if (gamedll == NULL)
{
continue;
}
CreateInterfaceFn fn = (CreateInterfaceFn)dlsym(gamedll, "CreateInterface");
if (fn == NULL)
{
dlclose(gamedll);
continue;
}
game_dll_t *pInfo = new game_dll_t;
pInfo->factory = fn;
pInfo->lib = gamedll;
gamedll_list.push_back(pInfo);
break;
}
}
}
fclose(fp);
}
if (!is_gamedll_loaded)
{
if (strncmp(iface, "ServerGameDLL", 13) == 0)
{
List<game_dll_t *>::iterator iter;
game_dll_t *pInfo;
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
{
pInfo = (*iter);
if ((server = (IServerGameDLL *)((pInfo->factory)(iface, ret))) != NULL)
{
if ((gamedll_version = provider->TryServerGameDLL(iface)) != 0)
{
/* We have a match. Erase us from the list and save our info. */
gamedll_list.erase(iter);
gamedll_info = *pInfo;
delete pInfo;
is_gamedll_loaded = true;
break;
}
/* :TODO: error otherwise? */
}
}
if (is_gamedll_loaded)
{
ClearGamedllList();
InitMainStates();
}
else
{
if (ret)
{
*ret = IFACE_FAILED;
}
return NULL;
}
}
else
{
/* wtf do we do... */
/* :TODO: .. something a bit more intelligent? */
provider->DisplayError("Engine requested unknown interface before GameDLL was known!\n");
return NULL;
}
}
/* If we got here, there's definitely a GameDLL */
IFACE_MACRO(gamedll_info.factory, GameDLL);
}
void ClearGamedllList()
{
List<game_dll_t *>::iterator iter;
game_dll_t *pInfo;
for (iter = gamedll_list.begin(); iter != gamedll_list.end(); iter++)
{
pInfo = (*iter);
dlclose(pInfo->lib);
delete pInfo;
}
gamedll_list.clear();
}
int LoadPluginsFromFile(const char *_file)
{
FILE *fp;
int total = 0, skipped=0;
PluginId id;
bool already;
fp = fopen(_file, "rt");
if (!fp)
{
LogMessage("[META] Could not open plugins file %s\n", _file);
return -1;
}
char buffer[255], error[255], full_path[255];
const char *ptr, *ext, *file;
size_t length;
while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL)
{
UTIL_TrimLeft(buffer);
UTIL_TrimRight(buffer);
length = strlen(buffer);
if (!length)
{
continue;
}
if (buffer[0] == '\0' || buffer[0] == ';' || strncmp(buffer, "//", 2) == 0)
{
continue;
}
file = buffer;
if (buffer[0] == '"')
{
char *cptr = buffer;
file = ++cptr;
while (*cptr)
{
if (*cptr == '"')
{
*cptr = '\0';
break;
}
cptr++;
}
}
else
{
char *cptr = buffer;
while (*cptr)
{
if (isspace(*cptr))
{
char *optr = cptr;
while (*cptr && isspace(*cptr))
{
cptr++;
}
*optr = '\0';
UTIL_TrimRight(cptr);
if (*cptr && isalpha(*cptr))
{
g_PluginMngr.SetAlias(buffer, cptr);
file = cptr;
}
break;
}
cptr++;
}
}
if (!file[0])
{
continue;
}
/* First find if it's an absolute path or not... */
if (file[0] == '/' || strncmp(&(file[1]), ":\\", 2) == 0)
{
/* If we're in an absolute path, ignore our normal heuristics */
id = g_PluginMngr.Load(file, Pl_File, already, error, sizeof(error));
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
{
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
}
else
{
if (already)
{
skipped++;
}
else
{
total++;
}
}
}
else
{
/* Attempt to find a file extension */
ptr = UTIL_GetExtension(file);
/* Add an extension if there's none there */
if (!ptr)
{
#if defined WIN32 || defined _WIN32
ext = ".dll";
#else
ext = "_i486.so";
#endif
}
else
{
ext = "";
}
/* Format the new path */
g_Metamod.PathFormat(full_path, sizeof(full_path), "%s/%s%s", mod_path.c_str(), file, ext);
id = g_PluginMngr.Load(full_path, Pl_File, already, error, sizeof(error));
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
{
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
}
else
{
if (already)
{
skipped++;
}
else
{
total++;
}
}
}
}
fclose(fp);
if (skipped)
{
LogMessage("[META] Loaded %d plugins from file (%d already loaded)", total, skipped);
}
else
{
LogMessage("[META] Loaded %d plugins from file.", total);
}
return total;
}
void InitializeVSP()
{
size_t len;
char engine_file[PATH_SIZE];
char engine_path[PATH_SIZE];
char rel_path[PATH_SIZE * 2];
GetFileOfAddress((void *)engine_factory, engine_file, sizeof(engine_file));
/* Chop off the "engine" file part */
len = strlen(engine_file);
for (size_t i = len - 1; i >= 0 && i < len; i--)
{
if (engine_file[i] == '/' || engine_file[i] == '\\')
{
engine_file[i] = '\0';
break;
}
}
abspath(engine_path, engine_file);
const char *usepath = metamod_path.c_str();
if (UTIL_Relatize(rel_path, sizeof(rel_path), engine_path, metamod_path.c_str()))
{
usepath = rel_path;
}
char command[PATH_SIZE * 2];
UTIL_Format(command, sizeof(command), "plugin_load \"%s\"\n", usepath);
provider->ServerCommand(command);
}
/* Wrapper function. This is called when the GameDLL thinks it's using
* the engine's real engineFactory.
*/
void *EngineFactory(const char *iface, int *ret)
{
IFACE_MACRO(engine_factory, Engine);
}
/* Wrapper function. This is called when the GameDLL thinks it's using
* the engine's real physicsFactory.
*/
void *PhysicsFactory(const char *iface, int *ret)
{
IFACE_MACRO(physics_factory, Physics);
}
/* Wrapper function. This is called when the GameDLL thinks it's using
* the engine's real fileSystemFactory.
*/
void *FileSystemFactory(const char *iface, int *ret)
{
IFACE_MACRO(filesystem_factory, FileSystem);
}
void LogMessage(const char *msg, ...)
{
va_list ap;
static char buffer[2048];
va_start(ap, msg);
size_t len = vsnprintf(buffer, sizeof(buffer) - 2, msg, ap);
va_end(ap);
buffer[len++] = '\n';
buffer[len] = '\0';
if (!provider->LogMessage(buffer))
{
fprintf(stdout, "%s", buffer);
}
}
bool Handler_DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
{
engine_factory = engineFactory;
filesystem_factory = filesystemFactory;
physics_factory = physicsFactory;
gpGlobals = pGlobals;
provider->Notify_DLLInit_Pre(server, engineFactory, gamedll_info.factory);
metamod_version = provider->CreateConVar("metamod_version",
SOURCEMM_VERSION,
"Metamod:Source Version",
ConVarFlag_Notify|ConVarFlag_Replicated|ConVarFlag_SpOnly);
mm_pluginsfile = provider->CreateConVar("mm_pluginsfile",
#if defined WIN32 || defined _WIN32
"addons\\metamod\\metaplugins.ini",
#else
"addons/metamod/metaplugins.ini",
#endif
"Metamod:Source Plugins File",
ConVarFlag_SpOnly);
const char *pluginFile = provider->GetCommandLineValue("mm_pluginsfile", NULL);
if (!pluginFile)
{
pluginFile = provider->GetConVarString(mm_pluginsfile);
if (pluginFile == NULL)
{
pluginFile = "addons/metamod/metaplugins.ini";
}
}
char full_path[260];
g_Metamod.PathFormat(full_path, sizeof(full_path), "%s/%s", mod_path.c_str(), pluginFile);
LoadPluginsFromFile(full_path);
in_first_level = true;
RETURN_META_VALUE(MRES_IGNORED, true);
}
bool Handler_GameInit()
{
if (is_game_init)
{
return true;
}
if (vsp_load_requested)
{
InitializeVSP();
}
is_game_init = true;
RETURN_META_VALUE(MRES_IGNORED, true);
}
bool Handler_DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
{
g_PluginMngr.SetAllLoaded();
RETURN_META_VALUE(MRES_IGNORED, true);
}
void Handler_DLLShutdown()
{
/* Unload plugins */
g_PluginMngr.UnloadAll();
provider->Notify_DLLShutdown_Pre();
SH_CALL(server, &IServerGameDLL::DLLShutdown)();
g_SourceHook.CompleteShutdown();
if (is_gamedll_loaded && gamedll_info.lib)
{
dlclose(gamedll_info.lib);
is_gamedll_loaded = false;
}
RETURN_META(MRES_SUPERCEDE);
}
void Handler_LevelShutdown(void)
{
if (!in_first_level)
{
char full_path[255];
g_Metamod.PathFormat(full_path,
sizeof(full_path),
"%s/%s",
mod_path.c_str(),
provider->GetConVarString(mm_pluginsfile));
LoadPluginsFromFile(full_path);
}
else
{
in_first_level = false;
}
ITER_EVENT(OnLevelShutdown, ());
RETURN_META(MRES_IGNORED);
}
bool Handler_LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
{
ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background));
RETURN_META_VALUE(MRES_IGNORED, false);
}
void MetamodSource::LogMsg(ISmmPlugin *pl, const char *msg, ...)
{
va_list ap;
char buffer[2048];
va_start(ap, msg);
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
va_end(ap);
LogMessage("[%s] %s", pl->GetLogTag(), buffer);
}
CreateInterfaceFn MetamodSource::engineFactory(bool syn/* =true */)
{
if (syn)
{
return EngineFactory;
}
return engine_factory;
}
CreateInterfaceFn MetamodSource::physicsFactory(bool syn/* =true */)
{
if (syn)
{
return PhysicsFactory;
}
return physics_factory;
}
CreateInterfaceFn MetamodSource::fileSystemFactory(bool syn/* =true */)
{
if (syn)
{
return FileSystemFactory;
}
return filesystem_factory;
}
CreateInterfaceFn MetamodSource::serverFactory(bool syn/* =true */)
{
if (syn)
{
return CreateInterface;
}
return gamedll_info.factory;
}
CGlobalVars *MetamodSource::pGlobals()
{
return gpGlobals;
}
void MetamodSource::SetLastMetaReturn(META_RES res)
{
last_meta_res = res;
}
META_RES MetamodSource::GetLastMetaReturn()
{
return last_meta_res;
}
void MetamodSource::ConPrint(const char *str)
{
provider->ConsolePrint(str);
}
void MetamodSource::ConPrintf(const char *fmt, ...)
{
va_list ap;
char buffer[2048];
va_start(ap, fmt);
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
provider->ConsolePrint(buffer);
}
void MetamodSource::GetApiVersions(int &major, int &minor, int &plvers, int &plmin)
{
major = SM_VERS_API_MAJOR;
minor = SM_VERS_API_MINOR;
plvers = PLAPI_VERSION;
plmin = PLAPI_MIN_VERSION;
}
void MetamodSource::GetShVersions(int &shvers, int &shimpl)
{
shvers = SH_IFACE_VERSION;
shimpl = SH_IMPL_VERSION;
}
int MetamodSource::FormatIface(char iface[], unsigned int maxlength)
{
int length = (int)strlen(iface);
int i;
int num = 0;
for (i = length - 1; i >= 0; i--)
{
if (!isdigit(iface[i]))
{
if (i != length - 1)
{
num = 1;
}
break;
}
}
if ( (num && ((int)maxlength <= length)) || (!num && ((int)maxlength <= length + 3)) )
{
return -1;
}
if (i != length - 1)
{
num = atoi(&(iface[++i]));
}
num++;
snprintf(&(iface[i]), 4, "%03d", num);
return num;
}
void *MetamodSource::InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, int *ret)
{
char _if[256]; /* assume no interface goes beyond this */
size_t len = strlen(iface);
int num = 0;
void *pf = NULL;
if (max > 999)
{
max = 999;
}
if (len + 4 > sizeof(_if))
{
if (ret)
{
*ret = IFACE_FAILED;
}
return NULL;
}
strcpy(_if, iface);
do
{
if ((pf = (fn)(_if, ret)) != NULL)
{
break;
}
if (num > max)
{
break;
}
} while ((num = FormatIface(_if, len+1)));
return pf;
}
void *MetamodSource::VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min)
{
char buffer[256]; /* assume no interface will go beyond this */
size_t len = strlen(iface);
int ret; /* just in case something doesn't handle NULL properly */
if (len > sizeof(buffer) - 4)
{
return NULL;
}
strcpy(buffer, iface);
if (min != -1)
{
char *ptr = &buffer[len - 1];
int digits = 0;
while (isdigit(*ptr) && digits <=3)
{
*ptr = '\0';
digits++;
ptr--;
}
if (digits != 3)
{
/* for now, assume this is an error */
strcpy(buffer, iface);
}
else
{
char num[4];
min = (min == 0) ? 1 : min;
snprintf(num, sizeof(num), "%03d", min);
strcat(buffer, num);
}
}
return InterfaceSearch(fn, buffer, IFACE_MAXNUM, &ret);
}
const char *MetamodSource::GetBaseDir()
{
return mod_path.c_str();
}
void MetamodSource::PathFormat(char *buffer, size_t len, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
size_t mylen = UTIL_FormatArgs(buffer, len, fmt, ap);
va_end(ap);
for (size_t i = 0; i < mylen; i++)
{
if (buffer[i] == ALT_SEP_CHAR)
{
buffer[i] = PATH_SEP_CHAR;
}
}
}
void MetamodSource::ClientConPrintf(edict_t *client, const char *fmt, ...)
{
va_list ap;
char buffer[2048];
va_start(ap, fmt);
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
provider->ClientConsolePrint(client, buffer);
}
void MetamodSource::EnableVSPListener()
{
if (is_game_init && !vsp_load_requested && !vsp_loaded)
{
InitializeVSP();
}
vsp_load_requested = true;
}
int MetamodSource::GetVSPVersion()
{
return vsp_version;
}
int MetamodSource::GetGameDLLVersion()
{
return gamedll_version;
}
bool MetamodSource::RemotePrintingAvailable()
{
return provider->IsRemotePrintingAvailable();
}
void *MetamodSource::MetaFactory(const char *iface, int *ret, PluginId *id)
{
if (id)
{
*id = 0;
}
if (!iface)
{
return NULL;
}
/* First check ours... we get first chance! */
if (strcmp(iface, MMIFACE_SOURCEHOOK) == 0)
{
if (ret)
{
*ret = IFACE_OK;
}
return static_cast<void *>(static_cast<SourceHook::ISourceHook *>(&g_SourceHook));
}
else if (strcmp(iface, MMIFACE_PLMANAGER) == 0)
{
if (ret)
{
*ret = IFACE_OK;
}
return static_cast<void *>(static_cast<ISmmPluginManager *>(&g_PluginMngr));
}
CPluginManager::CPlugin *pl;
List<IMetamodListener *>::iterator event;
IMetamodListener *api;
void *value;
int subret = 0;
for (PluginIter iter = g_PluginMngr._begin();
iter != g_PluginMngr._end();
iter++)
{
pl = (*iter);
for (event = pl->m_Events.begin(); event != pl->m_Events.end(); event++)
{
api = (*event);
subret = IFACE_FAILED;
if ((value = api->OnMetamodQuery(iface, &subret)) != NULL)
{
if (ret)
{
*ret = subret;
}
if (id)
{
*id = pl->m_Id;
}
return value;
}
}
}
if (ret)
{
*ret = IFACE_FAILED;
}
return NULL;
}
void MetamodSource::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener)
{
CPluginManager::CPlugin *pl = g_PluginMngr.FindByAPI(plugin);
pl->m_Events.push_back(pListener);
}
const char *MetamodSource::GetGameBinaryPath()
{
return full_bin_path.c_str();
}
const char *MetamodSource::GetPluginsFile()
{
return provider->GetConVarString(mm_pluginsfile);
}
IConCommandBaseAccessor *MetamodSource::GetCvarBaseAccessor()
{
return provider->GetConCommandBaseAccessor();
}
bool MetamodSource::RegisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand)
{
if (provider->IsConCommandBaseACommand(pCommand))
{
g_PluginMngr.AddPluginCmd(plugin, pCommand);
}
else
{
g_PluginMngr.AddPluginCvar(plugin, pCommand);
}
return provider->RegisterConCommandBase(pCommand);
}
void MetamodSource::UnregisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand)
{
if (provider->IsConCommandBaseACommand(pCommand))
{
g_PluginMngr.RemovePluginCmd(plugin, pCommand);
}
else
{
g_PluginMngr.RemovePluginCvar(plugin, pCommand);
}
CPluginManager::CPlugin *pOrig = g_PluginMngr.FindByAPI(plugin);
UnregisterConCommandBase(pOrig ? pOrig->m_Id : 0, pCommand);
}
void MetamodSource::UnregisterConCommandBase(PluginId id, ConCommandBase *pCommand)
{
PluginIter iter;
CPluginManager::CPlugin *pPlugin;
List<IMetamodListener *>::iterator event;
IMetamodListener *pML;
for (iter=g_PluginMngr._begin(); iter!=g_PluginMngr._end(); iter++)
{
pPlugin = (*iter);
if (pPlugin->m_Status < Pl_Paused)
{
continue;
}
/* Only valid for plugins >= 12 (v1:6, SourceMM 1.5) */
if (pPlugin->m_API->GetApiVersion() < 12)
{
continue;
}
for (event=pPlugin->m_Events.begin();
event!=pPlugin->m_Events.end();
event++)
{
pML = (*event);
pML->OnUnlinkConCommandBase(id, pCommand);
}
}
return provider->UnregisterConCommandBase(pCommand);
}
int MetamodSource::GetUserMessageCount()
{
return provider->GetUserMessageCount();
}
int MetamodSource::FindUserMessage(const char *name, int *size/* =NULL */)
{
return provider->FindUserMessage(name, size);
}
const char *MetamodSource::GetUserMessage(int index, int *size/* =NULL */)
{
return provider->GetUserMessage(index, size);
}
int MetamodSource::GetSourceEngineBuild()
{
return engine_build;
}
void MetamodSource::NotifyVSPListening(IServerPluginCallbacks *callbacks)
{
ITER_EVENT(OnVSPListening, (callbacks));
}
IServerPluginCallbacks *MetamodSource::GetVSPInfo(int *pVersion)
{
if (pVersion)
{
*pVersion = vsp_version;
}
return vsp_callbacks;
}

105
sourcemm/metamod.h Normal file
View File

@ -0,0 +1,105 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMM_H
#define _INCLUDE_SOURCEMM_H
/**
* @brief SourceMM main functionality for GameDLL interception
* @file sourcemm.h
*/
#include <string>
#include <interface.h>
#include <eiface.h>
#include <sourcehook/sourcehook_impl.h>
#include <sourcehook/sourcehook.h>
#include "ISmmAPI.h"
#include "metamod_provider.h"
#include "svn_version.h"
using namespace SourceMM;
/**
* Versioning
* increase api_major when API breaks
* increase api_minor when new functions are added (non-breaking)
*/
#define SOURCEMM_VERSION SVN_FILE_VERSION_STRING
#define SOURCEMM_DATE __DATE__
#define SM_VERS_API_MAJOR 1 //increase this on a breaking change
#define SM_VERS_API_MINOR 7 //increase this on a non-breaking API change
class MetamodSource : public ISmmAPI
{
public:
void LogMsg(ISmmPlugin *pl, const char *msg, ...);
CreateInterfaceFn engineFactory(bool syn=true);
CreateInterfaceFn physicsFactory(bool syn=true);
CreateInterfaceFn fileSystemFactory(bool syn=true);
CreateInterfaceFn serverFactory(bool syn=true);
CGlobalVars *pGlobals();
void SetLastMetaReturn(META_RES res);
META_RES GetLastMetaReturn();
IConCommandBaseAccessor *GetCvarBaseAccessor();
bool RegisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand);
void UnregisterConCmdBase(ISmmPlugin *plugin, ConCommandBase *pCommand);
void ConPrint(const char *str);
void ConPrintf(const char *fmt, ...);
bool RemotePrintingAvailable();
void GetApiVersions(int &major, int &minor, int &plvers, int &plmin);
void GetShVersions(int &shvers, int &shimpl);
void AddListener(ISmmPlugin *plugin, IMetamodListener *pListener);
void *MetaFactory(const char *iface, int *ret, PluginId *id);
int FormatIface(char iface[], unsigned int maxlength);
void *InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, int *ret);
const char *GetBaseDir();
void PathFormat(char *buffer, size_t len, const char *fmt, ...);
void ClientConPrintf(edict_t *client, const char *fmt, ...);
void *VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min=-1);
void EnableVSPListener();
int GetGameDLLVersion();
int GetUserMessageCount();
int FindUserMessage(const char *name, int *size=NULL);
const char *GetUserMessage(int index, int *size=NULL);
int GetVSPVersion();
int GetSourceEngineBuild();
IServerPluginCallbacks *GetVSPInfo(int *pVersion);
public:
const char *GetGameBinaryPath();
const char *GetPluginsFile();
void UnregisterConCommandBase(PluginId id, ConCommandBase *pCommand);
void NotifyVSPListening(IServerPluginCallbacks *callbacks);
};
void LogMessage(const char *msg, ...);
int LoadPluginsFromFile(const char *_file);
extern SourceHook::CSourceHookImpl g_SourceHook;
extern MetamodSource g_Metamod;
#endif //_INCLUDE_SOURCEMM_H

View File

@ -1,19 +1,43 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* License: zlib/libpng
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Author(s): David "BAILOPAN" Anderson
* ============================
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#if defined _DEBUG
#define DEBUG2
#undef _DEBUG
#endif
#include <ctype.h>
#include "CSmmAPI.h"
#include "concommands.h"
#include "CPlugin.h"
#include "sh_string.h"
#include "sh_list.h"
#include "metamod.h"
#include "metamod_util.h"
#include "metamod_console.h"
#include "metamod_plugins.h"
#if defined DEBUG2
#undef DEBUG2
#define _DEBUG
#endif
using namespace SourceMM;
using namespace SourceHook;
@ -23,143 +47,16 @@ using namespace SourceHook;
* @file concommands.cpp
*/
CAlwaysRegisterableCommand g_EternalCommand;
SMConVarAccessor g_SMConVarAccessor;
#define CONMSG g_Metamod.ConPrintf
#define CLIENT_CONMSG g_Metamod.ClientConPrintf
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
bool Command_Meta(IMetamodSourceCommandInfo *info)
{
// Add the FCVAR_GAMEDLL flag
// => No crash on exit!
// UPDATE: Do _not_ add the FCVAR_GAMEDLL flag here, as it
// causes the command to be unusable on listenservers until you load a map
// We will set the FCVAR_GAMEDLL flag on all commands we have registered once we are being unloaded
//pCommand->AddFlags(FCVAR_GAMEDLL);
m_RegisteredCommands.push_back(pCommand);
unsigned int args = info->GetArgCount();
pCommand->SetNext( NULL );
g_Engine.icvar->RegisterConCommandBase(pCommand);
return true;
}
bool SMConVarAccessor::Register(ConCommandBase *pCommand)
{
//simple, don't mark as part of sourcemm!
pCommand->SetNext( NULL );
g_Engine.icvar->RegisterConCommandBase(pCommand);
return true;
}
void SMConVarAccessor::MarkCommandsAsGameDLL()
{
for (List<ConCommandBase*>::iterator iter = m_RegisteredCommands.begin();
iter != m_RegisteredCommands.end(); ++iter)
if (args >= 1)
{
(*iter)->AddFlags(FCVAR_GAMEDLL);
}
}
void SMConVarAccessor::Unregister(PluginId id, ConCommandBase *pCommand)
{
/* Notify via IMetamodListener */
PluginIter iter;
CPluginManager::CPlugin *pPlugin;
List<IMetamodListener *>::iterator event;
IMetamodListener *pML;
for (iter=g_PluginMngr._begin(); iter!=g_PluginMngr._end(); iter++)
{
pPlugin = (*iter);
if (pPlugin->m_Status < Pl_Paused)
{
continue;
}
/* Only valid for plugins >= 12 (v1:6, SourceMM 1.5) */
if (pPlugin->m_API->GetApiVersion() < 12)
{
continue;
}
for (event=pPlugin->m_Events.begin();
event!=pPlugin->m_Events.end();
event++)
{
pML = (*event);
pML->OnUnlinkConCommandBase(id, pCommand);
}
}
ICvar *cv = g_Engine.icvar;
ConCommandBase *ptr = cv->GetCommands();
if (ptr == pCommand)
{
/* First in list */
g_EternalCommand.BringToFront();
g_EternalCommand.SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
} else {
/* Find us and unregister us */
ConCommandBase *pPrev = NULL;
while (ptr)
{
if (ptr == pCommand)
break;
pPrev = ptr;
ptr = const_cast<ConCommandBase *>(ptr->GetNext());
}
if (pPrev && ptr == pCommand)
{
pPrev->SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
}
}
}
void SMConVarAccessor::UnregisterGameDLLCommands()
{
ConCommandBase *begin = g_Engine.icvar->GetCommands();
ConCommandBase *iter = begin;
ConCommandBase *prev = NULL;
while (iter)
{
/* Watch out for the ETERNAL COMMAND! */
if (iter != &g_EternalCommand && iter->IsBitSet(FCVAR_GAMEDLL))
{
/* Remove it! */
if (iter == begin)
{
g_EternalCommand.BringToFront();
iter = const_cast<ConCommandBase*>(iter->GetNext());
g_EternalCommand.SetNext(iter);
prev = &g_EternalCommand;
continue;
}
else
{
iter = const_cast<ConCommandBase*>(iter->GetNext());
prev->SetNext(iter);
continue;
}
}
prev = iter;
iter = const_cast<ConCommandBase*>(iter->GetNext());
}
}
ConVar metamod_version("metamod_version", SOURCEMM_VERSION, FCVAR_REPLICATED | FCVAR_SPONLY | FCVAR_NOTIFY, "Metamod:Source Version");
#if defined WIN32 || defined _WIN32
ConVar mm_pluginsfile("mm_pluginsfile", "addons\\metamod\\metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File");
#else
ConVar mm_pluginsfile("mm_pluginsfile", "addons/metamod/metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File");
#endif
CON_COMMAND(meta, "Metamod:Source Menu")
{
IVEngineServer *e = g_Engine.engine;
int args = e->Cmd_Argc();
if (args >= 2)
{
const char *command = e->Cmd_Argv(1);
const char *command = info->GetArg(1);
if (strcmp(command, "credits") == 0)
{
CONMSG("Metamod:Source was developed by:\n");
@ -169,57 +66,73 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG("For more information, see the official website\n");
CONMSG("http://www.sourcemm.net/\n");
return;
} else if (strcmp(command, "version") == 0) {
return true;
}
else if (strcmp(command, "version") == 0)
{
CONMSG("Metamod:Source version %s\n", SOURCEMM_VERSION);
CONMSG("Compiled on: %s\n", SOURCEMM_DATE);
CONMSG("Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION);
CONMSG("SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
CONMSG("http://www.sourcemm.net/\n");
return;
} else if (strcmp(command, "game") == 0) {
return true;
}
else if (strcmp(command, "game") == 0)
{
CONMSG("GameDLL Information\n");
CONMSG(" Description: %s\n", g_GameDll.pGameDLL->GetGameDescription());
CONMSG(" Mod Path: %s\n", g_ModPath.c_str());
CONMSG(" DLL Path: %s\n", g_BinPath.c_str());
CONMSG(" Interface: ServerGameDLL%03d, ServerGameClients%03d\n", g_GameDllVersion, g_GameClientsVersion);
CONMSG(" Description: %s\n", provider->GetGameDescription());
CONMSG(" Mod Path: %s\n", g_Metamod.GetBaseDir());
CONMSG(" DLL Path: %s\n", g_Metamod.GetGameBinaryPath());
CONMSG(" Interface: ServerGameDLL%03d\n", g_Metamod.GetGameDLLVersion());
// Display user messages
if (g_SmmAPI.MsgCacheSuccessful())
int messages = g_Metamod.GetUserMessageCount();
if (messages != -1)
{
const char *msgname;
int msgsize;
int msgcount = g_SmmAPI.GetUserMessageCount();
if (msgcount > 0)
if (messages > 0)
{
CONMSG(" User Messages: %-32.31s %-5s %-5s\n", "Name", "Index", "Size");
for (int i = 0; i < msgcount; i++)
for (int i = 0; i < messages; i++)
{
msgname = g_SmmAPI.GetUserMessage(i, &msgsize);
msgname = g_Metamod.GetUserMessage(i, &msgsize);
CONMSG(" %-32.31s %-5d %-5d\n", msgname, i, msgsize);
}
CONMSG(" %d user message%s in total\n", msgcount, (msgcount > 1) ? "s" : "");
} else {
CONMSG(" %d user message%s in total\n", messages, (messages > 1) ? "s" : "");
}
else
{
CONMSG(" User Messages: None\n");
}
} else {
}
else
{
CONMSG(" User Messages: Failed to get list of user messages\n");
}
return;
} else if (strcmp(command, "refresh") == 0) {
return true;
}
else if (strcmp(command, "refresh") == 0)
{
char full_path[255];
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile());
g_Metamod.PathFormat(full_path,
sizeof(full_path),
"%s/%s",
g_Metamod.GetBaseDir(),
g_Metamod.GetPluginsFile());
LoadPluginsFromFile(full_path);
return;
} else if (strcmp(command, "list") == 0) {
return true;
}
else if (strcmp(command, "list") == 0)
{
CPluginManager::CPlugin *pl;
ISmmPlugin *plapi;
const char *plname;
@ -231,7 +144,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
if (!plnum)
{
CONMSG("No plugins loaded.\n");
return;
return true;
} else {
CONMSG("Listing %d plugin%s:\n", plnum, (plnum > 1) ? "s" : "");
}
@ -271,23 +184,27 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG("%s\n", buffer);
}
return;
} else if (strcmp(command, "cmds") == 0) {
if (args >= 3)
return true;
}
else if (strcmp(command, "cmds") == 0)
{
if (args >= 2)
{
int id = atoi(e->Cmd_Argv(2));
int id = atoi(info->GetArg(2));
CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
if (!pl)
{
CONMSG("Plugin %d not found.\n", id);
return;
return true;
}
if (!pl->m_API)
{
CONMSG("Plugin %d is not loaded.\n", id);
} else {
}
else
{
CONMSG("Console commands for %s:\n", pl->m_API->GetName());
List<ConCommandBase *>::iterator ci;
size_t count = 0;
@ -298,27 +215,33 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG(" [%5d] %-s\n", count, (*ci)->GetName());
}
}
} else {
}
else
{
CONMSG("Usage: meta cmds <id>\n");
}
return;
} else if (strcmp(command, "cvars") == 0) {
if (args >= 3)
return true;
}
else if (strcmp(command, "cvars") == 0)
{
if (args >= 2)
{
int id = atoi(e->Cmd_Argv(2));
int id = atoi(info->GetArg(2));
CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
if (!pl)
{
CONMSG("Plugin %d not found.\n", id);
return;
return true;
}
if (!pl->m_API)
{
CONMSG("Plugin %d is not loaded.\n", id);
} else {
}
else
{
CONMSG("Registered cvars for %s:\n", pl->m_API->GetName());
List<ConCommandBase *>::iterator ci;
size_t count = 0;
@ -329,38 +252,50 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG(" [%5d] %-s\n", count, (*ci)->GetName());
}
}
} else {
}
else
{
CONMSG("Usage: meta cvars <id>\n");
}
return;
} else if (strcmp(command, "info") == 0) {
if (args >= 3)
return true;
}
else if (strcmp(command, "info") == 0)
{
if (args >= 2)
{
int id = atoi(e->Cmd_Argv(2));
int id = atoi(info->GetArg(2));
CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
if (!pl)
{
CONMSG("Plugin %d not found.\n", id);
return;
return true;
}
if (!pl->m_API)
{
CONMSG("Plugin %d is not loaded.\n", id);
} else {
}
else
{
if (pl->m_Status == Pl_Paused)
{
CONMSG("Plugin %d is paused.\n", id);
} else if (pl->m_Status == Pl_Running) {
}
else if (pl->m_Status == Pl_Running)
{
char run_msg[255];
bool run = false;
if (pl->m_API && pl->m_API->QueryRunning(run_msg, sizeof(run_msg)-1))
{
run = true;
}
if (run)
{
CONMSG("Plugin %d is running.\n", id);
} else {
}
else
{
CONMSG("Plugin %d is stopped: %s\n", id, run_msg);
}
}
@ -373,57 +308,69 @@ CON_COMMAND(meta, "Metamod:Source Menu")
}
CONMSG("File: %s\n\n", pl->m_File.c_str());
return;
} else {
return true;
}
else
{
CONMSG("Usage: meta info <id>\n");
return;
return true;
}
} else if (strcmp(command, "pause") == 0) {
if (args >= 3)
}
else if (strcmp(command, "pause") == 0)
{
if (args >= 2)
{
int id = atoi(e->Cmd_Argv(2));
int id = atoi(info->GetArg(2));
char error[255];
if (!g_PluginMngr.Pause(id, error, sizeof(error)))
{
CONMSG("Pause failed: %s\n", error);
return;
return true;
}
CONMSG("Plugin %d has been paused.\n", id);
return;
} else {
return true;
}
else
{
CONMSG("Usage: meta pause <id>\n");
return;
return true;
}
} else if (strcmp(command, "unpause") == 0) {
if (args >= 3)
}
else if (strcmp(command, "unpause") == 0)
{
if (args >= 2)
{
int id = atoi(e->Cmd_Argv(2));
int id = atoi(info->GetArg(2));
char error[255];
if (!g_PluginMngr.Unpause(id, error, sizeof(error)))
{
CONMSG("Unpause failed: %s\n", error);
return;
return true;
}
CONMSG("Plugin %d has been unpaused.\n", id);
return;
} else {
return true;
}
else
{
CONMSG("Usage: meta unpause <id>\n");
return;
return true;
}
} else if (strcmp(command, "load") == 0) {
if (args >= 3)
}
else if (strcmp(command, "load") == 0)
{
if (args >= 2)
{
const char *file = e->Cmd_Argv(2);
const char *file = info->GetArg(2);
char full_path[255];
const char *alias = g_PluginMngr.LookupAlias(file);
@ -434,15 +381,22 @@ CON_COMMAND(meta, "Metamod:Source Menu")
if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0)
{
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s", file);
} else {
g_Metamod.PathFormat(full_path, sizeof(full_path), "%s", file);
}
else
{
const char *ext = UTIL_GetExtension(file);
#if defined WIN32 || defined _WIN32
ext = ext ? "" : ".dll";
#else
ext = ext ? "" : "_i486.so";
#endif
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext);
g_Metamod.PathFormat(full_path,
sizeof(full_path),
"%s/%s%s",
g_Metamod.GetBaseDir(),
file,
ext);
}
char error[255]={0};
@ -454,7 +408,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
if (!pl || id < Pl_MinId || (pl->m_Status < Pl_Paused))
{
CONMSG("Failed to load plugin %s (%s).\n", file, error);
return;
return true;
}
if (!already)
@ -464,28 +418,34 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG("Plugin \"%s\" is already loaded as %d.\n", pl->m_API->GetName(), pl->m_Id);
}
return;
} else {
return true;
}
else
{
CONMSG("Usage: meta load <path>\n");
return;
return true;
}
} else if ( (strcmp(command, "alias") == 0) ||
(strcmp(command, "aliases") == 0) ) {
if (args >= 4)
}
else if ( (strcmp(command, "alias") == 0) ||
(strcmp(command, "aliases") == 0) )
{
if (args >= 3)
{
const char *alias = e->Cmd_Argv(2);
const char *value = e->Cmd_Argv(3);
const char *alias = info->GetArg(2);
const char *value = info->GetArg(3);
g_PluginMngr.SetAlias(alias, value);
if (value[0] == '\0')
if (value == NULL || value[0] == '\0')
{
CONMSG("Deleted alias: %s.\n", alias);
} else {
CONMSG("Set alias \"%s\" to: %s\n", alias, value);
}
} else if (args >= 3) {
const char *alias = e->Cmd_Argv(2);
}
else if (args >= 2)
{
const char *alias = info->GetArg(2);
const char *value = g_PluginMngr.LookupAlias(alias);
if (value)
{
@ -493,7 +453,9 @@ CON_COMMAND(meta, "Metamod:Source Menu")
} else {
CONMSG("Alias \"%s\" was not found.\n", alias);
}
} else {
}
else
{
List<CNameAlias *>::iterator iter, end;
CNameAlias *p;
@ -512,15 +474,19 @@ CON_COMMAND(meta, "Metamod:Source Menu")
}
CONMSG(" --- \n");
CONMSG("%d aliases total.\n", total);
} else {
}
else
{
CONMSG("No aliases found.\n");
}
}
return;
} else if (strcmp(command, "unload") == 0) {
if (args >= 3)
return true;
}
else if (strcmp(command, "unload") == 0)
{
if (args >= 2)
{
const char *file = e->Cmd_Argv(2);
const char *file = info->GetArg(2);
int id = atoi(file);
char error[255]={0};
@ -537,15 +503,22 @@ CON_COMMAND(meta, "Metamod:Source Menu")
/* first check if it's a known filename */
if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0)
{
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s", file);
} else {
g_Metamod.PathFormat(full_path, sizeof(full_path), "%s", file);
}
else
{
const char *ext = UTIL_GetExtension(file);
#if defined WIN32 || defined _WIN32
ext = ext ? "" : ".dll";
#else
ext = ext ? "" : "_i486.so";
#endif
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext);
g_Metamod.PathFormat(full_path,
sizeof(full_path),
"%s/%s%s",
g_Metamod.GetBaseDir(),
file,
ext);
}
List<CPluginManager::CPlugin *>::iterator iter, end;
@ -564,70 +537,82 @@ CON_COMMAND(meta, "Metamod:Source Menu")
if (id == 0)
{
CONMSG("Plugin \"%s\" not found.\n", full_path);
return;
return true;
}
}
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)))
{
CONMSG("Unload failed: %s\n", error);
return;
return true;
}
CONMSG("Plugin %d unloaded.\n", id);
} else {
}
else
{
CONMSG("Usage: meta unload <id>\n");
}
return;
} else if (strcmp(command, "force_unload") == 0) {
if (args >= 3)
return true;
}
else if (strcmp(command, "force_unload") == 0)
{
if (args >= 2)
{
int id = atoi(e->Cmd_Argv(2));
int id = atoi(info->GetArg(2));
char error[255]={0};
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)))
{
CONMSG("Force unload failed: %s\n", error);
return;
return true;
}
CONMSG("Plugin %d force unloaded.\n", id);
return;
} else {
return true;
}
else
{
CONMSG("Usage: meta force_unload <id>\n");
return;
return true;
}
} else if (strcmp(command, "clear") == 0) {
}
else if (strcmp(command, "clear") == 0)
{
if (!g_PluginMngr.UnloadAll())
{
CONMSG("One or more plugins resisted removal (cleaned anyway).\n");
return;
return true;
}
CONMSG("All plugins unloaded.\n");
return;
} else if (strcmp(command, "retry") == 0) {
if (args >= 3)
return true;
}
else if (strcmp(command, "retry") == 0)
{
if (args >= 2)
{
int id = atoi(e->Cmd_Argv(2));
int id = atoi(info->GetArg(2));
char error[255];
if (!g_PluginMngr.Retry(id, error, sizeof(error)))
{
CONMSG("Error reloading plugin: %s\n", error);
return;
return true;
}
CONMSG("Plugin %d successfully reloaded.\n", id);
return;
} else {
return true;
}
else
{
CONMSG("Usage: meta retry <id>\n");
return;
return true;
}
}
}
@ -650,66 +635,20 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG(" unload - Unload a loaded plugin\n");
CONMSG(" unpause - Unpause a paused plugin\n");
CONMSG(" version - Version information\n");
return true;
}
CAlwaysRegisterableCommand::CAlwaysRegisterableCommand()
bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info)
{
Create("", NULL, FCVAR_UNREGISTERED|FCVAR_GAMEDLL);
m_pICvar = NULL;
}
bool CAlwaysRegisterableCommand::IsRegistered( void ) const
{
return false;
}
void CAlwaysRegisterableCommand::BringToFront()
{
if (!m_pICvar)
m_pICvar = g_Engine.icvar;
// First, let's try to find us!
ConCommandBase *pPtr = m_pICvar->GetCommands();
if (pPtr == this)
{
// We are already at the beginning; Nothing to do
return;
}
while (pPtr)
{
if (pPtr == this && pPtr->IsCommand() && stricmp(GetName(), pPtr->GetName()) == 0)
break;
ConCommandBase *pPrev = NULL;
while (pPtr)
{
if (pPtr == this)
break;
pPrev = pPtr;
pPtr = const_cast<ConCommandBase*>(pPtr->GetNext());
}
if (pPrev && pPtr == this)
{
pPrev->SetNext(m_pNext); // Remove us from the list
}
// Now, register us
SetNext(NULL);
m_pICvar->RegisterConCommandBase(this);
}
}
void ClientCommand_handler(edict_t *client)
{
IVEngineServer *e = g_Engine.engine;
const char *cmd = e->Cmd_Argv(0);
const char *cmd = info->GetArg(0);
if (strcmp(cmd, "meta") == 0)
{
int args = e->Cmd_Argc();
if (args == 2)
unsigned int args = info->GetArgCount();
if (args == 1)
{
const char *subcmd = e->Cmd_Argv(1);
const char *subcmd = info->GetArg(1);
if (strcmp(subcmd, "credits") == 0)
{
@ -720,16 +659,20 @@ void ClientCommand_handler(edict_t *client)
CLIENT_CONMSG(client, "For more information, see the official website\n");
CLIENT_CONMSG(client, "http://www.sourcemm.net/\n");
RETURN_META(MRES_SUPERCEDE);
} else if(strcmp(subcmd, "version") == 0) {
return true;
}
else if(strcmp(subcmd, "version") == 0)
{
CLIENT_CONMSG(client, "Metamod:Source version %s\n", SOURCEMM_VERSION);
CLIENT_CONMSG(client, "Compiled on: %s\n", SOURCEMM_DATE);
CLIENT_CONMSG(client, "Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION);
CLIENT_CONMSG(client, "SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
CLIENT_CONMSG(client, "http://www.sourcemm.net/\n");
RETURN_META(MRES_SUPERCEDE);
} else if(strcmp(subcmd, "list") == 0) {
return true;
}
else if(strcmp(subcmd, "list") == 0)
{
CPluginManager::CPlugin *pl;
ISmmPlugin *plapi;
const char *plname;
@ -773,7 +716,7 @@ void ClientCommand_handler(edict_t *client)
CLIENT_CONMSG(client, "No active plugins loaded.\n");
}
RETURN_META(MRES_SUPERCEDE);
return true;
}
}
@ -783,13 +726,8 @@ void ClientCommand_handler(edict_t *client)
CLIENT_CONMSG(client, " list - List plugins\n");
CLIENT_CONMSG(client, " version - Version information\n");
RETURN_META(MRES_SUPERCEDE);
return true;
}
RETURN_META(MRES_IGNORED);
}
const char *GetPluginsFile()
{
return mm_pluginsfile.GetString();
return false;
}

View File

@ -0,0 +1,36 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_CONCOMMANDS_H
#define _INCLUDE_CONCOMMANDS_H
#include "metamod_provider.h"
bool Command_Meta(IMetamodSourceCommandInfo *info);
bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info);
#endif //_INCLUDE_CONCOMMANDS_H

101
sourcemm/metamod_oslink.cpp Normal file
View File

@ -0,0 +1,101 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#include "metamod_oslink.h"
#include <malloc.h>
#ifdef __linux
#include <errno.h>
#include <stdio.h>
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32
const char *dlerror()
{
static char buf[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &buf, 0, NULL);
return buf;
}
#endif
#if defined __linux__
int GetLastError()
{
return errno;
}
extern "C" void __cxa_guard_acquire(void)
{
}
extern "C" void __cxa_guard_release(void)
{
}
#endif
bool GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
{
#if defined WIN32 || defined _WIN32
MEMORY_BASIC_INFORMATION mem;
if (!VirtualQuery(pAddr, &mem, sizeof(mem)))
return false;
if (mem.AllocationBase == NULL)
return false;
HMODULE dll = (HMODULE)mem.AllocationBase;
GetModuleFileName(dll, (LPTSTR)buffer, maxlength);
#elif defined __linux__
Dl_info info;
if (!dladdr(pAddr, &info))
return false;
if (!info.dli_fbase || !info.dli_fname)
return false;
const char *dllpath = info.dli_fname;
snprintf(buffer, maxlength, "%s", dllpath);
#endif
return true;
}
#if defined __GNUC__ && (__GNUC__ == 3 || __GNUC__ == 4)
void * operator new(size_t size) {
return malloc(size);
}
void * operator new[](size_t size) {
return malloc(size);
}
void operator delete(void * ptr) {
free(ptr);
}
void operator delete[](void * ptr) {
free(ptr);
}
#endif

View File

@ -1,11 +1,28 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* License: zlib/libpng
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Author(s): David "BAILOPAN" Anderson
* ============================
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_OSLINK_H
@ -37,6 +54,7 @@
#define ALT_SEP_CHAR '/'
#define PATH_SIZE MAX_PATH
#define SERVER_DLL "server.dll"
#define strcasecmp stricmp
#elif defined __linux__
#define OS_LINUX
#include <dlfcn.h>

View File

@ -1,647 +1,747 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
#include "CPlugin.h"
#include "CSmmAPI.h"
#include "sourcemm.h"
#include "concommands.h"
/**
* @brief Implements functions from CPlugin.h
* @file CPlugin.cpp
*/
using namespace SourceMM;
#define ITER_PLEVENT(evn, plid) \
CPluginManager::CPlugin *_Xpl; \
SourceHook::List<IMetamodListener *>::iterator event; \
IMetamodListener *api; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
_Xpl = (*iter); \
if (_Xpl->m_Id == plid) \
continue; \
for (event=_Xpl->m_Events.begin(); event!=_Xpl->m_Events.end(); event++) { \
api = (*event); \
api->evn(plid); \
} \
}
CPluginManager g_PluginMngr;
CPluginManager::CPluginManager()
{
m_LastId = Pl_MinId;
m_AllLoaded = false;
}
CPluginManager::~CPluginManager()
{
SourceHook::List<CNameAlias *>::iterator iter;
for (iter=m_Aliases.begin(); iter!=m_Aliases.end(); iter++)
{
delete (*iter);
}
m_Aliases.clear();
}
const char *CPluginManager::LookupAlias(const char *alias)
{
SourceHook::List<CNameAlias *>::iterator iter;
CNameAlias *p;
for (iter=m_Aliases.begin(); iter!=m_Aliases.end(); iter++)
{
p = (*iter);
if (p->alias.compare(alias) == 0)
{
return p->value.c_str();
}
}
return NULL;
}
SourceHook::List<SourceMM::CNameAlias *>::iterator CPluginManager::_alias_begin()
{
return m_Aliases.begin();
}
SourceHook::List<SourceMM::CNameAlias *>::iterator CPluginManager::_alias_end()
{
return m_Aliases.end();
}
void CPluginManager::SetAlias(const char *alias, const char *value)
{
SourceHook::List<CNameAlias *>::iterator iter;
CNameAlias *p;
for (iter=m_Aliases.begin(); iter!=m_Aliases.end(); iter++)
{
p = (*iter);
if (p->alias.compare(alias) == 0)
{
if (value[0] == '\0')
{
iter = m_Aliases.erase(iter);
return;
} else {
p->value.assign(value);
return;
}
}
}
if (value[0] != '\0')
{
p = new CNameAlias;
p->alias.assign(alias);
p->value.assign(value);
m_Aliases.push_back(p);
}
}
CPluginManager::CPlugin::CPlugin() : m_Id(0), m_Source(0), m_API(NULL), m_Lib(NULL)
{
}
PluginId CPluginManager::Load(const char *file, PluginId source, bool &already, char *error, size_t maxlen)
{
already = false;
//Check if we're about to reload an old plugin
PluginIter i = m_Plugins.begin();
while (i != m_Plugins.end())
{
if ( (*i) && UTIL_PathCmp(file, (*i)->m_File.c_str()) )
{
if ( (*i)->m_Status < Pl_Paused )
{
//Attempt to load the plugin again
already = true;
i = m_Plugins.erase(i);
continue;
} else {
//No need to load it
already = true;
return (*i)->m_Id;
}
}
i++;
}
CPlugin *pl = _Load(file, source, error, maxlen);
if (!pl)
return Pl_BadLoad;
ITER_PLEVENT(OnPluginLoad, pl->m_Id);
return pl->m_Id;
}
CPluginManager::CPlugin *CPluginManager::FindById(PluginId id)
{
PluginIter i;
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i)->m_Id == id )
return (*i);
}
return NULL;
}
void CPluginManager::SetAllLoaded()
{
m_AllLoaded = true;
PluginIter i;
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i) && (*i)->m_Status == Pl_Running && (*i)->m_API )
{
//API 4 is when we added this callback
//Min version is now 5, so we ignore this check
//if ( (*i)->m_API->GetApiVersion() >= 004 )
(*i)->m_API->AllPluginsLoaded();
}
}
}
bool CPluginManager::Pause(PluginId id, char *error, size_t maxlen)
{
CPlugin *pl = FindById(id);
if (!pl)
{
UTIL_Format(error, maxlen, "Plugin id not found");
return false;
}
bool ret;
if ( (ret=_Pause(pl, error, maxlen)) == true )
{
ITER_PLEVENT(OnPluginPause, pl->m_Id);
}
return ret;
}
bool CPluginManager::Unpause(PluginId id, char *error, size_t maxlen)
{
CPlugin *pl = FindById(id);
if (!pl)
{
UTIL_Format(error, maxlen, "Plugin id not found");
return false;
}
bool ret;
if ( (ret=_Unpause(pl, error, maxlen)) == true )
{
ITER_PLEVENT(OnPluginUnpause, pl->m_Id);
}
return ret;
}
bool CPluginManager::Unload(PluginId id, bool force, char *error, size_t maxlen)
{
CPlugin *pl = FindById(id);
if (!pl)
{
UTIL_Format(error, maxlen, "Plugin %d not found", id);
return false;
}
bool ret;
PluginId old_id = pl->m_Id;
if ( (ret=_Unload(pl, force, error, maxlen)) == true )
{
ITER_PLEVENT(OnPluginUnload, old_id);
}
return ret;
}
bool CPluginManager::Retry(PluginId id, char *error, size_t len)
{
PluginIter i;
char buffer[64];
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i) && (*i)->m_Id == id )
{
if ( (*i)->m_Status >= Pl_Paused)
{
UTIL_Format(error, len, "Plugin %d is already running.", id);
return false;
}
CPlugin *pl = _Load((*i)->m_File.c_str(), Pl_Console, error, len);
if (!pl)
return false;
if (pl->m_Status >= Pl_Paused)
{
//Now it gets crazy... unload the original copy.
_Unload( (*i), true, buffer, sizeof(buffer)-1 );
//Set the new copy's id
pl->m_Id = id;
//We just wasted an id... reclaim it
m_LastId--;
return true;
} else {
//don't really care about the buffer here
_Unload(pl, true, buffer, sizeof(buffer)-1);
//We just wasted an id... reclaim it
m_LastId--;
return false;
}
}
}
UTIL_Format(error, len, "Plugin %d not found,", id);
return false;
}
CPluginManager::CPlugin *CPluginManager::FindByAPI(ISmmPlugin *api)
{
PluginIter i;
//don't find bad plugins!
if (!api)
return NULL;
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i)->m_API == api )
return (*i);
}
return NULL;
}
int CPluginManager::GetPluginCount()
{
return (int)m_Plugins.size();
}
const char *CPluginManager::GetStatusText(CPlugin *pl)
{
switch (pl->m_Status)
{
case Pl_NotFound:
return "NOFILE";
case Pl_Error:
return "ERROR";
case Pl_Refused:
return "FAILED";
case Pl_Paused:
return "PAUSED";
case Pl_Running:
{
if (pl->m_API && pl->m_API->QueryRunning(NULL, 0))
{
return "STOPPED";
} else {
return "RUNNING";
}
}
default:
return "-";
}
}
CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source, char *error, size_t maxlen)
{
FILE *fp;
CPlugin *pl;
pl = new CPlugin();
*error = '\0';
//Add plugin to list
pl->m_Id = m_LastId;
pl->m_File.assign(file);
m_Plugins.push_back(pl);
m_LastId++;
//Check if the file even exists
fp = fopen(file, "r");
if (!fp)
{
if (error)
UTIL_Format(error, maxlen, "File not found: %s", file);
pl->m_Status = Pl_NotFound;
}
if (fp)
{
fclose(fp);
fp = NULL;
//Load the file
pl->m_Lib = dlmount(file);
if (!pl->m_Lib)
{
if (error)
UTIL_Format(error, maxlen, "%s", dlerror());
pl->m_Status = Pl_Error;
} else {
CreateInterfaceFn pfn = (CreateInterfaceFn)(dlsym(pl->m_Lib, PL_EXPOSURE_C));
if (!pfn)
{
if (error)
UTIL_Format(error, maxlen, "Function %s not found", PL_EXPOSURE_C);
pl->m_Status = Pl_Error;
} else {
pl->m_API = static_cast<ISmmPlugin *>((pfn)(PLAPI_NAME, NULL));
if (!pl->m_API)
{
if (error)
UTIL_Format(error, maxlen, "Failed to get API");
pl->m_Status = Pl_Error;
} else {
int api = pl->m_API->GetApiVersion();
if (api < PLAPI_MIN_VERSION)
{
if (error)
UTIL_Format(error, maxlen, "Plugin API %d is out of date with required minimum (%d)", api, PLAPI_MIN_VERSION);
pl->m_Status = Pl_Error;
} else if (api > PLAPI_VERSION) {
if (error)
UTIL_Format(error, maxlen, "Plugin API %d is newer than internal version (%d)", api, PLAPI_VERSION);
pl->m_Status = Pl_Error;
} else {
if (pl->m_API->Load(pl->m_Id, static_cast<ISmmAPI *>(&g_SmmAPI), error, maxlen, m_AllLoaded))
{
pl->m_Status = Pl_Running;
if (m_AllLoaded)
{
//API 4 is when we added this callback
//Removing this code as the min version is now 5
//if (pl->m_API->GetApiVersion() >= 4)
pl->m_API->AllPluginsLoaded();
}
} else {
pl->m_Status = Pl_Refused;
}
}
}
}
}
}
if (pl->m_Lib && (pl->m_Status < Pl_Paused))
{
pl->m_Events.clear();
g_SourceHook.UnloadPlugin(pl->m_Id);
UnregAllConCmds(pl);
dlclose(pl->m_Lib);
pl->m_Lib = NULL;
pl->m_API = NULL;
}
return pl;
}
bool CPluginManager::_Unload(CPluginManager::CPlugin *pl, bool force, char *error, size_t maxlen)
{
if (error)
*error = '\0';
if (pl->m_API && pl->m_Lib)
{
//Note, we'll always tell the plugin it will be unloading...
if (pl->m_API->Unload(error, maxlen) || force)
{
//Make sure to detach it from sourcehook!
g_SourceHook.UnloadPlugin(pl->m_Id);
UnregAllConCmds(pl);
//Clean up the DLL
dlclose(pl->m_Lib);
pl->m_Lib = NULL;
pl->m_API = NULL;
//Remove the plugin from the list
PluginIter i;
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i)->m_Id == pl->m_Id )
{
i = m_Plugins.erase(i);
break;
}
}
//Free its memory
delete pl;
return true;
}
} else {
//The plugin is not valid, and let's just remove it from the list anyway
PluginIter i;
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i)->m_Id == pl->m_Id )
{
i = m_Plugins.erase(i);
break;
}
}
delete pl;
return true;
}
return false;
}
bool CPluginManager::_Pause(CPluginManager::CPlugin *pl, char *error, size_t maxlen)
{
if (error)
*error = '\0';
if (pl->m_Status != Pl_Running || !pl->m_API)
{
if (error)
UTIL_Format(error, maxlen, "Plugin cannot be paused");
} else {
if (pl->m_API->Pause(error, maxlen))
{
g_SourceHook.PausePlugin(pl->m_Id);
pl->m_Status = Pl_Paused;
return true;
}
}
return false;
}
bool CPluginManager::_Unpause(CPluginManager::CPlugin *pl, char *error, size_t maxlen)
{
if (error)
*error = '\0';
if (pl->m_Status != Pl_Paused || !pl->m_API)
{
if (error)
UTIL_Format(error, maxlen, "Plugin cannot be unpaused");
} else {
if (pl->m_API->Unpause(error, maxlen))
{
g_SourceHook.UnpausePlugin(pl->m_Id);
pl->m_Status = Pl_Running;
return true;
}
}
return false;
}
bool CPluginManager::UnloadAll()
{
PluginIter i;
char error[128];
bool status = true;
while ((i = m_Plugins.begin()) != m_Plugins.end())
{
if ( !_Unload( (*i), true, error, sizeof(error)) )
status = false;
}
return status;
}
bool CPluginManager::Query(PluginId id, const char *&file, Pl_Status &status, PluginId &source)
{
CPlugin *pl = FindById(id);
if (!pl)
return false;
file = pl->m_File.c_str();
status = pl->m_Status;
source = pl->m_Source;
return true;
}
bool CPluginManager::QueryRunning(PluginId id, char *error, size_t maxlength)
{
CPlugin *pl = FindById(id);
if (!pl || !pl->m_API)
{
if (error)
UTIL_Format(error, maxlength, "Plugin not valid");
return false;
}
return pl->m_API->QueryRunning(error, maxlength);
}
bool CPluginManager::QueryHandle(PluginId id, void *&handle)
{
CPlugin *pl = FindById(id);
if (!pl)
{
return false;
}
handle = static_cast<void *>(pl->m_Lib);
return true;
}
PluginIter CPluginManager::_begin()
{
return m_Plugins.begin();
}
PluginIter CPluginManager::_end()
{
return m_Plugins.end();
}
void CPluginManager::AddPluginCvar(ISmmPlugin *api, ConCommandBase *pCvar)
{
CPlugin *pl = FindByAPI(api);
if (!pl)
return;
pl->m_Cvars.push_back(pCvar);
}
void CPluginManager::AddPluginCmd(ISmmPlugin *api, ConCommandBase *pCmd)
{
CPlugin *pl = FindByAPI(api);
if (!pl)
return;
pl->m_Cmds.push_back(pCmd);
}
void CPluginManager::RemovePluginCvar(ISmmPlugin *api, ConCommandBase *pCvar)
{
CPlugin *pl = FindByAPI(api);
if (!pl)
return;
pl->m_Cvars.remove(pCvar);
}
void CPluginManager::RemovePluginCmd(ISmmPlugin *api, ConCommandBase *pCmd)
{
CPlugin *pl = FindByAPI(api);
if (!pl)
return;
pl->m_Cmds.remove(pCmd);
}
void CPluginManager::UnregAllConCmds(CPlugin *pl)
{
SourceHook::List<ConCommandBase *>::iterator i;
for (i=pl->m_Cvars.begin(); i!=pl->m_Cvars.end(); i++)
g_SMConVarAccessor.Unregister(pl->m_Id, (*i) );
pl->m_Cvars.clear();
for (i=pl->m_Cmds.begin(); i!=pl->m_Cmds.end(); i++)
g_SMConVarAccessor.Unregister(pl->m_Id, (*i) );
pl->m_Cmds.clear();
}
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#if defined _DEBUG
#define DEBUG2
#undef _DEBUG
#endif
#include "metamod.h"
#include "metamod_plugins.h"
#include "metamod_util.h"
#if defined DEBUG2
#undef DEBUG2
#define _DEBUG
#endif
/**
* @brief Implements functions from CPlugin.h
* @file CPlugin.cpp
*/
using namespace SourceMM;
#define ITER_PLEVENT(evn, plid) \
CPluginManager::CPlugin *_Xpl; \
SourceHook::List<IMetamodListener *>::iterator event; \
IMetamodListener *api; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
_Xpl = (*iter); \
if (_Xpl->m_Id == plid) \
continue; \
for (event=_Xpl->m_Events.begin(); event!=_Xpl->m_Events.end(); event++) { \
api = (*event); \
api->evn(plid); \
} \
}
CPluginManager g_PluginMngr;
CPluginManager::CPluginManager()
{
m_LastId = Pl_MinId;
m_AllLoaded = false;
}
CPluginManager::~CPluginManager()
{
SourceHook::List<CNameAlias *>::iterator iter;
for (iter = m_Aliases.begin(); iter != m_Aliases.end(); iter++)
{
delete (*iter);
}
m_Aliases.clear();
}
const char *CPluginManager::LookupAlias(const char *alias)
{
SourceHook::List<CNameAlias *>::iterator iter;
CNameAlias *p;
for (iter = m_Aliases.begin(); iter != m_Aliases.end(); iter++)
{
p = (*iter);
if (p->alias.compare(alias) == 0)
{
return p->value.c_str();
}
}
return NULL;
}
SourceHook::List<SourceMM::CNameAlias *>::iterator CPluginManager::_alias_begin()
{
return m_Aliases.begin();
}
SourceHook::List<SourceMM::CNameAlias *>::iterator CPluginManager::_alias_end()
{
return m_Aliases.end();
}
void CPluginManager::SetAlias(const char *alias, const char *value)
{
SourceHook::List<CNameAlias *>::iterator iter;
CNameAlias *p;
for (iter = m_Aliases.begin(); iter != m_Aliases.end(); iter++)
{
p = (*iter);
if (p->alias.compare(alias) == 0)
{
if (value[0] == '\0')
{
iter = m_Aliases.erase(iter);
return;
}
else
{
p->value.assign(value);
return;
}
}
}
if (value[0] != '\0')
{
p = new CNameAlias;
p->alias.assign(alias);
p->value.assign(value);
m_Aliases.push_back(p);
}
}
CPluginManager::CPlugin::CPlugin() : m_Id(0), m_Source(0), m_API(NULL), m_Lib(NULL)
{
}
PluginId CPluginManager::Load(const char *file, PluginId source, bool &already, char *error, size_t maxlen)
{
already = false;
//Check if we're about to reload an old plugin
PluginIter i = m_Plugins.begin();
while (i != m_Plugins.end())
{
if ((*i) && UTIL_PathCmp(file, (*i)->m_File.c_str()))
{
if ((*i)->m_Status < Pl_Paused)
{
//Attempt to load the plugin again
already = true;
i = m_Plugins.erase(i);
continue;
}
else
{
//No need to load it
already = true;
return (*i)->m_Id;
}
}
i++;
}
CPlugin *pl = _Load(file, source, error, maxlen);
if (!pl)
{
return Pl_BadLoad;
}
ITER_PLEVENT(OnPluginLoad, pl->m_Id);
return pl->m_Id;
}
CPluginManager::CPlugin *CPluginManager::FindById(PluginId id)
{
PluginIter i;
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i)->m_Id == id )\
{
return (*i);
}
}
return NULL;
}
void CPluginManager::SetAllLoaded()
{
m_AllLoaded = true;
PluginIter i;
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i) && (*i)->m_Status == Pl_Running && (*i)->m_API )
{
//API 4 is when we added this callback
//Min version is now 5, so we ignore this check
//if ( (*i)->m_API->GetApiVersion() >= 004 )
(*i)->m_API->AllPluginsLoaded();
}
}
}
bool CPluginManager::Pause(PluginId id, char *error, size_t maxlen)
{
CPlugin *pl = FindById(id);
if (!pl)
{
UTIL_Format(error, maxlen, "Plugin id not found");
return false;
}
bool ret;
if ((ret=_Pause(pl, error, maxlen)) == true)
{
ITER_PLEVENT(OnPluginPause, pl->m_Id);
}
return ret;
}
bool CPluginManager::Unpause(PluginId id, char *error, size_t maxlen)
{
CPlugin *pl = FindById(id);
if (!pl)
{
UTIL_Format(error, maxlen, "Plugin id not found");
return false;
}
bool ret;
if ( (ret=_Unpause(pl, error, maxlen)) == true )
{
ITER_PLEVENT(OnPluginUnpause, pl->m_Id);
}
return ret;
}
bool CPluginManager::Unload(PluginId id, bool force, char *error, size_t maxlen)
{
CPlugin *pl = FindById(id);
if (!pl)
{
UTIL_Format(error, maxlen, "Plugin %d not found", id);
return false;
}
bool ret;
PluginId old_id = pl->m_Id;
if ( (ret=_Unload(pl, force, error, maxlen)) == true )
{
ITER_PLEVENT(OnPluginUnload, old_id);
}
return ret;
}
bool CPluginManager::Retry(PluginId id, char *error, size_t len)
{
PluginIter i;
char buffer[64];
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i) && (*i)->m_Id == id )
{
if ( (*i)->m_Status >= Pl_Paused)
{
UTIL_Format(error, len, "Plugin %d is already running.", id);
return false;
}
CPlugin *pl = _Load((*i)->m_File.c_str(), Pl_Console, error, len);
if (!pl)
{
return false;
}
if (pl->m_Status >= Pl_Paused)
{
//Now it gets crazy... unload the original copy.
_Unload( (*i), true, buffer, sizeof(buffer)-1 );
//Set the new copy's id
pl->m_Id = id;
//We just wasted an id... reclaim it
m_LastId--;
return true;
}
else
{
//don't really care about the buffer here
_Unload(pl, true, buffer, sizeof(buffer)-1);
//We just wasted an id... reclaim it
m_LastId--;
return false;
}
}
}
UTIL_Format(error, len, "Plugin %d not found,", id);
return false;
}
CPluginManager::CPlugin *CPluginManager::FindByAPI(ISmmPlugin *api)
{
PluginIter i;
//don't find bad plugins!
if (!api)
{
return NULL;
}
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ((*i)->m_API == api)
{
return (*i);
}
}
return NULL;
}
int CPluginManager::GetPluginCount()
{
return (int)m_Plugins.size();
}
const char *CPluginManager::GetStatusText(CPlugin *pl)
{
switch (pl->m_Status)
{
case Pl_NotFound:
return "NOFILE";
case Pl_Error:
return "ERROR";
case Pl_Refused:
return "FAILED";
case Pl_Paused:
return "PAUSED";
case Pl_Running:
{
if (pl->m_API && pl->m_API->QueryRunning(NULL, 0))
{
return "STOPPED";
} else {
return "RUNNING";
}
}
default:
return "-";
}
}
CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source, char *error, size_t maxlen)
{
FILE *fp;
CPlugin *pl;
pl = new CPlugin();
*error = '\0';
//Add plugin to list
pl->m_Id = m_LastId;
pl->m_File.assign(file);
m_Plugins.push_back(pl);
m_LastId++;
//Check if the file even exists
fp = fopen(file, "r");
if (!fp)
{
if (error)
{
UTIL_Format(error, maxlen, "File not found: %s", file);
}
pl->m_Status = Pl_NotFound;
}
if (fp)
{
fclose(fp);
fp = NULL;
//Load the file
pl->m_Lib = dlmount(file);
if (!pl->m_Lib)
{
if (error)
{
UTIL_Format(error, maxlen, "%s", dlerror());
}
pl->m_Status = Pl_Error;
}
else
{
CreateInterfaceFn pfn = (CreateInterfaceFn)(dlsym(pl->m_Lib, PL_EXPOSURE_C));
if (!pfn)
{
if (error)
{
UTIL_Format(error, maxlen, "Function %s not found", PL_EXPOSURE_C);
}
pl->m_Status = Pl_Error;
}
else
{
pl->m_API = static_cast<ISmmPlugin *>((pfn)(PLAPI_NAME, NULL));
if (!pl->m_API)
{
if (error)
{
UTIL_Format(error, maxlen, "Failed to get API");
}
pl->m_Status = Pl_Error;
}
else
{
int api = pl->m_API->GetApiVersion();
if (api < PLAPI_MIN_VERSION)
{
if (error)
{
UTIL_Format(error, maxlen, "Plugin API %d is out of date with required minimum (%d)", api, PLAPI_MIN_VERSION);
}
pl->m_Status = Pl_Error;
}
else if (api > PLAPI_VERSION)
{
if (error)
{
UTIL_Format(error, maxlen, "Plugin API %d is newer than internal version (%d)", api, PLAPI_VERSION);
}
pl->m_Status = Pl_Error;
}
else
{
if (pl->m_API->Load(pl->m_Id, &g_Metamod, error, maxlen, m_AllLoaded))
{
pl->m_Status = Pl_Running;
if (m_AllLoaded)
{
//API 4 is when we added this callback
//Removing this code as the min version is now 5
//if (pl->m_API->GetApiVersion() >= 4)
pl->m_API->AllPluginsLoaded();
}
}
else
{
pl->m_Status = Pl_Refused;
}
}
}
}
}
}
if (pl->m_Lib && (pl->m_Status < Pl_Paused))
{
pl->m_Events.clear();
g_SourceHook.UnloadPlugin(pl->m_Id);
UnregAllConCmds(pl);
dlclose(pl->m_Lib);
pl->m_Lib = NULL;
pl->m_API = NULL;
}
return pl;
}
bool CPluginManager::_Unload(CPluginManager::CPlugin *pl, bool force, char *error, size_t maxlen)
{
if (error)
{
*error = '\0';
}
if (pl->m_API && pl->m_Lib)
{
//Note, we'll always tell the plugin it will be unloading...
if (pl->m_API->Unload(error, maxlen) || force)
{
//Make sure to detach it from sourcehook!
g_SourceHook.UnloadPlugin(pl->m_Id);
pl->m_Events.clear();
UnregAllConCmds(pl);
//Clean up the DLL
dlclose(pl->m_Lib);
pl->m_Lib = NULL;
pl->m_API = NULL;
//Remove the plugin from the list
PluginIter i;
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i)->m_Id == pl->m_Id )
{
i = m_Plugins.erase(i);
break;
}
}
//Free its memory
delete pl;
return true;
}
} else {
//The plugin is not valid, and let's just remove it from the list anyway
PluginIter i;
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
{
if ( (*i)->m_Id == pl->m_Id )
{
i = m_Plugins.erase(i);
break;
}
}
delete pl;
return true;
}
return false;
}
bool CPluginManager::_Pause(CPluginManager::CPlugin *pl, char *error, size_t maxlen)
{
if (error)
{
*error = '\0';
}
if (pl->m_Status != Pl_Running || !pl->m_API)
{
if (error)
{
UTIL_Format(error, maxlen, "Plugin cannot be paused");
}
}
else
{
if (pl->m_API->Pause(error, maxlen))
{
g_SourceHook.PausePlugin(pl->m_Id);
pl->m_Status = Pl_Paused;
return true;
}
}
return false;
}
bool CPluginManager::_Unpause(CPluginManager::CPlugin *pl, char *error, size_t maxlen)
{
if (error)
{
*error = '\0';
}
if (pl->m_Status != Pl_Paused || !pl->m_API)
{
if (error)
{
UTIL_Format(error, maxlen, "Plugin cannot be unpaused");
}
}
else
{
if (pl->m_API->Unpause(error, maxlen))
{
g_SourceHook.UnpausePlugin(pl->m_Id);
pl->m_Status = Pl_Running;
return true;
}
}
return false;
}
bool CPluginManager::UnloadAll()
{
PluginIter i;
char error[128];
bool status = true;
while ((i = m_Plugins.begin()) != m_Plugins.end())
{
if ( !_Unload( (*i), true, error, sizeof(error)) )
{
status = false;
}
}
return status;
}
bool CPluginManager::Query(PluginId id, const char *&file, Pl_Status &status, PluginId &source)
{
CPlugin *pl = FindById(id);
if (!pl)
{
return false;
}
file = pl->m_File.c_str();
status = pl->m_Status;
source = pl->m_Source;
return true;
}
bool CPluginManager::QueryRunning(PluginId id, char *error, size_t maxlength)
{
CPlugin *pl = FindById(id);
if (!pl || !pl->m_API)
{
if (error)
{
UTIL_Format(error, maxlength, "Plugin not valid");
}
return false;
}
return pl->m_API->QueryRunning(error, maxlength);
}
bool CPluginManager::QueryHandle(PluginId id, void *&handle)
{
CPlugin *pl = FindById(id);
if (!pl)
{
return false;
}
handle = static_cast<void *>(pl->m_Lib);
return true;
}
PluginIter CPluginManager::_begin()
{
return m_Plugins.begin();
}
PluginIter CPluginManager::_end()
{
return m_Plugins.end();
}
void CPluginManager::AddPluginCvar(ISmmPlugin *api, ConCommandBase *pCvar)
{
CPlugin *pl = FindByAPI(api);
if (!pl)
{
return;
}
pl->m_Cvars.push_back(pCvar);
}
void CPluginManager::AddPluginCmd(ISmmPlugin *api, ConCommandBase *pCmd)
{
CPlugin *pl = FindByAPI(api);
if (!pl)
{
return;
}
pl->m_Cmds.push_back(pCmd);
}
void CPluginManager::RemovePluginCvar(ISmmPlugin *api, ConCommandBase *pCvar)
{
CPlugin *pl = FindByAPI(api);
if (!pl)
{
return;
}
pl->m_Cvars.remove(pCvar);
}
void CPluginManager::RemovePluginCmd(ISmmPlugin *api, ConCommandBase *pCmd)
{
CPlugin *pl = FindByAPI(api);
if (!pl)
{
return;
}
pl->m_Cmds.remove(pCmd);
}
void CPluginManager::UnregAllConCmds(CPlugin *pl)
{
SourceHook::List<ConCommandBase *>::iterator i;
/* :TODO: */
for (i=pl->m_Cvars.begin(); i!=pl->m_Cvars.end(); i++)
{
g_Metamod.UnregisterConCommandBase(pl->m_Id, (*i) );
}
pl->m_Cvars.clear();
for (i=pl->m_Cmds.begin(); i!=pl->m_Cmds.end(); i++)
{
g_Metamod.UnregisterConCommandBase(pl->m_Id, (*i) );
}
pl->m_Cmds.clear();
}

View File

@ -1,12 +1,29 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_CPLUGIN_H
#define _INCLUDE_CPLUGIN_H
@ -18,11 +35,10 @@
#include <interface.h>
#include <eiface.h>
#include "convar_smm.h"
#include <sh_list.h>
#include <sh_string.h>
#include "IPluginManager.h"
#include "oslink.h"
#include "sh_list.h"
#include "sh_string.h"
#include "metamod_oslink.h"
/**
* History of plugin versions: (M=min, C=current)
@ -38,7 +54,7 @@
* 8: New SourceHook version (2005-12-23)
* New ISmmAPI additions
* 9: New ISmmPluginManager additions
* 10: Added VSP listen functions to ISmmAPI and IMetamodListener (2007-02-09)
* C 10: Added VSP listen functions to ISmmAPI and IMetamodListener (2007-02-09)
* C 11: New SourceHook version V5 (May, 2007)
*/
@ -148,3 +164,4 @@ typedef SourceHook::List<SourceMM::CPluginManager::CPlugin *>::iterator PluginIt
extern SourceMM::CPluginManager g_PluginMngr;
#endif //_INCLUDE_CPLUGIN_H

294
sourcemm/metamod_provider.h Normal file
View File

@ -0,0 +1,294 @@
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_METAMOD_SOURCE_SUPPORT_H_
#define _INCLUDE_METAMOD_SOURCE_SUPPORT_H_
namespace SourceMM
{
enum
{
ConVarFlag_None,
ConVarFlag_Notify,
ConVarFlag_Replicated,
ConVarFlag_SpOnly
};
enum ProvidedHooks
{
ProvidedHook_LevelInit = 0, /**< IServerGameDLL::LevelInit */
ProvidedHook_LevelShutdown = 1, /**< IServerGameDLL::LevelShutdown */
ProvidedHook_DLLInit = 2, /**< IServerGameDLL::DLLInit */
ProvidedHook_DLLShutdown = 3, /**< IServerGameDLL::DLLShutdown */
ProvidedHook_GameInit = 4, /**< IServerGameDLL::GameInit */
};
/**
* @brief Abstracts command information, since the new engine fixes the
* re-entrancy problems in the tokenization system.
*/
class IMetamodSourceCommandInfo
{
public:
/**
* @brief Returns the argument count such that arguments
* 1 to N are valid arguments, and 0 is the command name.
*
* @return Argument count.
*/
virtual unsigned int GetArgCount() =0;
/**
* @brief Returns the string of an argument number.
*
* @param num Argument number.
* @return Argument text.
*/
virtual const char *GetArg(unsigned int num) =0;
/**
* @brief Returns the entire command argument string.
*
* @return Argument string.
*/
virtual const char *GetArgString() =0;
};
class IMetamodSourceProvider
{
public:
/**
* @brief Returns whether source engine build is compatible.
*
* @param build Source engine build.
* @return True if compatible, false otherwise.
*/
virtual bool IsSourceEngineBuildCompatible(int build) =0;
/**
* @brief Retrieves hook information for each callback. Each hook
* must be implemented.
*
* @param hook Hook information to provide.
* @param pInfo Non-NULL pointer to fill with information
* about the hook's virtual location.
* @return True if supported, false to fail, which
* will cause Metamod:Source to fail.
*/
virtual bool GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo) =0;
/**
* @brief Logs a message via IVEngineServer::LogPrint.
*
* @param buffer Buffer to print.
* @return True on success, false if not supported,
* or IVEngineServer is not yet known.
*/
virtual bool LogMessage(const char *buffer) =0;
/**
* @brief Returns the command line value of a parameter. If ICvar
* is not yet loaded, this uses an equivalent function.
*
* @param key Parameter to look up.
* @param val Default string to return if none found.
* @return Parameter value.
*/
virtual const char *GetCommandLineValue(const char *key, const char *defval) =0;
/**
* @brief Prints a string to the remote server console.
*
* Note: new lines are not appended.
*
* @param msg Message string.
*/
virtual void ConsolePrint(const char *msg) =0;
/**
* @brief Returns whether remote printing is available.
*
* @return True if remote printing is available,
* otherwise returns false.
*/
virtual bool IsRemotePrintingAvailable() =0;
/**
* @brief Prints text in the specified client's console.
*
* @param client Client edict pointer.
* @param msg Message string.
*/
virtual void ClientConsolePrint(edict_t *client, const char *msg) =0;
/**
* @brief Returns a server plugin helper for the given interface
* string.
*
* @param iface Interface version
* @return IServerPluginCallbacks pointer.
*/
virtual IServerPluginCallbacks *GetVSPCallbacks(const char *iface) =0;
/**
* @brief Halts the server with a fatal error message.
*
* No newline is appended.
*
* @param fmt Formatted message string.
* @param ... Format parameters.
*/
virtual void DisplayError(const char *fmt, ...) =0;
/**
* @brief Sends the server a warning message.
*
* No newline is appended.
*
* @param fmt Formatted message string.
* @param ... Format parameters.
*/
virtual void DisplayWarning(const char *fmt, ...) =0;
/**
* @brief Attempts to notify the provider of the gamedll version being
* used.
*
* @param iface Interface string.
* @return Version number on success, 0 otherwise.
*/
virtual int TryServerGameDLL(const char *iface) =0;
/**
* @brief Notifies the provider that the DLLInit pre-hook is almost done.
*/
virtual void Notify_DLLInit_Pre(void *gamedll,
CreateInterfaceFn engineFactory,
CreateInterfaceFn serverFactory) =0;
virtual void Notify_DLLShutdown_Pre() =0;
/**
* @brief Wrapper around IVEngineServer::ServerCommand()
*
* @param cmd Command string.
*/
virtual void ServerCommand(const char *cmd) =0;
/**
* @brief Creates a ConVar pointer.
*
* @param name ConVar name.
* @param defval Default value string.
* @param flags ConVar flags.
* @param help Help text.
* @return ConVar pointer.
*/
virtual ConVar *CreateConVar(const char *name,
const char *defval,
const char *help,
int flags) =0;
/**
* @brief Returns the string value of a ConVar.
*
* @param convar ConVar pointer.
* @return String value.
*/
virtual const char *GetConVarString(ConVar *convar) =0;
/**
* @brief Retrieves the game description.
*
* @return Game description.
*/
virtual const char *GetGameDescription() =0;
/**
* @brief Returns the ConCommandBase accessor.
*
* @return An IConCommandBaseAccessor pointer.
*/
virtual IConCommandBaseAccessor *GetConCommandBaseAccessor() =0;
/**
* @brief Registers a ConCommandBase.
*
* @param pCommand ConCommandBase to register.
* @return True if successful, false otherwise.
*/
virtual bool RegisterConCommandBase(ConCommandBase *pCommand) =0;
/**
* @brief Unregisters a ConCommandBase.
*
* @param pCommand ConCommandBase to unlink.
*/
virtual void UnregisterConCommandBase(ConCommandBase *pCommand) =0;
/**
* @brief Returns whether a ConCommandBase is a command or not.
*
* @param pCommand ConCommandBase pointer.
* @return True if a command, false otherwise.
*/
virtual bool IsConCommandBaseACommand(ConCommandBase *pCommand) =0;
/**
* @brief Returns the number of user messages in the GameDLL.
*
* @return Number of user messages, or -1 if SourceMM has
* failed to get user message list.
*/
virtual int GetUserMessageCount() =0;
/**
* @brief Returns the index of the specified user message.
*
* @param name User message name.
* @param size Optional pointer to store size of user message.
* @return Message index, or -1 on failure.
*/
virtual int FindUserMessage(const char *name, int *size=NULL) =0;
/**
* @brief Returns the name of the specified user message.
*
* @param index User message index.
* @param size Optional pointer to store size of user message.
* @return Message name, or NULL on failure.
*/
virtual const char *GetUserMessage(int index, int *size=NULL) =0;
};
};
extern PluginId g_PLID;
extern SourceHook::ISourceHook *g_SHPtr;
extern SourceMM::IMetamodSourceProvider *provider;
#endif //_INCLUDE_METAMOD_SOURCE_SUPPORT_H_

View File

@ -1,18 +1,35 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* License: zlib/libpng
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Author(s): David "BAILOPAN" Anderson
* ============================
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include "util.h"
#include "oslink.h"
#include "metamod_util.h"
#include "metamod_oslink.h"
/**
* @brief Utility functions

View File

@ -1,11 +1,28 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
/**
* vim: set ts=4 :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2007 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* License: zlib/libpng
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Author(s): David "BAILOPAN" Anderson
* ============================
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef _INCLUDE_UTIL_H

View File

@ -1,21 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sourcemm", "sourcemm.vcproj", "{F7D47743-73B3-49B5-9D76-2333C5DFD565}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Debug.ActiveCfg = Debug|Win32
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Debug.Build.0 = Debug|Win32
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Release.ActiveCfg = Release|Win32
{F7D47743-73B3-49B5-9D76-2333C5DFD565}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

View File

@ -1,256 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="sourcemm"
ProjectGUID="{F7D47743-73B3-49B5-9D76-2333C5DFD565}"
RootNamespace="sourcemm"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier1.lib vstdlib.lib tier0.lib"
OutputFile="$(OutDir)/server.dll"
LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcmt.lib;libcmtd.lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/sourcemm.pdb"
SubSystem="2"
EnableCOMDATFolding="1"
ImportLibrary="$(OutDir)/sourcemm.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS"
StringPooling="TRUE"
BufferSecurityCheck="FALSE"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
OutputFile="$(OutDir)/server.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="libcd.lib;libcmt.lib;libcmtd.lib"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/sourcemm.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath="..\concommands.cpp">
</File>
<File
RelativePath="..\CPlugin.cpp">
</File>
<File
RelativePath="..\CSmmAPI.cpp">
</File>
<File
RelativePath="..\oslink.cpp">
</File>
<File
RelativePath="..\sourcemm.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Detect64BitPortabilityProblems="FALSE"/>
</FileConfiguration>
</File>
<File
RelativePath="..\util.cpp">
</File>
<File
RelativePath="..\vsp_listener.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath="..\concommands.h">
</File>
<File
RelativePath="..\CPlugin.h">
</File>
<File
RelativePath="..\CSmmAPI.h">
</File>
<File
RelativePath="..\oslink.h">
</File>
<File
RelativePath="..\resource.h">
</File>
<File
RelativePath="..\sourcemm.h">
</File>
<File
RelativePath="..\util.h">
</File>
<File
RelativePath="..\vsp_listener.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
<File
RelativePath="..\version.rc">
</File>
</Filter>
<Filter
Name="Interfaces"
Filter="">
<File
RelativePath="..\IPluginManager.h">
</File>
<File
RelativePath="..\ISmmAPI.h">
</File>
<File
RelativePath="..\ISmmPlugin.h">
</File>
</Filter>
<Filter
Name="SourceHook"
Filter="">
<File
RelativePath="..\..\sourcehook\sh_list.h">
</File>
<File
RelativePath="..\..\sourcehook\sh_stack.h">
</File>
<File
RelativePath="..\..\sourcehook\sh_string.h">
</File>
<File
RelativePath="..\..\sourcehook\sh_tinyhash.h">
</File>
<File
RelativePath="..\..\sourcehook\sh_vector.h">
</File>
<Filter
Name="Headers"
Filter="">
<File
RelativePath="..\..\sourcehook\FastDelegate.h">
</File>
<File
RelativePath="..\..\sourcehook\sh_memfuncinfo.h">
</File>
<File
RelativePath="..\..\sourcehook\sh_memory.h">
</File>
<File
RelativePath="..\..\sourcehook\sourcehook.cpp">
</File>
<File
RelativePath="..\..\sourcehook\sourcehook.h">
</File>
<File
RelativePath="..\..\sourcehook\sourcehook_impl.h">
</File>
</Filter>
</Filter>
<Filter
Name="HL2SDK"
Filter="">
<File
RelativePath="..\convar_smm.h">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -1,69 +0,0 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
/**
* @brief Implements OS-dependant functions from oslink.h
* @file oslink.cpp
*/
#include "oslink.h"
#ifdef __linux
#include <errno.h>
#include <stdio.h>
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32
const char *dlerror()
{
static char buf[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &buf, 0, NULL);
return buf;
}
#endif
#if defined __linux__
int GetLastError()
{
return errno;
}
extern "C" void __cxa_guard_acquire(void)
{
}
extern "C" void __cxa_guard_release(void)
{
}
#endif
bool GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
{
#if defined WIN32 || defined _WIN32
MEMORY_BASIC_INFORMATION mem;
if (!VirtualQuery(pAddr, &mem, sizeof(mem)))
return false;
if (mem.AllocationBase == NULL)
return false;
HMODULE dll = (HMODULE)mem.AllocationBase;
GetModuleFileName(dll, (LPTSTR)buffer, maxlength);
#elif defined __linux__
Dl_info info;
if (!dladdr(pAddr, &info))
return false;
if (!info.dli_fbase || !info.dli_fname)
return false;
const char *dllpath = info.dli_fname;
snprintf(buffer, maxlength, "%s", dllpath);
#endif
return true;
}

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,21 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_mm", "sample_mm.vcproj", "{FAFF34FB-FE14-47B5-81BD-70D237392FB2}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Debug.ActiveCfg = Debug|Win32
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Debug.Build.0 = Debug|Win32
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Release.ActiveCfg = Release|Win32
{FAFF34FB-FE14-47B5-81BD-70D237392FB2}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

View File

@ -1,149 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="sample_mm"
ProjectGUID="{FAFF34FB-FE14-47B5-81BD-70D237392FB2}"
RootNamespace="sample_mm"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
OutputFile="$(OutDir)/sample_mm.dll"
LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcmt.lib;libcmtd.lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/sample_mm.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/sample_mm.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
RuntimeLibrary="4"
UsePrecompiledHeader="0"
ExpandAttributedSource="TRUE"
WarningLevel="3"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
OutputFile="$(OutDir)/sample_mm.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="libcd.lib;libcmt.lib;libcmtd.lib"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="1"
ImportLibrary="$(OutDir)/sample_mm.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath="..\cvars.cpp">
</File>
<File
RelativePath="..\SamplePlugin.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath="..\cvars.h">
</File>
<File
RelativePath="..\SamplePlugin.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

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,710 +0,0 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* Contributor(s): Scott "Damaged Soul" Ehlert
* : Pavol "PM OnoTo" Marko
* ============================
*/
#include <interface.h>
#include <eiface.h>
#include <tier0/icommandline.h>
#include "sourcemm.h"
#include "concommands.h"
#include "CSmmAPI.h"
#include "CPlugin.h"
#include "util.h"
#include "vsp_listener.h"
using namespace SourceMM;
/**
* @brief Implementation of main SourceMM GameDLL functionality
* @file sourcemm.cpp
*/
#undef CommandLine
DLL_IMPORT ICommandLine *CommandLine();
SH_DECL_HOOK4(IServerGameDLL, DLLInit, SH_NOATTRIB, false, bool, CreateInterfaceFn, CreateInterfaceFn, CreateInterfaceFn, CGlobalVars *);
SH_DECL_HOOK0_void(IServerGameDLL, DLLShutdown, SH_NOATTRIB, false);
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
SH_DECL_HOOK0(IServerGameDLL, GameInit, SH_NOATTRIB, false, bool);
bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals);
bool DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals);
void DLLShutdown_handler();
void LevelShutdown_handler();
bool LevelInit_handler(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
bool GameInit_handler();
GameDllInfo g_GameDll = {false, NULL, NULL, NULL, NULL};
EngineInfo g_Engine;
SourceHook::CSourceHookImpl g_SourceHook;
SourceHook::ISourceHook *g_SHPtr = &g_SourceHook;
SourceHook::String g_ModPath;
SourceHook::String g_BinPath;
SourceHook::String g_SmmPath;
PluginId g_PLID = Pl_Console; /* Technically, SourceMM is the "Console" plugin... :p */
bool bInFirstLevel = true;
bool gParsedGameInfo = false;
bool bGameInit = false;
SourceHook::List<GameDllInfo *> gamedll_list;
int g_GameDllVersion = 0;
int g_GameClientsVersion = 0;
int g_VspVersion = 0;
const char VSPIFACE[] = "ISERVERPLUGINCALLBACKS";
const char GAMEINFO_PATH[] = "|gameinfo_path|";
void ClearGamedllList();
/* Helper Macro */
#define IFACE_MACRO(orig,nam) \
CPluginManager::CPlugin *pl; \
SourceHook::List<IMetamodListener *>::iterator event; \
IMetamodListener *api; \
int mret = 0; \
void *val = NULL; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
pl = (*iter); \
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
api = (*event); \
mret = IFACE_FAILED; \
if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \
if (ret) *ret = mret; \
return val; \
} \
} \
} \
return (orig)(iface, ret);
#define ITER_EVENT(evn, args) \
CPluginManager::CPlugin *pl; \
SourceHook::List<IMetamodListener *>::iterator event; \
IMetamodListener *api; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
pl = (*iter); \
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
api = (*event); \
api->evn args; \
} \
}
///////////////////////////////////
// Main code for HL2 Interaction //
///////////////////////////////////
/* Initialize everything here */
void InitMainStates()
{
char full_path[PATH_SIZE] = {0};
GetFileOfAddress((void *)g_GameDll.factory, full_path, sizeof(full_path));
g_BinPath.assign(full_path);
/* Like Metamod, reload plugins at the end of the map.
* This is so plugins can hook everything on load, BUT, new plugins will be reloaded
* if the server is shut down (silly, but rare case).
*/
bInFirstLevel = true;
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLInit, g_GameDll.pGameDLL, DLLInit, false);
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLInit, g_GameDll.pGameDLL, DLLInit_Post, true);
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLShutdown, g_GameDll.pGameDLL, DLLShutdown_handler, false);
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelShutdown, g_GameDll.pGameDLL, LevelShutdown_handler, true);
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelInit, g_GameDll.pGameDLL, LevelInit_handler, true);
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, GameInit, g_GameDll.pGameDLL, GameInit_handler, false);
}
bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
{
g_Engine.engineFactory = engineFactory;
g_Engine.fileSystemFactory = filesystemFactory;
g_Engine.physicsFactory = physicsFactory;
g_Engine.pGlobals = pGlobals;
g_Engine.engine = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL));
if (!g_Engine.engine)
{
Error("Could not find IVEngineServer! Metamod cannot load.");
return false;
}
g_Engine.icvar = (ICvar *)((engineFactory)(VENGINE_CVAR_INTERFACE_VERSION , NULL));
if (!g_Engine.icvar)
{
Error("Could not find ICvar! Metamod cannot load.");
return false;
}
g_Engine.loaded = true;
/* Initialize our console hooks */
ConCommandBaseMgr::OneTimeInit(static_cast<IConCommandBaseAccessor *>(&g_SMConVarAccessor));
if (g_GameDll.pGameClients)
{
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, g_GameDll.pGameClients, ClientCommand_handler, false);
} else {
/* If IServerGameClients isn't found, this really isn't a fatal error so... */
LogMessage("[META] Warning: Could not find IServerGameClients!");
LogMessage("[META] Warning: The 'meta' command will not be available to clients.");
}
if (!g_SmmAPI.CacheCmds())
{
LogMessage("[META] Warning: Failed to initialize Con_Printf. Defaulting to Msg().");
LogMessage("[META] Warning: Console messages will not be redirected to rcon console.");
}
if (!g_SmmAPI.CacheUserMessages())
{
/* Don't know of a mod that has stripped out user messages completely,
* but perhaps should do something different here?
*/
LogMessage("[META] Warning: Failed to get list of user messages.");
LogMessage("[META] Warning: The 'meta game' command will not display user messages.");
}
const char *pluginFile = g_Engine.icvar->GetCommandLineValue("mm_pluginsfile");
if (!pluginFile)
{
pluginFile = GetPluginsFile();
}
char full_path[260];
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), pluginFile);
LoadPluginsFromFile(full_path);
bInFirstLevel = true;
RETURN_META_VALUE(MRES_IGNORED, true);
}
bool GameInit_handler()
{
if (bGameInit)
{
return true;
}
if (g_SmmAPI.VSPEnabled())
{
g_SmmAPI.LoadAsVSP();
}
bGameInit = true;
RETURN_META_VALUE(MRES_IGNORED, true);
}
bool DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
{
g_PluginMngr.SetAllLoaded();
RETURN_META_VALUE(MRES_IGNORED, true);
}
/* This is where the magic happens */
SMM_API void *CreateInterface(const char *iface, int *ret)
{
/* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */
if (strcmp(iface, PLAPI_NAME) == 0)
{
Warning("Do not try loading Metamod:Source as a SourceMM or Valve server plugin.\n");
if (ret)
{
*ret = IFACE_FAILED;
}
return NULL;
}
if (strncmp(iface, VSPIFACE, 22) == 0)
{
g_VspVersion = atoi(&(iface[22]));
if (g_VspVersion <= MAX_VSP_VERSION)
{
if (ret)
{
*ret = IFACE_OK;
}
return &g_VspListener;
}
}
if (!gParsedGameInfo)
{
gParsedGameInfo = true;
const char *gameDir = NULL;
char gamePath[PATH_SIZE];
char smmPath[PATH_SIZE];
/* Get path to SourceMM DLL */
if (!GetFileOfAddress((void *)CreateInterface, smmPath, sizeof(smmPath)))
{
Error("GetFileOfAddress() failed! Metamod cannot load.\n");
return NULL;
}
g_SmmPath.assign(smmPath);
/* Get value of -game from command line, defaulting to hl2 as engine seems to do */
gameDir = CommandLine()->ParmValue("-game", "hl2");
/* Get absolute path */
abspath(gamePath, gameDir);
g_ModPath.assign(gamePath);
char tempPath[PATH_SIZE];
/* Path to gameinfo.txt */
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s", g_ModPath.c_str(), "gameinfo.txt");
FILE *fp = fopen(tempPath, "rt");
if (!fp)
{
Error("Unable to open gameinfo.txt! Metamod cannot load.\n");
return NULL;
}
char buffer[255];
char key[128], val[128];
bool search = false;
bool gamebin = false;
char *ptr;
const char *lptr;
char curPath[PATH_SIZE];
getcwd(curPath, PATH_SIZE);
while (!feof(fp))
{
buffer[0] = '\0';
fgets(buffer, sizeof(buffer), fp);
UTIL_TrimComments(buffer);
UTIL_TrimLeft(buffer);
UTIL_TrimRight(buffer);
if (stricmp(buffer, "SearchPaths") == 0)
search = true;
if (!search)
continue;
UTIL_KeySplit(buffer, key, sizeof(key) - 1, val, sizeof(val) - 1);
if (stricmp(key, "Game") == 0 || stricmp(key, "GameBin") == 0)
{
if (stricmp(key, "Game") == 0)
gamebin = false;
else
gamebin = true;
if (strncmp(val, GAMEINFO_PATH, sizeof(GAMEINFO_PATH) - 1) == 0)
{
ptr = &(val[sizeof(GAMEINFO_PATH) - 1]);
if (ptr[0] == '.')
ptr++;
lptr = g_ModPath.c_str();
} else {
ptr = val;
lptr = curPath;
}
size_t ptr_len = strlen(ptr);
if (ptr[ptr_len] == '/' || ptr[ptr_len] == '\\')
ptr[--ptr_len] = '\0';
/* No need to append "bin" if key is GameBin */
if (gamebin)
{
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s", lptr, ptr, SERVER_DLL);
} else if (!ptr[0]) {
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s", lptr, "bin", SERVER_DLL);
} else {
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s/%s", lptr, ptr, "bin", SERVER_DLL);
}
/* If not path to SourceMM... */
if (!UTIL_PathCmp(smmPath, tempPath))
{
FILE *fp = fopen(tempPath, "rb");
if (!fp)
continue;
//:TODO: Optimize this a bit!
SourceHook::List<GameDllInfo *>::iterator iter;
GameDllInfo *pCheck;
bool found = false;
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
{
pCheck = (*iter);
if (GetFileOfAddress((void *)pCheck->factory, buffer, sizeof(buffer)))
{
if (UTIL_PathCmp(tempPath, buffer))
{
found = true;
break;
}
}
}
if (found)
continue;
fclose(fp);
HINSTANCE gamedll = dlmount(tempPath);
if (gamedll == NULL)
continue;
CreateInterfaceFn fn = (CreateInterfaceFn)dlsym(gamedll, "CreateInterface");
if (fn == NULL)
{
dlclose(gamedll);
continue;
}
GameDllInfo *pInfo = new GameDllInfo;
pInfo->factory = fn;
pInfo->lib = gamedll;
pInfo->loaded = true;
pInfo->pGameDLL = NULL;
gamedll_list.push_back(pInfo);
break;
}
}
}
fclose(fp);
}
if (!g_GameDll.loaded)
{
const char *str = "ServerGameDLL";
size_t len = strlen(str);
if (strncmp(iface, str, len) == 0)
{
/* This is the interface we want! Right now we support versions 3 through 8 */
g_GameDllVersion = atoi(&(iface[len]));
int sizeTooBig = 0; //rename this to sizeWrong in the future!
if (g_GameDllVersion < MIN_GAMEDLL_VERSION || g_GameDllVersion > MAX_GAMEDLL_VERSION)
{
/* Maybe this will get used in the future */
sizeTooBig = g_GameDllVersion;
if (ret)
{
*ret = IFACE_FAILED;
}
}
SourceHook::List<GameDllInfo *>::iterator iter;
GameDllInfo *pInfo = NULL;
void *ptr;
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
{
pInfo = (*iter);
ptr = (pInfo->factory)(iface, ret);
if (ptr)
{
/* This is our GameDLL. Unload the others. */
gamedll_list.erase(iter);
ClearGamedllList();
pInfo->pGameDLL = static_cast<IServerGameDLL *>(ptr);
g_GameDll = *pInfo;
delete pInfo;
break;
}
}
if (g_GameDll.loaded)
{
if (sizeTooBig)
{
Error("This mod version requires a SourceMM update (ServerGameDLL%03d)!\n", sizeTooBig);
if (ret)
{
*ret = IFACE_FAILED;
}
return NULL;
} else {
InitMainStates();
}
} else {
sizeTooBig = 0;
if (ret)
*ret = IFACE_FAILED;
return NULL;
}
} else {
/* wtf do we do... */
/* :TODO: .. something a bit more intelligent? */
Error("Engine requested unknown interface before GameDLL was known!\n");
return NULL;
}
}
/* We use this interface for responding to the meta client command */
if (strncmp(iface, "ServerGameClients", 17) == 0)
{
void *ptr = (g_GameDll.factory)(iface, ret);
g_GameDll.pGameClients = static_cast<IServerGameClients *>(ptr);
g_GameClientsVersion = atoi(&iface[17]);
return ptr;
}
/* If we got here, there's definitely a GameDLL */
IFACE_MACRO(g_GameDll.factory, GameDLL);
}
void ClearGamedllList()
{
SourceHook::List<GameDllInfo *>::iterator iter;
GameDllInfo *pInfo;
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
{
pInfo = (*iter);
dlclose(pInfo->lib);
delete pInfo;
}
gamedll_list.clear();
}
void DLLShutdown_handler()
{
/* Unload plugins */
g_PluginMngr.UnloadAll();
/* Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly */
g_SMConVarAccessor.MarkCommandsAsGameDLL();
g_SMConVarAccessor.UnregisterGameDLLCommands();
SH_CALL(g_GameDll.pGameDLL, &IServerGameDLL::DLLShutdown)();
g_SourceHook.CompleteShutdown();
if (g_GameDll.lib && g_GameDll.loaded)
dlclose(g_GameDll.lib);
memset(&g_GameDll, 0, sizeof(GameDllInfo));
RETURN_META(MRES_SUPERCEDE);
}
int LoadPluginsFromFile(const char *_file)
{
FILE *fp;
int total = 0, skipped=0;
PluginId id;
bool already;
fp = fopen(_file, "rt");
if (!fp)
{
LogMessage("[META] Could not open plugins file %s\n", _file);
return -1;
}
char buffer[255], error[255], full_path[255];
const char *ptr, *ext, *file;
size_t length;
while (!feof(fp))
{
buffer[0] = '\0';
fgets(buffer, sizeof(buffer), fp);
length = strlen(buffer);
if (!length)
continue;
if (buffer[length-1] == '\n')
buffer[--length] = '\0';
UTIL_TrimLeft(buffer);
UTIL_TrimRight(buffer);
if (buffer[0] == '\0' || buffer[0] == ';' || strncmp(buffer, "//", 2) == 0)
continue;
file = buffer;
if (buffer[0] == '"')
{
char *cptr = buffer;
file = ++cptr;
while (*cptr)
{
if (*cptr == '"')
{
*cptr = '\0';
break;
}
cptr++;
}
} else {
char *cptr = buffer;
while (*cptr)
{
if (isspace(*cptr))
{
char *optr = cptr;
while (*cptr && isspace(*cptr))
cptr++;
*optr = '\0';
UTIL_TrimRight(cptr);
if (*cptr && isalpha(*cptr))
{
g_PluginMngr.SetAlias(buffer, cptr);
file = cptr;
}
break;
}
cptr++;
}
}
if (!file[0])
{
continue;
}
/* First find if it's an absolute path or not... */
if (file[0] == '/' || strncmp(&(file[1]), ":\\", 2) == 0)
{
/* If we're in an absolute path, ignore our normal heuristics */
id = g_PluginMngr.Load(file, Pl_File, already, error, sizeof(error));
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
{
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
} else {
if (already)
skipped++;
else
total++;
}
} else {
/* Attempt to find a file extension */
ptr = UTIL_GetExtension(file);
/* Add an extension if there's none there */
if (!ptr)
{
#if defined WIN32 || defined _WIN32
ext = ".dll";
#else
ext = "_i486.so";
#endif
} else {
ext = "";
}
/* Format the new path */
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext);
id = g_PluginMngr.Load(full_path, Pl_File, already, error, sizeof(error));
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
{
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
} else {
if (already)
skipped++;
else
total++;
}
}
}
fclose(fp);
if (skipped)
{
LogMessage("[META] Loaded %d plugins from file (%d already loaded)", total, skipped);
} else {
LogMessage("[META] Loaded %d plugins from file.", total);
}
return total;
}
/* Wrapper function. This is called when the GameDLL thinks it's using
* the engine's real engineFactory.
*/
void *EngineFactory(const char *iface, int *ret)
{
IFACE_MACRO(g_Engine.engineFactory, Engine);
}
/* Wrapper function. This is called when the GameDLL thinks it's using
* the engine's real physicsFactory.
*/
void *PhysicsFactory(const char *iface, int *ret)
{
IFACE_MACRO(g_Engine.physicsFactory, Physics);
}
/* Wrapper function. This is called when the GameDLL thinks it's using
* the engine's real fileSystemFactory.
*/
void *FileSystemFactory(const char *iface, int *ret)
{
IFACE_MACRO(g_Engine.fileSystemFactory, FileSystem);
}
void LogMessage(const char *msg, ...)
{
va_list ap;
static char buffer[2048];
va_start(ap, msg);
size_t len = vsnprintf(buffer, sizeof(buffer) - 2, msg, ap);
va_end(ap);
buffer[len++] = '\n';
buffer[len] = '\0';
if (!g_Engine.engine)
{
fprintf(stdout, "%s", buffer);
} else {
g_Engine.engine->LogPrint(buffer);
}
}
void LevelShutdown_handler(void)
{
if (!bInFirstLevel)
{
char full_path[255];
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile());
LoadPluginsFromFile(full_path);
} else {
bInFirstLevel = false;
}
ITER_EVENT(OnLevelShutdown, ());
RETURN_META(MRES_IGNORED);
}
bool LevelInit_handler(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
{
if (!g_SmmAPI.CmdCacheSuccessful())
{
LogMessage("[META] Warning: Failed to initialize Con_Printf. Defaulting to Msg().");
LogMessage("[META] Warning: Console messages will not be redirected to rcon console.");
}
ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background));
RETURN_META_VALUE(MRES_IGNORED, false);
}
#if defined __GNUC__ && (__GNUC__ == 3 || __GNUC__ == 4)
void * operator new(size_t size) {
return(calloc(1, size));
}
void * operator new[](size_t size) {
return(calloc(1, size));
}
void operator delete(void * ptr) {
if(ptr)
free(ptr);
}
void operator delete[](void * ptr) {
if(ptr)
free(ptr);
}
#endif

View File

@ -1,128 +0,0 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
#ifndef _INCLUDE_SOURCEMM_H
#define _INCLUDE_SOURCEMM_H
/**
* @brief SourceMM main functionality for GameDLL interception
* @file sourcemm.h
*/
#include <string>
#include <interface.h>
#include <eiface.h>
#include <sourcehook/sourcehook_impl.h>
#include <sourcehook/sourcehook.h>
#include "ISmmAPI.h"
#include "CPlugin.h"
#include "oslink.h"
#include "util.h"
#include "svn_version.h"
/**
* Versioning
* increase api_major when API breaks
* increase api_minor when new functions are added (non-breaking)
*/
#define SOURCEMM_VERSION SVN_FILE_VERSION_STRING
#define SOURCEMM_DATE __DATE__
#define SM_VERS_API_MAJOR 1 //increase this on a breaking change
#define SM_VERS_API_MINOR 6 //increase this on a non-breaking API change
/* We need a good CServerGameDLL version to work properly. We support these inclusively. */
#define MIN_GAMEDLL_VERSION 3
#define MAX_GAMEDLL_VERSION 8
/* Maximum version of IServerPluginCallbacks that SourceMM supports */
#define MAX_VSP_VERSION 2
/**
* @brief Entry point for HL2 Engine
*/
SMM_API void *CreateInterface(const char *name, int *code);
/** @brief Wrapper to catch GameDLL calls */
void *EngineFactory(const char *name, int *code);
/** @brief Wrapper to catch GameDLL calls */
void *PhysicsFactory(const char *name, int *code);
/** @brief Wrapper to catch GameDLL calls */
void *FileSystemFactory(const char *name, int *code);
/** @brief Loads all plugins found in a file */
int LoadPluginsFromFile(const char *file);
/** @brief Logs a message to the standard log file */
void LogMessage(const char *msg, ...);
/** @brief Stores information about the GameDLL */
struct GameDllInfo
{
bool loaded;
HINSTANCE lib;
CreateInterfaceFn factory;
IServerGameDLL *pGameDLL;
IServerGameClients *pGameClients;
};
/** @brief Stores information about the HL2 Engine pointers */
struct EngineInfo
{
EngineInfo() : loaded(false),
engineFactory(NULL), physicsFactory(NULL), fileSystemFactory(NULL),
pGlobals(NULL), icvar(NULL), engine(NULL)
{ };
bool loaded;
CreateInterfaceFn engineFactory;
CreateInterfaceFn physicsFactory;
CreateInterfaceFn fileSystemFactory;
CGlobalVars *pGlobals;
ICvar *icvar;
IVEngineServer *engine;
};
/** @brief Global variable for GameDLL info */
extern GameDllInfo g_GameDll;
/** @brief Global variable for Engine info */
extern EngineInfo g_Engine;
/** @brief Global singleton for SourceHook */
extern SourceHook::CSourceHookImpl g_SourceHook;
/** @brief Mod path (important!)*/
extern SourceHook::String g_ModPath;
/** @brief Path to server binary */
extern SourceHook::String g_BinPath;
/** @brief Path to SourceMM binary */
extern SourceHook::String g_SmmPath;
/** @brief Global variable for SourceHook macros */
extern SourceHook::ISourceHook *g_SHPtr;
/** @brief We have our own internal plugin id... */
extern PluginId g_PLID;
/** @brief ServerGameDLL version that is currently loaded */
extern int g_GameDllVersion;
/** @brief Highest IServerPluginCallbacks version that is supported by engine */
extern int g_VspVersion;
/** @brief IServerGameClients version the mod uses */
extern int g_GameClientsVersion;
extern bool bGameInit;
#endif //_INCLUDE_SOURCEMM_H

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,21 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stub_mm", "stub_mm.vcproj", "{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Debug.ActiveCfg = Debug|Win32
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Debug.Build.0 = Debug|Win32
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Release.ActiveCfg = Release|Win32
{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

View File

@ -1,142 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="stub_mm"
ProjectGUID="{836E726E-AB80-43AB-9A8F-0E6EE680B0F6}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib"
ShowProgress="0"
OutputFile="$(OutDir)/stub_mm.dll"
LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcmt.lib;libcmtd.lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/stub_mm.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/stub_mm.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS"
RuntimeLibrary="4"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib"
OutputFile="$(OutDir)/stub_mm.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="libcd.lib;libcmt.lib;libcmtd.lib"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/stub_mm.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath="..\stub_mm.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath="..\stub_mm.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

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

@ -3,11 +3,11 @@
#ifndef _INCLUDE_SVN_VERSION_H_
#define _INCLUDE_SVN_VERSION_H_
#define SVN_PRODUCT_VERSION "1.4.0"
#define SVN_PRODUCT_VERSION "1.6.0"
#define SVN_REVISION 346
#define SVN_REVISION_STRING "346"
#define SVN_FILE_VERSION 1,4,0,346
#define SVN_FILE_VERSION_STRING "1.4.0.346"
#define SVN_REVISION 423
#define SVN_REVISION_STRING "423"
#define SVN_FILE_VERSION 1,6,0,423
#define SVN_FILE_VERSION_STRING "1.6.0.423"
#endif //_INCLUDE_SVN_VERSION_H_

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_