- 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
This commit is contained in:
David Anderson 2007-06-18 07:04:22 +00:00
parent 33b2d04e2d
commit 254fc2557a
14 changed files with 447 additions and 100 deletions

View File

@ -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<ConCommandBase *>(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<CmdHook *> &cmdlist, IPluginContext *pContext)
{
List<CmdHook *>::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);

View File

@ -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<CmdHook *> &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<ConCmdInfo *> 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;

View File

@ -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<const ConVar *> *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<const ConVar *>::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; i<num; i++)
{
can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(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; i<num; i++)
{
can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(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);
}

View File

@ -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_

View File

@ -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)

View File

@ -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))
{

View File

@ -59,6 +59,7 @@ public: //IRootConsole
public:
void GotRootCmd();
private:
bool m_CfgExecDone;
Trie *m_pCommands;
List<ConsoleEntry *> m_Menu;
};

View File

@ -13,10 +13,13 @@
*/
#include <time.h>
#include <string.h>
#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 <windows.h>
@ -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},

View File

@ -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;

View File

@ -16,6 +16,7 @@
#include <stdarg.h>
#include <string.h>
#include <sm_platform.h>
#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);
}

View File

@ -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;

View File

@ -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; i<m_configs.size(); i++)
{
delete m_configs[i];
}
m_configs.clear();
}
void CPlugin::InitIdentity()
@ -309,12 +315,9 @@ void CPlugin::Call_OnPluginStart()
pFunction->Execute(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<CPlugin *>::iterator iter;
//for (iter =
}

View File

@ -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<FakeNative *> m_fakeNatives;
Trie *m_pProps;
bool m_FakeNativesMissing;
CVector<AutoConfig *> 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

View File

@ -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, <plugin.filename.cfg> 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 <helpers>
#include <entity>