Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MoreHeadUtilities v1.0.11
MoreHeadUtilities.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using MenuLib; using MenuLib.MonoBehaviors; using Microsoft.CodeAnalysis; using MoreHead; using MoreHead.MoreHead.Patchers; using MoreHeadUtilities.Plugin; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("MoreHeadUtilities")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+09709e23c7cce3a3ba73cc372b40476964bbba6a")] [assembly: AssemblyProduct("MoreHeadUtilities")] [assembly: AssemblyTitle("MoreHeadUtilities")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace MoreHeadUtilities { public class PartShrinker : MonoBehaviour { [SerializeField] private HiddenParts.Part partToHide = HiddenParts.Part.LeftPupil; [SerializeField] private bool hideChildren = true; private Transform TotalParent; private HiddenParts parentComponent; private static double totalSearchingTime; private bool isFrameOne = true; private bool isFrameTwo; public static ManualLogSource bepInExLog; public static void Init(ManualLogSource source) { bepInExLog = source; bepInExLog.LogInfo((object)"LoggerUtil initialized!"); } public void Log(string message) { if (MoreHeadUtilitiesPlugin._enableDebugLogging.Value) { bepInExLog.LogInfo((object)message); } } public void LogError(string message) { if (MoreHeadUtilitiesPlugin._enableDebugLogging.Value) { bepInExLog.LogError((object)message); } } public void Update() { if (isFrameOne) { isFrameOne = false; isFrameTwo = true; } else { if (!isFrameTwo) { return; } isFrameTwo = false; Stopwatch.StartNew(); if (!Object.op_Implicit((Object)(object)parentComponent)) { Log(((Object)((Component)this).gameObject).name + " is finding parent on awakening"); TotalParent = ((Component)this).transform; while (((Object)TotalParent).name != "ANIM BOT" && ((Object)TotalParent).name != null && ((Object)TotalParent).name != "WorldDecorationFollower") { TotalParent = TotalParent.parent; } if (((Object)TotalParent).name == null) { LogError("No root found"); return; } if (((Object)TotalParent).name == "WorldDecorationFollower") { LogError(((Object)((Component)this).gameObject).name + " is set to world parent. MoreHeadUtilities does not support part removal from a world object."); return; } parentComponent = ((Component)TotalParent).GetComponent<HiddenParts>(); if (!Object.op_Implicit((Object)(object)parentComponent)) { parentComponent = ((Component)TotalParent).gameObject.AddComponent<HiddenParts>(); } else { Log("Part already exists"); } } parentComponent.AddHiddenPart(partToHide, hideChildren); } } private void OnDisable() { if (isFrameOne) { return; } isFrameOne = true; if (!Object.op_Implicit((Object)(object)parentComponent)) { Log(((Object)((Component)this).gameObject).name + " is finding parent for destruction"); TotalParent = ((Component)this).transform; while (((Object)TotalParent).name != "ANIM BOT" && ((Object)TotalParent).name != null && ((Object)TotalParent).name != "WorldDecorationFollower") { TotalParent = TotalParent.parent; } if (((Object)TotalParent).name == null) { LogError("No root found"); return; } if (((Object)TotalParent).name == "WorldDecorationFollower") { LogError(((Object)((Component)this).gameObject).name + " is set to world parent. MoreHeadUtilities does not support part removal from a world object."); return; } parentComponent = ((Component)TotalParent).GetComponent<HiddenParts>(); if (!Object.op_Implicit((Object)(object)parentComponent)) { parentComponent = ((Component)TotalParent).gameObject.AddComponent<HiddenParts>(); } else { Log("Component already exists"); } } parentComponent.RemoveHiddenPart(partToHide, hideChildren); } } public class HiddenParts : MonoBehaviour { public enum Part { Health, LeftArm, RightArm, LeftLeg, RightLeg, EyeLeft, EyeRight, Head, Neck, Body, Hips, LeftPupil, RightPupil } public static ManualLogSource bepInExLog; private string[][] partNames = new string[13][] { new string[3] { "mesh_health", "mesh_health frame", "mesh_health shadow" }, new string[1] { "mesh_arm_l" }, new string[1] { "mesh_arm_r" }, new string[1] { "mesh_leg_l" }, new string[1] { "mesh_leg_r" }, new string[1] { "mesh_eye_l" }, new string[1] { "mesh_eye_r" }, new string[1] { "mesh_head_top" }, new string[2] { "mesh_head_bot_sphere", "mesh_head_bot_flat" }, new string[2] { "mesh_body_top_sphere", "mesh_body_top_flat" }, new string[1] { "mesh_body_bot" }, new string[1] { "mesh_pupil_l" }, new string[1] { "mesh_pupil_r" } }; private MeshRenderer[][] partRenderers = new MeshRenderer[13][] { (MeshRenderer[])(object)new MeshRenderer[3], (MeshRenderer[])(object)new MeshRenderer[1], (MeshRenderer[])(object)new MeshRenderer[1], (MeshRenderer[])(object)new MeshRenderer[1], (MeshRenderer[])(object)new MeshRenderer[1], (MeshRenderer[])(object)new MeshRenderer[1], (MeshRenderer[])(object)new MeshRenderer[1], (MeshRenderer[])(object)new MeshRenderer[1], (MeshRenderer[])(object)new MeshRenderer[2], (MeshRenderer[])(object)new MeshRenderer[2], (MeshRenderer[])(object)new MeshRenderer[1], (MeshRenderer[])(object)new MeshRenderer[1], (MeshRenderer[])(object)new MeshRenderer[1] }; private Part[][] childParts = new Part[13][] { new Part[0], new Part[0], new Part[0], new Part[0], new Part[0], new Part[1] { Part.LeftPupil }, new Part[1] { Part.RightPupil }, new Part[2] { Part.EyeLeft, Part.EyeRight }, new Part[2] { Part.Head, Part.Health }, new Part[3] { Part.Neck, Part.LeftArm, Part.RightArm }, new Part[3] { Part.Body, Part.LeftLeg, Part.RightLeg }, new Part[0], new Part[0] }; private List<Part> hiddenParts = new List<Part>(); private bool updatedThisFrame; public static void Init(ManualLogSource source) { bepInExLog = source; bepInExLog.LogInfo((object)"LoggerUtil initialized!"); } public void Log(string message) { ManualLogSource obj = bepInExLog; if (obj != null) { obj.LogInfo((object)message); } } public void LogError(string message) { ManualLogSource obj = bepInExLog; if (obj != null) { obj.LogError((object)message); } } public void Start() { foreach (Part value in Enum.GetValues(typeof(Part))) { for (int i = 0; i < partNames[(int)value].Length; i++) { Transform val = FindInHierarchy(((Component)this).transform, partNames[(int)value][i]); if ((Object)(object)val == (Object)null) { Log("Part '" + partNames[(int)value][i] + "' not found"); continue; } MeshRenderer component = ((Component)val).gameObject.GetComponent<MeshRenderer>(); if (Object.op_Implicit((Object)(object)component)) { Log("Found part '" + partNames[(int)value][i] + "'"); partRenderers[(int)value][i] = component; } } } } public void AddHiddenPart(Part part, bool hideChildren, bool update = true) { Log($"Adding part {part}"); hiddenParts.Add(part); if (hideChildren) { Part[] array = childParts[(int)part]; foreach (Part part2 in array) { AddHiddenPart(part2, hideChildren, update: false); } } updatedThisFrame = true; } public void RemoveHiddenPart(Part part, bool hideChildren, bool update = true) { if (hiddenParts.Contains(part)) { hiddenParts.Remove(part); } if (hideChildren) { Part[] array = childParts[(int)part]; foreach (Part part2 in array) { RemoveHiddenPart(part2, hideChildren, update: false); } } updatedThisFrame = true; } private Transform FindInHierarchy(Transform parent, string name) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown if (((Object)parent).name == name) { return parent; } foreach (Transform item in parent) { Transform parent2 = item; Transform val = FindInHierarchy(parent2, name); if ((Object)(object)val != (Object)null) { return val; } } return null; } public void LateUpdate() { if (updatedThisFrame) { UpdateHiddenParts(); updatedThisFrame = false; } } public void UpdateHiddenParts() { Log($"Updating parts, to be hidden: {hiddenParts.ToArray()}"); foreach (Part value in Enum.GetValues(typeof(Part))) { ShowPart(value); } foreach (Part hiddenPart in hiddenParts) { HidePart(hiddenPart); } } private void ShowPart(Part partToShow) { for (int i = 0; i < partNames[(int)partToShow].Length; i++) { MeshRenderer val = partRenderers[(int)partToShow][i]; if ((Object)(object)val != (Object)null) { MeshRenderer component = ((Component)val).gameObject.GetComponent<MeshRenderer>(); if ((Object)(object)component != (Object)null) { ((Renderer)component).enabled = true; } } } } private void HidePart(Part partToHide) { for (int i = 0; i < partNames[(int)partToHide].Length; i++) { MeshRenderer val = partRenderers[(int)partToHide][i]; if ((Object)(object)val != (Object)null) { MeshRenderer component = ((Component)val).gameObject.GetComponent<MeshRenderer>(); if ((Object)(object)component != (Object)null) { ((Renderer)component).enabled = false; } } } } } } namespace MoreHeadUtilities.Plugin { [BepInPlugin("com.maygik.moreheadutilities", "MoreHeadUtilities", "1.0.8")] public class MoreHeadUtilitiesPlugin : BaseUnityPlugin { public static ConfigEntry<bool> _enableDebugLogging; private void Awake() { //IL_0094: Unknown result type (might be due to invalid IL or missing references) _enableDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableDebugLogging", false, "Enable debug logging for MoreHeadUtilities."); if (_enableDebugLogging.Value) { PartShrinker.Init(((BaseUnityPlugin)this).Logger); ManualLogSource logger = ((BaseUnityPlugin)this).Logger; if (logger != null) { logger.LogInfo((object)"MoreHeadUtilities initialized and logger passed to PartShrinker."); } HiddenParts.Init(((BaseUnityPlugin)this).Logger); ManualLogSource logger2 = ((BaseUnityPlugin)this).Logger; if (logger2 != null) { logger2.LogInfo((object)"MoreHeadUtilities initialized and logger passed to HiddenParts."); } Logger.Init(((BaseUnityPlugin)this).Logger); ManualLogSource logger3 = ((BaseUnityPlugin)this).Logger; if (logger3 != null) { logger3.LogInfo((object)"MoreHeadUtilities initialized and logger passed to DecorationGroups."); } } new Harmony("com.maygik.moreheadutilities").PatchAll(); ManualLogSource logger4 = ((BaseUnityPlugin)this).Logger; if (logger4 != null) { logger4.LogInfo((object)"Harmony patches applied."); } } } } namespace MoreHead { internal static class Logger { public static ManualLogSource? log; public static void Init(ManualLogSource logger) { log = logger; } public static void Log(string message) { ManualLogSource? obj = log; if (obj != null) { obj.LogInfo((object)message); } } public static void LogError(string message) { ManualLogSource? obj = log; if (obj != null) { obj.LogError((object)message); } } } internal static class MoreHeadGroupStorage { public static Dictionary<string?, List<string?>> tagGroupElements = new Dictionary<string, List<string>>(); public static Dictionary<string, bool> activeGroups = new Dictionary<string, bool>(); } internal static class MoreHeadUIStorage { [CanBeNull] public static REPOPopupPage page = null; [CanBeNull] public static string group = null; public static bool resetPosition = true; public static Dictionary<string?, REPOButton> groupButtons = new Dictionary<string, REPOButton>(); public static Dictionary<string?, List<string>> groupButtonTags = new Dictionary<string, List<string>>(); } internal class HeadDecorationManagerStorage { public static List<string?> Decorations = new List<string>(); } [HarmonyPatch(typeof(MoreHeadUI))] [HarmonyPatch("CreateAllDecorationButtons", new Type[] { typeof(REPOPopupPage) })] internal static class Patch_CreateAllDecorationButtons { private static readonly MethodInfo ClearScrolls = AccessTools.Method(typeof(Dictionary<string, List<REPOScrollViewElement>>), "Clear", (Type[])null, (Type[])null); private static readonly MethodInfo ToListDecorations = AccessTools.Method(typeof(Enumerable), "ToList", (Type[])null, (Type[])null).MakeGenericMethod(typeof(DecorationInfo)); private static readonly MethodInfo Helper1 = AccessTools.Method(typeof(MoreHeadUIHelpers), "Patch1_CreateAllDecorationButtons", (Type[])null, (Type[])null); private static readonly MethodInfo Helper2 = AccessTools.Method(typeof(MoreHeadUIHelpers), "Patch2_CreateAllDecorationButtons", (Type[])null, (Type[])null); private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instrs, ILGenerator il) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown List<CodeInstruction> list = instrs.ToList(); bool flag = false; bool flag2 = false; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (!flag && val.opcode == OpCodes.Callvirt && val.operand is MethodInfo methodInfo && methodInfo.Equals(ClearScrolls)) { Logger.Log("Patching Patch1_CreateAllDecorationButtons"); list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)Helper1)); flag = true; Logger.Log("Patched Patch1_CreateAllDecorationButtons"); continue; } if (!flag2 && val.opcode == OpCodes.Call && val.operand is MethodInfo methodInfo2 && methodInfo2.Equals(ToListDecorations)) { Logger.Log("Patching Patch2_CreateAllDecorationButtons"); il.DeclareLocal(typeof(List<DecorationInfo>)); list.Insert(++i, new CodeInstruction(OpCodes.Pop, (object)null)); list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)Helper2)); Logger.Log("Patched Patch2_CreateAllDecorationButtons"); flag2 = true; i += 3; } if (flag && flag2) { break; } } return list; } } [HarmonyPatch(typeof(MoreHeadUI))] [HarmonyPatch("CreateAllDecorationButtons", new Type[] { typeof(REPOPopupPage) })] internal static class Prefix_CreateAllDecorationButtons { [HarmonyPrefix] private static bool Prefix(REPOPopupPage page) { MoreHeadUIStorage.page = page; MoreHeadUIStorage.groupButtons.Clear(); MoreHeadUIStorage.groupButtonTags.Clear(); return true; } } [HarmonyPatch(typeof(MoreHeadUI))] [HarmonyPatch("CreateDecorationButton", new Type[] { typeof(REPOPopupPage), typeof(DecorationInfo) })] internal static class Patch_CreateDecorationButton { [CompilerGenerated] private sealed class <RestoreScrollAfterGroupToggle>d__5 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public REPOPopupPage page; public RectTransform anchor; public float beforeY; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RestoreScrollAfterGroupToggle>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: { <>1__state = -1; Canvas.ForceUpdateCanvases(); page.scrollView.UpdateElements(); float y = ((Transform)anchor).position.y; float num = beforeY - y; ScrollRect componentInChildren = ((Component)page.scrollView).GetComponentInChildren<ScrollRect>(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.content != (Object)null) { Vector2 anchoredPosition = componentInChildren.content.anchoredPosition; anchoredPosition.y += num; componentInChildren.content.anchoredPosition = anchoredPosition; } Canvas.ForceUpdateCanvases(); page.scrollView.UpdateElements(); return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly MethodInfo ShowTagDecorationsMI = AccessTools.Method(typeof(MoreHeadUI), "ShowTagDecorations", new Type[1] { typeof(string) }, (Type[])null); [HarmonyPrefix] private static bool Prefix(REPOPopupPage page, DecorationInfo decoration) { try { string text = HeadDecorationManagerStorage.Decorations[HeadDecorationManager.Decorations.IndexOf(decoration)]; if (text != null && text != "" && MoreHeadGroupStorage.tagGroupElements.TryGetValue("ALL", out List<string> value)) { if (!MoreHeadGroupStorage.activeGroups.ContainsKey(text)) { Logger.Log("Initialising group: " + text); MoreHeadGroupStorage.activeGroups[text] = false; } if (!value.Contains(text)) { CreateGroupButton(page, text); } } string[] source = (string[])typeof(MoreHeadUI).GetField("LIMB_TAGS", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null); MoreHeadGroupStorage.tagGroupElements["ALL"].Add(text); if (text != null) { if (!MoreHeadUIStorage.groupButtonTags.ContainsKey(text)) { Logger.Log("Initialising group button tag list for " + text); MoreHeadUIStorage.groupButtonTags[text] = new List<string>(); } MoreHeadUIStorage.groupButtonTags[text].Add("ALL"); } List<string> value2; if (source.Contains(decoration.ParentTag.ToUpper())) { MoreHeadGroupStorage.tagGroupElements["LIMBS"].Add(text); if (text != null) { MoreHeadUIStorage.groupButtonTags[text].Add("LIMBS"); } } else if (MoreHeadGroupStorage.tagGroupElements.TryGetValue(decoration.ParentTag.ToUpper(), out value2)) { value2.Add(text); if (text != null) { MoreHeadUIStorage.groupButtonTags[text].Add(decoration.ParentTag.ToUpper()); } } return true; } catch (Exception arg) { Logger.LogError($"Error creating decoration button {decoration.Name}: {arg}"); throw; } } private static string GetGroupButtonText(string group) { if (!MoreHeadGroupStorage.activeGroups[group]) { return "<size=20><color=#CCCCCC>[+]" + group + "</color></size>"; } return "<size=20><color=#777777>[-]" + group + "</color></size>"; } private static void CreateGroupButton(REPOPopupPage page, string groupName) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown try { string buttonText = GetGroupButtonText(groupName); REPOButton repoButton = null; page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) repoButton = MenuAPI.CreateREPOButton(buttonText, (Action)delegate { OnDecorationGroupButtonClick(groupName); }, scrollView, default(Vector2)); return ((REPOElement)repoButton).rectTransform; }, 0f, 0f); if ((Object)(object)repoButton != (Object)null) { MoreHeadUIStorage.groupButtons[groupName] = repoButton; MoreHeadUIStorage.groupButtonTags[groupName] = new List<string>(); MoreHeadUIStorage.group = groupName; return; } throw new Exception("Failed to create group button."); } catch (Exception ex) { Logger.Log("Error creating group button: " + ex.Message); } } private static void OnDecorationGroupButtonClick(string? groupName) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) Logger.Log("OnDecorationGroupButtonClick called for group: " + groupName); string text = (string)typeof(MoreHeadUI).GetField("currentTagFilter", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); REPOButton value = null; MoreHeadUIStorage.groupButtons.TryGetValue(groupName, out value); RectTransform val = ((value != null) ? ((REPOElement)value).rectTransform : null); float beforeY = (((Object)(object)val != (Object)null) ? ((Transform)val).position.y : 0f); MoreHeadGroupStorage.activeGroups[groupName] = !MoreHeadGroupStorage.activeGroups[groupName]; MoreHeadUIStorage.resetPosition = false; ShowTagDecorationsMI.Invoke(null, new object[1] { text }); if ((Object)(object)value != (Object)null) { string groupButtonText = GetGroupButtonText(groupName); ((TMP_Text)value.labelTMP).text = groupButtonText; } if ((Object)(object)MoreHeadUIStorage.page != (Object)null && (Object)(object)val != (Object)null) { MonoBehaviour obj = Object.FindObjectOfType<MonoBehaviour>(); if (obj != null) { obj.StartCoroutine(RestoreScrollAfterGroupToggle(MoreHeadUIStorage.page, val, beforeY)); } } MoreHeadUIStorage.resetPosition = true; } [IteratorStateMachine(typeof(<RestoreScrollAfterGroupToggle>d__5))] private static IEnumerator RestoreScrollAfterGroupToggle(REPOPopupPage page, RectTransform anchor, float beforeY) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RestoreScrollAfterGroupToggle>d__5(0) { page = page, anchor = anchor, beforeY = beforeY }; } } [HarmonyPatch(typeof(HeadDecorationManager))] [HarmonyPatch("LoadDecorationBundle", new Type[] { typeof(string) })] internal static class Patch_LoadDecorationBundle { private static readonly MethodInfo EnsureUniqueDisplayName = AccessTools.Method(typeof(HeadDecorationManager), "EnsureUniqueDisplayName", new Type[1] { typeof(string) }, (Type[])null); private static readonly MethodInfo EnsureUniqueName = AccessTools.Method(typeof(HeadDecorationManager), "EnsureUniqueName", new Type[1] { typeof(string) }, (Type[])null); private static readonly MethodInfo AddDecorationHelper1 = AccessTools.Method(typeof(HeadDecorationManagerHelpers), "Patch1_LoadDecorationBundle", new Type[1] { typeof(string) }, (Type[])null); private static readonly MethodInfo AddDecorationHelper2 = AccessTools.Method(typeof(HeadDecorationManagerHelpers), "Patch2_LoadDecorationBundle", (Type[])null, (Type[])null); private static readonly MethodInfo AddDecorationHelper3 = AccessTools.Method(typeof(HeadDecorationManagerHelpers), "Patch3_LoadDecorationBundle", (Type[])null, (Type[])null); private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instrs) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown List<CodeInstruction> list = instrs.ToList(); bool flag = false; bool flag2 = false; bool flag3 = false; for (int i = 0; i < list.Count(); i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Call && val.operand == EnsureUniqueDisplayName) { Logger.Log("Patching AddDecorationHelper2"); list.Insert(i, new CodeInstruction(OpCodes.Call, (object)AddDecorationHelper2)); Logger.Log("Patched AddDecorationHelper2"); flag2 = true; i += 2; } if (val.opcode == OpCodes.Call && val.operand == EnsureUniqueName) { Logger.Log("Patching AddDecorationHelper1"); list.Insert(i, new CodeInstruction(OpCodes.Dup, (object)null)); list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)AddDecorationHelper1)); Logger.Log("Patched AddDecorationHelper1"); flag = true; i += 2; } if (!flag3 && list[i].opcode == OpCodes.Call && list[i].operand == AccessTools.Method(typeof(DecorationBlacklistManager), "IsBlacklisted", new Type[1] { typeof(string) }, (Type[])null)) { int num = i + 4; Logger.Log("Patching AddDecorationHelper3"); list.Insert(num++, new CodeInstruction(OpCodes.Call, (object)AddDecorationHelper3)); Logger.Log("Patched AddDecorationHelper3"); flag3 = true; i += 5; } if (flag2 && flag && flag3) { break; } } return list; } } [HarmonyPatch(typeof(MoreHeadUI))] [HarmonyPatch("CreateDecorationButton", new Type[] { typeof(REPOPopupPage), typeof(DecorationInfo) })] internal static class Transpiler_CreateDecorationButton { private static readonly MethodInfo PatchMethod = AccessTools.Method(typeof(MoreHeadUIHelpers), "Patch1_CreateDecorationButton", new Type[2] { typeof(DecorationInfo), typeof(string) }, (Type[])null); private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instrs) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown List<CodeInstruction> list = instrs.ToList(); for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Callvirt && val.operand is MethodInfo methodInfo && methodInfo.Name == "Add" && methodInfo.DeclaringType == typeof(List<REPOScrollViewElement>)) { Logger.Log("Patch adding group"); list.Insert(i + 1, new CodeInstruction(OpCodes.Ldarg_1, (object)null)); list.Insert(i + 2, new CodeInstruction(OpCodes.Ldstr, (object)(MoreHeadUIStorage.group ?? ""))); list.Insert(i + 3, new CodeInstruction(OpCodes.Call, (object)PatchMethod)); i += 3; } } return list; } } [HarmonyPatch(typeof(MoreHeadUI))] [HarmonyPatch("UpdateDecorationVisibility")] internal static class Patch_UpdateDecorationVisibility { [HarmonyPrefix] private static bool Prefix() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown try { Type typeFromHandle = typeof(MoreHeadUI); Logger.Log("Accessing decorationsPage"); REPOPopupPage decorationsPage = (REPOPopupPage)typeFromHandle.GetField("decorationsPage", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null); Logger.Log("Accessing tagScrollViewElements"); Dictionary<string, List<REPOScrollViewElement>> tagScrollViewElements = (Dictionary<string, List<REPOScrollViewElement>>)typeFromHandle.GetField("tagScrollViewElements", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null); Logger.Log("Accessing currentTagFilter"); string currentTagFilter = (string)typeFromHandle.GetField("currentTagFilter", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null); FieldInfo field = typeFromHandle.GetField("currentSearchQuery", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); string currentSearchQuery = ""; try { currentSearchQuery = (string)field.GetValue(null); } catch { } Dictionary<string, List<DecorationInfo>> decorationDataCache = (Dictionary<string, List<DecorationInfo>>)typeFromHandle.GetField("decorationDataCache", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null); Dictionary<string, REPOButton> decorationButtons = (Dictionary<string, REPOButton>)typeFromHandle.GetField("decorationButtons", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null); ShowDecorationsForTag(decorationsPage, tagScrollViewElements, currentTagFilter, currentSearchQuery, decorationDataCache, decorationButtons); return false; } catch (Exception) { Logger.LogError("Error updating visibility"); } return true; } private static void ShowDecorationsForTag(REPOPopupPage decorationsPage, Dictionary<string, List<REPOScrollViewElement>> tagScrollViewElements, string currentTagFilter, string currentSearchQuery, Dictionary<string, List<DecorationInfo>> decorationDataCache, Dictionary<string, REPOButton> decorationButtons) { try { if ((Object)(object)decorationsPage == (Object)null || string.IsNullOrEmpty(currentTagFilter) || !tagScrollViewElements.TryGetValue(currentTagFilter, out var value) || !decorationDataCache.TryGetValue(currentTagFilter, out var value2)) { return; } foreach (KeyValuePair<string, List<REPOScrollViewElement>> tagScrollViewElement in tagScrollViewElements) { foreach (REPOScrollViewElement item in tagScrollViewElement.Value) { if ((Object)(object)item != (Object)null) { item.visibility = false; } } } bool flag = string.IsNullOrEmpty(currentSearchQuery); Logger.Log($"Showing decorations for tag: {currentTagFilter} with search query: '{currentSearchQuery}' (isSearchEmpty: {flag})"); if (flag) { Logger.Log("No search query, showing all decorations for tag: " + currentTagFilter); foreach (REPOScrollViewElement element in value) { if (!((Object)(object)element != (Object)null)) { continue; } element.visibility = true; string decorationName = decorationButtons.FirstOrDefault(delegate(KeyValuePair<string, REPOButton> kvp) { REPOButton value6 = kvp.Value; return (Object)(object)((value6 != null) ? ((REPOElement)value6).repoScrollViewElement : null) == (Object)(object)element; }).Key; if (string.IsNullOrEmpty(decorationName)) { continue; } int num = HeadDecorationManager.Decorations.FindIndex((DecorationInfo d) => d.Name == decorationName); if (num >= 0) { string text = HeadDecorationManagerStorage.Decorations[num]; if (text != null && MoreHeadGroupStorage.activeGroups.ContainsKey(text)) { Logger.Log($"Setting visibility of decoration '{decorationName}' in group '{text}' to {MoreHeadGroupStorage.activeGroups[text]}"); element.visibility = MoreHeadGroupStorage.activeGroups[text]; } } } } else { Logger.Log("Search query present, filtering decorations for tag: " + currentTagFilter + " with search query: '" + currentSearchQuery + "'"); string value3 = currentSearchQuery.Replace(" ", "").ToLowerInvariant(); foreach (DecorationInfo item2 in value2) { if (decorationButtons.TryGetValue(item2.Name ?? string.Empty, out var value4) && (Object)(object)value4 != (Object)null && value.Contains(((REPOElement)value4).repoScrollViewElement)) { string text2 = item2.DisplayName?.Replace(" ", "").ToLowerInvariant() ?? ""; ((REPOElement)value4).repoScrollViewElement.visibility = text2.Contains(value3); } } } if (flag) { Logger.Log("Showing groups for tag filter: " + currentTagFilter); for (int i = 0; i < MoreHeadUIStorage.groupButtons.Count(); i++) { string key = MoreHeadUIStorage.groupButtons.ElementAt(i).Key; MoreHeadUIStorage.groupButtonTags.TryGetValue(key, out var value5); if (currentTagFilter == "ALL" || value5.Contains(currentTagFilter)) { Logger.Log("Showing group for tag : " + key); ((REPOElement)MoreHeadUIStorage.groupButtons[key]).repoScrollViewElement.visibility = true; } else { ((REPOElement)MoreHeadUIStorage.groupButtons[key]).repoScrollViewElement.visibility = false; } } } else { for (int j = 0; j < MoreHeadUIStorage.groupButtons.Count(); j++) { string key2 = MoreHeadUIStorage.groupButtons.ElementAt(j).Key; ((REPOElement)MoreHeadUIStorage.groupButtons[key2]).repoScrollViewElement.visibility = false; } } if (MoreHeadUIStorage.resetPosition) { decorationsPage.scrollView.SetScrollPosition(0f); decorationsPage.scrollView.UpdateElements(); } else { decorationsPage.scrollView.UpdateElements(); } } catch (Exception ex) { Logger.LogError("Error in ShowDecorationsForTag: " + ex.Message); } } } } namespace MoreHead.MoreHead.Patchers { public static class HeadDecorationManagerHelpers { public static string bundleName; public static void Patch1_LoadDecorationBundle(string bundleBaseName) { Logger.Log("Saving bundle name"); bundleName = bundleBaseName; } public static void Patch2_LoadDecorationBundle() { Logger.Log("Patch_LoadDecorationBundle called"); string text = null; if (bundleName.Contains("~")) { string[] array = bundleName.Split(new char[1] { '~' }); if (array.Length >= 2) { text = array[^1].ToLower(); Logger.Log("Setting group: " + text); } } Logger.Log("Adding decoration"); HeadDecorationManagerStorage.Decorations.Add(text); } public static void Patch3_LoadDecorationBundle() { HeadDecorationManagerStorage.Decorations.RemoveAt(HeadDecorationManagerStorage.Decorations.Count - 1); Logger.Log("Removing last from decoration group list"); } } public static class MoreHeadUIHelpers { private static bool _inHelper; public static void Patch1_CreateAllDecorationButtons() { Logger.Log("Starting patch of CreateAllDecorationButtons"); Logger.Log("Accessing type MoreHeadUI"); Type typeFromHandle = typeof(MoreHeadUI); Logger.Log("Setting binding flags to Static and NonPublic"); Logger.Log("Retrieving ALL_TAGS field from MoreHeadUI"); string[] array = (string[])typeFromHandle.GetField("ALL_TAGS", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); foreach (string key in array) { MoreHeadGroupStorage.tagGroupElements[key] = new List<string>(); } } public static List<DecorationInfo> Patch2_CreateAllDecorationButtons() { try { Logger.Log("Starting Patch2_CreateAllDecorationButtons"); _ = (string[])typeof(MoreHeadUI).GetField("ALL_TAGS", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); List<DecorationInfo> allDecorations = HeadDecorationManager.Decorations.ToList(); Logger.Log("Gotten IsBuiltInDecoration"); MethodInfo isBuiltInMI = AccessTools.Method(typeof(MoreHeadUI), "IsBuiltInDecoration", new Type[1] { typeof(DecorationInfo) }, (Type[])null); if (isBuiltInMI.GetParameters().Length == 1 && isBuiltInMI.ReturnType == typeof(bool)) { _ = (Func<DecorationInfo, bool>)Delegate.CreateDelegate(typeof(Func<DecorationInfo, bool>), isBuiltInMI); Logger.Log("Delegate successfully created for IsBuiltInDecoration."); Logger.Log("Bound Delegate"); List<DecorationInfo> result = (from decoration in allDecorations orderby HeadDecorationManagerStorage.Decorations[allDecorations.IndexOf(decoration)] ?? string.Empty, decoration.IsVisible descending, (!(bool)isBuiltInMI.Invoke(null, new object[1] { decoration })) ? 1 : 0, decoration.DisplayName select decoration).ToList(); Logger.Log("decorations sorted"); return result; } throw new InvalidOperationException("IsBuiltInDecoration method signature does not match Func<DecorationInfo, bool>."); } catch (Exception arg) { Logger.LogError($"Error creating all decoration buttons: {arg}"); throw; } } public static void Patch1_CreateDecorationButton(DecorationInfo decoration, string group) { if (_inHelper) { return; } _inHelper = true; try { } finally { _inHelper = false; } } } }