From 8aac67e4eb0931704ea191eb42f9b77a28275993 Mon Sep 17 00:00:00 2001 From: twix <91138333+whichtwix@users.noreply.github.com> Date: Mon, 29 Apr 2024 11:42:46 +0600 Subject: [PATCH 1/5] remlove lag after 1st time opening hats --- source/Patches/CustomHats/CustomHatPatch.cs | 85 ++++++++++++++++----- source/Patches/CustomHats/HatCache.cs | 8 +- source/Patches/CustomHats/HatLoader.cs | 18 +++-- 3 files changed, 82 insertions(+), 29 deletions(-) diff --git a/source/Patches/CustomHats/CustomHatPatch.cs b/source/Patches/CustomHats/CustomHatPatch.cs index a0188e4d0..efe3c093b 100644 --- a/source/Patches/CustomHats/CustomHatPatch.cs +++ b/source/Patches/CustomHats/CustomHatPatch.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using AmongUs.Data; using HarmonyLib; @@ -11,30 +12,48 @@ namespace TownOfUs.Patches.CustomHats { - [HarmonyPatch(typeof(HatsTab), nameof(HatsTab.OnEnable))] + [HarmonyPatch] + public static class HatsTab_OnEnable { + [HarmonyPatch(typeof(HatsTab), nameof(HatsTab.OnEnable))] + public static bool Prefix(HatsTab __instance) { - __instance.currentHat = DestroyableSingleton.Instance.GetHatById(DataManager.Player.Customization.Hat); - var allHats = DestroyableSingleton.Instance.GetUnlockedHats(); - var hatGroups = new SortedList>( - new PaddedComparer("Vanilla", "") - ); - foreach (var hat in allHats) + __instance.currentHat = HatManager.Instance.GetHatById(DataManager.Player.Customization.Hat); + var allHats = HatManager.Instance.GetUnlockedHats().ToImmutableList(); + + if (HatCache.SortedHats == null) { - if (!hatGroups.ContainsKey(hat.StoreName)) - hatGroups[hat.StoreName] = new List(); - hatGroups[hat.StoreName].Add(hat); + HatCache.SortedHats = new(new PaddedComparer("Vanilla", "")); + foreach (var hat in allHats) + { + if (!HatCache.SortedHats.ContainsKey(hat.StoreName)) HatCache.SortedHats[hat.StoreName] = []; + HatCache.SortedHats[hat.StoreName].Add(hat); + } } - foreach (ColorChip instanceColorChip in __instance.ColorChips) - instanceColorChip.gameObject.Destroy(); + if (HatCache.Children.Count > 0) + { + HatCache.Children.Values.Do(x => + { + x.transform.SetParent(__instance.scroller.Inner); + x.gameObject.SetActive(true); + }); + __instance.scroller.ContentYBounds.max = -(__instance.YStart - (HatCache.hatIdx + 1) / __instance.NumPerRow * __instance.YOffset) - 3f; + __instance.currentHatIsEquipped = true; + + return false; + } + + foreach (ColorChip instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy(); __instance.ColorChips.Clear(); + var groupNameText = __instance.GetComponentInChildren(false); int hatIdx = 0; - foreach ((string groupName, List hats) in hatGroups) + foreach ((string groupName, List hats) in HatCache.SortedHats) { + hatIdx = (hatIdx + 4) / 5 * 5; var text = Object.Instantiate(groupNameText, __instance.scroller.Inner); text.gameObject.transform.localScale = Vector3.one; text.GetComponent().Destroy(); @@ -43,37 +62,61 @@ public static bool Prefix(HatsTab __instance) text.fontSize = 3f; text.fontSizeMax = 3f; text.fontSizeMin = 0f; - - hatIdx = (hatIdx + 4) / 5 * 5; - + text.name = $"{groupName} header"; float xLerp = __instance.XRange.Lerp(0.5f); - float yLerp = __instance.YStart - (hatIdx / __instance.NumPerRow) * __instance.YOffset; + float yLerp = __instance.YStart - hatIdx / __instance.NumPerRow * __instance.YOffset; text.transform.localPosition = new Vector3(xLerp, yLerp, -1f); + HatCache.Children.Add(groupName, text.transform); + hatIdx += 5; foreach (var hat in hats.OrderBy(HatManager.Instance.allHats.IndexOf)) { float num = __instance.XRange.Lerp(hatIdx % __instance.NumPerRow / (__instance.NumPerRow - 1f)); float num2 = __instance.YStart - hatIdx / __instance.NumPerRow * __instance.YOffset; - ColorChip colorChip = Object.Instantiate(__instance.ColorTabPrefab, __instance.scroller.Inner); - colorChip.transform.localPosition = new Vector3(num, num2, -1f); + + var colorChip = Object.Instantiate(__instance.ColorTabPrefab, __instance.scroller.Inner); + colorChip.gameObject.name = hat.ProductId; colorChip.Button.OnClick.AddListener((Action)(() => __instance.SelectHat(hat))); - colorChip.Inner.SetHat(hat, __instance.HasLocalPlayer() ? PlayerControl.LocalPlayer.Data.DefaultOutfit.ColorId : (int)DataManager.Player.Customization.Color); + colorChip.Inner.SetHat(hat, __instance.HasLocalPlayer() ? PlayerControl.LocalPlayer.Data.DefaultOutfit.ColorId : DataManager.Player.Customization.Color); + colorChip.transform.localPosition = new Vector3(num, num2, -1f); colorChip.Inner.transform.localPosition = hat.ChipOffset + new Vector2(0f, -0.3f); if (SubmergedCompatibility.Loaded) { colorChip.gameObject.transform.Find("HatParent").transform.localPosition = new Vector3(-0.1f, 0.05f, -2); } colorChip.Tag = hat; + HatCache.Children.Add(hat.ProductId, colorChip.gameObject.transform); __instance.ColorChips.Add(colorChip); hatIdx += 1; } - } + HatCache.hatIdx = hatIdx; __instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIdx + 1) / __instance.NumPerRow * __instance.YOffset) - 3f; __instance.currentHatIsEquipped = true; return false; } } + + [HarmonyPatch] + + public class HatsTab_OnDisable + { + [HarmonyPatch(typeof(InventoryTab), nameof(InventoryTab.OnDisable))] + + public static bool Prefix(InventoryTab __instance) + { + if (__instance is not HatsTab) return true; + + foreach (var transform in HatCache.Children.Values) + { + transform.SetParent(HatCache.ChipHolder.transform); + transform.gameObject.SetActive(false); + } + + __instance.ColorChips.Clear(); + return false; + } + } } diff --git a/source/Patches/CustomHats/HatCache.cs b/source/Patches/CustomHats/HatCache.cs index 6180c4c82..5c2f8e861 100644 --- a/source/Patches/CustomHats/HatCache.cs +++ b/source/Patches/CustomHats/HatCache.cs @@ -5,8 +5,12 @@ namespace TownOfUs.Patches.CustomHats { public static class HatCache { - public static Dictionary hatViewDatas= new Dictionary(); - + public static SortedList> SortedHats = null; + public static GameObject ChipHolder = null; + + public static Dictionary Children = []; + + public static int hatIdx = 0; } } diff --git a/source/Patches/CustomHats/HatLoader.cs b/source/Patches/CustomHats/HatLoader.cs index eef1d6b28..d0076326f 100644 --- a/source/Patches/CustomHats/HatLoader.cs +++ b/source/Patches/CustomHats/HatLoader.cs @@ -6,6 +6,7 @@ using Reactor.Utilities; using System.Linq; using UnityEngine.AddressableAssets; +using Reactor.Utilities.Extensions; namespace TownOfUs.Patches.CustomHats { @@ -18,8 +19,7 @@ internal static class HatLoader internal static void LoadHatsRoutine() { - if (LoadedHats || !DestroyableSingleton.InstanceExists || DestroyableSingleton.Instance.allHats.Count == 0) - return; + if (LoadedHats || !HatManager.InstanceExists || HatManager.Instance.allHats.Count == 0) return; LoadedHats = true; Coroutines.Start(LoadHats()); } @@ -32,17 +32,23 @@ internal static IEnumerator LoadHats() var hatBehaviours = DiscoverHatBehaviours(); var hatData = new List(); - hatData.AddRange(DestroyableSingleton.Instance.allHats); - hatData.ForEach((Action)(x => x.StoreName = "Vanilla")); + hatData.AddRange(HatManager.Instance.allHats); + hatData.ForEach(x => x.StoreName = "Vanilla"); - var originalCount = DestroyableSingleton.Instance.allHats.ToList().Count; + var originalCount = HatManager.Instance.allHats.ToList().Count; hatBehaviours.Reverse(); for (var i = 0; i < hatBehaviours.Count; i++) { hatBehaviours[i].displayOrder = originalCount + i; hatData.Add(hatBehaviours[i]); } - DestroyableSingleton.Instance.allHats = hatData.ToArray(); + HatManager.Instance.allHats = hatData.ToArray(); + + if (HatCache.ChipHolder == null) + { + HatCache.ChipHolder = new("HatHolder"); + HatCache.ChipHolder.DontDestroy(); + } } catch (Exception e) { From abed1b5c2929d24d513a1d7777ffe606040aef8d Mon Sep 17 00:00:00 2001 From: twix <91138333+whichtwix@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:43:58 +0600 Subject: [PATCH 2/5] fix the index out of range error and add back removed listeners --- source/Patches/CustomHats/CustomHatPatch.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/source/Patches/CustomHats/CustomHatPatch.cs b/source/Patches/CustomHats/CustomHatPatch.cs index efe3c093b..bde7ee339 100644 --- a/source/Patches/CustomHats/CustomHatPatch.cs +++ b/source/Patches/CustomHats/CustomHatPatch.cs @@ -77,6 +77,8 @@ public static bool Prefix(HatsTab __instance) var colorChip = Object.Instantiate(__instance.ColorTabPrefab, __instance.scroller.Inner); colorChip.gameObject.name = hat.ProductId; colorChip.Button.OnClick.AddListener((Action)(() => __instance.SelectHat(hat))); + colorChip.Button.OnMouseOver.AddListener((Action)(() => __instance.SelectHat(hat))); + colorChip.Button.OnMouseOut.AddListener((Action)(() => __instance.SelectHat(HatManager.Instance.GetHatById(DataManager.Player.Customization.Hat)))); colorChip.Inner.SetHat(hat, __instance.HasLocalPlayer() ? PlayerControl.LocalPlayer.Data.DefaultOutfit.ColorId : DataManager.Player.Customization.Color); colorChip.transform.localPosition = new Vector3(num, num2, -1f); colorChip.Inner.transform.localPosition = hat.ChipOffset + new Vector2(0f, -0.3f); @@ -104,6 +106,7 @@ public static bool Prefix(HatsTab __instance) public class HatsTab_OnDisable { [HarmonyPatch(typeof(InventoryTab), nameof(InventoryTab.OnDisable))] + [HarmonyPrefix] public static bool Prefix(InventoryTab __instance) { @@ -118,5 +121,22 @@ public static bool Prefix(InventoryTab __instance) __instance.ColorChips.Clear(); return false; } + + [HarmonyPatch(typeof(PlayerCustomizationMenu), nameof(PlayerCustomizationMenu.OpenTab))] + [HarmonyPrefix] + + public static void Prefix(ref InventoryTab tab) + { + if (tab is HatsTab hattab && hattab.ColorChips.Count == 0) + { + foreach (var transform in HatCache.Children.Values) + { + if (transform.gameObject.GetComponent()) + { + hattab.ColorChips.Add(transform.gameObject.GetComponent()); + } + } + } + } } } From 3b93e4cbffb2cfd79283689165ca806d178ad481 Mon Sep 17 00:00:00 2001 From: twix <91138333+whichtwix@users.noreply.github.com> Date: Fri, 3 May 2024 17:06:13 +0600 Subject: [PATCH 3/5] change to paging since the other method had issues. Removed the added listeners since it made slecting hats impossible --- source/Patches/CustomHats/CustomHatPatch.cs | 101 +++++++++----------- source/Patches/CustomHats/HatCache.cs | 7 +- source/Patches/CustomHats/HatLoader.cs | 7 -- 3 files changed, 44 insertions(+), 71 deletions(-) diff --git a/source/Patches/CustomHats/CustomHatPatch.cs b/source/Patches/CustomHats/CustomHatPatch.cs index bde7ee339..9d4c970b3 100644 --- a/source/Patches/CustomHats/CustomHatPatch.cs +++ b/source/Patches/CustomHats/CustomHatPatch.cs @@ -16,6 +16,10 @@ namespace TownOfUs.Patches.CustomHats public static class HatsTab_OnEnable { + public static int CurrentPage = 0; + + public static string LastHeader = string.Empty; + [HarmonyPatch(typeof(HatsTab), nameof(HatsTab.OnEnable))] public static bool Prefix(HatsTab __instance) @@ -25,33 +29,60 @@ public static bool Prefix(HatsTab __instance) if (HatCache.SortedHats == null) { + var num = 0; HatCache.SortedHats = new(new PaddedComparer("Vanilla", "")); foreach (var hat in allHats) { if (!HatCache.SortedHats.ContainsKey(hat.StoreName)) HatCache.SortedHats[hat.StoreName] = []; HatCache.SortedHats[hat.StoreName].Add(hat); + + if (!HatCache.StoreNames.ContainsValue(hat.StoreName)) + { + HatCache.StoreNames.Add(num, hat.StoreName); + num++; + } } } - if (HatCache.Children.Count > 0) - { - HatCache.Children.Values.Do(x => - { - x.transform.SetParent(__instance.scroller.Inner); - x.gameObject.SetActive(true); - }); - __instance.scroller.ContentYBounds.max = -(__instance.YStart - (HatCache.hatIdx + 1) / __instance.NumPerRow * __instance.YOffset) - 3f; - __instance.currentHatIsEquipped = true; + GenHats(__instance, CurrentPage); - return false; + return false; + } + + [HarmonyPatch(typeof(HatsTab), nameof(HatsTab.Update))] + [HarmonyPrefix] + + public static void Update(HatsTab __instance) + { + if (Input.GetKeyDown(KeyCode.F3)) + { + CurrentPage--; + CurrentPage = CurrentPage < 0 ? HatCache.StoreNames.Count - 1 : CurrentPage; + GenHats(__instance, CurrentPage); + } + else if (Input.GetKeyDown(KeyCode.F4)) + { + CurrentPage++; + CurrentPage = CurrentPage > HatCache.StoreNames.Count - 1 ? 0 : CurrentPage; + GenHats(__instance, CurrentPage); } + } + public static void GenHats(HatsTab __instance, int page) + { foreach (ColorChip instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy(); __instance.ColorChips.Clear(); + if (LastHeader != string.Empty) + { + var header = GameObject.Find(LastHeader); + if (header != null) header.Destroy(); + } + var groupNameText = __instance.GetComponentInChildren(false); int hatIdx = 0; - foreach ((string groupName, List hats) in HatCache.SortedHats) + var group = HatCache.SortedHats.Where(x => x.Key == HatCache.StoreNames[page]); + foreach ((string groupName, List hats) in group) { hatIdx = (hatIdx + 4) / 5 * 5; var text = Object.Instantiate(groupNameText, __instance.scroller.Inner); @@ -62,11 +93,10 @@ public static bool Prefix(HatsTab __instance) text.fontSize = 3f; text.fontSizeMax = 3f; text.fontSizeMin = 0f; - text.name = $"{groupName} header"; + LastHeader = text.name = $"{groupName} header"; float xLerp = __instance.XRange.Lerp(0.5f); float yLerp = __instance.YStart - hatIdx / __instance.NumPerRow * __instance.YOffset; text.transform.localPosition = new Vector3(xLerp, yLerp, -1f); - HatCache.Children.Add(groupName, text.transform); hatIdx += 5; foreach (var hat in hats.OrderBy(HatManager.Instance.allHats.IndexOf)) @@ -77,8 +107,6 @@ public static bool Prefix(HatsTab __instance) var colorChip = Object.Instantiate(__instance.ColorTabPrefab, __instance.scroller.Inner); colorChip.gameObject.name = hat.ProductId; colorChip.Button.OnClick.AddListener((Action)(() => __instance.SelectHat(hat))); - colorChip.Button.OnMouseOver.AddListener((Action)(() => __instance.SelectHat(hat))); - colorChip.Button.OnMouseOut.AddListener((Action)(() => __instance.SelectHat(HatManager.Instance.GetHatById(DataManager.Player.Customization.Hat)))); colorChip.Inner.SetHat(hat, __instance.HasLocalPlayer() ? PlayerControl.LocalPlayer.Data.DefaultOutfit.ColorId : DataManager.Player.Customization.Color); colorChip.transform.localPosition = new Vector3(num, num2, -1f); colorChip.Inner.transform.localPosition = hat.ChipOffset + new Vector2(0f, -0.3f); @@ -87,56 +115,13 @@ public static bool Prefix(HatsTab __instance) colorChip.gameObject.transform.Find("HatParent").transform.localPosition = new Vector3(-0.1f, 0.05f, -2); } colorChip.Tag = hat; - HatCache.Children.Add(hat.ProductId, colorChip.gameObject.transform); __instance.ColorChips.Add(colorChip); hatIdx += 1; } } - HatCache.hatIdx = hatIdx; __instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIdx + 1) / __instance.NumPerRow * __instance.YOffset) - 3f; __instance.currentHatIsEquipped = true; - - return false; - } - } - - [HarmonyPatch] - - public class HatsTab_OnDisable - { - [HarmonyPatch(typeof(InventoryTab), nameof(InventoryTab.OnDisable))] - [HarmonyPrefix] - - public static bool Prefix(InventoryTab __instance) - { - if (__instance is not HatsTab) return true; - - foreach (var transform in HatCache.Children.Values) - { - transform.SetParent(HatCache.ChipHolder.transform); - transform.gameObject.SetActive(false); - } - - __instance.ColorChips.Clear(); - return false; - } - - [HarmonyPatch(typeof(PlayerCustomizationMenu), nameof(PlayerCustomizationMenu.OpenTab))] - [HarmonyPrefix] - - public static void Prefix(ref InventoryTab tab) - { - if (tab is HatsTab hattab && hattab.ColorChips.Count == 0) - { - foreach (var transform in HatCache.Children.Values) - { - if (transform.gameObject.GetComponent()) - { - hattab.ColorChips.Add(transform.gameObject.GetComponent()); - } - } - } } } } diff --git a/source/Patches/CustomHats/HatCache.cs b/source/Patches/CustomHats/HatCache.cs index 5c2f8e861..431f2b1ac 100644 --- a/source/Patches/CustomHats/HatCache.cs +++ b/source/Patches/CustomHats/HatCache.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using UnityEngine; namespace TownOfUs.Patches.CustomHats { @@ -7,10 +6,6 @@ public static class HatCache { public static SortedList> SortedHats = null; - public static GameObject ChipHolder = null; - - public static Dictionary Children = []; - - public static int hatIdx = 0; + public static Dictionary StoreNames = []; } } diff --git a/source/Patches/CustomHats/HatLoader.cs b/source/Patches/CustomHats/HatLoader.cs index d0076326f..1b48a0781 100644 --- a/source/Patches/CustomHats/HatLoader.cs +++ b/source/Patches/CustomHats/HatLoader.cs @@ -6,7 +6,6 @@ using Reactor.Utilities; using System.Linq; using UnityEngine.AddressableAssets; -using Reactor.Utilities.Extensions; namespace TownOfUs.Patches.CustomHats { @@ -43,12 +42,6 @@ internal static IEnumerator LoadHats() hatData.Add(hatBehaviours[i]); } HatManager.Instance.allHats = hatData.ToArray(); - - if (HatCache.ChipHolder == null) - { - HatCache.ChipHolder = new("HatHolder"); - HatCache.ChipHolder.DontDestroy(); - } } catch (Exception e) { From fadae188a052012795f047dc1851fb378b4c0696 Mon Sep 17 00:00:00 2001 From: twix <91138333+whichtwix@users.noreply.github.com> Date: Fri, 3 May 2024 18:52:03 +0600 Subject: [PATCH 4/5] added text --- source/Patches/CustomHats/CustomHatPatch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Patches/CustomHats/CustomHatPatch.cs b/source/Patches/CustomHats/CustomHatPatch.cs index 9d4c970b3..2d4d623f7 100644 --- a/source/Patches/CustomHats/CustomHatPatch.cs +++ b/source/Patches/CustomHats/CustomHatPatch.cs @@ -88,7 +88,7 @@ public static void GenHats(HatsTab __instance, int page) var text = Object.Instantiate(groupNameText, __instance.scroller.Inner); text.gameObject.transform.localScale = Vector3.one; text.GetComponent().Destroy(); - text.text = groupName; + text.text = $"{groupName}\nPress F3 & F4 to cycle pages"; text.alignment = TextAlignmentOptions.Center; text.fontSize = 3f; text.fontSizeMax = 3f; From 98953419f17e0cb67c2688c71106080eaf0b084f Mon Sep 17 00:00:00 2001 From: twix <91138333+whichtwix@users.noreply.github.com> Date: Sat, 4 May 2024 00:33:21 +0600 Subject: [PATCH 5/5] listeners are fine now --- source/Patches/CustomHats/CustomHatPatch.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/Patches/CustomHats/CustomHatPatch.cs b/source/Patches/CustomHats/CustomHatPatch.cs index 2d4d623f7..93bab38db 100644 --- a/source/Patches/CustomHats/CustomHatPatch.cs +++ b/source/Patches/CustomHats/CustomHatPatch.cs @@ -106,7 +106,9 @@ public static void GenHats(HatsTab __instance, int page) var colorChip = Object.Instantiate(__instance.ColorTabPrefab, __instance.scroller.Inner); colorChip.gameObject.name = hat.ProductId; - colorChip.Button.OnClick.AddListener((Action)(() => __instance.SelectHat(hat))); + colorChip.Button.OnClick.AddListener((Action)(() => __instance.ClickEquip())); + colorChip.Button.OnMouseOver.AddListener((Action)(() => __instance.SelectHat(hat))); + colorChip.Button.OnMouseOut.AddListener((Action)(() => __instance.SelectHat(HatManager.Instance.GetHatById(DataManager.Player.Customization.Hat)))); colorChip.Inner.SetHat(hat, __instance.HasLocalPlayer() ? PlayerControl.LocalPlayer.Data.DefaultOutfit.ColorId : DataManager.Player.Customization.Color); colorChip.transform.localPosition = new Vector3(num, num2, -1f); colorChip.Inner.transform.localPosition = hat.ChipOffset + new Vector2(0f, -0.3f);