mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-12-07 10:28:30 +00:00
Bail will probably kill me for all this but...
1) Fixed amb93: Improved mod path detection. 2) Fixed various rare string inconsistencies. 3) Updated changelog 4) Other various internal things that don't matter much :o --HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40349
This commit is contained in:
parent
859506f742
commit
05226d7799
@ -188,7 +188,7 @@ bool CPluginManager::Pause(PluginId id, char *error, size_t maxlen)
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
snprintf(error, maxlen, "Plugin id not found");
|
||||
UTIL_Format(error, maxlen, "Plugin id not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -208,7 +208,7 @@ bool CPluginManager::Unpause(PluginId id, char *error, size_t maxlen)
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
snprintf(error, maxlen, "Plugin id not found");
|
||||
UTIL_Format(error, maxlen, "Plugin id not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -228,7 +228,7 @@ bool CPluginManager::Unload(PluginId id, bool force, char *error, size_t maxlen)
|
||||
|
||||
if (!pl)
|
||||
{
|
||||
snprintf(error, maxlen, "Plugin %d not found", id);
|
||||
UTIL_Format(error, maxlen, "Plugin %d not found", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -252,7 +252,7 @@ bool CPluginManager::Retry(PluginId id, char *error, size_t len)
|
||||
{
|
||||
if ( (*i)->m_Status >= Pl_Paused)
|
||||
{
|
||||
snprintf(error, len, "Plugin %d is already running.", id);
|
||||
UTIL_Format(error, len, "Plugin %d is already running.", id);
|
||||
return false;
|
||||
}
|
||||
CPlugin *pl = _Load((*i)->m_File.c_str(), Pl_Console, error, len);
|
||||
@ -281,7 +281,7 @@ bool CPluginManager::Retry(PluginId id, char *error, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(error, len, "Plugin %d not found,", id);
|
||||
UTIL_Format(error, len, "Plugin %d not found,", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -321,7 +321,7 @@ CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source
|
||||
if (!fp)
|
||||
{
|
||||
if (error)
|
||||
snprintf(error, maxlen, "File not found: %s", file);
|
||||
UTIL_Format(error, maxlen, "File not found: %s", file);
|
||||
pl->m_Status = Pl_NotFound;
|
||||
}
|
||||
|
||||
@ -335,32 +335,32 @@ CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source
|
||||
if (!pl->m_Lib)
|
||||
{
|
||||
if (error)
|
||||
snprintf(error, maxlen, "%s", dlerror());
|
||||
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)
|
||||
snprintf(error, maxlen, "Function %s not found", PL_EXPOSURE_C);
|
||||
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)
|
||||
snprintf(error, maxlen, "Failed to get API");
|
||||
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)
|
||||
snprintf(error, maxlen, "Plugin API %d is out of date with required minimum (%d)", api, PLAPI_MIN_VERSION);
|
||||
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)
|
||||
snprintf(error, maxlen, "Plugin API %d is newer than internal version (%d)", api, PLAPI_VERSION);
|
||||
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))
|
||||
@ -456,7 +456,7 @@ bool CPluginManager::_Pause(CPluginManager::CPlugin *pl, char *error, size_t max
|
||||
if (pl->m_Status != Pl_Running || !pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
snprintf(error, maxlen, "Plugin cannot be paused");
|
||||
UTIL_Format(error, maxlen, "Plugin cannot be paused");
|
||||
} else {
|
||||
if (pl->m_API->Pause(error, maxlen))
|
||||
{
|
||||
@ -478,7 +478,7 @@ bool CPluginManager::_Unpause(CPluginManager::CPlugin *pl, char *error, size_t m
|
||||
if (pl->m_Status != Pl_Paused || !pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
snprintf(error, maxlen, "Plugin cannot be unpaused");
|
||||
UTIL_Format(error, maxlen, "Plugin cannot be unpaused");
|
||||
} else {
|
||||
if (pl->m_API->Unpause(error, maxlen))
|
||||
{
|
||||
@ -506,7 +506,7 @@ bool CPluginManager::UnloadAll()
|
||||
|
||||
for (i=remqueue.begin(); i!=remqueue.end(); i++)
|
||||
{
|
||||
if ( !_Unload( (*i), true, error, sizeof(error)-1) )
|
||||
if ( !_Unload( (*i), true, error, sizeof(error)) )
|
||||
status = false;
|
||||
}
|
||||
|
||||
@ -537,7 +537,7 @@ bool CPluginManager::QueryRunning(PluginId id, char *error, size_t maxlength)
|
||||
if (!pl || !pl->m_API)
|
||||
{
|
||||
if (error)
|
||||
snprintf(error, maxlength, "Plugin not valid");
|
||||
UTIL_Format(error, maxlength, "Plugin not valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -42,10 +42,8 @@ void CSmmAPI::LogMsg(ISmmPlugin *pl, const char *msg, ...)
|
||||
va_list ap;
|
||||
static char buffer[2048];
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
va_start(ap, msg);
|
||||
vsnprintf(buffer, sizeof(buffer)-1, msg, ap);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
LogMessage("[%s] %s", pl->GetLogTag(), buffer);
|
||||
@ -131,11 +129,13 @@ void CSmmAPI::ConPrint(const char *fmt)
|
||||
void CSmmAPI::ConPrintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
static char buf[4096];
|
||||
static char buffer[4096];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf)-1, fmt, ap);
|
||||
ConPrint(buf);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
(m_ConPrintf)("%s", buffer);
|
||||
}
|
||||
|
||||
void CSmmAPI::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener)
|
||||
@ -275,7 +275,7 @@ bool CSmmAPI::CacheCmds()
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!offs || ptr[offs-1] != IA32_CALL)
|
||||
if (!offs || ptr[offs - 1] != IA32_CALL)
|
||||
{
|
||||
m_ConPrintf = (CONPRINTF_FUNC)Msg;
|
||||
return false;
|
||||
@ -322,11 +322,11 @@ int CSmmAPI::FormatIface(char iface[], unsigned int maxlength)
|
||||
int i;
|
||||
int num = 0;
|
||||
|
||||
for (i=length-1; i>=0; i--)
|
||||
for (i = length - 1; i >= 0; i--)
|
||||
{
|
||||
if (!isdigit(iface[i]))
|
||||
{
|
||||
if (i != length-1)
|
||||
if (i != length - 1)
|
||||
{
|
||||
num = 1;
|
||||
}
|
||||
@ -334,12 +334,12 @@ int CSmmAPI::FormatIface(char iface[], unsigned int maxlength)
|
||||
}
|
||||
}
|
||||
|
||||
if ( (num && ((int)maxlength <= length)) || (!num && ((int)maxlength <= length+3)) )
|
||||
if ( (num && ((int)maxlength <= length)) || (!num && ((int)maxlength <= length + 3)) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i != length-1)
|
||||
if (i != length - 1)
|
||||
num = atoi(&(iface[++i]));
|
||||
|
||||
num++;
|
||||
@ -384,10 +384,10 @@ void *CSmmAPI::InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max,
|
||||
void *CSmmAPI::VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min)
|
||||
{
|
||||
char buffer[256]; /* assume no interface will go beyond this */
|
||||
int len = static_cast<int>(strlen(iface));
|
||||
size_t len = strlen(iface);
|
||||
int ret; /* just in case something doesn't handle NULL properly */
|
||||
|
||||
if (len > static_cast<int>(sizeof(buffer) - 4))
|
||||
if (len > sizeof(buffer) - 4)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -396,7 +396,7 @@ void *CSmmAPI::VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min)
|
||||
|
||||
if (min != -1)
|
||||
{
|
||||
char *ptr = &buffer[len-1];
|
||||
char *ptr = &buffer[len - 1];
|
||||
int digits = 0;
|
||||
while (isdigit(*ptr) && digits <=3)
|
||||
{
|
||||
@ -427,30 +427,29 @@ const char *CSmmAPI::GetBaseDir()
|
||||
void CSmmAPI::PathFormat(char *buffer, size_t len, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap,fmt);
|
||||
size_t mylen = vsnprintf(buffer, len, fmt, ap);
|
||||
va_start(ap, fmt);
|
||||
size_t mylen = UTIL_FormatArgs(buffer, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (mylen == 0xFFFFFFFF || mylen >= len)
|
||||
{
|
||||
mylen = len - 1;
|
||||
}
|
||||
|
||||
for (size_t i=0; i<mylen; i++)
|
||||
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 buf[4096];
|
||||
static char buffer[4096];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
|
||||
g_Engine.engine->ClientPrintf(client, buf);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
g_Engine.engine->ClientPrintf(client, buffer);
|
||||
}
|
||||
|
||||
void CSmmAPI::LoadAsVSP()
|
||||
|
||||
@ -76,9 +76,9 @@ public:
|
||||
* @brief Called on plugin unload. You can return false if you know your plugin
|
||||
* is not capable of restoring critical states it modifies.
|
||||
*
|
||||
* @param error Error message buffer
|
||||
* @param maxlen Size of error message buffer
|
||||
* @return True on success, return false to request no unload.
|
||||
* @param error Error message buffer
|
||||
* @param maxlen Size of error message buffer
|
||||
* @return True on success, return false to request no unload.
|
||||
*/
|
||||
virtual bool Unload(char *error, size_t maxlen)
|
||||
{
|
||||
@ -353,7 +353,7 @@ public:
|
||||
#define META_CONPRINT g_SMAPI->ConPrint
|
||||
#define META_CONPRINTF g_SMAPI->ConPrintf
|
||||
|
||||
//probably should use this up above someday
|
||||
/* Probably should use this up above someday */
|
||||
#define CONCMD_VARNAME(name) name##_command
|
||||
|
||||
#if !defined SMM_API
|
||||
@ -374,7 +374,7 @@ public:
|
||||
* @param v_factory Factory method to use from ISmmAPI (such as engineFactory).
|
||||
* @param v_var Variable name to store into.
|
||||
* @param v_type Interface type (do not include the pointer/asterisk).
|
||||
* @param v_name Inteface name.
|
||||
* @param v_name Interface name.
|
||||
*/
|
||||
#define GET_V_IFACE_CURRENT(v_factory, v_var, v_type, v_name) \
|
||||
v_var = (v_type *)ismm->VInterfaceMatch(ismm->v_factory(), v_name); \
|
||||
@ -390,10 +390,10 @@ public:
|
||||
/**
|
||||
* @brief Same as GET_V_IFACE, except searches for any.
|
||||
*
|
||||
* @param v_factory Factory method to use from ISmmAPI (such as engineFactory).
|
||||
* @param v_var Variable name to store into.
|
||||
* @param v_factory Factory method to use from ISmmAPI (such as engineFactory).
|
||||
* @param v_var Variable name to store into.
|
||||
* @param v_type Interface type (do not include the pointer/asterisk).
|
||||
* @param v_name Inteface name.
|
||||
* @param v_name Interface name.
|
||||
*/
|
||||
#define GET_V_IFACE_ANY(v_factory, v_var, v_type, v_name) \
|
||||
v_var = (v_type *)ismm->VInterfaceMatch(ismm->v_factory(), v_name, 0); \
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
- Added API functions for retrieving User Message info without potentially crashing.
|
||||
- Added API functions for letting SourceMM plugins use Valve Server Plugin callbacks.
|
||||
- Changed version numbering to include the build number (SVN revision).
|
||||
- Fixed amb93 (improved mod path detection).
|
||||
- Fixed various potential buffer overflows.
|
||||
|
||||
2006/11/29 1.3d:
|
||||
- Updated Metamod:Source to recognize the latest Source Engine version (ServerGameDLL006)
|
||||
|
||||
@ -185,7 +185,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
return;
|
||||
} else if (strcmp(command, "refresh") == 0) {
|
||||
char full_path[255];
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path) - 1, "%s/%s", g_ModPath.c_str(), GetPluginsFile());
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile());
|
||||
|
||||
LoadPluginsFromFile(full_path);
|
||||
|
||||
@ -359,7 +359,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
|
||||
char error[255];
|
||||
|
||||
if (!g_PluginMngr.Pause(id, error, sizeof(error)-1))
|
||||
if (!g_PluginMngr.Pause(id, error, sizeof(error)))
|
||||
{
|
||||
CONMSG("Pause failed: %s\n", error);
|
||||
return;
|
||||
@ -379,7 +379,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
int id = atoi(e->Cmd_Argv(2));
|
||||
char error[255];
|
||||
|
||||
if (!g_PluginMngr.Unpause(id, error, sizeof(error)-1))
|
||||
if (!g_PluginMngr.Unpause(id, error, sizeof(error)))
|
||||
{
|
||||
CONMSG("Unpause failed: %s\n", error);
|
||||
return;
|
||||
@ -407,8 +407,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
|
||||
if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0)
|
||||
{
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s", file);
|
||||
snprintf(full_path, sizeof(full_path)-1, "%s", file);
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s", file);
|
||||
} else {
|
||||
const char *ext = UTIL_GetExtension(file);
|
||||
#if defined WIN32 || defined _WIN32
|
||||
@ -416,14 +415,14 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
#else
|
||||
ext = ext ? "" : "_i486.so";
|
||||
#endif
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s/%s%s", g_ModPath.c_str(), file, ext);
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext);
|
||||
}
|
||||
|
||||
char error[255]={0};
|
||||
bool already;
|
||||
SourceMM::CPluginManager::CPlugin *pl;
|
||||
|
||||
PluginId id = g_PluginMngr.Load(full_path, Pl_Console, already, error, sizeof(error)-1);
|
||||
PluginId id = g_PluginMngr.Load(full_path, Pl_Console, already, error, sizeof(error));
|
||||
pl = g_PluginMngr.FindById(id);
|
||||
if (!pl || id < Pl_MinId || (pl->m_Status < Pl_Paused))
|
||||
{
|
||||
@ -511,8 +510,7 @@ 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)-1, "%s", file);
|
||||
snprintf(full_path, sizeof(full_path)-1, "%s", file);
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s", file);
|
||||
} else {
|
||||
const char *ext = UTIL_GetExtension(file);
|
||||
#if defined WIN32 || defined _WIN32
|
||||
@ -520,7 +518,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
#else
|
||||
ext = ext ? "" : "_i486.so";
|
||||
#endif
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s/%s%s", g_ModPath.c_str(), file, ext);
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext);
|
||||
}
|
||||
|
||||
SourceHook::List<SourceMM::CPluginManager::CPlugin *>::iterator iter, end;
|
||||
@ -543,7 +541,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)-1))
|
||||
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)))
|
||||
{
|
||||
CONMSG("Unload failed: %s\n", error);
|
||||
return;
|
||||
@ -560,7 +558,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
int id = atoi(e->Cmd_Argv(2));
|
||||
char error[255]={0};
|
||||
|
||||
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)-1))
|
||||
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)))
|
||||
{
|
||||
CONMSG("Force unload failed: %s\n", error);
|
||||
return;
|
||||
@ -590,7 +588,7 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
int id = atoi(e->Cmd_Argv(2));
|
||||
char error[255];
|
||||
|
||||
if (!g_PluginMngr.Retry(id, error, sizeof(error)-1))
|
||||
if (!g_PluginMngr.Retry(id, error, sizeof(error)))
|
||||
{
|
||||
CONMSG("Error reloading plugin: %s\n", error);
|
||||
return;
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
@ -126,7 +126,7 @@
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||
StringPooling="true"
|
||||
ExceptionHandling="1"
|
||||
RuntimeLibrary="0"
|
||||
|
||||
@ -31,24 +31,28 @@
|
||||
#define dlsym(x, s) GetProcAddress(x, s)
|
||||
#define dlclose(x) FreeLibrary(x)
|
||||
const char* dlerror();
|
||||
#define PATH_SEP_STR "\\"
|
||||
#define PATH_SEP_CHAR '\\'
|
||||
#define ALT_SEP_CHAR '/'
|
||||
#define SERVER_DLL "server.dll"
|
||||
#define abspath(x, s) _fullpath(x, s, sizeof(x))
|
||||
#define PATH_SEP_STR "\\"
|
||||
#define PATH_SEP_CHAR '\\'
|
||||
#define ALT_SEP_CHAR '/'
|
||||
#define PATH_SIZE MAX_PATH
|
||||
#define SERVER_DLL "server.dll"
|
||||
#elif defined __linux__
|
||||
#define OS_LINUX
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#define dlmount(x) dlopen(x,RTLD_NOW)
|
||||
typedef void* HINSTANCE;
|
||||
#define PATH_SEP_STR "/"
|
||||
#define PATH_SEP_CHAR '/'
|
||||
#define ALT_SEP_CHAR '\\'
|
||||
#define dlmount(x) dlopen(x,RTLD_NOW)
|
||||
#define abspath(x, s) realpath(s, x)
|
||||
#define PATH_SEP_STR "/"
|
||||
#define PATH_SEP_CHAR '/'
|
||||
#define ALT_SEP_CHAR '\\'
|
||||
#define PATH_SIZE PATH_MAX
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#define SERVER_DLL "server_i486.so"
|
||||
#define SERVER_DLL "server_i486.so"
|
||||
#endif
|
||||
|
||||
#if defined __linux__
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include <tier0/icommandline.h>
|
||||
#include "sourcemm.h"
|
||||
#include "concommands.h"
|
||||
#include "CSmmAPI.h"
|
||||
@ -26,6 +27,9 @@ using namespace SourceMM;
|
||||
* @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);
|
||||
@ -46,17 +50,19 @@ SourceHook::CSourceHookImpl g_SourceHook;
|
||||
SourceHook::ISourceHook *g_SHPtr = &g_SourceHook;
|
||||
SourceHook::String g_ModPath;
|
||||
SourceHook::String g_BinPath;
|
||||
PluginId g_PLID = Pl_Console; //Technically, SourceMM is the "Console" plugin... :p
|
||||
PluginId g_PLID = Pl_Console; /* Technically, SourceMM is the "Console" plugin... :p */
|
||||
bool bInFirstLevel = true;
|
||||
bool gParsedGameInfo = false;
|
||||
bool bGameInit = false;
|
||||
SourceHook::List<GameDllInfo *> gamedll_list;
|
||||
SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
|
||||
int g_GameDllVersion = 0;
|
||||
const char VSPIFACE[] = "ISERVERPLUGINS";
|
||||
const char GAMEINFO_PATH[] = "|gameinfo_path|";
|
||||
|
||||
void ClearGamedllList();
|
||||
|
||||
//helper macro
|
||||
/* Helper Macro */
|
||||
#define IFACE_MACRO(orig,nam) \
|
||||
CPluginManager::CPlugin *pl; \
|
||||
SourceHook::List<IMetamodListener *>::iterator event; \
|
||||
@ -92,16 +98,17 @@ void ClearGamedllList();
|
||||
// Main code for HL2 Interaction //
|
||||
///////////////////////////////////
|
||||
|
||||
//Initialize everything here
|
||||
/* Initialize everything here */
|
||||
void InitMainStates()
|
||||
{
|
||||
char full_path[260] = {0};
|
||||
GetFileOfAddress((void *)g_GameDll.factory, full_path, sizeof(full_path)-1);
|
||||
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).
|
||||
/* 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);
|
||||
@ -115,7 +122,7 @@ void InitMainStates()
|
||||
{
|
||||
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...
|
||||
/* 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.");
|
||||
}
|
||||
@ -143,7 +150,7 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory,
|
||||
|
||||
g_Engine.loaded = true;
|
||||
|
||||
//Initialize our console hooks
|
||||
/* Initialize our console hooks */
|
||||
ConCommandBaseMgr::OneTimeInit(static_cast<IConCommandBaseAccessor *>(&g_SMConVarAccessor));
|
||||
|
||||
g_GameDllPatch = SH_GET_CALLCLASS(g_GameDll.pGameDLL);
|
||||
@ -157,7 +164,8 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory,
|
||||
if (!g_SmmAPI.CacheUserMessages())
|
||||
{
|
||||
/* Don't know of a mod that has stripped out user messages completely,
|
||||
but perhaps should do something different here? */
|
||||
* 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.");
|
||||
}
|
||||
@ -169,7 +177,7 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory,
|
||||
}
|
||||
|
||||
char full_path[260];
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s/%s", g_ModPath.c_str(), pluginFile);
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), pluginFile);
|
||||
|
||||
LoadPluginsFromFile(full_path);
|
||||
|
||||
@ -201,11 +209,10 @@ bool DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFact
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
//This is where the magic happens
|
||||
/* 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
|
||||
const char *vspIface = "ISERVERPLUGINCALLBACKS";
|
||||
/* 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");
|
||||
@ -218,7 +225,7 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strncmp(iface, vspIface, 22) == 0)
|
||||
if (strncmp(iface, VSPIFACE, sizeof(VSPIFACE) - 1) == 0)
|
||||
{
|
||||
if (ret)
|
||||
{
|
||||
@ -231,127 +238,52 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
if (!gParsedGameInfo)
|
||||
{
|
||||
gParsedGameInfo = true;
|
||||
char curpath[260] = {0};
|
||||
char dllpath[260] = {0};
|
||||
getcwd(curpath, sizeof(curpath)-1);
|
||||
if (!GetFileOfAddress((void *)CreateInterface, dllpath, sizeof(dllpath)-1))
|
||||
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;
|
||||
}
|
||||
SourceHook::String s_dllpath(dllpath);
|
||||
//begin the heuristics for searching for the mod path (these are quite ugly).
|
||||
//for OS compatibility purposes, we're going to do case insensitivity on windows.
|
||||
size_t path_len = strlen(curpath);
|
||||
size_t dll_len = strlen(dllpath);
|
||||
|
||||
//strip the dll path off
|
||||
//:TODO: with path stuff - in Linux, \ can exist in a file path as a non-seperator!
|
||||
for (size_t i=dll_len-1; i>0; i--)
|
||||
{
|
||||
if (dllpath[i] == '\\' || dllpath[i] == '/')
|
||||
{
|
||||
if (i == dll_len-1)
|
||||
break;
|
||||
//save path by stripping off file name and ending terminator
|
||||
dllpath[i] = '\0';
|
||||
dll_len = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Get value of -game from command line, defaulting to hl2 as engine seems to do */
|
||||
gameDir = CommandLine()->ParmValue("-game", "hl2");
|
||||
|
||||
//strip absolute path terminators if any!
|
||||
if (curpath[path_len-1] == '/' || curpath[path_len-1] == '\\')
|
||||
curpath[--path_len] = '\0';
|
||||
/* Get absolute path */
|
||||
abspath(gamePath, gameDir);
|
||||
g_ModPath.assign(gamePath);
|
||||
|
||||
//if the base path doesn't fit into the module path, something is wrong!
|
||||
// ex: c:\games\srcds
|
||||
// c:\gaben.dll
|
||||
if (path_len > dll_len)
|
||||
{
|
||||
Error("Could not detect GameDLL path! Metamod cannot load[1].\n");
|
||||
return NULL;
|
||||
}
|
||||
char tempPath[PATH_SIZE];
|
||||
|
||||
//we are now in such a position that the two dir names SHOULD MATCH!
|
||||
typedef int (*STRNCMP)(const char *str1, const char *str2, size_t n);
|
||||
STRNCMP cmp =
|
||||
#ifdef WIN32
|
||||
strnicmp;
|
||||
#else
|
||||
strncmp;
|
||||
#endif
|
||||
//are they equal?
|
||||
if ( ((cmp)(curpath, dllpath, path_len)) != 0 )
|
||||
{
|
||||
//:TODO: In this case, we should read /proc/self/maps and find srcds!
|
||||
Error("Could not detect GameDLL path! Metamod cannot load[2].\n");
|
||||
return NULL;
|
||||
}
|
||||
//this will skip past the dir and its separator char
|
||||
char *ptr = &(dllpath[path_len+1]);
|
||||
path_len = strlen(ptr);
|
||||
for (size_t i=0; i<path_len; i++)
|
||||
{
|
||||
if (ptr[i] == '/' || ptr[i] == '\\')
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
Error("Could not detect GameDLL path! Metamod cannot load[3].\n");
|
||||
return NULL;
|
||||
} else {
|
||||
ptr[i] = '\0';
|
||||
path_len = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//WE NOW HAVE A GUESS AT THE MOD DIR. OH MY GOD.
|
||||
char temp_path[260];
|
||||
snprintf(temp_path, sizeof(temp_path)-1,
|
||||
"%s%s%s",
|
||||
curpath,
|
||||
PATH_SEP_STR,
|
||||
ptr);
|
||||
/* Path to gameinfo.txt */
|
||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s", g_ModPath.c_str(), "gameinfo.txt");
|
||||
|
||||
g_ModPath.assign(temp_path);
|
||||
FILE *fp = fopen(tempPath, "rt");
|
||||
|
||||
snprintf(temp_path, sizeof(temp_path)-1,
|
||||
"%s%s%s",
|
||||
g_ModPath.c_str(),
|
||||
PATH_SEP_STR,
|
||||
"gameinfo.txt");
|
||||
|
||||
FILE *fp = fopen(temp_path, "rt");
|
||||
if (!fp)
|
||||
{
|
||||
/* Do not error out here! It's possible the mod exists in the root directory, i.e.
|
||||
* Dark Messiah. Let's check that just in case!
|
||||
*/
|
||||
g_SmmAPI.PathFormat(temp_path, sizeof(temp_path)-1, "%s", curpath);
|
||||
g_ModPath.assign(temp_path);
|
||||
g_SmmAPI.PathFormat(temp_path, sizeof(temp_path)-1, "%s/%s", g_ModPath.c_str(), "gameinfo.txt");
|
||||
|
||||
fp = fopen(temp_path, "rt");
|
||||
if (!fp)
|
||||
{
|
||||
/* Okay, we have to concede here. */
|
||||
Error("Unable to open gameinfo.txt! Metamod cannot load.\n");
|
||||
return NULL;
|
||||
}
|
||||
Error("Unable to open gameinfo.txt! Metamod cannot load.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char buffer[255];
|
||||
char key[128], val[128];
|
||||
size_t len = 0;
|
||||
const char *gameinfo = "|gameinfo_path|";
|
||||
size_t gameinfo_len = strlen(gameinfo);
|
||||
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)-1, fp);
|
||||
fgets(buffer, sizeof(buffer), fp);
|
||||
len = strlen(buffer);
|
||||
if (buffer[len-1] == '\n')
|
||||
buffer[--len] = '\0';
|
||||
@ -362,7 +294,7 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
search = true;
|
||||
if (!search)
|
||||
continue;
|
||||
UTIL_KeySplit(buffer, key, sizeof(key)-1, val, sizeof(val)-1);
|
||||
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)
|
||||
@ -370,32 +302,35 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
else
|
||||
gamebin = true;
|
||||
|
||||
if (strncmp(val, gameinfo, gameinfo_len) == 0)
|
||||
if (strncmp(val, GAMEINFO_PATH, sizeof(GAMEINFO_PATH) - 1) == 0)
|
||||
{
|
||||
ptr = &(val[gameinfo_len]);
|
||||
ptr = &(val[sizeof(GAMEINFO_PATH) - 1]);
|
||||
if (ptr[0] == '.')
|
||||
ptr++;
|
||||
lptr = g_ModPath.c_str();
|
||||
} else {
|
||||
lptr = curpath;
|
||||
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"
|
||||
/* No need to append "bin" if key is GameBin */
|
||||
if (gamebin)
|
||||
{
|
||||
g_SmmAPI.PathFormat(temp_path, sizeof(temp_path)-1, "%s/%s/%s", lptr, ptr, SERVER_DLL);
|
||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s", lptr, ptr, SERVER_DLL);
|
||||
} else if (!ptr[0]) {
|
||||
g_SmmAPI.PathFormat(temp_path, sizeof(temp_path)-1, "%s/%s/%s", lptr, "bin", SERVER_DLL);
|
||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s", lptr, "bin", SERVER_DLL);
|
||||
} else {
|
||||
g_SmmAPI.PathFormat(temp_path, sizeof(temp_path)-1, "%s/%s/%s/%s", lptr, ptr, "bin", SERVER_DLL);
|
||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s/%s", lptr, ptr, "bin", SERVER_DLL);
|
||||
}
|
||||
if (!UTIL_PathCmp(s_dllpath.c_str(), temp_path))
|
||||
|
||||
/* If not path to SourceMM... */
|
||||
if (!UTIL_PathCmp(smmPath, tempPath))
|
||||
{
|
||||
FILE *fp = fopen(temp_path, "rb");
|
||||
FILE *fp = fopen(tempPath, "rb");
|
||||
if (!fp)
|
||||
continue;
|
||||
//:TODO: Optimize this a bit!
|
||||
@ -405,9 +340,9 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
|
||||
{
|
||||
pCheck = (*iter);
|
||||
if (GetFileOfAddress((void *)pCheck->factory, buffer, sizeof(buffer)-1))
|
||||
if (GetFileOfAddress((void *)pCheck->factory, buffer, sizeof(buffer)))
|
||||
{
|
||||
if (UTIL_PathCmp(temp_path, buffer))
|
||||
if (UTIL_PathCmp(tempPath, buffer))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
@ -417,7 +352,7 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
if (found)
|
||||
continue;
|
||||
fclose(fp);
|
||||
HINSTANCE gamedll = dlmount(temp_path);
|
||||
HINSTANCE gamedll = dlmount(tempPath);
|
||||
if (gamedll == NULL)
|
||||
continue;
|
||||
CreateInterfaceFn fn = (CreateInterfaceFn)dlsym(gamedll, "CreateInterface");
|
||||
@ -447,12 +382,12 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
|
||||
if (strncmp(iface, str, len) == 0)
|
||||
{
|
||||
//This is the interface we want! Right now we support versions 3 through 5.
|
||||
/* 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
|
||||
/* Maybe this will get used in the future */
|
||||
sizeTooBig = g_GameDllVersion;
|
||||
if (ret)
|
||||
{
|
||||
@ -468,7 +403,7 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
ptr = (pInfo->factory)(iface, ret);
|
||||
if (ptr)
|
||||
{
|
||||
//this is our gamedll. unload the others.
|
||||
/* This is our GameDLL. Unload the others. */
|
||||
gamedll_list.erase(iter);
|
||||
ClearGamedllList();
|
||||
pInfo->pGameDLL = static_cast<IServerGameDLL *>(ptr);
|
||||
@ -497,14 +432,14 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
//wtf do we do...
|
||||
//:TODO: .. something a bit more intelligent?
|
||||
/* wtf do we do... */
|
||||
/* :TODO: .. something a bit more intelligent? */
|
||||
Error("Engine requested unknown interface before GameDLL was known!\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//if we got here, there's definitely a gamedll.
|
||||
/* If we got here, there's definitely a GameDLL */
|
||||
IFACE_MACRO(g_GameDll.factory, GameDLL);
|
||||
}
|
||||
|
||||
@ -525,10 +460,10 @@ void ClearGamedllList()
|
||||
|
||||
void DLLShutdown_handler()
|
||||
{
|
||||
//Unload plugins
|
||||
/* Unload plugins */
|
||||
g_PluginMngr.UnloadAll();
|
||||
|
||||
// Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly
|
||||
/* Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly */
|
||||
g_SMConVarAccessor.MarkCommandsAsGameDLL();
|
||||
g_SMConVarAccessor.UnregisterGameDLLCommands();
|
||||
|
||||
@ -566,7 +501,7 @@ int LoadPluginsFromFile(const char *_file)
|
||||
while (!feof(fp))
|
||||
{
|
||||
buffer[0] = '\0';
|
||||
fgets(buffer, sizeof(buffer)-1, fp);
|
||||
fgets(buffer, sizeof(buffer), fp);
|
||||
length = strlen(buffer);
|
||||
if (!length)
|
||||
continue;
|
||||
@ -618,11 +553,11 @@ int LoadPluginsFromFile(const char *_file)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//First find if it's an absolute path or not...
|
||||
/* 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)-1);
|
||||
/* 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);
|
||||
@ -633,9 +568,9 @@ int LoadPluginsFromFile(const char *_file)
|
||||
total++;
|
||||
}
|
||||
} else {
|
||||
//Attempt to find a file extension
|
||||
/* Attempt to find a file extension */
|
||||
ptr = UTIL_GetExtension(file);
|
||||
//Add an extension if there's none there
|
||||
/* Add an extension if there's none there */
|
||||
if (!ptr)
|
||||
{
|
||||
#if defined WIN32 || defined _WIN32
|
||||
@ -646,9 +581,9 @@ int LoadPluginsFromFile(const char *_file)
|
||||
} else {
|
||||
ext = "";
|
||||
}
|
||||
//Format the new path
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s/%s%s", g_ModPath.c_str(), file, ext);
|
||||
id = g_PluginMngr.Load(full_path, Pl_File, already, error, sizeof(error)-1);
|
||||
/* 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);
|
||||
@ -672,22 +607,25 @@ int LoadPluginsFromFile(const char *_file)
|
||||
return total;
|
||||
}
|
||||
|
||||
//Wrapper function. This is called when the GameDLL thinks it's using
|
||||
// the engine's real engineFactory.
|
||||
/* 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.
|
||||
/* 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.
|
||||
/* 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);
|
||||
@ -698,13 +636,13 @@ void LogMessage(const char *msg, ...)
|
||||
va_list ap;
|
||||
static char buffer[2048];
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
va_start(ap, msg);
|
||||
vsnprintf(buffer, sizeof(buffer)-5, msg, ap);
|
||||
strcat(buffer, "\n");
|
||||
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);
|
||||
@ -718,7 +656,7 @@ void LevelShutdown_handler(void)
|
||||
if (!bInFirstLevel)
|
||||
{
|
||||
char full_path[255];
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path) - 1, "%s/%s", g_ModPath.c_str(), GetPluginsFile());
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile());
|
||||
|
||||
LoadPluginsFromFile(full_path);
|
||||
} else {
|
||||
|
||||
@ -10,67 +10,86 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "util.h"
|
||||
#include "oslink.h"
|
||||
|
||||
/**
|
||||
* @brief Utility functons
|
||||
* @brief Utility functions
|
||||
* @file util.cpp
|
||||
*/
|
||||
|
||||
/* UTIL_GetExtension
|
||||
* Returns a pointer to the extension in a file name
|
||||
*/
|
||||
const char *UTIL_GetExtension(const char *file)
|
||||
{
|
||||
int len = strlen(file);
|
||||
int i = 0;
|
||||
|
||||
for (i=len-1; i>=0; i--)
|
||||
for (i = len - 1; i >= 0; i--)
|
||||
{
|
||||
if (file[i] == '/' || file[i] == '\\')
|
||||
return NULL;
|
||||
|
||||
if ((file[i] == '.') && (i != len-1))
|
||||
{
|
||||
return (const char *)&(file[i+1]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((file[i] == '.') && (i != len - 1))
|
||||
{
|
||||
return (const char *)&(file[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* UTIL_TrimLeft
|
||||
* Removes whitespace characters from left side of string
|
||||
*/
|
||||
void UTIL_TrimLeft(char *buffer)
|
||||
{
|
||||
// Let's think of this as our iterator
|
||||
/* Let's think of this as our iterator */
|
||||
char *i = buffer;
|
||||
|
||||
// Make sure the buffer isn't null
|
||||
/* Make sure the buffer isn't null */
|
||||
if (i && *i)
|
||||
{
|
||||
// Add up number of whitespace characters
|
||||
while(isspace(*i))
|
||||
/* Add up number of whitespace characters */
|
||||
while(isspace((unsigned char) *i))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
// If whitespace chars in buffer then adjust string so first non-whitespace char is at start of buffer
|
||||
/* If whitespace chars in buffer then adjust string so first non-whitespace char is at start of buffer */
|
||||
if (i != buffer)
|
||||
{
|
||||
memmove(buffer, i, (strlen(i) + 1) * sizeof(char));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//:TODO: this should skip string literals
|
||||
void UTIL_TrimRight(char *buffer)
|
||||
{
|
||||
/* Make sure buffer isn't null */
|
||||
if (buffer)
|
||||
{
|
||||
size_t len = strlen(buffer);
|
||||
|
||||
/* Loop through buffer backwards while replacing whitespace chars with null chars */
|
||||
for (size_t i = len - 1; i >= 0; i--)
|
||||
{
|
||||
if (isspace((unsigned char) buffer[i]))
|
||||
{
|
||||
buffer[i] = '\0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* :TODO: this should skip string literals */
|
||||
void UTIL_TrimComments(char *buffer)
|
||||
{
|
||||
int num_sc = 0;
|
||||
size_t len = strlen(buffer);
|
||||
if (buffer)
|
||||
{
|
||||
for (int i=(int)len-1; i>=0; i--)
|
||||
for (int i = len - 1; i >= 0; i--)
|
||||
{
|
||||
if (buffer[i] == '/')
|
||||
{
|
||||
@ -87,72 +106,62 @@ void UTIL_TrimComments(char *buffer)
|
||||
}
|
||||
num_sc = 0;
|
||||
}
|
||||
//size_t won't go below 0, manually break out
|
||||
/* size_t won't go below 0, manually break out */
|
||||
if (i == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* UTIL_TrimRight
|
||||
* Removes whitespace characters from right side of string
|
||||
*/
|
||||
void UTIL_TrimRight(char *buffer)
|
||||
{
|
||||
// Make sure buffer isn't null
|
||||
if (buffer)
|
||||
{
|
||||
// Loop through buffer backwards while replacing whitespace chars with null chars
|
||||
for (int i = (int)strlen(buffer) - 1; i >= 0; i--)
|
||||
{
|
||||
if (isspace(buffer[i]))
|
||||
buffer[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* UTIL_KeySplit
|
||||
* Breaks a string at the first space until it reaches a nonspace
|
||||
*/
|
||||
void UTIL_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2)
|
||||
{
|
||||
size_t start;
|
||||
size_t len = strlen(str);
|
||||
|
||||
for (start=0; start<len; start++)
|
||||
for (start = 0; start < len; start++)
|
||||
{
|
||||
if (!isspace(str[start]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t end;
|
||||
for (end=start; end<len; end++)
|
||||
for (end = start; end < len; end++)
|
||||
{
|
||||
if (isspace(str[end]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t i, c=0;
|
||||
for (i=start; i<end; i++,c++)
|
||||
size_t i, c = 0;
|
||||
for (i = start; i < end; i++, c++)
|
||||
{
|
||||
if (c >= len1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
buf1[c] = str[i];
|
||||
}
|
||||
buf1[c] = '\0';
|
||||
|
||||
for (start=end; start<len; start++)
|
||||
for (start = end; start < len; start++)
|
||||
{
|
||||
if (!isspace(str[start]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (c=0; start<len; start++,c++)
|
||||
for (c = 0; start < len; start++, c++)
|
||||
{
|
||||
if (c >= len2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
buf2[c] = str[start];
|
||||
}
|
||||
buf2[c] = '\0';
|
||||
@ -172,32 +181,61 @@ bool UTIL_PathCmp(const char *path1, const char *path2)
|
||||
if (path1[pos1] == PATH_SEP_CHAR)
|
||||
{
|
||||
if (path2[pos2] != PATH_SEP_CHAR)
|
||||
{
|
||||
return false;
|
||||
//look for extra path chars
|
||||
}
|
||||
|
||||
/* Look for extra path chars */
|
||||
while (path1[++pos1])
|
||||
{
|
||||
if (path1[pos1] != PATH_SEP_CHAR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (path2[++pos2])
|
||||
{
|
||||
if (path2[pos2] != PATH_SEP_CHAR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
//if we're at a different non-alphanumeric, the next character MUST Match
|
||||
/* If we're at a different non-alphanumeric, the next character MUST match */
|
||||
if (!isalpha(path1[pos1]) && (path1[pos1] != path2[pos2]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef WIN32
|
||||
if (toupper(path1[pos1]) != toupper(path2[pos2]))
|
||||
#else
|
||||
#else
|
||||
if (path1[pos1] != path2[pos2])
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pos1++;
|
||||
pos2++;
|
||||
}
|
||||
}
|
||||
|
||||
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
size_t len = vsnprintf(buffer, maxlength, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len >= maxlength)
|
||||
{
|
||||
len = maxlength - 1;
|
||||
buffer[len] = '\0';
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -11,16 +11,62 @@
|
||||
#ifndef _INCLUDE_UTIL_H
|
||||
#define _INCLUDE_UTIL_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* @brief Utility functons
|
||||
* @brief Utility functions
|
||||
* @file util.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the extension in a file name.
|
||||
*/
|
||||
const char *UTIL_GetExtension(const char *file);
|
||||
|
||||
/**
|
||||
* @brief Removes C-style comments from string.
|
||||
*/
|
||||
void UTIL_TrimComments(char *buffer);
|
||||
|
||||
/**
|
||||
* @brief Removes whitespace characters from left side of string.
|
||||
*/
|
||||
void UTIL_TrimLeft(char *buffer);
|
||||
|
||||
/**
|
||||
* @brief Removes whitespace characters from right side of string.
|
||||
*/
|
||||
void UTIL_TrimRight(char *buffer);
|
||||
|
||||
/**
|
||||
* @brief Breaks a string at the first space until it reaches a non-space.
|
||||
*/
|
||||
void UTIL_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2);
|
||||
|
||||
/**
|
||||
* @brief Compares two file paths.
|
||||
*/
|
||||
bool UTIL_PathCmp(const char *path1, const char *path2);
|
||||
|
||||
/**
|
||||
* @brief Same as snprintf except that it ensures the string buffer is null terminated.
|
||||
*/
|
||||
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Same as vsnprintf except that it ensures the string buffer is null terminated.
|
||||
*/
|
||||
inline size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params)
|
||||
{
|
||||
size_t len = vsnprintf(buffer, maxlength, fmt, params);
|
||||
|
||||
if (len >= maxlength)
|
||||
{
|
||||
len = maxlength - 1;
|
||||
buffer[len] = '\0';
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif //_INCLUDE_UTIL_H
|
||||
|
||||
Loading…
Reference in New Issue
Block a user