From c0518c5a24a557c92f99c446f7f3316d07b323f4 Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Sat, 20 Dec 2025 10:56:11 +0100 Subject: [PATCH] auto update EAC from github + simplifications --- Main.cs | 2 +- Modules/BanManager.cs | 53 +++++++++++++++++++++++++++++------ Modules/CustomSabotage.cs | 4 +-- Modules/Debugger.cs | 2 +- Modules/DevManager.cs | 2 +- Modules/EAC.cs | 6 ++-- Modules/GuessManager.cs | 2 +- Modules/LobbySharingAPI.cs | 4 +-- Modules/ModUpdater.cs | 6 ++-- Modules/PetsHelper.cs | 2 +- Modules/Translator.cs | 4 +-- Modules/Utils.cs | 16 ++++------- Patches/ChatCommandPatch.cs | 12 ++++---- Patches/ExilePatch.cs | 14 +++++---- Patches/HudPatch.cs | 2 +- Patches/PlayerControlPatch.cs | 8 +++--- Roles/Crewmate/Doorjammer.cs | 2 +- Roles/Crewmate/Enigma.cs | 2 +- Roles/RoleBase.cs | 2 +- 19 files changed, 89 insertions(+), 56 deletions(-) diff --git a/Main.cs b/Main.cs index e09ff6dea..d03264461 100644 --- a/Main.cs +++ b/Main.cs @@ -921,7 +921,7 @@ public class Main : BasePlugin try { string json = File.ReadAllText(path); - if (string.IsNullOrEmpty(json) || json == serialized || json.Length < serialized.Length) return; + if (string.IsNullOrWhiteSpace(json) || json == serialized || json.Length < serialized.Length) return; var deserialized = JsonSerializer.Deserialize>(json); RoleColors = deserialized.ToDictionary(x => Enum.Parse(x.Key), x => x.Value); } diff --git a/Modules/BanManager.cs b/Modules/BanManager.cs index a00e6700b..676867b9e 100644 --- a/Modules/BanManager.cs +++ b/Modules/BanManager.cs @@ -9,6 +9,7 @@ using System.Text.RegularExpressions; using HarmonyLib; using InnerNet; using UnityEngine; +using UnityEngine.Networking; using static EHR.Translator; namespace EHR; @@ -52,17 +53,51 @@ public static class BanManager Logger.Warn("Creating a new WhiteList.txt file", "BanManager"); File.Create(WhiteListListPath).Close(); } + + Main.Instance.StartCoroutine(LoadEACList()); - // Read EAC List - Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("EHR.Resources.Config.EACList.txt")!; - stream.Position = 0; - using StreamReader sr = new(stream, Encoding.UTF8); - - while (sr.ReadLine() is { } line) + static System.Collections.IEnumerator LoadEACList() { - if (line == "" || line.StartsWith("#")) continue; + EACList.Clear(); - EACList.Add(line); + UnityWebRequest request = UnityWebRequest.Get("https://raw.githubusercontent.com/Gurge44/EndlessHostRoles/main/Resources/Config/EACList.txt"); + request.timeout = 5; + request.SetRequestHeader("User-Agent", $"{Main.ModName} v{Main.PluginVersion}"); + + yield return request.SendWebRequest(); + + if (request.result == UnityWebRequest.Result.Success && !string.IsNullOrWhiteSpace(request.downloadHandler.text)) + { + using StringReader reader = new(request.downloadHandler.text); + + while (reader.ReadLine() is { } line) + { + line = line.Trim(); + if (line.Length == 0 || line.StartsWith("#")) continue; + + EACList.Add(line); + } + + Logger.Info("EAC list loaded from GitHub", "BanManager"); + yield break; + } + + Logger.Warn($"Failed to load EAC list from GitHub, falling back to local copy: {request.error}", "BanManager"); + + // Fallback: embedded resource + Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("EHR.Resources.Config.EACList.txt")!; + stream.Position = 0; + using StreamReader sr = new(stream, Encoding.UTF8); + + while (sr.ReadLine() is { } line) + { + line = line.Trim(); + if (line == "" || line.StartsWith("#")) continue; + + EACList.Add(line); + } + + Logger.Info("EAC list loaded from embedded resource", "BanManager"); } } catch (Exception ex) { Logger.Exception(ex, "BanManager"); } @@ -99,7 +134,7 @@ public static class BanManager if (!CheckBanList(friendCode, hashedPuid) && !TempBanWhiteList.Contains(hashedPuid)) { - if (!string.IsNullOrEmpty(hashedPuid)) + if (!string.IsNullOrWhiteSpace(hashedPuid)) { File.AppendAllText(BanListPath, $"{friendCode},{hashedPuid},{player.PlayerName.RemoveHtmlTags()}\n"); Logger.SendInGame(string.Format(GetString("Message.AddedPlayerToBanList"), player.PlayerName), Color.yellow); diff --git a/Modules/CustomSabotage.cs b/Modules/CustomSabotage.cs index dcf9378fc..76ff14085 100644 --- a/Modules/CustomSabotage.cs +++ b/Modules/CustomSabotage.cs @@ -59,9 +59,9 @@ public abstract class CustomSabotage foreach (CustomSabotage sabotage in Instances) { - string tempSuffix = sabotage.GetSuffix(seer, target, hud, meeting).Trim(); + string tempSuffix = sabotage.GetSuffix(seer, target, hud, meeting); - if (!string.IsNullOrEmpty(tempSuffix)) + if (!string.IsNullOrWhiteSpace(tempSuffix)) suffix.Append($"{tempSuffix}\n"); } diff --git a/Modules/Debugger.cs b/Modules/Debugger.cs index c99a68f5f..097e4adba 100644 --- a/Modules/Debugger.cs +++ b/Modules/Debugger.cs @@ -255,7 +255,7 @@ public class CustomLogger public void Finish(bool dump = true) { var append = Builder.ToString(); - if (string.IsNullOrEmpty(append.Trim())) return; + if (string.IsNullOrWhiteSpace(append)) return; if (dump) append += HtmlFooter; File.AppendAllText(LOGFilePath, append); PrivateInstance = null; diff --git a/Modules/DevManager.cs b/Modules/DevManager.cs index 700f77548..700e0e8b5 100644 --- a/Modules/DevManager.cs +++ b/Modules/DevManager.cs @@ -72,7 +72,7 @@ public static class DevManager public bool HasTag() { - return !string.IsNullOrEmpty(tag_name); + return !string.IsNullOrWhiteSpace(tag_name); } public string GetTag() diff --git a/Modules/EAC.cs b/Modules/EAC.cs index 9faa8c74a..bee24ec16 100644 --- a/Modules/EAC.cs +++ b/Modules/EAC.cs @@ -677,7 +677,7 @@ internal static class EAC string secondString = sr.ReadString(); sr.ReadInt32(); - bool flag = string.IsNullOrEmpty(firstString) && string.IsNullOrEmpty(secondString); + bool flag = string.IsNullOrWhiteSpace(firstString) && string.IsNullOrWhiteSpace(secondString); if (!flag) { @@ -731,7 +731,7 @@ internal static class EAC string firstString = sr.ReadString(); string secondString = sr.ReadString(); sr.ReadInt32(); - bool flag = string.IsNullOrEmpty(firstString) && string.IsNullOrEmpty(secondString); + bool flag = string.IsNullOrWhiteSpace(firstString) && string.IsNullOrWhiteSpace(secondString); if (!flag) { @@ -1289,7 +1289,7 @@ internal static class GameDataHandlerPatch return false; } - if (string.IsNullOrEmpty(scene)) + if (string.IsNullOrWhiteSpace(scene)) { Logger.Warn($"Client {client.PlayerName} ({client.Id}) tried to send SceneChangeFlag with null scene.", "GameDataHandlerPatch"); EAC.WarnHost(); diff --git a/Modules/GuessManager.cs b/Modules/GuessManager.cs index 31e67d215..943a89d5c 100644 --- a/Modules/GuessManager.cs +++ b/Modules/GuessManager.cs @@ -1306,7 +1306,7 @@ public static class GuessManager if (!NetIdToRawDisplay.TryGetValue(target.NetId, out display)) display = string.Empty; - if (string.IsNullOrEmpty(display)) + if (string.IsNullOrWhiteSpace(display)) { Reset(); return false; diff --git a/Modules/LobbySharingAPI.cs b/Modules/LobbySharingAPI.cs index 2439d5b9b..84139620d 100644 --- a/Modules/LobbySharingAPI.cs +++ b/Modules/LobbySharingAPI.cs @@ -23,7 +23,7 @@ public static class LobbySharingAPI if (gameId == 32) return; string roomCode = GameCode.IntToGameName(gameId); - if (roomCode == LastRoomCode || roomCode.IsNullOrWhiteSpace() || string.IsNullOrEmpty(roomCode)) return; + if (roomCode == LastRoomCode || string.IsNullOrWhiteSpace(roomCode)) return; LastRoomCode = roomCode; int modLanguage = Options.ModLanguage.GetValue(); @@ -105,7 +105,7 @@ public static class LobbySharingAPI private static IEnumerator SendLobbyStatusChangedRequest(string roomCode, string newStatus, int players, string map, string gameMode) { - if (string.IsNullOrEmpty(Token)) yield break; + if (string.IsNullOrWhiteSpace(Token)) yield break; long timeSinceLastRequest = Utils.TimeStamp - LastRequestTimeStamp; if (timeSinceLastRequest < BufferTime) yield return new WaitForSeconds(BufferTime); diff --git a/Modules/ModUpdater.cs b/Modules/ModUpdater.cs index bd26da064..2728fed99 100644 --- a/Modules/ModUpdater.cs +++ b/Modules/ModUpdater.cs @@ -65,7 +65,7 @@ public static class ModUpdater { FirstNotify = false; - if (!string.IsNullOrEmpty(LatestTitleModName)) + if (!string.IsNullOrWhiteSpace(LatestTitleModName)) ShowPopupWithTwoButtons(string.Format(GetString("NewUpdateAvailable"), LatestTitleModName), GetString("updateButton"), onClickOnFirstButton: () => StartUpdate(DownloadUrl, true)); } } @@ -146,7 +146,7 @@ public static class ModUpdater Logger.Info("latestVersionl: " + LatestVersion, "GitHub"); Logger.Info("latestTitle: " + LatestTitle, "GitHub"); - if (string.IsNullOrEmpty(DownloadUrl)) + if (string.IsNullOrWhiteSpace(DownloadUrl)) { Logger.Error("No Download URL", "CheckRelease"); return false; @@ -361,7 +361,7 @@ public static class ModUpdater var secondButtonGetChild = secondButton.GetChild(0); secondButtonGetChild.GetComponent().TargetText = StringNames.Cancel; secondButtonGetChild.GetComponent().ResetText(); - if (!string.IsNullOrEmpty(secondButtonText)) + if (!string.IsNullOrWhiteSpace(secondButtonText)) { secondButtonGetChild.GetComponent().DestroyTranslator(); secondButtonGetChild.GetComponent().text = secondButtonText; diff --git a/Modules/PetsHelper.cs b/Modules/PetsHelper.cs index e1b687434..24101a347 100644 --- a/Modules/PetsHelper.cs +++ b/Modules/PetsHelper.cs @@ -32,6 +32,6 @@ public static class PetsHelper string[] pets = Options.PetToAssign; string pet = pets[Options.PetToAssignToEveryone.GetValue()]; string petId = pet == "pet_RANDOM_FOR_EVERYONE" ? pets[IRandom.Instance.Next(0, pets.Length - 1)] : pet; - return string.IsNullOrEmpty(petId.Trim()) ? "pet_test" : petId; + return string.IsNullOrWhiteSpace(petId.Trim()) ? "pet_test" : petId; } } \ No newline at end of file diff --git a/Modules/Translator.cs b/Modules/Translator.cs index 2cf2b096e..d6dba7713 100644 --- a/Modules/Translator.cs +++ b/Modules/Translator.cs @@ -161,11 +161,11 @@ public static class Translator public static string GetString(string str, SupportedLangs langId) { - var res = $""; + var res = $"*{str}"; try { - if (TranslateMaps.TryGetValue(str, out Dictionary dic) && (!dic.TryGetValue((int)langId, out res) || string.IsNullOrEmpty(res) || (langId is not SupportedLangs.SChinese and not SupportedLangs.TChinese && Regex.IsMatch(res, @"[\u4e00-\u9fa5]") && res == GetString(str, SupportedLangs.SChinese)))) + if (TranslateMaps.TryGetValue(str, out Dictionary dic) && (!dic.TryGetValue((int)langId, out res) || string.IsNullOrWhiteSpace(res) || (langId is not SupportedLangs.SChinese and not SupportedLangs.TChinese && Regex.IsMatch(res, @"[\u4e00-\u9fa5]") && res == GetString(str, SupportedLangs.SChinese)))) res = langId == SupportedLangs.English ? $"*{str}" : GetString(str, SupportedLangs.English); if (!TranslateMaps.ContainsKey(str) && Enum.GetValues().FindFirst(x => x.ToString() == str, out StringNames stringNames)) diff --git a/Modules/Utils.cs b/Modules/Utils.cs index c90392307..edac9a5c6 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -2379,9 +2379,9 @@ public static class Utils foreach (PlayerState state in Main.PlayerStates.Values) { - string tempSuffix = state.Role.GetSuffix(seer, target, hud, meeting).Trim(); + string tempSuffix = state.Role.GetSuffix(seer, target, hud, meeting); - if (!string.IsNullOrEmpty(tempSuffix)) + if (!string.IsNullOrWhiteSpace(tempSuffix)) suffix.Append($"{tempSuffix}\n"); } @@ -2537,11 +2537,7 @@ public static class Utils SelfSuffix.Append(BuildSuffix(seer, seer, meeting: forMeeting)); - foreach (var suffix in new[] { Spurt.GetSuffix(seer), Dynamo.GetSuffix(seer), CustomTeamManager.GetSuffix(seer) }) - { - var trimmedSuffix = suffix.Trim(); - if (!string.IsNullOrEmpty(trimmedSuffix)) SelfSuffix.Append("\n" + trimmedSuffix); - } + new[] { Spurt.GetSuffix(seer), Dynamo.GetSuffix(seer), CustomTeamManager.GetSuffix(seer) }.DoIf(x => !string.IsNullOrWhiteSpace(x), x => SelfSuffix.Append("\n" + x)); if (!forMeeting) { @@ -2640,7 +2636,7 @@ public static class Utils break; } - List addSuff = additionalSuffixes.ConvertAll(x => x.Trim()).FindAll(x => !string.IsNullOrEmpty(x)); + List addSuff = additionalSuffixes.FindAll(x => !string.IsNullOrWhiteSpace(x)); if (addSuff.Count > 0) { @@ -2993,7 +2989,7 @@ public static class Utils break; } - if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrEmpty(target.FriendCode) && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.FFA or CustomGameMode.Speedrun) + if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrWhiteSpace(target.FriendCode) && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.FFA or CustomGameMode.Speedrun) additionalSuffixes.Add(GetString("DiedR1Warning")); if (!forMeeting) @@ -3004,7 +3000,7 @@ public static class Utils TargetSuffix.Append(BuildSuffix(seer, target, meeting: forMeeting)); - List addSuff = additionalSuffixes.ConvertAll(x => x.Trim()).FindAll(x => !string.IsNullOrEmpty(x)); + List addSuff = additionalSuffixes.FindAll(x => !string.IsNullOrWhiteSpace(x)); if (addSuff.Count > 0) { diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index f95f2f516..cd1771324 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -427,7 +427,7 @@ internal static class ChatCommands if (CheckMute(PlayerControl.LocalPlayer.PlayerId)) goto Canceled; - if (text.IsNullOrWhiteSpace() || string.IsNullOrEmpty(text)) + if (string.IsNullOrWhiteSpace(text)) goto Canceled; goto Skip; @@ -585,7 +585,7 @@ internal static class ChatCommands if (args.Length >= 2) { string uuid = args[1].Trim(); - if (string.IsNullOrEmpty(uuid)) return; + if (string.IsNullOrWhiteSpace(uuid)) return; Main.Instance.StartCoroutine(SendVerificationCoroutine(uuid)); } @@ -598,13 +598,13 @@ internal static class ChatCommands string puid = player.GetClient().ProductUserId; var gameId = AmongUsClient.Instance.GameId.ToString(); - if (string.IsNullOrEmpty(friendCode) || string.IsNullOrEmpty(puid)) + if (string.IsNullOrWhiteSpace(friendCode) || string.IsNullOrWhiteSpace(puid)) { Logger.Error($" Missing friendcode/puid for player {player.PlayerId}", "ConfirmAuth"); yield break; } - if (string.IsNullOrEmpty(gameId) || gameId == "32") + if (string.IsNullOrWhiteSpace(gameId) || gameId == "32") { Logger.Error(" Invalid GameId", "ConfirmAuth"); yield break; @@ -2163,7 +2163,7 @@ internal static class ChatCommands string subArgs = args.Length < 2 ? string.Empty : args[1]; - if (string.IsNullOrEmpty(subArgs) || !byte.TryParse(subArgs, out byte kickPlayerId)) + if (string.IsNullOrWhiteSpace(subArgs) || !byte.TryParse(subArgs, out byte kickPlayerId)) { Utils.SendMessage(GetString("KickCommandInvalidID"), player.PlayerId, sendOption: SendOption.None); return; @@ -2204,7 +2204,7 @@ internal static class ChatCommands if (!File.Exists(modLogFilePath)) { string directoryName = Path.GetDirectoryName(modLogFilePath); - if (!string.IsNullOrEmpty(directoryName)) Directory.CreateDirectory(directoryName); + if (!string.IsNullOrWhiteSpace(directoryName)) Directory.CreateDirectory(directoryName); File.WriteAllText(modLogFilePath, "=== Moderation Log ===\n"); } diff --git a/Patches/ExilePatch.cs b/Patches/ExilePatch.cs index 10008bb05..02c412363 100644 --- a/Patches/ExilePatch.cs +++ b/Patches/ExilePatch.cs @@ -109,14 +109,16 @@ internal static class ExileControllerWrapUpPatch } if (exiled == null) return; - byte id = exiled.PlayerId; + PlayerControl exiledPlayer = exiled.Object; LateTask.New(() => { - if (GameStates.IsEnded) return; - PlayerControl player = id.GetPlayer(); - if (player != null) Utils.AfterPlayerDeathTasks(player, true); - }, 2.5f, "AfterPlayerDeathTasks For Exiled Player"); + if (!GameStates.IsEnded && exiledPlayer != null) + { + exiledPlayer.RpcExileV2(); + Utils.AfterPlayerDeathTasks(exiledPlayer, true); + } + }, 3.5f, "AfterPlayerDeathTasks For Exiled Player"); } public static void WrapUpFinalizer() @@ -151,7 +153,7 @@ internal static class ExileControllerWrapUpPatch string finalText = ejectionNotify ? "<#ffffff>" + CheckForEndVotingPatch.EjectionText.Trim() : text; if (Options.EnableGameTimeLimit.GetBool()) finalText += $"\n<#888888>{Options.GameTimeLimit.GetInt() - Main.GameTimer:N0}s {Translator.GetString("RemainingText.Suffix")}"; - if (!string.IsNullOrEmpty(finalText)) + if (!string.IsNullOrWhiteSpace(finalText)) Main.AllAlivePlayerControls.NotifyPlayers(finalText, 13f); } diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 6b0335072..b6910ae40 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -293,7 +293,7 @@ internal static class HudManagerPatch CustomRoles.Deadlined => Deadlined.GetSuffix(player, true), CustomRoles.Introvert => Introvert.GetSelfSuffix(player), _ => string.Empty - }).Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x)).ToArray(); + }).Where(x => !string.IsNullOrWhiteSpace(x)).ToArray(); return suffixes.Length > 0 ? $"\n{string.Join('\n', suffixes)}" diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index 90e0842ff..657a32ce1 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -568,7 +568,7 @@ internal static class CheckMurderPatch return false; } - if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrEmpty(target.FriendCode)) + if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrWhiteSpace(target.FriendCode)) { Main.ShieldPlayer = string.Empty; killer.SetKillCooldown(15f); @@ -1468,7 +1468,7 @@ internal static class FixedUpdatePatch long now = TimeStamp; string nameWithRole = __instance.GetNameWithRole(); - if (string.IsNullOrEmpty(nameWithRole.Trim())) return; + if (string.IsNullOrWhiteSpace(nameWithRole)) return; if (LastErrorTS != now) { @@ -1983,10 +1983,10 @@ internal static class FixedUpdatePatch break; } - if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrEmpty(target.FriendCode) && !self && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.SoloPVP or CustomGameMode.FFA) + if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrWhiteSpace(target.FriendCode) && !self && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.SoloPVP or CustomGameMode.FFA) additionalSuffixes.Add(GetString("DiedR1Warning")); - List addSuff = additionalSuffixes.ConvertAll(x => x.Trim()).FindAll(x => !string.IsNullOrEmpty(x)); + List addSuff = additionalSuffixes.FindAll(x => !string.IsNullOrWhiteSpace(x)); if (addSuff.Count > 0) { diff --git a/Roles/Crewmate/Doorjammer.cs b/Roles/Crewmate/Doorjammer.cs index 9122ec8c2..cb428d328 100644 --- a/Roles/Crewmate/Doorjammer.cs +++ b/Roles/Crewmate/Doorjammer.cs @@ -88,6 +88,6 @@ public class Doorjammer : RoleBase { if (seer.PlayerId != DoorjammerId || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || meeting) return string.Empty; string join = string.Join(", ", JammedRooms.ConvertAll(x => Translator.GetString(x.ToString()))); - return string.Format(Translator.GetString("Doorjammer.Suffix"), JammedRooms.Count, MaxRoomsJammedAtOnce.GetInt(), string.IsNullOrEmpty(join.Trim()) ? string.Empty : $"\n{join}"); + return string.Format(Translator.GetString("Doorjammer.Suffix"), JammedRooms.Count, MaxRoomsJammedAtOnce.GetInt(), string.IsNullOrWhiteSpace(join) ? string.Empty : $"\n{join}"); } } \ No newline at end of file diff --git a/Roles/Crewmate/Enigma.cs b/Roles/Crewmate/Enigma.cs index 508ecb91c..a90016c62 100644 --- a/Roles/Crewmate/Enigma.cs +++ b/Roles/Crewmate/Enigma.cs @@ -280,7 +280,7 @@ public class Enigma : RoleBase { var letter2 = string.Empty; string tmpName = killerName.Replace(letter, string.Empty); - if (!string.IsNullOrEmpty(tmpName)) letter2 = tmpName.Where(char.IsLetter).RandomElement().ToString().ToLower(); + if (!string.IsNullOrWhiteSpace(tmpName)) letter2 = tmpName.Where(char.IsLetter).RandomElement().ToString().ToLower(); return string.Format(GetString("EnigmaClueName3"), letter, letter2); } diff --git a/Roles/RoleBase.cs b/Roles/RoleBase.cs index 9022b4413..96ca96cd5 100644 --- a/Roles/RoleBase.cs +++ b/Roles/RoleBase.cs @@ -241,7 +241,7 @@ public class OptionSetupHandler(int id, TabGroup tab, CustomRoles role) { try { - bool generalOption = !Translator.GetString(fieldName).Contains("INVALID"); + bool generalOption = !Translator.GetString(fieldName).StartsWith('*'); string name = overrideName == "" ? generalOption ? fieldName : $"{role}.{fieldName}" : overrideName; field = (valueRule, defaultValue) switch