- Code optimisations
- Added stripper_dump command
This commit is contained in:
tilgep 2022-09-16 13:57:09 +01:00 committed by GitHub
parent 83f8b6c21c
commit e3d51f963c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,19 +1,17 @@
#pragma newdecls required
#pragma semicolon 1 #pragma semicolon 1
#pragma newdecls required
#include <sourcemod> #include <sourcemod>
#include <regex> #include <regex>
#define PLUGIN_VERSION "1.1.0"
public Plugin myinfo = public Plugin myinfo =
{ {
name = "Stripper:Source (SP edition)", name = "Stripper:Source (SP edition)",
author = "tilgep, Stripper:Source by BAILOPAN", version = "1.2.0",
description = "Stripper:Source functionality in a Sourcemod plugin", description = "Stripper:Source functionality in a Sourcemod plugin",
version = PLUGIN_VERSION, author = "tilgep, Stripper:Source by BAILOPAN",
url = "" url = "https://forums.alliedmods.net/showthread.php?t=339448"
}; }
enum Mode enum Mode
{ {
@ -34,8 +32,8 @@ enum SubMode
enum struct Property enum struct Property
{ {
char key[255]; char key[PLATFORM_MAX_PATH];
char val[255]; char val[PLATFORM_MAX_PATH];
bool regex; bool regex;
} }
@ -44,11 +42,11 @@ enum struct Block
{ {
Mode mode; Mode mode;
SubMode submode; SubMode submode;
ArrayList match; // Filter/Modify ArrayList match; // Filter/Modify
ArrayList replace; // Modify ArrayList replace; // Modify
ArrayList del; // Modify ArrayList del; // Modify
ArrayList insert; // Add/Modify ArrayList insert; // Add/Modify
bool hasClassname; // Ensures that an add block has a classname set bool hasClassname; // Ensures that an add block has a classname set
void Init() void Init()
{ {
@ -79,13 +77,66 @@ int section;
public void OnPluginStart() public void OnPluginStart()
{ {
prop.Init(); prop.Init();
RegAdminCmd("stripper_dump", Command_Dump, ADMFLAG_ROOT, "Writes all of the map entity properties to a file in configs/stripper/dumps/");
}
public Action Command_Dump(int client, int args)
{
char buf1[PLATFORM_MAX_PATH], buf2[PLATFORM_MAX_PATH], path[PLATFORM_MAX_PATH];
int num = -1;
GetCurrentMap(buf1, PLATFORM_MAX_PATH);
BuildPath(Path_SM, buf2, PLATFORM_MAX_PATH, "configs/stripper/dumps");
if(!DirExists(buf1)) CreateDirectory(buf1);
do
{
num++;
// Use same format as original stripper
Format(path, PLATFORM_MAX_PATH, "%s/%s.%04d.cfg", buf2, buf1, num);
}
while(FileExists(path));
File fi = OpenFile(path, "w");
if(fi == null)
{
LogError("Failed to create dump file \"%s\"", path);
return Plugin_Handled;
}
EntityLumpEntry ent;
for(int i = 0; i < EntityLump.Length(); i++)
{
ent = EntityLump.Get(i);
fi.WriteLine("{");
for(int j = 0; j < ent.Length; j++)
{
ent.Get(j, buf1, PLATFORM_MAX_PATH, buf2, PLATFORM_MAX_PATH);
fi.WriteLine("\"%s\" \"%s\"", buf1, buf2);
}
fi.WriteLine("}");
delete ent;
}
delete fi;
ReplyToCommand(client, "[SM] Dumped entities to '%s'", path);
return Plugin_Handled;
} }
public void OnMapInit(const char[] mapName) public void OnMapInit(const char[] mapName)
{ {
// Parse global filters // Parse global filters
BuildPath(Path_SM, file, sizeof(file), "configs/stripper/global_filters.cfg"); BuildPath(Path_SM, file, sizeof(file), "configs/stripper/global_filters.cfg");
ParseFile(); ParseFile();
// Now parse map config // Now parse map config
@ -97,14 +148,13 @@ public void OnMapInit(const char[] mapName)
/** /**
* Parses a stripper config file * Parses a stripper config file
* *
* @param path Path to parse from * @param path Path to parse from
*/ */
public void ParseFile() public void ParseFile()
{ {
char error[128]; char error[128];
int line = 0; int line, col;
int col = 0;
section = 0; section = 0;
prop.Clear(); prop.Clear();
@ -115,17 +165,17 @@ public void ParseFile()
SMCError result = SMC_ParseFile(parser, file, line, col); SMCError result = SMC_ParseFile(parser, file, line, col);
delete parser; delete parser;
if (result != SMCError_Okay) if(result != SMCError_Okay)
{ {
SMC_GetErrorString(result, error, sizeof(error)); SMC_GetErrorString(result, error, sizeof(error));
LogError("%s on line %d, col %d of %s", error, line, col, file); LogError("%s on line %d, col %d of %s", error, line, col, file);
} }
} }
public SMCResult Config_NewSection(SMCParser smc, const char[] name, bool opt_quotes) public SMCResult Config_NewSection(SMCParser smc, const char[] name, bool opt_quotes)
{ {
section++; section++;
if (StrEqual(name, "filter:", false) || StrEqual(name, "remove:", false)) if(!strcmp(name, "filter:", false) || !strcmp(name, "remove:", false))
{ {
if(prop.mode != Mode_None) if(prop.mode != Mode_None)
{ {
@ -135,7 +185,7 @@ public SMCResult Config_NewSection(SMCParser smc, const char[] name, bool opt_qu
prop.Clear(); prop.Clear();
prop.mode = Mode_Filter; prop.mode = Mode_Filter;
} }
else if (StrEqual(name, "add:", false)) else if(!strcmp(name, "add:", false))
{ {
if(prop.mode != Mode_None) if(prop.mode != Mode_None)
{ {
@ -145,7 +195,7 @@ public SMCResult Config_NewSection(SMCParser smc, const char[] name, bool opt_qu
prop.Clear(); prop.Clear();
prop.mode = Mode_Add; prop.mode = Mode_Add;
} }
else if (StrEqual(name, "modify:", false)) else if(!strcmp(name, "modify:", false))
{ {
if(prop.mode != Mode_None) if(prop.mode != Mode_None)
{ {
@ -155,24 +205,12 @@ public SMCResult Config_NewSection(SMCParser smc, const char[] name, bool opt_qu
prop.Clear(); prop.Clear();
prop.mode = Mode_Modify; prop.mode = Mode_Modify;
} }
else if (prop.mode == Mode_Modify) else if(prop.mode == Mode_Modify)
{ {
if (StrEqual(name, "match:", false)) if(!strcmp(name, "match:", false)) prop.submode = SubMode_Match;
{ else if(!strcmp(name, "replace:", false)) prop.submode = SubMode_Replace;
prop.submode = SubMode_Match; else if(!strcmp(name, "delete:", false)) prop.submode = SubMode_Delete;
} else if(!strcmp(name, "insert:", false)) prop.submode = SubMode_Insert;
else if (StrEqual(name, "replace:", false))
{
prop.submode = SubMode_Replace;
}
if (StrEqual(name, "delete:", false))
{
prop.submode = SubMode_Delete;
}
if (StrEqual(name, "insert:", false))
{
prop.submode = SubMode_Insert;
}
} }
return SMCParse_Continue; return SMCParse_Continue;
@ -181,51 +219,29 @@ public SMCResult Config_NewSection(SMCParser smc, const char[] name, bool opt_qu
public SMCResult Config_KeyValue(SMCParser smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes) public SMCResult Config_KeyValue(SMCParser smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes)
{ {
Property kv; Property kv;
strcopy(kv.key, 255, key); strcopy(kv.key, PLATFORM_MAX_PATH, key);
strcopy(kv.val, 255, value); strcopy(kv.val, PLATFORM_MAX_PATH, value);
kv.regex = FormatRegex(kv.val, strlen(value)); kv.regex = FormatRegex(kv.val, strlen(value));
switch (prop.mode) switch(prop.mode)
{ {
case Mode_None: case Mode_None: return SMCParse_Continue;
{ case Mode_Filter: prop.match.PushArray(kv);
/*
* we shouldn't be getting key values if we aren't in a section
* ignore them and keep going
*/
return SMCParse_Continue;
}
case Mode_Filter:
{
prop.match.PushArray(kv);
}
case Mode_Add: case Mode_Add:
{ {
// Adding an entity without a classname will crash the server // Adding an entity without a classname will crash the server (shortest classname is "gib")
if(StrEqual(key, "classname", false)) prop.hasClassname = true; if(StrEqual(key, "classname", false) && strlen(value) > 2) prop.hasClassname = true;
prop.insert.PushArray(kv); prop.insert.PushArray(kv);
} }
case Mode_Modify: case Mode_Modify:
{ {
switch (prop.submode) switch(prop.submode)
{ {
case SubMode_Match: case SubMode_Match: prop.match.PushArray(kv);
{ case SubMode_Replace: prop.replace.PushArray(kv);
prop.match.PushArray(kv); case SubMode_Delete: prop.del.PushArray(kv);
} case SubMode_Insert: prop.insert.PushArray(kv);
case SubMode_Replace:
{
prop.replace.PushArray(kv);
}
case SubMode_Delete:
{
prop.del.PushArray(kv);
}
case SubMode_Insert:
{
prop.insert.PushArray(kv);
}
} }
} }
} }
@ -235,29 +251,20 @@ public SMCResult Config_KeyValue(SMCParser smc, const char[] key, const char[] v
public SMCResult Config_EndSection(SMCParser smc) public SMCResult Config_EndSection(SMCParser smc)
{ {
switch (prop.mode) switch(prop.mode)
{ {
case Mode_Filter: case Mode_Filter:
{ {
if (prop.match.Length > 0) if(prop.match.Length > 0) RunRemoveFilter();
{
RunRemoveFilter();
}
prop.mode = Mode_None; prop.mode = Mode_None;
} }
case Mode_Add: case Mode_Add:
{ {
if (prop.insert.Length > 0) if(prop.insert.Length > 0)
{ {
if(prop.hasClassname) if(prop.hasClassname) RunAddFilter();
{ else LogError("Add block with no classname found at section %d in file '%s'", section, file);
RunAddFilter();
}
else
{
LogError("Add block with no classname found at section %d in file '%s'", section, file);
}
} }
prop.mode = Mode_None; prop.mode = Mode_None;
@ -265,17 +272,14 @@ public SMCResult Config_EndSection(SMCParser smc)
case Mode_Modify: case Mode_Modify:
{ {
// Exiting a modify sub-block // Exiting a modify sub-block
if (prop.submode != SubMode_None) if(prop.submode != SubMode_None)
{ {
prop.submode = SubMode_None; prop.submode = SubMode_None;
return SMCParse_Continue; return SMCParse_Continue;
} }
// Must have some match for modify blocks // Must have something to match for modify blocks
if (prop.match.Length > 0) if(prop.match.Length > 0) RunModifyFilter();
{
RunModifyFilter();
}
prop.mode = Mode_None; prop.mode = Mode_None;
} }
@ -289,33 +293,32 @@ public void RunRemoveFilter()
* we know it has at least 1 entry here * we know it has at least 1 entry here
*/ */
char val2[255]; char val2[PLATFORM_MAX_PATH];
Property kv;
for (int i = 0; i < EntityLump.Length(); i++) EntityLumpEntry entry;
for(int i, matches, j, index; i < EntityLump.Length(); i++)
{ {
int matches = 0; matches = 0;
EntityLumpEntry entry = EntityLump.Get(i); entry = EntityLump.Get(i);
for(int j = 0; j < prop.match.Length; j++) for(j = 0; j < prop.match.Length; j++)
{ {
Property kv;
prop.match.GetArray(j, kv, sizeof(kv)); prop.match.GetArray(j, kv, sizeof(kv));
int index = entry.GetNextKey(kv.key, val2, sizeof(val2)); index = entry.GetNextKey(kv.key, val2, sizeof(val2));
while(index != -1)
while (index != -1)
{ {
if (EntPropsMatch(kv.val, val2, kv.regex)) if(EntPropsMatch(kv.val, val2, kv.regex))
{ {
matches++; matches++;
break; break;
} }
index = entry.GetNextKey(kv.key, val2, sizeof(val2), index); index = entry.GetNextKey(kv.key, val2, sizeof(val2), index);
} }
} }
if (matches == prop.match.Length) if(matches == prop.match.Length)
{ {
EntityLump.Erase(i); EntityLump.Erase(i);
i--; i--;
@ -333,11 +336,10 @@ public void RunAddFilter()
int index = EntityLump.Append(); int index = EntityLump.Append();
EntityLumpEntry entry = EntityLump.Get(index); EntityLumpEntry entry = EntityLump.Get(index);
for(int i = 0; i < prop.insert.Length; i++) Property kv;
for(int i; i < prop.insert.Length; i++)
{ {
Property kv;
prop.insert.GetArray(i, kv, sizeof(kv)); prop.insert.GetArray(i, kv, sizeof(kv));
entry.Append(kv.key, kv.val); entry.Append(kv.key, kv.val);
} }
@ -351,39 +353,39 @@ public void RunModifyFilter()
*/ */
// Nothing to do if these are all empty // Nothing to do if these are all empty
if (prop.replace.Length == 0 && prop.del.Length == 0 && prop.insert.Length == 0) if(prop.replace.Length == 0 && prop.del.Length == 0 && prop.insert.Length == 0)
{ {
return; return;
} }
char val2[255]; char val2[PLATFORM_MAX_PATH];
for (int i = 0; i < EntityLump.Length(); i++) Property kv;
EntityLumpEntry entry;
for(int i, matches, j, index; i < EntityLump.Length(); i++)
{ {
int matches = 0; matches = 0;
EntityLumpEntry entry = EntityLump.Get(i); entry = EntityLump.Get(i);
/* Check matches */ /* Check matches */
for(int j = 0; j < prop.match.Length; j++) for(j = 0; j < prop.match.Length; j++)
{ {
Property kv;
prop.match.GetArray(j, kv, sizeof(kv)); prop.match.GetArray(j, kv, sizeof(kv));
int index = entry.GetNextKey(kv.key, val2, sizeof(val2)); index = entry.GetNextKey(kv.key, val2, sizeof(val2));
while(index != -1)
while (index != -1)
{ {
if (EntPropsMatch(kv.val, val2, kv.regex)) if(EntPropsMatch(kv.val, val2, kv.regex))
{ {
matches++; matches++;
break; break;
} }
index = entry.GetNextKey(kv.key, val2, sizeof(val2), index); index = entry.GetNextKey(kv.key, val2, sizeof(val2), index);
} }
} }
if (matches < prop.match.Length) if(matches < prop.match.Length)
{ {
delete entry; delete entry;
continue; continue;
@ -392,17 +394,16 @@ public void RunModifyFilter()
/* This entry matches, perform any changes */ /* This entry matches, perform any changes */
/* First do deletions */ /* First do deletions */
if (prop.del.Length > 0) if(prop.del.Length > 0)
{ {
for(int j = 0; j < prop.del.Length; j++) for(j = 0; j < prop.del.Length; j++)
{ {
Property kv;
prop.del.GetArray(j, kv, sizeof(kv)); prop.del.GetArray(j, kv, sizeof(kv));
int index = entry.GetNextKey(kv.key, val2, sizeof(val2)); index = entry.GetNextKey(kv.key, val2, sizeof(val2));
while (index != -1) while(index != -1)
{ {
if (EntPropsMatch(kv.val, val2, kv.regex)) if(EntPropsMatch(kv.val, val2, kv.regex))
{ {
entry.Erase(index); entry.Erase(index);
index--; index--;
@ -413,15 +414,14 @@ public void RunModifyFilter()
} }
/* do replacements */ /* do replacements */
if (prop.replace.Length > 0) if(prop.replace.Length > 0)
{ {
for(int j = 0; j < prop.replace.Length; j++) for(j = 0; j < prop.replace.Length; j++)
{ {
Property kv;
prop.replace.GetArray(j, kv, sizeof(kv)); prop.replace.GetArray(j, kv, sizeof(kv));
int index = entry.GetNextKey(kv.key, val2, sizeof(val2)); index = entry.GetNextKey(kv.key, val2, sizeof(val2));
while (index != -1) while(index != -1)
{ {
entry.Update(index, NULL_STRING, kv.val); entry.Update(index, NULL_STRING, kv.val);
index = entry.GetNextKey(kv.key, val2, sizeof(val2), index); index = entry.GetNextKey(kv.key, val2, sizeof(val2), index);
@ -430,13 +430,11 @@ public void RunModifyFilter()
} }
/* do insertions */ /* do insertions */
if (prop.insert.Length > 0) if(prop.insert.Length > 0)
{ {
for(int j = 0; j < prop.insert.Length; j++) for(j = 0; j < prop.insert.Length; j++)
{ {
Property kv;
prop.insert.GetArray(j, kv, sizeof(kv)); prop.insert.GetArray(j, kv, sizeof(kv));
entry.Append(kv.key, kv.val); entry.Append(kv.key, kv.val);
} }
} }
@ -447,29 +445,25 @@ public void RunModifyFilter()
/** /**
* Checks if 2 values match * Checks if 2 values match
* *
* @param val1 First value * @param val1 First value
* @param val2 Second value * @param val2 Second value
* @param isRegex True if val1 should be treated as a regex pattern, false if not * @param isRegex True if val1 should be treated as a regex pattern, false if not
* @return True if match, false otherwise * @return True if match, false otherwise
* *
*/ */
stock bool EntPropsMatch(const char[] val1, const char[] val2, bool isRegex) stock bool EntPropsMatch(const char[] val1, const char[] val2, bool isRegex)
{ {
if (isRegex) return isRegex ? SimpleRegexMatch(val2, val1) > 0 : !strcmp(val1, val2);
{
return SimpleRegexMatch(val2, val1) > 0;
}
return StrEqual(val1, val2);
} }
stock bool FormatRegex(char[] pattern, int len) stock bool FormatRegex(char[] pattern, int len)
{ {
if (pattern[0] == '/' && pattern[len-1] == '/') if(pattern[0] == '/' && pattern[len-1] == '/')
{ {
strcopy(pattern, len-1, pattern[1]); strcopy(pattern, len-1, pattern[1]);
return true; return true;
} }
return false; return false;
} }