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 MoreHeadBridge v2.2.0
MoreHeadBridge.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Photon.Pun; using REPOLib; using REPOLib.Modules; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Xuaun")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Registers MoreHead .hhh cosmetics into the vanilla REPO cosmetics system via REPOLib.")] [assembly: AssemblyFileVersion("2.2.0.0")] [assembly: AssemblyInformationalVersion("2.2.0+d5ea3830f0322aae515765e2e2c6866d4975638b")] [assembly: AssemblyProduct("MoreHeadBridge")] [assembly: AssemblyTitle("MoreHeadBridge")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.2.0.0")] [module: UnverifiableCode] [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 MoreHeadBridge { internal static class BceConsole { private static readonly MethodInfo? _writeLine; private static readonly MethodInfo? _write; internal static bool IsAvailable => _writeLine != null; static BceConsole() { Type type = Type.GetType("BCE.console, BCE"); if (!(type == null)) { _writeLine = type.GetMethod("WriteLine", new Type[2] { typeof(string), typeof(ConsoleColor) }); _write = type.GetMethod("Write", new Type[2] { typeof(string), typeof(ConsoleColor) }); } } internal static void WriteLine(string msg, ConsoleColor color) { _writeLine?.Invoke(null, new object[2] { msg, color }); } internal static void Write(string msg, ConsoleColor color) { _write?.Invoke(null, new object[2] { msg, color }); } } internal static class BridgeIds { internal const string Prefix = "morehead-bridge:"; internal static bool IsBridgeAsset(string? assetId) { if (!string.IsNullOrEmpty(assetId)) { return assetId.StartsWith("morehead-bridge:", StringComparison.Ordinal); } return false; } internal static bool IsBridgeAsset(CosmeticAsset? asset) { if ((Object)(object)asset != (Object)null) { return IsBridgeAsset(asset.assetId); } return false; } } internal static class HhhCosmeticLoader { internal static readonly List<string> RegisteredAssetIds = new List<string>(); internal static readonly HashSet<string> WorldAssetIds = new HashSet<string>(); internal static readonly Dictionary<string, Texture2D> BridgeIconTextures = new Dictionary<string, Texture2D>(); private static readonly Dictionary<string, CosmeticType> TagToType = new Dictionary<string, CosmeticType> { ["head"] = (CosmeticType)0, ["neck"] = (CosmeticType)30, ["body"] = (CosmeticType)20, ["hip"] = (CosmeticType)21, ["rightarm"] = (CosmeticType)1, ["leftarm"] = (CosmeticType)2, ["rightleg"] = (CosmeticType)3, ["leftleg"] = (CosmeticType)4, ["world"] = (CosmeticType)0 }; private static readonly HashSet<string> ValidTags; private static readonly HashSet<string> _usedPrefabIds; private static readonly HashSet<string> _usedInternalNames; private static bool _moreHeadFixDone; private static readonly Dictionary<string, OverrideCosmeticType> _originalTypes; private static readonly Dictionary<string, OverrideCosmeticType> TagToOverrideType; public static void LoadAll() { string pluginPath = Paths.PluginPath; string[] files = Directory.GetFiles(pluginPath, "*.hhh", SearchOption.AllDirectories); string text = Plugin.SpecificFolders.Value ?? ""; if (!string.IsNullOrWhiteSpace(text)) { char[] invalidChars = Path.GetInvalidPathChars(); string[] array = (from s in (from s in text.Split(',') select s.Trim() into s where s.Length > 0 select s).Select(delegate(string s) { string text2 = new string(s.Where((char c) => !invalidChars.Contains(c)).ToArray()); if (text2 != s) { Plugin.Logger.LogWarning((object)("SpecificFolders: '" + s + "' contained invalid path characters — changed to '" + text2 + "'.")); } return text2; }) where s.Length > 0 select s).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray(); string[] matched = array.Where((string a) => files.Any((string f) => f.IndexOf(a, StringComparison.OrdinalIgnoreCase) >= 0)).ToArray(); string[] array2 = array.Except<string>(matched, StringComparer.OrdinalIgnoreCase).ToArray(); if (matched.Length == 0) { Plugin.Logger.LogWarning((object)("SpecificFolders: none of the specified folders were found (" + string.Join(", ", array) + "). Loading all .hhh files instead.")); } else { if (array2.Length != 0) { Plugin.Logger.LogWarning((object)("SpecificFolders: folder(s) not found and skipped: " + string.Join(", ", array2) + ".")); } int num = files.Length; files = files.Where((string f) => matched.Any((string a) => f.IndexOf(a, StringComparison.OrdinalIgnoreCase) >= 0)).ToArray(); LogInfo(string.Format("SpecificFolders: loaded from {0} — kept {1}/{2} files.", string.Join(", ", matched), files.Length, num)); } } LogInfo($"Found {files.Length} .hhh file(s). Translating cosmetics from MoreHead to Vanilla REPO..."); int num2 = 0; string[] array3 = files; foreach (string path in array3) { if (TryRegister(path)) { num2++; } } int num3 = files.Length; int num4 = num3 - num2; LogInfo($"Done — {num2}/{num3} registered, {num4} error(s)."); } private static bool TryRegister(string path) { //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) FileInfo fileInfo = new FileInfo(path); if (!fileInfo.Exists || fileInfo.Length < 1024) { Plugin.Logger.LogWarning((object)("Skipped (too small/missing): " + Path.GetFileName(path))); return false; } string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); ParseFileName(fileNameWithoutExtension, out string name, out string tag); if (!TagToType.TryGetValue(tag, out var value)) { return false; } AssetBundle val = AssetBundle.LoadFromFile(path); if ((Object)(object)val == (Object)null) { Plugin.Logger.LogError((object)("Failed to load bundle: " + fileNameWithoutExtension)); return false; } GameObject val2 = null; string[] allAssetNames = val.GetAllAssetNames(); foreach (string text in allAssetNames) { GameObject val3 = val.LoadAsset<GameObject>(text); if ((Object)(object)val3 != (Object)null) { val2 = val3; break; } } val.Unload(false); if ((Object)(object)val2 == (Object)null) { Plugin.Logger.LogError((object)("No GameObject in bundle: " + fileNameWithoutExtension)); return false; } if (Plugin.FixBridgedCosmetics.Value) { FixPrefab(val2, fileNameWithoutExtension); } string name2 = ((Object)val2).name; ((Object)val2).name = EnsureUniqueId(name2, _usedPrefabIds); if (((Object)val2).name != name2) { Plugin.Logger.LogWarning((object)("Duplicate prefab name '" + name2 + "' → renamed to '" + ((Object)val2).name + "'")); } string text2 = name; name = EnsureUniqueId(name, _usedInternalNames); if (name != text2) { Plugin.Logger.LogWarning((object)("Duplicate internal name '" + text2 + "' → renamed to '" + name + "'")); } Cosmetic val4 = val2.GetComponent<Cosmetic>(); if ((Object)(object)val4 == (Object)null) { val4 = val2.AddComponent<Cosmetic>(); } val4.type = value; PrefabRef val5 = NetworkPrefabs.RegisterNetworkPrefab("Cosmetics/" + ((Object)val2).name, val2); if (val5 == null) { Plugin.Logger.LogError((object)("Failed to register network prefab: " + name)); return false; } string text3 = "morehead-bridge:" + name.ToLowerInvariant(); CosmeticAsset val6 = ScriptableObject.CreateInstance<CosmeticAsset>(); ((Object)val6).name = name; val6.assetName = ((Object)val2).name; val6.type = value; val6.prefab = val5; val6.assetId = text3; val6.rarity = Plugin.DefaultRarity.Value; val6.customTypeList = new List<Type>(); val6.tintable = false; if (TagToOverrideType.TryGetValue(tag, out var value2)) { _originalTypes[text3] = value2; } PerCosmeticOverrides.ApplyIfPresent(val6); Cosmetics.RegisterCosmetic(val6); RegisteredAssetIds.Add(text3); if (tag == "world") { WorldAssetIds.Add(text3); } Texture2D val7 = TryExtractIconTexture(val2); if ((Object)(object)val7 != (Object)null) { BridgeIconTextures[text3] = val7; } return true; } private static Texture2D? TryExtractIconTexture(GameObject prefab) { Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); string[] array = new string[5] { "_MainTex", "_BaseMap", "_BaseColorMap", "_Albedo", "_AlbedoMap" }; Renderer[] array2 = componentsInChildren; foreach (Renderer val in array2) { if ((Object)(object)val == (Object)null) { continue; } Material[] sharedMaterials = val.sharedMaterials; foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 == (Object)null) { continue; } string[] array3 = array; foreach (string text in array3) { if (val2.HasProperty(text)) { Texture texture = val2.GetTexture(text); Texture2D val3 = (Texture2D)(object)((texture is Texture2D) ? texture : null); if (val3 != null && (Object)(object)val3 != (Object)null) { return val3; } } } } } return null; } private static void ParseFileName(string fileName, out string name, out string tag) { int num = fileName.LastIndexOf('_'); if (num >= 0) { int num2 = num + 1; string text = fileName.Substring(num2, fileName.Length - num2).ToLowerInvariant(); if (ValidTags.Contains(text)) { name = fileName.Substring(0, num); tag = text; return; } } name = fileName; tag = "head"; } private static string EnsureUniqueId(string baseName, HashSet<string> used) { string text = baseName; int num = 1; while (!used.Add(text)) { text = $"{baseName}({num})"; num++; } return text; } private static void LogInfo(string msg) { if (BceConsole.IsAvailable) { BceConsole.WriteLine("[Info : MoreHead Bridge] " + msg, ConsoleColor.Cyan); } else { Plugin.Logger.LogInfo((object)(msg ?? "")); } } internal static bool IsWorldAsset(CosmeticAsset? asset) { if ((Object)(object)asset != (Object)null && BridgeIds.IsBridgeAsset(asset)) { return WorldAssetIds.Contains(asset.assetId); } return false; } internal static void ReapplyDefaultRarityToAll() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)MetaManager.instance == (Object)null) { return; } Rarity value = Plugin.DefaultRarity.Value; foreach (CosmeticAsset cosmeticAsset in MetaManager.instance.cosmeticAssets) { if (!((Object)(object)cosmeticAsset == (Object)null) && BridgeIds.IsBridgeAsset(cosmeticAsset) && (!PerCosmeticOverrides.TryGet(cosmeticAsset.assetId, out CosmeticOverrideData data) || !data.Rarity.HasValue)) { cosmeticAsset.rarity = value; } } if (Plugin.FixBridgedCosmetics.Value && !_moreHeadFixDone) { _moreHeadFixDone = true; TryFixMoreHeadPrefabs(); } } private static void FixPrefab(GameObject prefab, string label = "", Type? partShrinkerType = null, bool verbose = true) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Invalid comparison between Unknown and I4 int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { num++; try { Object.DestroyImmediate((Object)(object)val); } catch { try { val.enabled = false; } catch { } } } Rigidbody[] componentsInChildren2 = prefab.GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody val2 in componentsInChildren2) { num2++; try { Object.DestroyImmediate((Object)(object)val2); } catch { try { val2.isKinematic = true; val2.useGravity = false; } catch { } } } Animation[] componentsInChildren3 = prefab.GetComponentsInChildren<Animation>(true); foreach (Animation val3 in componentsInChildren3) { if ((Object)(object)val3.clip != (Object)null && (int)val3.clip.wrapMode != 2) { val3.clip.wrapMode = (WrapMode)2; num3++; } val3.wrapMode = (WrapMode)2; } Animator[] componentsInChildren4 = prefab.GetComponentsInChildren<Animator>(true); foreach (Animator val4 in componentsInChildren4) { if ((Object)(object)val4.runtimeAnimatorController == (Object)null) { continue; } bool flag = false; AnimationClip[] animationClips = val4.runtimeAnimatorController.animationClips; foreach (AnimationClip val5 in animationClips) { if ((Object)(object)val5 != (Object)null && !((Motion)val5).isLooping) { flag = true; break; } } if (flag && (Object)(object)((Component)val4).GetComponent<AnimatorLooper>() == (Object)null) { ((Component)val4).gameObject.AddComponent<AnimatorLooper>(); num4++; } } string text = (string.IsNullOrEmpty(label) ? ((Object)prefab).name : label); if (num > 0 || num2 > 0 || num3 > 0 || num4 > 0) { string text2 = "'" + text + "': " + $"removed {num} Collider(s), {num2} Rigidbody(s); " + $"looped {num3} Animation clip(s), {num4} Animator(s)."; if (verbose) { Plugin.Logger.LogInfo((object)text2); } else { Plugin.Logger.LogDebug((object)text2); } } Type type = partShrinkerType ?? FindPartShrinkerType(); if (type != null) { Component[] componentsInChildren5 = prefab.GetComponentsInChildren(type, true); if (componentsInChildren5.Length != 0) { string text3 = $"'{text}': {componentsInChildren5.Length} component(s) — body-part hiding active."; if (verbose) { Plugin.Logger.LogInfo((object)text3); } else { Plugin.Logger.LogDebug((object)text3); } } return; } int num5 = 0; MonoBehaviour[] componentsInChildren6 = prefab.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val6 in componentsInChildren6) { if ((Object)(object)val6 == (Object)null) { num5++; } } if (num5 > 0) { Plugin.Logger.LogWarning((object)($"'{text}': {num5} missing script(s) detected — " + "install MoreHeadUtilities if body-part hiding is needed.")); } } private static Type? FindPartShrinkerType() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.GetName().Name == "MoreHeadUtilities") { return assembly.GetType("MoreHeadUtilities.PartShrinker"); } } return null; } private static void TryFixMoreHeadPrefabs() { try { Type type = Type.GetType("MoreHead.HeadDecorationManager, MoreHead"); if (type == null) { return; } PropertyInfo property = type.GetProperty("Decorations", BindingFlags.Static | BindingFlags.Public); if (property == null || !(property.GetValue(null) is IList list) || list.Count == 0) { return; } PropertyInfo property2 = list[0].GetType().GetProperty("Prefab"); if (property2 == null) { return; } Type partShrinkerType = FindPartShrinkerType(); int num = 0; foreach (object item in list) { object? value = property2.GetValue(item); GameObject val = (GameObject)((value is GameObject) ? value : null); if (val != null) { FixPrefab(val, "", partShrinkerType, verbose: false); num++; } } Plugin.Logger.LogInfo((object)$"Applied fixes to {num} bridged cosmetics."); } catch (Exception ex) { Plugin.Logger.LogDebug((object)("Bridged cosmetic pass skipped: " + ex.Message)); } } internal static void ReapplyDefaults(CosmeticAsset asset) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) asset.rarity = Plugin.DefaultRarity.Value; if (_originalTypes.TryGetValue(asset.assetId, out var value)) { (CosmeticType cosmeticType, bool isWorld) tuple = PerCosmeticOverrides.ResolveType(value); CosmeticType item = tuple.cosmeticType; bool item2 = tuple.isWorld; asset.type = item; if (item2) { WorldAssetIds.Add(asset.assetId); } else { WorldAssetIds.Remove(asset.assetId); } } } static HhhCosmeticLoader() { HashSet<string> hashSet = new HashSet<string>(); foreach (string key in TagToType.Keys) { hashSet.Add(key); } ValidTags = hashSet; _usedPrefabIds = new HashSet<string>(); _usedInternalNames = new HashSet<string>(); _originalTypes = new Dictionary<string, OverrideCosmeticType>(); TagToOverrideType = new Dictionary<string, OverrideCosmeticType> { ["head"] = OverrideCosmeticType.Hat, ["neck"] = OverrideCosmeticType.HeadBottom, ["body"] = OverrideCosmeticType.BodyTop, ["hip"] = OverrideCosmeticType.BodyBottom, ["rightarm"] = OverrideCosmeticType.ArmRight, ["leftarm"] = OverrideCosmeticType.ArmLeft, ["rightleg"] = OverrideCosmeticType.LegRight, ["leftleg"] = OverrideCosmeticType.LegLeft, ["world"] = OverrideCosmeticType.World }; } } internal static class BatchIconGenerator { [CompilerGenerated] private sealed class <Run>d__7 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private List<CosmeticAsset> <work>5__2; private bool <interrupted>5__3; private List<CosmeticAsset>.Enumerator <>7__wrap3; private CosmeticAsset <asset>5__5; private int <guard>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <Run>d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -4) <= 1u || (uint)(num - 2) <= 2u) { try { if (num == -4 || (uint)(num - 2) <= 2u) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } <work>5__2 = null; <>7__wrap3 = default(List<CosmeticAsset>.Enumerator); <asset>5__5 = null; <>1__state = -2; } private bool MoveNext() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Expected O, but got Unknown try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; _didStartOnce = true; <>2__current = (object)new WaitForSecondsRealtime(0.5f); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)MetaManager.instance == (Object)null) { _isRunning = false; return false; } <work>5__2 = new List<CosmeticAsset>(); foreach (CosmeticAsset cosmeticAsset in MetaManager.instance.cosmeticAssets) { if (!((Object)(object)cosmeticAsset == (Object)null) && cosmeticAsset.assetId != null && BridgeIds.IsBridgeAsset(cosmeticAsset) && !IconCapture.HasCache(cosmeticAsset)) { <work>5__2.Add(cosmeticAsset); } } Plugin.Logger.LogInfo((object)$"GenerateAllIcons: {<work>5__2.Count} icon(s) to generate."); if (<work>5__2.Count == 0) { _isRunning = false; Plugin.GenerateAllIcons.Value = false; ((BaseUnityPlugin)Plugin.Instance).Config.Save(); return false; } _progressDone = 0; _progressFailed = 0; _progressTotal = <work>5__2.Count; <interrupted>5__3 = true; <>1__state = -3; <>7__wrap3 = <work>5__2.GetEnumerator(); <>1__state = -4; goto IL_03a4; case 2: <>1__state = -4; <guard>5__6 = 0; goto IL_02af; case 3: <>1__state = -4; <guard>5__6++; goto IL_02af; case 4: { <>1__state = -4; if ((Object)(object)MetaManager.instance == (Object)null) { break; } if (IconCapture.TryCapture(<asset>5__5)) { _progressDone++; } else { _progressFailed++; } MetaManager.instance.CosmeticPreviewSet(false); MetaManager.instance.CosmeticPlayerUpdateLocal(false, false); WorldCosmeticsSetupPatch.SetAllWorldInstancesActive(active: true); int num = _progressDone + _progressFailed; if (num % 50 == 0) { Plugin.Logger.LogInfo((object)($"Batch progress: {num}/{<work>5__2.Count} " + $"({_progressDone} ok, {_progressFailed} failed)")); } <asset>5__5 = null; goto IL_03a4; } IL_03a4: while (<>7__wrap3.MoveNext()) { <asset>5__5 = <>7__wrap3.Current; if ((Object)(object)MetaManager.instance == (Object)null) { break; } int num2 = MetaManager.instance.cosmeticAssets.IndexOf(<asset>5__5); if (num2 < 0) { _progressFailed++; continue; } MetaManager.instance.cosmeticEquippedPreview.Clear(); MetaManager.instance.cosmeticEquippedPreview.Add(num2); if (MetaManager.instance.colorsEquipped != null) { MetaManager.instance.colorsEquippedPreview = (int[])MetaManager.instance.colorsEquipped.Clone(); } MetaManager.instance.CosmeticPreviewSet(true); MetaManager.instance.CosmeticPlayerUpdateLocal(false, false); WorldCosmeticsSetupPatch.SetAllWorldInstancesActive(active: false); if (HhhCosmeticLoader.IsWorldAsset(<asset>5__5)) { WorldCosmeticsSetupPatch.SetWorldAssetActive(<asset>5__5, active: true); } SkipEquipAnimationFor(<asset>5__5); <>2__current = null; <>1__state = 2; return true; } break; IL_02af: if (<guard>5__6 < 3 && !IsAnimComplete(<asset>5__5)) { <>2__current = null; <>1__state = 3; return true; } <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 4; return true; } <>m__Finally2(); <>7__wrap3 = default(List<CosmeticAsset>.Enumerator); <interrupted>5__3 = false; <>m__Finally1(); Plugin.GenerateAllIcons.Value = false; ((BaseUnityPlugin)Plugin.Instance).Config.Save(); Plugin.Logger.LogInfo((object)($"GenerateAllIcons done — {_progressDone} captured, " + $"{_progressFailed} failed. Flag reset to false.")); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (_isRunning) { _isRunning = false; if (<interrupted>5__3) { int num = _progressTotal - _progressDone - _progressFailed; Plugin.Logger.LogWarning((object)("GenerateAllIcons: batch interrupted at " + $"{_progressDone + _progressFailed}/{_progressTotal} " + $"({num} still to go). " + "Reopen the menu to continue.")); } } if ((Object)(object)MetaManager.instance != (Object)null) { MetaManager.instance.CosmeticPreviewSet(false); MetaManager.instance.CosmeticPlayerUpdateLocal(false, false); } WorldCosmeticsSetupPatch.SetAllWorldInstancesActive(active: true); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap3).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static bool _isRunning; private static bool _didStartOnce; private static int _progressDone; private static int _progressFailed; private static int _progressTotal; private static FieldInfo? _iconCreationAvatarField; private static FieldInfo? _equipLerpField; internal static void TryStart(MonoBehaviour host) { if (!_isRunning && Plugin.GenerateAllIcons.Value) { if (_didStartOnce) { Plugin.Logger.LogWarning((object)"GenerateAllIcons: previous batch was interrupted. Resuming — only icons still missing will be generated."); } _isRunning = true; host.StartCoroutine(Run()); } } internal static void NotifyMenuClosed() { if (_isRunning) { _isRunning = false; int num = _progressTotal - _progressDone - _progressFailed; Plugin.Logger.LogWarning((object)("GenerateAllIcons: batch interrupted at " + $"{_progressDone + _progressFailed}/{_progressTotal} " + $"({num} still to go). " + "Reopen the menu to continue. (Your equipped cosmetics were not modified.)")); } } [IteratorStateMachine(typeof(<Run>d__7))] private static IEnumerator Run() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Run>d__7(0); } private static void SkipEquipAnimationFor(CosmeticAsset asset) { if ((object)_iconCreationAvatarField == null) { _iconCreationAvatarField = AccessTools.Field(typeof(Cosmetic), "iconCreationAvatar"); } if (_iconCreationAvatarField == null) { return; } Cosmetic[] array = Object.FindObjectsOfType<Cosmetic>(); foreach (Cosmetic val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val.cosmeticAsset == (Object)(object)asset) { _iconCreationAvatarField.SetValue(val, true); } } } private static bool IsAnimComplete(CosmeticAsset asset) { if ((object)_equipLerpField == null) { _equipLerpField = AccessTools.Field(typeof(Cosmetic), "equipLerp"); } if (_equipLerpField == null) { return true; } Cosmetic[] array = Object.FindObjectsOfType<Cosmetic>(); foreach (Cosmetic val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val.cosmeticAsset == (Object)(object)asset && (float)(_equipLerpField.GetValue(val) ?? ((object)1f)) < 1f) { return false; } } return true; } } [HarmonyPatch(typeof(MenuPageCosmetics), "Start")] internal static class BatchIconGeneratorStartPatch { [HarmonyPostfix] private static void Postfix(MenuPageCosmetics __instance) { BatchIconGenerator.TryStart((MonoBehaviour)(object)__instance); } } [HarmonyPatch(typeof(MenuPageCosmetics), "OnDestroy")] internal static class BatchIconGeneratorMenuClosePatch { [HarmonyPostfix] private static void Postfix() { BatchIconGenerator.NotifyMenuClosed(); CosmeticHoverPatch.OnMenuClosed(); CosmeticsMenuState.OnMenuClosed(); CosmeticsMenuLateUpdatePatch.OnMenuClosed(); } } internal static class FavHideIcons { private const string ResourcePrefix = "MoreHeadBridge.Icons.Resources."; private static Sprite? _star; private static Sprite? _hide; internal static Sprite? StarSprite => _star ?? (_star = LoadSprite("star.png")); internal static Sprite? HideSprite => _hide ?? (_hide = LoadSprite("hide.png")); private static Sprite? LoadSprite(string fileName) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) try { string text = "MoreHeadBridge.Icons.Resources." + fileName; using Stream stream = typeof(FavHideIcons).Assembly.GetManifestResourceStream(text); if (stream == null) { Plugin.Logger.LogWarning((object)("FavHideIcons: embedded resource '" + text + "' not found.")); return null; } byte[] array = new byte[stream.Length]; for (int i = 0; i < array.Length; i += stream.Read(array, i, array.Length - i)) { } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ((Object)val).name = "MoreHeadBridge_" + fileName; ((Texture)val).filterMode = (FilterMode)1; if (!ImageConversion.LoadImage(val, array)) { Plugin.Logger.LogWarning((object)("FavHideIcons: Texture2D.LoadImage failed for '" + text + "'.")); return null; } MaskWhitePixels(val); Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)((Texture)val).width); ((Object)val2).name = "MoreHeadBridge_" + fileName; return val2; } catch (Exception ex) { Plugin.Logger.LogWarning((object)("FavHideIcons: error loading '" + fileName + "': " + ex.Message)); return null; } } private static void MaskWhitePixels(Texture2D tex) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Color32[] pixels = tex.GetPixels32(); for (int i = 0; i < pixels.Length; i++) { Color32 val = pixels[i]; if (val.r > 220 && val.g > 220 && val.b > 220) { pixels[i].a = 0; } } tex.SetPixels32(pixels); tex.Apply(); } } internal static class IconCacheCleaner { internal static void Run() { if (!Plugin.DeleteIconCache.Value) { return; } try { string cacheDir = IconCapture.CacheDir; if (!Directory.Exists(cacheDir)) { Plugin.Logger.LogInfo((object)"DeleteIconCache: no cache directory, nothing to do."); ResetFlag(); return; } string text = Plugin.DeleteIconsMatching.Value ?? ""; string[] array = (from s in text.Split(',') select s.Trim().ToLowerInvariant() into s where s.Length > 0 select s).ToArray(); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (string registeredAssetId in HhhCosmeticLoader.RegisteredAssetIds) { int num = registeredAssetId.IndexOf(':'); if (num >= 0 && num + 1 < registeredAssetId.Length) { string text2 = registeredAssetId; int num2 = num + 1; hashSet.Add(text2.Substring(num2, text2.Length - num2)); } } int num3 = 0; int num4 = 0; string[] files = Directory.GetFiles(cacheDir, "*.png"); foreach (string text3 in files) { string name = Path.GetFileNameWithoutExtension(text3).ToLowerInvariant(); if (!hashSet.Contains(name)) { num4++; continue; } if (array.Length != 0 && !array.Any((string f) => name.Contains(f))) { num4++; continue; } try { File.Delete(text3); num3++; } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Failed to delete '" + text3 + "': " + ex.Message)); } } Plugin.Logger.LogInfo((object)($"DeleteIconCache: removed {num3} bridge icon(s), kept {num4}. " + "Filter: " + ((array.Length == 0) ? "(all bridge icons)" : string.Join(",", array)))); } catch (Exception ex2) { Plugin.Logger.LogError((object)("DeleteIconCache failed: " + ex2.Message)); } finally { ResetFlag(); } } private static void ResetFlag() { Plugin.DeleteIconCache.Value = false; ((BaseUnityPlugin)Plugin.Instance).Config.Save(); } } internal static class IconCapture { private const int OutSize = 128; private static string? _cacheDir; private static FieldInfo? _renderTextureInstanceField; private static readonly Rect CropHead = new Rect(0.22f, 0.62f, 0.56f, 0.35f); private static readonly Rect CropNeck = new Rect(0.22f, 0.5f, 0.56f, 0.38f); private static readonly Rect CropBody = new Rect(0.18f, 0.34f, 0.64f, 0.36f); private static readonly Rect CropArmR = new Rect(0.05f, 0.3f, 0.5f, 0.4f); private static readonly Rect CropArmL = new Rect(0.45f, 0.3f, 0.5f, 0.4f); private static readonly Rect CropLegR = new Rect(0.1f, 0f, 0.45f, 0.45f); private static readonly Rect CropLegL = new Rect(0.45f, 0f, 0.45f, 0.45f); private static readonly Rect CropFull = new Rect(0f, 0f, 1f, 1f); internal static string CacheDir { get { if (_cacheDir != null) { return _cacheDir; } _cacheDir = Path.Combine(Application.persistentDataPath, "Cache", "Icons", "CosmeticsModded", "MoreHeadBridge_CosmeticsIcons"); MigrateLegacyCache(_cacheDir); return _cacheDir; } } private static void MigrateLegacyCache(string newDir) { string path = Path.Combine(Application.persistentDataPath, "MoreHeadBridge_Icons"); if (!Directory.Exists(path)) { return; } Plugin.Logger.LogInfo((object)"IconCapture: migrating icon cache from legacy location..."); try { Directory.CreateDirectory(newDir); int num = 0; int num2 = 0; string[] files = Directory.GetFiles(path, "*.png"); foreach (string text in files) { string text2 = Path.Combine(newDir, Path.GetFileName(text)); try { if (!File.Exists(text2)) { File.Move(text, text2); } else { File.Delete(text); } num++; } catch (Exception ex) { num2++; Plugin.Logger.LogWarning((object)("IconCapture: could not migrate '" + Path.GetFileName(text) + "': " + ex.Message)); } } try { if (Directory.GetFiles(path).Length == 0) { Directory.Delete(path, recursive: false); } } catch { } Plugin.Logger.LogInfo((object)$"IconCapture: cache migration done — {num} moved, {num2} failed."); } catch (Exception ex2) { Plugin.Logger.LogWarning((object)("IconCapture: cache migration failed: " + ex2.Message)); } } internal static string CachePathFor(CosmeticAsset asset) { string text = ((Object)asset).name.Replace("(Clone)", "").ToLowerInvariant(); return Path.Combine(CacheDir, text + ".png"); } internal static bool HasCache(CosmeticAsset asset) { return File.Exists(CachePathFor(asset)); } private static RenderTexture? FindActiveAvatarRT() { PlayerAvatarMenuHover val = Object.FindObjectOfType<PlayerAvatarMenuHover>(); if ((Object)(object)val == (Object)null) { return null; } if ((object)_renderTextureInstanceField == null) { _renderTextureInstanceField = AccessTools.Field(typeof(PlayerAvatarMenuHover), "renderTextureInstance"); } if (_renderTextureInstanceField == null) { Plugin.Logger.LogWarning((object)"IconCapture: PlayerAvatarMenuHover.renderTextureInstance not found — update MoreHeadBridge."); } else { object? value = _renderTextureInstanceField.GetValue(val); RenderTexture val2 = (RenderTexture)((value is RenderTexture) ? value : null); if ((Object)(object)val2 != (Object)null) { return val2; } } RawImage component = ((Component)val).GetComponent<RawImage>(); if (!((Object)(object)component != (Object)null)) { return null; } Texture texture = component.texture; return (RenderTexture?)(object)((texture is RenderTexture) ? texture : null); } internal static bool TryCapture(CosmeticAsset asset) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) return TryCapture(asset, (CosmeticType)(HhhCosmeticLoader.IsWorldAsset(asset) ? (-1) : ((asset != null) ? ((int)asset.type) : 0))); } internal static bool TryCapture(CosmeticAsset asset, CosmeticType type) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Expected O, but got Unknown if ((Object)(object)asset == (Object)null) { return false; } if (HasCache(asset)) { return false; } Texture2D val = null; Texture2D val2 = null; Texture2D val3 = null; RenderTexture active = RenderTexture.active; try { RenderTexture val4 = FindActiveAvatarRT(); if ((Object)(object)val4 == (Object)null) { return false; } Directory.CreateDirectory(CacheDir); RenderTexture.active = val4; val = new Texture2D(((Texture)val4).width, ((Texture)val4).height, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)((Texture)val4).width, (float)((Texture)val4).height), 0, 0); val.Apply(); Rect cropRect = GetCropRect(type); int num = Mathf.RoundToInt(((Rect)(ref cropRect)).x * (float)((Texture)val4).width); int num2 = Mathf.RoundToInt(((Rect)(ref cropRect)).y * (float)((Texture)val4).height); int num3 = Mathf.RoundToInt(((Rect)(ref cropRect)).width * (float)((Texture)val4).width); int num4 = Mathf.RoundToInt(((Rect)(ref cropRect)).height * (float)((Texture)val4).height); num3 = Mathf.Max(1, Mathf.Min(num3, ((Texture)val4).width - num)); num4 = Mathf.Max(1, Mathf.Min(num4, ((Texture)val4).height - num2)); Color[] pixels = val.GetPixels(num, num2, num3, num4); val2 = new Texture2D(num3, num4, (TextureFormat)4, false); val2.SetPixels(pixels); val2.Apply(); val3 = ResizeBilinear(val2, 128, 128); File.WriteAllBytes(CachePathFor(asset), ImageConversion.EncodeToPNG(val3)); if ((Object)(object)asset.icon != (Object)null) { Object.Destroy((Object)(object)asset.icon); asset.icon = null; } RefreshVisibleButtons(asset); return true; } catch (Exception ex) { Plugin.Logger.LogDebug((object)("Icon capture failed for '" + ((Object)asset).name + "': " + ex.Message)); return false; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); } if ((Object)(object)val3 != (Object)null) { Object.Destroy((Object)(object)val3); } } } private static Rect GetCropRect(CosmeticType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected I4, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) switch ((int)type) { case 0: case 5: case 14: case 15: case 17: case 18: case 24: case 31: case 32: return CropHead; case 6: case 25: case 30: return CropNeck; case 7: case 8: case 16: case 20: case 21: case 23: return CropBody; case 1: case 9: case 13: case 26: return CropArmR; case 2: case 10: case 27: return CropArmL; case 3: case 11: case 19: case 28: return CropLegR; case 4: case 12: case 22: case 29: return CropLegL; default: return CropFull; } } private static void RefreshVisibleButtons(CosmeticAsset asset) { try { MenuPageCosmetics val = Object.FindObjectOfType<MenuPageCosmetics>(); MenuElementCosmeticButton[] array = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentsInChildren<MenuElementCosmeticButton>(true) : Object.FindObjectsOfType<MenuElementCosmeticButton>()); MenuElementCosmeticButton[] array2 = array; foreach (MenuElementCosmeticButton val2 in array2) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.cosmeticAsset == (Object)(object)asset) { val2.UpdateIcon(false); } } } catch (Exception ex) { Plugin.Logger.LogDebug((object)("Button refresh failed: " + ex.Message)); } } private static Texture2D ResizeBilinear(Texture2D src, int w, int h) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) RenderTexture temporary = RenderTexture.GetTemporary(w, h); try { Graphics.Blit((Texture)(object)src, temporary); RenderTexture active = RenderTexture.active; RenderTexture.active = temporary; Texture2D val = new Texture2D(w, h, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)w, (float)h), 0, 0); val.Apply(); RenderTexture.active = active; return val; } finally { RenderTexture.ReleaseTemporary(temporary); } } } internal static class PlaceholderIcon { private const int Size = 64; private static Sprite? _cached; internal static Sprite Get() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_cached != (Object)null) { return _cached; } Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); ((Object)val).name = "MoreHeadBridge_Placeholder"; ((Texture)val).filterMode = (FilterMode)0; Color val2 = default(Color); ((Color)(ref val2))..ctor(1f, 0.8f, 0f, 1f); Color val3 = default(Color); ((Color)(ref val3))..ctor(0.13f, 0.13f, 0.18f, 1f); Color val4 = default(Color); ((Color)(ref val4))..ctor(0.22f, 0.22f, 0.28f, 1f); Color val5 = default(Color); ((Color)(ref val5))..ctor(1f, 0.8f, 0f, 0.35f); Color[] array = (Color[])(object)new Color[4096]; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { bool flag = j < 3 || j >= 61 || i < 3 || i >= 61; bool flag2 = (j + i) / 4 % 2 == 0; Color val6 = ((!flag) ? ((!flag2) ? val4 : Color.Lerp(val3, val5, 0.5f)) : val2); array[i * 64 + j] = val6; } } DrawM(array, 64, val2); val.SetPixels(array); val.Apply(); _cached = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f); ((Object)_cached).name = "MoreHeadBridge_Placeholder"; return _cached; } private static void DrawM(Color[] pixels, int size, Color color) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) for (int i = 14; i <= 50; i++) { Plot(pixels, size, 18, i, color); Plot(pixels, size, 19, i, color); Plot(pixels, size, 45, i, color); Plot(pixels, size, 44, i, color); } int num = 24; for (int j = 0; j <= num; j++) { int y = 50 - j; int num2 = 18 + j * 13 / num; int num3 = 45 - j * 14 / num; Plot(pixels, size, num2, y, color); Plot(pixels, size, num2 + 1, y, color); Plot(pixels, size, num3, y, color); Plot(pixels, size, num3 - 1, y, color); } } private static void Plot(Color[] pixels, int size, int x, int y, Color color) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (x >= 0 && y >= 0 && x < size && y < size) { pixels[y * size + x] = color; } } } internal static class BridgeFavoritesManager { private sealed class SaveData { public List<string> Favorites { get; set; } = new List<string>(); public List<string> Hidden { get; set; } = new List<string>(); } private static readonly HashSet<string> _favorites = new HashSet<string>(); private static readonly HashSet<string> _hidden = new HashSet<string>(); private static bool _loaded; private static readonly string SavePath = Path.Combine(Paths.ConfigPath, "MoreHeadBridge_Favorites.json"); private static Task _lastWrite = Task.CompletedTask; internal static void EnsureLoaded() { if (!_loaded) { _loaded = true; Load(); } } internal static bool IsFavorite(CosmeticAsset? asset) { if ((Object)(object)asset != (Object)null) { return _favorites.Contains(KeyFor(asset)); } return false; } internal static bool IsHidden(CosmeticAsset? asset) { if ((Object)(object)asset != (Object)null) { return _hidden.Contains(KeyFor(asset)); } return false; } internal static bool HasAnyFavorite() { return _favorites.Count > 0; } internal static bool HasAnyHidden() { return _hidden.Count > 0; } internal static bool ToggleFavorite(CosmeticAsset asset) { string item = KeyFor(asset); if (_favorites.Remove(item)) { Save(); return false; } _hidden.Remove(item); _favorites.Add(item); Save(); return true; } internal static bool ToggleHidden(CosmeticAsset asset) { string item = KeyFor(asset); if (_hidden.Remove(item)) { Save(); return false; } _favorites.Remove(item); _hidden.Add(item); Save(); return true; } private static void Load() { try { if (!File.Exists(SavePath)) { return; } SaveData saveData = JsonConvert.DeserializeObject<SaveData>(File.ReadAllText(SavePath)); if (saveData == null) { return; } _favorites.Clear(); _hidden.Clear(); foreach (string item in saveData.Favorites ?? new List<string>()) { _favorites.Add(item); } foreach (string item2 in saveData.Hidden ?? new List<string>()) { _hidden.Add(item2); } Plugin.Logger.LogInfo((object)$"BridgeFavoritesManager: loaded {_favorites.Count} favorite(s), {_hidden.Count} hidden."); } catch (Exception ex) { Plugin.Logger.LogWarning((object)("BridgeFavoritesManager: load failed: " + ex.Message)); } } private static void Save() { string json = JsonConvert.SerializeObject((object)new SaveData { Favorites = new List<string>(_favorites), Hidden = new List<string>(_hidden) }, (Formatting)1); _lastWrite = _lastWrite.ContinueWith(delegate { try { string text = SavePath + ".tmp"; File.WriteAllText(text, json, Encoding.UTF8); if (File.Exists(SavePath)) { File.Replace(text, SavePath, null); } else { File.Move(text, SavePath); } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("BridgeFavoritesManager: save failed: " + ex.Message)); } }, TaskScheduler.Default); } private static string KeyFor(CosmeticAsset asset) { if (!string.IsNullOrEmpty(asset.assetId)) { return asset.assetId; } if (!string.IsNullOrEmpty(asset.assetName)) { return asset.assetName; } return ((Object)asset).name ?? ""; } } internal static class CosmeticOverridePopup { private const float PopupX = -120f; private const float TitleGap = 15f; private const float BtnRowH = 30f; private const float BtnTopGap = 10f; private const float BtnBackX = -137f; private const float BtnSaveX = 58f; private const float BtnResetX = 51f; private static readonly string[] RarityOptions = Enum.GetNames(typeof(Rarity)); private static readonly string[] MainOptions = Enum.GetNames(typeof(MainCosmeticCategory)); private static readonly string[] ModdedOptions = new string[3] { "Default", "Yes", "No" }; private static readonly Dictionary<MainCosmeticCategory, OverrideCosmeticType[]> SubOptions = new Dictionary<MainCosmeticCategory, OverrideCosmeticType[]> { [MainCosmeticCategory.Head] = new OverrideCosmeticType[6] { OverrideCosmeticType.Hat, OverrideCosmeticType.Eyewear, OverrideCosmeticType.FaceTop, OverrideCosmeticType.FaceBottom, OverrideCosmeticType.HeadBottom, OverrideCosmeticType.Ears }, [MainCosmeticCategory.Body] = new OverrideCosmeticType[2] { OverrideCosmeticType.BodyTop, OverrideCosmeticType.BodyBottom }, [MainCosmeticCategory.Arms] = new OverrideCosmeticType[2] { OverrideCosmeticType.ArmRight, OverrideCosmeticType.ArmLeft }, [MainCosmeticCategory.Legs] = new OverrideCosmeticType[4] { OverrideCosmeticType.LegRight, OverrideCosmeticType.LegLeft, OverrideCosmeticType.FootRight, OverrideCosmeticType.FootLeft }, [MainCosmeticCategory.World] = new OverrideCosmeticType[1] { OverrideCosmeticType.World } }; private static readonly Dictionary<OverrideCosmeticType, string> SubLabels = new Dictionary<OverrideCosmeticType, string> { [OverrideCosmeticType.Hat] = "Hat", [OverrideCosmeticType.Eyewear] = "Eyewear", [OverrideCosmeticType.FaceTop] = "Face Upper", [OverrideCosmeticType.FaceBottom] = "Face Middle", [OverrideCosmeticType.HeadBottom] = "Face Lower", [OverrideCosmeticType.Ears] = "Ears", [OverrideCosmeticType.BodyTop] = "Bodywear Top", [OverrideCosmeticType.BodyBottom] = "Bodywear Bottom", [OverrideCosmeticType.ArmRight] = "Armwear Right", [OverrideCosmeticType.ArmLeft] = "Armwear Left", [OverrideCosmeticType.LegRight] = "Legwear Right", [OverrideCosmeticType.LegLeft] = "Legwear Left", [OverrideCosmeticType.FootRight] = "Footwear Right", [OverrideCosmeticType.FootLeft] = "Footwear Left", [OverrideCosmeticType.World] = "World" }; private static readonly Dictionary<string, OverrideCosmeticType> LabelToType = SubLabels.ToDictionary<KeyValuePair<OverrideCosmeticType, string>, string, OverrideCosmeticType>((KeyValuePair<OverrideCosmeticType, string> kvp) => kvp.Value, (KeyValuePair<OverrideCosmeticType, string> kvp) => kvp.Key); internal static void Show(CosmeticAsset asset) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Expected O, but got Unknown //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown CosmeticAsset asset2 = asset; bool flag = PerCosmeticOverrides.HasOverride(asset2); string text = asset2.assetName ?? ((Object)asset2).name ?? asset2.assetId; PerCosmeticOverrides.TryGet(asset2.assetId, out CosmeticOverrideData data); bool? pendingModded = data?.IsModded; Rarity pendingRarity = asset2.rarity; MainCosmeticCategory pendingMain = PerCosmeticOverrides.GetCurrentMain(asset2); OverrideCosmeticType pendingType = PerCosmeticOverrides.GetCurrentType(asset2); REPOPopupPage popup = MenuAPI.CreateREPOPopupPage(text, false, true, 5f, (Vector2?)new Vector2(-120f, 0f)); REPOSlider subSlider = null; popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown REPOSlider val6 = MenuAPI.CreateREPOSlider("Main Category", "", (Action<string>)delegate(string opt) { if (Enum.TryParse<MainCosmeticCategory>(opt, out var result2) && result2 != pendingMain) { pendingMain = result2; pendingType = SubOptions[result2][0]; if (!((Object)(object)subSlider == (Object)null)) { REPOScrollViewElement component = ((Component)subSlider).GetComponent<REPOScrollViewElement>(); if (result2 == MainCosmeticCategory.World) { if ((Object)(object)component != (Object)null) { component.visibility = false; } } else { subSlider.stringOptions = GetSubLabels(result2); subSlider.SetValue(0f, false); if ((Object)(object)component != (Object)null) { component.visibility = true; } } } } }, scrollView, MainOptions, pendingMain.ToString(), default(Vector2), "", "", (BarBehavior)0); return (RectTransform)((Component)val6).transform; }, 15f, 0f); popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown MainCosmeticCategory mainCosmeticCategory = ((pendingMain != MainCosmeticCategory.World) ? pendingMain : MainCosmeticCategory.Head); string[] subLabels = GetSubLabels(mainCosmeticCategory); string text3 = ((Array.IndexOf(SubOptions[mainCosmeticCategory], pendingType) >= 0 && SubLabels.ContainsKey(pendingType)) ? SubLabels[pendingType] : subLabels[0]); subSlider = MenuAPI.CreateREPOSlider("Sub Category", "", (Action<string>)delegate(string opt) { if (LabelToType.TryGetValue(opt, out var value)) { pendingType = value; } }, scrollView, subLabels, text3, default(Vector2), "", "", (BarBehavior)0); return (RectTransform)((Component)subSlider).transform; }, 0f, 0f); if (pendingMain == MainCosmeticCategory.World) { REPOSlider obj = subSlider; REPOScrollViewElement val = ((obj != null) ? ((Component)obj).GetComponent<REPOScrollViewElement>() : null); if ((Object)(object)val != (Object)null) { val.visibility = false; } } popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown Action<string> action = delegate(string opt) { bool? flag2 = ((opt == "Yes") ? new bool?(true) : ((!(opt == "No")) ? null : new bool?(false))); pendingModded = flag2; }; string text2 = ((!pendingModded.HasValue) ? "Default" : ((!pendingModded.GetValueOrDefault()) ? "No" : "Yes")); REPOSlider val5 = MenuAPI.CreateREPOSlider("Modded Rarity", "", action, scrollView, ModdedOptions, text2, default(Vector2), "", "", (BarBehavior)0); return (RectTransform)((Component)val5).transform; }, 0f, 0f); popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown REPOSlider val4 = MenuAPI.CreateREPOSlider("Rarity", "", (Action<string>)delegate(string opt) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (Enum.TryParse<Rarity>(opt, out Rarity result)) { pendingRarity = result; } }, scrollView, RarityOptions, ((object)(Rarity)(ref pendingRarity)).ToString(), default(Vector2), "", "", (BarBehavior)0); return (RectTransform)((Component)val4).transform; }, 0f, 0f); popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) RectTransform val3 = MakeRow(scrollView); MenuAPI.CreateREPOButton("Back", (Action)delegate { popup.ClosePage(false); }, (Transform)(object)val3, new Vector2(-137f, 0f)); MenuAPI.CreateREPOButton("Save", (Action)delegate { //IL_000d: Unknown result type (might be due to invalid IL or missing references) PerCosmeticOverrides.SetAndApply(asset2, pendingModded, pendingRarity, pendingType); RefreshMenu(); popup.ClosePage(false); }, (Transform)(object)val3, new Vector2(58f, 0f)); return val3; }, 10f, 0f); if (flag) { popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) RectTransform val2 = MakeRow(scrollView); MenuAPI.CreateREPOButton("Reset", (Action)delegate { PerCosmeticOverrides.Reset(asset2); RefreshMenu(); popup.ClosePage(false); }, (Transform)(object)val2, new Vector2(51f, 0f)); return val2; }, 5f, 0f); } popup.OpenPage(false); } private static string[] GetSubLabels(MainCosmeticCategory main) { return Array.ConvertAll(SubOptions[main], (OverrideCosmeticType t) => SubLabels[t]); } private static RectTransform MakeRow(Transform scrollView) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) RectTransform component = new GameObject("Button Row", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>(); ((Transform)component).SetParent(scrollView, false); component.sizeDelta = new Vector2(0f, 30f); return component; } private static void RefreshMenu() { MenuPageCosmetics? activePage = CosmeticsMenuState.ActivePage; if (activePage != null) { activePage.RefreshScrollContent(); } } } internal static class CosmeticsMenuState { [CompilerGenerated] private sealed class <SearchRefreshCoroutine>d__51 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public MenuPageCosmetics page; object? IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SearchRefreshCoroutine>d__51(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 1; return true; case 1: <>1__state = -1; _searchDebounce = null; page.RefreshScrollContent(); 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 Coroutine? _searchDebounce; private const float SearchDebounceDelay = 0.25f; private static Dictionary<CosmeticAsset, int>? _assetIndexCache; internal static CosmeticCategoryAsset? SelectedCategory { get; private set; } internal static CosmeticCategoryAsset? SearchCategory { get; private set; } internal static CosmeticCategoryAsset? FavoritesCategory { get; private set; } internal static CosmeticCategoryAsset? HiddenCategory { get; private set; } internal static TextMeshProUGUI? StatusLabel { get; private set; } internal static TMP_InputField? SearchField { get; private set; } internal static GameObject? EmptyStateLabel { get; private set; } internal static bool SearchMode { get; private set; } internal static string SearchText { get; private set; } = ""; internal static MenuPageCosmetics? ActivePage { get; private set; } internal static bool IsVirtual(CosmeticCategoryAsset? c) { if ((Object)(object)c != (Object)null) { if (!((Object)(object)c == (Object)(object)SelectedCategory) && !((Object)(object)c == (Object)(object)SearchCategory) && !((Object)(object)c == (Object)(object)FavoritesCategory)) { return (Object)(object)c == (Object)(object)HiddenCategory; } return true; } return false; } internal static bool IsSelected(CosmeticCategoryAsset? c) { if ((Object)(object)c != (Object)null) { return (Object)(object)c == (Object)(object)SelectedCategory; } return false; } internal static bool IsSearch(CosmeticCategoryAsset? c) { if ((Object)(object)c != (Object)null) { return (Object)(object)c == (Object)(object)SearchCategory; } return false; } internal static bool IsFavCategory(CosmeticCategoryAsset? c) { if ((Object)(object)c != (Object)null) { return (Object)(object)c == (Object)(object)FavoritesCategory; } return false; } internal static bool IsHideCategory(CosmeticCategoryAsset? c) { if ((Object)(object)c != (Object)null) { return (Object)(object)c == (Object)(object)HiddenCategory; } return false; } internal static void EnsureCategories() { if (SelectedCategory == null) { SelectedCategory = MakeCategory("MHB_Selected", "SELECTED"); } if (SearchCategory == null) { SearchCategory = MakeCategory("MHB_Search", "SEARCH"); } if (FavoritesCategory == null) { FavoritesCategory = MakeCategory("MHB_Favorites", "FAV"); } if (HiddenCategory == null) { HiddenCategory = MakeCategory("MHB_Hidden", "HIDE"); } } internal static void SetStatusLabel(TextMeshProUGUI? v) { StatusLabel = v; } internal static void SetSearchField(TMP_InputField? v) { SearchField = v; } internal static void SetEmptyStateLabel(GameObject? v) { EmptyStateLabel = v; } internal static void SetSearchMode(bool v) { SearchMode = v; } internal static void SetSearchText(string v) { SearchText = v; } internal static void ClearSearch() { SearchText = ""; SearchMode = false; if ((Object)(object)SearchField != (Object)null) { SearchField.SetTextWithoutNotify(""); } } internal static void ScheduleSearchRefresh() { MenuPageCosmetics activePage = ActivePage; if (!((Object)(object)activePage == (Object)null)) { if (_searchDebounce != null) { ((MonoBehaviour)activePage).StopCoroutine(_searchDebounce); } _searchDebounce = ((MonoBehaviour)activePage).StartCoroutine(SearchRefreshCoroutine(activePage)); } } [IteratorStateMachine(typeof(<SearchRefreshCoroutine>d__51))] private static IEnumerator SearchRefreshCoroutine(MenuPageCosmetics page) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SearchRefreshCoroutine>d__51(0) { page = page }; } internal static void SetActivePage(MenuPageCosmetics? v) { ActivePage = v; } internal static void OnMenuClosed() { if (_searchDebounce != null && (Object)(object)ActivePage != (Object)null) { ((MonoBehaviour)ActivePage).StopCoroutine(_searchDebounce); } _searchDebounce = null; ActivePage = null; _assetIndexCache = null; } internal static int GetAssetIndex(CosmeticAsset asset) { if ((Object)(object)MetaManager.instance == (Object)null) { return -1; } if (_assetIndexCache == null) { List<CosmeticAsset> cosmeticAssets = MetaManager.instance.cosmeticAssets; _assetIndexCache = new Dictionary<CosmeticAsset, int>(cosmeticAssets.Count); for (int i = 0; i < cosmeticAssets.Count; i++) { if ((Object)(object)cosmeticAssets[i] != (Object)null) { _assetIndexCache[cosmeticAssets[i]] = i; } } } if (!_assetIndexCache.TryGetValue(asset, out var value)) { return -1; } return value; } internal static bool IsPresetsCategory(CosmeticCategoryAsset? cat) { if ((Object)(object)cat == (Object)null) { return false; } string text = (cat.categoryName ?? ((Object)cat).name ?? "").ToUpperInvariant(); if (!text.Contains("PRESET")) { return text.Contains("OUTFIT"); } return true; } private static CosmeticCategoryAsset MakeCategory(string id, string label) { CosmeticCategoryAsset val = ScriptableObject.CreateInstance<CosmeticCategoryAsset>(); ((Object)val).name = id; val.categoryName = label; val.typeList = Enum.GetValues(typeof(CosmeticType)).Cast<CosmeticType>().ToList(); return val; } } internal static class FavHideMarkerHelper { private const string MarkerName = "MHB_FavHideMarker"; private const float OffsetX = -7f; private const float OffsetY = 7f; private const float Size = 9f; internal static void UpdateMarker(MenuElementCosmeticButton btn) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)btn == (Object)null || (Object)(object)btn.cosmeticAsset == (Object)null) { return; } bool flag = BridgeFavoritesManager.IsFavorite(btn.cosmeticAsset); bool flag2 = BridgeFavoritesManager.IsHidden(btn.cosmeticAsset); Transform val = ((Component)btn).transform.Find("MHB_FavHideMarker"); if (!flag && !flag2) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } return; } Image val4; if ((Object)(object)val == (Object)null) { GameObject val2 = new GameObject("MHB_FavHideMarker"); RectTransform val3 = val2.AddComponent<RectTransform>(); val2.transform.SetParent(((Component)btn).transform, false); val2.transform.SetAsLastSibling(); val3.anchorMin = new Vector2(1f, 0f); val3.anchorMax = new Vector2(1f, 0f); val3.pivot = new Vector2(1f, 0f); ApplyRect(val3); val4 = val2.AddComponent<Image>(); ((Graphic)val4).raycastTarget = false; val4.preserveAspect = true; } else { val.SetAsLastSibling(); ApplyRect(((Component)val).GetComponent<RectTransform>()); val4 = ((Component)val).GetComponent<Image>(); } if (!((Object)(object)val4 == (Object)null)) { if (flag) { val4.sprite = FavHideIcons.StarSprite; ((Graphic)val4).color = Color.white; } else { val4.sprite = FavHideIcons.HideSprite; ((Graphic)val4).color = Color.white; } } } private static void ApplyRect(RectTransform? rt) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rt == (Object)null)) { rt.anchoredPosition = new Vector2(-7f, 7f); rt.sizeDelta = new Vector2(9f, 9f); } } } [HarmonyPatch] internal static class CosmeticsBulkActionRefreshPatch { [CompilerGenerated] private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; MethodBase IEnumerator<MethodBase>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TargetMethods>d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = AccessTools.Method(typeof(MenuPageCosmetics), "RandomizeAllButton", (Type[])null, (Type[])null); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = AccessTools.Method(typeof(MenuPageCosmetics), "RandomizeCosmeticsButton", (Type[])null, (Type[])null); <>1__state = 2; return true; case 2: <>1__state = -1; <>2__current = AccessTools.Method(typeof(MenuPageCosmetics), "ResetAllButton", (Type[])null, (Type[])null); <>1__state = 3; return true; case 3: <>1__state = -1; <>2__current = AccessTools.Method(typeof(MenuPageCosmetics), "ResetCosmeticsButton", (Type[])null, (Type[])null); <>1__state = 4; return true; case 4: <>1__state = -1; 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(); } [DebuggerHidden] IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <TargetMethods>d__0(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodBase>)this).GetEnumerator(); } } [IteratorStateMachine(typeof(<TargetMethods>d__0))] private static IEnumerable<MethodBase> TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TargetMethods>d__0(-2); } [HarmonyPostfix] private static void Postfix(MenuPageCosmetics __instance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if ((int)__instance.selectedTab == 0 && CosmeticsMenuState.IsSelected(__instance.selectedCategory)) { __instance.RefreshScrollContent(); } } } [HarmonyPatch(typeof(MenuPageCosmetics), "RefreshScrollContent")] internal static class CosmeticsFilterPatch { private const float SectionSpacing = 10f; private const float SectionHeader = 40f; internal const string WorldSectionName = "MHB_WorldSection"; internal const CosmeticType WorldSubCategory = 999; [HarmonyPostfix] private static void Postfix(MenuPageCosmetics __instance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Invalid comparison between Unknown and I4 //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Invalid comparison between Unknown and I4 //IL_03f8: Unknown result type (might be due to invalid IL or missing references) //IL_0402: Expected O, but got Unknown //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_047f: Unknown result type (might be due to invalid IL or missing references) //IL_048d: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_04cd: Unknown result type (might be due to invalid IL or missing references) //IL_04d9: Unknown result type (might be due to invalid IL or missing references) if ((int)__instance.selectedTab == 1) { UpdateSearchFieldVisibility(isSearch: false); HideEmptyState(); return; } CosmeticCategoryAsset selectedCategory = __instance.selectedCategory; if ((Object)(object)selectedCategory == (Object)null) { return; } if (CosmeticsMenuState.IsPresetsCategory(selectedCategory)) { UpdateSearchFieldVisibility(isSearch: false); HideEmptyState(); return; } bool flag = CosmeticsMenuState.IsSelected(selectedCategory); bool flag2 = CosmeticsMenuState.IsSearch(selectedCategory); bool flag3 = CosmeticsMenuState.IsFavCategory(selectedCategory); bool flag4 = CosmeticsMenuState.IsHideCategory(selectedCategory); bool flag5 = CosmeticsMenuState.IsVirtual(selectedCategory); string text = (CosmeticsMenuState.SearchText?.Trim() ?? "").ToLowerInvariant(); bool flag6 = text.Length > 0; UpdateSearchFieldVisibility(flag2); BridgeFavoritesManager.EnsureLoaded(); bool flag7 = !flag4 && !flag && BridgeFavoritesManager.HasAnyHidden(); if (!flag5 && !flag6 && !flag7) { SortFavoritesInCategory(__instance); HideEmptyState(); } else { if ((Object)(object)MetaManager.instance == (Object)null) { return; } HashSet<int> equippedSet = new HashSet<int>(MetaManager.instance.cosmeticEquipped); HashSet<int> unlocksSet = new HashSet<int>(MetaManager.instance.cosmeticUnlocks); Dictionary<CosmeticAsset, int> assetIndexMap = BuildAssetIndexMap(MetaManager.instance); Dictionary<CosmeticType, GameObject> dictionary = new Dictionary<CosmeticType, GameObject>(); foreach (Transform item in __instance.subCategoriesTransform) { Transform val = item; MenuElementButtonCosmeticCategory component = ((Component)val).GetComponent<MenuElementButtonCosmeticCategory>(); if ((Object)(object)component != (Object)null && (int)component.buttonType == 1) { dictionary[component.subCategory] = ((Component)val).gameObject; } } foreach (GameObject value in dictionary.Values) { value.SetActive(!flag5); } float num = 0f; int num2 = 0; bool flag8 = flag5 && HhhCosmeticLoader.WorldAssetIds.Count > 0; MenuElementCosmeticSection val2 = null; foreach (MenuElementCosmeticSection item2 in __instance.sections.ToList()) { if (item2.isStickyHeader) { continue; } bool flag9 = flag8 && (int)item2.subCategory == 0; MenuElementCosmeticButton[] componentsInChildren = ((Component)item2.cosmeticListTransform).GetComponentsInChildren<MenuElementCosmeticButton>(true); MenuElementCosmeticButton[] array = componentsInChildren.Where((MenuElementCosmeticButton b) => (Object)(object)b != (Object)null && (Object)(object)b.cosmeticAsset != (Object)null).ToArray(); int num3 = 0; MenuElementCosmeticButton[] array2 = array; foreach (MenuElementCosmeticButton val3 in array2) { if ((Object)(object)val3 == (Object)null || (Object)(object)((Component)val3).gameObject == (Object)null) { continue; } bool flag10; if (flag9 && HhhCosmeticLoader.IsWorldAsset(val3.cosmeticAsset)) { flag10 = false; } else { if (!flag5 && flag7) { if (BridgeFavoritesManager.IsHidden(val3.cosmeticAsset) && ((Component)val3).gameObject.activeSelf) { ((Component)val3).gameObject.SetActive(false); } if (((Component)val3).gameObject.activeSelf) { FavHideMarkerHelper.UpdateMarker(val3); } continue; } flag10 = Matches(val3.cosmeticAsset, flag, flag2, flag3, flag4, flag7, flag6, text, equippedSet, assetIndexMap, unlocksSet); } if (((Component)val3).gameObject.activeSelf != flag10) { ((Component)val3).gameObject.SetActive(flag10); } if (flag10) { FavHideMarkerHelper.UpdateMarker(val3); } else { num3++; } } int num4 = array.Length - num3; if (num4 == 0) { if (flag5) { __instance.sections.Remove(item2); Object.Destroy((Object)(object)((Component)item2).gameObject); } continue; } num2 += num4; if (flag5) { if (!((Component)item2).gameObject.activeSelf) { ((Component)item2).gameObject.SetActive(true); } if ((Object)(object)item2.highlightObj != (Object)null) { ((Component)item2.highlightObj).gameObject.SetActive(false); } GridLayoutGroup component2 = ((Component)item2.cosmeticListTransform).GetComponent<GridLayoutGroup>(); ((LayoutGroup)component2).padding = new RectOffset(((LayoutGroup)component2).padding.left, ((LayoutGroup)component2).padding.right, ((LayoutGroup)component2).padding.top, 0); int num5 = Mathf.Max(1, component2.constraintCount); int num6 = Mathf.Max(1, Mathf.CeilToInt((float)(num4 + 1) / (float)num5)); float num7 = component2.cellSize.y * (float)num6 + component2.spacing.y * (float)(num6 - 1) + (float)((LayoutGroup)component2).padding.top + (float)((LayoutGroup)component2).padding.bottom; float num8 = 40f + num7; RectTransform component3 = ((Component)item2).GetComponent<RectTransform>(); ((Transform)component3).localPosition = new Vector3(((Transform)component3).localPosition.x, num, ((Transform)component3).localPosition.z); component3.sizeDelta = new Vector2(component3.sizeDelta.x, num8); RectTransform component4 = ((Component)item2.cosmeticListTransform).GetComponent<RectTransform>(); component4.sizeDelta = new Vector2(component4.sizeDelta.x, num7); LayoutRebuilder.ForceRebuildLayoutImmediate(component4); LayoutRebuilder.ForceRebuildLayoutImmediate(component3); val2 = item2; num -= num8 + 10f; } } if (!flag5 || flag2 || flag || flag3 || flag4) { SortFavoritesInCategory(__instance, flag); } int num9 = (flag8 ? InjectWorldSection(__instance, num, flag, flag2, flag3, flag4, flag7, flag6, text, equippedSet, assetIndexMap, unlocksSet) : 0); num2 += num9; if (flag5) { MenuElementCosmeticSection obj; if (num9 <= 0) { obj = val2; } else { List<MenuElementCosmeticSection> sections = __instance.sections; obj = sections[sections.Count - 1]; } MenuElementCosmeticSection section = obj; ApplyStickyPadding(__instance, section); } if (flag5 && num2 == 0) { string message = (flag3 ? "Add a favorite with Ctrl+click :)" : (flag4 ? "Hide cosmetics with Alt+click :P" : ((!flag2) ? "Equip a cosmetic to see it here :3" : (string.IsNullOrWhiteSpace(CosmeticsMenuState.SearchText) ? "Type to search cosmetics here :)" : "No cosmetics found :'(")))); ShowEmptyState(message); } else { HideEmptyState(); } if (flag5) { RebuildScroll(__instance); } } } private static void SortFavoritesInCategory(MenuPageCosmetics page, bool hiddenAtEnd = false) { bool flag = BridgeFavoritesManager.HasAnyFavorite(); bool hasHidden = hiddenAtEnd && BridgeFavoritesManager.HasAnyHidden(); foreach (MenuElementCosmeticSection section in page.sections) { if ((Object)(object)section == (Object)null || (Object)(object)section.cosmeticListTransform == (Object)null) { continue; } MenuElementCosmeticButton[] componentsInChildren = ((Component)section.cosmeticListTransform).GetComponentsInChildren<MenuElementCosmeticButton>(true); MenuElementCosmeticButton[] array = componentsInChildren; foreach (MenuElementCosmeticButton val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val.cosmeticAsset != (Object)null && ((Component)val).gameObject.activeSelf) { FavHideMarkerHelper.UpdateMarker(val); } } MenuElementCosmeticButton val2 = ((IEnumerable<MenuElementCosmeticButton>)componentsInChildren).FirstOrDefault((Func<MenuElementCosmeticButton, bool>)((MenuElementCosmeticButton b) => (Object)(object)b != (Object)null && (Object)(object)b.cosmeticAsset == (Object)null)); MenuElementCosmeticButton[] array2 = componentsInChildren.Where((MenuElementCosmeticButton b) => (Object)(object)b != (Object)null && (Object)(object)b.cosmeticAsset != (Object)null).ToArray(); if (array2.Length == 0) { continue; } bool flag2 = flag && array2.Any((MenuElementCosmeticButton b) => ((Component)b).gameObject.activeSelf && BridgeFavoritesManager.IsFavorite(b.cosmeticAsset)); bool flag3 = hasHidden && array2.Any((MenuElementCosmeticButton b) => ((Component)b).gameObject.activeSelf && BridgeFavoritesManager.IsHidden(b.cosmeticAsset)); bool flag4 = array2.Any((MenuElementCosmeticButton b) => ((Component)b).gameObject.activeSelf && PerCosmeticOverrides.IsModdedForAsset(b.cosmeticAsset)); if (!flag2 && !flag3 && !flag4) { continue; } MenuElementCosmeticButton[] array3 = array2.Where((MenuElementCosmeticButton b) => ((Component)b).gameObject.activeSelf).OrderBy(delegate(MenuElementCosmeticButton b) { if (BridgeFavoritesManager.IsFavorite(b.cosmeticAsset)) { return 0; } return (!hasHidden || !BridgeFavoritesManager.IsHidden(b.cosmeticAsset)) ? 1 : 3; }).ThenBy((MenuElementCosmeticButton b) => (!IsUnlocked(b)) ? 1 : 0) .ThenBy((MenuElementCosmeticButton b) => (!PerCosmeticOverrides.IsModdedForAsset(b.cosmeticAsset)) ? 1 : 0) .ThenBy((MenuElementCosmeticButton b) => ((Component)b).transform.GetSiblingIndex()) .ToArray(); MenuElementCosmeticButton[] array4 = (from b in array2 where !((Component)b).gameObject.activeSelf orderby ((Component)b).transform.GetSiblingIndex() select b).ToArray(); int num = 0; if ((Object)(object)val2 != (Object)null) { ((Component)val2).transform.SetSiblingIndex(num++); } MenuElementCosmeticButton[] array5 = array3; foreach (MenuElementCosmeticButton val3 in array5) { ((Component)val3).transform.SetSiblingIndex(num++); } MenuElementCosmeticButton[] array6 = array4; foreach (MenuElementCosmeticButton val4 in array6) { ((Component)val4).transform.SetSiblingIndex(num++); } Transform cosmeticListTransform = section.cosmeticListTransform; RectTransform val5 = ((cosmeticListTransform != null) ? ((Component)cosmeticListTransform).GetComponent<RectTransform>() : null); if ((Object)(object)val5 != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate(val5); } } } private static bool IsUnlocked(MenuElementCosmeticButton btn) { if ((Object)(object)MetaManager.instance == (Object)null) { return true; } int assetIndex = CosmeticsMenuState.GetAssetIndex(btn.cosmeticAsset); if (assetIndex < 0) { return true; } return MetaManager.instance.cosmeticUnlocks.Contains(assetIndex); } private static void ApplyStickyPadding(MenuPageCosmetics page, MenuElementCosmeticSection? section) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)section == (Object)null) { return; } RectTransform val = page.stickyHeader?.viewport; if ((Object)(object)val == (Object)null) { return; } RectTransform component = ((Component)section).GetComponent<RectTransform>(); Transform cosmeticListTransform = section.cosmeticListTransform; RectTransform val2 = ((cosmeticListTransform != null) ? ((Component)cosmeticListTransform).GetComponent<RectTransform>() : null); Transform cosmeticListTransform2 = section.cosmeticListTransform; GridLayoutGroup val3 = ((cosmeticListTransform2 != null) ? ((Component)cosmeticListTransform2).GetComponent<GridLayoutGroup>() : null); if (!((Object)(object)component == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null)) { Rect rect = val.rect; float num = Mathf.Max(0f, ((Rect)(ref rect)).height - component.sizeDelta.y - 10f); if (!(num <= 0f)) { ((LayoutGroup)val3).padding = new RectOffset(((LayoutGroup)val3).padding.left, ((LayoutGroup)val3).padding.right, ((LayoutGroup)val3).padding.top, (int)num); val2.sizeDelta = new Vector2(val2.sizeDelta.x, val2.sizeDelta.y + num); component.sizeDelta = new Vector2(component.sizeDelta.x, component.sizeDelta.y + num); LayoutRebuilder.ForceRebuildLayoutImmediate(val2); LayoutRebuilder.ForceRebuildLayoutImmediate(component); } } } private static int InjectWorldSection(MenuPageCosmetics page, float yPos, bool isSelected, bool isSearch, bool isFav, bool isHide, bool suppressHidden, bool applySearch, string search, HashSet<int> equippedSet, Dictionary<CosmeticAsset, int> assetIndexMap, HashSet<int> unlocksSet) { //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Unknown result type (might be due to invalid IL or missing references) string search2 = search; HashSet<int> equippedSet2 = equippedSet; Dictionary<CosmeticAsset, int> assetIndexMap2 = assetIndexMap; HashSet<int> unlocksSet2 = unlocksSet; for (int num = page.sections.Count - 1; num >= 0; num--) { if ((Object)(object)page.sections[num] != (Object)null && ((Object)((Component)page.sections[num]).gameObject).name == "MHB_WorldSection") { Object.Destroy((Object)(object)((Component)page.sections[num]).gameObject); page.sections.RemoveAt(num); } } int value; List<CosmeticAsset> list = (from a in MetaManager.instance.cosmeticAssets where (Object)(object)a != (Object)null && a.prefab.IsValid() && HhhCosmeticLoader.IsWorldAsset(a) && Matches(a, isSelected, isSearch, isFav, isHide, suppressHidden, applySearch, search2, equippedSet2, assetIndexMap2, unlocksSet2) orderby !unlocksSet2.Contains(assetIndexMap2.TryGetValue(a, out value) ? value : (-1)), a.rarity descending, a.assetName select a).ToList(); if (isSearch || isSelected) { bool hiddenAtEnd = isSelected; list = (from t in list.Select((CosmeticAsset a, int i) => (a, i)) orderby (!BridgeFavoritesManager.IsFavorite(t.a)) ? ((!hiddenAtEnd || !BridgeFavoritesManager.IsHidden(t.a)) ? 1 : 3) : 0, t.i select t.a).ToList(); } if (list.Count == 0) { return 0; } GameObject val = Object.Instantiate<GameObject>(page.sectionPrefab, page.sectionRootTransform); ((Object)val).name = "MHB_WorldSection"; MenuElementCosmeticSection component = val.GetComponent<MenuElementCosmeticSection>(); component.subCategory = (CosmeticType)999; if ((Object)(object)component.headerText != (Object)null) { ((TMP_Text)component.headerText).text = "WORLD"; ((TMP_Text)component.headerText).ForceMeshUpdate(false, false); } if ((Object)(object)component.highlightObj != (Object)null) { ((Component)component.highlightObj).gameObject.SetActive(false); } GridLayoutGroup component2 = ((Component)component.cosmeticListTransform).GetComponent<GridLayoutGroup>(); foreach (CosmeticAsset item in list) { GameObject val2 = Object.Instantiate<GameObject>(page.sectionButtonPrefab, component.cosmeticListTransform); MenuElementCosmeticButton component3 = val2.GetComponent<MenuElementCosmeticButton>(); component3.cosmeticAsset = item; FavHideMarkerHelper.UpdateMarker(component3); } int count = list.Count; int num2 = Mathf.Max(1, component2.constraintCount); int num3 = Mathf.Max(1, Mathf.CeilToInt((float)(count + 1) / (float)num2)); float num4 = component2.cellSize.y * (float)num3 + component2.spacing.y * (float)(num3 - 1) + (float)((LayoutGroup)component2).padding.top + (float)((LayoutGroup)component2).padding.bottom; float num5 = 40f + num4; RectTransform component4 = val.GetComponent<RectTransform>(); ((Transform)component4).localPosition = new Vector3(((Transform)component4).localPosition.x, yPos, ((Transform)component4).localPosition.z); component4.sizeDelta = new Vector2(component4.sizeDelta.x, num5); RectTransform component5 = ((Component)component.cosmeticListTransform).GetComponent<RectTransform>(); component5.sizeDelta = new Vector2(component5.sizeDelta.x, num4); LayoutRebuilder.ForceRebuildLayoutImmediate(component5); LayoutRebuilder.ForceRebuildLayoutImmediate(component4); page.sections.Add(component); return count; } private static void UpdateSearchFieldVisibility(bool isSearch) { TMP_InputField searchField = CosmeticsMenuState.SearchField; if ((Object)(object)searchField == (Object)null) { return; } if (isSearch) { CosmeticsMenuState.SetSearchMode(v: true); ((Component)searchField).gameObject.SetActive(true); return; } if (CosmeticsMenuState.SearchMode) { CosmeticsMenuState.ClearSearch(); } ((Component)searchField).gameObject.SetActive(false); } private static bool Matches(CosmeticAsset asset, bool isSelected, bool isSearch, bool isFav, bool isHide, bool suppressHidden, bool applySearch, string search, HashSet<int> equippedSet, Dictionary<CosmeticAsset, int> assetIndexMap, HashSet<int> unlocksSet) { if (isSearch && !applySearch) { return false; } assetIndexMap.TryGetValue(asset, out var value); if (isHide) { return BridgeFavoritesManager.IsHidden(asset); } if (isFav) { return BridgeFavoritesManager.IsFavorite(asset); } if (suppressHidden && BridgeFavoritesManager.IsHidden(asset)) { return false; } if (isSelected && !equippedSet.Contains(value)) { return false; } if (isSearch && value >= 0 && !unlocksSet.Contains(value)) { return false; } if (applySearch) { string text = (asset.assetName ?? ((Object)asset).name ?? "").ToLowerInvariant(); if (!text.Contains(search)) { return false; } } return true; } private static Dictionary<CosmeticAsset, int> BuildAssetIndexMap(MetaManager meta) { Dictionary<CosmeticAsset, int> dictionary = new Dictionary<CosmeticAsset, int>(meta.cosmeticAssets.Count); for (int i = 0; i < meta.cosmeticAssets.Count; i++) { CosmeticAsset val = meta.cosmeticAssets[i]; if ((Object)(object)val != (Object)null) { dictionary[val] = i; } } return dictionary; } private static void ShowEmptyState(string message) { GameObject emptyStateLabel = CosmeticsMenuState.EmptyStateLabel; if (!((Object)(object)emptyStateLabel == (Object)null)) { TextMeshProUGUI component = emptyStateLabel.GetComponent<TextMeshProUGUI>(); if ((Object)(object)component != (Object)null) { ((TMP_Text)component).text = message; } if (!emptyStateLabel.activeSelf) { emptyStateLabel.SetActive(true); } } } private static void HideEmptyState() { GameObject emptyStateLabel = CosmeticsMenuState.EmptyStateLabel; if ((Object)(object)emptyStateLabel != (Object)null && emptyStateLabel.activeSelf) { emptyStateLabel.SetActive(false); } } private static void RebuildScroll(MenuPageCosmetics page) { ScrollRect componentInChildren = ((Component)page).GetComponentInChildren<ScrollRect>(true); if ((Object)(object)((componentInChildren != null) ? componentInChildren.content : null) != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate(componentInChildren.content); } } } [HarmonyPatch(typeof(MenuPageCosmetics), "LateUpdate")] internal static class CosmeticsMenuLateUpdatePatch { private const string Hint = "Ctrl+click = Fav\nAlt+click = Hide"; private const float HintDelay = 2f; private const float HintFade = 0.5f; private const float HintAlpha = 0.4f; private static readonly Color NormalColor = Color.white; private static float _noHoverTime; internal static void OnMenuClosed() { _noHoverTime = 0f; } [HarmonyPostfix] private static void Postfix(MenuPageCosmetics __instance) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI statusLabel = CosmeticsMenuState.StatusLabel; if ((Object)(object)statusLabel == (Object)null) { return; } if ((int)__instance.selectedTab != 0) { _noHoverTime = 0f; ((Component)((TMP_Text)statusLabel).transform.parent).gameObject.SetActive(false); return; } ((Component)((TMP_Text)statusLabel).transform.parent).gameObject.SetActive(true); MenuElementCosmeticButton hoveredCosmeticButton = __instance.hoveredCosmeticButton; bool flag = false; if ((Object)(object)hoveredCosmeticButton != (Object)null) { flag = (Object)(object)hoveredCosmeticButton.cosmeticAsset != (Object)null || IsLocked(hoveredCosmeticButton); } if (flag) { _noHoverTime = 0f; string text; if (IsLocked(hoveredCosmeticButton)) { text = "Locked"; } else { CosmeticAsset cosmeticAsset = hoveredCosmeticButton.cosmeticAsset; string text2 = cosmeticAsset?.assetName ?? ((cosmeticAsset != null) ? ((Object)cosmeticAsset).name : null) ?? ""; BridgeFavoritesManager.EnsureLoaded(); bool fl