using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; 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 BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Pigeon.UI; using Sparroh.UI; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")] [assembly: AssemblyCompany("GridSolverCoru")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+43d5f77c3d56dd34f465fe381150b7afa2528d50")] [assembly: AssemblyProduct("GridSolverCoru")] [assembly: AssemblyTitle("GridSolverCoru")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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; } } } [BepInPlugin("sparroh.gridsolverplus", "GridSolverCoru", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [MycoMod(/*Could not decode attribute arguments.*/)] public class GridSolverPlugin : BaseUnityPlugin { public const string PluginGUID = "sparroh.gridsolverplus"; public const string PluginName = "GridSolverCoru"; public const string PluginVersion = "1.1.0"; internal static ManualLogSource Logger; public static GridSolverPlugin Instance; private UpgradeSolver upgradeSolver; private void Awake() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; Instance = this; upgradeSolver = new UpgradeSolver(); UpgradeSolver.Instance = upgradeSolver; Harmony val = new Harmony("sparroh.gridsolverplus"); val.PatchAll(); Logger.LogInfo((object)"GridSolverCoru v1.1.0 loaded."); } private void OnDestroy() { try { upgradeSolver?.SolverUI?.Close(); } catch (Exception ex) { Logger.LogError((object)("Failed to close UpgradeSolver UI: " + ex.Message)); } } private void Update() { upgradeSolver?.Update(); } private void OnGUI() { upgradeSolver?.OnGUI(); } } public class UpgradeSolver { public Coroutine? SolverCoroutine; internal static UpgradeSolver Instance; internal SolverUI SolverUI = new SolverUI(null, null); public void Update() { SolverUI.Update(); if (GearActionBar.IsGearMenuOpen()) { SolverUI.EnsureBarIfNeeded(); } } internal void OnUpgradeWindowOpen(IUpgradeWindow window, IUpgradable gear, MonoBehaviour mono) { SolverUI.ResetSelectionState(); SolverUI.UpgradeWindow = window; SolverUI.CurrentGear = gear; SolverUI.OnWindowOpened(); SolverUI.PatchUpgradeClick(); mono.StartCoroutine(DelayPatch()); } private IEnumerator DelayPatch() { yield return null; SolverUI.PatchUpgradeClick(); } internal void OnUpgradeWindowClosed() { SolverUI.Close(); } public void OnGUI() { SolverUI.OnGUI(); } } public static class UpgradeSolverPatches { [HarmonyPatch(typeof(GearDetailsWindow), "OnOpen")] public static class GearDetailsWindowPatch { [HarmonyPostfix] public static void Postfix(GearDetailsWindow __instance) { object? obj = _upgradablePrefabProperty?.GetValue(__instance); IUpgradable gear = (IUpgradable)((obj is IUpgradable) ? obj : null); UpgradeSolver.Instance.OnUpgradeWindowOpen((IUpgradeWindow)(object)__instance, gear, (MonoBehaviour)(object)GridSolverPlugin.Instance); } } [HarmonyPatch(typeof(GearDetailsWindow), "OnCloseCallback")] public static class GearDetailsWindowClosePatch { [HarmonyPostfix] public static void Postfix() { UpgradeSolver.Instance.OnUpgradeWindowClosed(); } } [HarmonyPatch(typeof(OuroGearWindow), "OnOpen")] public static class OuroGearWindowPatch { [HarmonyPostfix] public static void Postfix(OuroGearWindow __instance) { object? obj = _selectedGearField?.GetValue(__instance); IUpgradable gear = (IUpgradable)((obj is IUpgradable) ? obj : null); UpgradeSolver.Instance.OnUpgradeWindowOpen((IUpgradeWindow)(object)__instance, gear, (MonoBehaviour)(object)GridSolverPlugin.Instance); } } [HarmonyPatch(typeof(OuroGearWindow), "OnCloseCallback")] public static class OuroGearWindowClosePatch { [HarmonyPostfix] public static void Postfix() { UpgradeSolver.Instance.OnUpgradeWindowClosed(); } } private static readonly PropertyInfo _upgradablePrefabProperty = typeof(GearDetailsWindow).GetProperty("UpgradablePrefab", BindingFlags.Instance | BindingFlags.Public); private static readonly FieldInfo _selectedGearField = typeof(OuroGearWindow).GetField("selectedGear", BindingFlags.Instance | BindingFlags.NonPublic); } public class SolverUI { private readonly Color _defaultSecondaryColor = new Color(0.9434f, 0.9434f, 0.9434f, 1f); private readonly Color _grayedOutColor = new Color(0.9434f, 0.9434f, 0.9434f, 0.1484f); internal IUpgradeWindow? UpgradeWindow; internal IUpgradable? CurrentGear; private readonly HashSet _patchedButtons = new HashSet(); private Dictionary _selectedUpgrades = new Dictionary(); private GearUpgradeUI? _hoveredUpgrade; private bool _showSolveButton; private bool _solveButtonEnabled; private readonly HashSet _toggledThisSession = new HashSet(); private readonly InputActionMap _solverControls; private readonly InputAction _addForSolve; private bool _barRegistered; private bool _lastSolveEnabled; private bool _lastCancelEnabled; private bool _lastClearEnabled; private bool _lastClearGridEnabled; private bool _buttonStateInitialized; private static readonly PropertyInfo? _detailsGearProperty = typeof(GearDetailsWindow).GetProperty("UpgradablePrefab", BindingFlags.Instance | BindingFlags.Public); private static readonly FieldInfo? _ouroGearField = typeof(OuroGearWindow).GetField("selectedGear", BindingFlags.Instance | BindingFlags.NonPublic); private Solver? _activeSolver; private static FieldInfo? GetPrivateField(string name, Type? type) { try { while (type != null) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type = type.BaseType; } } catch { } return null; } public SolverUI(IUpgradeWindow? upgradeWindow, IUpgradable? currentGear) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) UpgradeWindow = upgradeWindow; CurrentGear = currentGear; _solverControls = new InputActionMap("SolverControls"); _addForSolve = InputActionSetupExtensions.AddAction(_solverControls, "AddForSolve", (InputActionType)0, (string)null, (string)null, (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(_addForSolve, "/n", (string)null, (string)null, (string)null); } internal void OnWindowOpened() { _showSolveButton = true; _solveButtonEnabled = false; EnsureButtons(); RefreshButtonStates(); } internal void ResetSelectionState() { ResetSelectionColors(); _selectedUpgrades.Clear(); _toggledThisSession.Clear(); _hoveredUpgrade = null; _solveButtonEnabled = false; RefreshButtonStates(); } private IUpgradable? GetGearFromWindow() { if (UpgradeWindow == null) { return null; } try { IUpgradeWindow? upgradeWindow = UpgradeWindow; GearDetailsWindow val = (GearDetailsWindow)(object)((upgradeWindow is GearDetailsWindow) ? upgradeWindow : null); if (val != null) { object? obj = _detailsGearProperty?.GetValue(val); return (IUpgradable?)((obj is IUpgradable) ? obj : null); } IUpgradeWindow? upgradeWindow2 = UpgradeWindow; OuroGearWindow val2 = (OuroGearWindow)(object)((upgradeWindow2 is OuroGearWindow) ? upgradeWindow2 : null); if (val2 != null) { object? obj2 = _ouroGearField?.GetValue(val2); return (IUpgradable?)((obj2 is IUpgradable) ? obj2 : null); } } catch { } return CurrentGear; } internal bool SyncGearWithWindow() { if (UpgradeWindow == null) { return false; } IUpgradable gearFromWindow = GetGearFromWindow(); if (gearFromWindow == null || gearFromWindow == CurrentGear) { return false; } GridSolverPlugin.Logger.LogInfo((object)"Gear changed in open window; clearing solver selection."); CurrentGear = gearFromWindow; ResetSelectionState(); PatchUpgradeClick(); return true; } private bool IsUpgradeUIInCurrentWindow(GearUpgradeUI ui) { if (UpgradeWindow == null || (Object)(object)ui == (Object)null) { return false; } IUpgradeWindow? upgradeWindow = UpgradeWindow; Component val = (Component)(object)((upgradeWindow is Component) ? upgradeWindow : null); if (val != null && (Object)(object)val != (Object)null) { return ((Component)ui).transform.IsChildOf(val.transform); } object? obj = GetPrivateField("upgradeListParent", ((object)UpgradeWindow).GetType())?.GetValue(UpgradeWindow); Transform val2 = (Transform)((obj is Transform) ? obj : null); if ((Object)(object)val2 != (Object)null) { return ((Component)ui).transform.IsChildOf(val2); } return true; } internal void EnsureBarIfNeeded() { if (GearActionBar.IsGearMenuOpen()) { _showSolveButton = true; EnsureButtons(); RefreshButtonStates(); } } private void SelectUpgrade() { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_hoveredUpgrade == (Object)null || !((HoverInfoUpgrade)_hoveredUpgrade).Upgrade.IsUnlocked || !IsUpgradeUIInCurrentWindow(_hoveredUpgrade) || !Solver.UpgradeBelongsToGear(CurrentGear, ((HoverInfoUpgrade)_hoveredUpgrade).Upgrade)) { return; } UpgradeInstance upgrade = ((HoverInfoUpgrade)_hoveredUpgrade).Upgrade; RarityData val = Global.Instance.Rarities[upgrade.Upgrade.Rarity]; FieldInfo privateField = GetPrivateField("button", typeof(GearUpgradeUI)); FieldInfo privateField2 = GetPrivateField("hoverColor", typeof(DefaultButton)); if (privateField == null) { return; } if (_selectedUpgrades.TryGetValue(upgrade.InstanceID, out var value)) { object? value2 = privateField.GetValue(value); DefaultButton val2 = (DefaultButton)((value2 is DefaultButton) ? value2 : null); if ((Object)(object)val2 != (Object)null) { val2.SetDefaultColor(val.backgroundColor); } _selectedUpgrades.Remove(upgrade.InstanceID); _solveButtonEnabled = _selectedUpgrades.Count > 0; RefreshButtonStates(); return; } if (!upgrade.CanStack) { GearUpgradeUI val3 = ((IEnumerable)_selectedUpgrades.Values).FirstOrDefault((Func)((GearUpgradeUI u) => (Object)(object)u != (Object)null && ((HoverInfoUpgrade)u).Upgrade != null && ((object)((HoverInfoUpgrade)u).Upgrade.SourceUpgradeID/*cast due to .constrained prefix*/).Equals((object?)upgrade.SourceUpgradeID))); if ((Object)(object)val3 != (Object)null) { Color backgroundColor = Global.Instance.Rarities[((HoverInfoUpgrade)val3).Upgrade.Upgrade.Rarity].backgroundColor; object? value3 = privateField.GetValue(val3); DefaultButton val4 = (DefaultButton)((value3 is DefaultButton) ? value3 : null); if ((Object)(object)val4 != (Object)null) { val4.SetDefaultColor(backgroundColor); } _selectedUpgrades.Remove(((HoverInfoUpgrade)val3).Upgrade.InstanceID); } } object? value4 = privateField.GetValue(_hoveredUpgrade); DefaultButton val5 = (DefaultButton)((value4 is DefaultButton) ? value4 : null); if ((Object)(object)val5 != (Object)null && privateField2 != null) { Color? val6 = privateField2.GetValue(val5) as Color?; if (val6.HasValue) { val5.SetDefaultColor(val6.Value); } } _selectedUpgrades[upgrade.InstanceID] = _hoveredUpgrade; _solveButtonEnabled = true; RefreshButtonStates(); } internal void RebuildSelectedUpgrades() { //IL_0147: Unknown result type (might be due to invalid IL or missing references) if (UpgradeWindow == null) { return; } FieldInfo privateField = GetPrivateField("upgradeListParent", ((object)UpgradeWindow).GetType()); FieldInfo privateField2 = GetPrivateField("button", typeof(GearUpgradeUI)); FieldInfo privateField3 = GetPrivateField("hoverColor", typeof(DefaultButton)); if (privateField == null || privateField2 == null) { return; } object? value = privateField.GetValue(UpgradeWindow); Transform val = (Transform)((value is Transform) ? value : null); if ((Object)(object)val == (Object)null) { return; } List source = (from x in ((Component)val).GetComponentsInChildren() where _selectedUpgrades.ContainsKey(((HoverInfoUpgrade)x).Upgrade.InstanceID) select x).ToList(); _selectedUpgrades = source.ToDictionary((GearUpgradeUI ui) => ((HoverInfoUpgrade)ui).Upgrade.InstanceID); foreach (KeyValuePair selectedUpgrade in _selectedUpgrades) { object? value2 = privateField2.GetValue(selectedUpgrade.Value); DefaultButton val2 = (DefaultButton)((value2 is DefaultButton) ? value2 : null); Color? val3 = privateField3?.GetValue(val2) as Color?; if ((Object)(object)val2 != (Object)null && val3.HasValue) { val2.SetDefaultColor(val3.Value); } } _solveButtonEnabled = _selectedUpgrades.Count > 0; RefreshButtonStates(); } internal void Close() { _solverControls.Disable(); _showSolveButton = false; _patchedButtons.Clear(); _selectedUpgrades.Clear(); _toggledThisSession.Clear(); _hoveredUpgrade = null; _solveButtonEnabled = false; Coroutine solverCoroutine = UpgradeSolver.Instance.SolverCoroutine; if (solverCoroutine != null) { ((MonoBehaviour)GridSolverPlugin.Instance).StopCoroutine(solverCoroutine); UpgradeSolver.Instance.SolverCoroutine = null; _activeSolver?.AbortAndRestore(); } _activeSolver = null; RefreshButtonStates(); } internal void Update() { SyncGearWithWindow(); if (Keyboard.current != null) { if (!((ButtonControl)Keyboard.current.nKey).isPressed) { if (_toggledThisSession.Count > 0) { _toggledThisSession.Clear(); } } else { GearUpgradeUI val = null; if (UIRaycaster.RaycastForComponent(ref val)) { UpgradeInstance upgrade = ((HoverInfoUpgrade)val).Upgrade; if (upgrade != null && !_toggledThisSession.Contains(upgrade)) { _hoveredUpgrade = val; SelectUpgrade(); _toggledThisSession.Add(upgrade); } } } } GearActionBar.Tick(); EnsureBarIfNeeded(); } private void EnsureButtons() { if (!_barRegistered) { GearActionBar.Register("clear_grid", "Unequip All", 10, (Action)OnClearGridClicked, (UIButtonStyle)2); GearActionBar.Register("solve", "Solve", 20, (Action)OnSolveClicked, (UIButtonStyle)1); GearActionBar.Register("cancel_solve", "Cancel", 30, (Action)OnCancelClicked, (UIButtonStyle)2); GearActionBar.Register("clear_selection", "Deselect", 40, (Action)OnClearClicked, (UIButtonStyle)0); GearActionBar.SetSlotVisible("clear_grid", true); GearActionBar.SetSlotVisible("solve", true); GearActionBar.SetSlotVisible("cancel_solve", true); GearActionBar.SetSlotVisible("clear_selection", true); _barRegistered = true; } } private void RefreshButtonStates() { if (_barRegistered) { bool flag = UpgradeSolver.Instance != null && UpgradeSolver.Instance.SolverCoroutine != null; bool flag2 = _solveButtonEnabled && !flag; bool flag3 = flag; bool flag4 = _selectedUpgrades.Count > 0 && !flag; bool flag5 = _showSolveButton && !flag; if (!_buttonStateInitialized || flag2 != _lastSolveEnabled || flag3 != _lastCancelEnabled || flag4 != _lastClearEnabled || flag5 != _lastClearGridEnabled) { _buttonStateInitialized = true; _lastSolveEnabled = flag2; _lastCancelEnabled = flag3; _lastClearEnabled = flag4; _lastClearGridEnabled = flag5; GearActionBar.SetInteractable("solve", flag2); GearActionBar.SetInteractable("cancel_solve", flag3); GearActionBar.SetInteractable("clear_selection", flag4); GearActionBar.SetInteractable("clear_grid", flag5); } } } private void OnSolveClicked() { if (UpgradeWindow == null || !_solveButtonEnabled || UpgradeSolver.Instance.SolverCoroutine != null || SyncGearWithWindow()) { return; } if (CurrentGear == null) { UIDialog.Alert("Solve Error", "Could not determine which gear this window is editing.", (Action)null, "OK"); return; } List list = (from kv in _selectedUpgrades where (Object)(object)kv.Value == (Object)null || !Solver.UpgradeBelongsToGear(CurrentGear, ((HoverInfoUpgrade)kv.Value).Upgrade) select kv.Key).ToList(); foreach (int item in list) { GridSolverPlugin.Logger.LogWarning((object)$"Dropping stale/foreign selected upgrade (InstanceID {item}) before solve."); _selectedUpgrades.Remove(item); } if (_selectedUpgrades.Count == 0) { _solveButtonEnabled = false; RefreshButtonStates(); return; } foreach (GearUpgradeUI value in _selectedUpgrades.Values) { GridSolverPlugin.Logger.LogInfo((object)("\t • " + FormatUpgrade(value))); } List upgrades = (from u in _selectedUpgrades select ((HoverInfoUpgrade)u.Value).Upgrade into u orderby Solver.GetPlacementPriority(u.Upgrade) descending, u.GetPattern(false).GetCellCount() descending select u).ToList(); Solver solver = new Solver(UpgradeWindow, CurrentGear, upgrades); _activeSolver = solver; solver.TrySolve(delegate(bool success) { GridSolverPlugin.Logger.LogInfo((object)(success ? "Found a solution" : "No solution")); UpgradeSolver.Instance.SolverCoroutine = null; _activeSolver = null; if (success) { ResetSelectionColors(); _selectedUpgrades.Clear(); _solveButtonEnabled = false; } else { UIDialog.Alert("Solve Failed", solver.FailureMessage ?? "No valid arrangement found for the selected upgrades.", (Action)null, "OK"); RebuildSelectedUpgrades(); ((MonoBehaviour)GridSolverPlugin.Instance).StartCoroutine(RebuildSelectionNextFrame()); } RefreshButtonStates(); }); RefreshButtonStates(); } private IEnumerator RebuildSelectionNextFrame() { yield return null; RebuildSelectedUpgrades(); } private void OnCancelClicked() { if (UpgradeSolver.Instance.SolverCoroutine != null) { ((MonoBehaviour)GridSolverPlugin.Instance).StopCoroutine(UpgradeSolver.Instance.SolverCoroutine); UpgradeSolver.Instance.SolverCoroutine = null; _activeSolver?.AbortAndRestore(); _activeSolver = null; RebuildSelectedUpgrades(); ((MonoBehaviour)GridSolverPlugin.Instance).StartCoroutine(RebuildSelectionNextFrame()); RefreshButtonStates(); } } private void OnClearClicked() { ResetSelectionColors(); _selectedUpgrades.Clear(); _solveButtonEnabled = false; RefreshButtonStates(); } private void OnClearGridClicked() { if (UpgradeWindow == null || UpgradeSolver.Instance.SolverCoroutine != null) { return; } SyncGearWithWindow(); if (CurrentGear == null) { return; } object? obj = GetPrivateField("equipSlots", ((object)UpgradeWindow).GetType())?.GetValue(UpgradeWindow); ModuleEquipSlots val = (ModuleEquipSlots)((obj is ModuleEquipSlots) ? obj : null); if ((Object)(object)val == (Object)null) { GridSolverPlugin.Logger.LogWarning((object)"Unequip All: could not access the window's equip slots."); return; } List list = (from inst in Solver.EnumerateInstances(CurrentGear) where inst.IsEquipped(CurrentGear) orderby Solver.GetPlacementPriority(inst) select inst).ToList(); int num = 0; foreach (UpgradeInstance item in list) { if (val.Unequip(CurrentGear, item)) { num++; } } GridSolverPlugin.Logger.LogInfo((object)$"Unequip All: removed {num} mod(s) from the current gear."); } private void ResetSelectionColors() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) FieldInfo privateField = GetPrivateField("button", typeof(GearUpgradeUI)); foreach (GearUpgradeUI value in _selectedUpgrades.Values) { try { if (!((Object)(object)value == (Object)null)) { RarityData val = Global.Instance.Rarities[((HoverInfoUpgrade)value).Upgrade.Upgrade.Rarity]; object? obj = privateField?.GetValue(value); DefaultButton val2 = (DefaultButton)((obj is DefaultButton) ? obj : null); if ((Object)(object)val2 != (Object)null) { val2.SetDefaultColor(val.backgroundColor); } } } catch { } } } private static string FormatUpgrade(GearUpgradeUI upgrade) { UpgradeInstance upgrade2 = ((HoverInfoUpgrade)upgrade).Upgrade; return $"[{upgrade2.Upgrade.RarityName}] {upgrade2.Upgrade.Name} ({upgrade2.InstanceID})"; } internal void PatchUpgradeClick() { //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown if (UpgradeWindow == null) { return; } _solverControls.Enable(); FieldInfo privateField = GetPrivateField("upgradeListParent", ((object)UpgradeWindow).GetType()); FieldInfo privateField2 = GetPrivateField("button", typeof(GearUpgradeUI)); if (privateField == null || privateField2 == null) { return; } object? value = privateField.GetValue(UpgradeWindow); Transform val = (Transform)((value is Transform) ? value : null); if ((Object)(object)val == (Object)null) { return; } List list = (from x in ((Component)val).GetComponentsInChildren() where ((Component)x).gameObject.activeSelf select x).ToList(); foreach (GearUpgradeUI upgradeUI in list) { object? value2 = privateField2.GetValue(upgradeUI); DefaultButton val2 = (DefaultButton)((value2 is DefaultButton) ? value2 : null); if (val2 != null && _patchedButtons.Add(val2)) { ((Button)val2).OnHoverExit.AddListener((UnityAction)delegate { _hoveredUpgrade = null; }); ((Button)val2).OnHoverEnter.AddListener((UnityAction)delegate { _hoveredUpgrade = upgradeUI; }); } } } public void OnGUI() { } } public static class HexMapUtils { private static readonly FieldInfo _hexMapWidthField = typeof(HexMap).GetField("width", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo _hexMapHeightField = typeof(HexMap).GetField("height", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo _hexMapNodesField = typeof(HexMap).GetField("nodes", BindingFlags.Instance | BindingFlags.NonPublic); public static HexMap CloneHexMap(HexMap original) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (original == null) { return null; } int num = (int)_hexMapWidthField.GetValue(original); int num2 = (int)_hexMapHeightField.GetValue(original); HexMap val = new HexMap(num, num2); for (int i = 0; i < num2; i++) { for (int j = 0; j < num; j++) { val[j, i] = original[j, i]; } } return val; } public static HexMap CanonicalizeHexMap(HexMap map) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) if (map == null) { return null; } int num = (int)_hexMapWidthField.GetValue(map); int num2 = (int)_hexMapHeightField.GetValue(map); int num3 = int.MaxValue; int num4 = int.MaxValue; bool flag = false; for (int i = 0; i < num2; i++) { for (int j = 0; j < num; j++) { if (map[j, i].enabled) { if (j < num3) { num3 = j; } if (i < num4) { num4 = i; } flag = true; } } } if (!flag) { return CloneHexMap(map); } int num5 = num - num3; int num6 = num2 - num4; HexMap val = new HexMap(num5, num6); for (int k = 0; k < num2; k++) { for (int l = 0; l < num; l++) { if (map[l, k].enabled) { int num7 = l - num3; int num8 = k - num4; val[num7, num8] = map[l, k]; } } } return val; } public static bool HexMapsEqual(HexMap a, HexMap b) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00e1: Unknown result type (might be due to invalid IL or missing references) if (a == null && b == null) { return true; } if (a == null || b == null) { return false; } int num = (int)_hexMapWidthField.GetValue(a); int num2 = (int)_hexMapHeightField.GetValue(a); int num3 = (int)_hexMapWidthField.GetValue(b); int num4 = (int)_hexMapHeightField.GetValue(b); if (num != num3 || num2 != num4) { return false; } for (int i = 0; i < num2; i++) { for (int j = 0; j < num; j++) { Node val = a[j, i]; Node val2 = b[j, i]; if (val.enabled != val2.enabled || (val.enabled && val.connections != val2.connections)) { return false; } } } return true; } } public class Offset(int offsetX, int offsetY) { public readonly int OffsetX = offsetX; public readonly int OffsetY = offsetY; } public class Solver { private struct Placement { public ulong[] Mask; public int OffsetX; public int OffsetY; public byte Rotation; } private static readonly HashSet GridExpandingUpgradeNames = new HashSet { "Boundary Incursion", "Edge Fault", "Multiversal Thievery" }; private static readonly HashSet MajorGridExpanderNames = new HashSet { "Multiversal Thievery" }; private static readonly HashSet CellCountModifyingUpgradeNames = new HashSet { "Handheld Pocket Universe" }; private static readonly FieldInfo _modifiedMapWidthField = GetPrivateField("width", typeof(HexMap)); private static readonly FieldInfo _modifiedMapHeightField = GetPrivateField("height", typeof(HexMap)); private static readonly FieldInfo _hexMapWidthField = GetPrivateField("width", typeof(HexMap)); private static readonly FieldInfo _hexMapHeightField = GetPrivateField("height", typeof(HexMap)); private readonly IUpgradeWindow _upgradeWindow; private readonly List _upgrades; private readonly IUpgradable _gear; private readonly ModuleEquipSlots _equipSlots; private readonly HexMap _hexMap; private List _specials; private List _normals; private List _expanders; private UpgradeInstance _hpu; private readonly Dictionary, Offset> _offsetCache = new Dictionary, Offset>(); private readonly Dictionary> _uniqueRotationsCache = new Dictionary>(); private readonly List> _previousLayout = new List>(); private bool _foundSolution; private const long NormalSolveNodeCap = 6000000L; private const long NormalSolveTimeCapMs = 4000L; private long _normalNodes; private Stopwatch _normalTimer; public string? FailureMessage { get; private set; } private static bool HasName(Upgrade u) { return ((u != null) ? u.Name : null) != null; } private static bool HasName(UpgradeInstance i) { object obj; if (i == null) { obj = null; } else { Upgrade upgrade = i.Upgrade; obj = ((upgrade != null) ? upgrade.Name : null); } return obj != null; } internal static bool IsMajorGridExpander(Upgrade upgrade) { return HasName(upgrade) && MajorGridExpanderNames.Contains(upgrade.Name); } internal static bool IsMajorGridExpander(UpgradeInstance inst) { return HasName(inst) && MajorGridExpanderNames.Contains(inst.Upgrade.Name); } internal static bool IsGridExpander(Upgrade upgrade) { return HasName(upgrade) && GridExpandingUpgradeNames.Contains(upgrade.Name); } internal static bool IsGridExpander(UpgradeInstance inst) { return HasName(inst) && GridExpandingUpgradeNames.Contains(inst.Upgrade.Name); } internal static bool IsCellCountModifier(Upgrade upgrade) { return HasName(upgrade) && CellCountModifyingUpgradeNames.Contains(upgrade.Name); } internal static bool IsCellCountModifier(UpgradeInstance inst) { return HasName(inst) && CellCountModifyingUpgradeNames.Contains(inst.Upgrade.Name); } private static int GetEffectiveCellCount(UpgradeInstance upgrade, bool hasHPU) { int cellCount = upgrade.GetPattern(false).GetCellCount(); if (!hasHPU) { return cellCount; } if (IsCellCountModifier(upgrade)) { return cellCount; } return upgrade.Upgrade.RarityName switch { "Standard" => 1, "Rare" => 2, "Epic" => 3, "Exotic" => 4, _ => cellCount, }; } internal static int GetPlacementPriority(UpgradeInstance inst) { if (IsMajorGridExpander(inst)) { return 3; } if (IsGridExpander(inst)) { return 2; } if (IsCellCountModifier(inst)) { return 1; } return 0; } internal static int GetPlacementPriority(Upgrade upgrade) { if (IsMajorGridExpander(upgrade)) { return 3; } if (IsGridExpander(upgrade)) { return 2; } if (IsCellCountModifier(upgrade)) { return 1; } return 0; } private static FieldInfo? GetPrivateField(string name, Type type) { try { return type.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic); } catch { return null; } } private static int MaxRotationsFor(UpgradeInstance upgrade) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) try { return (!PlayerData.Instance.CanRotateUpgrade(upgrade.Upgrade.Rarity)) ? 1 : 6; } catch { return (!PlayerData.Instance.canRotateUpgrades) ? 1 : 6; } } internal static bool UpgradeBelongsToGear(IUpgradable gear, UpgradeInstance instance) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 if (gear == null || instance == null) { return false; } try { object gear2 = instance.Gear; if (gear2 != null) { if (gear2 == gear) { return true; } if ((int)gear.GearType == 5 && gear2 == Global.Instance) { return true; } } } catch { } try { foreach (UpgradeInstance item in EnumerateInstances(gear)) { if (item == instance || item.InstanceID == instance.InstanceID) { return true; } } return false; } catch { return true; } } public Solver(IUpgradeWindow upgradeWindow, IUpgradable gear, List upgrades) { _upgradeWindow = upgradeWindow; _gear = gear; _upgrades = upgrades.Where(delegate(UpgradeInstance u) { bool flag = UpgradeBelongsToGear(gear, u); if (!flag) { ManualLogSource logger = GridSolverPlugin.Logger; object obj2; if (u == null) { obj2 = null; } else { Upgrade upgrade = u.Upgrade; obj2 = ((upgrade != null) ? upgrade.Name : null); } logger.LogWarning((object)("Solver rejected '" + (string?)obj2 + "' — it does not belong to the target gear.")); } return flag; }).ToList(); ref ModuleEquipSlots equipSlots = ref _equipSlots; object? obj = GetPrivateField("equipSlots", ((object)upgradeWindow).GetType())?.GetValue(upgradeWindow); equipSlots = (ModuleEquipSlots)((obj is ModuleEquipSlots) ? obj : null); FieldInfo privateField = GetPrivateField("hexMap", typeof(ModuleEquipSlots)); if ((Object)(object)_equipSlots != (Object)null && privateField != null) { ref HexMap hexMap = ref _hexMap; object? value = privateField.GetValue(_equipSlots); hexMap = (HexMap)((value is HexMap) ? value : null); } Dictionary> dictionary = new Dictionary>(); foreach (UpgradeInstance upgrade2 in _upgrades) { HexMap pattern = upgrade2.GetPattern(false); string hexMapKey = GetHexMapKey(HexMapUtils.CanonicalizeHexMap(pattern)); if (!dictionary.ContainsKey(hexMapKey)) { dictionary[hexMapKey] = new List(); } dictionary[hexMapKey].Add(upgrade2); _uniqueRotationsCache[upgrade2] = GetUniqueRotations(upgrade2); } _expanders = (from u in _upgrades where IsGridExpander(u) orderby GetPlacementPriority(u) descending select u).ToList(); List list = _upgrades.Where((UpgradeInstance u) => IsCellCountModifier(u)).ToList(); _normals = _upgrades.Where((UpgradeInstance u) => GetPlacementPriority(u) == 0).ToList(); if (list.Count == 1) { _hpu = list[0]; _specials = _expanders; return; } _hpu = null; _specials = (from u in _expanders.Concat(list) orderby GetPlacementPriority(u) descending select u).ToList(); } private List GetUniqueRotations(UpgradeInstance upgrade) { HexMap pattern = upgrade.GetPattern(false); Dictionary dictionary = new Dictionary(); List list = new List(); int num = MaxRotationsFor(upgrade); for (int i = 0; i < num; i++) { HexMap modifiedMap = pattern.GetModifiedMap(i, (HexMap)null); HexMap map = HexMapUtils.CanonicalizeHexMap(modifiedMap); string hexMapKey = GetHexMapKey(map); if (!dictionary.ContainsKey(hexMapKey)) { dictionary[hexMapKey] = i; list.Add(i); } } return list; } private string GetHexMapKey(HexMap map) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected I4, but got Unknown if (map == null) { return ""; } int num = (int)_hexMapWidthField.GetValue(map); int num2 = (int)_hexMapHeightField.GetValue(map); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < num2; i++) { for (int j = 0; j < num; j++) { Node val = map[j, i]; stringBuilder.Append(val.enabled ? '1' : '0'); stringBuilder.Append((int)val.connections); stringBuilder.Append(','); } stringBuilder.Append(';'); } return stringBuilder.ToString(); } private Offset GetOffsetsCached(UpgradeInstance upgrade, int rotation, UpgradeEquipCell cell) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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) Tuple key = new Tuple(upgrade, rotation); if (_offsetCache.TryGetValue(key, out var value)) { return new Offset(cell.X + value.offsetX, cell.Y + value.offsetY); } HexMap pattern = upgrade.GetPattern(false); HexMap modifiedMap = pattern.GetModifiedMap(rotation, (HexMap)null); int num = ((_modifiedMapWidthField != null) ? ((int)_modifiedMapWidthField.GetValue(modifiedMap)) : 8); int num2 = num / 2; int num3 = 0; int num4 = 0; for (int i = 0; i < ((_modifiedMapHeightField != null) ? ((int)_modifiedMapHeightField.GetValue(modifiedMap)) : 8); i++) { Node val = modifiedMap[num2, i]; if (val.enabled) { num3 += i; num4++; } } int num5 = ((num4 > 0) ? (num3 / num4) : 0); int num6 = -num5; if (num2 % 2 == 1) { num6--; } value = new Offset(-num2, num6); _offsetCache[key] = value; return new Offset(cell.X + value.offsetX, cell.Y + value.offsetY); } internal static IEnumerable EnumerateInstances(IUpgradable gear) { List merged = new List(PlayerData.GetAllUpgrades(gear, true)); if ((int)gear.GearType == 5) { IUpgradable playerUpgradesPrefab = (IUpgradable)(object)Global.Instance; merged.AddRange(PlayerData.GetAllUpgrades(playerUpgradesPrefab, true)); } foreach (UpgradeInfo upgradeInfo in merged) { if (upgradeInfo?.Instances == null) { continue; } foreach (UpgradeInstance item in upgradeInfo.Instances.OfType().ToList()) { yield return item; } } } private void SnapshotEquipped() { _previousLayout.Clear(); sbyte item = default(sbyte); sbyte item2 = default(sbyte); foreach (UpgradeInstance upgrade in _upgrades) { if (upgrade.IsEquipped(_gear) && upgrade.GetPosition(_gear, ref item, ref item2)) { _previousLayout.Add(new Tuple(upgrade, item, item2, upgrade.GetRotation(_gear))); } } _previousLayout.Sort((Tuple a, Tuple b) => GetPlacementPriority(b.Item1).CompareTo(GetPlacementPriority(a.Item1))); } private void RestoreEquipped() { if ((Object)(object)_equipSlots == (Object)null) { return; } foreach (Tuple item in _previousLayout) { if (!_equipSlots.EquipModule(_gear, item.Item1, (int)item.Item2, (int)item.Item3, item.Item4, true, false)) { GridSolverPlugin.Logger.LogWarning((object)("Could not restore '" + item.Item1.Upgrade.Name + "' to its previous slot.")); } } } private void ClearSlots() { if ((Object)(object)_equipSlots == (Object)null) { return; } foreach (UpgradeInstance item in _upgrades.OrderBy((UpgradeInstance i) => GetPlacementPriority(i))) { _equipSlots.Unequip(_gear, item); } } private int GridWidth() { return (_hexMap != null && _hexMapWidthField != null) ? ((int)_hexMapWidthField.GetValue(_hexMap)) : 8; } private int GridHeight() { return (_hexMap != null && _hexMapHeightField != null) ? ((int)_hexMapHeightField.GetValue(_hexMap)) : 8; } private IEnumerator SolveDfs(int index) { if ((Object)(object)_equipSlots == (Object)null) { _foundSolution = false; yield break; } if (index >= _specials.Count) { _foundSolution = SolveNormals(); yield break; } UpgradeInstance upgrade = _specials[index]; List uniqueRotations = _uniqueRotationsCache[upgrade]; int h = GridHeight(); int w = GridWidth(); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { foreach (int rotation in uniqueRotations) { UpgradeEquipCell cell = null; try { cell = _equipSlots.GetCell(x, y); } catch { } if (cell == null || ((HoverInfoUpgrade)cell).Upgrade != null) { continue; } Offset offset = GetOffsetsCached(upgrade, rotation, cell); if (_equipSlots.EquipModule(_gear, upgrade, offset.offsetX, offset.offsetY, (byte)rotation, true, false)) { yield return SolveDfs(index + 1); if (_foundSolution) { yield break; } _equipSlots.Unequip(_gear, upgrade); } } } } } private static int WordCount(int cellCount) { return (cellCount + 63) / 64; } private static int PopCount(ulong[] a) { int num = 0; for (int i = 0; i < a.Length; i++) { ulong num2 = a[i]; while (num2 != 0) { num2 &= num2 - 1; num++; } } return num; } private static bool Intersects(ulong[] a, ulong[] b) { for (int i = 0; i < a.Length; i++) { if ((a[i] & b[i]) != 0) { return true; } } return false; } private List ComputeCells(HexMap modMap, int offsetX, int offsetY, int W, int H) { int num = ((_modifiedMapWidthField != null) ? ((int)_modifiedMapWidthField.GetValue(modMap)) : 8); int num2 = ((_modifiedMapHeightField != null) ? ((int)_modifiedMapHeightField.GetValue(modMap)) : 8); int num3 = offsetX + num / 2; List list = new List(8); for (int i = 0; i < num2; i++) { for (int j = 0; j < num; j++) { bool enabled; try { enabled = modMap[j, i].enabled; } catch { continue; } if (enabled) { int num4 = j + offsetX; int num5 = i + offsetY; if (j % 2 == 1 && num4 % 2 == 0) { num5++; } if (num3 % 2 == 1) { num5++; } if (num3 % 2 == 1 && num / 2 % 2 == 0) { num5--; } if (num4 < 0 || num5 < 0 || num4 >= W || num5 >= H) { return null; } list.Add(num5 * W + num4); } } } return list; } private List EnumeratePlacements(UpgradeInstance upgrade, int W, int H, int words, ulong[] baseOccupied) { List list = new List(); HashSet hashSet = new HashSet(); List uniqueRotations = GetUniqueRotations(upgrade); HexMap pattern = upgrade.GetPattern(false); for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { foreach (int item2 in uniqueRotations) { UpgradeEquipCell val = null; try { val = _equipSlots.GetCell(j, i); } catch { } if (val == null) { continue; } Offset offsetsCached = GetOffsetsCached(upgrade, item2, val); HexMap modifiedMap = pattern.GetModifiedMap(item2, (HexMap)null); List list2 = ComputeCells(modifiedMap, offsetsCached.offsetX, offsetsCached.offsetY, W, H); if (list2 == null) { continue; } ulong[] array = new ulong[words]; foreach (int item3 in list2) { array[item3 >> 6] |= (ulong)(1L << item3); } if (!Intersects(array, baseOccupied)) { string item = MaskKey(array); if (hashSet.Add(item)) { list.Add(new Placement { Mask = array, OffsetX = offsetsCached.offsetX, OffsetY = offsetsCached.offsetY, Rotation = (byte)item2 }); } } } } } return list; } private static string MaskKey(ulong[] mask) { StringBuilder stringBuilder = new StringBuilder(mask.Length * 17); for (int i = 0; i < mask.Length; i++) { stringBuilder.Append(mask[i].ToString("x16")); stringBuilder.Append(','); } return stringBuilder.ToString(); } private bool SolveNormals() { if ((Object)(object)_equipSlots == (Object)null) { return false; } List list = new List(); if (_hpu != null) { list.Add(_hpu); } list.AddRange(_normals); if (list.Count == 0) { return true; } int num = GridWidth(); int num2 = GridHeight(); int num3 = num * num2; if (num3 <= 0) { return false; } int num4 = WordCount(num3); ulong[] array = new ulong[num4]; for (int i = 0; i < num2; i++) { for (int j = 0; j < num; j++) { UpgradeEquipCell val = null; try { val = _equipSlots.GetCell(j, i); } catch { } if ((Object)(object)val != (Object)null && ((HoverInfoUpgrade)val).Upgrade != null) { int num5 = i * num + j; array[num5 >> 6] |= (ulong)(1L << num5); } } } int count = list.Count; List[] array2 = new List[count]; int[] array3 = new int[count]; string[] array4 = new string[count]; int num6 = 0; if (_hpu != null) { array2[0] = EnumeratePlacements(_hpu, num, num2, num4, array); if (array2[0].Count == 0) { return false; } array3[0] = PopCount(array2[0][0].Mask); array4[0] = PieceSignature(array2[0]); num6 = 1; } UpgradeInstance parked = null; if (_hpu != null && !ParkHpu(num, num2, out parked)) { return false; } try { for (int k = num6; k < count; k++) { array2[k] = EnumeratePlacements(list[k], num, num2, num4, array); if (array2[k].Count == 0) { return false; } array3[k] = PopCount(array2[k][0].Mask); array4[k] = PieceSignature(array2[k]); } } finally { if (parked != null) { _equipSlots.Unequip(_gear, parked); } } ulong[][] neighbors = BuildNeighbors(num, num2, num4); int[] array5 = new int[count]; for (int l = 0; l < count; l++) { array5[l] = -1; } List list2 = new List(count); for (int m = 0; m < count; m++) { list2.Add(m); } _normalNodes = 0L; _normalTimer = Stopwatch.StartNew(); if (!NormalDfs(list2, array, array2, array3, array4, neighbors, num3, num4, array5)) { return false; } List list3 = new List(); for (int n = 0; n < count; n++) { Placement placement = array2[n][array5[n]]; if (!_equipSlots.EquipModule(_gear, list[n], placement.OffsetX, placement.OffsetY, placement.Rotation, true, false)) { ManualLogSource logger = GridSolverPlugin.Logger; Upgrade upgrade = list[n].Upgrade; logger.LogWarning((object)("Bitmask solution failed to apply '" + ((upgrade != null) ? upgrade.Name : null) + "'; rolling back.")); foreach (UpgradeInstance item in list3) { _equipSlots.Unequip(_gear, item); } return false; } list3.Add(list[n]); } return true; } private bool ParkHpu(int W, int H, out UpgradeInstance parked) { parked = null; List uniqueRotations = GetUniqueRotations(_hpu); for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { UpgradeEquipCell val = null; try { val = _equipSlots.GetCell(j, i); } catch { } if (val == null || ((HoverInfoUpgrade)val).Upgrade != null) { continue; } foreach (int item in uniqueRotations) { Offset offsetsCached = GetOffsetsCached(_hpu, item, val); if (_equipSlots.EquipModule(_gear, _hpu, offsetsCached.offsetX, offsetsCached.offsetY, (byte)item, true, false)) { parked = _hpu; return true; } } } } return false; } private static string PieceSignature(List placements) { List list = new List(placements.Count); foreach (Placement placement in placements) { list.Add(MaskKey(placement.Mask)); } list.Sort(StringComparer.Ordinal); return string.Join("|", list); } private static ulong[][] BuildNeighbors(int W, int H, int words) { int num = W * H; ulong[][] array = new ulong[num][]; for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { ulong[] array2 = new ulong[words]; (int, int)[] array3 = ((j % 2 != 0) ? new(int, int)[6] { (0, -1), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0) } : new(int, int)[6] { (0, -1), (1, -1), (1, 0), (0, 1), (-1, 0), (-1, -1) }); (int, int)[] array4 = array3; for (int k = 0; k < array4.Length; k++) { (int, int) tuple = array4[k]; int item = tuple.Item1; int item2 = tuple.Item2; int num2 = j + item; int num3 = i + item2; if (num2 >= 0 && num2 < W && num3 >= 0 && num3 < H) { int num4 = num3 * W + num2; array2[num4 >> 6] |= (ulong)(1L << num4); } } array[i * W + j] = array2; } } return array; } private bool NormalDfs(List remaining, ulong[] occupied, List[] placements, int[] sizes, string[] signatures, ulong[][] neighbors, int N, int words, int[] chosen) { if (++_normalNodes > 6000000 || _normalTimer.ElapsedMilliseconds > 4000) { return false; } if (remaining.Count == 0) { return true; } int num = N - PopCount(occupied); int num2 = 0; int num3 = int.MaxValue; for (int i = 0; i < remaining.Count; i++) { int num4 = sizes[remaining[i]]; num2 += num4; if (num4 < num3) { num3 = num4; } } if (num < num2) { return false; } if (num3 > 1 && UsableCells(occupied, neighbors, N, words, num3) < num2) { return false; } if (num == num2) { int num5 = FirstEmpty(occupied, N); if (num5 < 0) { return false; } ulong num6 = (ulong)(1L << num5); int num7 = num5 >> 6; HashSet hashSet = new HashSet(); for (int j = 0; j < remaining.Count; j++) { int num8 = remaining[j]; if (!hashSet.Add(signatures[num8])) { continue; } List list = placements[num8]; for (int k = 0; k < list.Count; k++) { ulong[] mask = list[k].Mask; if ((mask[num7] & num6) != 0 && !Intersects(mask, occupied)) { Or(occupied, mask); chosen[num8] = k; remaining.RemoveAt(j); if (NormalDfs(remaining, occupied, placements, sizes, signatures, neighbors, N, words, chosen)) { return true; } remaining.Insert(j, num8); chosen[num8] = -1; AndNot(occupied, mask); if (_normalNodes > 6000000 || _normalTimer.ElapsedMilliseconds > 4000) { return false; } } } } return false; } int index = -1; int num9 = int.MaxValue; for (int l = 0; l < remaining.Count; l++) { int num10 = remaining[l]; int num11 = 0; List list2 = placements[num10]; for (int m = 0; m < list2.Count; m++) { if (!Intersects(list2[m].Mask, occupied)) { num11++; } } if (num11 == 0) { return false; } if (num11 < num9) { num9 = num11; index = l; if (num11 == 1) { break; } } } int num12 = remaining[index]; remaining.RemoveAt(index); List list3 = placements[num12]; for (int n = 0; n < list3.Count; n++) { ulong[] mask2 = list3[n].Mask; if (!Intersects(mask2, occupied)) { Or(occupied, mask2); chosen[num12] = n; if (NormalDfs(remaining, occupied, placements, sizes, signatures, neighbors, N, words, chosen)) { return true; } chosen[num12] = -1; AndNot(occupied, mask2); if (_normalNodes > 6000000 || _normalTimer.ElapsedMilliseconds > 4000) { remaining.Insert(index, num12); return false; } } } remaining.Insert(index, num12); return false; } private static void Or(ulong[] target, ulong[] mask) { for (int i = 0; i < target.Length; i++) { target[i] |= mask[i]; } } private static void AndNot(ulong[] target, ulong[] mask) { for (int i = 0; i < target.Length; i++) { target[i] &= ~mask[i]; } } private static int TrailingZeros(ulong v) { if (v == 0) { return 64; } int num = 0; while ((v & 1) == 0) { v >>= 1; num++; } return num; } private static int FirstEmpty(ulong[] occupied, int N) { for (int i = 0; i < N; i++) { if ((occupied[i >> 6] & (ulong)(1L << i)) == 0) { return i; } } return -1; } private static int UsableCells(ulong[] occupied, ulong[][] neighbors, int N, int words, int minSize) { ulong[] array = new ulong[words]; int num = 0; for (int i = 0; i < N; i++) { int num2 = i >> 6; ulong num3 = (ulong)(1L << i); if ((occupied[num2] & num3) != 0 || (array[num2] & num3) != 0) { continue; } int num4 = 0; List list = new List { i }; array[num2] |= num3; while (list.Count > 0) { int num5 = list[list.Count - 1]; list.RemoveAt(list.Count - 1); num4++; ulong[] array2 = neighbors[num5]; for (int j = 0; j < words; j++) { ulong num6 = array2[j] & ~occupied[j] & ~array[j]; while (num6 != 0) { ulong num7 = num6 & (~num6 + 1); int num8 = TrailingZeros(num7); num6 &= num6 - 1; int item = (j << 6) + num8; array[j] |= num7; list.Add(item); } } } if (num4 >= minSize) { num += num4; } } return num; } private IEnumerator SolveAndNotify(Action onComplete) { yield return SolveDfs(0); if (!_foundSolution) { FailureMessage = "No valid arrangement found for the selected upgrades. Your previous layout has been restored — deselect one or more upgrades and try again."; RestoreEquipped(); } onComplete(_foundSolution); } public void TrySolve(Action onComplete) { _foundSolution = false; FailureMessage = null; if (_upgrades.Count == 0) { FailureMessage = "None of the selected upgrades belong to this gear."; onComplete(obj: false); return; } SnapshotEquipped(); ClearSlots(); if (!CanFitAll()) { FailureMessage = "The selected upgrades cannot fit in the available space. Your previous layout has been restored."; RestoreEquipped(); onComplete(obj: false); } else { UpgradeSolver.Instance.SolverCoroutine = ((MonoBehaviour)GridSolverPlugin.Instance).StartCoroutine(SolveAndNotify(onComplete)); } } public void AbortAndRestore() { if ((Object)(object)_equipSlots == (Object)null) { return; } foreach (UpgradeInstance item in _upgrades.OrderBy((UpgradeInstance u) => GetPlacementPriority(u))) { _equipSlots.Unequip(_gear, item); } RestoreEquipped(); } public bool CanFitAll() { if (_hexMap == null) { return true; } bool hasHPU = _upgrades.Any((UpgradeInstance u) => IsCellCountModifier(u)); List list = _upgrades.Where((UpgradeInstance u) => IsGridExpander(u)).ToList(); List list2 = _upgrades.Where((UpgradeInstance u) => IsCellCountModifier(u)).ToList(); List source = _upgrades.Where((UpgradeInstance u) => !IsGridExpander(u) && !IsCellCountModifier(u)).ToList(); foreach (UpgradeInstance item in list) { bool flag = false; int num = ((_hexMapHeightField != null) ? ((int)_hexMapHeightField.GetValue(_hexMap)) : 8); int num2 = ((_hexMapWidthField != null) ? ((int)_hexMapWidthField.GetValue(_hexMap)) : 8); List value; List list3 = (_uniqueRotationsCache.TryGetValue(item, out value) ? value : new List { 0 }); for (int num3 = 0; num3 < num; num3++) { if (flag) { break; } for (int num4 = 0; num4 < num2; num4++) { if (flag) { break; } foreach (int item2 in list3) { UpgradeEquipCell val = null; try { val = _equipSlots.GetCell(num4, num3); } catch { } if (!((Object)(object)val == (Object)null) && ((HoverInfoUpgrade)val).Upgrade == null) { Offset offsetsCached = GetOffsetsCached(item, item2, val); if (_equipSlots.EquipModule(_gear, item, offsetsCached.offsetX, offsetsCached.offsetY, (byte)item2, true, false)) { flag = true; break; } } } } } if (flag) { continue; } foreach (UpgradeInstance item3 in list) { if (item3 == item) { break; } _equipSlots.Unequip(_gear, item3); } return false; } foreach (UpgradeInstance item4 in list2) { bool flag2 = false; int num5 = ((_hexMapHeightField != null) ? ((int)_hexMapHeightField.GetValue(_hexMap)) : 8); int num6 = ((_hexMapWidthField != null) ? ((int)_hexMapWidthField.GetValue(_hexMap)) : 8); List value2; List list4 = (_uniqueRotationsCache.TryGetValue(item4, out value2) ? value2 : new List { 0 }); for (int num7 = 0; num7 < num5; num7++) { if (flag2) { break; } for (int num8 = 0; num8 < num6; num8++) { if (flag2) { break; } foreach (int item5 in list4) { UpgradeEquipCell val2 = null; try { val2 = _equipSlots.GetCell(num8, num7); } catch { } if (!((Object)(object)val2 == (Object)null) && ((HoverInfoUpgrade)val2).Upgrade == null) { Offset offsetsCached2 = GetOffsetsCached(item4, item5, val2); if (_equipSlots.EquipModule(_gear, item4, offsetsCached2.offsetX, offsetsCached2.offsetY, (byte)item5, true, false)) { flag2 = true; break; } } } } } if (flag2) { continue; } foreach (UpgradeInstance item6 in list) { _equipSlots.Unequip(_gear, item6); } foreach (UpgradeInstance item7 in list2) { if (item7 == item4) { break; } _equipSlots.Unequip(_gear, item7); } return false; } int num9 = ((_hexMapHeightField != null) ? ((int)_hexMapHeightField.GetValue(_hexMap)) : 8); int num10 = ((_hexMapWidthField != null) ? ((int)_hexMapWidthField.GetValue(_hexMap)) : 8); int num11 = 0; for (int num12 = 0; num12 < num9; num12++) { for (int num13 = 0; num13 < num10; num13++) { try { UpgradeEquipCell cell = _equipSlots.GetCell(num13, num12); if ((Object)(object)cell != (Object)null && ((HoverInfoUpgrade)cell).Upgrade == null) { num11++; } } catch { } } } int num14 = source.Select((UpgradeInstance u) => GetEffectiveCellCount(u, hasHPU)).Sum(); foreach (UpgradeInstance item8 in list) { _equipSlots.Unequip(_gear, item8); } foreach (UpgradeInstance item9 in list2) { _equipSlots.Unequip(_gear, item9); } return num14 <= num11; } } namespace GridSolverPlus { public static class MyPluginInfo { public const string PLUGIN_GUID = "GridSolverCoru"; public const string PLUGIN_NAME = "GridSolverCoru"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }