diff --git a/sourcemm/CPlugin.cpp b/sourcemm/CPlugin.cpp index f3fa7f0..decf89a 100644 --- a/sourcemm/CPlugin.cpp +++ b/sourcemm/CPlugin.cpp @@ -261,6 +261,9 @@ bool CPluginManager::_Pause(CPluginManager::CPlugin *pl, char *error, size_t max if (pl->m_API->Pause(error, maxlen)) { g_SourceHook.PausePlugin(pl->m_Id); + pl->m_Status = Pl_Paused; + + return true; } } @@ -280,6 +283,9 @@ bool CPluginManager::_Unpause(CPluginManager::CPlugin *pl, char *error, size_t m if (pl->m_API->Unpause(error, maxlen)) { g_SourceHook.UnpausePlugin(pl->m_Id); + pl->m_Status = Pl_Running; + + return true; } } diff --git a/sourcemm/concommands.cpp b/sourcemm/concommands.cpp index 00d6d0e..b5d2994 100644 --- a/sourcemm/concommands.cpp +++ b/sourcemm/concommands.cpp @@ -44,14 +44,14 @@ CON_COMMAND(meta, "Metamod:Source Menu") Msg(" GameDLL/Plugins: David \"BAILOPAN\" Anderson\n"); Msg(" GameDLL: Scott \"Damaged Soul\" Ehlert\n"); Msg("For more information, see the official website\n"); - Msg("http://www.sourcemm.net/\n"); + Msg("http://www.sourcemm.net/\n\n"); return; } else if (strcmp(command, "version") == 0) { Msg("Metamod:Source version %s\n", SOURCEMM_VERSION); Msg("Compiled on: %s\n", SOURCEMM_DATE); Msg("Plugin interface version: %d/%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION); - Msg("http://www.sourcemm.net/\n"); + Msg("http://www.sourcemm.net/\n\n"); return; } else if (strcmp(command, "game") == 0) { @@ -74,6 +74,9 @@ CON_COMMAND(meta, "Metamod:Source Menu") SourceMM::CPluginManager::CPlugin *pl; PluginIter i; const char *status=""; + const char *version=NULL; + const char *name=NULL; + const char *author=NULL; Msg("-Id- %-16.15s %-8.7s %-12.11s %-8.7s\n", "Name", "Version", "Author", "Status"); for (i=g_PluginMngr._begin(); i!=g_PluginMngr._end(); i++) @@ -93,9 +96,31 @@ CON_COMMAND(meta, "Metamod:Source Menu") } else if (pl->m_Status == Pl_NotFound) { status = "NOFILE"; } - Msg("[%02d] %-16.15s %-8.7s %-12.11s %-8.7s\n", pl->m_Id, pl->m_API->GetName(), pl->m_API->GetVersion(), pl->m_API->GetAuthor(), status); + + if (pl->m_API) + { + version = pl->m_API->GetVersion(); + author = pl->m_API->GetAuthor(); + name = pl->m_API->GetName(); + } else { + version = "-"; + author = "-"; + name = "-"; + } + + if (!version) + version = "-"; + if (!author) + author = "-"; + if (!name) + name = pl->m_File.c_str(); + + + Msg("[%02d] %-16.15s %-8.7s %-12.11s %-8.7s\n", pl->m_Id, name, version, author, status); } + Msg("\n"); + return; } else if (strcmp(command, "info") == 0) { if (args >= 3) @@ -125,7 +150,7 @@ CON_COMMAND(meta, "Metamod:Source Menu") Msg("URL: %s\n", pl->m_API->GetURL()); Msg("Details: API %03d, Date: %s\n", pl->m_API->GetApiVersion(), pl->m_API->GetDate()); } - Msg("File: %s\n", pl->m_File.c_str()); + Msg("File: %s\n\n", pl->m_File.c_str()); return; } else { @@ -137,28 +162,16 @@ CON_COMMAND(meta, "Metamod:Source Menu") if (args >= 3) { int id = atoi(e->Cmd_Argv(2)); - SourceMM::CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id); - if (!pl) + + char error[255]; + + if (!g_PluginMngr.Pause(id, error, sizeof(error)-1)) { - Msg("Plugin %d not found.\n", id); + Msg("Pause failed: %s\n", error); return; } - if (pl->m_Status != Pl_Running) - { - Msg("Plugin %d is not pausable.\n", pl->m_Id); - return; - } - - char error[255]={0}; - if (!pl->m_API->Pause(error, sizeof(error)-1)) - { - Msg("Plugin %d refused pause: %s\n", pl->m_Id, error); - return; - } - - g_SourceHook.PausePlugin(pl->m_Id); - Msg("\"%s\" has been paused.\n", pl->m_API->GetName()); + Msg("Plugin %d has been paused.\n", id); return; } else { @@ -170,28 +183,15 @@ CON_COMMAND(meta, "Metamod:Source Menu") if (args >= 3) { int id = atoi(e->Cmd_Argv(2)); - SourceMM::CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id); - if (!pl) + char error[255]; + + if (!g_PluginMngr.Unpause(id, error, sizeof(error)-1)) { - Msg("Plugin %d not found.\n", id); - return; - } - - if (pl->m_Status != Pl_Paused) - { - Msg("Plugin %d is not unpausable.\n", pl->m_Id); + Msg("Unpause failed: %s\n", error); return; } - char error[255]={0}; - if (!pl->m_API->Pause(error, sizeof(error)-1)) - { - Msg("Plugin %d refused unpause: %s\n", pl->m_Id, error); - return; - } - - g_SourceHook.UnpausePlugin(pl->m_Id); - Msg("\"%s\" has been unpaused.\n", pl->m_API->GetName()); + Msg("Plugin %d has been unpaused.\n", id); return; } else { @@ -211,10 +211,10 @@ CON_COMMAND(meta, "Metamod:Source Menu") } else { const char *ext = UTIL_GetExtension(file); #if defined WIN32 || defined _WIN32 - ext ? "" : ".dll"; + ext = ext ? "" : ".dll"; snprintf(full_path, sizeof(full_path)-1, "%s\\%s%s", g_ModPath.c_str(), file, ext); #else - ext ? "" : "_i486.so"; + ext = ext ? "" : "_i486.so"; snprintf(full_path, sizeof(full_path)-1, "%s/%s%s", g_ModPath.c_str(), file, ext); #endif } @@ -299,15 +299,17 @@ CON_COMMAND(meta, "Metamod:Source Menu") Msg("Metamod:Source Menu\n"); Msg("usage: meta [arguments]\n"); - Msg(" clear - Unload all plugins forcefully\n"); - Msg(" credits - About Metamod:Source\n"); - Msg(" game - Information about GameDLL\n"); - Msg(" info - Information about a plugin\n"); - Msg(" list - List plugins\n"); - Msg(" load - Load a plugin\n"); - Msg(" pause - Pause a running plugin\n"); - Msg(" refresh - Reparse plugins file\n"); - Msg(" unload - Unload a loaded plugin\n"); - Msg(" unpause - Unpause a paused plugin\n"); - Msg(" version - Version information\n"); + Msg(" clear - Unload all plugins forcefully\n"); + Msg(" credits - About Metamod:Source\n"); + Msg(" force_unload - Forcefully unload a plugin\n"); + Msg(" game - Information about GameDLL\n"); + Msg(" info - Information about a plugin\n"); + Msg(" list - List plugins\n"); + Msg(" load - Load a plugin\n"); + Msg(" pause - Pause a running plugin\n"); + Msg(" refresh - Reparse plugins file\n"); + Msg(" unload - Unload a loaded plugin\n"); + Msg(" unpause - Unpause a paused plugin\n"); + Msg(" version - Version information\n"); + Msg("\n"); } diff --git a/sourcemm/sample_mm/SamplePlugin.cpp b/sourcemm/sample_mm/SamplePlugin.cpp index 55ca314..1331c3d 100644 --- a/sourcemm/sample_mm/SamplePlugin.cpp +++ b/sourcemm/sample_mm/SamplePlugin.cpp @@ -1,13 +1,28 @@ +#include #include "SamplePlugin.h" SamplePlugin g_SamplePlugin; PLUGIN_EXPOSE(SamplePlugin, g_SamplePlugin); +//SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, char const *, char const *, char const *, char const *, bool, bool); + +//bool LevelInit_handler( char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background ); + bool SamplePlugin::Load(PluginId id, ISmmAPI *ismm, factories *list, char *error, size_t maxlen) { PLUGIN_SAVEVARS(); + IServerGameDLL *isgd = (IServerGameDLL *)((ismm->serverFactory())(INTERFACEVERSION_SERVERGAMEDLL, NULL)); + + if (!isgd) + { + snprintf(error, maxlen, "Could not find interface %s", INTERFACEVERSION_SERVERGAMEDLL); + return false; + } + + //SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelInit, isgd, LevelInit_handler, false); + return true; } @@ -15,3 +30,16 @@ bool SamplePlugin::Unload(char *error, size_t maxlen) { return true; } + +/*bool LevelInit_handler( char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background ) +{ + FILE *fp = fopen("c:\\dump.txt", "at"); + if (!fp) + RETURN_META_VALUE(MRES_IGNORED, false); + + fprintf(fp, "Map name: %s (old level: %s)\n", pMapName?pMapName:"", pOldLevel?pOldLevel:""); + + fclose(fp); + + RETURN_META_VALUE(MRES_IGNORED, false); +}*/ diff --git a/sourcemm/sample_mm/sample_mm.vcproj b/sourcemm/sample_mm/sample_mm.vcproj index 6f658e2..8aa65e4 100644 --- a/sourcemm/sample_mm/sample_mm.vcproj +++ b/sourcemm/sample_mm/sample_mm.vcproj @@ -22,7 +22,7 @@ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS" MinimalRebuild="TRUE" BasicRuntimeChecks="3" - RuntimeLibrary="1" + RuntimeLibrary="5" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="TRUE" @@ -31,6 +31,7 @@ Name="VCCustomBuildTool"/> @@ -82,7 +84,7 @@ GenerateDebugInformation="TRUE" SubSystem="2" OptimizeReferences="2" - EnableCOMDATFolding="2" + EnableCOMDATFolding="1" ImportLibrary="$(OutDir)/sample_mm.lib" TargetMachine="1"/> (&g_SourceHook); + //The gamedll isn't loaded yet. We need to find out where it's hiding. IVEngineServer *ive = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL)); if (!ive) @@ -151,6 +159,8 @@ bool CServerGameDLL::DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn return false; } + g_GameDll.serverGameDLL = serverDll; + //Set this information early in case our wrappers are called somehow g_Engine.engineFactory = engineFactory; g_Engine.icvar = (ICvar *)(g_Engine.engineFactory)(VENGINE_CVAR_INTERFACE_VERSION, NULL); @@ -240,6 +250,9 @@ bool CServerGameDLL::DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn //Everything's done. g_GameDll.loaded = true; + //Initialize our shutdown hook + SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLShutdown, serverDll, DLLShutdown_handler, false); + //Initialize our console hooks ConCommandBaseMgr::OneTimeInit(static_cast(&g_SMConVarAccessor)); @@ -263,6 +276,29 @@ bool CServerGameDLL::DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn return false; } +void DLLShutdown_handler(void) +{ + //It's time for us to shut down too! + g_PluginMngr.UnloadAll(); + + //Call the DLL... + g_GameDll.serverGameDLL->DLLShutdown(); + + //Unload the DLL forcefully + dlclose(g_GameDll.lib); + memset(&g_GameDll, 0, sizeof(GameDllInfo)); + + //For now, I'm not gonna bother freeing the memory allocated above. + //Why? + // 1. We're exiting the application (I should hope!) + // 2. If we're not exiting, we just deallocated the gamedll, so we're about to crash out ANYWAY + // 3. We never saved the original vtable pointers, and we'd have to copy them back to get our destructors. + //Soooo... we'll just accept our fate here. + + //DON'T CALL THE GAMEDLL! IT'S GONE! pinin' for the fjords + RETURN_META(MRES_SUPERCEDE); +} + int LoadPluginsFromFile(const char *file) { FILE *fp; diff --git a/sourcemm/sourcemm.h b/sourcemm/sourcemm.h index 68b05c4..c90b8ec 100644 --- a/sourcemm/sourcemm.h +++ b/sourcemm/sourcemm.h @@ -55,6 +55,7 @@ struct GameDllInfo bool loaded; HINSTANCE lib; CreateInterfaceFn factory; + IServerGameDLL *serverGameDLL; }; /** @brief Stores information about the HL2 Engine pointers */ @@ -83,4 +84,10 @@ extern std::string g_ModPath; /** @brief Path to server binary */ extern std::string g_BinPath; +/** @brief Global variable for SourceHook macros */ +extern SourceHook::ISourceHook *g_SHPtr; + +/** @brief We have our own internal plugin id... */ +extern PluginId g_PLID; + #endif //_INCLUDE_SOURCEMM_H