Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 51 additions & 20 deletions addons/sourcemod/scripting/SaveLevel.sp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public Plugin myinfo =
name = "SaveLevel",
author = "BotoX",
description = "Saves players level on maps when they disconnect and restore them on connect.",
version = "2.4.4",
version = "2.4.5",
url = ""
};

Expand Down Expand Up @@ -52,11 +52,21 @@ public void OnPluginEnd()

public void OnMapStart()
{
if(g_Config)
delete g_Config;
if(g_PlayerLevels)
delete g_PlayerLevels;
// A new map means the cached levels no longer map to anything, so start fresh here.
// Config (re)loading lives in LoadMapConfig() so `sm_savelevel_reload` can keep the cache.
delete g_PlayerLevels;
g_PlayerLevels = new StringMap();

LoadMapConfig();
Comment thread
Rushaway marked this conversation as resolved.
}

// `keepOnFailure` controls what happens to the currently active g_Config when loading fails:
// - OnMapStart() passes false: the previous map's config is meaningless on a new map, so it
// must be cleared even if the new map has no config of its own.
// - Command_ReloadConfig() passes true: a missing/malformed file on `sm_savelevel_reload`
// should leave the last known-good config (and level saving/restoring) running as-is.
bool LoadMapConfig(bool keepOnFailure = false)
{
char sMapName[PLATFORM_MAX_PATH];
GetCurrentMap(sMapName, sizeof(sMapName));

Expand All @@ -71,29 +81,39 @@ public void OnMapStart()
if(!FileExists(sConfigFile)) // Second attempt with Map name as lowercase
{
LogMessage("Could not find mapconfig: \"%s\"", sMapName);
return;
if(!keepOnFailure)
delete g_Config;
return false;
}
}

LogMessage("Found mapconfig: \"%s\"", sConfigFile);

g_Config = new KeyValues("levels");
if(!g_Config.ImportFromFile(sConfigFile))
// Load into a temporary KeyValues and only swap it into g_Config once it has been fully
// validated, so a failed reload never leaves g_Config half-updated or unset.
KeyValues Config = new KeyValues("levels");
if(!Config.ImportFromFile(sConfigFile))
{
delete g_Config;
delete Config;
LogMessage("ImportFromFile() failed!");
return;
if(!keepOnFailure)
delete g_Config;
return false;
}
g_Config.Rewind();
Config.Rewind();

if(!g_Config.GotoFirstSubKey())
if(!Config.GotoFirstSubKey())
{
delete g_Config;
delete Config;
LogMessage("GotoFirstSubKey() failed!");
return;
if(!keepOnFailure)
delete g_Config;
return false;
}

g_PlayerLevels = new StringMap();
delete g_Config;
g_Config = Config;
return true;
}

public void OnClientPostAdminCheck(int client)
Expand Down Expand Up @@ -205,17 +225,20 @@ bool RestoreLevel(int client, const char[] sTarget, char[] sName = NULL_STRING,

continue;
}
// FindCharInString() returns an offset relative to sValue[Target], make it absolute.
Input += Target;
sValue[Input] = 0; Input++;

// Input (e.g. add)
int Parameter = Input + FindCharInString(sValue[Input], ',');
if(Input == -1)
int Parameter = FindCharInString(sValue[Input], ',');
if(Parameter == -1)
{
while((Index = FindOutput(client, sValue, 0, sValue[Target], sValue[Input])) != -1)
DeleteOutput(client, sValue, Index);

continue;
}
Parameter += Input;
sValue[Parameter] = 0; Parameter++;

// Parameter (e.g. 1)
Expand Down Expand Up @@ -368,9 +391,14 @@ bool GetLevel(int client, char[] sTargets, int TargetsLen, char[] sNames = NULL_
int Parameter;

Input = FindCharInString(sValue[Target], ',');
if(Input == -1) // Malformed "<target>,<add|subtract>,<value>" entry, skip it.
continue;
sValue[Input] = 0; Input++;

Parameter = Input + FindCharInString(sValue[Input], ',');
int ParameterOffset = FindCharInString(sValue[Input], ',');
if(ParameterOffset == -1)
continue;
Parameter = Input + ParameterOffset;
sValue[Parameter] = 0; Parameter++;

int Value = 0;
Expand Down Expand Up @@ -455,8 +483,11 @@ public Action Command_ClearCache(int args)

public Action Command_ReloadConfig(int client, int args)
{
OnMapStart();
CReplyToCommand(client, "%s Map config file has been reloaded.", PREFIX);
if(LoadMapConfig(true))
CReplyToCommand(client, "%s Map config file has been reloaded.", PREFIX);
else
CReplyToCommand(client, "%s Failed to reload: no valid map config found for the current map (check the server logs). The active configuration is unchanged.", PREFIX);

return Plugin_Handled;
}

Expand Down