From 17b203dbdc0cda1c212e950588cb81caebb489a1 Mon Sep 17 00:00:00 2001 From: Alienmario Date: Mon, 13 May 2024 01:57:45 +0200 Subject: [PATCH] sc_importconfigs command WIP --- scripting/include/srccoop/commands.inc | 171 +++++++++++++++++++++++-- scripting/include/srccoop/utils.inc | 42 +++++- scripting/srccoop.sp | 3 +- 3 files changed, 205 insertions(+), 11 deletions(-) diff --git a/scripting/include/srccoop/commands.inc b/scripting/include/srccoop/commands.inc index 0c26a167..926ba8a1 100644 --- a/scripting/include/srccoop/commands.inc +++ b/scripting/include/srccoop/commands.inc @@ -86,7 +86,7 @@ public Action Command_DumpMapEntities(int iArgs) return Plugin_Handled; } -public Action Command_MakeConfigs(int iArgs) +bool VerifyDefaultMapConfigCvars() { char szBuffer[PLATFORM_MAX_PATH]; @@ -95,7 +95,7 @@ public Action Command_MakeConfigs(int iArgs) { g_pConvarDefaultMapConfig.GetName(szBuffer, sizeof(szBuffer)); MsgSrv("Set \"%s\" before running this command.", szBuffer); - return Plugin_Handled; + return false; } g_pConvarDefaultMapConfigDest.GetString(szBuffer, 2); @@ -103,6 +103,23 @@ public Action Command_MakeConfigs(int iArgs) { g_pConvarDefaultMapConfigDest.GetName(szBuffer, sizeof(szBuffer)); MsgSrv("Set \"%s\" before running this command.", szBuffer); + return false; + } + + return true; +} + +public Action Command_MakeConfigs(int iArgs) +{ + if (iArgs < 1) + { + char szCmd[32]; GetCmdArg(0, szCmd, sizeof(szCmd)); + ServerCommand("help %s", szCmd); + return Plugin_Handled; + } + + if (!VerifyDefaultMapConfigCvars()) + { return Plugin_Handled; } @@ -113,11 +130,14 @@ public Action Command_MakeConfigs(int iArgs) return Plugin_Handled; } - bool bDryRun = !GetCmdArgInt(1); + char szBuffer[PLATFORM_MAX_PATH]; + char szMapFilter[MAX_MAPNAME * 2]; + GetCmdArg(1, szMapFilter, sizeof(szMapFilter)); + bool bDryRun = !GetCmdArgInt(2); int count; FileType ft; CoopConfigLocation ccl; - char szConfigPath[PLATFORM_MAX_PATH]; + char szSrcCoopConfig[PLATFORM_MAX_PATH]; while (dir.GetNext(szBuffer, sizeof(szBuffer), ft)) { @@ -125,11 +145,15 @@ public Action Command_MakeConfigs(int iArgs) if (ft == FileType_File && StrEndsWithEx(szBuffer, len, ".bsp", false)) { szBuffer[len - 4] = EOS; - if (!CoopManager.FindMapConfig(szBuffer, szConfigPath, ccl, false)) + + if (!StrEqualsWildcard(szMapFilter, szBuffer, false)) + continue; + + if (!CoopManager.FindMapConfig(szBuffer, szSrcCoopConfig, ccl, false)) { if (!bDryRun) { - if (!CoopManager.CreateDefaultConfig(szBuffer, szConfigPath)) + if (!CoopManager.CreateDefaultConfig(szBuffer, szSrcCoopConfig)) { dir.Close(); MsgSrv("Aborted processing."); @@ -150,12 +174,141 @@ public Action Command_MakeConfigs(int iArgs) GetCmdArg(0, szBuffer, sizeof(szBuffer)); PrintToServer(""); - MsgSrv("You are about to create %d new map configs.\n Template: %s\n Destination dir: %s\nType %s 1 to continue...\n", - count, szTemplate, szDest, szBuffer); + MsgSrv("You are about to create %d new map configs.\n Template: %s\n Destination dir: %s\nExecute \"%s %s 1\" to continue...\n", + count, szTemplate, szDest, + szBuffer, szMapFilter); } else { - MsgSrv("Success. Created %d configs.", count); + if (count) + MsgSrv("Success. Created %d configs.", count); + else + MsgSrv("No new configs were created!"); } return Plugin_Handled; +} + +public Action Command_ImportConfigs(int iArgs) +{ + if (iArgs < 3) + { + char szCmd[32]; GetCmdArg(0, szCmd, sizeof(szCmd)); + ServerCommand("help %s", szCmd); + return Plugin_Handled; + } + + char szType[32]; + char szMapFilter[MAX_MAPNAME * 2]; + GetCmdArg(1, szType, sizeof(szType)); + GetCmdArg(2, szMapFilter, sizeof(szMapFilter)); + bool bCreateConfigs = !!GetCmdArgInt(3); + bool bDryRun = !GetCmdArgInt(4); + + if (bCreateConfigs && !VerifyDefaultMapConfigCvars()) + { + return Plugin_Handled; + } + + int count, createdCount, errors; + if (StrEqual(szType, "stripper", false)) + { + Command_ImportConfigs_Stripper(szMapFilter, bCreateConfigs, bDryRun, count, createdCount, errors); + } + else + { + MsgSrv("Unsupported import type: \"%s\"", szType); + return Plugin_Handled; + } + + if (count < 0) + { + return Plugin_Handled; + } + + if (bDryRun) + { + char szCmd[32]; GetCmdArg(0, szCmd, sizeof(szCmd)); + + PrintToServer(""); + MsgSrv("You are about to import %d %s configs (of which %d will be created).\nExecute \"%s %s %s %d 1\" to continue...\n", + count, szType, createdCount, + szCmd, szType, szMapFilter, bCreateConfigs); + } + else + { + MsgSrv("Import finished.\n Total imported: %d\n New configs: %d\n Errors: %d", count, createdCount, errors); + } + + return Plugin_Handled; +} + +void Command_ImportConfigs_Stripper(const char[] szMapFilter, bool bCreate, bool bDryRun, int &count, int &createdCount, int &errors) +{ + static const char szStripperMapsDir[] = "addons/stripper/maps"; + DirectoryListing dir = OpenDirectory(szStripperMapsDir, false); + if (!dir) + { + MsgSrv("Unable to enumerate \"%s\" folder.", szStripperMapsDir); + count = -1; + return; + } + + FileType ft; + CoopConfigLocation ccl; + char szBuffer[PLATFORM_MAX_PATH]; + char szSrcCoopConfig[PLATFORM_MAX_PATH]; + char szError[128]; + + while (dir.GetNext(szBuffer, sizeof(szBuffer), ft)) + { + int len = strlen(szBuffer); + if (ft == FileType_File && StrEndsWithEx(szBuffer, len, ".cfg", false)) + { + szBuffer[len - 4] = EOS; + if (!StrEqualsWildcard(szMapFilter, szBuffer, false)) + continue; + + bool bCreatedDefault; + if (!CoopManager.FindMapConfig(szBuffer, szSrcCoopConfig, ccl, false)) + { + if (!bCreate) + { + MsgSrv("Found stripper config for \"%s\", but no SourceCoop config. Run with set to 1 to remedy this.", szBuffer); + continue; + } + if (!bDryRun && !CoopManager.CreateDefaultConfig(szBuffer, szSrcCoopConfig)) + { + MsgSrv("Aborted processing."); + dir.Close(); + count = -1; + return; + } + bCreatedDefault = true; + } + + Format(szBuffer, sizeof(szBuffer), "%s/%s.cfg", szStripperMapsDir, szBuffer); + if (bDryRun || ImportStripperConfig(szBuffer, szSrcCoopConfig, szError, sizeof(szError))) + { + count++; + if (bCreatedDefault) + createdCount++; + } + else + { + errors++; + MsgSrv("Error in importing stripper config from \"%s\" to \"%s\":\n%s", szBuffer, szSrcCoopConfig, szError); + if (bCreatedDefault) + { + MsgSrv("Cleaning up."); + DeleteFile(szSrcCoopConfig); + } + } + } + } + dir.Close(); +} + +bool ImportStripperConfig(const char[] szStripperConfig, const char[] szSrcCoopConfig, char[] szError, int maxErrorLen) +{ + return true; } \ No newline at end of file diff --git a/scripting/include/srccoop/utils.inc b/scripting/include/srccoop/utils.inc index cff7e95b..05043990 100644 --- a/scripting/include/srccoop/utils.inc +++ b/scripting/include/srccoop/utils.inc @@ -387,7 +387,47 @@ stock bool StrEqualsRegex(const char[] pattern, const char[] str, bool caseSensi } return strcmp(pattern, str, caseSensitive) == 0; } -#endif + +/** + * Simple * wildcard pattern matching. Best for comparing map names, file names (think gitignore), etc. + */ +stock bool StrEqualsWildcard(const char[] pattern, const char[] str, bool caseSensitive = false) +{ + int regexLen = strlen(pattern) * 2 + 3; + char[] regex = new char[regexLen]; + + EscapeRegex(pattern, regex, regexLen, "*"); + ReplaceString(regex, regexLen, "*", ".*"); + Format(regex, regexLen, "^%s$", regex); + + int substrings = SimpleRegexMatch(str, regex, caseSensitive? 0 : PCRE_CASELESS); + return (substrings > 0); +} + +/** + * Quotes / escapes all special regex characters in a string. + * @param allowedChars Characters that should not be escaped. + * @return characters written + */ +stock int EscapeRegex(const char[] str, char[] dest, int destLen, const char[] allowedChars = "") +{ + static const char specialChars[] = ".\\+*?[^]$(){}=!<>|:-#"; + int i, j; + while (str[i] != EOS && (j + 1) < destLen) + { + if (FindCharInString(specialChars, str[i]) != -1 && FindCharInString(allowedChars, str[i]) == -1) + { + if (j + 2 >= destLen) + break; + dest[j++] = '\\'; + } + dest[j++] = str[i++]; + } + dest[j] = EOS; + return j; +} + +#endif // defined _regex_included stock void FormatTimeLength(int seconds, char[] out, int size) { diff --git a/scripting/srccoop.sp b/scripting/srccoop.sp index 4139d0c3..e1f54c38 100644 --- a/scripting/srccoop.sp +++ b/scripting/srccoop.sp @@ -222,7 +222,8 @@ public void OnPluginStart() RegAdminCmd("sc_ft", Command_SetFeature, ADMFLAG_ROOT, "Command for toggling plugin features on/off"); RegServerCmd("sourcecoop_dump", Command_DumpMapEntities, "Command for dumping map entities to a file"); RegServerCmd("sc_dump", Command_DumpMapEntities, "Command for dumping map entities to a file"); - RegServerCmd("sc_mkconfigs", Command_MakeConfigs, "Creates default edt configs for all maps in the maps directory which are missing one"); + RegServerCmd("sc_mkconfigs", Command_MakeConfigs, "Creates default SourceCoop configs for maps found in the maps directory, which are missing one.\n - Format: sc_mkconfigs [CONFIRM]\n MAPFILTER: filters the map names to include; use * for all; supports wildcards with * such as coop_*\n CONFIRM: [0 = dry run, 1 = live run]"); + RegServerCmd("sc_importconfigs", Command_ImportConfigs, "Imports other formats of map configs into SourceCoop configs.\n - Format: sc_importconfigs [CONFIRM]\n TYPE: The type of config to import, values: [stripper = Stripper:source]\n MAPFILTER: filters the map names to import; use * for all; supports wildcards with * such as coop_*\n CREATE: [1 = attempts to create default SourceCoop config for the map if it's missing, 0 = prints a warning and skips if missing]\n CONFIRM: [0 = dry run, 1 = live run]"); g_pLevelLump.Initialize(); CCoopSpawnSystem.Initialize();