diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj
index 0855fd4a..e77b19dd 100644
--- a/core/msvc8/sourcemod_mm.vcproj
+++ b/core/msvc8/sourcemod_mm.vcproj
@@ -251,6 +251,10 @@
RelativePath="..\smn_string.cpp"
>
+
+
diff --git a/core/smn_textparse.cpp b/core/smn_textparse.cpp
new file mode 100644
index 00000000..7f1f1d5f
--- /dev/null
+++ b/core/smn_textparse.cpp
@@ -0,0 +1,285 @@
+#include "sm_globals.h"
+#include "CTextParsers.h"
+#include "HandleSys.h"
+
+HandleType_t g_TypeSMC = 0;
+
+class ParseInfo : public ITextListener_SMC
+{
+public:
+ ParseInfo()
+ {
+ parse_start = NULL;
+ parse_end = NULL;
+ new_section = NULL;
+ key_value = NULL;
+ end_section = NULL;
+ raw_line = NULL;
+ handle = 0;
+ }
+public:
+ void ReadSMC_ParseStart()
+ {
+ if (parse_start)
+ {
+ cell_t result;
+ parse_start->PushCell(handle);
+ parse_start->Execute(&result);
+ }
+ }
+
+ void ReadSMC_ParseEnd(bool halted, bool failed)
+ {
+ if (parse_end)
+ {
+ cell_t result;
+ parse_start->PushCell(handle);
+ parse_end->PushCell(halted ? 1 : 0);
+ parse_end->PushCell(failed ? 1 : 0);
+ parse_end->Execute(&result);
+ }
+ }
+
+ SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes)
+ {
+ cell_t result = SMCParse_Continue;
+
+ if (new_section)
+ {
+ new_section->PushCell(handle);
+ new_section->PushString(name);
+ new_section->PushCell(opt_quotes ? 1 : 0);
+ new_section->Execute(&result);
+ }
+
+ return (SMCParseResult)result;
+ }
+
+ SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
+ {
+ cell_t result = SMCParse_Continue;
+
+ if (key_value)
+ {
+ key_value->PushCell(handle);
+ key_value->PushString(key);
+ key_value->PushString(value);
+ key_value->PushCell(key_quotes ? 1 : 0);
+ key_value->PushCell(value_quotes ? 1 : 0);
+ key_value->Execute(&result);
+ }
+
+ return (SMCParseResult)result;
+ }
+
+ SMCParseResult ReadSMC_LeavingSection()
+ {
+ cell_t result = SMCParse_Continue;
+
+ if (end_section)
+ {
+ end_section->PushCell(handle);
+ end_section->Execute(&result);
+ }
+
+ return (SMCParseResult)result;
+ }
+
+ SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline)
+ {
+ cell_t result = SMCParse_Continue;
+
+ if (raw_line)
+ {
+ raw_line->PushCell(handle);
+ raw_line->PushString(line);
+ raw_line->PushCell(curline);
+ raw_line->Execute(&result);
+ }
+
+ return (SMCParseResult)result;
+ }
+public:
+ IPluginFunction *parse_start;
+ IPluginFunction *parse_end;
+ IPluginFunction *new_section;
+ IPluginFunction *key_value;
+ IPluginFunction *end_section;
+ IPluginFunction *raw_line;
+ Handle_t handle;
+};
+
+class TextParseGlobals :
+ public SMGlobalClass,
+ public IHandleTypeDispatch
+{
+public:
+ void OnSourceModAllInitialized()
+ {
+ HandleAccess sec;
+
+ /* These cannot be cloned, because they are locked to a specific plugin.
+ * However, we let anyone read them because we don't care.
+ */
+ g_HandleSys.InitAccessDefaults(NULL, &sec);
+ sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
+ sec.access[HandleAccess_Read] = 0;
+
+ g_TypeSMC = g_HandleSys.CreateType("SMCParser", this, 0, NULL, &sec, g_pCoreIdent, NULL);
+ }
+
+ void OnSourceModShutdown()
+ {
+ g_HandleSys.RemoveType(g_TypeSMC, g_pCoreIdent);
+ }
+
+ void OnHandleDestroy(HandleType_t type, void *object)
+ {
+ ParseInfo *parse = (ParseInfo *)object;
+ delete parse;
+ }
+};
+
+TextParseGlobals g_TextParseGlobals;
+
+static cell_t SMC_CreateParse(IPluginContext *pContext, const cell_t *params)
+{
+ ParseInfo *pInfo = new ParseInfo();
+
+ Handle_t hndl = g_HandleSys.CreateHandle(g_TypeSMC, pInfo, pContext->GetIdentity(), g_pCoreIdent, NULL);
+
+ /* Should never happen */
+ if (!hndl)
+ {
+ delete pInfo;
+ return 0;
+ }
+
+ pInfo->handle = hndl;
+
+ return hndl;
+}
+
+static cell_t SMC_SetParseStart(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = (Handle_t)params[1];
+ HandleError err;
+ ParseInfo *parse;
+
+ if ((err=g_HandleSys.ReadHandle(hndl, g_TypeSMC, NULL, (void **)&parse))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid SMC Parse Handle %x (error %d)", hndl, err);
+ }
+
+ parse->parse_start = pContext->GetFunctionById((funcid_t)params[2]);
+
+ return 1;
+}
+
+static cell_t SMC_SetParseEnd(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = (Handle_t)params[1];
+ HandleError err;
+ ParseInfo *parse;
+
+ if ((err=g_HandleSys.ReadHandle(hndl, g_TypeSMC, NULL, (void **)&parse))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid SMC Parse Handle %x (error %d)", hndl, err);
+ }
+
+ parse->parse_end = pContext->GetFunctionById((funcid_t)params[2]);
+
+ return 1;
+}
+
+static cell_t SMC_SetReaders(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = (Handle_t)params[1];
+ HandleError err;
+ ParseInfo *parse;
+
+ if ((err=g_HandleSys.ReadHandle(hndl, g_TypeSMC, NULL, (void **)&parse))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid SMC Parse Handle %x (error %d)", hndl, err);
+ }
+
+ parse->new_section = pContext->GetFunctionById((funcid_t)params[2]);
+ parse->key_value = pContext->GetFunctionById((funcid_t)params[3]);
+ parse->end_section = pContext->GetFunctionById((funcid_t)params[4]);
+
+ return 1;
+}
+
+static cell_t SMC_SetRawLine(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = (Handle_t)params[1];
+ HandleError err;
+ ParseInfo *parse;
+
+ if ((err=g_HandleSys.ReadHandle(hndl, g_TypeSMC, NULL, (void **)&parse))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid SMC Parse Handle %x (error %d)", hndl, err);
+ }
+
+ parse->raw_line = pContext->GetFunctionById((funcid_t)params[2]);
+
+ return 1;
+}
+
+static cell_t SMC_ParseFile(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = (Handle_t)params[1];
+ HandleError err;
+ ParseInfo *parse;
+
+ if ((err=g_HandleSys.ReadHandle(hndl, g_TypeSMC, NULL, (void **)&parse))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid SMC Parse Handle %x (error %d)", hndl, err);
+ }
+
+ char *file;
+ pContext->LocalToString(params[2], &file);
+
+ char path[PLATFORM_MAX_PATH];
+ g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file);
+
+ unsigned int line = 0, col = 0;
+ SMCParseError p_err = g_TextParser.ParseFile_SMC(path, parse, &line, &col);
+
+ cell_t *c_line, *c_col;
+ pContext->LocalToPhysAddr(params[3], &c_line);
+ pContext->LocalToPhysAddr(params[4], &c_col);
+
+ return (cell_t)p_err;
+}
+
+static cell_t SMC_GetErrorString(IPluginContext *pContext, const cell_t *params)
+{
+ const char *str = g_TextParser.GetSMCErrorString((SMCParseError)params[1]);
+
+ if (!str)
+ {
+ return 0;
+ }
+
+ pContext->StringToLocal(params[2], params[3], str);
+
+ return 1;
+}
+
+REGISTER_NATIVES(textNatives)
+{
+ {"SMC_CreateParse", SMC_CreateParse},
+ {"SMC_ParseFile", SMC_ParseFile},
+ {"SMC_GetErrorString", SMC_GetErrorString},
+ {"SMC_SetParseStart", SMC_SetParseStart},
+ {"SMC_SetParseEnd", SMC_SetParseEnd},
+ {"SMC_SetReaders", SMC_SetReaders},
+ {"SMC_SetRawLine", SMC_SetRawLine},
+ {NULL, NULL},
+};
diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp
index b87b34eb..4b635679 100644
--- a/core/sourcemod.cpp
+++ b/core/sourcemod.cpp
@@ -8,6 +8,7 @@
#include "ShareSys.h"
#include "CLogger.h"
#include "ExtensionSys.h"
+#include "AdminCache.h"
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);
@@ -169,6 +170,8 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch
m_IsMapLoading = false;
+ g_Admins.DumpAdminCache(ADMIN_CACHE_GROUPS|ADMIN_CACHE_ADMINS|ADMIN_CACHE_OVERRIDES, true);
+
RETURN_META_VALUE(MRES_IGNORED, true);
}
diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp
index c6f99289..2404a20b 100644
--- a/core/systems/PluginSys.cpp
+++ b/core/systems/PluginSys.cpp
@@ -238,7 +238,7 @@ void CPlugin::Call_OnPluginInit()
m_status = Plugin_Running;
cell_t result;
- IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginInit");
+ IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginStart");
if (!pFunction)
{
return;
@@ -256,7 +256,7 @@ void CPlugin::Call_OnPluginUnload()
}
cell_t result;
- IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginUnload");
+ IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginEnd");
if (!pFunction)
{
return;
@@ -1369,8 +1369,12 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc
assert(pl->GetStatus() != Plugin_Created);
int len = 0;
const sm_plugininfo_t *info = pl->GetPublicInfo();
-
- len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, GetStatusText(pl->GetStatus()));
+ if (pl->GetStatus() != Pl_Running)
+ {
+ len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, GetStatusText(pl->GetStatus()));
+ } else {
+ len += UTIL_Format(buffer, sizeof(buffer), " %02d", id);
+ }
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
if (IS_STR_FILLED(info->version))
{