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.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Pigeon; using Sparroh.UI; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Sparroh")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.2.0")] [assembly: AssemblyInformationalVersion("1.1.2")] [assembly: AssemblyProduct("UpgradeFiltering")] [assembly: AssemblyTitle("UpgradeFiltering")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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; } } } public static class ConfigManager { private const float DebounceSeconds = 0.25f; private static ConfigFile config; private static ManualLogSource logger; private static FileSystemWatcher configWatcher; private static volatile bool reloadPending; private static float lastReloadTime; public static ConfigEntry EnableStatReformat { get; private set; } public static void Initialize(ConfigFile configFile, ManualLogSource log) { config = configFile; logger = log; EnableStatReformat = config.Bind("General", "Enable Reformat", false, "Force Key: Value stat format"); StatFormatHandling.enableStatReformat = EnableStatReformat.Value; EnableStatReformat.SettingChanged += OnStatReformatChanged; try { SetupFileWatcher(); } catch (Exception ex) { logger.LogError((object)("Error setting up config file watcher: " + ex.Message)); } } public static void Tick() { if (!reloadPending || Time.unscaledTime - lastReloadTime < 0.25f) { return; } reloadPending = false; lastReloadTime = Time.unscaledTime; try { config.Reload(); StatFormatHandling.enableStatReformat = EnableStatReformat.Value; logger.LogInfo((object)"Config reloaded from disk."); } catch (Exception ex) { logger.LogError((object)("Error reloading config: " + ex.Message)); } } public static void Dispose() { if (EnableStatReformat != null) { EnableStatReformat.SettingChanged -= OnStatReformatChanged; } if (configWatcher != null) { configWatcher.EnableRaisingEvents = false; configWatcher.Changed -= OnConfigFileChanged; configWatcher.Created -= OnConfigFileChanged; configWatcher.Renamed -= OnConfigFileChanged; configWatcher.Dispose(); configWatcher = null; } } private static void SetupFileWatcher() { configWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.upgradefiltering.cfg"); configWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite; configWatcher.Changed += OnConfigFileChanged; configWatcher.Created += OnConfigFileChanged; configWatcher.Renamed += OnConfigFileChanged; configWatcher.EnableRaisingEvents = true; } private static void OnConfigFileChanged(object sender, FileSystemEventArgs e) { reloadPending = true; } private static void OnStatReformatChanged(object sender, EventArgs e) { StatFormatHandling.enableStatReformat = EnableStatReformat.Value; } } public class FilterPanelUI { private readonly Dictionary _rarityButtons = new Dictionary(); private UIButton _favHide; private UIButton _favOnly; private UIButton _favShowAll; private UIScrollView _statScroll; private UIWindow _window; private bool isInitialized; public bool IsExpanded { get; private set; } public void Toggle() { if (!isInitialized) { CreateFilterPanel(); if (!isInitialized) { return; } } IsExpanded = !IsExpanded; if (IsExpanded) { RegenerateStatFilters(); _window.Show(); } else { _window.Hide(false); } } public void RegenerateStatFilters() { try { if (isInitialized && _statScroll != null) { FilterState.CurrentFilters.StatIncludeList.Clear(); FilterState.CurrentFilters.FilterStats = false; RebuildStatToggles(); } } catch { } } public void RebuildFilterPanel() { try { bool isExpanded = IsExpanded; if (_window != null) { _window.Destroy(); _window = null; } _rarityButtons.Clear(); isInitialized = false; IsExpanded = false; CreateFilterPanel(); if (isExpanded && isInitialized) { IsExpanded = true; _window.Show(); } } catch { } } private void CreateFilterPanel() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) if (isInitialized) { return; } try { UITheme.Initialize(); _window = UIWindow.Create("UpgradeFilter", (Vector2?)new Vector2(280f, 480f), "Upgrade Filters", true, true, (int?)(UITheme.WindowSortingOrder + 7)); _window.OnClose((Action)delegate { IsExpanded = false; }); Transform content = _window.Content; UIFactory.AddVerticalLayout(((Component)content).gameObject, UITheme.S(6f), UITheme.ScaledPadding(6, 6, 6, 6), (TextAnchor)0, true, false, true, true); UIButton.Create(content, "Clear All Filters", (Action)ClearAllFilters, (UIButtonStyle)2, (string)null, (float?)UITheme.S(28f)); UIText.Create(content, "RarityLbl", "Hide Rarities", UITheme.ScaledFontSmall, (Color?)UIColors.TextSecondary, (TextAlignmentOptions)513, false); (string, Rarity)[] array = new(string, Rarity)[5] { ("Standard", (Rarity)0), ("Rare", (Rarity)1), ("Epic", (Rarity)2), ("Exotic", (Rarity)3), ("Oddity", (Rarity)4) }; for (int num = 0; num < array.Length; num++) { (string, Rarity) tuple = array[num]; Rarity rarity = tuple.Item2; bool flag = FilterState.CurrentFilters.HiddenRarities.Contains(rarity); UIButton value = UIButton.Create(content, tuple.Item1, (Action)delegate { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0055: Unknown result type (might be due to invalid IL or missing references) if (FilterState.CurrentFilters.HiddenRarities.Contains(rarity)) { FilterState.CurrentFilters.HiddenRarities.Remove(rarity); _rarityButtons[rarity].SetStyle((UIButtonStyle)0); UpgradeFilteringPlugin.Logger.LogInfo((object)$"Filter: show rarity {rarity}"); } else { FilterState.CurrentFilters.HiddenRarities.Add(rarity); _rarityButtons[rarity].SetStyle((UIButtonStyle)2); UpgradeFilteringPlugin.Logger.LogInfo((object)$"Filter: hide rarity {rarity}"); } UpgradeFilteringPlugin.Logger.LogInfo((object)("Filter: HiddenRarities=[" + string.Join(",", FilterState.CurrentFilters.HiddenRarities) + "]")); RefreshUpgrades(); }, (UIButtonStyle)(flag ? 2 : 0), (string)null, (float?)UITheme.S(24f)); _rarityButtons[rarity] = value; } UIText.Create(content, "FavLbl", "Favorites", UITheme.ScaledFontSmall, (Color?)UIColors.TextSecondary, (TextAlignmentOptions)513, false); _favShowAll = UIButton.Create(content, "Show All", (Action)delegate { FilterState.CurrentFilters.FavoriteSetting = FavoriteFilter.ShowAll; UpdateFavoriteHighlights(); RefreshUpgrades(); }, (UIButtonStyle)3, (string)null, (float?)UITheme.S(24f)); _favOnly = UIButton.Create(content, "Only Favorite", (Action)delegate { FilterState.CurrentFilters.FavoriteSetting = FavoriteFilter.ShowOnlyFavorited; UpdateFavoriteHighlights(); RefreshUpgrades(); }, (UIButtonStyle)0, (string)null, (float?)UITheme.S(24f)); _favHide = UIButton.Create(content, "Hide Favorite", (Action)delegate { FilterState.CurrentFilters.FavoriteSetting = FavoriteFilter.HideFavorited; UpdateFavoriteHighlights(); RefreshUpgrades(); }, (UIButtonStyle)0, (string)null, (float?)UITheme.S(24f)); UIText.Create(content, "StatLbl", "Show Only With", UITheme.ScaledFontSmall, (Color?)UIColors.TextSecondary, (TextAlignmentOptions)513, false); _statScroll = UIScrollView.Create(content, "StatScroll", true, false); GameObject gameObject = _statScroll.GameObject; float? num2 = UITheme.S(160f); float? num3 = UITheme.S(120f); UIHelpers.EnsureLayoutElement(gameObject, (float?)null, num2, num3); RebuildStatToggles(); _window.Hide(false); isInitialized = true; IsExpanded = false; } catch (Exception) { isInitialized = false; } } private void UpdateFavoriteHighlights() { FavoriteFilter favoriteSetting = FilterState.CurrentFilters.FavoriteSetting; if (_favShowAll != null) { _favShowAll.SetStyle((UIButtonStyle)((favoriteSetting == FavoriteFilter.ShowAll) ? 3 : 0)); } if (_favOnly != null) { _favOnly.SetStyle((UIButtonStyle)((favoriteSetting == FavoriteFilter.ShowOnlyFavorited) ? 3 : 0)); } if (_favHide != null) { _favHide.SetStyle((UIButtonStyle)((favoriteSetting == FavoriteFilter.HideFavorited) ? 3 : 0)); } } private void ClearAllFilters() { FilterState.CurrentFilters.HiddenRarities.Clear(); FilterState.CurrentFilters.FavoriteSetting = FavoriteFilter.ShowAll; FilterState.CurrentFilters.FilterStats = false; FilterState.CurrentFilters.StatIncludeList.Clear(); foreach (KeyValuePair rarityButton in _rarityButtons) { rarityButton.Value.SetStyle((UIButtonStyle)0); } UpdateFavoriteHighlights(); RebuildStatToggles(); RefreshUpgrades(); } private void RebuildStatToggles() { if (_statScroll == null) { return; } UIHelpers.DestroyChildren((Transform)(object)_statScroll.Content); foreach (string item in from p in GetContextAwareProperties() orderby p select p) { string text = item.Replace("_", " "); string prop = item; GameObject gameObject = UIToggle.Create((Transform)(object)_statScroll.Content, text, false, (Action)delegate(bool value) { if (value) { FilterState.CurrentFilters.FilterStats = true; if (!FilterState.CurrentFilters.StatIncludeList.Contains(prop)) { FilterState.CurrentFilters.StatIncludeList.Add(prop); } } else { FilterState.CurrentFilters.StatIncludeList.Remove(prop); if (FilterState.CurrentFilters.StatIncludeList.Count == 0) { FilterState.CurrentFilters.FilterStats = false; } } RefreshUpgrades(); }, (string)null).GameObject; float? num = UITheme.S(22f); UIHelpers.EnsureLayoutElement(gameObject, (float?)null, num, (float?)null); } } private List GetContextAwareProperties() { try { GearDetailsWindow openWindow = FilterState.GetOpenWindow(); bool flag = false; if ((Object)(object)openWindow != (Object)null) { FieldInfo fieldInfo = AccessTools.Field(typeof(GearDetailsWindow), "inSkinMode"); if (fieldInfo != null) { try { flag = (bool)fieldInfo.GetValue(openWindow); } catch { } } } return flag ? DiscoverSkinProperties() : GetCuratedUpgradeProperties(); } catch { return GetCuratedUpgradeProperties(); } } private static List GetCuratedUpgradeProperties() { return new List { "AmmoCapacity", "AutomaticFire", "BatteryCapacity", "BulletsPerShot", "BurstFire", "Carver_Blood", "Charge", "Damage", "FireInterval", "Globbler_Globblometer", "Health", "HealthRegenDelay", "HitForce", "MagazineSize", "MaxBounces", "MeleeDamage", "Range", "Recoil", "Reload", "Speed" }; } private static List DiscoverSkinProperties() { List list = new List(); try { Type skinUpgradePropertyType = typeof(GearUpgradeUI).Assembly.GetType("SkinUpgradeProperty"); if (skinUpgradePropertyType == null) { return list; } foreach (Type item in (from t in skinUpgradePropertyType.Assembly.GetTypes() where t.IsClass && !t.IsAbstract && skinUpgradePropertyType.IsAssignableFrom(t) && t.FullName != null && t.FullName.StartsWith("SkinUpgradeProperty_") select t).ToList()) { string text = item.Name; if (text.StartsWith("SkinUpgradeProperty_")) { text = text.Substring("SkinUpgradeProperty_".Length); } list.Add(text); } return (from p in list.Distinct() orderby p select p).ToList(); } catch { return list; } } private void RefreshUpgrades() { GearDetailsWindow val = PriorityPatches.ResolveWindow() ?? FilterState.GetOpenWindow(); if ((Object)(object)val == (Object)null) { UpgradeFilteringPlugin.Logger.LogWarning((object)"Filter refresh: no GearDetailsWindow."); return; } UpgradeFilteringPlugin.Logger.LogInfo((object)$"Filter refresh: window={((Object)val).name}, priorityActive={PriorityPatches.PrioritySortActive}"); try { FilterState.ApplyToWindow(val); } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogError((object)("Filter refresh failed: " + ex.Message + "\n" + ex.StackTrace)); } } } [HarmonyPatch(typeof(GearDetailsWindow))] public static class GearDetailsWindowPatches { [HarmonyPostfix] [HarmonyPatch("OnOpen")] private static void OnOpen(GearDetailsWindow __instance) { try { FieldInfo fieldInfo = AccessTools.Field(typeof(GearDetailsWindow), "inSkinMode"); if (fieldInfo != null) { bool flag = (bool)fieldInfo.GetValue(__instance); if (FilterState.PreviousSkinMode.HasValue && FilterState.PreviousSkinMode.Value != flag && FilterState.FilterPanel != null) { FilterState.FilterPanel.RegenerateStatFilters(); } FilterState.PreviousSkinMode = flag; } } catch { } if (FilterState.FilterPanel == null) { FilterState.FilterPanel = new FilterPanelUI(); } } [HarmonyPrefix] [HarmonyPatch("SwitchUpgradeView")] private static void SwitchUpgradeView_Prefix() { ListRebuildReapply.BeginViewSwitch(); } [HarmonyPostfix] [HarmonyPatch("SwitchUpgradeView")] private static void SwitchUpgradeView_Postfix(GearDetailsWindow __instance) { try { ListRebuildReapply.After(__instance, "SwitchUpgradeView"); } finally { ListRebuildReapply.EndViewSwitch(); } } } [HarmonyPatch(typeof(GearDetailsWindow), "SetupUpgrades", new Type[] { typeof(IUpgradable), typeof(bool), typeof(bool) })] public static class SetupUpgradesPatch { [HarmonyPostfix] public static void Postfix(GearDetailsWindow __instance, bool skins) { if (!ListRebuildReapply.SuppressNestedReapply) { ListRebuildReapply.After(__instance, $"SetupUpgrades(skins={skins})"); } } } [HarmonyPatch(typeof(GearDetailsWindow), "SortUpgrades", new Type[] { typeof(SortingMethod), typeof(bool) })] public static class SortUpgradesMethodPatch { private static bool? lastSkinMode; [HarmonyPostfix] public static void Postfix(GearDetailsWindow __instance, SortingMethod method, bool resetScroll) { if (ListRebuildReapply.SuppressNestedReapply || PriorityPatches.PrioritySortActive) { return; } FieldInfo fieldInfo = AccessTools.Field(typeof(GearDetailsWindow), "inSkinMode"); bool flag = false; if (fieldInfo != null) { try { flag = (bool)fieldInfo.GetValue(__instance); } catch { } } bool num = lastSkinMode.HasValue && lastSkinMode.Value != flag; lastSkinMode = flag; if (num) { return; } try { FilterState.ApplyToWindow(__instance); } catch { } } } internal static class ListRebuildReapply { public static bool SuppressNestedReapply { get; private set; } public static void After(GearDetailsWindow window, string reason) { if ((Object)(object)window == (Object)null) { return; } try { PriorityPatches.currentWindow = window; PriorityPatches.CancelDeferredLayout(); List upgradeUIs = FilterState.GetUpgradeUIs(); int num = FilterState.GetUpgradeUICount(window); if (upgradeUIs == null) { UpgradeFilteringPlugin.Logger.LogWarning((object)("List rebuild (" + reason + "): upgradeUIs null")); return; } if (num <= 0 || num > upgradeUIs.Count) { num = upgradeUIs.Count; } PriorityPatches.ClearStalePoolSlots(upgradeUIs, num); if (!PriorityPatches.LogUniqueInstanceIds("BEFORE repair (" + reason + ")", upgradeUIs, num) && !PriorityPatches.TryRepairDuplicateUiRefs(window, upgradeUIs, num)) { UpgradeFilteringPlugin.Logger.LogError((object)("List rebuild (" + reason + "): pool repair failed — reopen gear window.")); return; } PriorityPatches.ActivateAllLiveSlots(upgradeUIs, num); if (PriorityPatches.PrioritySortActive) { PriorityPatches.ApplyPrioritySort(window, resetScroll: false, skipDeferred: true); UpgradeFilteringPlugin.Logger.LogInfo((object)$"List rebuild re-apply ({reason}): visual priority + filters, isGrid={PriorityPatches.GetIsGridView(window)}"); } else if (FilterState.HasActiveFilters()) { FilterState.ApplyToWindow(window); UpgradeFilteringPlugin.Logger.LogInfo((object)$"List rebuild re-apply ({reason}): filters only, isGrid={PriorityPatches.GetIsGridView(window)}"); } else { PriorityPatches.ForceLayoutVisibleOnly(window, upgradeUIs, num); UpgradeFilteringPlugin.Logger.LogInfo((object)$"List rebuild re-apply ({reason}): layout only, isGrid={PriorityPatches.GetIsGridView(window)}"); } } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogError((object)("List rebuild re-apply failed (" + reason + "): " + ex.Message + "\n" + ex.StackTrace)); } } public static void BeginViewSwitch() { SuppressNestedReapply = true; PriorityPatches.CancelDeferredLayout(); } public static void EndViewSwitch() { SuppressNestedReapply = false; } } public enum FavoriteFilter { ShowAll, ShowOnlyFavorited, HideFavorited } public struct FilterSettings { public List HiddenRarities; public bool FilterStats; public List StatIncludeList; public FavoriteFilter FavoriteSetting; } public static class FilterState { internal static FilterPanelUI FilterPanel; internal static readonly Dictionary RarityOrder = new Dictionary { { (Rarity)4, 5 }, { (Rarity)3, 4 }, { (Rarity)2, 3 }, { (Rarity)1, 2 }, { (Rarity)0, 1 }, { (Rarity)(-1), 0 } }; internal static FilterSettings CurrentFilters = new FilterSettings { HiddenRarities = new List(), FilterStats = false, StatIncludeList = new List(), FavoriteSetting = FavoriteFilter.ShowAll }; internal static bool? PreviousSkinMode; private static FieldInfo _upgradeUIsField; private static FieldInfo _upgradeUICountField; public static bool HasActiveFilters() { if (!CurrentFilters.HiddenRarities.Any() && CurrentFilters.FavoriteSetting == FavoriteFilter.ShowAll) { if (CurrentFilters.FilterStats) { return CurrentFilters.StatIncludeList.Any(); } return false; } return true; } public static void ApplyVisibilityOnly(GearDetailsWindow window) { if ((Object)(object)window == (Object)null) { return; } List upgradeUIs = GetUpgradeUIs(); if (upgradeUIs == null || upgradeUIs.Count == 0) { return; } int num = GetUpgradeUICount(window); if (num <= 0) { num = upgradeUIs.Count; } num = Mathf.Min(num, upgradeUIs.Count); bool isGridView = PriorityPatches.GetIsGridView(window); int num2 = 0; int num3 = 0; int num4 = 0; for (int i = 0; i < num; i++) { GearUpgradeUI val = upgradeUIs[i]; if ((Object)(object)val == (Object)null) { continue; } UpgradeInstance upgrade = ((HoverInfoUpgrade)val).Upgrade; if ((Object)(object)((upgrade != null) ? upgrade.Upgrade : null) == (Object)null) { if (((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(false); } num3++; } else if (ShouldShow(val)) { if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); try { val.SetUpgrade(((HoverInfoUpgrade)val).Upgrade, false); } catch { } num4++; } try { val.EnableGridView(isGridView); } catch { } num2++; } else { if (((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(false); } num3++; } } UpgradeFilteringPlugin.Logger.LogInfo((object)($"Filter visibility: count={num}, visible={num2}, hidden={num3}, " + $"reenabled={num4}, fav={CurrentFilters.FavoriteSetting}")); } public static void ApplyToWindow(GearDetailsWindow window) { if ((Object)(object)window == (Object)null) { UpgradeFilteringPlugin.Logger.LogWarning((object)"ApplyToWindow: window null"); return; } List upgradeUIs = GetUpgradeUIs(); if (upgradeUIs == null || upgradeUIs.Count == 0) { UpgradeFilteringPlugin.Logger.LogWarning((object)"ApplyToWindow: upgradeUIs empty"); return; } int num = GetUpgradeUICount(window); if (num <= 0) { num = upgradeUIs.Count; } num = Mathf.Min(num, upgradeUIs.Count); string arg = ((CurrentFilters.HiddenRarities != null && CurrentFilters.HiddenRarities.Count > 0) ? string.Join(",", CurrentFilters.HiddenRarities) : "(none)"); UpgradeFilteringPlugin.Logger.LogInfo((object)($"Filter apply: count={num}, hiddenRarities=[{arg}], " + $"fav={CurrentFilters.FavoriteSetting}, stats={CurrentFilters.FilterStats}/" + $"{CurrentFilters.StatIncludeList?.Count ?? 0}")); ApplyVisibilityOnly(window); if (PriorityPatches.PrioritySortActive) { List order = PriorityPatches.FilterOrderForAvailableMods(PriorityPatches.LoadPriorityOrder()); PriorityPatches.ApplyVisualPriorityOrder(window, upgradeUIs, num, order); } else { PriorityPatches.ForceLayoutVisibleOnly(window, upgradeUIs, num); } try { typeof(GearDetailsWindow).GetMethod("SetUpgradeListScroll", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(float) }, null)?.Invoke(window, new object[1] { 1f }); } catch { } } internal static List GetUpgradeUIs() { try { if (_upgradeUIsField == null) { _upgradeUIsField = typeof(GearDetailsWindow).GetField("upgradeUIs", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if (_upgradeUIsField == null) { return null; } return _upgradeUIsField.GetValue(null) as List; } catch { return null; } } internal static int GetUpgradeUICount(GearDetailsWindow window) { if ((Object)(object)window == (Object)null) { return 0; } try { if (_upgradeUICountField == null) { _upgradeUICountField = typeof(GearDetailsWindow).GetField("upgradeUICount", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (_upgradeUICountField == null) { return 0; } return (int)_upgradeUICountField.GetValue(window); } catch { return 0; } } internal static GearDetailsWindow GetOpenWindow() { try { Menu instance = Menu.Instance; if ((Object)(object)((instance != null) ? instance.WindowSystem : null) != (Object)null) { Window top = Menu.Instance.WindowSystem.GetTop(); GearDetailsWindow val = (GearDetailsWindow)(object)((top is GearDetailsWindow) ? top : null); if ((Object)(object)val != (Object)null) { return val; } } } catch { } if ((Object)(object)PriorityPatches.currentWindow != (Object)null) { try { if ((Object)(object)((Component)PriorityPatches.currentWindow).gameObject != (Object)null) { return PriorityPatches.currentWindow; } } catch { } } try { return Object.FindObjectOfType(); } catch { return null; } } public static bool ShouldShow(GearUpgradeUI ui) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) object obj; if (ui == null) { obj = null; } else { UpgradeInstance upgrade = ((HoverInfoUpgrade)ui).Upgrade; obj = ((upgrade != null) ? upgrade.Upgrade : null); } if ((Object)obj == (Object)null) { return false; } bool flag = true; if (CurrentFilters.HiddenRarities != null && CurrentFilters.HiddenRarities.Count > 0) { flag &= !CurrentFilters.HiddenRarities.Contains(((HoverInfoUpgrade)ui).Upgrade.Upgrade.Rarity); } switch (CurrentFilters.FavoriteSetting) { case FavoriteFilter.ShowOnlyFavorited: flag &= ((HoverInfoUpgrade)ui).Upgrade.Favorite; break; case FavoriteFilter.HideFavorited: flag &= !((HoverInfoUpgrade)ui).Upgrade.Favorite; break; } if (CurrentFilters.FilterStats && CurrentFilters.StatIncludeList != null && CurrentFilters.StatIncludeList.Count > 0) { foreach (string statInclude in CurrentFilters.StatIncludeList) { bool flag2 = false; Enumerator properties = ((HoverInfoUpgrade)ui).Upgrade.Upgrade.GetProperties(); while (((Enumerator)(ref properties)).MoveNext()) { UpgradeProperty current2 = ((Enumerator)(ref properties)).Current; if (current2 != null) { string text = ((object)current2).GetType().Name; if (text.StartsWith("UpgradeProperty_")) { text = text.Substring("UpgradeProperty_".Length); } else if (text.StartsWith("SkinUpgradeProperty_")) { text = text.Substring("SkinUpgradeProperty_".Length); } if (text == statInclude) { flag2 = true; break; } } } if (!flag2) { return false; } } } return flag; } } [BepInPlugin("sparroh.upgradefiltering", "UpgradeFiltering", "1.1.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [MycoMod(/*Could not decode attribute arguments.*/)] public class UpgradeFilteringPlugin : BaseUnityPlugin { public const string PluginGUID = "sparroh.upgradefiltering"; public const string PluginName = "UpgradeFiltering"; public const string PluginVersion = "1.1.2"; internal static ManualLogSource Logger; public static UpgradeFilteringPlugin Instance; private bool _barRegistered; private void Awake() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown try { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; Harmony val = new Harmony("sparroh.upgradefiltering"); try { ConfigManager.Initialize(((BaseUnityPlugin)this).Config, Logger); } catch (Exception ex) { Logger.LogError((object)("Failed to setup configuration bindings: " + ex.Message)); } try { StatFormatHandling.Initialize(); } catch (Exception ex2) { Logger.LogError((object)("Failed to initialize StatFormatHandling: " + ex2.Message)); } try { PriorityGUI.EnsureExists(); } catch (Exception ex3) { Logger.LogError((object)("Failed to initialize PriorityGUI: " + ex3.Message)); } try { PriorityPatches.Patch(val); } catch (Exception ex4) { Logger.LogError((object)("Failed to apply PriorityPatches: " + ex4.Message)); } Type[] array = new Type[4] { typeof(GearDetailsWindowPatches), typeof(SetupUpgradesPatch), typeof(SortUpgradesMethodPatch), typeof(PriorityPatches) }; foreach (Type type in array) { try { val.PatchAll(type); } catch (Exception ex5) { Logger.LogError((object)("Failed to patch " + type.Name + ": " + ex5.Message)); } } try { array = typeof(UpgradeFilteringPlugin).Assembly.GetTypes(); foreach (Type type2 in array) { if (type2 == typeof(GearDetailsWindowPatches) || type2 == typeof(SetupUpgradesPatch) || type2 == typeof(SortUpgradesMethodPatch) || type2 == typeof(PriorityPatches) || type2 == typeof(ListRebuildReapply) || !type2.IsClass) { continue; } object[] customAttributes = type2.GetCustomAttributes(typeof(HarmonyPatch), inherit: true); if (customAttributes != null && customAttributes.Length != 0) { try { val.PatchAll(type2); } catch (Exception ex6) { Logger.LogError((object)("Failed to patch " + type2.Name + ": " + ex6.Message)); } } } } catch (Exception ex7) { Logger.LogError((object)("Failed scanning assembly patches: " + ex7.Message)); } } catch (Exception ex8) { Logger.LogError((object)("Critical error during mod initialization: " + ex8.Message + "\n" + ex8.StackTrace)); } Logger.LogInfo((object)"UpgradeFiltering loaded successfully."); } private void Update() { ConfigManager.Tick(); GearActionBar.Tick(); if (GearActionBar.IsGearMenuOpen() && !_barRegistered) { GearActionBar.Register("filter", "Filter", 100, (Action)delegate { FilterState.FilterPanel?.Toggle(); }, (UIButtonStyle)0); GearActionBar.Register("priority", "Upgr. Sort", 110, (Action)PriorityGUI.ToggleWindowStatic, (UIButtonStyle)1); _barRegistered = true; } } private void OnDestroy() { ConfigManager.Dispose(); GearActionBar.Unregister("filter"); GearActionBar.Unregister("priority"); _barRegistered = false; } } [Serializable] public class PriorityData { public List order; public PriorityData() { order = new List { 0, 1, 2, 3, 7, 8, 9, 10, 11, 12, 14, 4, 5, 6 }; } public string ToJson() { return JsonUtility.ToJson((object)this); } public static PriorityData FromJson(string json) { if (string.IsNullOrEmpty(json)) { return new PriorityData(); } return JsonUtility.FromJson(json); } } public enum PriorityCriteria { Favorited, NotFavorited, Unlocked, Locked, RecentlyUsed, RecentlyAcquired, InstanceName, Oddity, Exotic, Epic, Rare, Standard, Turbocharged, Trashed, NotTurbocharged, NotTrashed } public class PriorityGUI : MonoBehaviour { private static readonly PriorityCriteria[] BaseDefaultOrder = new PriorityCriteria[14] { PriorityCriteria.Favorited, PriorityCriteria.NotFavorited, PriorityCriteria.Unlocked, PriorityCriteria.Locked, PriorityCriteria.Oddity, PriorityCriteria.Exotic, PriorityCriteria.Epic, PriorityCriteria.Rare, PriorityCriteria.Standard, PriorityCriteria.Turbocharged, PriorityCriteria.NotTurbocharged, PriorityCriteria.RecentlyUsed, PriorityCriteria.RecentlyAcquired, PriorityCriteria.InstanceName }; private static readonly PriorityCriteria[] TrashCriteria = new PriorityCriteria[2] { PriorityCriteria.Trashed, PriorityCriteria.NotTrashed }; private UIDragList _list; private UIWindow _window; private List currentOrder; private bool showWindow; public static PriorityGUI Instance { get; private set; } private void Awake() { Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); currentOrder = PriorityPatches.LoadPriorityOrder(); } private void Update() { if (!PriorityPatches.IsWindowOpen && !GearActionBar.IsGearMenuOpen() && showWindow) { CloseWindow(reload: true); } } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private static List BuildDefaultOrder() { List list = BaseDefaultOrder.ToList(); if (PriorityPatches.IsBatchScrappingPresent()) { int num = list.IndexOf(PriorityCriteria.Locked); if (num < 0) { num = list.Count - 1; } list.InsertRange(num + 1, TrashCriteria); } return list; } public static void EnsureExists() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) PriorityGUI priorityGUI = Object.FindObjectOfType(); if ((Object)(object)priorityGUI != (Object)null) { Object.Destroy((Object)(object)((Component)priorityGUI).gameObject); Instance = null; } new GameObject("PriorityGUI").AddComponent(); } public static void ToggleWindowStatic() { if (!((Object)(object)Instance == (Object)null)) { Instance.ToggleWindow(); } } private void ToggleWindow() { if (showWindow) { CloseWindow(reload: true); } else { OpenWindow(); } } private void OpenWindow() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Expected O, but got Unknown showWindow = true; currentOrder = PriorityPatches.LoadPriorityOrder(); if (currentOrder == null || currentOrder.Count == 0) { currentOrder = BuildDefaultOrder(); } else { currentOrder = PriorityPatches.FilterOrderForAvailableMods(currentOrder); } if (_window == null) { _window = UIWindow.Create("SortPriority", (Vector2?)new Vector2(340f, 560f), "Sort Priority", false, true, (int?)null); _window.OnClose((Action)delegate { CloseWindow(reload: true); }); Transform content = _window.Content; UIFactory.AddVerticalLayout(((Component)content).gameObject, UITheme.S(8f), UITheme.ScaledPadding(8, 8, 8, 8), (TextAnchor)0, true, false, true, true); UIText.Create(content, "Hint", "Higher = applied first. Put rarities above Name/Recently* or they won't matter.", UITheme.ScaledFontSmall, (Color?)UIColors.TextSecondary, (TextAlignmentOptions)513, false); _list = UIDragList.Create(content, "PriorityList"); GameObject gameObject = _list.GameObject; float? num = UITheme.S(400f); float? num2 = UITheme.S(280f); UIHelpers.EnsureLayoutElement(gameObject, (float?)null, num, num2); LayoutElement component = _list.GameObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.flexibleHeight = 1f; } _list.OnReordered((Action)delegate(int from, int to) { if (from >= 0 && to >= 0 && from < currentOrder.Count && to < currentOrder.Count) { PriorityCriteria item = currentOrder[from]; currentOrder.RemoveAt(from); currentOrder.Insert(to, item); } }); RectTransform obj = UIFactory.CreateRect("Buttons", content); GameObject gameObject2 = ((Component)obj).gameObject; num2 = UITheme.ScaledButtonHeight + UITheme.S(4f); UIHelpers.EnsureLayoutElement(gameObject2, (float?)null, num2, (float?)null); UIFactory.AddHorizontalLayout(((Component)obj).gameObject, UITheme.S(8f), new RectOffset(0, 0, 0, 0), (TextAnchor)4, false, false, true, true); UIButton.Create((Transform)(object)obj, "Save", (Action)delegate { PriorityPatches.SavePriorityOrder(currentOrder); PriorityPatches.TriggerPrioritySort(currentOrder); CloseWindow(reload: false); }, (UIButtonStyle)1, (string)null, (float?)null).SetWidth(UITheme.S(90f)); UIButton.Create((Transform)(object)obj, "Cancel", (Action)delegate { CloseWindow(reload: true); }, (UIButtonStyle)0, (string)null, (float?)null).SetWidth(UITheme.S(90f)); UIButton.Create((Transform)(object)obj, "Reset", (Action)delegate { currentOrder = BuildDefaultOrder(); RefreshList(); }, (UIButtonStyle)2, (string)null, (float?)null).SetWidth(UITheme.S(90f)); } RefreshList(); _window.Show(); } private void RefreshList() { if (_list == null || currentOrder == null) { return; } List list = new List(); foreach (PriorityCriteria item in currentOrder) { list.Add(GetCriteriaName(item)); } _list.SetItems((IList)list); } private void CloseWindow(bool reload) { showWindow = false; if (reload) { currentOrder = PriorityPatches.LoadPriorityOrder(); } if (_window != null) { _window.Hide(true); } } private string GetCriteriaName(PriorityCriteria criteria) { return criteria switch { PriorityCriteria.Favorited => "Favorited", PriorityCriteria.NotFavorited => "Not Favorited", PriorityCriteria.Unlocked => "Unlocked", PriorityCriteria.Locked => "Locked", PriorityCriteria.RecentlyUsed => "Recently Used", PriorityCriteria.RecentlyAcquired => "Recently Acquired", PriorityCriteria.InstanceName => "Name (tie-break)", PriorityCriteria.Oddity => "Oddity", PriorityCriteria.Exotic => "Exotic", PriorityCriteria.Epic => "Epic", PriorityCriteria.Rare => "Rare", PriorityCriteria.Standard => "Standard", PriorityCriteria.Turbocharged => "Turbocharged", PriorityCriteria.Trashed => "Trashed (BatchScrapping)", PriorityCriteria.NotTurbocharged => "Not Turbocharged", PriorityCriteria.NotTrashed => "Not Trashed (BatchScrapping)", _ => "Unknown", }; } } public static class PriorityPatches { private struct SortEntry { public GearUpgradeUI Ui; public int[] Keys; } private sealed class SortEntryComparer : IComparer { public static readonly SortEntryComparer Instance = new SortEntryComparer(); public int Compare(SortEntry x, SortEntry y) { int[] keys = x.Keys; int[] keys2 = y.Keys; if (keys == null && keys2 == null) { return 0; } if (keys == null) { return 1; } if (keys2 == null) { return -1; } int num = Math.Min(keys.Length, keys2.Length); for (int i = 0; i < num; i++) { int num2 = keys2[i].CompareTo(keys[i]); if (num2 != 0) { return num2; } } return keys.Length.CompareTo(keys2.Length); } } private static List priorityOrder; public static GearDetailsWindow currentWindow; private static bool? _batchScrappingPresent; private static MethodInfo _isTrashMarkedMethod; private static Coroutine _deferredLayoutCoroutine; private static bool _deferredLayoutCancelled; private static FieldInfo _isGridViewField; private static FieldInfo _upgradeListParentField; private static bool _layoutLookupsDone; public static bool PrioritySortActive { get; private set; } public static bool IsWindowOpen { get; private set; } static PriorityPatches() { priorityOrder = new List(); priorityOrder = LoadPriorityOrder(); try { string value = default(string); PrioritySortActive = PlayerOptions.TryGetConfig("SortPriority.Order", ref value) && !string.IsNullOrEmpty(value); } catch { PrioritySortActive = false; } } public static bool IsBatchScrappingPresent() { if (_batchScrappingPresent.HasValue) { return _batchScrappingPresent.Value; } try { foreach (PluginInfo value in Chainloader.PluginInfos.Values) { object obj; if (value == null) { obj = null; } else { BepInPlugin metadata = value.Metadata; obj = ((metadata != null) ? metadata.GUID : null); } if ((string?)obj == "sparroh.batchscrapping") { _batchScrappingPresent = true; CacheTrashApi(); return true; } } } catch { } try { if (AccessTools.TypeByName("ScrapHandlingMod") != null) { _batchScrappingPresent = true; CacheTrashApi(); return true; } } catch { } _batchScrappingPresent = false; return false; } private static void CacheTrashApi() { try { Type type = AccessTools.TypeByName("ScrapHandlingMod"); _isTrashMarkedMethod = ((type != null) ? AccessTools.Method(type, "IsTrashMarked", new Type[1] { typeof(UpgradeInstance) }, (Type[])null) : null); } catch { _isTrashMarkedMethod = null; } } public static bool IsTrashMarked(UpgradeInstance instance) { if (instance == null || !IsBatchScrappingPresent()) { return false; } if (_isTrashMarkedMethod != null) { try { return (bool)_isTrashMarkedMethod.Invoke(null, new object[1] { instance }); } catch { } } try { FieldInfo fieldInfo = AccessTools.Field(typeof(UpgradeInstance), "flags"); if (fieldInfo == null) { return false; } return (Convert.ToByte(fieldInfo.GetValue(instance)) & 0x20) != 0; } catch { return false; } } [HarmonyPostfix] [HarmonyPatch(typeof(GearDetailsWindow), "OnOpen")] public static void OnOpen_Postfix(GearDetailsWindow __instance) { IsWindowOpen = true; currentWindow = __instance; if (PrioritySortActive) { try { ApplyPrioritySort(__instance, priorityOrder, resetScroll: false); return; } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("Priority sort on open failed: " + ex.Message)); return; } } try { FilterState.ApplyToWindow(__instance); } catch { } } [HarmonyPostfix] [HarmonyPatch(typeof(GearDetailsWindow), "OnCloseCallback")] public static void OnCloseCallback_Postfix() { IsWindowOpen = false; currentWindow = null; } public static bool SortUpgradesInt_Prefix(int i) { if (PrioritySortActive) { PrioritySortActive = false; UpgradeFilteringPlugin.Logger.LogInfo((object)$"Priority sort disabled (vanilla sort button {i})."); } return true; } public static bool SortUpgradesMethod_Prefix(GearDetailsWindow __instance, SortingMethod method, bool resetScroll) { if (!PrioritySortActive) { return true; } if (ListRebuildReapply.SuppressNestedReapply) { return true; } try { ApplyPrioritySort(__instance, priorityOrder, resetScroll); return false; } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogError((object)("Priority sort prefix failed: " + ex.Message + "\n" + ex.StackTrace)); return true; } } public static bool SortUpgradesMethodPublic_Prefix(GearDetailsWindow __instance, SortingMethod method) { if (!PrioritySortActive) { return true; } if (ListRebuildReapply.SuppressNestedReapply) { return true; } try { ApplyPrioritySort(__instance, priorityOrder); return false; } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogError((object)("Priority sort public prefix failed: " + ex.Message)); return true; } } public static void Patch(Harmony harmony) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(GearDetailsWindow), "SortUpgrades", new Type[1] { typeof(int) }, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(PriorityPatches), "SortUpgradesInt_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { UpgradeFilteringPlugin.Logger.LogWarning((object)"Could not find SortUpgrades(int)."); } MethodInfo methodInfo2 = AccessTools.Method(typeof(GearDetailsWindow), "SortUpgrades", new Type[2] { typeof(SortingMethod), typeof(bool) }, (Type[])null); if (methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(PriorityPatches), "SortUpgradesMethod_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); UpgradeFilteringPlugin.Logger.LogInfo((object)"Patched SortUpgrades(SortingMethod, bool) for sticky priority."); return; } MethodInfo methodInfo3 = AccessTools.Method(typeof(GearDetailsWindow), "SortUpgrades", new Type[1] { typeof(SortingMethod) }, (Type[])null); if (methodInfo3 != null) { harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(PriorityPatches), "SortUpgradesMethodPublic_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { UpgradeFilteringPlugin.Logger.LogWarning((object)"Could not find SortUpgrades(SortingMethod) — sticky priority may not hook vanilla sorts."); } } public static void TriggerPrioritySort(List order = null) { if (order != null && order.Count > 0) { priorityOrder = new List(order); } else { priorityOrder = LoadPriorityOrder(); } PrioritySortActive = true; GearDetailsWindow val = ResolveWindow(); if ((Object)(object)val == (Object)null) { UpgradeFilteringPlugin.Logger.LogWarning((object)"Priority sort: no GearDetailsWindow found — order saved; will apply next open."); return; } currentWindow = val; ApplyPrioritySort(val, priorityOrder); } public static GearDetailsWindow ResolveWindow() { if ((Object)(object)currentWindow != (Object)null) { try { if ((Object)(object)((Component)currentWindow).gameObject != (Object)null && ((Component)currentWindow).gameObject.activeInHierarchy) { return currentWindow; } } catch { currentWindow = null; } } GearDetailsWindow openWindow = FilterState.GetOpenWindow(); if ((Object)(object)openWindow != (Object)null) { return openWindow; } try { return Object.FindObjectOfType(); } catch { return null; } } public static void ApplyPrioritySort(GearDetailsWindow window, bool resetScroll = true, bool skipDeferred = false) { ApplyPrioritySort(window, priorityOrder ?? LoadPriorityOrder(), resetScroll, skipDeferred); } public static void CancelDeferredLayout() { _deferredLayoutCancelled = true; try { if (_deferredLayoutCoroutine != null && (Object)(object)PriorityGUI.Instance != (Object)null) { ((MonoBehaviour)PriorityGUI.Instance).StopCoroutine(_deferredLayoutCoroutine); _deferredLayoutCoroutine = null; } } catch { } } public static void ApplyPrioritySort(GearDetailsWindow window, List order, bool resetScroll = true, bool skipDeferred = false) { if ((Object)(object)window == (Object)null) { return; } PrioritySortActive = true; if (order != null && order.Count > 0) { priorityOrder = new List(order); } List list = FilterOrderForAvailableMods(priorityOrder); List upgradeUIs = FilterState.GetUpgradeUIs(); if (upgradeUIs == null || upgradeUIs.Count == 0) { UpgradeFilteringPlugin.Logger.LogWarning((object)"Priority sort: upgradeUIs empty."); return; } int num = FilterState.GetUpgradeUICount(window); if (num <= 0 || num > upgradeUIs.Count) { num = upgradeUIs.Count; } UpgradeFilteringPlugin.Logger.LogInfo((object)($"Sort begin (visual-only): window={((Object)window).name}, listCount={upgradeUIs.Count}, uiCount={num}, " + "criteria=[" + string.Join(" > ", list) + "]")); ActivateAllLiveSlots(upgradeUIs, num); if (!LogUniqueInstanceIds("BEFORE visual sort", upgradeUIs, num) && !TryRepairDuplicateUiRefs(window, upgradeUIs, num)) { UpgradeFilteringPlugin.Logger.LogError((object)"Pool corrupt and repair failed — skip visual reorder; reopen gear window."); FilterState.ApplyVisibilityOnly(window); return; } FilterState.ApplyVisibilityOnly(window); ApplyVisualPriorityOrder(window, upgradeUIs, num, list); LogRowSnapshot("AFTER visual priority+filter", upgradeUIs, num); if (resetScroll) { try { typeof(GearDetailsWindow).GetMethod("SetUpgradeListScroll", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(float) }, null)?.Invoke(window, new object[1] { 1f }); } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("SetUpgradeListScroll failed: " + ex.Message)); } } try { typeof(GearDetailsWindow).GetMethod("DisableSortButtonContainer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null)?.Invoke(window, null); } catch { } } public static void ClearStalePoolSlots(List upgradeUIs, int liveCount) { if (upgradeUIs == null) { return; } liveCount = Mathf.Max(0, liveCount); int num = 0; for (int i = liveCount; i < upgradeUIs.Count; i++) { GearUpgradeUI val = upgradeUIs[i]; if ((Object)(object)val == (Object)null) { continue; } try { if (((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(false); } if (((HoverInfoUpgrade)val).Upgrade != null) { ((HoverInfoUpgrade)val).Upgrade = null; num++; } } catch { try { ((Component)val).gameObject.SetActive(false); } catch { } } } if (num > 0) { UpgradeFilteringPlugin.Logger.LogInfo((object)$"ClearStalePoolSlots: cleared Upgrade on {num} slots past liveCount={liveCount}"); } } public static bool TryRepairDuplicateUiRefs(GearDetailsWindow window, List upgradeUIs, int count) { if (upgradeUIs == null || (Object)(object)window == (Object)null || count <= 0) { return true; } count = Mathf.Min(count, upgradeUIs.Count); HashSet hashSet = new HashSet(); List list = new List(); for (int i = 0; i < count; i++) { GearUpgradeUI val = upgradeUIs[i]; if ((Object)(object)val == (Object)null) { list.Add(i); } else if (!hashSet.Add(val)) { list.Add(i); } } if (list.Count == 0) { return true; } UpgradeFilteringPlugin.Logger.LogWarning((object)$"Repairing {list.Count} duplicate/null GearUpgradeUI refs in live pool."); Queue queue = new Queue(); for (int j = 0; j < upgradeUIs.Count; j++) { GearUpgradeUI val2 = upgradeUIs[j]; if (!((Object)(object)val2 == (Object)null) && !hashSet.Contains(val2)) { queue.Enqueue(val2); } } RectTransform val3 = null; try { EnsureLayoutLookups(); object? obj = _upgradeListParentField?.GetValue(window); val3 = (RectTransform)((obj is RectTransform) ? obj : null); } catch { } FieldInfo fieldInfo = null; try { fieldInfo = typeof(GearDetailsWindow).GetField("upgradeUIPrefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { } foreach (int item in list) { GearUpgradeUI obj4 = upgradeUIs[item]; UpgradeInstance val4 = ((obj4 != null) ? ((HoverInfoUpgrade)obj4).Upgrade : null); GearUpgradeUI val5 = null; if (queue.Count > 0) { val5 = queue.Dequeue(); } else if (fieldInfo != null && (Object)(object)val3 != (Object)null) { try { object? value = fieldInfo.GetValue(window); GearUpgradeUI val6 = (GearUpgradeUI)((value is GearUpgradeUI) ? value : null); if ((Object)(object)val6 != (Object)null) { val5 = Object.Instantiate(val6, (Transform)(object)val3); upgradeUIs.Add(val5); } } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("Instantiate repair UI failed: " + ex.Message)); } } if ((Object)(object)val5 == (Object)null) { UpgradeFilteringPlugin.Logger.LogError((object)$"Could not repair duplicate at index {item}"); return false; } upgradeUIs[item] = val5; hashSet.Add(val5); try { if (val4 != null) { ((Component)val5).gameObject.SetActive(true); val5.SetUpgrade(val4, false); val5.EnableGridView(GetIsGridView(window)); } else { ((Component)val5).gameObject.SetActive(false); } } catch { } } return LogUniqueInstanceIds("AFTER pool ref repair", upgradeUIs, count); } public static void ActivateAllLiveSlots(List upgradeUIs, int count) { if (upgradeUIs == null) { return; } count = Mathf.Min(count, upgradeUIs.Count); ClearStalePoolSlots(upgradeUIs, count); bool isGridView = GetIsGridView(currentWindow); int num = 0; for (int i = 0; i < count; i++) { GearUpgradeUI val = upgradeUIs[i]; object obj; if (val == null) { obj = null; } else { UpgradeInstance upgrade = ((HoverInfoUpgrade)val).Upgrade; obj = ((upgrade != null) ? upgrade.Upgrade : null); } if ((Object)obj == (Object)null) { continue; } try { if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); num++; } val.EnableGridView(isGridView); } catch { } } UpgradeFilteringPlugin.Logger.LogInfo((object)$"ActivateAllLiveSlots: count={count}, reactivated={num}, isGrid={isGridView}"); } public static void ApplyVisualPriorityOrder(GearDetailsWindow window, List upgradeUIs, int count, List order) { if ((Object)(object)window == (Object)null || upgradeUIs == null) { return; } count = Mathf.Min(count, upgradeUIs.Count); List<(GearUpgradeUI, int[])> list = new List<(GearUpgradeUI, int[])>(count); for (int i = 0; i < count; i++) { GearUpgradeUI val = upgradeUIs[i]; if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeSelf) { continue; } UpgradeInstance upgrade = ((HoverInfoUpgrade)val).Upgrade; if ((Object)(object)((upgrade != null) ? upgrade.Upgrade : null) == (Object)null || !FilterState.ShouldShow(val)) { continue; } int[] array = new int[(order?.Count ?? 0) + 2]; int num = 0; if (order != null) { foreach (PriorityCriteria item4 in order) { array[num++] = ScoreCriteria(val, item4); } } array[num++] = ((HoverInfoUpgrade)val).Upgrade.InstanceID; array[num] = -i; list.Add((val, array)); } list.Sort(delegate((GearUpgradeUI ui, int[] keys) a, (GearUpgradeUI ui, int[] keys) b) { int[] item2 = a.keys; int[] item3 = b.keys; int num5 = Math.Min(item2.Length, item3.Length); for (int j = 0; j < num5; j++) { int num6 = item3[j].CompareTo(item2[j]); if (num6 != 0) { return num6; } } return 0; }); EnsureLayoutLookups(); bool isGridView = GetIsGridView(window); RectTransform listParent = null; try { object? obj = _upgradeListParentField?.GetValue(window); listParent = (RectTransform)((obj is RectTransform) ? obj : null); } catch { } for (int num2 = 0; num2 < count; num2++) { try { GearUpgradeUI obj3 = upgradeUIs[num2]; if (obj3 != null) { ((Component)obj3).transform.SetAsLastSibling(); } } catch { } } for (int num3 = 0; num3 < list.Count; num3++) { GearUpgradeUI item = list[num3].Item1; try { ((Component)item).transform.SetSiblingIndex(num3); item.EnableGridView(isGridView); SetUpgradeAnchoredPosition(item, num3, isGridView, listParent); } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("Visual order place failed: " + ex.Message)); } } int count2 = list.Count; for (int num4 = 0; num4 < count; num4++) { GearUpgradeUI val2 = upgradeUIs[num4]; if (!((Object)(object)val2 == (Object)null) && !((Component)val2).gameObject.activeSelf) { try { ((Component)val2).transform.SetSiblingIndex(count2++); } catch { } } } try { Canvas.ForceUpdateCanvases(); } catch { } UpgradeFilteringPlugin.Logger.LogInfo((object)$"Visual priority order: visiblePlaced={list.Count}, isGrid={isGridView}"); } private static IEnumerator DeferredLayout(GearDetailsWindow window) { yield return null; _deferredLayoutCoroutine = null; if (_deferredLayoutCancelled || (Object)(object)window == (Object)null) { yield break; } try { if (FilterState.HasActiveFilters() || PrioritySortActive) { FilterState.ApplyToWindow(window); } else { List upgradeUIs = FilterState.GetUpgradeUIs(); int num = FilterState.GetUpgradeUICount(window); if (upgradeUIs == null) { yield break; } if (num <= 0 || num > upgradeUIs.Count) { num = upgradeUIs.Count; } ForceLayout(window, upgradeUIs, num); } UpgradeFilteringPlugin.Logger.LogInfo((object)"Deferred layout pass complete."); } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("Deferred layout failed: " + ex.Message)); } } internal static void LogRowSnapshot(string label, List upgradeUIs, int count) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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) try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(label).Append(':'); int num = 0; for (int i = 0; i < count; i++) { if (num >= 6) { break; } GearUpgradeUI val = upgradeUIs[i]; if ((Object)(object)val == (Object)null) { continue; } string value = "?"; string value2 = "?"; try { UpgradeInstance upgrade = ((HoverInfoUpgrade)val).Upgrade; if ((Object)(object)((upgrade != null) ? upgrade.Upgrade : null) != (Object)null) { value = ((HoverInfoUpgrade)val).Upgrade.Upgrade.Name ?? "?"; value2 = ((object)((HoverInfoUpgrade)val).Upgrade.Upgrade.Rarity/*cast due to .constrained prefix*/).ToString(); } } catch { } Transform transform = ((Component)val).transform; RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null); Vector2 val3 = (((Object)(object)val2 != (Object)null) ? val2.anchoredPosition : Vector2.zero); int siblingIndex = ((Component)val).transform.GetSiblingIndex(); string value3 = (((Object)(object)((Component)val).transform.parent != (Object)null) ? ((Object)((Component)val).transform.parent).name : "null"); stringBuilder.Append("\n [").Append(i).Append("] ") .Append(value2) .Append(" | ") .Append(value) .Append(" | active=") .Append(((Component)val).gameObject.activeSelf) .Append(" | sib=") .Append(siblingIndex) .Append(" | pos=") .Append(val3) .Append(" | parent=") .Append(value3); num++; } UpgradeFilteringPlugin.Logger.LogInfo((object)stringBuilder.ToString()); } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("LogRowSnapshot failed: " + ex.Message)); } } private static void EnsureLayoutLookups() { if (!_layoutLookupsDone) { _layoutLookupsDone = true; Type? typeFromHandle = typeof(GearDetailsWindow); _isGridViewField = typeFromHandle.GetField("isGridView", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); _upgradeListParentField = typeFromHandle.GetField("upgradeListParent", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); UpgradeFilteringPlugin.Logger.LogInfo((object)($"Layout lookups: isGridView={_isGridViewField != null}, " + $"listParent={_upgradeListParentField != null}")); } } internal static bool GetIsGridView(GearDetailsWindow window) { EnsureLayoutLookups(); try { if (_isGridViewField == null) { return false; } return _isGridViewField.IsStatic ? ((bool)_isGridViewField.GetValue(null)) : ((bool)_isGridViewField.GetValue(window)); } catch { return false; } } internal static void ForceLayout(GearDetailsWindow window, List upgradeUIs, int count) { //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) if (upgradeUIs == null || (Object)(object)window == (Object)null) { return; } count = Mathf.Min(count, upgradeUIs.Count); EnsureLayoutLookups(); bool flag = false; try { if (_isGridViewField != null) { flag = (_isGridViewField.IsStatic ? ((bool)_isGridViewField.GetValue(null)) : ((bool)_isGridViewField.GetValue(window))); } } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("isGridView read failed: " + ex.Message)); } RectTransform val = null; try { object? obj = _upgradeListParentField?.GetValue(window); val = (RectTransform)((obj is RectTransform) ? obj : null); } catch (Exception ex2) { UpgradeFilteringPlugin.Logger.LogWarning((object)("upgradeListParent read failed: " + ex2.Message)); } string text = null; try { if (count > 0) { GearUpgradeUI obj2 = upgradeUIs[0]; object obj3; if (obj2 == null) { obj3 = null; } else { UpgradeInstance upgrade = ((HoverInfoUpgrade)obj2).Upgrade; obj3 = ((upgrade != null) ? upgrade.Upgrade : null); } if ((Object)obj3 != (Object)null) { text = ((HoverInfoUpgrade)upgradeUIs[0]).Upgrade.Upgrade.Name; } } } catch { } Vector2 val2 = default(Vector2); if (count > 0 && (Object)(object)upgradeUIs[0] != (Object)null) { Transform transform = ((Component)upgradeUIs[0]).transform; RectTransform val3 = (RectTransform)(object)((transform is RectTransform) ? transform : null); if ((Object)(object)val3 != (Object)null) { val2 = val3.anchoredPosition; } } for (int i = 0; i < count; i++) { GearUpgradeUI val4 = upgradeUIs[i]; if (!((Object)(object)val4 == (Object)null)) { try { ((Component)val4).transform.SetAsLastSibling(); } catch { } } } int num = 0; for (int j = 0; j < count; j++) { GearUpgradeUI val5 = upgradeUIs[j]; if ((Object)(object)val5 == (Object)null) { continue; } try { ((Component)val5).transform.SetSiblingIndex(j); } catch (Exception ex3) { UpgradeFilteringPlugin.Logger.LogWarning((object)$"Sibling set failed @ {j}: {ex3.Message}"); } if (((Component)val5).gameObject.activeSelf) { try { val5.EnableGridView(flag); SetUpgradeAnchoredPosition(val5, num, flag, val); } catch (Exception ex4) { UpgradeFilteringPlugin.Logger.LogWarning((object)$"Inline pos failed @ {j}: {ex4.Message}"); } num++; } } try { Canvas.ForceUpdateCanvases(); } catch { } string text2 = null; try { if (count > 0) { GearUpgradeUI obj7 = upgradeUIs[0]; object obj8; if (obj7 == null) { obj8 = null; } else { UpgradeInstance upgrade2 = ((HoverInfoUpgrade)obj7).Upgrade; obj8 = ((upgrade2 != null) ? upgrade2.Upgrade : null); } if ((Object)obj8 != (Object)null) { text2 = ((HoverInfoUpgrade)upgradeUIs[0]).Upgrade.Upgrade.Name; } } } catch { } Vector2 val6 = default(Vector2); if (count > 0 && (Object)(object)upgradeUIs[0] != (Object)null) { Transform transform2 = ((Component)upgradeUIs[0]).transform; RectTransform val7 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null); if ((Object)(object)val7 != (Object)null) { val6 = val7.anchoredPosition; } } if (text != null && text2 != null && text != text2) { UpgradeFilteringPlugin.Logger.LogError((object)("ForceLayout mutated list head! '" + text + "' -> '" + text2 + "'")); } UpgradeFilteringPlugin.Logger.LogInfo((object)(string.Format("ForceLayout done: isGrid={0}, listParent={1}, ", flag, ((Object)(object)val != (Object)null) ? ((Object)val).name : "null") + $"visiblePlaced={num}, head={text2}, firstPos {val2} -> {val6}")); } private static void SetUpgradeAnchoredPosition(GearUpgradeUI ui, int index, bool isGrid, RectTransform listParent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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) RectTransform val = (RectTransform)((Component)ui).transform; Rect rect = val.rect; float num; if (!(((Rect)(ref rect)).height > 1f)) { num = 52f; } else { rect = val.rect; num = ((Rect)(ref rect)).height; } float num2 = num; rect = val.rect; float num3; if (!(((Rect)(ref rect)).width > 1f)) { num3 = 300f; } else { rect = val.rect; num3 = ((Rect)(ref rect)).width; } float num4 = num3; if (isGrid && (Object)(object)listParent != (Object)null) { float num5 = num4 + 10f; rect = listParent.rect; float num6; if (!(((Rect)(ref rect)).width > 1f)) { num6 = 400f; } else { rect = listParent.rect; num6 = ((Rect)(ref rect)).width; } int num7 = Mathf.Max(Mathf.FloorToInt((num6 - 6f) / num5), 1); float num8 = 3f + (float)(index % num7) * (num4 + 10f); float num9 = -3f - (float)(index / num7) * (num2 + 10f); val.anchoredPosition = new Vector2(num8, num9); } else { Vector2 offsetMin = val.offsetMin; Vector2 offsetMax = val.offsetMax; val.offsetMin = new Vector2(0f, offsetMin.y); val.offsetMax = new Vector2(0f, offsetMax.y); val.anchoredPosition = new Vector2(0f, -3f - (num2 + 4f) * (float)index); } } public static List FilterOrderForAvailableMods(List order) { if (order == null) { return new List(); } List list = new List(order.Count); bool flag = IsBatchScrappingPresent(); foreach (PriorityCriteria item in order) { if (flag || (item != PriorityCriteria.Trashed && item != PriorityCriteria.NotTrashed)) { list.Add(item); } } return MigrateTotalKeysAfterRarities(list); } public static List MigrateTotalKeysAfterRarities(List order) { if (order == null || order.Count == 0) { return order ?? new List(); } int num = -1; int num2 = -1; for (int i = 0; i < order.Count; i++) { if (IsRarity(order[i])) { if (num < 0) { num = i; } num2 = i; } } if (num < 0) { return order; } bool flag = false; for (int j = 0; j < order.Count; j++) { if (IsTotalKey(order[j]) && j < num2) { flag = true; break; } } if (!flag) { return order; } List list = new List(order.Count); List list2 = new List(4); foreach (PriorityCriteria item in order) { if (IsTotalKey(item)) { list2.Add(item); } else { list.Add(item); } } list.AddRange(list2); UpgradeFilteringPlugin.Logger.LogInfo((object)"Migrated sort order: moved Name/Recently* after rarities so rarity criteria apply."); return list; static bool IsRarity(PriorityCriteria c) { if ((uint)(c - 7) <= 4u) { return true; } return false; } static bool IsTotalKey(PriorityCriteria c) { if ((uint)(c - 4) <= 2u) { return true; } return false; } } public static bool TryDecorateSortLiveSlice(List upgradeUIs, int count, List order) { if (upgradeUIs == null || count <= 0) { return true; } count = Mathf.Min(count, upgradeUIs.Count); int num = count; SortEntry[] array = new SortEntry[num]; int num2 = (order?.Count ?? 0) + 2; for (int i = 0; i < num; i++) { GearUpgradeUI val = upgradeUIs[i]; int[] array2 = new int[num2]; int num3 = 0; if (order != null) { foreach (PriorityCriteria item in order) { array2[num3++] = ScoreCriteria(val, item); } } array2[num3++] = ((((val != null) ? ((HoverInfoUpgrade)val).Upgrade : null) != null) ? ((HoverInfoUpgrade)val).Upgrade.InstanceID : int.MinValue); array2[num3] = -i; array[i] = new SortEntry { Ui = val, Keys = array2 }; } Array.Sort(array, SortEntryComparer.Instance); HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); for (int j = 0; j < num; j++) { GearUpgradeUI obj = upgradeUIs[j]; if (((obj != null) ? ((HoverInfoUpgrade)obj).Upgrade : null) != null) { hashSet.Add(((HoverInfoUpgrade)upgradeUIs[j]).Upgrade.InstanceID); } GearUpgradeUI ui = array[j].Ui; if (((ui != null) ? ((HoverInfoUpgrade)ui).Upgrade : null) != null) { hashSet2.Add(((HoverInfoUpgrade)array[j].Ui).Upgrade.InstanceID); } } if (hashSet.Count != hashSet2.Count || !hashSet.SetEquals(hashSet2)) { UpgradeFilteringPlugin.Logger.LogError((object)$"Decorate-sort validation failed: beforeIds={hashSet.Count} afterIds={hashSet2.Count}"); return false; } HashSet hashSet3 = new HashSet(); for (int k = 0; k < num; k++) { GearUpgradeUI ui2 = array[k].Ui; if (!((Object)(object)ui2 == (Object)null) && !hashSet3.Add(ui2)) { UpgradeFilteringPlugin.Logger.LogError((object)"Decorate-sort validation failed: duplicate GearUpgradeUI reference."); return false; } } for (int l = 0; l < num; l++) { upgradeUIs[l] = array[l].Ui; } return true; } private static int ScoreCriteria(GearUpgradeUI ui, PriorityCriteria criteria) { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Invalid comparison between Unknown and I4 //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Invalid comparison between Unknown and I4 //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Invalid comparison between Unknown and I4 //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Invalid comparison between Unknown and I4 //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Invalid comparison between Unknown and I4 UpgradeInstance val = ((ui != null) ? ((HoverInfoUpgrade)ui).Upgrade : null); if ((Object)(object)((val != null) ? val.Upgrade : null) == (Object)null) { return int.MinValue; } return criteria switch { PriorityCriteria.Favorited => val.Favorite ? 1 : 0, PriorityCriteria.NotFavorited => (!val.Favorite) ? 1 : 0, PriorityCriteria.Unlocked => val.IsUnlocked ? 1 : 0, PriorityCriteria.Locked => (!val.IsUnlocked) ? 1 : 0, PriorityCriteria.Turbocharged => val.IsTurbocharged ? 1 : 0, PriorityCriteria.NotTurbocharged => (!val.IsTurbocharged) ? 1 : 0, PriorityCriteria.Trashed => (!IsTrashMarked(val)) ? 1 : 0, PriorityCriteria.NotTrashed => (!IsTrashMarked(val)) ? 1 : 0, PriorityCriteria.RecentlyAcquired => (int)Math.Max(-2147483648L, Math.Min(2147483647L, val.TimeUnlocked)), PriorityCriteria.RecentlyUsed => (int)(val.TimeUnequipped * 1000f), PriorityCriteria.InstanceName => 0, PriorityCriteria.Oddity => ((int)val.Upgrade.Rarity == 4) ? 1 : 0, PriorityCriteria.Exotic => ((int)val.Upgrade.Rarity == 3) ? 1 : 0, PriorityCriteria.Epic => ((int)val.Upgrade.Rarity == 2) ? 1 : 0, PriorityCriteria.Rare => ((int)val.Upgrade.Rarity == 1) ? 1 : 0, PriorityCriteria.Standard => ((int)val.Upgrade.Rarity == 0) ? 1 : 0, _ => 0, }; } public static Comparison GetPriorityComparison(List order) { return delegate(GearUpgradeUI a, GearUpgradeUI b) { if (a == b) { return 0; } if ((Object)(object)a == (Object)null) { return 1; } if ((Object)(object)b == (Object)null) { return -1; } if (((HoverInfoUpgrade)a).Upgrade == null && ((HoverInfoUpgrade)b).Upgrade == null) { return 0; } if (((HoverInfoUpgrade)a).Upgrade == null) { return 1; } if (((HoverInfoUpgrade)b).Upgrade == null) { return -1; } if ((Object)(object)((HoverInfoUpgrade)a).Upgrade.Upgrade == (Object)null && (Object)(object)((HoverInfoUpgrade)b).Upgrade.Upgrade == (Object)null) { return 0; } if ((Object)(object)((HoverInfoUpgrade)a).Upgrade.Upgrade == (Object)null) { return 1; } if ((Object)(object)((HoverInfoUpgrade)b).Upgrade.Upgrade == (Object)null) { return -1; } if (order != null) { foreach (PriorityCriteria item in order) { int value = ScoreCriteria(a, item); int num = ScoreCriteria(b, item).CompareTo(value); if (num != 0) { return num; } } } return ((HoverInfoUpgrade)a).Upgrade.InstanceID.CompareTo(((HoverInfoUpgrade)b).Upgrade.InstanceID); }; } public static bool LogUniqueInstanceIds(string label, List upgradeUIs, int count) { try { HashSet hashSet = new HashSet(); int num = 0; for (int i = 0; i < count; i++) { GearUpgradeUI val = upgradeUIs[i]; if (((val != null) ? ((HoverInfoUpgrade)val).Upgrade : null) == null) { num++; } else { hashSet.Add(((HoverInfoUpgrade)val).Upgrade.InstanceID); } } if (hashSet.Count + num != count) { UpgradeFilteringPlugin.Logger.LogError((object)$"{label}: LIST CORRUPTION uniqueIds={hashSet.Count} nulls={num} count={count}"); return false; } UpgradeFilteringPlugin.Logger.LogInfo((object)$"{label}: uniqueIds={hashSet.Count} nulls={num} count={count} OK"); return true; } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("LogUniqueInstanceIds failed: " + ex.Message)); return false; } } public static void ForceLayoutVisibleOnly(GearDetailsWindow window, List upgradeUIs, int count) { if ((Object)(object)window == (Object)null || upgradeUIs == null) { return; } count = Mathf.Min(count, upgradeUIs.Count); EnsureLayoutLookups(); bool isGridView = GetIsGridView(window); RectTransform listParent = null; try { object? obj = _upgradeListParentField?.GetValue(window); listParent = (RectTransform)((obj is RectTransform) ? obj : null); } catch { } int num = 0; for (int i = 0; i < count; i++) { GearUpgradeUI val = upgradeUIs[i]; if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeSelf) { try { ((Component)val).transform.SetSiblingIndex(num); val.EnableGridView(isGridView); SetUpgradeAnchoredPosition(val, num, isGridView, listParent); num++; } catch { } } } try { Canvas.ForceUpdateCanvases(); } catch { } UpgradeFilteringPlugin.Logger.LogInfo((object)$"ForceLayoutVisibleOnly: visiblePlaced={num}, isGrid={isGridView}"); } public static int CompareByCriteria(GearUpgradeUI a, GearUpgradeUI b, PriorityCriteria criteria) { //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Invalid comparison between Unknown and I4 //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Invalid comparison between Unknown and I4 //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Invalid comparison between Unknown and I4 //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Invalid comparison between Unknown and I4 //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Invalid comparison between Unknown and I4 //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Invalid comparison between Unknown and I4 //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Invalid comparison between Unknown and I4 //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Invalid comparison between Unknown and I4 //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Invalid comparison between Unknown and I4 //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Invalid comparison between Unknown and I4 switch (criteria) { case PriorityCriteria.Favorited: return -(((HoverInfoUpgrade)a).Upgrade.Favorite ? 1 : 0).CompareTo(((HoverInfoUpgrade)b).Upgrade.Favorite ? 1 : 0); case PriorityCriteria.NotFavorited: return -((!((HoverInfoUpgrade)a).Upgrade.Favorite) ? 1 : 0).CompareTo((!((HoverInfoUpgrade)b).Upgrade.Favorite) ? 1 : 0); case PriorityCriteria.Unlocked: return -((HoverInfoUpgrade)a).Upgrade.IsUnlocked.CompareTo(((HoverInfoUpgrade)b).Upgrade.IsUnlocked); case PriorityCriteria.Locked: return -((!((HoverInfoUpgrade)a).Upgrade.IsUnlocked) ? 1 : 0).CompareTo((!((HoverInfoUpgrade)b).Upgrade.IsUnlocked) ? 1 : 0); case PriorityCriteria.Turbocharged: { bool isTurbocharged = ((HoverInfoUpgrade)a).Upgrade.IsTurbocharged; bool isTurbocharged2 = ((HoverInfoUpgrade)b).Upgrade.IsTurbocharged; return -(isTurbocharged ? 1 : 0).CompareTo(isTurbocharged2 ? 1 : 0); } case PriorityCriteria.Trashed: { if (!IsBatchScrappingPresent()) { return 0; } bool num = IsTrashMarked(((HoverInfoUpgrade)a).Upgrade); bool flag = IsTrashMarked(((HoverInfoUpgrade)b).Upgrade); return (num ? 1 : 0).CompareTo(flag ? 1 : 0); } case PriorityCriteria.NotTurbocharged: { bool num3 = !((HoverInfoUpgrade)a).Upgrade.IsTurbocharged; bool flag3 = !((HoverInfoUpgrade)b).Upgrade.IsTurbocharged; return -(num3 ? 1 : 0).CompareTo(flag3 ? 1 : 0); } case PriorityCriteria.NotTrashed: { if (!IsBatchScrappingPresent()) { return 0; } bool num2 = !IsTrashMarked(((HoverInfoUpgrade)a).Upgrade); bool flag2 = !IsTrashMarked(((HoverInfoUpgrade)b).Upgrade); return -(num2 ? 1 : 0).CompareTo(flag2 ? 1 : 0); } case PriorityCriteria.RecentlyAcquired: return -((HoverInfoUpgrade)a).Upgrade.TimeUnlocked.CompareTo(((HoverInfoUpgrade)b).Upgrade.TimeUnlocked); case PriorityCriteria.RecentlyUsed: return -((HoverInfoUpgrade)a).Upgrade.TimeUnequipped.CompareTo(((HoverInfoUpgrade)b).Upgrade.TimeUnequipped); case PriorityCriteria.InstanceName: { string text = ((HoverInfoUpgrade)a).Upgrade.Upgrade.GetInstanceName(((HoverInfoUpgrade)a).Upgrade.Seed); if (string.IsNullOrEmpty(text)) { text = ((HoverInfoUpgrade)a).Upgrade.Upgrade.Name; } string text2 = ((HoverInfoUpgrade)b).Upgrade.Upgrade.GetInstanceName(((HoverInfoUpgrade)b).Upgrade.Seed); if (string.IsNullOrEmpty(text2)) { text2 = ((HoverInfoUpgrade)b).Upgrade.Upgrade.Name; } return string.Compare(text, text2, StringComparison.Ordinal); } case PriorityCriteria.Oddity: return -(((int)((HoverInfoUpgrade)a).Upgrade.Upgrade.Rarity == 4) ? 1 : 0).CompareTo(((int)((HoverInfoUpgrade)b).Upgrade.Upgrade.Rarity == 4) ? 1 : 0); case PriorityCriteria.Exotic: return -(((int)((HoverInfoUpgrade)a).Upgrade.Upgrade.Rarity == 3) ? 1 : 0).CompareTo(((int)((HoverInfoUpgrade)b).Upgrade.Upgrade.Rarity == 3) ? 1 : 0); case PriorityCriteria.Epic: return -(((int)((HoverInfoUpgrade)a).Upgrade.Upgrade.Rarity == 2) ? 1 : 0).CompareTo(((int)((HoverInfoUpgrade)b).Upgrade.Upgrade.Rarity == 2) ? 1 : 0); case PriorityCriteria.Rare: return -(((int)((HoverInfoUpgrade)a).Upgrade.Upgrade.Rarity == 1) ? 1 : 0).CompareTo(((int)((HoverInfoUpgrade)b).Upgrade.Upgrade.Rarity == 1) ? 1 : 0); case PriorityCriteria.Standard: return -(((int)((HoverInfoUpgrade)a).Upgrade.Upgrade.Rarity == 0) ? 1 : 0).CompareTo(((int)((HoverInfoUpgrade)b).Upgrade.Upgrade.Rarity == 0) ? 1 : 0); default: return 0; } } public static List LoadPriorityOrder() { try { string json = default(string); if (PlayerOptions.TryGetConfig("SortPriority.Order", ref json)) { try { PriorityData priorityData = PriorityData.FromJson(json); List list = new List(); if (priorityData?.order != null) { foreach (int item in priorityData.order) { if (Enum.IsDefined(typeof(PriorityCriteria), item)) { list.Add((PriorityCriteria)item); } } } if (list.Count > 0) { return FilterOrderForAvailableMods(list); } } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("Failed to parse priority order from config, using defaults: " + ex.Message)); } } return FilterOrderForAvailableMods(new PriorityData().order.ConvertAll((int i) => (PriorityCriteria)i)); } catch (Exception ex2) { UpgradeFilteringPlugin.Logger.LogError((object)("Critical error loading priority order: " + ex2.Message)); return FilterOrderForAvailableMods(new PriorityData().order.ConvertAll((int i) => (PriorityCriteria)i)); } } public static void SavePriorityOrder(List order) { try { if (order != null) { priorityOrder = new List(order); string text = new PriorityData { order = order.ConvertAll((PriorityCriteria c) => (int)c) }.ToJson(); PlayerOptions.SetConfig("SortPriority.Order", text); UpgradeFilteringPlugin.Logger.LogInfo((object)$"Saved priority order ({order.Count} criteria)."); } } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogError((object)("Failed to save priority order: " + ex.Message)); } } } public static class StatFormatHandling { public static bool enableStatReformat = true; public static void Initialize() { } public static void ReformatStats(Upgrade __instance, ref string text) { if (!enableStatReformat || string.IsNullOrEmpty(text)) { return; } try { string[] array = text.Split(new string[2] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); StringBuilder stringBuilder = new StringBuilder(); string[] array2 = array; foreach (string text2 in array2) { string text3 = text2.Trim(); if (string.IsNullOrWhiteSpace(text3)) { stringBuilder.AppendLine(); continue; } string input = Regex.Replace(text3, "<[^>]*>", ""); if (Regex.IsMatch(input, "^[-+]?\\d")) { Match match = Regex.Match(input, "^([-+]?\\d+(?:\\.\\d+)?[%s]?)\\s*(.+)$"); if (match.Success) { string value = match.Groups[1].Value; string text4 = match.Groups[2].Value.Trim(); if (!string.IsNullOrEmpty(text4)) { string value2 = text4 + ": " + value + ""; stringBuilder.AppendLine(value2); continue; } } } stringBuilder.AppendLine(text2); } text = stringBuilder.ToString().TrimEnd(); } catch (Exception) { } } public static void ReformatUIText(TextMeshProUGUI textComponent, string fieldName = "text") { if (!enableStatReformat || (Object)(object)textComponent == (Object)null) { return; } string text = ((TMP_Text)textComponent).text; if (string.IsNullOrEmpty(text)) { return; } try { string[] array = text.Split(new string[2] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); StringBuilder stringBuilder = new StringBuilder(); string[] array2 = array; foreach (string text2 in array2) { string text3 = text2.Trim(); if (string.IsNullOrWhiteSpace(text3)) { stringBuilder.AppendLine(); continue; } string input = Regex.Replace(text3, "<[^>]*>", ""); if (Regex.IsMatch(input, "^[-+]?\\d")) { Match match = Regex.Match(input, "^([-+]?\\d+(?:\\.\\d+)?[%s]?)\\s*(.+)$"); if (match.Success) { string value = match.Groups[1].Value; string text4 = match.Groups[2].Value.Trim(); if (!string.IsNullOrEmpty(text4)) { string value2 = text4 + ": " + value + ""; stringBuilder.AppendLine(value2); continue; } } } stringBuilder.AppendLine(text2); } string text5 = stringBuilder.ToString().TrimEnd(); ((TMP_Text)textComponent).text = text5; ((TMP_Text)textComponent).ForceMeshUpdate(false, false); } catch (Exception) { } } } [HarmonyPatch(typeof(Upgrade), "GetStatList")] public static class StatListReformatPatch { private static void Postfix(Upgrade __instance, int seed, ref string __result) { StatFormatHandling.ReformatStats(__instance, ref __result); } } [HarmonyPatch(typeof(HoverInfoDisplay), "Activate")] public static class HoverInfoDisplayReformatPatch { private static void Postfix(HoverInfoDisplay __instance, HoverInfo info, bool resetPosition) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown if (!StatFormatHandling.enableStatReformat || (Object)(object)info == (Object)null || ((object)info).GetType().Name == "DirectiveButton") { return; } try { FieldInfo fieldInfo = AccessTools.Field(typeof(HoverInfoDisplay), "text"); if (fieldInfo != null) { StatFormatHandling.ReformatUIText((TextMeshProUGUI)fieldInfo.GetValue(__instance), "main text"); } FieldInfo fieldInfo2 = AccessTools.Field(typeof(HoverInfoDisplay), "statsText"); if (fieldInfo2 != null) { StatFormatHandling.ReformatUIText((TextMeshProUGUI)fieldInfo2.GetValue(__instance), "statsText"); } } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("HoverInfoDisplayReformatPatch: Failed: " + ex.Message)); } } } [HarmonyPatch(typeof(HoverInfoDisplay), "Refresh")] public static class HoverInfoDisplayRefreshReformatPatch { private static void Postfix(HoverInfoDisplay __instance) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(typeof(HoverInfoDisplay), "selectedInfo"); if (fieldInfo == null) { return; } object? value = fieldInfo.GetValue(__instance); HoverInfo val = (HoverInfo)((value is HoverInfo) ? value : null); if (!StatFormatHandling.enableStatReformat || (Object)(object)val == (Object)null || ((object)val).GetType().Name == "DirectiveButton") { return; } try { FieldInfo fieldInfo2 = AccessTools.Field(typeof(HoverInfoDisplay), "text"); if (fieldInfo2 != null) { StatFormatHandling.ReformatUIText((TextMeshProUGUI)fieldInfo2.GetValue(__instance), "main text (refresh)"); } FieldInfo fieldInfo3 = AccessTools.Field(typeof(HoverInfoDisplay), "statsText"); if (fieldInfo3 != null) { StatFormatHandling.ReformatUIText((TextMeshProUGUI)fieldInfo3.GetValue(__instance), "statsText (refresh)"); } } catch (Exception ex) { UpgradeFilteringPlugin.Logger.LogWarning((object)("HoverInfoDisplayRefreshReformatPatch: Failed: " + ex.Message)); } } } namespace UpgradeFiltering { public static class MyPluginInfo { public const string PLUGIN_GUID = "UpgradeFiltering"; public const string PLUGIN_NAME = "UpgradeFiltering"; public const string PLUGIN_VERSION = "1.1.2"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }