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<DefaultButton> _patchedButtons = new HashSet<DefaultButton>();
private Dictionary<int, GearUpgradeUI> _selectedUpgrades = new Dictionary<int, GearUpgradeUI>();
private GearUpgradeUI? _hoveredUpgrade;
private bool _showSolveButton;
private bool _solveButtonEnabled;
private readonly HashSet<UpgradeInstance> _toggledThisSession = new HashSet<UpgradeInstance>();
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, "<Keyboard>/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<GearUpgradeUI>)_selectedUpgrades.Values).FirstOrDefault((Func<GearUpgradeUI, bool>)((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<GearUpgradeUI> source = (from x in ((Component)val).GetComponentsInChildren<GearUpgradeUI>()
where _selectedUpgrades.ContainsKey(((HoverInfoUpgrade)x).Upgrade.InstanceID)
select x).ToList();
_selectedUpgrades = source.ToDictionary((GearUpgradeUI ui) => ((HoverInfoUpgrade)ui).Upgrade.InstanceID);
foreach (KeyValuePair<int, GearUpgradeUI> 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<GearUpgradeUI>(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<int> 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<UpgradeInstance> 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<UpgradeInstance> 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<GearUpgradeUI> list = (from x in ((Component)val).GetComponentsInChildren<GearUpgradeUI>()
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<string> GridExpandingUpgradeNames = new HashSet<string> { "Boundary Incursion", "Edge Fault", "Multiversal Thievery" };
private static readonly HashSet<string> MajorGridExpanderNames = new HashSet<string> { "Multiversal Thievery" };
private static readonly HashSet<string> CellCountModifyingUpgradeNames = new HashSet<string> { "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<UpgradeInstance> _upgrades;
private readonly IUpgradable _gear;
private readonly ModuleEquipSlots _equipSlots;
private readonly HexMap _hexMap;
private List<UpgradeInstance> _specials;
private List<UpgradeInstance> _normals;
private List<UpgradeInstance> _expanders;
private UpgradeInstance _hpu;
private readonly Dictionary<Tuple<UpgradeInstance, int>, Offset> _offsetCache = new Dictionary<Tuple<UpgradeInstance, int>, Offset>();
private readonly Dictionary<UpgradeInstance, List<int>> _uniqueRotationsCache = new Dictionary<UpgradeInstance, List<int>>();
private readonly List<Tuple<UpgradeInstance, sbyte, sbyte, byte>> _previousLayout = new List<Tuple<UpgradeInstance, sbyte, sbyte, byte>>();
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<UpgradeInstance> 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<string, List<UpgradeInstance>> dictionary = new Dictionary<string, List<UpgradeInstance>>();
foreach (UpgradeInstance upgrade2 in _upgrades)
{
HexMap pattern = upgrade2.GetPattern(false);
string hexMapKey = GetHexMapKey(HexMapUtils.CanonicalizeHexMap(pattern));
if (!dictionary.ContainsKey(hexMapKey))
{
dictionary[hexMapKey] = new List<UpgradeInstance>();
}
dictionary[hexMapKey].Add(upgrade2);
_uniqueRotationsCache[upgrade2] = GetUniqueRotations(upgrade2);
}
_expanders = (from u in _upgrades
where IsGridExpander(u)
orderby GetPlacementPriority(u) descending
select u).ToList();
List<UpgradeInstance> 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<int> GetUniqueRotations(UpgradeInstance upgrade)
{
HexMap pattern = upgrade.GetPattern(false);
Dictionary<string, int> dictionary = new Dictionary<string, int>();
List<int> list = new List<int>();
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<UpgradeInstance, int> key = new Tuple<UpgradeInstance, int>(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<UpgradeInstance> EnumerateInstances(IUpgradable gear)
{
List<UpgradeInfo> merged = new List<UpgradeInfo>(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<UpgradeInstance>().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<UpgradeInstance, sbyte, sbyte, byte>(upgrade, item, item2, upgrade.GetRotation(_gear)));
}
}
_previousLayout.Sort((Tuple<UpgradeInstance, sbyte, sbyte, byte> a, Tuple<UpgradeInstance, sbyte, sbyte, byte> b) => GetPlacementPriority(b.Item1).CompareTo(GetPlacementPriority(a.Item1)));
}
private void RestoreEquipped()
{
if ((Object)(object)_equipSlots == (Object)null)
{
return;
}
foreach (Tuple<UpgradeInstance, sbyte, sbyte, byte> 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<int> 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<int> 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<int> list = new List<int>(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<Placement> EnumeratePlacements(UpgradeInstance upgrade, int W, int H, int words, ulong[] baseOccupied)
{
List<Placement> list = new List<Placement>();
HashSet<string> hashSet = new HashSet<string>();
List<int> 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<int> 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<UpgradeInstance> list = new List<UpgradeInstance>();
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<Placement>[] array2 = new List<Placement>[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<int> list2 = new List<int>(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<UpgradeInstance> list3 = new List<UpgradeInstance>();
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<int> 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<Placement> placements)
{
List<string> list = new List<string>(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<int> remaining, ulong[] occupied, List<Placement>[] 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<string> hashSet = new HashSet<string>();
for (int j = 0; j < remaining.Count; j++)
{
int num8 = remaining[j];
if (!hashSet.Add(signatures[num8]))
{
continue;
}
List<Placement> 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<Placement> 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<Placement> 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<int> list = new List<int> { 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<bool> 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<bool> 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<UpgradeInstance> list = _upgrades.Where((UpgradeInstance u) => IsGridExpander(u)).ToList();
List<UpgradeInstance> list2 = _upgrades.Where((UpgradeInstance u) => IsCellCountModifier(u)).ToList();
List<UpgradeInstance> 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<int> value;
List<int> list3 = (_uniqueRotationsCache.TryGetValue(item, out value) ? value : new List<int> { 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<int> value2;
List<int> list4 = (_uniqueRotationsCache.TryGetValue(item4, out value2) ? value2 : new List<int> { 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)
{
}
}
}