diff --git a/EHR.csproj b/EHR.csproj index 8656a47ce..32f8bd2b2 100644 --- a/EHR.csproj +++ b/EHR.csproj @@ -33,7 +33,7 @@ - + diff --git a/Gamemodes/CaptureTheFlag.cs b/Gamemodes/CaptureTheFlag.cs index f4fbaec6d..4e696cf58 100644 --- a/Gamemodes/CaptureTheFlag.cs +++ b/Gamemodes/CaptureTheFlag.cs @@ -326,6 +326,8 @@ public static class CaptureTheFlag if (pc && outfit != null) Utils.RpcChangeSkin(pc, outfit); } + + DefaultOutfits = []; } } diff --git a/Gamemodes/CustomHnS.cs b/Gamemodes/CustomHnS.cs index a0cd9fb98..fa443469a 100644 --- a/Gamemodes/CustomHnS.cs +++ b/Gamemodes/CustomHnS.cs @@ -174,7 +174,7 @@ internal static class CustomHnS } } - Dictionary playerTeams =Main.TeamValues[1..4] + Dictionary playerTeams = Main.TeamValues[1..4] .SelectMany(x => Enumerable.Repeat(x, Math.Max(memberNum[x], 0))) .Shuffle() .Zip(allPlayers) diff --git a/Gamemodes/KingOfTheZones.cs b/Gamemodes/KingOfTheZones.cs index 4d2261cdc..2f679c0b6 100644 --- a/Gamemodes/KingOfTheZones.cs +++ b/Gamemodes/KingOfTheZones.cs @@ -664,7 +664,11 @@ public static class KingOfTheZones } } - void ResetSkins() => DefaultOutfits.Select(x => (pc: x.Key.GetPlayer(), outfit: x.Value)).DoIf(x => x.pc && x.outfit != null, x => Utils.RpcChangeSkin(x.pc, x.outfit)); + void ResetSkins() + { + DefaultOutfits.Select(x => (pc: x.Key.GetPlayer(), outfit: x.Value)).DoIf(x => x.pc && x.outfit != null, x => Utils.RpcChangeSkin(x.pc, x.outfit)); + DefaultOutfits = []; + } } public static bool IsNotInLocalPlayersTeam(PlayerControl pc) diff --git a/Gamemodes/TheMindGame.cs b/Gamemodes/TheMindGame.cs index eb4cf0fe7..d7da0468e 100644 --- a/Gamemodes/TheMindGame.cs +++ b/Gamemodes/TheMindGame.cs @@ -14,7 +14,6 @@ public static class TheMindGame { private static Dictionary Points = []; private static Dictionary SuperPoints = []; - private static Dictionary DefaultColorIds = []; private static Dictionary Groups = []; private static Dictionary> GroupPlayers = []; private static List AllRooms = []; @@ -276,7 +275,7 @@ public static class TheMindGame var pcCount = aapc.Count; Points = aapc.ToDictionary(x => x.PlayerId, _ => 0); SuperPoints = aapc.ToDictionary(x => x.PlayerId, _ => 0); - DefaultColorIds = aapc.ToDictionary(x => x, x => x.Data.DefaultOutfit.ColorId); + aapc.ToDictionary(x => x, x => x.Data.DefaultOutfit.ColorId); PlayerItems = aapc.ToDictionary(x => x.PlayerId, _ => new List()); Groups = []; diff --git a/Main.cs b/Main.cs index a8fda79bd..e4f168461 100644 --- a/Main.cs +++ b/Main.cs @@ -1060,6 +1060,12 @@ public class Main : BasePlugin catch (Exception e) { Utils.ThrowException(e); } } + public Coroutine StartCoroutine(Il2CppSystem.Collections.IEnumerator coroutine) + { + if (coroutine == null) return null; + return coroutines.StartCoroutine(coroutine); + } + public Coroutine StartCoroutine(IEnumerator coroutine) { if (coroutine == null) return null; diff --git a/Modules/Camouflage.cs b/Modules/Camouflage.cs index 40b6719d1..03fa61625 100644 --- a/Modules/Camouflage.cs +++ b/Modules/Camouflage.cs @@ -46,7 +46,6 @@ public static class Camouflage public static bool IsCamouflage; public static bool BlockCamouflage; public static Dictionary PlayerSkins = []; - public static List ResetSkinAfterDeathPlayers = []; private static HashSet WaitingForSkinChange = []; private static int SkippedCamoTimes; @@ -57,7 +56,6 @@ public static class Camouflage { IsCamouflage = false; PlayerSkins = []; - ResetSkinAfterDeathPlayers = []; WaitingForSkinChange = []; SkippedCamoTimes = 0; diff --git a/Modules/CustomRpcSender.cs b/Modules/CustomRpcSender.cs index a96e65a12..1ef1f2b73 100644 --- a/Modules/CustomRpcSender.cs +++ b/Modules/CustomRpcSender.cs @@ -969,8 +969,10 @@ static class PreventLargePacketKickPatch public static bool Prefix([HarmonyArgument(0)] MessageWriter msg) { if (msg.Length <= 1200) return true; - - if (GameStates.CurrentServerType is GameStates.ServerType.Local or GameStates.ServerType.Vanilla) + + var serverType = GameStates.CurrentServerType; + + if (serverType is GameStates.ServerType.Local or GameStates.ServerType.Vanilla || (serverType == GameStates.ServerType.Niko && msg.Length > 1400)) { Logger.Warn($" Blocked large packet from sending (size: {msg.Length})", nameof(PreventLargePacketKickPatch)); return false; diff --git a/Modules/Extensions/CollectionExtensions.cs b/Modules/Extensions/CollectionExtensions.cs index e6ce440dd..1554f98f6 100644 --- a/Modules/Extensions/CollectionExtensions.cs +++ b/Modules/Extensions/CollectionExtensions.cs @@ -457,13 +457,7 @@ public static class CollectionExtensions foreach (PlayerControl player in players) { hasValue |= sender.Notify(player, text, time, overrideAll, log, setName); - - if (sender.stream.Length > 500) - { - sender.SendMessage(); - sender = CustomRpcSender.Create("NotifyPlayers", SendOption.Reliable); - hasValue = false; - } + // RpcSetName will handle oversized packets } sender.SendMessage(dispose: !hasValue); @@ -475,15 +469,8 @@ public static class CollectionExtensions for (int index = 0; index < players.Count; index++) { - PlayerControl player = players[index]; - hasValue |= sender.Notify(player, text, time, overrideAll, log, setName); - - if (sender.stream.Length > 500) - { - sender.SendMessage(); - sender = CustomRpcSender.Create("NotifyPlayers", SendOption.Reliable); - hasValue = false; - } + hasValue |= sender.Notify(players[index], text, time, overrideAll, log, setName); + // RpcSetName will handle oversized packets } sender.SendMessage(dispose: !hasValue); diff --git a/Modules/OnlinePresetsManager.cs b/Modules/OnlinePresetsManager.cs index ee0a5d94a..9effbb7ab 100644 --- a/Modules/OnlinePresetsManager.cs +++ b/Modules/OnlinePresetsManager.cs @@ -14,20 +14,25 @@ namespace EHR.Modules; public static class OnlinePresetsManager { + private static readonly Dictionary OptionBehaviourCache = []; + private static readonly Dictionary HeaderCache = []; public static List CachedPresets = []; public static bool PresetsLoaded = false; - public static IEnumerator CreatePresetExplorerUI(GameOptionsMenu menu) + public static void CreatePresetExplorerUI(GameOptionsMenu menu) { + if (!PresetsLoaded) return; + float y = 2.0f; { - CategoryHeaderMasked header = ModGameOptionsMenu.Track(Object.Instantiate( + CategoryHeaderMasked header = HeaderCache.TryGetValue(0, out CategoryHeaderMasked cache) ? cache : ModGameOptionsMenu.Track(Object.Instantiate( menu.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer )); + HeaderCache[0] = header; header.SetHeader(StringNames.RolesCategory, 20); header.Title.DestroyTranslator(); @@ -37,11 +42,11 @@ public static class OnlinePresetsManager y -= 0.8f; - StringOption upload = ModGameOptionsMenu.Track(Object.Instantiate(menu.stringOptionOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer)); + StringOption upload = OptionBehaviourCache.TryGetValue(-1, out StringOption uploadCache) ? uploadCache : ModGameOptionsMenu.Track(Object.Instantiate(menu.stringOptionOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer)); upload.name = nameof(OnlinePresetsManager) + ";" + Translator.GetString("UploadPreset"); upload.transform.localPosition = new Vector3(0.952f, y, -2f); upload.SetClickMask(menu.ButtonClickMask); - upload.SetUpFromData(ScriptableObject.CreateInstance(), 20); + upload.SetUpFromData(null, 20); Object.Destroy(upload.transform.FindChild("Value_TMP (1)").gameObject); Object.Destroy(upload.transform.FindChild("ValueBox").gameObject); @@ -57,17 +62,19 @@ public static class OnlinePresetsManager upload.gameObject.SetActive(true); menu.Children.Add(upload); + OptionBehaviourCache[-1] = upload; y -= 0.6f; } { - CategoryHeaderMasked header = ModGameOptionsMenu.Track(Object.Instantiate( + CategoryHeaderMasked header = HeaderCache.TryGetValue(1, out CategoryHeaderMasked cache) ? cache : ModGameOptionsMenu.Track(Object.Instantiate( menu.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer )); + HeaderCache[1] = header; header.SetHeader(StringNames.RolesCategory, 20); header.Title.DestroyTranslator(); @@ -78,23 +85,22 @@ public static class OnlinePresetsManager y -= 0.8f; } - if (!PresetsLoaded) yield break; - - foreach (PresetMeta preset in CachedPresets) + for (var index = 0; index < CachedPresets.Count; index++) { - StringOption row = ModGameOptionsMenu.Track(Object.Instantiate(menu.stringOptionOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer)); + PresetMeta preset = CachedPresets[index]; + StringOption row = OptionBehaviourCache.TryGetValue(index, out StringOption cache) ? cache : ModGameOptionsMenu.Track(Object.Instantiate(menu.stringOptionOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer)); row.name = $"{nameof(OnlinePresetsManager)};{string.Format(Translator.GetString("OnlinePresetInfo"), preset.name, preset.author, (Utils.TimeStamp - (long)preset.created_at) / 86400, preset.downloads)}"; row.transform.localPosition = new Vector3(0.952f, y, -2f); row.SetClickMask(menu.ButtonClickMask); - row.SetUpFromData(ScriptableObject.CreateInstance(), 20); - + row.SetUpFromData(null, 20); + Object.Destroy(row.transform.FindChild("Value_TMP (1)").gameObject); Object.Destroy(row.transform.FindChild("ValueBox").gameObject); row.OnValueChanged = new Action(menu.ValueChanged); row.LabelBackground.transform.localScale += new Vector3(1f, 0f, 0f); row.TitleText.GetComponent().sizeDelta = new(5.7f, 0.37f); - + TextMeshPro plusText = row.PlusBtn.GetComponentInChildren(); plusText.DestroyTranslator(); plusText.text = "ⓘ"; @@ -103,7 +109,7 @@ public static class OnlinePresetsManager { bool b = plusText.text == "ⓘ"; GameObject.Find("PlayerOptionsMenu(Clone)").transform.FindChild("What Is This?").gameObject.SetActive(b); - GameSettingMenuPatch.GMButtons.ForEach(x => x.gameObject.SetActive(!b)); + GameSettingMenuPatch.GMButtons.Values.Do(x => x.gameObject.SetActive(!b)); if (b) GameSettingMenu.Instance.MenuDescriptionText.text = preset.description; plusText.text = b ? "∅" : "ⓘ"; })); @@ -112,14 +118,13 @@ public static class OnlinePresetsManager row.MinusBtn.OnClick = new(); row.MinusBtn.OnClick.AddListener((UnityAction)(() => { - ModGameOptionsMenu.Reloading = true; - LateTask.New(() => ModGameOptionsMenu.Reloading = false, 0.01f); + LateTask.New(() => { }, 0.01f); GameSettingMenu.Instance.Close(); - + Prompt.Show(Translator.GetString("Promt.ApplyPreset"), () => { Logger.SendInGame(Translator.GetString("DownloadingPreset")); - + Main.Instance.StartCoroutine( DownloadPreset(preset.id, downloadedPreset => { @@ -129,10 +134,10 @@ public static class OnlinePresetsManager if (!downloadedPreset.TryGetValue(id, out int newValue)) continue; optionItem.SetValue(newValue, doSave: false, doSync: false); } - + OptionItem.SyncAllOptions(); OptionSaver.Save(); - + Logger.SendInGame(Translator.GetString("PresetApplied"), Color.green); }) ); @@ -143,13 +148,13 @@ public static class OnlinePresetsManager if (!GameStates.IsLobby) return; GameObject.Find("Host Buttons").transform.FindChild("Edit").GetComponent().ReceiveClickDown(); }, 0.1f); - + LateTask.New(() => { if (!GameStates.IsLobby || !GameSettingMenu.Instance) return; - const int index = (int)TabGroup.PresetExplorer + 3; - GameSettingMenu.Instance.ChangeTab(index, Controller.currentTouchType == Controller.TouchType.Joystick); - ModGameOptionsMenu.TabIndex = index; + const int tabIndex = (int)TabGroup.PresetExplorer + 3; + GameSettingMenu.Instance.ChangeTab(tabIndex, Controller.currentTouchType == Controller.TouchType.Joystick); + ModGameOptionsMenu.TabIndex = tabIndex; }, 0.4f); }); })); @@ -160,13 +165,11 @@ public static class OnlinePresetsManager row.gameObject.SetActive(true); menu.Children.Add(row); + OptionBehaviourCache[index] = row; y -= 0.6f; - - if (y < -10) - yield return null; } - + menu.scrollBar.SetYBoundsMax(-y - 1.65f); menu.ControllerSelectable.Clear(); diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index e84f50c67..6266cf631 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -3093,7 +3093,7 @@ public static class Options IntegrateNaturalDisasters = new BooleanOptionItem(24454, "IntegrateNaturalDisasters", false, TabGroup.GameSettings) .SetColor(new Color32(193, 255, 209, byte.MaxValue)) - .RegisterUpdateValueEvent((_, _, _) => GameOptionsMenuPatch.ReloadUI()); + .RegisterUpdateValueEvent((_, _, _) => GameOptionsMenuPatch.ReCreateSettings(GameSettingMenuPatch.ModSettingsTabs[TabGroup.GameSettings])); EnableGameTimeLimit = new BooleanOptionItem(24455, "EnableGameTimeLimit", false, TabGroup.GameSettings) .SetColor(new Color32(193, 255, 209, byte.MaxValue)) diff --git a/Modules/OptionItem/OptionItem.cs b/Modules/OptionItem/OptionItem.cs index f675048d5..c4ec3e667 100644 --- a/Modules/OptionItem/OptionItem.cs +++ b/Modules/OptionItem/OptionItem.cs @@ -64,7 +64,6 @@ public abstract class OptionItem public bool IsText { get; protected set; } public TextOptionItem Header { get; set; } - public BaseGameSetting CachedSetting { get; set; } public Dictionary ReplacementDictionary { diff --git a/Modules/Prompt.cs b/Modules/Prompt.cs index 8b7548dc2..7ace0c1ea 100644 --- a/Modules/Prompt.cs +++ b/Modules/Prompt.cs @@ -105,4 +105,11 @@ public static class Prompt return true; } } + + public static void Reset() + { + CurrentQuestion = string.Empty; + ClearQueue(); + HidePromt(); + } } \ No newline at end of file diff --git a/Modules/RPC.cs b/Modules/RPC.cs index d1b5982f0..4b10004e6 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -619,22 +619,7 @@ internal static class RPCHandlerPatch } case CustomRPC.NotificationPopper: { - byte typeId = reader.ReadByte(); - int optionId = reader.ReadPackedInt32(); - int customRole = reader.ReadPackedInt32(); - bool playSound = reader.ReadBoolean(); - OptionItem key = OptionItem.FastOptions[optionId]; - - switch (typeId) - { - case 0: - NotificationPopperPatch.AddSettingsChangeMessage(key, playSound); - break; - case 1: - NotificationPopperPatch.AddRoleSettingsChangeMessage(key, (CustomRoles)customRole, playSound); - break; - } - + NotificationPopperPatch.AddSettingsChangeMessage(OptionItem.FastOptions[reader.ReadPackedInt32()], reader.ReadBoolean()); break; } case CustomRPC.RequestCommandProcessing: diff --git a/Modules/Utils.cs b/Modules/Utils.cs index b715e6829..9a95bbd26 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -90,7 +90,7 @@ public static class Utils private static readonly StringBuilder ContAliveLog = new(100); - private static readonly Dictionary CachedSprites = []; + public static readonly Dictionary CachedSprites = []; private static long LastNotifyRolesErrorTS = TimeStamp; @@ -468,22 +468,38 @@ public static class Utils mode = mode.Replace("color=", string.Empty); return parentheses ? $"({mode})" : mode; } - public static Color GetTabColor(this TabGroup tab) + + extension(TabGroup tab) { - return tab switch + public Color GetTabColor() { - TabGroup.SystemSettings => new(0.2f, 0.2f, 0.2f), - TabGroup.GameSettings => new(0.2f, 0.4f, 0.3f), - TabGroup.TaskSettings => new(0.4f, 0.2f, 0.5f), - TabGroup.ImpostorRoles => new(0.5f, 0.2f, 0.2f), - TabGroup.CrewmateRoles => new(0.2f, 0.4f, 0.5f), - TabGroup.NeutralRoles => new(0.5f, 0.4f, 0.2f), - TabGroup.CovenRoles => new(0.5f, 0.2f, 0.4f), - TabGroup.Addons => new(0.4f, 0.2f, 0.3f), - TabGroup.OtherRoles => new(0.4f, 0.4f, 0.4f), - TabGroup.PresetExplorer => new(0.5f, 0.5f, 0.5f), - _ => new(0.3f, 0.3f, 0.3f) - }; + return tab switch + { + TabGroup.SystemSettings => new(0.2f, 0.2f, 0.2f), + TabGroup.GameSettings => new(0.2f, 0.4f, 0.3f), + TabGroup.TaskSettings => new(0.4f, 0.2f, 0.5f), + TabGroup.ImpostorRoles => new(0.5f, 0.2f, 0.2f), + TabGroup.CrewmateRoles => new(0.2f, 0.4f, 0.5f), + TabGroup.NeutralRoles => new(0.5f, 0.4f, 0.2f), + TabGroup.CovenRoles => new(0.5f, 0.2f, 0.4f), + TabGroup.Addons => new(0.4f, 0.2f, 0.3f), + TabGroup.OtherRoles => new(0.4f, 0.4f, 0.4f), + TabGroup.PresetExplorer => new(0.5f, 0.5f, 0.5f), + _ => new(0.3f, 0.3f, 0.3f) + }; + } + + public bool IsRelevant(CustomGameMode? gm = null) + { + if (tab == TabGroup.PresetExplorer) return true; + + return (gm ?? Options.CurrentGameMode) switch + { + CustomGameMode.Standard => true, + CustomGameMode.HideAndSeek => tab <= TabGroup.NeutralRoles, + _ => tab <= TabGroup.TaskSettings + }; + } } public static string GetRoleColorCode(CustomRoles role, string defaultHtml = "#ffffff") @@ -4908,6 +4924,7 @@ public static class Utils { foreach (var pc in players) { + if (pc.IsModdedClient()) continue; var dummyImp = players.FirstOrDefault(x => x != pc); if (dummyImp) dummyImp.RpcSetRoleDesync(RoleTypes.Impostor, pc.OwnerId); } diff --git a/Patches/CredentialsPatch.cs b/Patches/CredentialsPatch.cs index 084456917..5844dbbf2 100644 --- a/Patches/CredentialsPatch.cs +++ b/Patches/CredentialsPatch.cs @@ -16,12 +16,11 @@ internal static class PingTrackerUpdatePatch { public static PingTracker Instance; private static readonly StringBuilder Sb = new(); - private static long LastUpdate; private static readonly float[] FpsBuffer = new float[10]; private static int FpsIndex; private static int FpsCount; - private static Color32 FpsColor = new(0, 165, 255, 255); + private static readonly Color32 FpsColor = new(0, 165, 255, 255); public static bool Prefix(PingTracker __instance) { diff --git a/Patches/ExceptionSwallowers.cs b/Patches/ExceptionSwallowers.cs index 66fc6406f..31bfc86cc 100644 --- a/Patches/ExceptionSwallowers.cs +++ b/Patches/ExceptionSwallowers.cs @@ -19,7 +19,10 @@ static class ExceptionSwallowers yield return AccessTools.Method(typeof(PlayerControl), nameof(PlayerControl.RawSetName)); yield return AccessTools.Method(typeof(PlayerControl), nameof(PlayerControl.SetName)); yield return AccessTools.Method(typeof(CosmeticsLayer), nameof(CosmeticsLayer.UpdateBodyMaterial)); + yield return AccessTools.Method(typeof(CosmeticsCache), nameof(CosmeticsCache.ClearUnusedCosmetics)); yield return AccessTools.Method(typeof(InnerNetClient), nameof(InnerNetClient.SendOrDisconnect)); + yield return AccessTools.Method(typeof(DisconnectPopup), nameof(DisconnectPopup.DoShow)); + yield return AccessTools.Method(typeof(IGameOptionsExtensions), nameof(IGameOptionsExtensions.GetValue)); } public static Exception Finalizer() diff --git a/Patches/GameOptionsMenuPatch.cs b/Patches/GameOptionsMenuPatch.cs index 4947b47d3..4ed635b1a 100644 --- a/Patches/GameOptionsMenuPatch.cs +++ b/Patches/GameOptionsMenuPatch.cs @@ -20,103 +20,54 @@ namespace EHR; public static class ModGameOptionsMenu { public static int TabIndex; - public static bool Reloading; - public static readonly List RunningMainCoroutines = new(); public static readonly Dictionary OptionList = new(); public static readonly Dictionary BehaviourList = new(); public static readonly Dictionary CategoryHeaderList = new(); - private static readonly List SpawnedUI = new(); + public static readonly System.Collections.Generic.Dictionary HelpIconList = []; + public static readonly System.Collections.Generic.Dictionary BaseGameSettingCache = []; + public static readonly HashSet SpawnedUI = new(); public static T Track(T obj) where T : Object { - if (obj is GameObject go) - SpawnedUI.Add(go); - - else if (obj is Component c) - SpawnedUI.Add(c.gameObject); + switch (obj) + { + case GameObject go: + SpawnedUI.Add(go); + break; + case Component c: + SpawnedUI.Add(c.gameObject); + break; + } return obj; } - public static void DestroyOption() + public static Color32 GetCurrentThemeColor(TabGroup? tab = null) { - foreach (var ui in SpawnedUI) + CustomGameMode gm = Options.CurrentGameMode; + Color32 color = gm == CustomGameMode.Standard ? (tab ?? (TabGroup)(TabIndex - 3)) switch { - if (!ui) continue; - - foreach (var btn in ui.GetComponentsInChildren(true)) - btn.OnClick.RemoveAllListeners(); - - Destroy(ui); - } - SpawnedUI.Clear(); - - foreach (var kv in OptionItem.AllOptions) - { - kv.OptionBehaviour = null; - kv.Header = null; - } - - foreach (var kv in OptionList) - { - if (kv.Key) - { - kv.Key.OnValueChanged = null; - kv.Key.SetClickMask(null); - if (kv.Key.TryGetComponent(out var btn)) - btn.OnClick.RemoveAllListeners(); - Destroy(kv.Key.gameObject); - } - } - - foreach (var kv in BehaviourList) - { - if (kv.Value) - { - kv.Value.OnValueChanged = null; - kv.Value.SetClickMask(null); - if (kv.Value.TryGetComponent(out var btn)) - btn.OnClick.RemoveAllListeners(); - Destroy(kv.Value.gameObject); - } - } - - foreach (var kv in CategoryHeaderList) - { - if (kv.Value) - { - if (kv.Value.TryGetComponent(out var btn)) - btn.OnClick.RemoveAllListeners(); - Destroy(kv.Value.gameObject); - } - } - - foreach (var co in RunningMainCoroutines) - { - if (co != null) - Main.Instance.StopCoroutine(co); - } - - OptionList.Clear(); - BehaviourList.Clear(); - CategoryHeaderList.Clear(); - RunningMainCoroutines.Clear(); - } - - public static void Destroy(GameObject gameObject) - { - if (Reloading) Object.DestroyImmediate(gameObject); - else Object.Destroy(gameObject); + TabGroup.ImpostorRoles => new Color32(255, 25, 25, 255), + TabGroup.CrewmateRoles => new Color32(140, 255, 255, 255), + TabGroup.NeutralRoles => new Color32(255, 171, 27, 255), + TabGroup.CovenRoles => new Color32(123, 63, 187, 255), + _ => new Color32(0, 165, 255, 255) + } : Main.GameModeColors.TryGetValue(gm, out var c) ? c : new Color32(0, 165, 255, 255); + return color; } } [HarmonyPatch(typeof(GameOptionsMenu))] public static class GameOptionsMenuPatch { + public static GameOptionsMenu Instance; + [HarmonyPatch(nameof(GameOptionsMenu.Initialize))] [HarmonyPrefix] private static bool InitializePrefix(GameOptionsMenu __instance) { + Instance = __instance; + if (ModGameOptionsMenu.TabIndex < 3) return true; if (__instance.Children == null || __instance.Children.Count == 0) @@ -187,7 +138,7 @@ public static class GameOptionsMenuPatch if (modTab == TabGroup.PresetExplorer) { - __instance.StartCoroutine(OnlinePresetsManager.CreatePresetExplorerUI(__instance).WrapToIl2Cpp()); + OnlinePresetsManager.CreatePresetExplorerUI(__instance); return false; } @@ -216,7 +167,7 @@ public static class GameOptionsMenuPatch if (option is TextOptionItem toi) { - CategoryHeaderMasked categoryHeaderMasked = ModGameOptionsMenu.Track(Object.Instantiate(__instance.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)); + CategoryHeaderMasked categoryHeaderMasked = ModGameOptionsMenu.CategoryHeaderList.TryGetValue(index, out CategoryHeaderMasked cache) ? cache : ModGameOptionsMenu.Track(Object.Instantiate(__instance.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)); categoryHeaderMasked.SetHeader(StringNames.RolesCategory, 20); categoryHeaderMasked.Title.SetText(option.GetName(disableColor: true).Trim('★', ' ')); categoryHeaderMasked.Background.color = categoryHeaderMasked.Divider.color = option.NameColor; @@ -255,25 +206,27 @@ public static class GameOptionsMenuPatch BaseGameSetting baseGameSetting = GetSetting(option); if (!baseGameSetting) continue; - OptionBehaviour optionBehaviour; - - try + if (!ModGameOptionsMenu.BehaviourList.TryGetValue(index, out OptionBehaviour optionBehaviour)) { - optionBehaviour = baseGameSetting.Type switch + try { - OptionTypes.Checkbox => ModGameOptionsMenu.Track(Object.Instantiate(__instance.checkboxOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)), - OptionTypes.String => ModGameOptionsMenu.Track(Object.Instantiate(__instance.stringOptionOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)), - OptionTypes.Float or OptionTypes.Int => ModGameOptionsMenu.Track(Object.Instantiate(__instance.numberOptionOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)), - _ => throw new Exception() - }; + optionBehaviour = baseGameSetting.Type switch + { + OptionTypes.Checkbox => ModGameOptionsMenu.Track(Object.Instantiate(__instance.checkboxOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)), + OptionTypes.String => ModGameOptionsMenu.Track(Object.Instantiate(__instance.stringOptionOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)), + OptionTypes.Float or OptionTypes.Int => ModGameOptionsMenu.Track(Object.Instantiate(__instance.numberOptionOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)), + _ => throw new Exception() + }; + } + catch { continue; } + + optionBehaviour.transform.localPosition = new(posX, num, posZ); + OptionBehaviourSetSizeAndPosition(optionBehaviour, option, baseGameSetting.Type); + } + else + { + optionBehaviour.transform.localPosition = new(posX, num, posZ); } - catch { continue; } - - optionBehaviour.transform.localPosition = new(posX, num, posZ); - OptionBehaviourSetSizeAndPosition(optionBehaviour, option, baseGameSetting.Type); - - if (!ModGameOptionsMenu.OptionList.ContainsValue(index) && option.Name == "Preset") - GameSettingMenuPatch.PresetBehaviour = (NumberOption)optionBehaviour; optionBehaviour.transform.localPosition = new(0.952f, num, -2f); optionBehaviour.SetClickMask(__instance.ButtonClickMask); @@ -298,6 +251,8 @@ public static class GameOptionsMenuPatch foreach (UiElement x in __instance.scrollBar.GetComponentsInChildren()) __instance.ControllerSelectable.Add(x); + + Canvas.ForceUpdateCanvases(); } float CalculateScrollBarYBoundsMax() @@ -323,7 +278,7 @@ public static class GameOptionsMenuPatch } } - public static bool AllParentsEnabledAndVisible(OptionItem o, bool checkCollapsedSection = true) + private static bool AllParentsEnabledAndVisible(OptionItem o, bool checkCollapsedSection = true) { while (true) { @@ -415,7 +370,7 @@ public static class GameOptionsMenuPatch public static void UpdatePostfix(GameOptionsMenu __instance) { // Disable scroll options when chat open - if (!HudManager.InstanceExists || !__instance.gameObject.activeSelf) return; + if (!HudManager.InstanceExists || !__instance.gameObject.activeSelf || !GameSettingMenu.Instance) return; __instance.scrollBar.enabled = !HudManager.Instance.Chat.IsOpenOrOpening; } @@ -473,9 +428,60 @@ public static class GameOptionsMenuPatch __instance.scrollBar.SetYBoundsMax(-num - 1.65f); } + + public static void RefreshSettingValues() + { + // ReSharper disable once UseDeconstruction - unsupported here by Il2Cpp + foreach (KeyValuePair kvp in ModGameOptionsMenu.OptionList) + { + OptionBehaviour optionBehaviour = kvp.Key; + OptionItem optionItem = OptionItem.AllOptions[kvp.Value]; + + switch (optionItem) + { + case BooleanOptionItem when optionBehaviour is ToggleOption toggleOption: + var color = ModGameOptionsMenu.GetCurrentThemeColor(optionItem.Tab); + toggleOption.CheckMark.color = color; + toggleOption.CheckMark.enabled = optionItem.GetBool(); + toggleOption.CheckMark.transform.parent.FindChild("ActiveSprite").GetComponent().color = color; + break; + case StringOptionItem when optionBehaviour is StringOption stringOption: + stringOption.Value = optionItem.GetInt(); + stringOption.UpdateValue(); + break; + case FloatOptionItem or IntegerOptionItem when optionBehaviour is NumberOption numberOption: + numberOption.Value = optionItem.GetFloat(); + break; + } + } + + GameOptionsManager.Instance.GameHostOptions = GameOptionsManager.Instance.CurrentGameOptions; + GameManager.Instance.LogicOptions.SyncOptions(); + } + + public static void RefreshTabButtons() + { + foreach ((TabGroup tab, PassiveButton button) in GameSettingMenuPatch.ModSettingsButtons) + button.gameObject.SetActive(tab.IsRelevant()); + } + + public static void RefreshCheckMarkColors() + { + // ReSharper disable once UseDeconstruction - unsupported here by Il2Cpp + foreach (KeyValuePair kvp in ModGameOptionsMenu.OptionList) + { + if (kvp.Key is ToggleOption toggleOption) + { + var color = ModGameOptionsMenu.GetCurrentThemeColor(OptionItem.AllOptions[kvp.Value].Tab); + toggleOption.CheckMark.color = color; + toggleOption.CheckMark.transform.parent.FindChild("ActiveSprite").GetComponent().color = color; + } + } + } + public static BaseGameSetting GetSetting(OptionItem item) { - if (item.CachedSetting) return item.CachedSetting; + if (ModGameOptionsMenu.BaseGameSettingCache.TryGetValue(item, out BaseGameSetting cache)) return cache; BaseGameSetting baseGameSetting; @@ -515,67 +521,14 @@ public static class GameOptionsMenuPatch stringGameSetting.Index = stringOptionItem.GetInt(); baseGameSetting = stringGameSetting; break; - case PresetOptionItem presetOptionItem: - var presetIntGameSetting = ScriptableObject.CreateInstance(); - presetIntGameSetting.Type = OptionTypes.Int; - presetIntGameSetting.Value = presetOptionItem.GetInt(); - presetIntGameSetting.Increment = presetOptionItem.Rule.Step; - presetIntGameSetting.ValidRange = new(presetOptionItem.Rule.MinValue, presetOptionItem.Rule.MaxValue); - presetIntGameSetting.ZeroIsInfinity = false; - presetIntGameSetting.SuffixType = NumberSuffixes.Multiplier; - presetIntGameSetting.FormatString = string.Empty; - baseGameSetting = presetIntGameSetting; - break; default: - baseGameSetting = null; - break; + return null; } - if (baseGameSetting) - { - baseGameSetting.Title = StringNames.Accept; - item.CachedSetting = baseGameSetting; - } + baseGameSetting.Title = StringNames.Accept; + ModGameOptionsMenu.BaseGameSettingCache[item] = baseGameSetting; return baseGameSetting; } - - // From MoreGamemodes, by Rabek009 - public static void ReloadUI() - { - int tab = ModGameOptionsMenu.TabIndex; - if (!GameSettingMenu.Instance) return; - - ModGameOptionsMenu.Reloading = true; - LateTask.New(() => ModGameOptionsMenu.Reloading = false, 0.01f); - - GameSettingMenu.Instance.Close(); - - OptionsConsole optionsConsole = null; - - foreach (OptionsConsole console in Object.FindObjectsOfType()) - { - if (console.HostOnly) - optionsConsole = console; - } - - if (!optionsConsole) return; - - Camera main = Camera.main; - - if (main) - { - GameObject gameObject = ModGameOptionsMenu.Track(Object.Instantiate(optionsConsole.MenuPrefab, main.transform, false)); - gameObject.transform.localPosition = optionsConsole.CustomPosition; - } - - LateTask.New(() => - { - if (!GameSettingMenu.Instance) return; - GameSettingMenu.Instance.ChangeTab(tab, false); - }, 0.01f); - - LateTask.New(() => GameObject.Find("PlayerOptionsMenu(Clone)")?.transform.FindChild("What Is This?")?.gameObject.SetActive(false), 0.02f); - } } [HarmonyPatch(typeof(ToggleOption))] @@ -589,15 +542,7 @@ public static class ToggleOptionPatch { OptionItem item = OptionItem.AllOptions[index]; - CustomGameMode gm = Options.CurrentGameMode; - Color32 color = gm == CustomGameMode.Standard ? (TabGroup)(ModGameOptionsMenu.TabIndex - 3) switch - { - TabGroup.ImpostorRoles => new Color32(255, 25, 25, 255), - TabGroup.CrewmateRoles => new Color32(140, 255, 255, 255), - TabGroup.NeutralRoles => new Color32(255, 171, 27, 255), - TabGroup.CovenRoles => new Color32(123, 63, 187, 255), - _ => new Color32(0, 165, 255, 255) - } : Main.GameModeColors.TryGetValue(gm, out var c) ? c : new Color32(0, 165, 255, 255); + var color = ModGameOptionsMenu.GetCurrentThemeColor(); __instance.CheckMark.sprite = Utils.LoadSprite("EHR.Resources.Images.Checkmark.png", 100f); __instance.CheckMark.color = color; var renderer = __instance.CheckMark.transform.parent.FindChild("ActiveSprite").GetComponent(); @@ -715,10 +660,6 @@ public static class NumberOptionPatch case FloatOptionItem floatOptionItem: floatOptionItem.SetValue(floatOptionItem.Rule.GetNearestIndex(__instance.GetFloat())); break; - case PresetOptionItem presetOptionItem: - presetOptionItem.SetValue(presetOptionItem.Rule.GetNearestIndex(__instance.GetInt())); - GameOptionsMenuPatch.ReloadUI(); - break; } NotificationPopperPatch.AddSettingsChangeMessage(item, true); @@ -811,12 +752,13 @@ public static class NumberOptionPatch public static class StringOptionPatch { private static long HelpShowEndTS; + private static readonly Dictionary NameCache = new(); [HarmonyPatch(nameof(StringOption.Initialize))] [HarmonyPrefix] private static bool InitializePrefix(StringOption __instance) { - if (__instance.name.StartsWith(nameof(OnlinePresetsManager))) return true; + if (__instance.name.StartsWith(nameof(OnlinePresetsManager))) return false; if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out int index)) { @@ -855,6 +797,7 @@ public static class StringOptionPatch } __instance.TitleText.SetText(name); + NameCache[__instance] = name; return false; } @@ -864,7 +807,8 @@ public static class StringOptionPatch private static void SetupHelpIcon(CustomRoles role, StringOption option) { Transform template = option.MinusBtn.transform; - Transform icon = ModGameOptionsMenu.Track(Object.Instantiate(template, template.parent, true)); + bool cached = ModGameOptionsMenu.HelpIconList.TryGetValue(role, out Transform cache); + Transform icon = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(template, template.parent, true)); icon.name = $"{role}HelpIcon"; var text = icon.GetComponentInChildren(); text.SetText("?"); @@ -890,7 +834,7 @@ public static class StringOptionPatch catch { infoLong = str; } GameObject.Find("PlayerOptionsMenu(Clone)").transform.FindChild("What Is This?").gameObject.SetActive(true); - GameSettingMenuPatch.GMButtons.ForEach(x => x.gameObject.SetActive(false)); + GameSettingMenuPatch.GMButtons.Values.Do(x => x.gameObject.SetActive(false)); var info = $"{value.ToColoredString()}: {infoLong}"; GameSettingMenu.Instance.MenuDescriptionText.SetText(info); @@ -898,11 +842,7 @@ public static class StringOptionPatch long now = Utils.TimeStamp; bool startCoRoutine = now > HelpShowEndTS; HelpShowEndTS = now + 15; - if (startCoRoutine) - { - var co = Main.Instance.StartCoroutine(CoRoutine()); - ModGameOptionsMenu.RunningMainCoroutines.Add(co); - } + if (startCoRoutine) GameSettingMenu.Instance.StartCoroutine(CoRoutine().WrapToIl2Cpp()); IEnumerator CoRoutine() { @@ -917,16 +857,17 @@ public static class StringOptionPatch if (findChild) findChild.gameObject.SetActive(false); } - GameSettingMenuPatch.GMButtons.ForEach(x => x.gameObject.SetActive(true)); + GameSettingMenuPatch.GMButtons.Values.Do(x => x.gameObject.SetActive(true)); } } } })); gameOptionButton.interactableColor = Color.black; - gameOptionButton.interactableHoveredColor = new Color32(0, 165, 255, 255); + gameOptionButton.interactableHoveredColor = ModGameOptionsMenu.GetCurrentThemeColor(); icon.localPosition += new Vector3(-0.8f, 0f, 0f); icon.SetAsLastSibling(); + ModGameOptionsMenu.HelpIconList[role] = icon; } public static string GetGhostRoleTeam(CustomRoles role) @@ -968,43 +909,8 @@ public static class StringOptionPatch { OptionItem item = OptionItem.AllOptions[index]; item.SetValue(__instance.GetInt()); - string name = item.GetName(); - - string name1 = name; - - if (Main.CustomRoleValues.FindFirst(x => Translator.GetString($"{x}") == name1.RemoveHtmlTags(), out CustomRoles role)) - { - if (role.ToString().Contains("GuardianAngel")) role = CustomRoles.GA; - - name = name.RemoveHtmlTags(); - - switch (Options.UsePets.GetBool()) - { - case true when role.PetActivatedAbility(): - name += Translator.GetString("SupportsPetIndicator"); - break; - case false when role.OnlySpawnsWithPets(): - name += Translator.GetString("RequiresPetIndicator"); - Prompt.Show(Translator.GetString("Promt.RequiresPets"), () => Options.UsePets.SetValue(1), () => { }); - break; - } - - if (role.IsExperimental()) name += $"{Translator.GetString("ExperimentalRoleIndicator")}"; - if (role.IsGhostRole()) name += GetGhostRoleTeam(role); - if (role.IsDevFavoriteRole()) name += " <#00ffff>★"; - - __instance.TitleText.fontWeight = FontWeight.Black; - __instance.TitleText.outlineColor = new(255, 255, 255, 255); - __instance.TitleText.outlineWidth = 0.04f; - __instance.LabelBackground.color = Utils.GetRoleColor(role); - __instance.TitleText.color = Color.white; - name = $"{name}"; - NotificationPopperPatch.AddRoleSettingsChangeMessage(item, role, true); - } - else - NotificationPopperPatch.AddSettingsChangeMessage(item, true); - - __instance.TitleText.SetText(name); + NotificationPopperPatch.AddSettingsChangeMessage(item, true); + __instance.TitleText.SetText(NameCache[__instance]); return false; } @@ -1074,7 +980,7 @@ public static class StringOptionPatch [HarmonyPatch(typeof(GameSettingMenu))] public static class GameSettingMenuPatch { - public static readonly System.Collections.Generic.List GMButtons = []; + public static readonly System.Collections.Generic.Dictionary GMButtons = []; private static readonly Vector3 ButtonPositionLeft = new(-3.9f, -0.55f, 0f); private static readonly Vector3 ButtonPositionRight = new(-2.4f, -0.55f, 0f); @@ -1084,10 +990,9 @@ public static class GameSettingMenuPatch private static GameOptionsMenu TemplateGameOptionsMenu; private static PassiveButton TemplateGameSettingsButton; - private static readonly System.Collections.Generic.Dictionary ModSettingsButtons = []; - private static readonly System.Collections.Generic.Dictionary ModSettingsTabs = []; + public static readonly System.Collections.Generic.Dictionary ModSettingsButtons = []; + public static readonly System.Collections.Generic.Dictionary ModSettingsTabs = []; - public static NumberOption PresetBehaviour; public static long LastPresetChange; public static FreeChatInputField InputField; @@ -1101,58 +1006,16 @@ public static class GameSettingMenuPatch private static float VanillaKillCooldownOnOpen = 1; private static float ModdedKillCooldownOnOpen = 1; - private static void DestroySetting() - { - foreach (var button in ModSettingsButtons.Values) - { - if (button) - { - button.OnClick.RemoveAllListeners(); - ModGameOptionsMenu.Destroy(button.gameObject); - } - } - - foreach (var tab in ModSettingsTabs.Values) - { - if (!tab) continue; - - if (tab.Children != null) - { - foreach (var child in tab.Children) - { - if (!child) continue; - - if (child.TryGetComponent(out var btn)) - btn.OnClick.RemoveAllListeners(); - - ModGameOptionsMenu.Destroy(child.gameObject); - } - tab.Children.Clear(); - } - ModGameOptionsMenu.Destroy(tab.gameObject); - } - - foreach (var gmButton in GMButtons) - if (gmButton) ModGameOptionsMenu.Destroy(gmButton); - - ModSettingsButtons.Clear(); - ModSettingsTabs.Clear(); - GMButtons.Clear(); - - InputField = null; - SearchForOptionsAction = null; - } - [HarmonyPatch(nameof(GameSettingMenu.Start))] [HarmonyPrefix] [HarmonyPriority(Priority.First)] - public static void StartPostfix(GameSettingMenu __instance) + public static void StartPrefix(ref GameSettingMenu __instance) { try { - (OptionItem MinSetting, OptionItem MaxSetting) = Options.FactionMinMaxSettings[Team.Impostor]; - MinImpsOnOpen = MinSetting.GetInt(); - MaxImpsOnOpen = MaxSetting.GetInt(); + (OptionItem minSetting, OptionItem maxSetting) = Options.FactionMinMaxSettings[Team.Impostor]; + MinImpsOnOpen = minSetting.GetInt(); + MaxImpsOnOpen = maxSetting.GetInt(); NumImpsOnOpen = Main.NormalOptions.NumImpostors; VanillaKillCooldownOnOpen = Main.NormalOptions.KillCooldown; @@ -1160,20 +1023,12 @@ public static class GameSettingMenuPatch } catch (Exception e) { Utils.ThrowException(e); } - ModSettingsButtons.Clear(); - TabGroup[] tabGroups = Main.TabGroupValues; - - tabGroups = Options.CurrentGameMode switch + foreach (TabGroup tab in Main.TabGroupValues) { - CustomGameMode.Standard => tabGroups, - CustomGameMode.HideAndSeek => tabGroups[..6], - _ => tabGroups[..3] - }; - - foreach (TabGroup tab in tabGroups) - { - PassiveButton button = ModGameOptionsMenu.Track(Object.Instantiate(TemplateGameSettingsButton, __instance.GameSettingsButton.transform.parent)); - button.gameObject.SetActive(true); + bool cached = ModSettingsButtons.TryGetValue(tab, out PassiveButton cache); + PassiveButton button = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(TemplateGameSettingsButton, __instance.GameSettingsButton.transform.parent)); + if (cached) button.transform.SetParent(__instance.GameSettingsButton.transform.parent, false); + button.gameObject.SetActive(tab.IsRelevant()); button.name = "Button_" + tab; var label = button.GetComponentInChildren(); label.DestroyTranslator(); @@ -1194,23 +1049,23 @@ public static class GameSettingMenuPatch var buttonComponent = button.GetComponent(); buttonComponent.OnClick = new(); - buttonComponent.OnClick.AddListener((Action)(() => __instance.ChangeTab((int)tab + 3, false))); + buttonComponent.OnClick.AddListener((Action)(() => GameSettingMenu.Instance.ChangeTab((int)tab + 3, false))); - ModSettingsButtons.Add(tab, button); + ModSettingsButtons[tab] = button; } - ModSettingsTabs.Clear(); - - foreach (TabGroup tab in tabGroups) + foreach (TabGroup tab in Main.TabGroupValues) { - GameOptionsMenu setTab = ModGameOptionsMenu.Track(Object.Instantiate(TemplateGameOptionsMenu, __instance.GameSettingsTab.transform.parent)); + bool cached = ModSettingsTabs.TryGetValue(tab, out GameOptionsMenu cache); + GameOptionsMenu setTab = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(TemplateGameOptionsMenu, __instance.GameSettingsTab.transform.parent)); + if (cached) setTab.transform.SetParent(__instance.GameSettingsTab.transform.parent, false); setTab.name = "tab_" + tab; setTab.gameObject.SetActive(false); - ModSettingsTabs.Add(tab, setTab); + ModSettingsTabs[tab] = setTab; } - foreach (TabGroup tab in tabGroups) + foreach (TabGroup tab in Main.TabGroupValues) { if (ModSettingsButtons.TryGetValue(tab, out PassiveButton button)) __instance.ControllerSelectable.Add(button); @@ -1222,11 +1077,20 @@ public static class GameSettingMenuPatch SetupExtendedUI(__instance); } + private static readonly System.Collections.Generic.Dictionary ExtraObjectsCache = []; + // Thanks: Drakos for the preset button and search bar code (https://github.com/0xDrMoe/TownofHost-Enhanced/pull/1115) private static void SetupExtendedUI(GameSettingMenu __instance) { Transform parentLeftPanel = __instance.GamePresetsButton.transform.parent; - GameObject preset = ModGameOptionsMenu.Track(Object.Instantiate(GameObject.Find("ModeValue"), parentLeftPanel)); + bool cached = ExtraObjectsCache.TryGetValue(0, out GameObject cache); + GameObject preset = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(GameObject.Find("ModeValue"), parentLeftPanel)); + if (cached) + { + preset.transform.SetParent(parentLeftPanel, false); + preset.SetActive(true); + } + ExtraObjectsCache[0] = preset; preset.transform.localPosition = new(-1.8f, 0f, -2f); preset.transform.localScale = new(0.65f, 0.63f, 1f); @@ -1244,7 +1108,10 @@ public static class GameSettingMenuPatch GameObject tempMinus = GameObject.Find("MinusButton").gameObject; - GameObject gMinus = ModGameOptionsMenu.Track(Object.Instantiate(__instance.GamePresetsButton.gameObject, preset.transform)); + cached = ExtraObjectsCache.TryGetValue(1, out cache); + GameObject gMinus = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(__instance.GamePresetsButton.gameObject, preset.transform)); + if (cached) gMinus.transform.SetParent(preset.transform, false); + ExtraObjectsCache[1] = gMinus; gMinus.gameObject.SetActive(true); gMinus.transform.localScale = new(0.08f, 0.4f, 1f); @@ -1252,7 +1119,7 @@ public static class GameSettingMenuPatch mLabel.alignment = TextAlignmentOptions.Center; mLabel.DestroyTranslator(); mLabel.SetText("-"); - mLabel.transform.localPosition = new(mLabel.transform.localPosition.x, mLabel.transform.localPosition.y + 0.26f, mLabel.transform.localPosition.z); + if (!cached) mLabel.transform.localPosition = new(mLabel.transform.localPosition.x, mLabel.transform.localPosition.y + 0.26f, mLabel.transform.localPosition.z); mLabel.color = Color.white; mLabel.SetFaceColor(new Color(255f, 255f, 255f)); mLabel.transform.localScale = new(12f, 4f, 1f); @@ -1262,11 +1129,12 @@ public static class GameSettingMenuPatch minus.OnClick.AddListener((Action)(() => { - if (!PresetBehaviour) - __instance.ChangeTab(3, false); - LastPresetChange = Utils.TimeStamp; - PresetBehaviour.Decrease(); + Options.Preset--; + ModSettingsTabs.Values.Do(GameOptionsMenuPatch.ReCreateSettings); + GameOptionsMenuPatch.RefreshSettingValues(); + GameOptionsMenuPatch.RefreshTabButtons(); + presetTmp.SetText(Translator.GetString($"Preset_{OptionItem.CurrentPreset + 1}")); Logger.Info($"Current preset: {OptionItem.CurrentPreset + 1}", "GameOptionsMenuPatch"); })); @@ -1286,13 +1154,20 @@ public static class GameSettingMenuPatch selectedSprites.color = new Color32(0, 165, 255, 255); - GameObject plusFab = ModGameOptionsMenu.Track(Object.Instantiate(gMinus, preset.transform)); + cached = ExtraObjectsCache.TryGetValue(2, out cache); + GameObject plusFab = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(gMinus, preset.transform)); + if (cached) + { + plusFab.transform.SetParent(preset.transform, false); + plusFab.SetActive(true); + } + ExtraObjectsCache[2] = plusFab; var plusLabel = plusFab.transform.Find("FontPlacer/Text_TMP").GetComponent(); plusLabel.alignment = TextAlignmentOptions.Center; plusLabel.DestroyTranslator(); plusLabel.SetText("+"); plusLabel.color = Color.white; - plusLabel.transform.localPosition = new(plusLabel.transform.localPosition.x, plusLabel.transform.localPosition.y + 0.26f, plusLabel.transform.localPosition.z); + if (!cached) plusLabel.transform.localPosition = new(plusLabel.transform.localPosition.x, plusLabel.transform.localPosition.y + 0.26f, plusLabel.transform.localPosition.z); plusLabel.transform.localScale = new(18f, 4f, 1f); var plus = plusFab.GetComponent(); @@ -1300,11 +1175,12 @@ public static class GameSettingMenuPatch plus.OnClick.AddListener((Action)(() => { - if (!PresetBehaviour) - __instance.ChangeTab(3, false); - LastPresetChange = Utils.TimeStamp; - PresetBehaviour.Increase(); + Options.Preset++; + ModSettingsTabs.Values.Do(GameOptionsMenuPatch.ReCreateSettings); + GameOptionsMenuPatch.RefreshSettingValues(); + GameOptionsMenuPatch.RefreshTabButtons(); + presetTmp.SetText(Translator.GetString($"Preset_{OptionItem.CurrentPreset + 1}")); Logger.Info($"Current preset: {OptionItem.CurrentPreset + 1}", "GameOptionsMenuPatch"); })); @@ -1350,9 +1226,14 @@ public static class GameSettingMenuPatch { CustomGameMode gm = gms[index]; - var gmButton = ModGameOptionsMenu.Track(Object.Instantiate(gMinus, gameSettingsLabel.transform, true)); + cached = GMButtons.TryGetValue(gm, out cache); + var gmButton = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(gMinus, gameSettingsLabel.transform, true)); + if (cached) + { + gmButton.transform.SetParent(gameSettingsLabel.transform, false); + gmButton.SetActive(true); + } gmButton.transform.localPosition = new Vector3((((index / 8) - ((totalCols - 1) / 2f)) * 1.4f) + 0.86f, gameSettingsLabelPos.y - 1.9f - (0.22f * (index % 8)), -1f); - gmButton.transform.localScale = new(0.4f, 0.3f, 1f); var gmButtonTmp = gmButton.transform.Find("FontPlacer/Text_TMP").GetComponent(); gmButtonTmp.alignment = TextAlignmentOptions.Center; @@ -1366,19 +1247,36 @@ public static class GameSettingMenuPatch gmPassiveButton.OnClick.RemoveAllListeners(); gmPassiveButton.OnClick.AddListener((Action)(() => { + if (ModSettingsTabLoaded && !((TabGroup)(ModGameOptionsMenu.TabIndex - 3)).IsRelevant(gm)) + GameSettingMenu.Instance.ChangeTab(4, false); Options.GameMode.SetValue((int)gm - 1); - GameOptionsMenuPatch.ReloadUI(); + GameOptionsMenuPatch.ReCreateSettings(ModSettingsTabs[TabGroup.GameSettings]); + if (gm is CustomGameMode.Standard or CustomGameMode.HideAndSeek) + { + GameOptionsMenuPatch.ReCreateSettings(ModSettingsTabs[TabGroup.ImpostorRoles]); + GameOptionsMenuPatch.ReCreateSettings(ModSettingsTabs[TabGroup.CrewmateRoles]); + GameOptionsMenuPatch.ReCreateSettings(ModSettingsTabs[TabGroup.NeutralRoles]); + } + GameOptionsMenuPatch.RefreshTabButtons(); + GameOptionsMenuPatch.RefreshCheckMarkColors(); + gameSettingsLabel.SetText($"{Translator.GetString($"Mode{Options.CurrentGameMode}")}\n"); })); gmPassiveButton.activeTextColor = gmPassiveButton.inactiveTextColor = gmPassiveButton.disabledTextColor = gmPassiveButton.selectedTextColor = Main.GameModeColors[gm]; - GMButtons.Add(gmButton); + GMButtons[gm] = gmButton; } if (!HudManager.InstanceExists) return; FreeChatInputField freeChatField = HudManager.Instance.Chat.freeChatField; - FreeChatInputField field = ModGameOptionsMenu.Track(Object.Instantiate(freeChatField, parentLeftPanel.parent)); + cached = InputField; + FreeChatInputField field = cached ? InputField : ModGameOptionsMenu.Track(Object.Instantiate(freeChatField, parentLeftPanel.parent)); + if (cached) + { + field.transform.SetParent(parentLeftPanel.parent, false); + field.gameObject.SetActive(true); + } field.transform.localScale = new(0.3f, 0.59f, 1); field.transform.localPosition = new(-0.7f, -2.5f, -5f); field.textArea.outputText.transform.localScale = new(3.5f, 2f, 1f); @@ -1481,6 +1379,8 @@ public static class GameSettingMenuPatch __instance.ControllerSelectable.Add(gameSettingButton); } + private static bool ModSettingsTabLoaded; + [HarmonyPatch(nameof(GameSettingMenu.ChangeTab))] [HarmonyPrefix] public static bool ChangeTabPrefix(GameSettingMenu __instance, ref int tabNum, [HarmonyArgument(1)] bool previewOnly) @@ -1523,15 +1423,14 @@ public static class GameSettingMenuPatch if (!OnlinePresetsManager.PresetsLoaded && tabGroup == TabGroup.PresetExplorer) { - var co = Main.Instance.StartCoroutine( + __instance.StartCoroutine( OnlinePresetsManager.FetchPresetList(list => { OnlinePresetsManager.CachedPresets = list; OnlinePresetsManager.PresetsLoaded = true; - GameOptionsMenuPatch.ReloadUI(); - }) + OnlinePresetsManager.CreatePresetExplorerUI(ModSettingsTabs[tabGroup]); + }).WrapToIl2Cpp() ); - ModGameOptionsMenu.RunningMainCoroutines.Add(co); } if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly) @@ -1561,7 +1460,11 @@ public static class GameSettingMenuPatch __instance.ToggleLeftSideDarkener(true); __instance.ToggleRightSideDarkener(false); - if (ModSettingsButtons.TryGetValue(tabGroup, out button) && button) button.SelectButton(true); + if (ModSettingsButtons.TryGetValue(tabGroup, out button) && button) + button.SelectButton(true); + + if (tabGroup == TabGroup.GameSettings) + ModSettingsTabLoaded = true; return false; } @@ -1593,36 +1496,34 @@ public static class GameSettingMenuPatch return false; } + private static Transform TempParent; + [HarmonyPatch(nameof(GameSettingMenu.Close))] [HarmonyPrefix] - public static void Close_Prefix(GameSettingMenu __instance) + public static void Close_Prefix() { - DestroySetting(); - ModGameOptionsMenu.DestroyOption(); - - if (__instance.GameSettingsTab && __instance.GameSettingsTab.Children != null) + if (TempParent == null) { - foreach (var opt in __instance.GameSettingsTab.Children) - { - if (!opt) continue; - - if (opt.TryGetComponent(out var btn)) - btn.OnClick.RemoveAllListeners(); - - ModGameOptionsMenu.Destroy(opt.gameObject); - } + var go = new GameObject("EHR Settings UI Cache Root"); + Object.DontDestroyOnLoad(go); + go.SetActive(true); + TempParent = go.transform; } + + foreach (var x in ModSettingsTabs.Values) SetTempParent(x.gameObject); + foreach (var x in ModSettingsButtons.Values) SetTempParent(x.gameObject); + foreach (var x in ExtraObjectsCache.Values) SetTempParent(x); + foreach (var x in GMButtons.Values) SetTempParent(x); + SetTempParent(InputField.gameObject); + return; - try { __instance.StopAllCoroutines(); } - catch { } - - Cleanup(); - } - private static void Cleanup() - { - GC.Collect(); - Resources.UnloadUnusedAssets(); + void SetTempParent(GameObject go) + { + go.gameObject.transform.SetParent(TempParent, false); + go.gameObject.SetActive(false); + } } + [HarmonyPatch(nameof(GameSettingMenu.Close))] [HarmonyPostfix] public static void Close_Postfix() @@ -1630,12 +1531,12 @@ public static class GameSettingMenuPatch try { int numImpostors = Main.NormalOptions.NumImpostors; - (OptionItem MinSetting, OptionItem MaxSetting) = Options.FactionMinMaxSettings[Team.Impostor]; + (OptionItem minSetting, OptionItem maxSetting) = Options.FactionMinMaxSettings[Team.Impostor]; - if (numImpostors != NumImpsOnOpen && MinImpsOnOpen == MinSetting.GetInt() && MaxImpsOnOpen == MaxSetting.GetInt()) + if (numImpostors != NumImpsOnOpen && MinImpsOnOpen == minSetting.GetInt() && MaxImpsOnOpen == maxSetting.GetInt()) { - MinSetting.SetValue(numImpostors); - MaxSetting.SetValue(numImpostors); + minSetting.SetValue(numImpostors); + maxSetting.SetValue(numImpostors); Logger.SendInGame(string.Format(Translator.GetString("MinMaxModdedImpCountsSettingsChangedAuto"), numImpostors)); } @@ -1659,8 +1560,6 @@ public static class GameSettingMenuPatch catch (Exception e) { Utils.ThrowException(e); } Options.AutoSetFactionMinMaxSettings(); - - //Main.Instance.StartCoroutine(OptionShower.GetText()); } } @@ -1669,7 +1568,7 @@ public static class FixInputChatField { public static bool Prefix(FreeChatInputField __instance) { - if (GameSettingMenuPatch.InputField && __instance == GameSettingMenuPatch.InputField) + if (GameSettingMenuPatch.InputField && __instance == GameSettingMenuPatch.InputField && __instance.gameObject.activeSelf) { Vector2 size = __instance.Background.size; size.y = Math.Max(0.62f, __instance.textArea.TextHeight + 0.2f); @@ -1690,7 +1589,7 @@ public static class FixDarkThemeForSearchBar FreeChatInputField field = GameSettingMenuPatch.InputField; - if (field) + if (field && field.gameObject.activeSelf) { field.background.color = new Color32(40, 40, 40, byte.MaxValue); field.textArea.compoText.Color(Color.white); diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 9ed7a0c43..b81b60667 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -1065,6 +1065,9 @@ internal static class TaskPanelBehaviourPatch internal static TaskPanelBehaviour CreateRoleTab(CustomRoles role) { + TempPlayerData.Clear(); + TempPointsData.Clear(); + TaskPanel = HudManager.Instance.TaskStuff.transform.FindChild("TaskPanel").gameObject.GetComponent(); GameObject clonePanel = Object.Instantiate(TaskPanel.gameObject, TaskPanel.transform.parent); clonePanel.name = "RolePanel"; diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index d77243b4f..a98e4e54b 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -1384,7 +1384,7 @@ internal static class MeetingHudOnDestroyPatch [HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.CastVote))] internal static class MeetingHudCastVotePatch { - private static readonly Dictionary ShouldCancelVoteList = []; + public static readonly Dictionary ShouldCancelVoteList = []; public static bool Prefix(MeetingHud __instance, [HarmonyArgument(0)] byte srcPlayerId, [HarmonyArgument(1)] byte suspectPlayerId) { diff --git a/Patches/NotificationPopperPatch.cs b/Patches/NotificationPopperPatch.cs index 8e25c21bb..e2195cd6a 100644 --- a/Patches/NotificationPopperPatch.cs +++ b/Patches/NotificationPopperPatch.cs @@ -22,17 +22,19 @@ internal static class NotificationPopperPatch public static void AddSettingsChangeMessage(OptionItem option, bool playSound = false) { + if (Utils.TimeStamp == GameSettingMenuPatch.LastPresetChange) return; + string optValue = option.GetString(); if (optValue == "STRMISS") return; - SendRpc(0, option.Id, playSound: playSound); - string name = option.GetName(); if (name == "Accept") return; string parentName = option.Parent?.GetName() ?? string.Empty; if (parentName == "Accept") return; + SendRpc(option.Id, playSound); + string str = option.Parent != null ? TranslationController.Instance.GetString(StringNames.LobbyChangeSettingNotification, "" + parentName + ": " + name + "", "" + optValue + "") : TranslationController.Instance.GetString(StringNames.LobbyChangeSettingNotification, "" + name + "", "" + optValue + ""); @@ -40,19 +42,6 @@ internal static class NotificationPopperPatch SettingsChangeMessageLogic(option, str, playSound); } - public static void AddRoleSettingsChangeMessage(OptionItem option, CustomRoles customRole, bool playSound = false) - { - string optValue = option.GetString(); - if (optValue == "STRMISS") return; - - string name = option.GetName(); - if (name == "Accept") return; - - SendRpc(1, option.Id, customRole, playSound); - string str = TranslationController.Instance.GetString(StringNames.LobbyChangeSettingNotification, "" + name + "", "" + optValue + ""); - SettingsChangeMessageLogic(option, str, playSound); - } - private static void SettingsChangeMessageLogic(OptionItem option, string item, bool playSound) { if (Instance.lastMessageKey == option.Id && Instance.activeMessages.Count > 0) @@ -70,13 +59,11 @@ internal static class NotificationPopperPatch if (playSound) SoundManager.Instance.PlaySoundImmediate(Instance.settingsChangeSound, false); } - private static void SendRpc(byte typeId, int optionId, CustomRoles customRole = CustomRoles.NotAssigned, bool playSound = true) + private static void SendRpc(int optionId, bool playSound = true) { - if (Options.HideGameSettings.GetBool()) return; + if (!AmongUsClient.Instance.AmHost || Options.HideGameSettings.GetBool()) return; var msg = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.NotificationPopper, Hazel.SendOption.None); - msg.Write(typeId); msg.Write(optionId); - msg.Write((int)customRole); msg.Write(playSound); AmongUsClient.Instance.FinishRpcImmediately(msg); } diff --git a/Patches/OnGameStartedPatch.cs b/Patches/OnGameStartedPatch.cs index a7d8d6b97..d5448b4cc 100644 --- a/Patches/OnGameStartedPatch.cs +++ b/Patches/OnGameStartedPatch.cs @@ -27,116 +27,6 @@ internal static class ChangeRoleSettings { public static bool BlockPopulateSkins; - public static bool Prefix(AmongUsClient __instance, ref IEnumerator __result) - { - if (!GameStates.IsLocalGame || !HudManager.InstanceExists) return true; - - __result = CoStartGame().WrapToIl2Cpp(); - return false; - - IEnumerator CoStartGame() - { - if (HudManager.Instance.GameMenu.IsOpen) - HudManager.Instance.GameMenu.Close(); - - UnityTelemetry.Instance.Init(); - __instance.logger.Info("Received game start: " + __instance.AmHost); - yield return null; - - while (!HudManager.InstanceExists) - yield return null; - - while (!PlayerControl.LocalPlayer) - yield return null; - - PlayerControl.LocalPlayer.moveable = false; - PlayerControl.LocalPlayer.MyPhysics.inputHandler.enabled = true; - var objectOfType1 = Object.FindObjectOfType(); - - if (objectOfType1) - objectOfType1.Close(false); - - var objectOfType2 = Object.FindObjectOfType(); - - if (objectOfType2) - objectOfType2.Close(); - - if (GameStartManager.InstanceExists) - { - __instance.DisconnectHandlers.Remove(GameStartManager.Instance.CastFast()); - Object.Destroy(GameStartManager.Instance.gameObject); - } - - if (LobbyInfoPane.InstanceExists) - Object.Destroy(LobbyInfoPane.Instance.gameObject); - - if (DiscordManager.InstanceExists) - DiscordManager.Instance.SetPlayingGame(); - - if (!string.IsNullOrEmpty(DataManager.Player.Store.ActiveCosmicube)) - AmongUsClient.Instance.SetActivePodType(CosmicubeManager.Instance.GetCubeDataByID(DataManager.Player.Store.ActiveCosmicube).podId); - else - { - PlayerStorageManager.CloudPlayerPrefs playerPrefs = PlayerStorageManager.Instance.PlayerPrefs; - AmongUsClient.Instance.SetActivePodType(playerPrefs.ActivePodType); - } - - FriendsListManager.Instance.ConfirmationScreen.Cancel(); - FriendsListManager.Instance.Ui.Close(true); - FriendsListManager.Instance.ReparentUI(); - - try { CosmeticsCache.ClearUnusedCosmetics(); } - catch (Exception e) { Utils.ThrowException(e); } - - yield return HudManager.Instance.CoFadeFullScreen(Color.clear, Color.black); - ++DataManager.Player.Ban.BanPoints; - DataManager.Player.Ban.PreviousGameStartDate = DateTime.UtcNow; - DataManager.Player.Save(); - - if (__instance.AmHost) - yield return __instance.CoStartGameHost(); - else - { - yield return __instance.CoStartGameClient(); - - if (__instance.AmHost) - yield return __instance.CoStartGameHost(); - } - - for (var index = 0; index < GameData.Instance.PlayerCount; ++index) - { - PlayerControl player = GameData.Instance.AllPlayers[index].Object; - - if (player) - { - player.moveable = true; - player.NetTransform.enabled = true; - player.MyPhysics.enabled = true; - player.MyPhysics.Awake(); - player.MyPhysics.ResetMoveState(); - player.Collider.enabled = true; - ShipStatus.Instance.SpawnPlayer(player, GameData.Instance.PlayerCount, true); - } - } - - FriendsListManager.Instance.SetRecentlyPlayed(GameData.Instance.AllPlayers); - GameData.TimeGameStarted = Time.realtimeSinceStartup; - int map = Mathf.Clamp(GameOptionsManager.Instance.CurrentGameOptions.MapId, 0, Constants.MapNames.Length - 1); - string gameName = GameCode.IntToGameName(AmongUsClient.Instance.GameId); - DebugAnalytics.Instance.Analytics.StartGame(PlayerControl.LocalPlayer.Data, GameData.Instance.PlayerCount, GameOptionsManager.Instance.CurrentGameOptions.NumImpostors, AmongUsClient.Instance.NetworkMode, (MapNames)map, GameOptionsManager.Instance.CurrentGameOptions.GameMode, gameName, ServerManager.Instance.CurrentRegion.Name, GameOptionsManager.Instance.CurrentGameOptions, GameData.Instance.AllPlayers); - - try - { - UnityTelemetry.Instance.StartGame(AmongUsClient.Instance.AmHost, GameData.Instance.PlayerCount, GameOptionsManager.Instance.CurrentGameOptions.NumImpostors, AmongUsClient.Instance.NetworkMode, DataManager.Player.Stats.GetStat(StatID.GamesAsImpostor), DataManager.Player.Stats.GetStat(StatID.GamesStarted), DataManager.Player.Stats.GetStat(StatID.CrewmateStreak)); - NetworkedPlayerInfo.PlayerOutfit defaultOutfit = PlayerControl.LocalPlayer.Data.DefaultOutfit; - UnityTelemetry.Instance.StartGameCosmetics(defaultOutfit.ColorId, defaultOutfit.HatId, defaultOutfit.SkinId, defaultOutfit.PetId, defaultOutfit.VisorId, defaultOutfit.NamePlateId); - } - catch { } - - GameDebugCommands.AddCommands(); - } - } - public static void Postfix(AmongUsClient __instance) { try { LobbySharingAPI.NotifyLobbyStatusChanged(LobbyStatus.In_Game); } @@ -309,6 +199,7 @@ internal static class ChangeRoleSettings ChatCommands.MutedPlayers.Clear(); ExtendedPlayerControl.TempExiled.Clear(); Utils.CachedRoleSettings.Clear(); + MeetingHudCastVotePatch.ShouldCancelVoteList.Clear(); MeetingTimeManager.Init(); Main.DefaultCrewmateVision = Main.RealOptionsData.GetFloat(FloatOptionNames.CrewLightMod); @@ -330,6 +221,9 @@ internal static class ChangeRoleSettings Camouflage.BlockCamouflage = false; Camouflage.Init(); + ReportDeadBodyPatch.CanReport.Clear(); + ReportDeadBodyPatch.WaitReport.Clear(); + RoleResult = []; foreach (PlayerControl pc in Main.CachedAllPlayerControls()) @@ -434,6 +328,7 @@ internal static class ChangeRoleSettings RoleBlockManager.Reset(); ChatManager.ResetHistory(); PerSecondUpdateScheduler.Reset(); + Prompt.Reset(); } catch (Exception e) { Utils.ThrowException(e); } diff --git a/Patches/OutroPatch.cs b/Patches/OutroPatch.cs index b81ecb2ee..c50293f8a 100644 --- a/Patches/OutroPatch.cs +++ b/Patches/OutroPatch.cs @@ -101,7 +101,7 @@ internal static class EndGamePatch HashSet winner = Main.EnumeratePlayerControls().Where(pc => CustomWinnerHolder.WinnerIds.Contains(pc.PlayerId)).ToHashSet(); foreach (CustomRoles team in CustomWinnerHolder.WinnerRoles) - winner.UnionWith(Main.EnumeratePlayerControls().Where(p => p.Is(team) && !winner.Contains(p))); + winner.UnionWith(Main.EnumeratePlayerControls().Where(p => p.Is(team))); Main.WinnerNameList = []; Main.WinnerList = []; diff --git a/Patches/ShowHostMeetingPatch.cs b/Patches/ShowHostMeetingPatch.cs index e264e3e55..b3aa0c29e 100644 --- a/Patches/ShowHostMeetingPatch.cs +++ b/Patches/ShowHostMeetingPatch.cs @@ -23,7 +23,7 @@ public static class ShowHostMeetingPatch Main.ForceRebuildCachesPlayerControls(); GameEndChecker.ForceCheckEnd(); - if (GameStates.IsInGame && HostControl == null) + if (GameStates.IsInGame && !HostControl) { PlayerControl host = AmongUsClient.Instance.GetHost().Character; NetworkedPlayerInfo.PlayerOutfit outfit = Main.PlayerStates[host.Data.PlayerId].NormalOutfit; diff --git a/Roles/Standard/Impostor/Concealing/Warlock.cs b/Roles/Standard/Impostor/Concealing/Warlock.cs index b77033968..2b0f73590 100644 --- a/Roles/Standard/Impostor/Concealing/Warlock.cs +++ b/Roles/Standard/Impostor/Concealing/Warlock.cs @@ -79,6 +79,9 @@ internal class Warlock : RoleBase public override void Init() { On = false; + WarlockTimer = []; + CursedPlayers = []; + IsCurseAndKill = []; } public override void ApplyGameOptions(IGameOptions opt, byte playerId) diff --git a/Roles/Standard/Neutral/Benign/Revolutionist.cs b/Roles/Standard/Neutral/Benign/Revolutionist.cs index 960c50784..0871e16d2 100644 --- a/Roles/Standard/Neutral/Benign/Revolutionist.cs +++ b/Roles/Standard/Neutral/Benign/Revolutionist.cs @@ -62,6 +62,11 @@ internal class Revolutionist : RoleBase public override void Init() { On = false; + IsDraw = []; + RevolutionistTimer = []; + RevolutionistStart = []; + RevolutionistLastTime = []; + RevolutionistCountdown = []; } public override bool CanUseKillButton(PlayerControl pc) diff --git a/Roles/Standard/Neutral/Evil/Arsonist.cs b/Roles/Standard/Neutral/Evil/Arsonist.cs index 602f87ed7..2a9d762f9 100644 --- a/Roles/Standard/Neutral/Evil/Arsonist.cs +++ b/Roles/Standard/Neutral/Evil/Arsonist.cs @@ -67,6 +67,8 @@ internal class Arsonist : RoleBase public override void Init() { On = false; + ArsonistTimer = []; + IsDoused = []; } public override bool CanUseKillButton(PlayerControl pc) diff --git a/Roles/Standard/Neutral/Killing/Infection.cs b/Roles/Standard/Neutral/Killing/Infection.cs index a3ba573e5..b1470a65e 100644 --- a/Roles/Standard/Neutral/Killing/Infection.cs +++ b/Roles/Standard/Neutral/Killing/Infection.cs @@ -71,6 +71,7 @@ public class Infection : RoleBase InfectInfos.Clear(); InfectActive = false; ShadeColor = Utils.GetRoleColor(CustomRoles.Infection).ShadeColor(0.25f); + Updates.Clear(); } public override void Add(byte playerId) diff --git a/Roles/Standard/Neutral/Killing/Sprayer.cs b/Roles/Standard/Neutral/Killing/Sprayer.cs index 5915f568e..4eb0b5549 100644 --- a/Roles/Standard/Neutral/Killing/Sprayer.cs +++ b/Roles/Standard/Neutral/Killing/Sprayer.cs @@ -27,7 +27,7 @@ internal class Sprayer : RoleBase private static readonly Dictionary LastUpdate = []; private static int Id => 643240; - private static PlayerControl SprayerPC => GetPlayerById(SprayerId); + private static PlayerControl SprayerPC; public override bool IsEnable => SprayerId != byte.MaxValue; @@ -73,6 +73,7 @@ internal class Sprayer : RoleBase public override void Init() { SprayerId = byte.MaxValue; + SprayerPC = null; Traps.Clear(); TrappedCount.Clear(); LowerVisionList.Clear(); @@ -82,6 +83,7 @@ internal class Sprayer : RoleBase public override void Add(byte playerId) { SprayerId = playerId; + SprayerPC = playerId.GetPlayer(); playerId.SetAbilityUseLimit(UseLimitOpt.GetFloat()); foreach (PlayerControl pc in Main.CachedAlivePlayerControls()) TrappedCount[pc.PlayerId] = 0;