From 254fc2557aa4a04c47321409074edba828a3b07d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 18 Jun 2007 07:04:22 +0000 Subject: [PATCH] - removed OnServerCfg in favor of OnConfigsExecuted - added AutoExecConfig() which automates safe config execution --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40984 --- core/ConCmdManager.cpp | 76 ---------- core/ConCmdManager.h | 11 -- core/CoreConfig.cpp | 271 ++++++++++++++++++++++++++++++++++ core/CoreConfig.h | 7 + core/PlayerManager.cpp | 3 + core/sm_srvcmds.cpp | 18 +++ core/sm_srvcmds.h | 1 + core/smn_core.cpp | 34 +++++ core/sourcemod.cpp | 1 + core/systems/LibrarySys.cpp | 32 ++++ core/systems/LibrarySys.h | 2 + core/systems/PluginSys.cpp | 46 +++++- core/systems/PluginSys.h | 14 ++ plugins/include/sourcemod.inc | 31 +++- 14 files changed, 447 insertions(+), 100 deletions(-) diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 96120402..fd53dfa3 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -40,10 +40,6 @@ ConCmdManager::ConCmdManager() : m_Strings(1024) { m_pCmds = sm_trie_create(); m_pCmdGrps = sm_trie_create(); - m_bServerCfgDone = true; - m_pExecCmd = NULL; - m_pServerCfgFile = NULL; - m_pServerCfgFwd = NULL; m_CmdClient = 0; } @@ -58,77 +54,15 @@ void ConCmdManager::OnSourceModAllInitialized() g_PluginSys.AddPluginsListener(this); g_RootMenu.AddRootConsoleCommand("cmds", "List console commands", this); SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false); - - ConCommandBase *pCmd = icvar->GetCommands(); - const char *name; - while (pCmd) - { - if (pCmd->IsCommand()) - { - name = pCmd->GetName(); - if (strcmp(name, "exec") == 0) - { - m_pExecCmd = (ConCommand *)pCmd; - break; - } - } - pCmd = const_cast(pCmd->GetNext()); - } - - if (m_pExecCmd) - { - m_pServerCfgFile = (ConVar *)icvar->FindVar("servercfgfile"); - SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pExecCmd, this, &ConCmdManager::OnExecCmd, true); - m_pServerCfgFwd = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL); - } } void ConCmdManager::OnSourceModShutdown() { - if (m_pExecCmd) - { - SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pExecCmd, this, &ConCmdManager::OnExecCmd, true); - g_Forwards.ReleaseForward(m_pServerCfgFwd); - m_pServerCfgFwd = NULL; - m_pExecCmd = NULL; - } - /* All commands should already be removed by the time we're done */ SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false); g_RootMenu.RemoveRootConsoleCommand("cmds", this); } -void ConCmdManager::OnSourceModLevelChange(const char *mapName) -{ - m_bServerCfgDone = false; -} - -void ConCmdManager::OnExecCmd() -{ - const char *arg = engine->Cmd_Argv(1); - const char *cfgfile = "server.cfg"; - - if (m_pServerCfgFile) - { - cfgfile = m_pServerCfgFile->GetString(); - } - - if (strcmp(arg, cfgfile) == 0) - { - engine->ServerCommand("sm cmds internal 1\n"); - } -} - -void ConCmdManager::NotifyExecDone(const char *file) -{ - if (file == NULL && !m_bServerCfgDone) - { - /* Server-cfg file */ - m_bServerCfgDone = true; - m_pServerCfgFwd->Execute(NULL); - } -} - void ConCmdManager::RemoveConCmds(List &cmdlist, IPluginContext *pContext) { List::iterator iter = cmdlist.begin(); @@ -838,16 +772,6 @@ void ConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argco { const char *text = engine->Cmd_Argv(2); - if (strcmp(text, "internal") == 0) - { - const char *num = engine->Cmd_Argv(3); - if (atoi(num) == 1) - { - NotifyExecDone(NULL); - } - return; - } - int id = atoi(text); CPlugin *pPlugin = g_PluginSys.GetPluginByOrder(id); diff --git a/core/ConCmdManager.h b/core/ConCmdManager.h index d9e8cbf8..bf363d64 100644 --- a/core/ConCmdManager.h +++ b/core/ConCmdManager.h @@ -84,7 +84,6 @@ public: public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); - void OnSourceModLevelChange(const char *mapName); public: //IPluginsListener void OnPluginDestroyed(IPlugin *plugin); public: //IRootConsoleCommand @@ -100,7 +99,6 @@ public: int flags); ResultType DispatchClientCommand(int client, ResultType type); void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits); - void NotifyExecDone(const char *file); bool LookForSourceModCommand(const char *cmd); private: void InternalDispatch(); @@ -111,26 +109,17 @@ private: void RemoveConCmd(ConCmdInfo *info); void RemoveConCmds(List &cmdlist, IPluginContext *pContext); bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin); - void OnExecCmd(); public: inline int GetCommandClient() { return m_CmdClient; } - inline bool IsServerCfgDone() - { - return m_bServerCfgDone; - } private: Trie *m_pCmds; /* command lookup */ Trie *m_pCmdGrps; /* command group lookup */ List m_CmdList; /* command list */ int m_CmdClient; /* current client */ BaseStringTable m_Strings; /* string table */ - ConVar *m_pServerCfgFile; /* servercfgfile cvar */ - ConCommand *m_pExecCmd; /* "exec" command */ - IForward *m_pServerCfgFwd; /* server config forward */ - bool m_bServerCfgDone; /* marks whether a servercfg was detected */ }; extern ConCmdManager g_ConCmds; diff --git a/core/CoreConfig.cpp b/core/CoreConfig.cpp index d64fd671..b8db4786 100644 --- a/core/CoreConfig.cpp +++ b/core/CoreConfig.cpp @@ -16,9 +16,13 @@ #include "sourcemod.h" #include "sourcemm_api.h" #include "sm_srvcmds.h" +#include "sm_version.h" +#include "sm_stringutil.h" #include "LibrarySys.h" #include "TextParsers.h" #include "Logger.h" +#include "PluginSys.h" +#include "ForwardSys.h" #ifdef PLATFORM_WINDOWS ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file"); @@ -26,16 +30,28 @@ ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file"); #endif +IForward *g_pOnServerCfg = NULL; +IForward *g_pOnConfigsExecuted = NULL; CoreConfig g_CoreConfig; +bool g_bConfigsExecd = false; void CoreConfig::OnSourceModAllInitialized() { g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this); + g_pOnServerCfg = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL); + g_pOnConfigsExecuted = g_Forwards.CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL); } void CoreConfig::OnSourceModShutdown() { g_RootMenu.RemoveRootConsoleCommand("config", this); + g_Forwards.ReleaseForward(g_pOnServerCfg); + g_Forwards.ReleaseForward(g_pOnConfigsExecuted); +} + +void CoreConfig::OnSourceModLevelChange(const char *mapName) +{ + g_bConfigsExecd = false; } void CoreConfig::OnRootConsoleCommand(const char *command, unsigned int argcount) @@ -121,3 +137,258 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, return ConfigResult_Ignore; } + +bool SM_AreConfigsExecuted() +{ + return g_bConfigsExecd; +} + +inline bool IsPathSepChar(char c) +{ +#if defined PLATFORM_WINDOWS + return (c == '\\' || c == '/'); +#elif defined PLATFORM_LINUX + return (c == '/'); +#endif +} + +bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create) +{ + bool will_create = false; + + /* See if we should be creating */ + if (can_create && cfg->create) + { + will_create = true; + + /* If the folder does not exist, attempt to create it. + * We're awfully nice. + */ + const char *folder = cfg->folder.c_str(); + char path[PLATFORM_MAX_PATH]; + char build[PLATFORM_MAX_PATH]; + + g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "cfg/%s", folder); + + if (!g_LibSys.IsPathDirectory(path)) + { + char *cur_ptr = path; + size_t len; + + g_LibSys.PathFormat(path, sizeof(path), "%s", folder); + len = g_SourceMod.BuildPath(Path_Game, build, sizeof(build), "cfg"); + + do + { + /* Find next suitable path */ + char *next_ptr = cur_ptr; + while (*next_ptr != '\0') + { + if (IsPathSepChar(*next_ptr)) + { + *next_ptr = '\0'; + next_ptr++; + break; + } + next_ptr++; + } + if (*next_ptr == '\0') + { + next_ptr = NULL; + } + len += g_LibSys.PathFormat(&build[len], + sizeof(build)-len, + "/%s", + cur_ptr); + if (!g_LibSys.CreateDirectory(build)) + { + break; + } + cur_ptr = next_ptr; + } while (cur_ptr); + } + } + + /* Check if the file exists. */ + char file[PLATFORM_MAX_PATH]; + char local[PLATFORM_MAX_PATH]; + + if (cfg->folder.size()) + { + g_LibSys.PathFormat(local, + sizeof(local), + "%s/%s.cfg", + cfg->folder.c_str(), + cfg->autocfg.c_str()); + } else { + g_LibSys.PathFormat(local, + sizeof(local), + "%s.cfg", + cfg->autocfg.c_str()); + } + + g_SourceMod.BuildPath(Path_Game, file, sizeof(file), "cfg/%s", local); + + bool file_exists = g_LibSys.IsPathFile(file); + if (!file_exists && will_create) + { + List *convars = NULL; + if (pl->GetProperty("ConVarList", (void **)&convars, false) && convars) + { + /* Attempt to create it */ + FILE *fp = fopen(file, "wt"); + if (fp) + { + fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SVN_FULL_VERSION); + fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename()); + fprintf(fp, "\n\n"); + + List::iterator iter; + float x; + for (iter = convars->begin(); iter != convars->end(); iter++) + { + const ConVar *cvar = (*iter); + char descr[255]; + char *dptr = descr; + + /* Print comments until there is no more */ + strncopy(descr, cvar->GetHelpText(), sizeof(descr)); + while (*dptr != '\0') + { + /* Find the next line */ + char *next_ptr = dptr; + while (*next_ptr != '\0') + { + if (*next_ptr == '\n') + { + *next_ptr = '\0'; + next_ptr++; + break; + } + next_ptr++; + } + fprintf(fp, "// %s\n", dptr); + dptr = next_ptr; + } + + fprintf(fp, "// -\n"); + fprintf(fp, "// Default: \"%s\"\n", cvar->GetDefault()); + if (cvar->GetMin(x)) + { + fprintf(fp, "// Minimum: \"%02f\"\n", x); + } + if (cvar->GetMax(x)) + { + fprintf(fp, "// Maximum: \"%02f\"\n", x); + } + fprintf(fp, "%s \"%s\"\n", cvar->GetName(), cvar->GetDefault()); + fprintf(fp, "\n"); + } + fprintf(fp, "\n"); + + file_exists = true; + can_create = false; + fclose(fp); + } + } + } + + if (file_exists) + { + char cmd[255]; + UTIL_Format(cmd, sizeof(cmd), "exec %s\n", local); + engine->ServerCommand(cmd); + } + + return can_create; +} + +void SM_DoSingleExecFwds(IPluginContext *ctx) +{ + IPluginFunction *pf; + + if ((pf = ctx->GetFunctionByName("OnServerCfg")) != NULL) + { + pf->Execute(NULL); + } + + if ((pf = ctx->GetFunctionByName("OnConfigsExecuted")) != NULL) + { + pf->Execute(NULL); + } +} + +void SM_ConfigsExecuted_Plugin(unsigned int serial) +{ + IPluginIterator *iter = g_PluginSys.GetPluginIterator(); + while (iter->MorePlugins()) + { + CPlugin *plugin = (CPlugin *)(iter->GetPlugin()); + if (plugin->GetSerial() == serial) + { + SM_DoSingleExecFwds(plugin->GetBaseContext()); + break; + } + iter->NextPlugin(); + } + iter->Release(); +} + +void SM_ExecuteForPlugin(IPluginContext *ctx) +{ + CPlugin *plugin = (CPlugin *)g_PluginSys.GetPluginByCtx(ctx->GetContext()); + + unsigned int num = plugin->GetConfigCount(); + if (!num) + { + SM_DoSingleExecFwds(ctx); + } else { + bool can_create = true; + for (unsigned int i=0; iGetConfig(i), can_create); + } + char cmd[255]; + UTIL_Format(cmd, sizeof(cmd), "sm internal 2 %d\n", plugin->GetSerial()); + engine->ServerCommand(cmd); + } +} + +void SM_ExecuteAllConfigs() +{ + if (g_bConfigsExecd) + { + return; + } + + engine->ServerCommand("exec cfg/sourcemod/sourcemod.cfg\n"); + + IPluginIterator *iter = g_PluginSys.GetPluginIterator(); + while (iter->MorePlugins()) + { + CPlugin *plugin = (CPlugin *)(iter->GetPlugin()); + unsigned int num = plugin->GetConfigCount(); + bool can_create = true; + for (unsigned int i=0; iGetConfig(i), can_create); + } + iter->NextPlugin(); + } + iter->Release(); + + engine->ServerCommand("sm internal 1\n"); +} + +void SM_ConfigsExecuted_Global() +{ + if (g_bConfigsExecd) + { + return; + } + + g_bConfigsExecd = true; + + g_pOnServerCfg->Execute(NULL); + g_pOnConfigsExecuted->Execute(NULL); +} diff --git a/core/CoreConfig.h b/core/CoreConfig.h index da83d46d..b0790bfd 100644 --- a/core/CoreConfig.h +++ b/core/CoreConfig.h @@ -29,6 +29,7 @@ class CoreConfig : public: // SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); + void OnSourceModLevelChange(const char *mapName); public: // ITextListener_SMC SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes); public: // IRootConsoleCommand @@ -45,6 +46,12 @@ private: ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength); }; +extern bool SM_AreConfigsExecuted(); +extern void SM_ExecuteAllConfigs(); +extern void SM_ExecuteForPlugin(IPluginContext *ctx); +extern void SM_ConfigsExecuted_Global(); +extern void SM_ConfigsExecuted_Plugin(unsigned int serial); + extern CoreConfig g_CoreConfig; #endif // _INCLUDE_SOURCEMOD_CORECONFIG_H_ diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 25c7c52a..e41ebb05 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -20,6 +20,7 @@ #include "MenuStyle_Valve.h" #include "MenuStyle_Radio.h" #include "sm_stringutil.h" +#include "CoreConfig.h" PlayerManager g_Players; bool g_OnMapStarted = false; @@ -114,6 +115,8 @@ void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int cl m_onActivate2->Execute(NULL); g_OnMapStarted = true; + + SM_ExecuteAllConfigs(); } bool CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id) diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 81bd00b6..4a776325 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -16,6 +16,7 @@ #include "sm_version.h" #include "sm_stringutil.h" #include "HandleSys.h" +#include "CoreConfig.h" RootConsoleMenu g_RootMenu; @@ -24,6 +25,7 @@ ConVar sourcemod_version("sourcemod_version", SVN_FULL_VERSION, FCVAR_SPONLY|FCV RootConsoleMenu::RootConsoleMenu() { m_pCommands = sm_trie_create(); + m_CfgExecDone = false; } RootConsoleMenu::~RootConsoleMenu() @@ -193,7 +195,23 @@ void RootConsoleMenu::GotRootCmd() { _IntExt_EnableYams(); return; + } else if (strcmp(cmd, "internal") == 0) { + if (argnum >= 3) + { + const char *arg = GetArgument(2); + if (strcmp(arg, "1") == 0) + { + SM_ConfigsExecuted_Global(); + } else if (strcmp(arg, "2") == 0) { + if (argnum >= 4) + { + SM_ConfigsExecuted_Plugin(atoi(GetArgument(3))); + } + } + } + return; } + IRootConsoleCommand *pHandler; if (sm_trie_retrieve(m_pCommands, cmd, (void **)&pHandler)) { diff --git a/core/sm_srvcmds.h b/core/sm_srvcmds.h index 78002c5e..14a748c7 100644 --- a/core/sm_srvcmds.h +++ b/core/sm_srvcmds.h @@ -59,6 +59,7 @@ public: //IRootConsole public: void GotRootCmd(); private: + bool m_CfgExecDone; Trie *m_pCommands; List m_Menu; }; diff --git a/core/smn_core.cpp b/core/smn_core.cpp index 7f675880..79e19afa 100644 --- a/core/smn_core.cpp +++ b/core/smn_core.cpp @@ -13,10 +13,13 @@ */ #include +#include +#include "sm_stringutil.h" #include "sm_globals.h" #include "sourcemod.h" #include "PluginSys.h" #include "HandleSys.h" +#include "LibrarySys.h" #if defined PLATFORM_WINDOWS #include @@ -283,8 +286,39 @@ static cell_t GetSysTickCount(IPluginContext *pContext, const cell_t *params) #endif } +static cell_t AutoExecConfig(IPluginContext *pContext, const cell_t *params) +{ + CPlugin *plugin = g_PluginSys.GetPluginByCtx(pContext->GetContext()); + + char *cfg, *folder; + pContext->LocalToString(params[2], &cfg); + pContext->LocalToString(params[3], &folder); + + if (cfg[0] == '\0') + { + static char temp_str[255]; + static char temp_file[PLATFORM_MAX_PATH]; + char *ptr; + + g_LibSys.GetFileFromPath(temp_str, sizeof(temp_str), plugin->GetFilename()); + if ((ptr = strstr(temp_str, ".smx")) != NULL) + { + *ptr = '\0'; + } + + /* We have the raw filename! */ + UTIL_Format(temp_file, sizeof(temp_file), "plugin.%s", temp_str); + cfg = temp_file; + } + + plugin->AddConfig(params[1] ? true : false, cfg, folder); + + return 1; +} + REGISTER_NATIVES(coreNatives) { + {"AutoExecConfig", AutoExecConfig}, {"GetPluginFilename", GetPluginFilename}, {"GetPluginInfo", GetPluginInfo}, {"GetPluginIterator", GetPluginIterator}, diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 8d2b0657..0142f3db 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -35,6 +35,7 @@ SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, false, bool); +SH_DECL_HOOK1_void(IVEngineServer, ServerCommand, SH_NOATTRIB, false, const char *); SourcePawnEngine g_SourcePawn; SourceModBase g_SourceMod; diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index d70fd182..dbd5cd65 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -16,6 +16,7 @@ #include #include #include +#include "sm_stringutil.h" #include "LibrarySys.h" LibrarySystem g_LibSys; @@ -347,3 +348,34 @@ const char *LibrarySystem::GetFileExtension(const char *filename) return NULL; } + +bool LibrarySystem::CreateDirectory(const char *path) +{ +#if defined PLATFORM_WINDOWS + return (mkdir(path) != -1); +#elif defined PLATFORM_POSIX + return (mkdir(path, 0775) != -1); +#endif +} + +size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char *path) +{ + size_t length = strlen(path); + + for (size_t i = length - 1; + i >= 0 && i <= length - 1; + i++) + { + if (path[i] == '/' +#if defined PLATFORM_WINDOWS + || path[i] == '\\' +#endif + ) + { + return UTIL_Format(buffer, maxlength, "%s", &path[i+1]); + } + } + + /* We scanned and found no path separator */ + return UTIL_Format(buffer, maxlength, "%s", path); +} diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h index ff6223fa..dd38b428 100644 --- a/core/systems/LibrarySys.h +++ b/core/systems/LibrarySys.h @@ -75,6 +75,8 @@ public: void GetPlatformError(char *error, size_t maxlength); size_t PathFormat(char *buffer, size_t len, const char *fmt, ...); const char *GetFileExtension(const char *filename); + bool CreateDirectory(const char *path); + size_t GetFileFromPath(char *buffer, size_t maxlength, const char *path); }; extern LibrarySystem g_LibSys; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 50137b66..b630a68f 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -27,6 +27,7 @@ #include "sm_stringutil.h" #include "ConCmdManager.h" #include "PlayerManager.h" +#include "CoreConfig.h" CPluginManager g_PluginSys; HandleType_t g_PluginType = 0; @@ -85,6 +86,11 @@ CPlugin::~CPlugin() { sm_trie_destroy(m_pProps); } + for (size_t i=0; iExecute(NULL); } } - if (g_ConCmds.IsServerCfgDone()) + if (SM_AreConfigsExecuted()) { - if ((pFunction = m_ctx.base->GetFunctionByName("OnServerCfg")) != NULL) - { - pFunction->Execute(NULL); - } + SM_ExecuteForPlugin(GetBaseContext()); } } } @@ -618,6 +621,32 @@ void CPlugin::DependencyDropped(CPlugin *pOwner) m_dependsOn.remove(pOwner); } +unsigned int CPlugin::GetConfigCount() +{ + return (unsigned int)m_configs.size(); +} + +AutoConfig *CPlugin::GetConfig(unsigned int i) +{ + if (i >= GetConfigCount()) + { + return NULL; + } + + return m_configs[i]; +} + +void CPlugin::AddConfig(bool autoCreate, const char *cfg, const char *folder) +{ + AutoConfig *c = new AutoConfig; + + c->autocfg = cfg; + c->folder = folder; + c->create = autoCreate; + + m_configs.push_back(c); +} + /******************* * PLUGIN ITERATOR * *******************/ @@ -1971,3 +2000,10 @@ CPlugin *CPluginManager::GetPluginFromIdentity(IdentityToken_t *pToken) return (CPlugin *)(pToken->ptr); } + +void CPluginManager::ExecAndGenPluginConfs() +{ + List::iterator iter; + + //for (iter = +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index b5f325bf..46d2fd14 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -109,6 +109,13 @@ enum LoadRes LoadRes_Failure }; +struct AutoConfig +{ + String autocfg; + String folder; + bool create; +}; + class CPlugin : public IPlugin { friend class CPluginManager; @@ -223,6 +230,10 @@ public: bool WasRunning(); Handle_t GetMyHandle(); + + void AddConfig(bool autoCreate, const char *cfg, const char *folder); + unsigned int GetConfigCount(); + AutoConfig *GetConfig(unsigned int i); protected: void UpdateInfo(); void SetTimeStamp(time_t t); @@ -246,6 +257,7 @@ private: List m_fakeNatives; Trie *m_pProps; bool m_FakeNativesMissing; + CVector m_configs; }; class CPluginManager : @@ -395,6 +407,8 @@ private: bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength); void _SetPauseState(CPlugin *pPlugin, bool pause); + + void ExecAndGenPluginConfs(); protected: /** * Caching internal objects diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index f40b78e2..42c33b51 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -125,16 +125,16 @@ forward OnMapStart(); forward OnMapEnd(); /** - * Called when the map has loaded and the servercfgfile has finished - * executing. This is usually 'server.cfg' but most mods allow it to - * be set via 'servercfgfile'. + * Called when the map has loaded, servercfgfile (server.cfg) has been + * executed, and all plugin configs are done executing. This is the best + * place to inialize plugin functions which are based on cvar data. * - * @note If server.cfg is executed more than once per map, this forward - * will only be called the first time (per map). - * @note It is not guaranteed that this will be called on all mods. If - * a mod does not appear to support it, please file a SourceMod bug report. + * @note This will always be called once and only once per map. It will be + * called after OnMapStart(). + * + * @noreturn */ -forward OnServerCfg(); +forward OnConfigsExecuted(); /** * Returns the calling plugin's Handle. @@ -297,5 +297,20 @@ native bool:GameConfGetKeyValue(Handle:gc, const String:key[], String:buffer[], */ native GetSysTickCount(); +/** + * Specifies that the given config file should be executed after plugin load. + * OnConfigsExecuted() will not be called until the config file has executed, + * but it will be called if the execution fails. + * + * @param autoCreate If true, and the config file does not exist, such a config + * file will be automatically created and populated with + * information from the plugin's registered cvars. + * @param name Name of the config file, excluding the .cfg extension. + * If empty, is assumed. + * @param folder Folder under cfg/ to use. By default this is "sourcemod." + * @noreturn + */ +native AutoExecConfig(bool:autoCreate=true, const String:name[]="", const String:folder[]="sourcemod"); + #include #include