using 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(); if (!Object.op_Implicit((Object)(object)parentComponent)) { parentComponent = ((Component)TotalParent).gameObject.AddComponent(); } 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(); if (!Object.op_Implicit((Object)(object)parentComponent)) { parentComponent = ((Component)TotalParent).gameObject.AddComponent(); } 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 hiddenParts = new List(); 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(); 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(); 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(); 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 _enableDebugLogging; private void Awake() { //IL_0094: Unknown result type (might be due to invalid IL or missing references) _enableDebugLogging = ((BaseUnityPlugin)this).Config.Bind("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> tagGroupElements = new Dictionary>(); public static Dictionary activeGroups = new Dictionary(); } internal static class MoreHeadUIStorage { [CanBeNull] public static REPOPopupPage page = null; [CanBeNull] public static string group = null; public static bool resetPosition = true; public static Dictionary groupButtons = new Dictionary(); public static Dictionary> groupButtonTags = new Dictionary>(); } internal class HeadDecorationManagerStorage { public static List Decorations = new List(); } [HarmonyPatch(typeof(MoreHeadUI))] [HarmonyPatch("CreateAllDecorationButtons", new Type[] { typeof(REPOPopupPage) })] internal static class Patch_CreateAllDecorationButtons { private static readonly MethodInfo ClearScrolls = AccessTools.Method(typeof(Dictionary>), "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 Transpiler(IEnumerable 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 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)); 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 d__5 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public REPOPopupPage page; public RectTransform anchor; public float beforeY; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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(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 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(); } MoreHeadUIStorage.groupButtonTags[text].Add("ALL"); } List 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 "[+]" + group + ""; } return "[-]" + group + ""; } 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(); 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(); if (obj != null) { obj.StartCoroutine(RestoreScrollAfterGroupToggle(MoreHeadUIStorage.page, val, beforeY)); } } MoreHeadUIStorage.resetPosition = true; } [IteratorStateMachine(typeof(d__5))] private static IEnumerator RestoreScrollAfterGroupToggle(REPOPopupPage page, RectTransform anchor, float beforeY) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new 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 Transpiler(IEnumerable 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 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 Transpiler(IEnumerable 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 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)) { 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> tagScrollViewElements = (Dictionary>)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> decorationDataCache = (Dictionary>)typeFromHandle.GetField("decorationDataCache", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null); Dictionary decorationButtons = (Dictionary)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> tagScrollViewElements, string currentTagFilter, string currentSearchQuery, Dictionary> decorationDataCache, Dictionary 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> 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 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(); } } public static List Patch2_CreateAllDecorationButtons() { try { Logger.Log("Starting Patch2_CreateAllDecorationButtons"); _ = (string[])typeof(MoreHeadUI).GetField("ALL_TAGS", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); List 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)Delegate.CreateDelegate(typeof(Func), isBuiltInMI); Logger.Log("Delegate successfully created for IsBuiltInDecoration."); Logger.Log("Bound Delegate"); List 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."); } 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; } } } }