diff --git a/metamod/include/dlls/util.h b/metamod/include/dlls/util.h
index 8e36d48..3cbcb48 100644
--- a/metamod/include/dlls/util.h
+++ b/metamod/include/dlls/util.h
@@ -186,5 +186,4 @@ inline void UTIL_TraceLine(const Vector &vecStart, const Vector &vecEnd, IGNORE_
TRACE_LINE(vecStart, vecEnd, (igmon == ignore_monsters), pentIgnore, ptr);
}
-extern char *UTIL_VarArgs(char *format, ...);
extern void UTIL_LogPrintf(const char *fmt, ...);
diff --git a/metamod/msvc/metamod.vcxproj b/metamod/msvc/metamod.vcxproj
index 1904227..114a127 100644
--- a/metamod/msvc/metamod.vcxproj
+++ b/metamod/msvc/metamod.vcxproj
@@ -197,7 +197,6 @@
-
@@ -213,7 +212,6 @@
-
@@ -232,7 +230,6 @@
-
@@ -245,7 +242,6 @@
-
diff --git a/metamod/msvc/metamod.vcxproj.filters b/metamod/msvc/metamod.vcxproj.filters
index 3d5db74..d11fa0b 100644
--- a/metamod/msvc/metamod.vcxproj.filters
+++ b/metamod/msvc/metamod.vcxproj.filters
@@ -41,9 +41,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -77,9 +74,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -130,9 +124,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -169,9 +160,6 @@
Source Files
-
- Source Files
-
Source Files
diff --git a/metamod/src/callback_jit.cpp b/metamod/src/callback_jit.cpp
index 30832fd..e46763d 100644
--- a/metamod/src/callback_jit.cpp
+++ b/metamod/src/callback_jit.cpp
@@ -128,7 +128,7 @@ void CForwardCallbackJIT::naked_main()
for (int i = 0, hookid = 0; i < m_jitdata->plugins_count; i++) {
auto plug = &m_jitdata->plugins[i];
- if (plug->m_status < PL_RUNNING) // allow only running and paused
+ if (plug->status() < PL_RUNNING) // allow only running and paused
continue;
size_t fn_table = *(size_t *)(size_t(plug) + m_jitdata->table_offset);
@@ -141,7 +141,7 @@ void CForwardCallbackJIT::naked_main()
// check status and handler set
mov(ecx, dword_ptr[fn_table + m_jitdata->pfn_offset]);
- cmp(byte_ptr[size_t(&plug->m_status)], PL_RUNNING);
+ cmp(byte_ptr[plug->status_ptr()], PL_RUNNING);
jecxz(go_next_plugin);
jnz(go_next_plugin);
@@ -209,7 +209,7 @@ void CForwardCallbackJIT::naked_main()
for (int i = 0, hookid = 0; i < m_jitdata->plugins_count; i++) {
auto plug = &m_jitdata->plugins[i];
- if (plug->m_status < PL_RUNNING) // allow only running and paused
+ if (plug->status() < PL_RUNNING) // allow only running and paused
continue;
size_t fn_table = *(size_t *)(size_t(plug) + m_jitdata->post_table_offset);
@@ -222,7 +222,7 @@ void CForwardCallbackJIT::naked_main()
// check status and handler set
mov(ecx, dword_ptr[fn_table + m_jitdata->pfn_offset]);
- cmp(byte_ptr[size_t(&plug->m_status)], PL_RUNNING);
+ cmp(byte_ptr[plug->status_ptr()], PL_RUNNING);
jecxz(go_next_plugin);
jnz(go_next_plugin);
diff --git a/metamod/src/commands_meta.cpp b/metamod/src/commands_meta.cpp
index 80d4cba..b11dfdb 100644
--- a/metamod/src/commands_meta.cpp
+++ b/metamod/src/commands_meta.cpp
@@ -335,7 +335,7 @@ void cmd_doplug(PLUG_CMD pcmd)
// Otherwise, print error and exit.
if (pcmd == PC_REQUIRE)
{
- if (findp && findp->m_status >= PL_RUNNING && unique)
+ if (findp && findp->status() >= PL_RUNNING && unique)
{
META_DEBUG(3, "Required plugin '%s' found loaded and running.", arg);
return;
@@ -375,69 +375,69 @@ void cmd_doplug(PLUG_CMD pcmd)
{
case PC_PAUSE:
if (findp->pause())
- META_CONS("Paused plugin '%s'", findp->m_desc);
+ META_CONS("Paused plugin '%s'", findp->description());
else
- META_CONS("Pause failed for plugin '%s'", findp->m_desc);
+ META_CONS("Pause failed for plugin '%s'", findp->description());
break;
case PC_UNPAUSE:
if (findp->unpause())
- META_CONS("Unpaused plugin '%s'", findp->m_desc);
+ META_CONS("Unpaused plugin '%s'", findp->description());
else
- META_CONS("Unpause failed for plugin '%s'", findp->m_desc);
+ META_CONS("Unpause failed for plugin '%s'", findp->description());
break;
case PC_UNLOAD:
{
- findp->m_action = PA_UNLOAD;
- if (findp->unload(PT_ANYTIME, PNL_COMMAND, PNL_COMMAND))
+ findp->set_action(PA_UNLOAD);
+ if (findp->unload(PT_ANYTIME, PNL_COMMAND))
{
- META_CONS("Unloaded plugin '%s'", findp->m_desc);
+ META_CONS("Unloaded plugin '%s'", findp->description());
g_plugins->show();
}
else if (false /*meta_errno == ME_DELAYED*/) // TODO
- META_CONS("Unload delayed for plugin '%s'", findp->m_desc);
+ META_CONS("Unload delayed for plugin '%s'", findp->description());
else
- META_CONS("Unload failed for plugin '%s'", findp->m_desc);
+ META_CONS("Unload failed for plugin '%s'", findp->description());
break;
}
case PC_FORCE_UNLOAD:
{
- findp->m_action = PA_UNLOAD;
- if (findp->unload(PT_ANYTIME, PNL_CMD_FORCED, PNL_CMD_FORCED))
+ findp->set_action(PA_UNLOAD);
+ if (findp->unload(PT_ANYTIME, PNL_CMD_FORCED))
{
- META_CONS("Forced unload plugin '%s'", findp->m_desc);
+ META_CONS("Forced unload plugin '%s'", findp->description());
g_plugins->show();
}
else
- META_CONS("Forced unload failed for plugin '%s'", findp->m_desc);
+ META_CONS("Forced unload failed for plugin '%s'", findp->description());
break;
}
case PC_RELOAD:
{
- findp->m_action = PA_RELOAD;
+ findp->set_action(PA_RELOAD);
if (findp->reload(PT_ANYTIME, PNL_COMMAND))
- META_CONS("Reloaded plugin '%s'", findp->m_desc);
+ META_CONS("Reloaded plugin '%s'", findp->description());
else if (0/*meta_errno == ME_DELAYED*/) // TODO
- META_CONS("Reload delayed for plugin '%s'", findp->m_desc);
+ META_CONS("Reload delayed for plugin '%s'", findp->description());
else if (0/*meta_errno == ME_NOTALLOWED*/)
- META_CONS("Reload not allowed for plugin '%s' now, only allowed %s", findp->m_desc, findp->str_loadable(SL_ALLOWED));
+ META_CONS("Reload not allowed for plugin '%s' now, only allowed %s", findp->description(), findp->str_loadable(SL_ALLOWED));
else
- META_CONS("Reload failed for plugin '%s'", findp->m_desc);
+ META_CONS("Reload failed for plugin '%s'", findp->description());
break;
}
case PC_RETRY:
if (findp->retry(PT_ANYTIME, PNL_COMMAND))
- META_CONS("Retry succeeded for plugin '%s'", findp->m_desc);
+ META_CONS("Retry succeeded for plugin '%s'", findp->description());
else
- META_CONS("Retry failed for plugin '%s'", findp->m_desc);
+ META_CONS("Retry failed for plugin '%s'", findp->description());
break;
case PC_CLEAR:
if (!findp->clear())
{
- META_CONS("Clear failed for plugin '%s'", findp->m_desc);
+ META_CONS("Clear failed for plugin '%s'", findp->description());
return;
}
- META_CONS("Cleared failed plugin '%s' from list", findp->m_desc);
+ META_CONS("Cleared failed plugin '%s' from list", findp->description());
g_plugins->show();
break;
case PC_INFO:
diff --git a/metamod/src/conf_meta.cpp b/metamod/src/conf_meta.cpp
index 94c30c5..fd151f1 100644
--- a/metamod/src/conf_meta.cpp
+++ b/metamod/src/conf_meta.cpp
@@ -193,7 +193,7 @@ void MConfig::set_directory()
}
#endif
- NormalizePath(m_directory);
+ normalize_path(m_directory);
// get directory
char *dir = Q_strrchr(m_directory, '/');
diff --git a/metamod/src/engine_api.cpp b/metamod/src/engine_api.cpp
index f8e062e..48ea1dd 100644
--- a/metamod/src/engine_api.cpp
+++ b/metamod/src/engine_api.cpp
@@ -3,8 +3,8 @@
#define CDATA_ENG_H(x, p, h) CDATA_ENTRY(enginefuncs_t, x, p, size_t(h))
#define CDATA_ENG(x) CDATA_ENTRY(enginefuncs_t, x, P_PRE, 0u)
-meta_enginefuncs_t g_meta_engfuncs; // static trampolines to dynamic callbacks (for gamedll)
-meta_enginefuncs_t g_meta_engfuncs_jit; // dynamic jit callbacks
+enginefuncs_t g_meta_engfuncs; // static trampolines to dynamic callbacks (for gamedll)
+enginefuncs_t g_meta_engfuncs_jit; // dynamic jit callbacks
void MM_PRE_HOOK mm_QueryClientCvarValue(const edict_t* pEdict, const char* cvarName)
{
diff --git a/metamod/src/engine_api.h b/metamod/src/engine_api.h
index 29d5456..337ec14 100644
--- a/metamod/src/engine_api.h
+++ b/metamod/src/engine_api.h
@@ -12,8 +12,7 @@ typedef int (*GET_ENGINE_FUNCTIONS_FN)(enginefuncs_s *pengfuncsFromEngine, int *
// Protect against other projects which use this include file but use the
// normal enginefuncs_t type for their meta_engfuncs.
#ifdef METAMOD_CORE
- #include "meta_eiface.h" // meta_enginefuncs_t
- extern meta_enginefuncs_t g_meta_engfuncs;
+ extern enginefuncs_t g_meta_engfuncs;
void compile_engine_callbacks();
#else
diff --git a/metamod/src/enginecallbacks.h b/metamod/src/enginecallbacks.h
index e45aa71..187209c 100644
--- a/metamod/src/enginecallbacks.h
+++ b/metamod/src/enginecallbacks.h
@@ -10,14 +10,6 @@
// "hack" our way around that by using a flag METAMOD_CORE which is set
// when compiling Metamod proper.
-#ifdef METAMOD_CORE
- #include "meta_eiface.h" // HL_enginefuncs_t
-
- // Use a #define to bend the enginefuncs_t type to our HL_enginefuncs_t
- // type instead as we now use that for the global object g_engfuncs.
- #define enginefuncs_t HL_enginefuncs_t
-#endif
-
#include // ALERT, etc
#ifdef METAMOD_CORE
diff --git a/metamod/src/game_support.cpp b/metamod/src/game_support.cpp
index 6ab1568..10bd0e0 100644
--- a/metamod/src/game_support.cpp
+++ b/metamod/src/game_support.cpp
@@ -116,7 +116,7 @@ bool setup_gamedll(gamedll_t *gamedll)
// If the path is relative, the gamedll file will be missing and
// it might be found in the cache file.
- if (!IsAbsolutePath(gamedll->pathname))
+ if (!is_abs_path(gamedll->pathname))
{
char szInstallPath[MAX_PATH];
Q_snprintf(szInstallPath, sizeof(szInstallPath), "%s/%s", gamedll->gamedir, gamedll->pathname);
diff --git a/metamod/src/h_export.cpp b/metamod/src/h_export.cpp
index 789fd1b..ffb6348 100644
--- a/metamod/src/h_export.cpp
+++ b/metamod/src/h_export.cpp
@@ -34,7 +34,7 @@ void _fini()
#endif
//! Holds engine functionality callbacks
-HL_enginefuncs_t g_engfuncs;
+enginefuncs_t g_engfuncs;
globalvars_t* gpGlobals;
engine_t g_engine;
@@ -49,7 +49,8 @@ void WINAPI GiveFnptrsToDll(enginefuncs_t *pengfuncsFromEngine, globalvars_t *pG
g_engine.funcs = &g_engfuncs;
g_engine.globals = pGlobals;
- g_engfuncs.initialise_interface(pengfuncsFromEngine);
+ g_engfuncs = *pengfuncsFromEngine;
+ flush_ALERT_buffer();
// NOTE! Have to call logging function _after_ initialising g_engfuncs, so
// that g_engfuncs.pfnAlertMessage() can be resolved properly, heh. :)
META_DEV("called: GiveFnptrsToDll");
diff --git a/metamod/src/meta_eiface.cpp b/metamod/src/meta_eiface.cpp
deleted file mode 100644
index f0b1cd4..0000000
--- a/metamod/src/meta_eiface.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "precompiled.h"
-
-void meta_new_dll_functions_t::set_from(NEW_DLL_FUNCTIONS* _pFuncs)
-{
- Q_memcpy(this, _pFuncs, sizeof(NEW_DLL_FUNCTIONS));
-}
-
-void meta_enginefuncs_t::set_from(enginefuncs_t* _pFuncs)
-{
- Q_memcpy(this, _pFuncs, sizeof(enginefuncs_t));
-}
-
-void HL_enginefuncs_t::initialise_interface(enginefuncs_t* _pFuncs)
-{
- set_from(_pFuncs);
-
- // Now the pfnAlertMessage is available and we trust it to be a valid
- // pointer, so flush the message buffer.
- flush_ALERT_buffer();
-}
diff --git a/metamod/src/meta_eiface.h b/metamod/src/meta_eiface.h
deleted file mode 100644
index 8ff6f12..0000000
--- a/metamod/src/meta_eiface.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-
-// We use our own versions of the engine/dll interface structs. We add a
-// few dummy entries to the end and set them to 0. That way we are
-// protected from updates to the HL SDK adding new functions which would
-// cause a) the game dll copying arbitrary values from us and b) the game
-// dll overwriting our memory when using an old Metamod with a new game
-// dll.
-
-// meta_new_dll_functions_t
-struct meta_new_dll_functions_t: public NEW_DLL_FUNCTIONS
-{
- // Fill this object with pointers copied from a NEW_DLL_FUNCTIONS struct.
- void set_from(NEW_DLL_FUNCTIONS* pFuncs);
-};
-
-// meta_enginefuncs_t
-struct meta_enginefuncs_t : public enginefuncs_t
-{
- // Fill this object with pointers copied from an enginefuncs_t struct.
- void set_from(enginefuncs_t* pFuncs);
-};
-
-// This is a specialisation of the meta_enginefuncs_t struct which is only
-// used for the initial copy of the engine functions, i.e. those we get
-// passed from the HL engine right at the beginning.
-// Since there is only one master copy of engine functions this could be
-// implemented as a singleton. This is left as an option for later.
-struct HL_enginefuncs_t: public meta_enginefuncs_t
-{
- HL_enginefuncs_t() {};
-
- // Fill this object with pointers copied from an enginefuncs_t struct
- // and fixup the interface.
- // For this class this happens in the GiveFptrsToDll() function
- // with the pointers passed from the HL engine.
- void initialise_interface(enginefuncs_t* pFuncs);
-
-private:
- // Moving copy_to() and set_from() to the private space.
- void set_from(enginefuncs_t* pFuncs)
- {
- meta_enginefuncs_t::set_from(pFuncs);
- }
-};
diff --git a/metamod/src/metamod.cpp b/metamod/src/metamod.cpp
index 752d781..8720a24 100644
--- a/metamod/src/metamod.cpp
+++ b/metamod/src/metamod.cpp
@@ -20,7 +20,7 @@ gamedll_t g_GameDLL;
ALIGN16
meta_globals_t g_metaGlobals;
-meta_enginefuncs_t g_plugin_engfuncs;
+enginefuncs_t g_plugin_engfuncs;
MPluginList *g_plugins;
MRegCmdList *g_regCmds;
@@ -84,7 +84,7 @@ void metamod_startup()
{
META_LOG("Configfile specified via localinfo: %s", cp);
- if (FileExistsInGameDir(cp))
+ if (is_file_exists_in_gamedir(cp))
{
Q_strncpy(configFile, cp, sizeof configFile - 1);
configFile[sizeof configFile - 1] = '\0';
@@ -93,7 +93,7 @@ void metamod_startup()
META_ERROR("Empty/missing config.ini file: %s; falling back to %s", cp, configFile);
}
- if (!FileExistsInGameDir(configFile))
+ if (!is_file_exists_in_gamedir(configFile))
{
Q_strncpy(configFile, g_config->directory(), sizeof configFile - 1);
configFile[sizeof configFile - 1] = '\0';
@@ -105,14 +105,14 @@ void metamod_startup()
}
Q_strcat(configFile, "/" CONFIG_INI);
- if (!FileExistsInGameDir(configFile))
+ if (!is_file_exists_in_gamedir(configFile))
{
META_DEBUG(2, "No config.ini file found: %s", CONFIG_INI);
}
}
// Load config file
- if (FileExistsInGameDir(configFile))
+ if (is_file_exists_in_gamedir(configFile))
g_config->load(configFile);
// Now, override config options with localinfo commandline options.
@@ -163,7 +163,7 @@ void metamod_startup()
// Copy, and store pointer in g_engine struct. Yes, we could just store
// the actual engine_t struct in g_engine, but then it wouldn't be a
// pointer to match the other g_engfuncs.
- g_plugin_engfuncs.set_from(g_engine.funcs);
+ g_plugin_engfuncs = *g_engine.funcs;
g_engine.pl_funcs = &g_plugin_engfuncs;
// substitute our special versions of various commands
g_engine.pl_funcs->pfnAddServerCommand = meta_AddServerCommand;
@@ -197,7 +197,7 @@ void metamod_startup()
// In fact, we need gamedir even earlier, so moved up above.
// Load plugins file
- if (!FileExistsInGameDir(pluginFile))
+ if (!is_file_exists_in_gamedir(pluginFile))
{
Q_strncpy(pluginFile, g_config->directory(), sizeof pluginFile - 1);
pluginFile[sizeof pluginFile - 1] = '\0';
@@ -209,7 +209,7 @@ void metamod_startup()
}
Q_strcat(pluginFile, "/" PLUGINS_INI);
- if (!FileExistsInGameDir(pluginFile))
+ if (!is_file_exists_in_gamedir(pluginFile))
{
META_DEBUG(2, "No plugins.ini file found: %s", PLUGINS_INI);
}
@@ -243,7 +243,7 @@ void metamod_startup()
execFile[sizeof execFile - 1] = '\0';
}
- if (FileExistsInGameDir(execFile))
+ if (is_file_exists_in_gamedir(execFile))
{
if (execFile[0] == '/')
META_ERROR("Cannot exec absolute pathnames: %s", execFile);
@@ -268,7 +268,7 @@ bool meta_init_gamedll()
Q_memset(&g_GameDLL, 0, sizeof g_GameDLL);
GET_GAME_DIR(gamedir);
- NormalizePath(gamedir);
+ normalize_path(gamedir);
// As of 1.1.1.1, the engine routine GET_GAME_DIR no longer returns a
// full-pathname, but rather just the path specified as the argument to
@@ -280,7 +280,7 @@ bool meta_init_gamedll()
// Note: the code has always assumed the server op wouldn't do:
// hlds -game other/firearms
//
- if (IsAbsolutePath(gamedir))
+ if (is_abs_path(gamedir))
{
// Old style; GET_GAME_DIR returned full pathname. Copy this into
// our gamedir, and truncate to get the game name.
diff --git a/metamod/src/metamod.h b/metamod/src/metamod.h
index bfb5b35..036da33 100644
--- a/metamod/src/metamod.h
+++ b/metamod/src/metamod.h
@@ -6,7 +6,6 @@
#include "conf_meta.h" // MConfig
#include "osdep.h" // NAME_MAX, etc
#include "mplayer.h" // MPlayerList
-#include "meta_eiface.h" // HL_enginefuncs_t, meta_enginefuncs_t
#include "engine_t.h" // engine_t, Engine
#define PLUGINS_INI "plugins.ini" // file that lists plugins to load at startup
@@ -32,11 +31,11 @@ struct gamedll_t
extern gamedll_t g_GameDLL;
// SDK variables for storing engine funcs and globals.
-extern HL_enginefuncs_t g_engfuncs;
+extern enginefuncs_t g_engfuncs;
extern globalvars_t *gpGlobals;
// Our modified version of the engine funcs, to give to plugins.
-extern meta_enginefuncs_t g_plugin_engfuncs;
+extern enginefuncs_t g_plugin_engfuncs;
// g_config structure.
extern MConfig *g_config;
diff --git a/metamod/src/mlist.cpp b/metamod/src/mlist.cpp
index bcabb07..59238e9 100644
--- a/metamod/src/mlist.cpp
+++ b/metamod/src/mlist.cpp
@@ -11,7 +11,7 @@ MPluginList::MPluginList(const char* ifile) : m_max_loaded_count(0)
Q_memset(m_plist, 0, sizeof m_plist);
for (int i = 0; i < MAX_PLUGINS; i++)
{
- m_plist[i].m_index = i + 1; // 1-based
+ new(m_plist + i) MPlugin(i + 1); // 1-based
}
m_max_loaded_count = 0;
@@ -67,7 +67,6 @@ MPlugin *MPluginList::find(plid_t id)
{
if (m_plist[i].m_status < PL_VALID)
continue;
-
if (m_plist[i].m_info == id)
return &m_plist[i];
}
@@ -131,10 +130,10 @@ MPlugin *MPluginList::find_match(const char *prefix, bool& unique)
if (plug->m_status < PL_VALID)
continue;
- if (plug->m_info && !Q_strnicmp(plug->m_info->name, prefix, len)
+ if (plug->info() && !Q_strnicmp(plug->info()->name, prefix, len)
|| !Q_strnicmp(plug->m_desc, prefix, len)
|| !Q_strnicmp(plug->m_file, prefix, len)
- || plug->m_info && !Q_strnicmp(plug->m_info->logtag, prefix, len))
+ || plug->info() && !Q_strnicmp(plug->info()->logtag, prefix, len))
{
if (pfound) {
unique = false;
@@ -182,7 +181,7 @@ MPlugin* MPluginList::plugin_addload(plid_t plid, const char* fname, PLUG_LOADTI
return nullptr;
}
- if (pl_temp.resolve() != true) {
+ if (!pl_temp.resolve()) {
META_DEBUG(1, "Couldn't resolve given path into a file: %s", pl_temp.m_file);
return nullptr;
}
@@ -215,7 +214,6 @@ MPlugin* MPluginList::plugin_addload(plid_t plid, const char* fname, PLUG_LOADTI
return nullptr;
}
- meta_rebuild_callbacks();
META_DEBUG(1, "Loaded plugin '%s' successfully", pl_added->m_desc);
return pl_added;
@@ -263,7 +261,7 @@ MPlugin* MPluginList::add(MPlugin* padd)
// copy pathname
Q_strncpy(iplug->m_pathname, padd->m_pathname, sizeof iplug->m_pathname - 1);
iplug->m_pathname[sizeof iplug->m_pathname - 1] = '\0';
- NormalizePath(iplug->m_pathname);
+ normalize_path(iplug->m_pathname);
iplug->m_source = padd->m_source;
iplug->m_status = padd->m_status;
@@ -272,15 +270,13 @@ MPlugin* MPluginList::add(MPlugin* padd)
return iplug;
}
-
// Read plugins.ini at server startup.
bool MPluginList::ini_startup()
{
char line[MAX_STRBUF_LEN];
int n, ln;
- MPlugin *pmatch;
- if (!FileExistsInGameDir(m_inifile))
+ if (!is_file_exists_in_gamedir(m_inifile))
{
META_ERROR("ini: Metamod plugins file empty or missing: %s", m_inifile);
return false;
@@ -307,9 +303,7 @@ bool MPluginList::ini_startup()
// Parse directly into next entry in array
if (!m_plist[n].ini_parseline(line))
- {
continue;
- }
// Check for a duplicate - an existing entry with this pathname.
if (find(m_plist[n].m_pathname))
@@ -321,18 +315,13 @@ bool MPluginList::ini_startup()
// Check for a matching platform with different platform specifics
// level.
- if (nullptr != (pmatch = find_match(&m_plist[n])))
+ auto pmatch = find_match(&m_plist[n]);
+ if (pmatch)
{
- if (pmatch->m_pfspecific >= m_plist[n].m_pfspecific)
- {
- META_DEBUG(1, "ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, m_inifile, pmatch->m_pfspecific, m_plist[n].m_pfspecific);
- continue;
- }
-
- META_DEBUG(1, "ini: Plugin in line %d overrides existing plugin with lower platform specific level %d, ours %d", ln, pmatch->m_pfspecific, m_plist[n].m_pfspecific);
- int _index = pmatch->m_index;
+ META_DEBUG(1, "ini: Plugin in line %d overrides existing plugin", ln);
+ int index = pmatch->m_index;
Q_memset(pmatch, 0, sizeof(MPlugin));
- pmatch->m_index = _index;
+ pmatch->m_index = index;
}
m_plist[n].m_action = PA_LOAD;
META_LOG("ini: Read plugin config for: %s", m_plist[n].m_desc);
@@ -340,12 +329,10 @@ bool MPluginList::ini_startup()
m_max_loaded_count = n; // mark end of list
}
META_LOG("ini: Finished reading plugins list: %s; Found %d plugins to load", m_inifile, n);
-
fclose(fp);
+
if (!n)
- {
- META_ERROR("ini: Warning; no plugins found to load?");
- }
+ META_LOG("ini: Warning; no plugins found to load?");
return true;
}
@@ -355,8 +342,6 @@ bool MPluginList::ini_refresh()
{
char line[MAX_STRBUF_LEN];
int n, ln;
- MPlugin pl_temp;
- MPlugin *pl_found, *pl_added;
FILE* fp = fopen(m_inifile, "r");
if (!fp)
@@ -377,7 +362,7 @@ bool MPluginList::ini_refresh()
*cp = '\0';
// Parse into a temp plugin
- Q_memset(&pl_temp, 0, sizeof pl_temp);
+ MPlugin pl_temp = {};
if (!pl_temp.ini_parseline(line))
{
META_ERROR("ini: Skipping malformed line %d of %s",ln, m_inifile);
@@ -385,32 +370,30 @@ bool MPluginList::ini_refresh()
}
// Try to find plugin with this pathname in the current list of
// plugins.
- if (!(pl_found = find(pl_temp.m_pathname)))
+ auto pl_found = find(pl_temp.m_pathname);
+ if (!pl_found)
{
// Check for a matching platform with higher platform specifics
// level.
- if (nullptr != (pl_found = find_match(&pl_temp)))
+ pl_found = find_match(&pl_temp);
+ if (pl_found)
{
- if (pl_found->m_pfspecific >= pl_temp.m_pfspecific)
+ if (pl_found->m_action == PA_LOAD)
{
- META_DEBUG(1, "ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, m_inifile, pl_found->m_pfspecific, pl_temp.m_pfspecific);
- continue;
- }
- if (PA_LOAD == pl_found->m_action)
- {
- META_DEBUG(1, "ini: Plugin in line %d overrides loading of plugin with lower platform specific level %d, ours %d", ln, pl_found->m_pfspecific, pl_temp.m_pfspecific);
+ META_DEBUG(1, "ini: Plugin in line %d overrides loading of plugin", ln);
int _index = pl_found->m_index;
Q_memset(pl_found, 0, sizeof(MPlugin));
pl_found->m_index = _index;
}
else
{
- META_DEBUG(1, "ini: Plugin in line %d should override existing plugin with lower platform specific level %d, ours %d. Unable to comply.", ln, pl_found->m_pfspecific, pl_temp.m_pfspecific);
+ META_DEBUG(1, "ini: Plugin in line %d should override existing plugin. Unable to comply.", ln);
continue;
}
}
// new plugin; add to list
- if ((pl_added = add(&pl_temp)))
+ auto pl_added = add(&pl_temp);
+ if (pl_added)
{
// try to load this plugin at the next opportunity
pl_added->m_action = PA_LOAD;
@@ -447,22 +430,17 @@ bool MPluginList::ini_refresh()
}
if (pl_found)
- {
META_LOG("ini: Read plugin config for: %s", pl_found->m_desc);
- }
else
- {
META_LOG("ini: Read plugin config for: %s", pl_temp.m_desc);
- }
+
n++;
}
META_LOG("ini: Finished reading plugins list: %s; Found %d plugins", m_inifile, n);
-
fclose(fp);
+
if (!n)
- {
META_ERROR("ini: Warning; no plugins found to load?");
- }
return true;
}
@@ -471,9 +449,7 @@ bool MPluginList::ini_refresh()
bool MPluginList::cmd_addload(const char* args)
{
MPlugin pl_temp = {};
- MPlugin *pl_found, *pl_added;
-
- if (pl_temp.cmd_parseline(args) != true)
+ if (!pl_temp.cmd_parseline(args))
{
META_CONS("Couldn't parse 'meta load' arguments: %s", args);
return false;
@@ -481,7 +457,7 @@ bool MPluginList::cmd_addload(const char* args)
// resolve given path into a file; accepts various "shortcut"
// pathnames.
- if (pl_temp.resolve() != true)
+ if (!pl_temp.resolve())
{
// Couldn't find a matching file on disk
META_CONS("Couldn't resolve given path into a file: %s", pl_temp.m_file);
@@ -490,14 +466,16 @@ bool MPluginList::cmd_addload(const char* args)
// Try to find plugin with this pathname in the current list of
// plugins.
- if ((pl_found = find(pl_temp.m_pathname)))
+ auto pl_found = find(pl_temp.m_pathname);
+ if (pl_found)
{
// Already in list
META_CONS("Plugin '%s' already in current list; file=%s desc='%s'", pl_temp.m_file, pl_found->m_file, pl_found->m_desc);
return false;
}
// new plugin; add to list
- if (!(pl_added = add(&pl_temp)))
+ auto pl_added = add(&pl_temp);
+ if (!pl_added)
{
META_CONS("Couldn't add plugin '%s' to list; see log", pl_temp.m_desc);
return false;
@@ -513,14 +491,13 @@ bool MPluginList::cmd_addload(const char* args)
else
META_CONS("Couldn't load plugin '%s'; see log", pl_added->m_desc);
- show(0);
+ show();
return false;
}
META_CONS("Loaded plugin '%s' successfully", pl_added->m_desc);
+ show();
meta_rebuild_callbacks();
- show(0);
-
return true;
}
@@ -540,16 +517,15 @@ bool MPluginList::load()
if (m_plist[i].m_status < PL_VALID)
continue;
- if (m_plist[i].load(PT_STARTUP) == true)
+ if (m_plist[i].load(PT_STARTUP))
n++;
else
// all plugins should be loadable at startup...
META_ERROR("dll: Failed to load plugin '%s'", m_plist[i].m_file);
}
- meta_rebuild_callbacks();
-
META_LOG("dll: Finished loading %d plugins", n);
+ meta_rebuild_callbacks();
return true;
}
@@ -598,7 +574,7 @@ bool MPluginList::refresh(PLUG_LOADTIME now)
{
META_DEBUG(1, "Unloading plugin '%s'", iplug->m_desc);
iplug->m_action = PA_UNLOAD;
- if (iplug->unload(now, PNL_INI_DELETED, PNL_INI_DELETED))
+ if (iplug->unload(now, PNL_INI_DELETED))
nunloaded++;
/*else if (meta_errno == ME_DELAYED) TODO
ndelayed++;*/
@@ -630,9 +606,8 @@ bool MPluginList::refresh(PLUG_LOADTIME now)
ndone++;
}
- meta_rebuild_callbacks();
-
META_LOG("dll: Finished updating %d plugins; kept %d, loaded %d, unloaded %d, reloaded %d, delayed %d", ndone, nkept, nloaded, nunloaded, nreloaded, ndelayed);
+ meta_rebuild_callbacks();
return true;
}
@@ -688,9 +663,9 @@ void MPluginList::show(int source_index)
Q_strncpy(file, pl->m_file, sizeof file - 1);
file[sizeof file - 1] = '\0';
- if (pl->m_info && pl->m_info->version)
+ if (pl->info() && pl->info()->version)
{
- Q_strncpy(vers, pl->m_info->version, sizeof vers - 1);
+ Q_strncpy(vers, pl->info()->version, sizeof vers - 1);
vers[sizeof vers - 1] = '\0';
}
else
@@ -724,16 +699,16 @@ void MPluginList::show_client(edict_t *pEntity)
for (int i = 0; i < m_max_loaded_count; i++)
{
auto pl = &m_plist[i];
- if (pl->m_status != PL_RUNNING || !pl->m_info)
+ if (pl->m_status != PL_RUNNING || !pl->info())
continue;
n++;
META_CLIENT(pEntity, " [%3d] %s, v%s, %s, by %s, see %s", n,
- pl->m_info->name ? pl->m_info->name : "",
- pl->m_info->version ? pl->m_info->version : ">",
- pl->m_info->date ? pl->m_info->date : "<../../..>",
- pl->m_info->author ? pl->m_info->author : "",
- pl->m_info->url ? pl->m_info->url : "");
+ pl->info()->name ? pl->info()->name : "",
+ pl->info()->version ? pl->info()->version : ">",
+ pl->info()->date ? pl->info()->date : "<../../..>",
+ pl->info()->author ? pl->info()->author : "",
+ pl->info()->url ? pl->info()->url : "");
}
META_CLIENT(pEntity, "%d plugins", n);
diff --git a/metamod/src/mlist.h b/metamod/src/mlist.h
index 4588b4f..4781f6f 100644
--- a/metamod/src/mlist.h
+++ b/metamod/src/mlist.h
@@ -12,7 +12,8 @@
#define WIDTH_MAX_PLUGINS 2
// A list of plugins.
-class MPluginList {
+class MPluginList
+{
public:
MPluginList(const char *ifile);
diff --git a/metamod/src/mplugin.cpp b/metamod/src/mplugin.cpp
index 7b28277..fd2264c 100644
--- a/metamod/src/mplugin.cpp
+++ b/metamod/src/mplugin.cpp
@@ -1,49 +1,54 @@
#include "precompiled.h"
-const char* g_platform_postfixes[] = {
- "_i386.so",
- "_i486.so",
- "_i586.so",
- "_i686.so",
+const char *MPlugin::s_rPrintLoadTime[][4] = {
+ // SL_SIMPLE // SL_SHOW // SL_ALLOWED // SL_NOW
+ { "never", "Never", "never", "never" }, // PT_NEVER
+ { "startup", "Start", "at server startup", "during server startup" }, // PT_STARTUP
+ { "changelevel","Chlvl", "at changelevel", "during changelevel" }, // PT_CHANGELEVEL
+ { "anytime", "ANY", "at any time", "during map" }, // PT_ANYTIME
+ { "pausable", "Pause", "at any time, and pausable", "for requested pause" }, // PT_ANYPAUSE
};
-// Parse a line from plugins.ini into a plugin.
-bool MPlugin::ini_parseline(char *_line)
+// ReSharper disable once CppPossiblyUninitializedMember
+MPlugin::MPlugin()
{
- char line[1024];
- strncpy(line, _line, sizeof line - 1);
- line[sizeof line - 1] = '\0';
+}
- trimbuf(line);
+// ReSharper disable once CppPossiblyUninitializedMember
+MPlugin::MPlugin(int index) : m_index(index)
+{
+}
+
+// Parse a line from plugins.ini into a plugin.
+bool MPlugin::ini_parseline(char *line)
+{
+ char buf[1024];
+ strncpy(buf, line, sizeof buf - 1);
+ buf[sizeof buf - 1] = '\0';
+
+ trimbuf(buf);
// skip empty lines
- if (line[0] == '\0') {
- META_DEBUG(7, "ini: Ignoring empty line: %s", line);
+ if (buf[0] == '\0') {
return false;
}
- if (line[0] == '#' || line[0] == ';' || !Q_strncmp(line, "//", 2)) {
- META_DEBUG(7, "ini: Ignoring commented line: %s", line);
+ // skip comments
+ if (buf[0] == '#' || buf[0] == ';' || !Q_strncmp(buf, "//", 2)) {
return false;
}
// grab platform ("win32" or "linux")
char* ptr_token;
- char* token = strtok_r(line, " \t", &ptr_token);
- if (!token)
+ char* token = strtok_r(buf, " \t", &ptr_token);
+ if (!token) {
return false;
+ }
- if (!Q_stricmp(token, PLATFORM)) {
- m_pfspecific = 0; // TODO: remove it?
- }
- else if (!Q_stricmp(token, PLATFORM_SPC)) {
- m_pfspecific = 1;
- }
- else {
- // plugin is not for this OS
- META_DEBUG(7, "ini: Ignoring entry for %s", token);
- return false;
- }
+ if (!strcmp(token, "linux"))
+ m_platform = SP_LINUX;
+ else
+ m_platform = SP_WINDOWS;
// grab filename
token = strtok_r(nullptr, " \t\r\n", &ptr_token);
@@ -53,7 +58,7 @@ bool MPlugin::ini_parseline(char *_line)
Q_strncpy(m_filename, token, sizeof m_filename - 1);
m_filename[sizeof m_filename - 1] = '\0';
- NormalizePath(m_filename);
+ normalize_path(m_filename);
// Store name of just the actual _file_, without dir components.
char* cp = Q_strrchr(m_filename, '/');
@@ -87,74 +92,6 @@ bool MPlugin::ini_parseline(char *_line)
return true;
}
-// Unload a plugin from plugin request
-bool MPlugin::plugin_unload(plid_t plid, PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
-{
- MPlugin *pl_unloader = g_plugins->find(plid);
-
- if (!pl_unloader) {
- META_WARNING("dll: Not unloading plugin '%s'; plugin that requested unload is not found.", m_desc);
- return false;
- }
- if (pl_unloader->m_index == m_index) {
- META_WARNING("dll: Not unloading plugin '%s'; Plugin tried to unload itself.", m_desc);
- return false;
- }
- if (m_is_unloader) {
- META_WARNING("dll: Not unloading plugin '%s'; Plugin is unloading plugin that tried to unload it.", m_desc);
- return false;
- }
-
- m_unloader_index = pl_unloader->m_index;
-
- //block unloader from being unloaded by other plugin
- pl_unloader->m_is_unloader = true;
-
- //try unload
- PLUG_ACTION old_action = m_action;
- m_action = PA_UNLOAD;
-
- if (unload(now, reason, PNL_PLG_FORCED)) {
- META_DEBUG(1, "Unloaded plugin '%s'", m_desc);
- pl_unloader->m_is_unloader = false;
- return true;
- }
-
- pl_unloader->m_is_unloader = false;
- m_action = old_action;
-
- return false;
-}
-
-// Parse a filename string from PEXT_LOAD_PLUGIN_BY_ *function into a plugin.
-bool MPlugin::plugin_parseline(const char *fname, int loader_index)
-{
- m_source_plugin_index = loader_index;
-
- Q_strncpy(m_filename, fname, sizeof m_filename - 1);
- m_filename[sizeof m_filename - 1] = '\0';
- NormalizePath(m_filename);
-
- //store just name of the actual _file, without path
- char* cp = Q_strrchr(m_filename, '/');
- if (cp)
- m_file = cp + 1;
- else
- m_file = m_filename;
-
- //grab description
- //temporarily use plugin file until plugin can be queried
- Q_snprintf(m_desc, sizeof m_desc, "<%s>", m_file);
-
- //make full pathname
- full_gamedir_path(m_filename, m_pathname);
-
- m_source = PS_PLUGIN;
- m_status = PL_VALID;
-
- return true;
-}
-
// Parse a line from console "load" command into a plugin.
bool MPlugin::cmd_parseline(const char *line)
{
@@ -176,7 +113,7 @@ bool MPlugin::cmd_parseline(const char *line)
Q_strncpy(m_filename, token, sizeof m_filename - 1);
m_filename[sizeof m_filename - 1] = '\0';
- NormalizePath(m_filename);
+ normalize_path(m_filename);
// store name of just the actual _file_, without dir components
char* cp = Q_strrchr(m_filename, '/');
@@ -188,14 +125,12 @@ bool MPlugin::cmd_parseline(const char *line)
// Grab description.
// Specify no delimiter chars, as we just want the rest of the line.
token = strtok_r(nullptr, "", &ptr_token);
- if (token)
- {
+ if (token) {
token = token + strspn(token, " \t"); // skip whitespace
Q_strncpy(m_desc, token, sizeof m_desc - 1);
m_desc[sizeof m_desc - 1] = '\0';
}
- else
- {
+ else {
// if no description is specified, temporarily use plugin file,
// until plugin can be queried, and desc replaced with info->name.
Q_snprintf(m_desc, sizeof m_desc, "<%s>", m_file);
@@ -210,6 +145,35 @@ bool MPlugin::cmd_parseline(const char *line)
return true;
}
+// Parse a filename string from PEXT_LOAD_PLUGIN_BY_ *function into a plugin.
+bool MPlugin::plugin_parseline(const char *fname, int loader_index)
+{
+ m_source_plugin_index = loader_index;
+
+ Q_strncpy(m_filename, fname, sizeof m_filename - 1);
+ m_filename[sizeof m_filename - 1] = '\0';
+ normalize_path(m_filename);
+
+ //store just name of the actual _file, without path
+ char* cp = Q_strrchr(m_filename, '/');
+ if (cp)
+ m_file = cp + 1;
+ else
+ m_file = m_filename;
+
+ //grab description
+ //temporarily use plugin file until plugin can be queried
+ Q_snprintf(m_desc, sizeof m_desc, "<%s>", m_file);
+
+ //make full pathname
+ full_gamedir_path(m_filename, m_pathname);
+
+ m_source = PS_PLUGIN;
+ m_status = PL_VALID;
+
+ return true;
+}
+
// Make sure this plugin has the necessary minimal information.
bool MPlugin::check_input()
{
@@ -230,7 +194,6 @@ bool MPlugin::check_input()
META_ERROR("dll: Tried to operate on plugin[%d] with an empty pathname", m_index);
return false;
}
-
if (!m_desc[0]) {
// if no description is specified, temporarily use plugin file,
// until plugin can be queried, and desc replaced with info->name.
@@ -242,29 +205,26 @@ bool MPlugin::check_input()
// Try to resolve a plugin's filename as a (possibly partial) path to an
// actual filename on disk, to facilitate easier console load-command
-// arguments. Uses resolve_dirs, resolve_prefix, and resolve_suffix below.
+// arguments. Uses resolve_dirs and resolve_suffix below.
// Example paths that it tries:
// filename
// Gamedir/filename.dll, Gamedir/filename.so
// Gamedir/filename_i386.so
-// Gamedir/dlls/mm_filename_i386.so
// Gamedir/dlls/filename_mm_i386.so
// Gamedir/dlls/filename_MM_i386.so
bool MPlugin::resolve()
{
- char *found;
-
if (!check_input()) {
return false;
}
- if (IsAbsolutePath(m_filename))
- found = resolve_prefix(m_filename);
+ char* found, tempbuf[MAX_PATH];
+ if (is_abs_path(m_filename))
+ found = resolve_suffix(m_filename, tempbuf, sizeof tempbuf);
else
- found = resolve_dirs(m_filename);
+ found = resolve_dirs(m_filename, tempbuf, sizeof tempbuf);
- if (!found)
- {
+ if (!found) {
META_DEBUG(2, "Couldn't resolve '%s' to file", m_filename);
return false;
}
@@ -282,20 +242,15 @@ bool MPlugin::resolve()
else
m_file = m_pathname;
+ const char* filename = m_pathname;
+
// store pathname: the gamedir relative path, or an absolute path
size_t len = Q_strlen(g_GameDLL.gamedir);
-
if (!Q_strnicmp(m_pathname, g_GameDLL.gamedir, len))
- {
- Q_strncpy(m_filename, m_pathname + len + 1, sizeof m_filename - 1);
- m_filename[sizeof m_filename - 1] = '\0';
- }
- else
- {
- Q_strncpy(m_filename, m_pathname, sizeof m_filename - 1);
- m_filename[sizeof m_filename - 1] = '\0';
- }
+ filename += len + 1;
+ Q_strncpy(m_filename, filename, sizeof m_filename - 1);
+ m_filename[sizeof m_filename - 1] = '\0';
return true;
}
@@ -304,73 +259,32 @@ bool MPlugin::resolve()
// Try:
// GAMEDIR/filename
// GAMEDIR/dlls/filename
-char *MPlugin::resolve_dirs(char *path) const
+char *MPlugin::resolve_dirs(const char *path, char *tempbuf, size_t maxlen) const
{
- static char buf[PATH_MAX];
+ // try in gamedir
+ Q_snprintf(tempbuf, maxlen, "%s/%s", g_GameDLL.gamedir, path);
+ if (is_valid_path(tempbuf))
+ return tempbuf;
- Q_snprintf(buf, sizeof buf, "%s/%s", g_GameDLL.gamedir, path);
+ // try other file prefixes in gamedir
+ char buf[MAX_PATH];
+ strncpy(buf, tempbuf, sizeof buf - 1);
+ buf[sizeof buf - 1] = '\0';
- // try this path
- struct stat st;
- if (!stat(buf, &st) && S_ISREG(st.st_mode))
- return buf;
-
- // try other file prefixes in this path
- char* found = resolve_prefix(buf);
+ char* found = resolve_suffix(buf, tempbuf, maxlen);
if (found)
return found;
- Q_snprintf(buf, sizeof buf, "%s/dlls/%s", g_GameDLL.gamedir, path);
+ // try in gamedir/dlls/
+ Q_snprintf(tempbuf, maxlen, "%s/dlls/%s", g_GameDLL.gamedir, path);
+ if (is_valid_path(tempbuf))
+ return tempbuf;
- // try this path
- if (!stat(buf, &st) && S_ISREG(st.st_mode))
- return buf;
+ strncpy(buf, tempbuf, sizeof buf - 1);
+ buf[sizeof buf - 1] = '\0';
// try other file prefixes for this path
- return resolve_prefix(buf);
-}
-
-// For the given path, tries several possible filename prefixes.
-// Try:
-// dir/mm_file
-// dir/file
-char *MPlugin::resolve_prefix(char *path) const
-{
- struct stat st;
- char dname[PATH_MAX];
- static char buf[PATH_MAX];
- char *found;
-
- // try "mm_" prefix FIRST.
- // split into dirname and filename
- Q_strncpy(dname, path, sizeof dname - 1);
- dname[sizeof dname - 1] = '\0';
-
- char* cp = Q_strrchr(dname, '/');
- if (cp)
- {
- *cp = '\0';
- Q_snprintf(buf, sizeof buf, "%s/mm_%s", dname, cp + 1);
- }
- else
- {
- // no directory in given path
- Q_snprintf(buf, sizeof buf, "mm_%s", path);
- }
-
- // try this path
- if (!stat(buf, &st) && S_ISREG(st.st_mode))
- return buf;
-
- // try other suffixes for this path
- if ((found = resolve_suffix(buf)))
- return found;
-
- // try other suffixes for the original path
- if ((found = resolve_suffix(path)))
- return found;
-
- return nullptr;
+ return resolve_suffix(buf, tempbuf, maxlen);
}
// For the given path, tries several different filename suffixes.
@@ -378,66 +292,42 @@ char *MPlugin::resolve_prefix(char *path) const
// path
// path_mm
// path_MM
-// path.so (linux), path.dll (win32), path.dylib (osx)
+// path.so (linux), path.dll (win32)
// path_i386.so, path_i486.so, etc (if linux)
-char *MPlugin::resolve_suffix(char *path) const
+char* MPlugin::resolve_suffix(const char *path, char *tempbuf, size_t bufsize) const
{
- char *found = nullptr;
-
- auto check = [](const char* path) -> char*
- {
- struct stat st;
-
- if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
- static char buf[PATH_MAX];
- strncpy(buf, path, sizeof buf - 1);
- buf[sizeof buf - 1] = '\0';
- return buf;
- }
-
- return nullptr;
- };
-
- if (Q_strstr(path, PLATFORM_DLEXT)) {
- return check(path);
+ if (Q_strstr(path, PLATFORM_DLEXT) && is_valid_path(path)) {
+ strncpy(tempbuf, path, bufsize - 1);
+ tempbuf[bufsize - 1] = '\0';
+ return tempbuf;
}
- char tmpbuf[PATH_MAX];
- Q_snprintf(tmpbuf, sizeof tmpbuf, "%s%s", path, PLATFORM_DLEXT);
- if ((found = check(tmpbuf))) return found;
+ // try with ext
+ Q_snprintf(tempbuf, bufsize, "%s%s", path, PLATFORM_DLEXT);
+ if (is_valid_path(tempbuf))
+ return tempbuf;
- // Hmm, recursion.
- if (!Q_strstr(path, "_mm"))
- {
- Q_snprintf(tmpbuf, sizeof tmpbuf, "%s_mm", path);
- if ((found = resolve_suffix(tmpbuf))) return found;
+ // try add suffix
+ if (!Q_strstr(path, "_mm")) {
+ char buf[MAX_PATH];
+ Q_snprintf(buf, sizeof buf, "%s_mm", path);
+
+ char* found = resolve_suffix(buf, tempbuf, bufsize);
+ if (found)
+ return found;
}
#ifndef _WIN32
for (size_t i = 0; i < arraysize(g_platform_postfixes); i++) {
- Q_snprintf(tmpbuf, sizeof tmpbuf, "%s%s", path, g_platform_postfixes[i]);
- if ((found = check(tmpbuf))) return found;
+ Q_snprintf(tempbuf, bufsize, "%s%s", path, g_platform_postfixes[i]);
+ if (is_valid_path(tempbuf))
+ return tempbuf;
}
#endif
return nullptr;
}
-// Check if a passed string starts with a known platform postfix.
-// It does not check beyond the period in order to work for both
-// Linux and Win32.
-static bool is_platform_postfix(char *pf)
-{
- if (pf) {
- for (size_t i = 0; i < arraysize(g_platform_postfixes); i++) {
- if (!Q_strcmp(pf, g_platform_postfixes[i]))
- return true;
- }
- }
- return false;
-}
-
-
// Check if a given plugin is the same but possibly for a
// different platform. A match is considered to be found if
// 1. the filename without the path is the same, or
@@ -450,34 +340,34 @@ static bool is_platform_postfix(char *pf)
// the part up to the last dot, if one exists.
bool MPlugin::platform_match(MPlugin *other) const
{
- if (m_status == PL_EMPTY || other->m_status == PL_EMPTY)
+ if (m_status == PL_EMPTY || other->status() == PL_EMPTY)
return false;
- if (!Q_strcmp(m_file, other->m_file))
+ if (!Q_strcmp(m_file, other->file()))
return true;
- if (m_status >= PL_OPENED && other->m_status >= PL_OPENED && !Q_strcmp(m_info->logtag, other->m_info->logtag))
+ if (m_status >= PL_OPENED && other->status() >= PL_OPENED && !Q_strcmp(m_info->logtag, other->info()->logtag))
return true;
- if (*m_desc != '\0' && !Q_stricmp(m_desc, other->m_desc))
+ if (m_desc[0] != '\0' && other->description()[0] != '0' && !Q_stricmp(m_desc, other->description()))
return true;
- char* end = Q_strrchr(m_file, '_');
+ const char* end = Q_strrchr(m_file, '_');
if (!end || !is_platform_postfix(end))
end = Q_strrchr(m_file, '.');
-
- char* other_end = Q_strrchr(other->m_file, '_');
+
+ const char* other_end = Q_strrchr(other->file(), '_');
if (!other_end || !is_platform_postfix(other_end))
- other_end = Q_strrchr(other->m_file, '.');
+ other_end = Q_strrchr(other->file(), '.');
if (!end || !other_end)
return false;
int prefixlen = end - m_file;
- if (other_end - other->m_file != prefixlen)
+ if (other_end - other->file() != prefixlen)
return false;
- if (!Q_strncmp(m_file, other->m_file, prefixlen))
+ if (!Q_strncmp(m_file, other->file(), prefixlen))
return true;
return false;
@@ -486,29 +376,23 @@ bool MPlugin::platform_match(MPlugin *other) const
// Load a plugin; query, check allowed time, attach.
bool MPlugin::load(PLUG_LOADTIME now)
{
- if (!check_input())
- {
+ if (!check_input()) {
return false;
}
- if (m_status >= PL_RUNNING)
- {
+ if (m_status >= PL_RUNNING) {
META_ERROR("dll: Not loading plugin '%s'; already loaded (status=%s)", m_desc, str_status());
return false;
}
- if (m_action != PA_LOAD && m_action != PA_ATTACH)
- {
+ if (m_action != PA_LOAD && m_action != PA_ATTACH) {
META_ERROR("dll: Not loading plugin '%s'; not marked for load (action=%s)", m_desc, str_action());
return false;
}
- if (m_status < PL_OPENED)
- {
+ if (m_status < PL_OPENED) {
// query plugin; open file and get info about it
- if (!query())
- {
+ if (!query()) {
META_ERROR("dll: Skipping plugin '%s'; couldn't query", m_desc);
- if (!m_sys_module.unload())
- {
+ if (!m_sys_module.unload()) {
META_ERROR("dll: Couldn't close plugin file '%s': %s", m_file, "invalid handle");
}
m_status = PL_BADFILE;
@@ -519,26 +403,21 @@ bool MPlugin::load(PLUG_LOADTIME now)
}
// are we allowed to attach this plugin at this time?
- if (m_info->loadable < now)
- {
- if (m_info->loadable > PT_STARTUP)
- {
+ if (m_info->loadable < now) {
+ if (m_info->loadable > PT_STARTUP) {
// will try to attach again at next opportunity
META_DEBUG(2, "dll: Delaying load plugin '%s'; can't attach now: allowed=%s; now=%s", m_desc, str_loadable(), str_loadtime(now, SL_SIMPLE));
return false;
}
- else
- {
- META_DEBUG(2, "dll: Failed load plugin '%s'; can't attach now: allowed=%s; now=%s", m_desc, str_loadable(), str_loadtime(now, SL_SIMPLE));
- // don't try to attach again later
- m_action = PA_NONE;
- return false;
- }
+
+ META_DEBUG(2, "dll: Failed load plugin '%s'; can't attach now: allowed=%s; now=%s", m_desc, str_loadable(), str_loadtime(now, SL_SIMPLE));
+ // don't try to attach again later
+ m_action = PA_NONE;
+ return false;
}
// attach plugin; get function tables
- if (attach(now) != true)
- {
+ if (!attach(now)) {
META_ERROR("dll: Failed to attach plugin '%s'", m_desc);
// Note we don't dlclose() here, since we're returning PL_FAILED,
// which implies that it's been dlopened and queried successfully.
@@ -567,6 +446,279 @@ bool MPlugin::load(PLUG_LOADTIME now)
return true;
}
+// Unload a plugin. Check time, detach.
+bool MPlugin::unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
+{
+ if (!check_input()) {
+ return false;
+ }
+ if (m_status < PL_RUNNING) {
+ if (reason != PNL_CMD_FORCED && reason != PNL_RELOAD) {
+ META_ERROR("dll: Not unloading plugin '%s'; already unloaded (status=%s)", m_desc, str_status());
+ return false;
+ }
+ }
+ if (m_action != PA_UNLOAD && m_action != PA_RELOAD) {
+ META_WARNING("dll: Not unloading plugin '%s'; not marked for unload (action=%s)", m_desc, str_action());
+ return false;
+ }
+
+ // Are we allowed to detach this plugin at this time?
+ // If forcing unload, we disregard when plugin wants to be unloaded.
+ if (m_info && m_info->unloadable < now) {
+ if (reason == PNL_CMD_FORCED) {
+ META_DEBUG(2, "dll: Forced unload plugin '%s' overriding allowed times: allowed=%s; now=%s", m_desc, str_unloadable(), str_loadtime(now, SL_SIMPLE));
+ }
+ else {
+ if (m_info->unloadable > PT_STARTUP) {
+ META_DEBUG(2, "dll: Delaying unload plugin '%s'; can't detach now: allowed=%s; now=%s", m_desc, str_unloadable(), str_loadtime(now, SL_SIMPLE));
+ // caller should give message to user
+ // try to unload again at next opportunity
+ return false;
+ }
+
+ META_DEBUG(2, "dll: Failed unload plugin '%s'; can't detach now: allowed=%s; now=%s", m_desc, str_unloadable(), str_loadtime(now, SL_SIMPLE));
+ // don't try to unload again later
+ m_action = PA_NONE;
+ return false;
+ }
+ }
+
+ // If unloading during map, then I'd like to call plugin's
+ // ServerDeactivate. However, I don't want to do this until I start
+ // calling ServerActivate when loading during map, since the SDK
+ // indicates these two routines should match call for call.
+
+ // detach plugin
+ if (!detach(now, reason)) {
+ if (reason == PNL_RELOAD) {
+ META_DEBUG(2, "dll: Reload plugin '%s' overriding failed detach", m_desc);
+ }
+ else if (reason == PNL_CMD_FORCED) {
+ META_DEBUG(2, "dll: Forced unload plugin '%s' overriding failed detach");
+ }
+ else {
+ META_WARNING("dll: Failed to detach plugin '%s'; ", m_desc);
+ return false;
+ }
+ }
+
+ g_plugins->clear_source_plugin_index(m_index);
+
+ // successful detach, or forced unload
+
+ // Unmark registered commands for this plugin (by index number).
+ g_regCmds->remove(m_index);
+ // Unmark registered cvars for this plugin (by index number).
+ g_regCvars->disable(m_index);
+
+ // Close the file. Note: after this, attempts to reference any memory
+ // locations in the file will produce a segfault.
+ if (!m_sys_module.unload()) {
+ // If DLL cannot be closed, OS is badly broken or we are giving invalid handle.
+ // So we don't return here but instead remove plugin from our listings.
+ META_WARNING("dll: Couldn't close plugin file '%s': %s", m_file, "invalid handle");
+ }
+
+ if (m_action == PA_UNLOAD) {
+ m_status = PL_EMPTY;
+ }
+ else if (m_action == PA_RELOAD) {
+ m_status = PL_VALID;
+ m_action = PA_LOAD;
+ }
+
+ clear();
+
+ META_LOG("dll: Unloaded plugin '%s' for reason '%s'", m_desc, str_reason(reason));
+ meta_rebuild_callbacks();
+ return true;
+}
+
+// Reload a plugin; unload and load again.
+bool MPlugin::reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
+{
+ if (!check_input()) {
+ return false;
+ }
+ // Are we allowed to load this plugin at this time?
+ // If we cannot load the plugin after unloading it, we keep it.
+ if (m_info && m_info->loadable < now) {
+ if (m_info->loadable > PT_STARTUP) {
+ META_DEBUG(2, "dll: Delaying reload plugin '%s'; would not be able to reattach now: allowed=%s; now=%s", m_desc, str_loadable(), str_loadtime(now, SL_SIMPLE));
+ // caller should give message to user
+ // try to reload again at next opportunity
+ return false;
+ }
+ else {
+ META_DEBUG(2, "dll: Failed reload plugin '%s'; would not be able to reattach now: allowed=%s; now=%s", m_desc, str_loadable(), str_loadtime(now, SL_SIMPLE));
+ // don't try to reload again later
+ m_action = PA_NONE;
+ return false;
+ }
+ }
+
+ if (m_status < PL_RUNNING) {
+ META_WARNING("dll: Plugin '%s' isn't running; Forcing unload plugin for reloading", m_desc);
+ reason = PNL_RELOAD;
+ }
+
+ if (!unload(now, reason)) {
+ META_WARNING("dll: Failed to unload plugin '%s' for reloading", m_desc);
+ return false;
+ }
+
+ if (!load(now)) {
+ META_WARNING("dll: Failed to reload plugin '%s' after unloading", m_desc);
+ return false;
+ }
+
+ return true;
+}
+
+// Pause a plugin; temporarily disabled for API routines.
+bool MPlugin::pause()
+{
+ if (m_status == PL_PAUSED) {
+ META_ERROR("Not pausing plugin '%s'; already paused", m_desc);
+ return false;
+ }
+ if (m_status != PL_RUNNING) {
+ META_ERROR("Cannot pause plugin '%s'; not currently running (status=%s)", m_desc, str_status());
+ return false;
+ }
+
+ // are we allowed to pause this plugin?
+ if (m_info->unloadable < PT_ANYPAUSE) {
+ META_ERROR("Cannot pause plugin '%s'; not allowed by plugin (allowed=%s)", m_desc, str_unloadable());
+ m_action = PA_NONE;
+ return false;
+ }
+
+ m_status = PL_PAUSED;
+ META_LOG("Paused plugin '%s'", m_desc);
+ return true;
+}
+
+// Unpause a plugin.
+bool MPlugin::unpause()
+{
+ if (m_status != PL_PAUSED) {
+ META_ERROR("Cannot unpause plugin '%s'; not currently paused (status=%s)", m_desc, str_status());
+ return false;
+ }
+
+ m_status = PL_RUNNING;
+ META_LOG("Unpaused plugin '%s'", m_desc);
+ return true;
+}
+
+// Retry pending action, presumably from a previous failure.
+bool MPlugin::retry(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
+{
+ if (m_action == PA_LOAD || m_action == PA_ATTACH)
+ return load(now);
+ if (m_action == PA_UNLOAD)
+ return unload(now, reason);
+ if (m_action == PA_RELOAD)
+ return reload(now, reason);
+
+ META_ERROR("No pending action to retry for plugin '%s'; (status=%s, action=%s)", m_desc, str_status(), str_action());
+ return false;
+}
+
+template
+void free_table(T& table)
+{
+ if (table) {
+ Q_free(table);
+ table = nullptr;
+ }
+}
+
+// Clear a plugin (it failed a previous action and should be
+// removed from the list, or it's being unloaded).
+bool MPlugin::clear()
+{
+ if (m_status != PL_FAILED && m_status != PL_BADFILE && m_status != PL_EMPTY && m_status != PL_OPENED) {
+ META_ERROR("Cannot clear plugin '%s'; not marked as failed, empty, or open (status=%s)", m_desc, str_status());
+ return false;
+ }
+ // If file is open, close the file. Note: after this, attempts to
+ // reference any memory locations in the file will produce a segfault.
+ if (!m_sys_module.unload()) {
+ META_ERROR("dll: Couldn't close plugin file '%s': %s", m_file, "invalid handle");
+ m_status = PL_FAILED;
+ return false;
+ }
+
+ free_table(m_gamedll_funcs.dllapi_table);
+ free_table(m_gamedll_funcs.newapi_table);
+ free_table(m_dllapi_table);
+ free_table(m_dllapi_post_table);
+ free_table(m_newapi_table);
+ free_table(m_newapi_post_table);
+ free_table(m_engine_table);
+ free_table(m_engine_post_table);
+
+ m_status = PL_EMPTY;
+ m_action = PA_NULL;
+ m_info = nullptr;
+ m_time_loaded = 0;
+ m_dllapi_table = nullptr;
+ m_dllapi_post_table = nullptr;
+ m_newapi_table = nullptr;
+ m_newapi_post_table = nullptr;
+ m_engine_table = nullptr;
+ m_engine_post_table = nullptr;
+ m_gamedll_funcs.dllapi_table = nullptr;
+ m_gamedll_funcs.newapi_table = nullptr;
+ m_source_plugin_index = 0;
+ m_unloader_index = 0;
+ m_is_unloader = false;
+
+ return true;
+}
+
+// Unload a plugin from plugin request
+bool MPlugin::plugin_unload(plid_t plid, PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
+{
+ MPlugin *pl_unloader = g_plugins->find(plid);
+
+ if (!pl_unloader) {
+ META_WARNING("dll: Not unloading plugin '%s'; plugin that requested unload is not found.", m_desc);
+ return false;
+ }
+ if (pl_unloader->index() == m_index) {
+ META_WARNING("dll: Not unloading plugin '%s'; Plugin tried to unload itself.", m_desc);
+ return false;
+ }
+ if (m_is_unloader) {
+ META_WARNING("dll: Not unloading plugin '%s'; Plugin is unloading plugin that tried to unload it.", m_desc);
+ return false;
+ }
+
+ m_unloader_index = pl_unloader->index();
+
+ //block unloader from being unloaded by other plugin
+ pl_unloader->m_is_unloader = true;
+
+ //try unload
+ PLUG_ACTION old_action = m_action;
+ m_action = PA_UNLOAD;
+
+ if (unload(now, reason)) {
+ META_DEBUG(1, "Unloaded plugin '%s'", m_desc);
+ pl_unloader->m_is_unloader = false;
+ return true;
+ }
+
+ pl_unloader->m_is_unloader = false;
+ m_action = old_action;
+
+ return false;
+}
+
// Query a plugin:
// - dlopen() the file, store the handle
// - dlsym() and call:
@@ -629,11 +781,10 @@ bool MPlugin::query()
auto pfn_give_engfuncs = (GIVE_ENGINE_FUNCTIONS_FN)m_sys_module.getsym("GiveFnptrsToDll");
if (!pfn_give_engfuncs)
{
- // META_ERROR("dll: Couldn't find GiveFnptrsToDll() in plugin '%s': %s", desc, DLERROR());
META_ERROR("dll: Failed query plugin '%s'; Couldn't find GiveFnptrsToDll(): %s", m_desc, "function not found");
- // caller will dlclose()
return false;
}
+
pfn_give_engfuncs(g_engine.pl_funcs, g_engine.globals);
META_DEBUG(6, "dll: Plugin '%s': Called GiveFnptrsToDll()", m_desc);
@@ -671,25 +822,27 @@ bool MPlugin::query()
if (Q_strcmp(m_info->ifvers, META_INTERFACE_VERSION))
{
- int mmajor = 0, mminor = 0, pmajor = 0, pminor = 0;
+ int mmajor, mminor, pmajor, pminor;
META_DEBUG(3, "dll: Note: Plugin '%s' interface version didn't match; expected %s, found %s", m_desc, META_INTERFACE_VERSION, m_info->ifvers);
- sscanf(META_INTERFACE_VERSION, "%d:%d", &mmajor, &mminor);
- sscanf(m_info->ifvers, "%d:%d", &pmajor, &pminor);
+ sscanf(META_INTERFACE_VERSION, "%i:%i", &mmajor, &mminor);
+ sscanf(m_info->ifvers, "%i:%i", &pmajor, &pminor);
// If plugin has later interface version, it's incompatible
// (update metamod).
if (pmajor > mmajor || (pmajor == mmajor && pminor > mminor))
{
META_ERROR("dll: Plugin '%s' requires a newer version of Metamod (Metamod needs at least interface %s not the current %s)", m_desc, m_info->ifvers, META_INTERFACE_VERSION);
+ return false;
}
// If plugin has older major interface version, it's incompatible
// (update plugin).
- else if (pmajor < mmajor)
+ if (pmajor < mmajor)
{
META_ERROR("dll: Plugin '%s' is out of date and incompatible with this version of Metamod; please find a newer version of the plugin (plugin needs at least interface %s not the current %s)", m_desc, META_INTERFACE_VERSION, m_info->ifvers);
+ return false;
}
// Plugin has identical major, with older minor. This is supposed to be
// backwards compatible, so we warn, but we still accept it.
- else if (pmajor == mmajor && pminor < mminor)
+ if (pmajor == mmajor && pminor < mminor)
META_LOG("dll: Note: plugin '%s' is using an older interface version (%s), not the latest interface version (%s); there might be an updated version of the plugin", m_desc, m_info->ifvers, META_INTERFACE_VERSION);
else
META_LOG("dll: Plugin '%s': unexpected version comparision; metavers=%s, mmajor=%d, mminor=%d; plugvers=%s, pmajor=%d, pminor=%d", m_desc, META_INTERFACE_VERSION, mmajor, mminor, m_info->ifvers, pmajor, pminor);
@@ -781,7 +934,7 @@ bool MPlugin::attach(PLUG_LOADTIME now)
{
// Make copy of gameDLL's function tables for each plugin, so we don't
// risk the plugins screwing with the tables everyone uses.
- if (g_GameDLL.funcs.dllapi_table && !m_gamedll_funcs.dllapi_table) // TODO: check it
+ if (g_GameDLL.funcs.dllapi_table && !m_gamedll_funcs.dllapi_table)
{
m_gamedll_funcs.dllapi_table = (DLL_FUNCTIONS *)Q_malloc(sizeof(DLL_FUNCTIONS));
if (!m_gamedll_funcs.dllapi_table)
@@ -793,19 +946,18 @@ bool MPlugin::attach(PLUG_LOADTIME now)
}
if (g_GameDLL.funcs.newapi_table && !m_gamedll_funcs.newapi_table)
{
- m_gamedll_funcs.newapi_table = (NEW_DLL_FUNCTIONS *)Q_calloc(1, sizeof(meta_new_dll_functions_t));
+ m_gamedll_funcs.newapi_table = (NEW_DLL_FUNCTIONS *)Q_malloc(sizeof(NEW_DLL_FUNCTIONS));
if (!m_gamedll_funcs.newapi_table)
{
META_ERROR("dll: Failed attach plugin '%s': Failed malloc() for newapi_table");
return false;
}
- static_cast(m_gamedll_funcs.newapi_table)->set_from(g_GameDLL.funcs.newapi_table);
+ Q_memcpy(m_gamedll_funcs.newapi_table, g_GameDLL.funcs.newapi_table, sizeof(NEW_DLL_FUNCTIONS));
}
auto pfn_attach = (META_ATTACH_FN)m_sys_module.getsym("Meta_Attach");
if (!pfn_attach)
{
META_ERROR("dll: Failed attach plugin '%s': Couldn't find Meta_Attach(): %s", m_desc, "function not found");
- // caller will dlclose()
return false;
}
@@ -817,7 +969,6 @@ bool MPlugin::attach(PLUG_LOADTIME now)
if (ret != TRUE)
{
META_ERROR("dll: Failed attach plugin '%s': Error from Meta_Attach(): %d", m_desc, ret);
- // caller will dlclose()
return false;
}
@@ -853,121 +1004,17 @@ bool MPlugin::attach(PLUG_LOADTIME now)
return true;
}
-// Unload a plugin. Check time, detach.
-bool MPlugin::unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL_UNLOAD_REASON real_reason)
-{
- if (!check_input())
- {
- return false;
- }
- if (m_status < PL_RUNNING)
- {
- if (reason != PNL_CMD_FORCED && reason != PNL_RELOAD)
- {
- META_ERROR("dll: Not unloading plugin '%s'; already unloaded (status=%s)", m_desc, str_status());
- return false;
- }
- }
- if (m_action != PA_UNLOAD && m_action != PA_RELOAD)
- {
- META_WARNING("dll: Not unloading plugin '%s'; not marked for unload (action=%s)", m_desc, str_action());
- return false;
- }
-
- // Are we allowed to detach this plugin at this time?
- // If forcing unload, we disregard when plugin wants to be unloaded.
- if (m_info && m_info->unloadable < now)
- {
- if (reason == PNL_CMD_FORCED)
- {
- META_DEBUG(2, "dll: Forced unload plugin '%s' overriding allowed times: allowed=%s; now=%s", m_desc, str_unloadable(), str_loadtime(now, SL_SIMPLE));
- }
- else
- {
- if (m_info->unloadable > PT_STARTUP)
- {
- META_DEBUG(2, "dll: Delaying unload plugin '%s'; can't detach now: allowed=%s; now=%s", m_desc, str_unloadable(), str_loadtime(now, SL_SIMPLE));
- // caller should give message to user
- // try to unload again at next opportunity
- return false;
- }
-
- META_DEBUG(2, "dll: Failed unload plugin '%s'; can't detach now: allowed=%s; now=%s", m_desc, str_unloadable(), str_loadtime(now, SL_SIMPLE));
- // don't try to unload again later
- m_action = PA_NONE;
- return false;
- }
- }
-
- // If unloading during map, then I'd like to call plugin's
- // ServerDeactivate. However, I don't want to do this until I start
- // calling ServerActivate when loading during map, since the SDK
- // indicates these two routines should match call for call.
-
- // detach plugin
- if (!detach(now, reason))
- {
- if (reason == PNL_RELOAD)
- {
- META_DEBUG(2, "dll: Reload plugin '%s' overriding failed detach", m_desc);
- }
- else if (reason == PNL_CMD_FORCED)
- {
- META_DEBUG(2, "dll: Forced unload plugin '%s' overriding failed detach");
- }
- else
- {
- META_WARNING("dll: Failed to detach plugin '%s'; ", m_desc);
- return false;
- }
- }
-
- g_plugins->clear_source_plugin_index(m_index);
-
- // successful detach, or forced unload
-
- // Unmark registered commands for this plugin (by index number).
- g_regCmds->remove(m_index);
- // Unmark registered cvars for this plugin (by index number).
- g_regCvars->disable(m_index);
-
- // Close the file. Note: after this, attempts to reference any memory
- // locations in the file will produce a segfault.
- if (!m_sys_module.unload())
- {
- // If DLL cannot be closed, OS is badly broken or we are giving invalid handle.
- // So we don't return here but instead remove plugin from our listings.
- META_WARNING("dll: Couldn't close plugin file '%s': %s", m_file, "invalid handle");
- }
-
- if (m_action == PA_UNLOAD)
- {
- m_status = PL_EMPTY;
- clear();
- }
- else if (m_action == PA_RELOAD)
- {
- m_status = PL_VALID;
- m_action = PA_LOAD;
- clear();
- }
-
- META_LOG("dll: Unloaded plugin '%s' for reason '%s'", m_desc, str_reason(reason, real_reason));
- return true;
-}
-
// Inform plugin we're going to unload it.
bool MPlugin::detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
{
- META_DETACH_FN pfn_detach;
-
// If we have no handle, i.e. no dll loaded, we return true because the
// dll is obviously detached. We shouldn't call DLSYM() with a nullptr
// handle since this will DLSYM() ourself.
if (!m_sys_module.gethandle())
return true;
- if (!(pfn_detach = (META_DETACH_FN)m_sys_module.getsym("Meta_Detach")))
+ auto pfn_detach = (META_DETACH_FN)m_sys_module.getsym("Meta_Detach");
+ if (!pfn_detach)
{
META_ERROR("dll: Error detach plugin '%s': Couldn't find Meta_Detach(): %s", m_desc, "function not found");
// caller will dlclose()
@@ -985,157 +1032,6 @@ bool MPlugin::detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
return true;
}
-// Reload a plugin; unload and load again.
-bool MPlugin::reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
-{
- if (!check_input())
- {
- return false;
- }
- // Are we allowed to load this plugin at this time?
- // If we cannot load the plugin after unloading it, we keep it.
- if (m_info && m_info->loadable < now)
- {
- if (m_info->loadable > PT_STARTUP)
- {
- META_DEBUG(2, "dll: Delaying reload plugin '%s'; would not be able to reattach now: allowed=%s; now=%s", m_desc, str_loadable(), str_loadtime(now, SL_SIMPLE));
- // caller should give message to user
- // try to reload again at next opportunity
- return false;
- }
- else
- {
- META_DEBUG(2, "dll: Failed reload plugin '%s'; would not be able to reattach now: allowed=%s; now=%s", m_desc, str_loadable(), str_loadtime(now, SL_SIMPLE));
- // don't try to reload again later
- m_action = PA_NONE;
- return false;
- }
- }
-
- if (m_status < PL_RUNNING)
- {
- META_WARNING("dll: Plugin '%s' isn't running; Forcing unload plugin for reloading", m_desc);
- reason = PNL_RELOAD;
- }
-
- if (!unload(now, reason, reason))
- {
- META_WARNING("dll: Failed to unload plugin '%s' for reloading", m_desc);
- return false;
- }
-
- if (!load(now))
- {
- META_WARNING("dll: Failed to reload plugin '%s' after unloading", m_desc);
- return false;
- }
-
- return true;
-}
-
-// Pause a plugin; temporarily disabled for API routines.
-bool MPlugin::pause()
-{
- if (m_status == PL_PAUSED)
- {
- META_ERROR("Not pausing plugin '%s'; already paused", m_desc);
- return false;
- }
- if (m_status != PL_RUNNING)
- {
- META_ERROR("Cannot pause plugin '%s'; not currently running (status=%s)", m_desc, str_status());
- return false;
- }
-
- // are we allowed to pause this plugin?
- if (m_info->unloadable < PT_ANYPAUSE)
- {
- META_ERROR("Cannot pause plugin '%s'; not allowed by plugin (allowed=%s)", m_desc, str_unloadable());
- m_action = PA_NONE;
- return false;
- }
-
- m_status = PL_PAUSED;
- META_LOG("Paused plugin '%s'", m_desc);
- return true;
-}
-
-// Unpause a plugin.
-bool MPlugin::unpause()
-{
- if (m_status != PL_PAUSED)
- {
- META_ERROR("Cannot unpause plugin '%s'; not currently paused (status=%s)", m_desc, str_status());
- return false;
- }
-
- m_status = PL_RUNNING;
- META_LOG("Unpaused plugin '%s'", m_desc);
- return true;
-}
-
-// Retry pending action, presumably from a previous failure.
-bool MPlugin::retry(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
-{
- if (m_action == PA_LOAD)
- return load(now);
- if (m_action == PA_ATTACH)
- return load(now);
- if (m_action == PA_UNLOAD)
- return unload(now, reason, reason);
- if (m_action == PA_RELOAD)
- return reload(now, reason);
-
- META_ERROR("No pending action to retry for plugin '%s'; (status=%s, action=%s)", m_desc, str_status(), str_action());
- return false;
-}
-
-// Clear a plugin (it failed a previous action and should be
-// removed from the list, or it's being unloaded).
-bool MPlugin::clear()
-{
- if (m_status != PL_FAILED && m_status != PL_BADFILE && m_status != PL_EMPTY && m_status != PL_OPENED)
- {
- META_ERROR("Cannot clear plugin '%s'; not marked as failed, empty, or open (status=%s)", m_desc, str_status());
- return false;
- }
- // If file is open, close the file. Note: after this, attempts to
- // reference any memory locations in the file will produce a segfault.
- if (!m_sys_module.unload())
- {
- META_ERROR("dll: Couldn't close plugin file '%s': %s", m_file, "invalid handle");
- m_status = PL_FAILED;
- return false;
- }
-
- if (m_gamedll_funcs.dllapi_table) Q_free(m_gamedll_funcs.dllapi_table);
- if (m_gamedll_funcs.newapi_table) Q_free(m_gamedll_funcs.newapi_table);
- if (m_dllapi_table) Q_free(m_dllapi_table);
- if (m_dllapi_post_table) Q_free(m_dllapi_post_table);
- if (m_newapi_table) Q_free(m_newapi_table);
- if (m_newapi_post_table) Q_free(m_newapi_post_table);
- if (m_engine_table) Q_free(m_engine_table);
- if (m_engine_post_table) Q_free(m_engine_post_table);
-
- m_status = PL_EMPTY;
- m_action = PA_NULL;
- m_info = nullptr;
- m_time_loaded = 0;
- m_dllapi_table = nullptr;
- m_dllapi_post_table = nullptr;
- m_newapi_table = nullptr;
- m_newapi_post_table = nullptr;
- m_engine_table = nullptr;
- m_engine_post_table = nullptr;
- m_gamedll_funcs.dllapi_table = nullptr;
- m_gamedll_funcs.newapi_table = nullptr;
- m_source_plugin_index = 0;
- m_unloader_index = 0;
- m_is_unloader = false;
-
- return true;
-}
-
template
void show_table(const char* table_name, table_t* table, info_t* info_begin, bool post)
{
@@ -1218,7 +1114,7 @@ bool MPlugin::newer_file() const
return false;
}
- time_t file_time = st.st_ctime > st.st_mtime ? st.st_ctime : st.st_mtime;
+ time_t file_time = max(st.st_ctime, st.st_mtime);
META_DEBUG(5, "newer_file? file=%s; load=%d, file=%d; ctime=%d, mtime=%d", m_file, m_time_loaded, file_time, st.st_ctime, st.st_mtime);
if (file_time > m_time_loaded)
return true;
@@ -1231,32 +1127,16 @@ bool MPlugin::newer_file() const
// SHOW is max 4 chars, for "show" output.
const char *MPlugin::str_status(STR_STATUS fmt) const
{
- switch (m_status)
- {
- case PL_EMPTY:
- if (fmt == ST_SHOW) return "empt";
- else return "empty";
- case PL_VALID:
- if (fmt == ST_SHOW) return "info";
- else return "valid";
- case PL_BADFILE:
- if (fmt == ST_SHOW) return "badf";
- else return "badfile";
- case PL_OPENED:
- if (fmt == ST_SHOW) return "open";
- else return "opened";
- case PL_FAILED:
- if (fmt == ST_SHOW) return "fail";
- else return "failed";
- case PL_RUNNING:
- if (fmt == ST_SHOW) return "RUN";
- else return "running";
- case PL_PAUSED:
- if (fmt == ST_SHOW) return "PAUS";
- else return "paused";
- default:
- if (fmt == ST_SHOW) return UTIL_VarArgs("UNK%d", m_status);
- return UTIL_VarArgs("unknown (%d)", m_status);
+ bool show = fmt == ST_SHOW;
+ switch (m_status) {
+ case PL_EMPTY: return show ? "empt" : "empty";
+ case PL_VALID: return show ? "info" : "valid";
+ case PL_BADFILE: return show ? "badf" : "badfile";
+ case PL_OPENED: return show ? "open" : "opened";
+ case PL_FAILED: return show ? "fail" : "failed";
+ case PL_RUNNING: return show ? "RUN" : "running";
+ case PL_PAUSED: return show ? "PAUS" : "paused";
+ default: return UTIL_VarArgs(show ? "UNK%d" : "unknown (%d)", m_status);
}
}
@@ -1265,32 +1145,48 @@ const char *MPlugin::str_status(STR_STATUS fmt) const
// SHOW is max 4 chars, for "show" output.
const char *MPlugin::str_action(STR_ACTION fmt) const
{
+ bool show = fmt == ST_SHOW;
switch (m_action)
{
- case PA_NULL:
- if (fmt == SA_SHOW) return "nullptr";
- else return "nullptr";
- case PA_NONE:
- if (fmt == SA_SHOW) return " - ";
- else return "none";
- case PA_KEEP:
- if (fmt == SA_SHOW) return "keep";
- else return "keep";
- case PA_LOAD:
- if (fmt == SA_SHOW) return "load";
- else return "load";
- case PA_ATTACH:
- if (fmt == SA_SHOW) return "atch";
- else return "attach";
- case PA_UNLOAD:
- if (fmt == SA_SHOW) return "unld";
- else return "unload";
- case PA_RELOAD:
- if (fmt == SA_SHOW) return "relo";
- else return "reload";
- default:
- if (fmt == SA_SHOW) return UTIL_VarArgs("UNK%d", m_action);
- else return UTIL_VarArgs("unknown (%d)", m_action);
+ case PA_NULL: return "null";
+ case PA_NONE: return show ? " - " : "none";
+ case PA_KEEP: return "keep";
+ case PA_LOAD: return "load";
+ case PA_ATTACH: return show ? "atch" : "attach";
+ case PA_UNLOAD: return show ? "unld" : "unload";
+ case PA_RELOAD: return show ? "relo" : "reload";
+ default: return UTIL_VarArgs(show ? "UNK%d" : "unknown (%d)", m_action);
+ }
+}
+
+// Return a string describing how the plugin was loaded.
+const char *MPlugin::str_source(STR_SOURCE fmt) const
+{
+ bool show = fmt == SO_SHOW;
+ switch (m_source) {
+ case PS_INI: return show ? "ini" : "ini file";
+ case PS_CMD: return show ? "cmd" : "console command";
+ case PS_PLUGIN:
+ if (m_source_plugin_index <= 0)
+ return show ? "plUN" : "unloaded plugin";
+ return show ? UTIL_VarArgs("pl%d", m_source_plugin_index) : UTIL_VarArgs("plugin [%s]", g_plugins->find(m_source_plugin_index)->description());
+ default: return UTIL_VarArgs(show ? "UNK%d" : "unknown (%d)", m_source);
+ }
+}
+
+// Return a string describing why a plugin is to be unloaded.
+const char *MPlugin::str_reason(PL_UNLOAD_REASON reason) const
+{
+ switch (reason) {
+ case PNL_NULL: return "null";
+ case PNL_INI_DELETED: return "deleted from ini file";
+ case PNL_FILE_NEWER: return "file on disk is newer";
+ case PNL_COMMAND: return "server command";
+ case PNL_CMD_FORCED: return "forced by server command";
+ case PNL_PLUGIN: return UTIL_VarArgs("%s (request from plugin[%d])", str_reason(PNL_NULL), m_unloader_index);
+ case PNL_PLG_FORCED: return UTIL_VarArgs("%s (forced request from plugin[%d])", str_reason(PNL_NULL), m_unloader_index);
+ case PNL_RELOAD: return "reloading";
+ default: return UTIL_VarArgs("unknown (%d)", reason);
}
}
@@ -1301,91 +1197,88 @@ const char *MPlugin::str_action(STR_ACTION fmt) const
// NOW is to describe current situation of load/unload attempt.
const char *MPlugin::str_loadtime(PLUG_LOADTIME ptime, STR_LOADTIME fmt)
{
- static const char *rPrintLoadTime[][26] = {
- // SL_SIMPLE // SL_SHOW // SL_ALLOWED // SL_NOW
- { "never", "Never", "never", "never" }, // PT_NEVER
- { "startup", "Start", "at server startup", "during server startup" }, // PT_STARTUP
- { "changelevel","Chlvl", "at changelevel", "during changelevel" }, // PT_CHANGELEVEL
- { "anytime", "ANY", "at any time", "during map" }, // PT_ANYTIME
- { "pausable", "Pause", "at any time, and pausable", "for requested pause" }, // PT_ANYPAUSE
- };
-
if (ptime >= PT_NEVER || ptime <= PT_ANYPAUSE)
- return rPrintLoadTime[ptime][fmt];
+ return s_rPrintLoadTime[ptime][fmt];
- if (fmt == SL_SHOW)
- return UTIL_VarArgs("UNK-%d", ptime);
-
- return UTIL_VarArgs("unknown (%d)", ptime);
+ return UTIL_VarArgs((fmt == SL_SHOW) ? "UNK-%i" : "unknown (%i)", ptime);
}
-// Return a string describing why a plugin is to be unloaded.
-const char *MPlugin::str_reason(PL_UNLOAD_REASON preason, PL_UNLOAD_REASON preal_reason) const
+const char* MPlugin::str_loadable() const
{
- char buf[128];
-
- if (preason == PNL_PLUGIN)
- preason = PNL_NULL;
- else if (preason == PNL_PLG_FORCED)
- preason = PNL_NULL;
-
- switch (preal_reason)
- {
- case PNL_NULL:
- return "null";
- case PNL_INI_DELETED:
- return "deleted from ini file";
- case PNL_FILE_NEWER:
- return "file on disk is newer";
- case PNL_COMMAND:
- return "server command";
- case PNL_CMD_FORCED:
- return "forced by server command";
- case PNL_PLUGIN:
- {
- Q_strncpy(buf, str_reason(PNL_NULL, preason), sizeof buf - 1);
- buf[sizeof buf - 1] = '\0';
-
- return UTIL_VarArgs("%s (request from plugin[%d])", buf, m_unloader_index);
- }
- case PNL_PLG_FORCED:
- {
- Q_strncpy(buf, str_reason(PNL_NULL, preason), sizeof buf - 1);
- buf[sizeof buf - 1] = '\0';
-
- return UTIL_VarArgs("%s (forced request from plugin[%d])", buf, m_unloader_index);
- }
- case PNL_RELOAD:
- return "reloading";
- default:
- return UTIL_VarArgs("unknown (%d)", preal_reason);
- }
+ return m_info ? str_loadtime(m_info->loadable, SL_SIMPLE) : " -";
}
-// Return a string describing how the plugin was loaded.
-const char *MPlugin::str_source(STR_SOURCE fmt) const
+const char* MPlugin::str_unloadable() const
{
- switch (m_source)
- {
- case PS_INI:
- if (fmt == SO_SHOW) return "ini";
- else return "ini file";
- case PS_CMD:
- if (fmt == SO_SHOW) return "cmd";
- else return "console command";
- case PS_PLUGIN:
- if (m_source_plugin_index <= 0)
- {
- if (fmt == SO_SHOW) return "plUN";
- else return "unloaded plugin";
- }
- else
- {
- if (fmt == SO_SHOW) return UTIL_VarArgs("pl%d", m_source_plugin_index);
- else return UTIL_VarArgs("plugin [%s]", g_plugins->find(m_source_plugin_index)->m_desc);
- }
- default:
- if (fmt == SO_SHOW) return UTIL_VarArgs("UNK%d", m_source);
- else return UTIL_VarArgs("unknown (%d)", m_source);
- }
+ return m_info ? str_loadtime(m_info->unloadable, SL_SIMPLE) : " -";
+}
+
+const char* MPlugin::str_loadable(STR_LOADTIME fmt) const
+{
+ return m_info ? str_loadtime(m_info->loadable, fmt) : " -";
+}
+
+const char* MPlugin::str_unloadable(STR_LOADTIME fmt) const
+{
+ return m_info ? str_loadtime(m_info->unloadable, fmt) : " -";
+}
+
+PLUG_STATUS MPlugin::status() const
+{
+ return m_status;
+}
+
+PLUG_ACTION MPlugin::action() const
+{
+ return m_action;
+}
+
+const char* MPlugin::description() const
+{
+ return m_desc;
+}
+
+plugin_info_t* MPlugin::info() const
+{
+ return m_info;
+}
+
+int MPlugin::index() const
+{
+ return m_index;
+}
+
+int MPlugin::source_index() const
+{
+ return m_source_plugin_index;
+}
+
+const char* MPlugin::file() const
+{
+ return m_file;
+}
+
+const char* MPlugin::filename() const
+{
+ return m_filename;
+}
+
+const char* MPlugin::pathname() const
+{
+ return m_pathname;
+}
+
+const CSysModule& MPlugin::sys_module() const
+{
+ return m_sys_module;
+}
+
+size_t MPlugin::status_ptr()
+{
+ return size_t(&m_status);
+}
+
+void MPlugin::set_action(PLUG_ACTION action)
+{
+ m_action = action;
}
diff --git a/metamod/src/mplugin.h b/metamod/src/mplugin.h
index 9573ae9..075090b 100644
--- a/metamod/src/mplugin.h
+++ b/metamod/src/mplugin.h
@@ -1,13 +1,12 @@
#pragma once
-#include "api_info.h"
-#include "support_meta.h"
+#include "utils.h"
// Flags to indicate current "load" state of plugin.
// NOTE: order is important, as greater/less comparisons are made.
enum PLUG_STATUS : uint8
{
- PL_EMPTY = 0, // empty slot
+ PL_EMPTY, // empty slot
PL_VALID, // has valid info in it
PL_BADFILE, // nonexistent file (open failed), or not a valid plugin file (query failed)
PL_OPENED, // dlopened and queried
@@ -19,7 +18,7 @@ enum PLUG_STATUS : uint8
// Action to take for plugin at next opportunity.
enum PLUG_ACTION : uint8
{
- PA_NULL = 0,
+ PA_NULL,
PA_NONE, // no action needed right now
PA_KEEP, // keep, after ini refresh
PA_LOAD, // load (dlopen, query) and try to attach
@@ -31,7 +30,7 @@ enum PLUG_ACTION : uint8
// Flags to indicate from where the plugin was loaded.
enum PLOAD_SOURCE : uint8
{
- PS_INI = 0, // was loaded from the plugins.ini
+ PS_INI, // was loaded from the plugins.ini
PS_CMD, // was loaded via a server command
PS_PLUGIN, // was loaded by other plugin
};
@@ -48,68 +47,50 @@ enum STR_LOADTIME : uint8
// Flags for how to format description of status.
enum STR_STATUS : uint8
{
- ST_SIMPLE = 0, // single word
+ ST_SIMPLE, // single word
ST_SHOW, // for "show" output, 4 chars
};
// Flags for how to format description of action.
enum STR_ACTION : uint8
{
- SA_SIMPLE = 0, // single word
+ SA_SIMPLE, // single word
SA_SHOW, // for "show" output, 4 chars
};
// Flags for how to format description of source.
enum STR_SOURCE : uint8
{
- SO_SIMPLE = 0, // two words
+ SO_SIMPLE, // two words
SO_SHOW, // for "list" output, 3 chars
};
+enum STR_PLATFORM : uint8
+{
+ SP_WINDOWS,
+ SP_LINUX
+};
+
// An individual plugin.
-class MPlugin {
+class MPlugin
+{
public:
- PLUG_STATUS m_status; // current status of plugin (loaded, etc)
- PLUG_ACTION m_action; // what to do with plugin (load, unload, etc)
- PLOAD_SOURCE m_source; // source of the request to load the plugin
- int m_index; // 1-based
- plugin_info_t *m_info; // information plugin provides about itself
- CSysModule m_sys_module;
- time_t m_time_loaded; // when plugin was loaded
- int m_source_plugin_index; // who loaded this plugin
- int m_unloader_index;
- bool m_is_unloader; // fix to prevent other plugins unload active unloader.
+ MPlugin();
+ MPlugin(int index);
- DLL_FUNCTIONS *m_dllapi_table;
- DLL_FUNCTIONS *m_dllapi_post_table;
- NEW_DLL_FUNCTIONS *m_newapi_table;
- NEW_DLL_FUNCTIONS *m_newapi_post_table;
- enginefuncs_t *m_engine_table;
- enginefuncs_t *m_engine_post_table;
-
- gamedll_funcs_t m_gamedll_funcs;
- mutil_funcs_t m_mutil_funcs;
-
- char m_filename[PATH_MAX]; // ie "dlls/mm_test_i386.so", from inifile
- char *m_file; // ie "mm_test_i386.so", ptr from filename
- char m_desc[MAX_DESC_LEN]; // ie "Test metamod plugin", from inifile
- char m_pathname[PATH_MAX]; // UNIQUE, ie "/home/willday/half-life/cstrike/dlls/mm_test_i386.so", built with GameDLL.gamedir
- int m_pfspecific; // level of specific platform affinity, used during load time
-
- bool ini_parseline(char *line); // parse line from inifile
- bool cmd_parseline(const char *line); // parse from console command
+ bool ini_parseline(char *line); // parse line from .ini file
+ bool cmd_parseline(const char *line); // parse from console command
bool plugin_parseline(const char *fname, int loader_index); // parse from plugin
- bool check_input();
+ bool check_input(); // check filename, path, status
- bool resolve(); // find a matching file on disk
- char *resolve_dirs(char *path) const;
- char *resolve_prefix(char *path) const;
- char *resolve_suffix(char *path) const;
+ bool resolve(); // find a matching file on disk
+ char *resolve_dirs(const char *path, char *tempbuf, size_t bufsize) const; // try resolve filename in different dirs
+ char *resolve_suffix(const char *path, char *tempbuf, size_t bufsize) const; // try resolve given filename with different suffixes
- bool platform_match(MPlugin* plugin) const;
+ bool platform_match(MPlugin* plugin) const; // check if a given plugin is the same but possibly for a different platform
- bool load(PLUG_LOADTIME now);
- bool unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL_UNLOAD_REASON real_reason);
+ bool load(PLUG_LOADTIME now); // load parsed plugin
+ bool unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason);
bool reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason);
bool pause();
bool unpause();
@@ -120,36 +101,66 @@ public:
bool newer_file() const; // check for newer file on disk
- const char *str_status(STR_STATUS fmt) const;
- const char *str_action(STR_ACTION fmt) const;
- const char *str_source(STR_SOURCE fmt) const;
-
- const char *str_reason(PL_UNLOAD_REASON preason, PL_UNLOAD_REASON preal_reason) const;
+ const char *str_status(STR_STATUS fmt = ST_SIMPLE) const;
+ const char *str_action(STR_ACTION fmt = SA_SIMPLE) const;
+ const char *str_source(STR_SOURCE fmt = SO_SIMPLE) const;
+ const char *str_reason(PL_UNLOAD_REASON reason) const;
static const char *str_loadtime(PLUG_LOADTIME pallow, STR_LOADTIME fmt);
- const char *str_status() { return str_status(ST_SIMPLE); };
- const char *str_action() { return str_action(SA_SIMPLE); };
- const char *str_source() { return str_source(SO_SIMPLE); };
+ const char* str_loadable() const;
+ const char* str_unloadable() const;
+ const char* str_loadable(STR_LOADTIME fmt) const;
+ const char* str_unloadable(STR_LOADTIME fmt) const;
- const char *str_loadable() {
- if (m_info) return str_loadtime(m_info->loadable, SL_SIMPLE);
- else return " -";
- };
- const char *str_unloadable() {
- if (m_info) return str_loadtime(m_info->unloadable, SL_SIMPLE);
- else return " -";
- };
- const char *str_loadable(STR_LOADTIME fmt) {
- if (m_info) return str_loadtime(m_info->loadable, fmt);
- else return " -";
- };
- const char *str_unloadable(STR_LOADTIME fmt) {
- if (m_info) return str_loadtime(m_info->unloadable, fmt);
- else return " -";
- };
+ PLUG_STATUS status() const;
+ PLUG_ACTION action() const;
+ const char* description() const;
+ plugin_info_t* info() const;
+ int index() const;
+ int source_index() const;
+ const char* file() const;
+ const char* filename() const;
+ const char* pathname() const;
+ const CSysModule& sys_module() const;
+ size_t status_ptr();
+ void set_action(PLUG_ACTION action);
private:
- bool query();
- bool attach(PLUG_LOADTIME now);
- bool detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason);
+ bool query(); // check exports, call init, getfnptrs and query
+ bool attach(PLUG_LOADTIME now); // call attach
+ bool detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason); // call detach
+
+ PLUG_STATUS m_status; // current status of plugin (loaded, etc)
+ PLUG_ACTION m_action; // what to do with plugin (load, unload, etc)
+ PLOAD_SOURCE m_source; // source of the request to load the plugin
+ STR_PLATFORM m_platform; // plugin platform
+ int m_index; // 1-based
+ plugin_info_t *m_info; // information plugin provides about itself
+ CSysModule m_sys_module; // system module
+ time_t m_time_loaded; // when plugin was loaded
+ int m_source_plugin_index; // who loaded this plugin
+ int m_unloader_index; // index of unloader plugin
+ bool m_is_unloader; // fix to prevent other plugins unload active unloader.
+
+public:
+ // pointers to tables inside plugins
+ DLL_FUNCTIONS *m_dllapi_table;
+ DLL_FUNCTIONS *m_dllapi_post_table;
+ NEW_DLL_FUNCTIONS *m_newapi_table;
+ NEW_DLL_FUNCTIONS *m_newapi_post_table;
+ enginefuncs_t *m_engine_table;
+ enginefuncs_t *m_engine_post_table;
+
+private:
+ gamedll_funcs_t m_gamedll_funcs;
+ mutil_funcs_t m_mutil_funcs;
+
+ char m_filename[PATH_MAX]; // ie "dlls/mm_test_i386.so", from inifile
+ char *m_file; // ie "mm_test_i386.so", ptr from filename
+ char m_desc[MAX_DESC_LEN]; // ie "Test metamod plugin", from inifile
+ char m_pathname[PATH_MAX]; // UNIQUE, ie "/home/willday/half-life/cstrike/dlls/mm_test_i386.so", built with GameDLL.gamedir
+
+ static const char *s_rPrintLoadTime[][4];
+
+ friend class MPluginList;
};
diff --git a/metamod/src/mreg.cpp b/metamod/src/mreg.cpp
index 4a9f423..db53082 100644
--- a/metamod/src/mreg.cpp
+++ b/metamod/src/mreg.cpp
@@ -1,6 +1,6 @@
#include "precompiled.h"
-MRegCmd::MRegCmd(char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin) : m_pfunction(cmd_handler), m_plugid(cmd_plugin->m_index), m_status(RG_VALID)
+MRegCmd::MRegCmd(char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin) : m_pfunction(cmd_handler), m_plugid(cmd_plugin->index()), m_status(RG_VALID)
{
m_name = Q_strdup(cmd_name);
}
@@ -112,7 +112,7 @@ void MRegCmdList::show() const
{
auto iplug = g_plugins->find(reg->m_plugid);
- Q_strncpy(bplug, iplug ? iplug->m_desc : "(unknown)", sizeof bplug - 1);
+ Q_strncpy(bplug, iplug ? iplug->description() : "(unknown)", sizeof bplug - 1);
bplug[sizeof bplug - 1] = '\0';
}
else
@@ -149,7 +149,7 @@ void MRegCmdList::show(int plugin_id) const
META_CONS("%d commands", total_count);
}
-MRegCvar::MRegCvar(cvar_t* cv_ptr, MPlugin* cv_plugin) : m_cvar(cv_ptr), m_plugid(cv_plugin ? cv_plugin->m_index : 0), m_status(RG_VALID)
+MRegCvar::MRegCvar(cvar_t* cv_ptr, MPlugin* cv_plugin) : m_cvar(cv_ptr), m_plugid(cv_plugin ? cv_plugin->index() : 0), m_status(RG_VALID)
{
m_cvar = new cvar_t;
m_cvar->name = Q_strdup(cv_ptr->name);
@@ -228,7 +228,7 @@ void MRegCvarList::show() const
if (reg->m_status == RG_VALID)
{
auto plug = g_plugins->find(reg->m_plugid);
- Q_strncpy(bplug, plug ? plug->m_desc : "(unknown)", sizeof bplug - 1);
+ Q_strncpy(bplug, plug ? plug->description() : "(unknown)", sizeof bplug - 1);
bplug[sizeof bplug - 1] = '\0';
}
else
diff --git a/metamod/src/mutil.cpp b/metamod/src/mutil.cpp
index 5e2851a..3284afb 100644
--- a/metamod/src/mutil.cpp
+++ b/metamod/src/mutil.cpp
@@ -252,7 +252,7 @@ const char* EXT_FUNC mutil_GetPluginPath(plid_t plid)
return nullptr;
}
- Q_strncpy(buf, plug->m_pathname, sizeof buf - 1);
+ Q_strncpy(buf, plug->pathname(), sizeof buf - 1);
buf[sizeof buf - 1] = '\0';
return buf;
}
@@ -301,7 +301,6 @@ int EXT_FUNC mutil_LoadMetaPlugin(plid_t plid, const char* fname, PLUG_LOADTIME
}
auto pl_loaded = g_plugins->plugin_addload(plid, fname, now);
-
if (!pl_loaded)
{
if (plugin_handle)
@@ -309,13 +308,13 @@ int EXT_FUNC mutil_LoadMetaPlugin(plid_t plid, const char* fname, PLUG_LOADTIME
return 1; // TODO: WTF
}
- else
- {
- if (plugin_handle)
- *plugin_handle = (void *)pl_loaded->m_sys_module.gethandle();
- return 0;
- }
+ meta_rebuild_callbacks();
+
+ if (plugin_handle)
+ *plugin_handle = (void *)pl_loaded->sys_module().gethandle();
+
+ return 0;
}
int EXT_FUNC mutil_UnloadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
@@ -339,8 +338,10 @@ int EXT_FUNC mutil_UnloadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIM
if (!findp || !unique)
return 1;
- if (findp->plugin_unload(plid, now, reason))
+ if (findp->plugin_unload(plid, now, reason)) {
+ meta_rebuild_callbacks();
return 0;
+ }
return 1;
}
@@ -357,8 +358,10 @@ int EXT_FUNC mutil_UnloadMetaPluginByHandle(plid_t plid, void *plugin_handle, PL
if (!findp)
return 1;
- if (findp->plugin_unload(plid, now, reason))
+ if (findp->plugin_unload(plid, now, reason)) {
+ meta_rebuild_callbacks();
return 0;
+ }
return 1;
}
diff --git a/metamod/src/osdep.cpp b/metamod/src/osdep.cpp
index e501070..d825d8f 100644
--- a/metamod/src/osdep.cpp
+++ b/metamod/src/osdep.cpp
@@ -7,12 +7,14 @@ CSysModule::CSysModule() : m_handle(0), m_base(0), m_size(0)
#ifdef _WIN32
module_handle_t CSysModule::load(const char* filepath)
{
- m_handle = LoadLibrary(filepath);
+ if (!m_handle) {
+ m_handle = LoadLibrary(filepath);
- MODULEINFO module_info;
- if (GetModuleInformation(GetCurrentProcess(), m_handle, &module_info, sizeof module_info)) {
- m_base = (uintptr_t)module_info.lpBaseOfDll;
- m_size = module_info.SizeOfImage;
+ MODULEINFO module_info;
+ if (GetModuleInformation(GetCurrentProcess(), m_handle, &module_info, sizeof module_info)) {
+ m_base = (uintptr_t)module_info.lpBaseOfDll;
+ m_size = module_info.SizeOfImage;
+ }
}
return m_handle;
@@ -20,7 +22,7 @@ module_handle_t CSysModule::load(const char* filepath)
bool CSysModule::unload()
{
- bool ret = false;
+ bool ret = true;
if (m_handle) {
ret = FreeLibrary(m_handle) != ERROR;
@@ -34,7 +36,7 @@ bool CSysModule::unload()
void* CSysModule::getsym(const char* name) const
{
- return GetProcAddress(m_handle, name);
+ return m_handle ? GetProcAddress(m_handle, name) : nullptr;
}
#else
static ElfW(Addr) dlsize(void* base)
@@ -59,35 +61,38 @@ static ElfW(Addr) dlsize(void* base)
module_handle_t CSysModule::load(const char* filepath)
{
- m_handle = dlopen(filepath, RTLD_NOW);
+ if (!m_handle) {
+ m_handle = dlopen(filepath, RTLD_NOW);
- char buf[1024], dummy[1024], path[260];
- sprintf(buf, "/proc/%i/maps", getpid());
+ char buf[1024], dummy[1024], path[260];
+ sprintf(buf, "/proc/%i/maps", getpid());
- FILE* fp = fopen(buf, "r");
+ FILE* fp = fopen(buf, "r");
- while (fgets(buf, sizeof buf, fp)) {
- uintptr_t start, end;
+ while (fgets(buf, sizeof buf, fp)) {
+ uintptr_t start, end;
- int args = sscanf(buf, "%x-%x %128s %128s %128s %128s %255s", &start, &end, dummy, dummy, dummy, dummy, path);
- if (args != 7) {
- continue;
+ int args = sscanf(buf, "%x-%x %128s %128s %128s %128s %255s", &start, &end, dummy, dummy, dummy, dummy, path);
+ if (args != 7) {
+ continue;
+ }
+
+ if (!Q_stricmp(path, filepath)) {
+ m_base = start;
+ m_size = end - start;
+ break;
+ }
}
- if (!Q_stricmp(path, filepath)) {
- m_base = start;
- m_size = end - start;
- break;
- }
+ fclose(fp);
}
- fclose(fp);
return m_handle;
}
bool CSysModule::unload()
{
- bool ret = false;
+ bool ret = true;
if (m_handle) {
ret = dlclose(m_handle) != 0;
@@ -101,7 +106,7 @@ bool CSysModule::unload()
void* CSysModule::getsym(const char* name) const
{
- return dlsym(m_handle, name);
+ return m_handle ? dlsym(m_handle, name) : nullptr;
}
#endif
@@ -130,7 +135,7 @@ const char* CSysModule::getloaderror()
// http://msdn.microsoft.com/library/en-us/debug/errors_0sdh.asp
// except without FORMAT_MESSAGE_ALLOCATE_BUFFER, since we use a local
// static buffer.
-const char *str_GetLastError()
+static const char *str_GetLastError()
{
static char buf[MAX_STRBUF_LEN];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, MAX_STRBUF_LEN - 1, nullptr);
diff --git a/metamod/src/plinfo.h b/metamod/src/plinfo.h
index 9d40002..876429e 100644
--- a/metamod/src/plinfo.h
+++ b/metamod/src/plinfo.h
@@ -4,7 +4,7 @@
// NOTE: order is crucial, as greater/less comparisons are made.
enum PLUG_LOADTIME
{
- PT_NEVER = 0,
+ PT_NEVER,
PT_STARTUP, // should only be loaded/unloaded at initial hlds execution
PT_CHANGELEVEL, // can be loaded/unloaded between maps
PT_ANYTIME, // can be loaded/unloaded at any time
@@ -14,7 +14,7 @@ enum PLUG_LOADTIME
// Flags to indicate why the plugin is being unloaded.
enum PL_UNLOAD_REASON
{
- PNL_NULL = 0,
+ PNL_NULL,
PNL_INI_DELETED, // was deleted from plugins.ini
PNL_FILE_NEWER, // file on disk is newer than last load
PNL_COMMAND, // requested by server/console command
diff --git a/metamod/src/precompiled.h b/metamod/src/precompiled.h
index 4282e40..45a2602 100644
--- a/metamod/src/precompiled.h
+++ b/metamod/src/precompiled.h
@@ -31,11 +31,9 @@
#include "metamod.h"
#include "log_meta.h"
#include "conf_meta.h"
-#include "support_meta.h"
#include "dllapi.h"
#include "engine_api.h"
#include "game_support.h"
-#include "meta_eiface.h"
#include "mreg.h"
#include "meta_api.h"
#include "mutil.h"
diff --git a/metamod/src/reg_support.cpp b/metamod/src/reg_support.cpp
index 60ec7f2..bef7b25 100644
--- a/metamod/src/reg_support.cpp
+++ b/metamod/src/reg_support.cpp
@@ -30,7 +30,7 @@ void EXT_FUNC meta_AddServerCommand(char *cmd_name, void (*function)())
{
MPlugin *plug = g_plugins->find_memloc(function);
- META_DEBUG(4, "called: meta_AddServerCommand; cmd_name=%s, function=%d, plugin=%s", cmd_name, function, plug ? plug->m_file : "unknown");
+ META_DEBUG(4, "called: meta_AddServerCommand; cmd_name=%s, function=%d, plugin=%s", cmd_name, function, plug ? plug->file() : "unknown");
if (!plug) {
META_ERROR("Failed to find memloc for regcmd '%s'", cmd_name);
diff --git a/metamod/src/sdk_util.cpp b/metamod/src/sdk_util.cpp
index 245e9be..5a979c9 100644
--- a/metamod/src/sdk_util.cpp
+++ b/metamod/src/sdk_util.cpp
@@ -1,6 +1,6 @@
#include "precompiled.h"
-char *UTIL_VarArgs(char *format, ...)
+char *UTIL_VarArgs(const char *format, ...)
{
va_list argptr;
static char string[1024];
diff --git a/metamod/src/sdk_util.h b/metamod/src/sdk_util.h
index 0584c41..5141fe2 100644
--- a/metamod/src/sdk_util.h
+++ b/metamod/src/sdk_util.h
@@ -13,4 +13,5 @@
#include "enginecallbacks.h"
#include
+char *UTIL_VarArgs(const char *format, ...);
void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage);
diff --git a/metamod/src/support_meta.cpp b/metamod/src/support_meta.cpp
deleted file mode 100644
index e88d68b..0000000
--- a/metamod/src/support_meta.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-#include "precompiled.h"
-
-void __declspec(noreturn) do_exit(int exitval)
-{
- //Allahu Akbar!!
- *((int *)nullptr) = 0;
-}
-
-// Checks for a non-empty file, relative to the gamedir if necessary.
-// Formerly used LOAD_FILE_FOR_ME, which provided a simple way to check for
-// a file under the gamedir, but which would _also_ look in the sibling
-// "valve" directory, thus sometimes finding files that weren't desired.
-// Also, formerly named just "valid_file".
-//
-// Special-case-recognize "/dev/null" as a valid file.
-bool FileExistsInGameDir(const char *path)
-{
- struct stat st;
- char buf[PATH_MAX];
-
- if (!path)
- return false;
-
- if (!Q_strcmp(path, "/dev/null"))
- return true;
-
- if (IsAbsolutePath(path))
- {
- Q_strncpy(buf, path, sizeof buf);
- buf[sizeof buf - 1] = '\0';
- }
- else
- snprintf(buf, sizeof buf, "%s/%s", g_GameDLL.gamedir, path);
-
- int ret = stat(buf, &st);
- if (ret != 0)
- {
- META_DEBUG(5, "Unable to stat '%s': %s", buf, strerror(errno));
- return false;
- }
-
- int reg = S_ISREG(st.st_mode);
- if (!reg)
- {
- META_DEBUG(5, "Not a regular file: %s", buf);
- return false;
- }
-
- if (!st.st_size)
- {
- META_DEBUG(5, "Empty file: %s", buf);
- return false;
- }
-
- if (ret == 0 && reg)
- return true;
-
- return false;
-}
-
-// Turns path into a full path:
-// - if not absolute, prepends gamedir
-// - calls realpath() to collapse ".." and such
-// - calls NormalizePath() to fix backslashes, etc
-//
-// Much like realpath, buffer pointed to by fullpath is assumed to be
-// able to store a string of PATH_MAX length.
-char* full_gamedir_path(const char* path, char* fullpath)
-{
- char buf[PATH_MAX];
-
- // Build pathname from filename, plus gamedir if relative path.
- if (IsAbsolutePath(path))
- {
- Q_strncpy(buf, path, sizeof buf - 1);
- buf[sizeof buf - 1] = '\0';
- }
- else snprintf(buf, sizeof buf, "%s/%s", g_GameDLL.gamedir, path);
-
- // Remove relative path components, if possible.
- if (!realpath(buf, fullpath))
- {
- META_DEBUG(4, "Unable to get realpath for '%s': %s", buf, str_os_error());
- Q_strncpy(fullpath, path, sizeof fullpath - 1);
- fullpath[sizeof fullpath - 1] = '\0';
- }
-
- // Replace backslashes, etc.
- NormalizePath(fullpath);
- return fullpath;
-}
diff --git a/metamod/src/support_meta.h b/metamod/src/support_meta.h
deleted file mode 100644
index 8242794..0000000
--- a/metamod/src/support_meta.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-#include // stat
-#include // stat
-
-#include "osdep.h" // _stricmp, S_ISREG,
-
-void __declspec(noreturn) do_exit(int exitval);
-
-bool FileExistsInGameDir(const char *path);
-char *full_gamedir_path(const char *path, char *fullpath);
-
-// Turn a variable/function name into the corresponding string, optionally
-// stripping off the leading "len" characters. Useful for things like
-// turning 'pfnClientCommand' into "ClientCommand" so we don't have to
-// specify strings used for all the debugging/log messages.
-#define STRINGIZE(name, len) #name+len
-
-// Max description length for plugins.ini and other places.
-#define MAX_DESC_LEN 256
-
-// For various character string buffers.
-#define MAX_STRBUF_LEN 1024
diff --git a/metamod/src/utils.cpp b/metamod/src/utils.cpp
index 7044ad4..c537a58 100644
--- a/metamod/src/utils.cpp
+++ b/metamod/src/utils.cpp
@@ -1,5 +1,13 @@
#include "precompiled.h"
+const char* g_platform_postfixes[4] =
+{
+ "_i386.so",
+ "_i486.so",
+ "_i586.so",
+ "_i686.so",
+};
+
bool is_yes(const char* str)
{
return !Q_strcmp(str, "true") || !Q_strcmp(str, "yes") || !Q_strcmp(str, "1");
@@ -119,7 +127,7 @@ char *trimbuf(char *str)
return str;
}
-void NormalizePath(char *path)
+void normalize_path(char *path)
{
#ifdef _WIN32
for (char* cp = path; *cp; cp++)
@@ -133,7 +141,7 @@ void NormalizePath(char *path)
#endif
}
-bool IsAbsolutePath(const char *path)
+bool is_abs_path(const char *path)
{
if (path[0] == '/') return true;
#ifdef _WIN32
@@ -143,6 +151,23 @@ bool IsAbsolutePath(const char *path)
return false;
}
+bool is_valid_path(const char *path)
+{
+ struct stat st;
+ return !stat(path, &st) && S_ISREG(st.st_mode);
+}
+
+bool is_platform_postfix(const char* pf)
+{
+ if (pf) {
+ for (size_t i = 0; i < arraysize(g_platform_postfixes); i++) {
+ if (!Q_strcmp(pf, g_platform_postfixes[i]))
+ return true;
+ }
+ }
+ return false;
+}
+
#ifdef _WIN32
char *realpath(const char *file_name, char *resolved_name)
{
@@ -162,10 +187,94 @@ char *realpath(const char *file_name, char *resolved_name)
}
FindClose(handle);
- NormalizePath(resolved_name);
+ normalize_path(resolved_name);
return resolved_name;
}
return nullptr;
}
#endif // _WIN32
+
+void __declspec(noreturn) do_exit(int exitval)
+{
+ //Allahu Akbar!!
+ *((int *)nullptr) = 0;
+}
+
+// Checks for a non-empty file, relative to the gamedir if necessary.
+// Formerly used LOAD_FILE_FOR_ME, which provided a simple way to check for
+// a file under the gamedir, but which would _also_ look in the sibling
+// "valve" directory, thus sometimes finding files that weren't desired.
+// Also, formerly named just "valid_file".
+//
+// Special-case-recognize "/dev/null" as a valid file.
+bool is_file_exists_in_gamedir(const char *path)
+{
+ char buf[PATH_MAX];
+
+ if (!path)
+ return false;
+
+ if (!Q_strcmp(path, "/dev/null"))
+ return true;
+
+ if (is_abs_path(path)) {
+ Q_strncpy(buf, path, sizeof buf);
+ buf[sizeof buf - 1] = '\0';
+ }
+ else
+ snprintf(buf, sizeof buf, "%s/%s", g_GameDLL.gamedir, path);
+
+ struct stat st;
+ int ret = stat(buf, &st);
+ if (ret != 0) {
+ META_DEBUG(5, "Unable to stat '%s': %s", buf, strerror(errno));
+ return false;
+ }
+
+ int reg = S_ISREG(st.st_mode);
+ if (!reg) {
+ META_DEBUG(5, "Not a regular file: %s", buf);
+ return false;
+ }
+
+ if (!st.st_size) {
+ META_DEBUG(5, "Empty file: %s", buf);
+ return false;
+ }
+
+ if (ret == 0 && reg)
+ return true;
+
+ return false;
+}
+
+// Turns path into a full path:
+// - if not absolute, prepends gamedir
+// - calls realpath() to collapse ".." and such
+// - calls NormalizePath() to fix backslashes, etc
+//
+// Much like realpath, buffer pointed to by fullpath is assumed to be
+// able to store a string of PATH_MAX length.
+char* full_gamedir_path(const char* path, char* fullpath)
+{
+ char buf[PATH_MAX];
+
+ // Build pathname from filename, plus gamedir if relative path.
+ if (is_abs_path(path)) {
+ Q_strncpy(buf, path, sizeof buf - 1);
+ buf[sizeof buf - 1] = '\0';
+ }
+ else snprintf(buf, sizeof buf, "%s/%s", g_GameDLL.gamedir, path);
+
+ // Remove relative path components, if possible.
+ if (!realpath(buf, fullpath)) {
+ META_DEBUG(4, "Unable to get realpath for '%s': %s", buf, str_os_error());
+ Q_strncpy(fullpath, path, sizeof fullpath - 1);
+ fullpath[sizeof fullpath - 1] = '\0';
+ }
+
+ // Replace backslashes, etc.
+ normalize_path(fullpath);
+ return fullpath;
+}
diff --git a/metamod/src/utils.h b/metamod/src/utils.h
index 2913d07..049e71b 100644
--- a/metamod/src/utils.h
+++ b/metamod/src/utils.h
@@ -1,5 +1,17 @@
#pragma once
+// Turn a variable/function name into the corresponding string, optionally
+// stripping off the leading "len" characters. Useful for things like
+// turning 'pfnClientCommand' into "ClientCommand" so we don't have to
+// specify strings used for all the debugging/log messages.
+#define STRINGIZE(name, len) #name+len
+
+// Max description length for plugins.ini and other places.
+#define MAX_DESC_LEN 256
+
+// For various character string buffers.
+#define MAX_STRBUF_LEN 1024
+
template
char(&ArraySizeHelper(T(&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
@@ -54,5 +66,14 @@ char *realpath(const char *file_name, char *resolved_name);
#endif // _WIN32
char* trimbuf(char *str);
-void NormalizePath(char *path);
-bool IsAbsolutePath(const char *path);
+void normalize_path(char *path);
+bool is_abs_path(const char *path);
+bool is_valid_path(const char *path);
+bool is_platform_postfix(const char *pf);
+
+void __declspec(noreturn) do_exit(int exitval);
+
+bool is_file_exists_in_gamedir(const char *path);
+char *full_gamedir_path(const char *path, char *fullpath);
+
+extern const char* g_platform_postfixes[4];