Decompiled source of AddSkillTree v1.0.0

BepInEx\plugins\REPOModSkillTree\REPOModSkillTree.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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 ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("REPOModSkillTree")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+5aa026f94994f6f93e9dca634333522a1e5097a0")]
[assembly: AssemblyProduct("REPO Skill Tree")]
[assembly: AssemblyTitle("REPOModSkillTree")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace REPOModSkillTree
{
	[Serializable]
	internal sealed class CreditProgressData
	{
		public int version = 7;

		public long totalCredits;

		public int carryRate = 100;

		public int highestFloorReached;

		public int healthLevel;

		public int staminaLevel;

		public int strengthLevel;

		public int rangeLevel;

		public int crouchStaminaRecoveryLevel;

		public int speedLevel;

		public int jumpLevel;

		public int mapPlayerCountLevel;

		public int healthAppliedLevel;

		public string healthRunRoomName = string.Empty;

		public string healthRestartRoomName = string.Empty;

		public int healthRestartServerTimestamp;

		public string[] purchasedNodeIds = Array.Empty<string>();
	}
	internal static class CreditDataStore
	{
		private const string FileName = "RepoSkillTreeProgress.json";

		private const int CurrentDataVersion = 7;

		private static CreditProgressData _data = new CreditProgressData();

		private static string _filePath;

		internal static long TotalCredits => _data.totalCredits;

		internal static int CarryRate => CreditMath.NormalizeCarryRate(_data.carryRate);

		internal static int HighestFloorReached => _data.highestFloorReached;

		internal static int HealthLevel => _data.healthLevel;

		internal static int StaminaLevel => _data.staminaLevel;

		internal static int PendingHealthLevels => Math.Max(0, _data.healthLevel - _data.healthAppliedLevel);

		internal static bool PreserveCurrentHealthOnLoadedSave { get; private set; }

		internal static string FilePath => _filePath ?? Path.Combine(Paths.ConfigPath, "RepoSkillTreeProgress.json");

		internal static void Load()
		{
			_filePath = Path.Combine(Paths.ConfigPath, "RepoSkillTreeProgress.json");
			_data = new CreditProgressData();
			PreserveCurrentHealthOnLoadedSave = false;
			try
			{
				Directory.CreateDirectory(Paths.ConfigPath);
				if (!File.Exists(_filePath))
				{
					TrySave();
					return;
				}
				CreditProgressData creditProgressData = JsonUtility.FromJson<CreditProgressData>(File.ReadAllText(_filePath));
				if (creditProgressData == null)
				{
					throw new InvalidDataException("Progress JSON did not contain an object.");
				}
				bool flag = creditProgressData.version < 7;
				if (creditProgressData.purchasedNodeIds == null)
				{
					creditProgressData.purchasedNodeIds = Array.Empty<string>();
					flag = true;
				}
				if (creditProgressData.highestFloorReached < 0)
				{
					creditProgressData.highestFloorReached = 0;
					flag = true;
				}
				int num = Math.Max(0, Math.Min(10, creditProgressData.healthLevel));
				if (num != creditProgressData.healthLevel)
				{
					creditProgressData.healthLevel = num;
					flag = true;
				}
				int num2 = Math.Max(0, Math.Min(11, creditProgressData.staminaLevel));
				if (num2 != creditProgressData.staminaLevel)
				{
					creditProgressData.staminaLevel = num2;
					flag = true;
				}
				flag |= NormalizeLevel(ref creditProgressData.strengthLevel, 4);
				flag |= NormalizeLevel(ref creditProgressData.rangeLevel, 2);
				flag |= NormalizeLevel(ref creditProgressData.crouchStaminaRecoveryLevel, 1);
				flag |= NormalizeLevel(ref creditProgressData.speedLevel, 2);
				flag |= NormalizeLevel(ref creditProgressData.jumpLevel, 1);
				flag |= NormalizeLevel(ref creditProgressData.mapPlayerCountLevel, 1);
				if (creditProgressData.version < 3)
				{
					creditProgressData.healthAppliedLevel = 0;
					flag = true;
				}
				int num3 = Math.Max(0, Math.Min(creditProgressData.healthLevel, creditProgressData.healthAppliedLevel));
				if (num3 != creditProgressData.healthAppliedLevel)
				{
					creditProgressData.healthAppliedLevel = num3;
					flag = true;
				}
				if (Array.IndexOf(creditProgressData.purchasedNodeIds, "tier1_hp_up") >= 0 && creditProgressData.healthLevel == 0)
				{
					creditProgressData.healthLevel = 1;
					flag = true;
				}
				if (creditProgressData.healthLevel > 0 && Array.IndexOf(creditProgressData.purchasedNodeIds, "tier1_hp_up") < 0)
				{
					string[] array = new string[creditProgressData.purchasedNodeIds.Length + 1];
					Array.Copy(creditProgressData.purchasedNodeIds, array, creditProgressData.purchasedNodeIds.Length);
					array[^1] = "tier1_hp_up";
					creditProgressData.purchasedNodeIds = array;
					flag = true;
				}
				if (Array.IndexOf(creditProgressData.purchasedNodeIds, "tier1_stamina_up") >= 0 && creditProgressData.staminaLevel == 0)
				{
					creditProgressData.staminaLevel = 1;
					flag = true;
				}
				if (creditProgressData.staminaLevel > 0 && Array.IndexOf(creditProgressData.purchasedNodeIds, "tier1_stamina_up") < 0)
				{
					string[] array2 = new string[creditProgressData.purchasedNodeIds.Length + 1];
					Array.Copy(creditProgressData.purchasedNodeIds, array2, creditProgressData.purchasedNodeIds.Length);
					array2[^1] = "tier1_stamina_up";
					creditProgressData.purchasedNodeIds = array2;
					flag = true;
				}
				if (creditProgressData.totalCredits < 0)
				{
					Plugin.Logger.LogWarning((object)"Saved totalCredits was negative; using 0K.");
					creditProgressData.totalCredits = 0L;
				}
				if (creditProgressData.carryRate <= 0)
				{
					creditProgressData.carryRate = 100;
				}
				else
				{
					creditProgressData.carryRate = CreditMath.NormalizeCarryRate(creditProgressData.carryRate);
				}
				if (creditProgressData.version != 7)
				{
					creditProgressData.version = 7;
					flag = true;
				}
				_data = creditProgressData;
				if (flag)
				{
					TrySave();
					Plugin.Logger.LogInfo((object)$"Migrated progress data to schema version {7}.");
				}
				Plugin.Logger.LogInfo((object)$"Loaded {TotalCredits}K credits at {CarryRate}% carry rate.");
			}
			catch (Exception ex)
			{
				_data = new CreditProgressData();
				Plugin.Logger.LogWarning((object)("Could not load credit data; using 0K. " + ex.Message));
			}
		}

		internal static int GetLevel(PermanentUpgradeStat stat)
		{
			return stat switch
			{
				PermanentUpgradeStat.Health => _data.healthLevel, 
				PermanentUpgradeStat.Stamina => _data.staminaLevel, 
				PermanentUpgradeStat.Strength => _data.strengthLevel, 
				PermanentUpgradeStat.Range => _data.rangeLevel, 
				PermanentUpgradeStat.CrouchStaminaRecovery => _data.crouchStaminaRecoveryLevel, 
				PermanentUpgradeStat.Speed => _data.speedLevel, 
				PermanentUpgradeStat.ExtraJump => _data.jumpLevel, 
				PermanentUpgradeStat.MapPlayerCount => _data.mapPlayerCountLevel, 
				PermanentUpgradeStat.CarryRate => Math.Max(0, Math.Min(5, (_data.carryRate - 100) / 20)), 
				_ => throw new ArgumentOutOfRangeException("stat", stat, "Unsupported permanent upgrade stat."), 
			};
		}

		internal static bool IsNodePurchased(string nodeId)
		{
			return Array.IndexOf(_data.purchasedNodeIds, nodeId) >= 0;
		}

		internal static NodePurchaseResult TryPurchaseNode(UpgradeNodeDefinition node)
		{
			if (node == null)
			{
				throw new ArgumentNullException("node");
			}
			switch (UpgradeNodeService.GetAvailability(node))
			{
			case NodeAvailability.Owned:
				return NodePurchaseResult.AlreadyOwned;
			case NodeAvailability.Locked:
				return NodePurchaseResult.Locked;
			case NodeAvailability.InsufficientCredits:
				return NodePurchaseResult.InsufficientCredits;
			case NodeAvailability.MaximumReached:
				return NodePurchaseResult.MaximumReached;
			case NodeAvailability.SinglePlayerOnly:
				return NodePurchaseResult.SinglePlayerOnly;
			default:
				throw new ArgumentOutOfRangeException("node", "Unknown node availability.");
			case NodeAvailability.Available:
			{
				long totalCredits = _data.totalCredits;
				int level = GetLevel(node.Stat);
				int carryRate = _data.carryRate;
				string[] purchasedNodeIds = _data.purchasedNodeIds;
				_data.totalCredits -= node.CostK;
				if (node.Stat == PermanentUpgradeStat.CarryRate)
				{
					_data.carryRate = Math.Min(200, _data.carryRate + 20);
				}
				else
				{
					SetLevel(node.Stat, level + 1);
				}
				_data.purchasedNodeIds = new string[purchasedNodeIds.Length + 1];
				Array.Copy(purchasedNodeIds, _data.purchasedNodeIds, purchasedNodeIds.Length);
				_data.purchasedNodeIds[_data.purchasedNodeIds.Length - 1] = node.Id;
				if (TrySave())
				{
					Plugin.Logger.LogInfo((object)$"Purchased {node.Id} for {node.CostK}K.");
					return NodePurchaseResult.Purchased;
				}
				_data.totalCredits = totalCredits;
				SetLevel(node.Stat, level);
				_data.carryRate = carryRate;
				_data.purchasedNodeIds = purchasedNodeIds;
				return NodePurchaseResult.SaveFailed;
			}
			}
		}

		private static bool NormalizeLevel(ref int level, int maximum)
		{
			int num = Math.Max(0, Math.Min(maximum, level));
			if (num == level)
			{
				return false;
			}
			level = num;
			return true;
		}

		private static void SetLevel(PermanentUpgradeStat stat, int level)
		{
			switch (stat)
			{
			case PermanentUpgradeStat.Health:
				_data.healthLevel = level;
				break;
			case PermanentUpgradeStat.Stamina:
				_data.staminaLevel = level;
				break;
			case PermanentUpgradeStat.Strength:
				_data.strengthLevel = level;
				break;
			case PermanentUpgradeStat.Range:
				_data.rangeLevel = level;
				break;
			case PermanentUpgradeStat.CrouchStaminaRecovery:
				_data.crouchStaminaRecoveryLevel = level;
				break;
			case PermanentUpgradeStat.Speed:
				_data.speedLevel = level;
				break;
			case PermanentUpgradeStat.ExtraJump:
				_data.jumpLevel = level;
				break;
			case PermanentUpgradeStat.MapPlayerCount:
				_data.mapPlayerCountLevel = level;
				break;
			case PermanentUpgradeStat.CarryRate:
				_data.carryRate = 100 + level * 20;
				break;
			default:
				throw new ArgumentOutOfRangeException("stat", stat, "Unsupported permanent upgrade stat.");
			}
		}

		internal static bool TryMarkHealthBonusApplied(int appliedLevel)
		{
			int num = Math.Max(_data.healthAppliedLevel, Math.Min(_data.healthLevel, appliedLevel));
			if (num == _data.healthAppliedLevel)
			{
				return true;
			}
			int healthAppliedLevel = _data.healthAppliedLevel;
			_data.healthAppliedLevel = num;
			if (TrySave())
			{
				return true;
			}
			_data.healthAppliedLevel = healthAppliedLevel;
			return false;
		}

		internal static bool ResetHealthBonusForNewGame()
		{
			PreserveCurrentHealthOnLoadedSave = false;
			if (_data.healthAppliedLevel == 0)
			{
				return true;
			}
			int healthAppliedLevel = _data.healthAppliedLevel;
			_data.healthAppliedLevel = 0;
			if (TrySave())
			{
				Plugin.Logger.LogInfo((object)$"Reset current-HP bonus marker for a new game save (previously applied level {healthAppliedLevel}).");
				return true;
			}
			_data.healthAppliedLevel = healthAppliedLevel;
			return false;
		}

		internal static void PreserveCurrentHealthForLoadedSave()
		{
			PreserveCurrentHealthOnLoadedSave = true;
			Plugin.Logger.LogInfo((object)"Existing REPO save selected; preserving its saved current HP.");
		}

		internal static bool PrepareHealthBonusForMultiplayerRun(string roomName)
		{
			if (string.IsNullOrEmpty(roomName))
			{
				throw new ArgumentException("A multiplayer room name is required.", "roomName");
			}
			if (_data.healthRunRoomName == roomName)
			{
				return true;
			}
			string healthRunRoomName = _data.healthRunRoomName;
			int healthAppliedLevel = _data.healthAppliedLevel;
			_data.healthRunRoomName = roomName;
			_data.healthAppliedLevel = 0;
			if (TrySave())
			{
				Plugin.Logger.LogInfo((object)"Prepared the current-HP bonus for a new multiplayer run.");
				return true;
			}
			_data.healthRunRoomName = healthRunRoomName;
			_data.healthAppliedLevel = healthAppliedLevel;
			return false;
		}

		internal static bool PrepareHealthBonusForMultiplayerRestart(string roomName, int serverTimestamp, out bool isNewRestart)
		{
			if (string.IsNullOrEmpty(roomName))
			{
				throw new ArgumentException("A multiplayer room name is required.", "roomName");
			}
			isNewRestart = false;
			if (_data.healthRestartRoomName == roomName && serverTimestamp - _data.healthRestartServerTimestamp <= 0)
			{
				return true;
			}
			string healthRunRoomName = _data.healthRunRoomName;
			string healthRestartRoomName = _data.healthRestartRoomName;
			int healthRestartServerTimestamp = _data.healthRestartServerTimestamp;
			int healthAppliedLevel = _data.healthAppliedLevel;
			_data.healthRunRoomName = roomName;
			_data.healthRestartRoomName = roomName;
			_data.healthRestartServerTimestamp = serverTimestamp;
			_data.healthAppliedLevel = 0;
			if (TrySave())
			{
				isNewRestart = true;
				Plugin.Logger.LogInfo((object)"Prepared the current-HP bonus for a multiplayer restart after game over.");
				return true;
			}
			_data.healthRunRoomName = healthRunRoomName;
			_data.healthRestartRoomName = healthRestartRoomName;
			_data.healthRestartServerTimestamp = healthRestartServerTimestamp;
			_data.healthAppliedLevel = healthAppliedLevel;
			return false;
		}

		internal static bool TryCommitClearedFloor(int floorReached, long creditedK)
		{
			if (floorReached <= 0)
			{
				throw new ArgumentOutOfRangeException("floorReached");
			}
			if (creditedK < 0)
			{
				throw new ArgumentOutOfRangeException("creditedK");
			}
			long totalCredits;
			try
			{
				totalCredits = checked(_data.totalCredits + creditedK);
			}
			catch (OverflowException)
			{
				Plugin.Logger.LogError((object)"Credit total overflow; refusing to update saved balance.");
				return false;
			}
			long totalCredits2 = _data.totalCredits;
			int highestFloorReached = _data.highestFloorReached;
			_data.totalCredits = totalCredits;
			_data.highestFloorReached = Math.Max(highestFloorReached, floorReached);
			if (_data.totalCredits == totalCredits2 && _data.highestFloorReached == highestFloorReached)
			{
				return true;
			}
			if (TrySave())
			{
				return true;
			}
			_data.totalCredits = totalCredits2;
			_data.highestFloorReached = highestFloorReached;
			return false;
		}

		private static bool TrySave()
		{
			string text = _filePath + ".tmp";
			try
			{
				Directory.CreateDirectory(Paths.ConfigPath);
				File.WriteAllText(text, JsonUtility.ToJson((object)_data, true));
				if (File.Exists(_filePath))
				{
					File.Replace(text, _filePath, null);
				}
				else
				{
					File.Move(text, _filePath);
				}
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Could not save credit data to '{_filePath}': {arg}");
				try
				{
					if (File.Exists(text))
					{
						File.Delete(text);
					}
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogWarning((object)("Could not remove temporary credit file: " + ex.Message));
				}
				return false;
			}
		}
	}
	internal static class CreditMath
	{
		internal const int MinimumCarryRate = 100;

		internal const int MaximumCarryRate = 200;

		internal static long RecoveredAmountToK(long rawAmount)
		{
			if (rawAmount > 0)
			{
				return rawAmount / 1000;
			}
			return 0L;
		}

		internal static int NormalizeCarryRate(int carryRate)
		{
			return Math.Max(100, Math.Min(200, carryRate));
		}

		internal static long CalculateCarryCredits(long rawAmount, int carryRate)
		{
			return CalculateCreditsAtRate(rawAmount, NormalizeCarryRate(carryRate));
		}

		internal static long CalculateMultiplayerCarryCredits(long rawAmount, int singlePlayerCarryRate)
		{
			int multiplayerCarryRate = GetMultiplayerCarryRate(singlePlayerCarryRate);
			return CalculateCreditsAtRate(rawAmount, multiplayerCarryRate);
		}

		internal static int GetMultiplayerCarryRate(int singlePlayerCarryRate)
		{
			return NormalizeCarryRate(singlePlayerCarryRate) / 2;
		}

		private static long CalculateCreditsAtRate(long rawAmount, int carryRate)
		{
			return (long)decimal.Floor((decimal)RecoveredAmountToK(rawAmount) * (decimal)carryRate / 100m);
		}
	}
	internal static class FloorHaulTracker
	{
		private sealed class ClearedFloorReward
		{
			internal int Floor { get; }

			internal long RawRecovered { get; }

			internal long CreditsK { get; }

			internal ClearedFloorReward(int floor, long rawRecovered, long creditsK)
			{
				Floor = floor;
				RawRecovered = rawRecovered;
				CreditsK = creditsK;
			}
		}

		private static long _pendingRawRecovered;

		private static readonly Queue<ClearedFloorReward> UncommittedRewards = new Queue<ClearedFloorReward>();

		private static bool _saveFailureReported;

		internal static long PendingRawRecovered => _pendingRawRecovered;

		internal static bool HasUncommittedRewards => UncommittedRewards.Count > 0;

		internal static void RecordSuccessfulExtraction(long rawRecovered)
		{
			if (rawRecovered <= 0)
			{
				return;
			}
			checked
			{
				try
				{
					_pendingRawRecovered += rawRecovered;
					Plugin.Logger.LogInfo((object)$"Recorded extracted haul for this floor: {rawRecovered}; pending total {_pendingRawRecovered}.");
				}
				catch (OverflowException)
				{
					Plugin.Logger.LogError((object)"Extracted haul overflow; discarding this floor's unbanked haul.");
					_pendingRawRecovered = 0L;
				}
			}
		}

		internal static void CompleteSuccessfulFloor(int floorNumber, bool isMultiplayer)
		{
			if (floorNumber <= 0)
			{
				Plugin.Logger.LogError((object)$"Cannot record an invalid cleared floor number: {floorNumber}.");
				return;
			}
			long pendingRawRecovered = _pendingRawRecovered;
			_pendingRawRecovered = 0L;
			int carryRate = CreditDataStore.CarryRate;
			int num = (isMultiplayer ? CreditMath.GetMultiplayerCarryRate(carryRate) : carryRate);
			long num2 = (isMultiplayer ? CreditMath.CalculateMultiplayerCarryCredits(pendingRawRecovered, carryRate) : CreditMath.CalculateCarryCredits(pendingRawRecovered, carryRate));
			Plugin.Logger.LogInfo((object)($"Calculating floor reward: raw={pendingRawRecovered}, personalCarryRate={carryRate}%, " + $"multiplayer={isMultiplayer}, appliedCarryRate={num}%, credited={num2}K."));
			UncommittedRewards.Enqueue(new ClearedFloorReward(floorNumber, pendingRawRecovered, num2));
			RetryUncommittedRewards();
		}

		internal static void RetryUncommittedRewards()
		{
			while (UncommittedRewards.Count > 0)
			{
				ClearedFloorReward clearedFloorReward = UncommittedRewards.Peek();
				if (!CreditDataStore.TryCommitClearedFloor(clearedFloorReward.Floor, clearedFloorReward.CreditsK))
				{
					if (!_saveFailureReported)
					{
						_saveFailureReported = true;
						Plugin.Logger.LogError((object)"A cleared-floor reward could not be saved. It will be retried while the game remains open.");
						CreditBalanceView.RefreshAll();
					}
					return;
				}
				UncommittedRewards.Dequeue();
				Plugin.Logger.LogInfo((object)($"Banked {clearedFloorReward.CreditsK}K from {clearedFloorReward.RawRecovered} recovered on cleared floor {clearedFloorReward.Floor}. " + $"Balance: {CreditDataStore.TotalCredits}K."));
				CreditBalanceView.RefreshAll();
			}
			if (_saveFailureReported)
			{
				_saveFailureReported = false;
				Plugin.Logger.LogInfo((object)"All previously unsaved cleared-floor rewards have been saved.");
			}
		}

		internal static void DiscardIncompleteFloor()
		{
			if (_pendingRawRecovered > 0)
			{
				Plugin.Logger.LogInfo((object)$"Discarding {_pendingRawRecovered} unbanked haul from an incomplete floor.");
			}
			_pendingRawRecovered = 0L;
		}

		internal static void ResetForNewRun()
		{
			DiscardIncompleteFloor();
		}
	}
	[HarmonyPatch(typeof(StatsManager), "RunStartStats")]
	internal static class RunStartCreditResetPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			FloorHaulTracker.ResetForNewRun();
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "StateComplete")]
	internal static class ExtractionCompletePatch
	{
		private sealed class ExtractionCapture
		{
			internal readonly long RawRecovered;

			internal ExtractionCapture(long rawRecovered)
			{
				RawRecovered = rawRecovered;
			}
		}

		private static readonly FieldInfo StateStartField = AccessTools.Field(typeof(ExtractionPoint), "stateStart");

		private static readonly FieldInfo CurrentStateField = AccessTools.Field(typeof(ExtractionPoint), "currentState");

		private static readonly FieldInfo HaulSurplusField = AccessTools.Field(typeof(ExtractionPoint), "haulSurplus");

		private static readonly FieldInfo IsShopField = AccessTools.Field(typeof(ExtractionPoint), "isShop");

		private static readonly FieldInfo TaxReturnField = AccessTools.Field(typeof(ExtractionPoint), "taxReturn");

		[HarmonyPrefix]
		private static void Prefix(ExtractionPoint __instance, out ExtractionCapture __state)
		{
			__state = null;
			if ((Object)(object)__instance == (Object)null || !SemiFunc.RunIsLevel())
			{
				return;
			}
			try
			{
				if ((bool)StateStartField.GetValue(__instance) && string.Equals(CurrentStateField.GetValue(__instance)?.ToString(), "Complete", StringComparison.Ordinal) && !(bool)IsShopField.GetValue(__instance) && !(bool)TaxReturnField.GetValue(__instance))
				{
					long num = (long)__instance.haulGoal + (long)(int)HaulSurplusField.GetValue(__instance);
					if (num > 0)
					{
						__state = new ExtractionCapture(num);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Could not inspect completed extraction: " + ex.Message));
			}
		}

		[HarmonyPostfix]
		private static void Postfix(ExtractionCapture __state)
		{
			if (__state == null)
			{
				return;
			}
			try
			{
				FloorHaulTracker.RecordSuccessfulExtraction(__state.RawRecovered);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Could not record completed extraction: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(RunManager), "ChangeLevel")]
	internal static class FloorCompletionPatch
	{
		[HarmonyPrefix]
		private static void Prefix(RunManager __instance, bool _completedLevel, bool _levelFailed)
		{
			bool flag = SemiFunc.IsMultiplayer();
			if (!flag || SemiFunc.IsMasterClientOrSingleplayer())
			{
				if ((Object)(object)__instance == (Object)null)
				{
					Plugin.Logger.LogError((object)"RunManager.ChangeLevel received a null manager; floor outcome was not processed.");
				}
				else if (_levelFailed)
				{
					FloorHaulTracker.DiscardIncompleteFloor();
				}
				else if (_completedLevel && SemiFunc.RunIsLevel())
				{
					FloorHaulTracker.CompleteSuccessfulFloor(__instance.levelsCompleted + 1, flag);
				}
			}
		}
	}
	[HarmonyPatch(typeof(RunManagerPUN), "UpdateLevelRPC")]
	internal static class GuestFloorCompletionPatch
	{
		[HarmonyPrefix]
		private static void Prefix(out int __state)
		{
			__state = (((Object)(object)RunManager.instance != (Object)null) ? RunManager.instance.levelsCompleted : (-1));
		}

		[HarmonyPostfix]
		private static void Postfix(string _levelName, int _levelsCompleted, bool _gameOver, PhotonMessageInfo _info, int __state)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMasterClientOrSingleplayer() || !SemiFunc.MasterOnlyRPC(_info))
			{
				return;
			}
			Plugin.Logger.LogInfo((object)($"Received host level update: level={_levelName}, completed={_levelsCompleted}, " + $"previousCompleted={__state}, gameOver={_gameOver}, " + $"local pending haul={FloorHaulTracker.PendingRawRecovered}."));
			if (_gameOver)
			{
				UpgradeMultiplayerSync.OnGuestRunRestarted(_info);
				FloorHaulTracker.DiscardIncompleteFloor();
				return;
			}
			if (__state < 0 || _levelsCompleted != __state + 1)
			{
				Plugin.Logger.LogInfo((object)("Not crediting host level update '" + _levelName + "': floor count did not advance by exactly one."));
				FloorHaulTracker.DiscardIncompleteFloor();
				return;
			}
			Level val = (((Object)(object)RunManager.instance != (Object)null) ? RunManager.instance.levelCurrent : null);
			if (_levelsCompleted > 0 && (Object)(object)val != (Object)null && SemiFunc.IsLevelShop(val))
			{
				FloorHaulTracker.CompleteSuccessfulFloor(_levelsCompleted, isMultiplayer: true);
			}
			else
			{
				Plugin.Logger.LogInfo((object)("Not crediting host level update '" + _levelName + "': destination is not a shop."));
			}
		}
	}
	internal sealed class CreditBalanceView : MonoBehaviour
	{
		private TMP_Text _label;

		private CanvasGroup _canvasGroup;

		private bool _isInitialized;

		private Coroutine _revealCoroutine;

		internal bool IsRevealInProgress => _revealCoroutine != null;

		internal void Initialize(TMP_Text source)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			bool num = !_isInitialized;
			_canvasGroup = ((Component)this).GetComponent<CanvasGroup>();
			if ((Object)(object)_canvasGroup == (Object)null)
			{
				_canvasGroup = ((Component)this).gameObject.AddComponent<CanvasGroup>();
			}
			if (num)
			{
				_canvasGroup.alpha = 0f;
				_canvasGroup.interactable = false;
				_canvasGroup.blocksRaycasts = false;
			}
			if ((Object)(object)_label == (Object)null)
			{
				GameObject val = new GameObject("CreditBalanceLabel", new Type[1] { typeof(RectTransform) });
				val.transform.SetParent(((Component)this).transform, false);
				RectTransform val2 = (RectTransform)val.transform;
				val2.anchorMin = Vector2.zero;
				val2.anchorMax = Vector2.one;
				val2.offsetMin = new Vector2(12f, 0f);
				val2.offsetMax = new Vector2(-12f, 0f);
				_label = (TMP_Text)(object)val.AddComponent<TextMeshProUGUI>();
				if ((Object)(object)source != (Object)null)
				{
					_label.font = source.font;
					_label.fontSharedMaterial = source.fontSharedMaterial;
					_label.fontSize = Mathf.Clamp(source.fontSize, 14f, 18f);
					_label.fontStyle = source.fontStyle;
				}
				else
				{
					_label.fontSize = 18f;
				}
				((Graphic)_label).color = Color.white;
				_label.alignment = (TextAlignmentOptions)4097;
				_label.textWrappingMode = (TextWrappingModes)0;
				((Graphic)_label).raycastTarget = false;
			}
			Refresh();
			_isInitialized = true;
		}

		internal void RevealForMainMenuActivation()
		{
			if (_isInitialized && !((Object)(object)_canvasGroup == (Object)null))
			{
				if (_revealCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_revealCoroutine);
					_revealCoroutine = null;
				}
				_canvasGroup.alpha = 0f;
				_canvasGroup.interactable = false;
				_canvasGroup.blocksRaycasts = false;
				BeginReveal();
			}
		}

		internal void HideForGameplayStart()
		{
			if (_revealCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_revealCoroutine);
				_revealCoroutine = null;
			}
			if ((Object)(object)_canvasGroup != (Object)null)
			{
				_canvasGroup.alpha = 0f;
				_canvasGroup.interactable = false;
				_canvasGroup.blocksRaycasts = false;
			}
		}

		private void OnDisable()
		{
			if (_revealCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_revealCoroutine);
				_revealCoroutine = null;
			}
		}

		internal void ShowImmediately()
		{
			if (!((Object)(object)_canvasGroup == (Object)null) && _isInitialized)
			{
				if (_revealCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_revealCoroutine);
					_revealCoroutine = null;
				}
				_canvasGroup.alpha = 1f;
				_canvasGroup.interactable = false;
				_canvasGroup.blocksRaycasts = false;
			}
		}

		private void BeginReveal()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_canvasGroup == (Object)null) && ((Behaviour)this).isActiveAndEnabled && _revealCoroutine == null)
			{
				MenuPage componentInParent = ((Component)this).GetComponentInParent<MenuPage>();
				if (!((Object)(object)componentInParent == (Object)null) && (int)componentInParent.menuPageIndex == 0 && !((Object)(object)UpgradeMenuPageRegistry.GetCurrentPage() != (Object)(object)componentInParent) && !(_canvasGroup.alpha >= 0.999f))
				{
					_canvasGroup.alpha = 0f;
					_canvasGroup.interactable = false;
					_canvasGroup.blocksRaycasts = false;
					_revealCoroutine = ((MonoBehaviour)this).StartCoroutine(RevealAfterMenuEntrance());
				}
			}
		}

		private IEnumerator RevealAfterMenuEntrance()
		{
			yield return (object)new WaitForSecondsRealtime(6f);
			float elapsed = 0f;
			while (elapsed < 0.35f)
			{
				if (!((Behaviour)this).isActiveAndEnabled)
				{
					_revealCoroutine = null;
					yield break;
				}
				elapsed += Time.unscaledDeltaTime;
				_canvasGroup.alpha = Mathf.Clamp01(elapsed / 0.35f);
				yield return null;
			}
			_canvasGroup.alpha = 1f;
			_revealCoroutine = null;
		}

		internal void Refresh()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_label != (Object)null)
			{
				_label.text = $"CREDITS : {CreditDataStore.TotalCredits} K" + (FloorHaulTracker.HasUncommittedRewards ? "\nSAVE FAILED" : string.Empty);
				((Graphic)_label).color = (Color)(FloorHaulTracker.HasUncommittedRewards ? new Color(1f, 0.55f, 0.3f, 1f) : Color.white);
			}
		}

		internal static void RefreshAll()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			CreditBalanceView[] array = Resources.FindObjectsOfTypeAll<CreditBalanceView>();
			foreach (CreditBalanceView creditBalanceView in array)
			{
				if ((Object)(object)creditBalanceView != (Object)null)
				{
					Scene scene = ((Component)creditBalanceView).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						creditBalanceView.Refresh();
					}
				}
			}
			UpgradeScreenView.RefreshAllCredits();
		}
	}
	[HarmonyPatch(typeof(MenuPageMain), "Start")]
	internal static class MainMenuCreditIntegration
	{
		private const string PanelName = "REPOModSkillTree_CreditBalance";

		private const float CreditPanelHeight = 54f;

		private const float AddonVerticalGap = 10f;

		private static Vector2 _creditPanelPosition = new Vector2(-42f, 230f);

		private static Vector2 _upgradeButtonPosition = new Vector2(-42f, 294f);

		private static Transform _addonParent;

		private static bool _suppressMainMenuReveal;

		private static bool _initialMainRevealStarted;

		private static bool _gameplayReturnRevealPending;

		internal static Vector2 CreditPanelPosition => _creditPanelPosition;

		internal static Vector2 UpgradeButtonPosition => _upgradeButtonPosition;

		internal static Transform AddonParent => _addonParent;

		[HarmonyPostfix]
		private static void Postfix(MenuPageMain __instance)
		{
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				MenuPage component = ((Component)__instance).GetComponent<MenuPage>();
				TextMeshProUGUI val = (((Object)(object)component != (Object)null) ? component.menuHeader : null);
				Canvas val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInParent<Canvas>() : ((Component)__instance).GetComponentInParent<Canvas>());
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"Could not find a Canvas for the main-menu credit display.");
					return;
				}
				RectTransform component2 = ((Component)val2).GetComponent<RectTransform>();
				bool flag = ConfigureAddonPositions(__instance, component2);
				Transform val3 = FindPanel(((Component)__instance).transform);
				if ((Object)(object)val3 == (Object)null)
				{
					GameObject val4 = new GameObject("REPOModSkillTree_CreditBalance", new Type[3]
					{
						typeof(RectTransform),
						typeof(Image),
						typeof(CreditBalanceView)
					});
					val3 = val4.transform;
					val3.SetParent(((Object)(object)_addonParent != (Object)null) ? _addonParent : ((Component)__instance).transform, false);
					Image component3 = val4.GetComponent<Image>();
					((Graphic)component3).color = new Color(0.025f, 0.035f, 0.05f, 0.78f);
					((Graphic)component3).raycastTarget = false;
				}
				ConfigurePanelRect((RectTransform)val3, _creditPanelPosition);
				PlacePanelBehindCursor(val3, ((Component)__instance).transform);
				TMP_Text val5 = FindMenuFontSource(__instance, (TMP_Text)(object)val);
				((Component)val3).GetComponent<CreditBalanceView>().Initialize(val5);
				UpgradeShopView.Install(__instance, val5);
				if (!flag)
				{
					((MonoBehaviour)__instance).StartCoroutine(ConfigureAddonPositionsAfterLayout(__instance));
				}
				NotifyMainPageActivation(component);
				Plugin.Logger.LogInfo((object)"Main-menu credit balance display is ready.");
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Could not create the main-menu credit display: {arg}");
			}
		}

		private static bool ConfigureAddonPositions(MenuPageMain mainPage, RectTransform canvasRect)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			_addonParent = (((Object)(object)mainPage != (Object)null) ? ((Component)mainPage).transform : null);
			_creditPanelPosition = new Vector2(-42f, 230f);
			_upgradeButtonPosition = new Vector2(-42f, 294f);
			RectTransform val = (((Object)(object)mainPage != (Object)null) ? ((Component)mainPage).GetComponent<RectTransform>() : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Rect rect = val.rect;
			Vector2 size = ((Rect)(ref rect)).size;
			if ((size.x <= 0f || size.y <= 0f) && (Object)(object)canvasRect != (Object)null)
			{
				rect = canvasRect.rect;
				size = ((Rect)(ref rect)).size;
			}
			RectTransform val2 = MainMenuAddonLayout.FindNewUpdatePanel(((Component)mainPage).transform, size);
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			RectTransform val3 = val;
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			val2.GetWorldCorners(array);
			Vector3 val4 = ((Transform)val3).InverseTransformPoint(array[2]);
			float x = val4.x;
			rect = val3.rect;
			float num = x - ((Rect)(ref rect)).xMax;
			float y = val4.y;
			rect = val3.rect;
			float num2 = y - ((Rect)(ref rect)).yMin + 14f;
			_addonParent = ((Component)mainPage).transform;
			_creditPanelPosition = new Vector2(num, num2);
			_upgradeButtonPosition = new Vector2(num, num2 + 54f + 10f);
			ManualLogSource logger = Plugin.Logger;
			rect = val2.rect;
			string text = $"Placed CREDITS and UPGRADES above NEW UPDATE: promo={((Rect)(ref rect)).size}, ";
			string name = ((Object)val3).name;
			rect = val3.rect;
			logger.LogInfo((object)(text + $"parent={name} {((Rect)(ref rect)).size}, " + $"credits={_creditPanelPosition}, upgrades={_upgradeButtonPosition}."));
			return true;
		}

		private static IEnumerator ConfigureAddonPositionsAfterLayout(MenuPageMain mainPage)
		{
			for (int frame = 0; frame < 120; frame++)
			{
				yield return null;
				if ((Object)(object)mainPage == (Object)null)
				{
					yield break;
				}
				Canvas componentInParent = ((Component)mainPage).GetComponentInParent<Canvas>();
				if (!ConfigureAddonPositions(mainPage, ((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).GetComponent<RectTransform>() : null))
				{
					continue;
				}
				Transform obj = FindPanel(((Component)mainPage).transform);
				RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					if ((Object)(object)_addonParent != (Object)null && (Object)(object)((Transform)val).parent != (Object)(object)_addonParent)
					{
						((Transform)val).SetParent(_addonParent, false);
					}
					ConfigurePanelRect(val, _creditPanelPosition);
				}
				((Component)mainPage).GetComponent<UpgradeShopView>()?.SetEntryLayout(_addonParent, _upgradeButtonPosition);
				yield break;
			}
			Plugin.Logger.LogWarning((object)"The main-menu page did not expose a measurable NEW UPDATE panel after layout; keeping safe fallback addon positions.");
		}

		private static void ConfigurePanelRect(RectTransform rect, Vector2 position)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(1f, 0f);
			rect.anchorMax = new Vector2(1f, 0f);
			rect.pivot = new Vector2(1f, 0f);
			rect.anchoredPosition = position;
			rect.sizeDelta = new Vector2(130f, 54f);
		}

		internal static void NotifyMainPageActivation(MenuPage page)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)page == (Object)null || (int)page.menuPageIndex != 0 || (Object)(object)UpgradeMenuPageRegistry.GetCurrentPage() != (Object)(object)page)
			{
				return;
			}
			CreditBalanceView componentInChildren = ((Component)page).GetComponentInChildren<CreditBalanceView>(true);
			UpgradeShopView component = ((Component)page).GetComponent<UpgradeShopView>();
			if (!((Object)(object)componentInChildren == (Object)null) || !((Object)(object)component == (Object)null))
			{
				if (_suppressMainMenuReveal)
				{
					componentInChildren?.ShowImmediately();
					component?.ShowImmediately();
				}
				else if (!_initialMainRevealStarted || _gameplayReturnRevealPending)
				{
					_initialMainRevealStarted = true;
					_gameplayReturnRevealPending = false;
					componentInChildren?.RevealForMainMenuActivation();
					component?.RevealForMainMenuActivation();
					Plugin.Logger.LogInfo((object)"Started Main-menu 6-second reveal for CREDITS and UPGRADES.");
				}
				else if ((componentInChildren == null || !componentInChildren.IsRevealInProgress) && (component == null || !component.IsRevealInProgress))
				{
					componentInChildren?.ShowImmediately();
					component?.ShowImmediately();
				}
			}
		}

		internal static void HideForGameplayStart()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			_gameplayReturnRevealPending = true;
			CreditBalanceView[] array = Resources.FindObjectsOfTypeAll<CreditBalanceView>();
			Scene scene;
			foreach (CreditBalanceView creditBalanceView in array)
			{
				if ((Object)(object)creditBalanceView != (Object)null)
				{
					scene = ((Component)creditBalanceView).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						creditBalanceView.HideForGameplayStart();
					}
				}
			}
			UpgradeShopView[] array2 = Resources.FindObjectsOfTypeAll<UpgradeShopView>();
			foreach (UpgradeShopView upgradeShopView in array2)
			{
				if ((Object)(object)upgradeShopView != (Object)null)
				{
					scene = ((Component)upgradeShopView).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						upgradeShopView.HideForGameplayStart();
					}
				}
			}
		}

		internal static void SuppressMainMenuReveal()
		{
			_suppressMainMenuReveal = true;
		}

		internal static void ResumeMainMenuReveal()
		{
			_suppressMainMenuReveal = false;
		}

		internal static void ShowCurrentMainMenuImmediately()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)MenuManager.instance == (Object)null))
			{
				MenuPage currentPage = UpgradeMenuPageRegistry.GetCurrentPage();
				if (!((Object)(object)currentPage == (Object)null) && (int)currentPage.menuPageIndex == 0)
				{
					((Component)currentPage).GetComponentInChildren<CreditBalanceView>(true)?.ShowImmediately();
					((Component)currentPage).GetComponent<UpgradeShopView>()?.ShowImmediately();
				}
			}
		}

		private static TMP_Text FindMenuFontSource(MenuPageMain page, TMP_Text fallback)
		{
			TMP_Text[] componentsInChildren = ((Component)page).GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val in componentsInChildren)
			{
				string a = val.text?.Trim();
				if (string.Equals(a, "PRIVATE GAME", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "SINGLEPLAYER", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "QUIT GAME", StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return fallback;
		}

		private static Transform FindPanel(Transform root)
		{
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				if (((Object)child).name == "REPOModSkillTree_CreditBalance")
				{
					return child;
				}
				Transform val = FindPanel(child);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		internal static void PlacePanelBehindCursor(Transform panel, Transform pageRoot)
		{
			Transform val = FindCursor(pageRoot);
			if ((Object)(object)panel.parent != (Object)(object)pageRoot)
			{
				panel.SetAsLastSibling();
				return;
			}
			Transform val2 = val;
			while ((Object)(object)val2 != (Object)null && (Object)(object)val2.parent != (Object)(object)pageRoot)
			{
				val2 = val2.parent;
			}
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)panel)
			{
				panel.SetSiblingIndex(val2.GetSiblingIndex());
			}
			else
			{
				panel.SetAsLastSibling();
			}
		}

		private static Transform FindCursor(Transform root)
		{
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				if (((Object)child).name.IndexOf("cursor", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)child).name.IndexOf("mouse", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return child;
				}
				Transform val = FindCursor(child);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}
	}
	internal static class MainMenuAddonLayout
	{
		internal static RectTransform FindNewUpdatePanel(Transform root, Vector2 pageSize)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			RectTransform result = null;
			float num = 0f;
			TMP_Text[] componentsInChildren = ((Component)root).GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || val.text.IndexOf("NEW UPDATE", StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				Transform val2 = val.transform;
				while ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)root)
				{
					RectTransform val3 = (RectTransform)(object)((val2 is RectTransform) ? val2 : null);
					if ((Object)(object)val3 != (Object)null && (Object)(object)((Component)val2).GetComponent<Image>() != (Object)null)
					{
						Rect rect = val3.rect;
						Vector2 size = ((Rect)(ref rect)).size;
						if (size.x >= pageSize.x * 0.12f && size.y >= pageSize.y * 0.06f && size.x <= pageSize.x * 0.8f && size.y <= pageSize.y * 0.5f)
						{
							float num2 = size.x * size.y;
							if (num2 > num)
							{
								num = num2;
								result = val3;
							}
						}
					}
					val2 = val2.parent;
				}
			}
			return result;
		}
	}
	[HarmonyPatch(typeof(MenuManager), "PageSetCurrent")]
	internal static class MainMenuPageActivationPatch
	{
		[HarmonyPatch(typeof(TutorialDirector), "Start")]
		internal static class TutorialMainMenuUiHidePatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				MainMenuCreditIntegration.HideForGameplayStart();
			}
		}

		[HarmonyPatch(typeof(PlayerAvatar), "LateStart")]
		internal static class GameplayMainMenuUiHidePatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				if (SemiFunc.RunIsLevel())
				{
					MainMenuCreditIntegration.HideForGameplayStart();
				}
			}
		}

		[HarmonyPostfix]
		private static void Postfix(MenuPageIndex __0, MenuPage __1)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if ((int)__0 == 0 && (Object)(object)__1 != (Object)null)
			{
				MainMenuCreditIntegration.NotifyMainPageActivation(__1);
			}
		}
	}
	internal static class MenuPageIdAllocator
	{
		internal static int FindAvailable(IEnumerable<int> reservedIds)
		{
			if (reservedIds == null)
			{
				throw new ArgumentNullException("reservedIds");
			}
			HashSet<int> hashSet = new HashSet<int>(reservedIds);
			int i;
			for (i = 0; hashSet.Contains(i); i++)
			{
				if (i == int.MaxValue)
				{
					throw new InvalidOperationException("No non-negative menu page ID is available.");
				}
			}
			return i;
		}
	}
	internal static class MenuRevealTiming
	{
		internal const float DelaySeconds = 6f;

		internal const float FadeSeconds = 0.35f;
	}
	internal sealed class NativeMenuButtonAdapter
	{
		private static readonly FieldInfo ButtonField = AccessTools.Field(typeof(MenuButton), "button");

		private static readonly FieldInfo TextField = AccessTools.Field(typeof(MenuButton), "buttonText");

		private static readonly FieldInfo DisabledField = AccessTools.Field(typeof(MenuButton), "disabled");

		private static readonly FieldInfo HoveringField = AccessTools.Field(typeof(MenuButton), "hovering");

		private static readonly FieldInfo HoverTimerField = AccessTools.Field(typeof(MenuButton), "hoverTimer");

		private static readonly FieldInfo ClickedField = AccessTools.Field(typeof(MenuButton), "clicked");

		private static readonly FieldInfo ClickTimerField = AccessTools.Field(typeof(MenuButton), "clickTimer");

		private static readonly MethodInfo OnHoverEndMethod = AccessTools.Method(typeof(MenuButton), "OnHoverEnd", (Type[])null, (Type[])null);

		private static readonly FieldInfo PopupField = AccessTools.Field(typeof(MenuButton), "menuButtonPopUp");

		private static readonly FieldInfo TextStringField = AccessTools.Field(typeof(MenuButton), "buttonTextString");

		private static readonly FieldInfo SelectableElementField = FindField(typeof(MenuButton), "menuSelectableElement", "<menuSelectableElement>k__BackingField");

		private static readonly PropertyInfo SelectableElementProperty = AccessTools.Property(typeof(MenuButton), "menuSelectableElement");

		private static readonly FieldInfo SelectableMenuIdField = FindField(typeof(MenuSelectableElement), "menuID", "<menuID>k__BackingField");

		private static readonly PropertyInfo SelectableMenuIdProperty = AccessTools.Property(typeof(MenuSelectableElement), "menuID");

		private static readonly FieldInfo ClickEventField = typeof(Button).GetField("m_OnClick", BindingFlags.Instance | BindingFlags.NonPublic);

		internal MenuButton Component { get; }

		internal Button Button => GetValue<Button>(ButtonField);

		internal TextMeshProUGUI Text => GetValue<TextMeshProUGUI>(TextField);

		internal GameObject GameObject => ((Component)Component).gameObject;

		internal bool Disabled
		{
			get
			{
				return GetValue<bool>(DisabledField);
			}
			set
			{
				SetValue(DisabledField, value);
			}
		}

		internal bool HasPopup => GetValue<Object>(PopupField) != (Object)null;

		internal string EnsureSelectableMenuId()
		{
			object? obj = SelectableElementProperty?.GetValue(Component, null);
			MenuSelectableElement val = (MenuSelectableElement)(((obj is MenuSelectableElement) ? obj : null) ?? GetValue<MenuSelectableElement>(SelectableElementField));
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			string text = (SelectableMenuIdProperty?.GetValue(val, null) as string) ?? (SelectableMenuIdField?.GetValue(val) as string);
			if (string.IsNullOrEmpty(text))
			{
				text = SemiFunc.MenuGetSelectableID(((Component)val).gameObject);
				MethodInfo methodInfo = SelectableMenuIdProperty?.GetSetMethod(nonPublic: true);
				if (methodInfo != null)
				{
					methodInfo.Invoke(val, new object[1] { text });
				}
				else
				{
					if (SelectableMenuIdField == null)
					{
						Plugin.Logger.LogError((object)"Could not set the MenuSelectableElement ID; required field/property is missing.");
						return null;
					}
					SelectableMenuIdField.SetValue(val, text);
				}
			}
			return text;
		}

		internal NativeMenuButtonAdapter(MenuButton component)
		{
			Component = component;
		}

		internal bool ReplaceClickAction(UnityAction listener)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			Button button = Button;
			if ((Object)(object)button == (Object)null || ClickEventField == null)
			{
				return false;
			}
			ButtonClickedEvent val = new ButtonClickedEvent();
			((UnityEvent)val).AddListener(listener);
			ClickEventField.SetValue(button, val);
			return true;
		}

		internal T GetValue<T>(FieldInfo field)
		{
			if (!(field == null))
			{
				return (T)field.GetValue(Component);
			}
			return default(T);
		}

		internal void SetValue(string fieldName, object value)
		{
			FieldInfo fieldInfo = FindField(typeof(MenuButton), fieldName, "<" + fieldName + ">k__BackingField");
			if (fieldInfo != null)
			{
				SetValue(fieldInfo, value);
				return;
			}
			MethodInfo methodInfo = AccessTools.Property(typeof(MenuButton), fieldName)?.GetSetMethod(nonPublic: true);
			if (methodInfo != null)
			{
				methodInfo.Invoke(Component, new object[1] { value });
			}
			else
			{
				Plugin.Logger.LogWarning((object)("Could not set MenuButton member '" + fieldName + "' because no field or writable property exists."));
			}
		}

		private static FieldInfo FindField(Type type, string fieldName, string backingFieldName)
		{
			return type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField(backingFieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		}

		private void SetValue(FieldInfo field, object value)
		{
			field?.SetValue(Component, value);
		}

		internal void SetTextString(string value)
		{
			SetValue(TextStringField, value);
		}

		internal void SetText(string value)
		{
			((TMP_Text)Text).text = value;
			SetTextString(value);
		}

		internal void SetDisabled(bool disabled)
		{
			Disabled = disabled;
			if ((Object)(object)Button != (Object)null)
			{
				((Selectable)Button).interactable = !disabled;
			}
		}

		internal void ResetHoverState()
		{
			if (GetValue<bool>(HoveringField))
			{
				OnHoverEndMethod?.Invoke(Component, null);
			}
			SetValue(HoveringField, false);
			SetValue(HoverTimerField, 0f);
			SetValue(ClickedField, false);
			SetValue(ClickTimerField, 0f);
		}
	}
	internal static class NativeMenuButtonFactory
	{
		private static Sprite _circleSprite;

		internal static NativeMenuButtonAdapter Create(Transform parent, MenuPage ownerPage, string objectName, string label, TMP_Text fontSource, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 position, Vector2 size, UnityAction onClick, Color backgroundColor, bool circleBackground = false, UnityAction onHover = null)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Expected O, but got Unknown
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Expected O, but got Unknown
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_047d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_046f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0502: Unknown result type (might be due to invalid IL or missing references)
			//IL_050a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0512: Unknown result type (might be due to invalid IL or missing references)
			//IL_051a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0522: Unknown result type (might be due to invalid IL or missing references)
			//IL_058e: Unknown result type (might be due to invalid IL or missing references)
			//IL_059a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)parent == (Object)null || (Object)(object)ownerPage == (Object)null)
			{
				Plugin.Logger.LogError((object)("Cannot create native menu control '" + objectName + "' without a parent MenuPage."));
				return null;
			}
			GameObject val = new GameObject(objectName, new Type[1] { typeof(RectTransform) });
			val.SetActive(false);
			val.transform.SetParent(parent, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = anchorMin;
			val2.anchorMax = anchorMax;
			val2.pivot = pivot;
			val2.anchoredPosition = position;
			val2.sizeDelta = size;
			Image val3 = val.AddComponent<Image>();
			((Graphic)val3).color = Color.clear;
			((Graphic)val3).raycastTarget = true;
			Button val4 = val.AddComponent<Button>();
			((Selectable)val4).targetGraphic = (Graphic)(object)val3;
			((Selectable)val4).transition = (Transition)0;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)val4).navigation = navigation;
			GameObject val5 = new GameObject("MenuSelectableElement", new Type[1] { typeof(RectTransform) });
			val5.transform.SetParent(val.transform, false);
			RectTransform val6 = (RectTransform)val5.transform;
			val6.anchorMin = Vector2.zero;
			val6.anchorMax = Vector2.one;
			val6.offsetMin = Vector2.zero;
			val6.offsetMax = Vector2.zero;
			MenuSelectableElement val7 = val5.AddComponent<MenuSelectableElement>();
			((Selectable)val7).transition = (Transition)0;
			navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)val7).navigation = navigation;
			((Selectable)val7).targetGraphic = (Graphic)(object)val3;
			SetSelectableMember(val7, "parentPage", ownerPage);
			SetSelectableMember(val7, "rectTransform", val6);
			MenuButton component = val.AddComponent<MenuButton>();
			NativeMenuButtonHitboxMarker nativeMenuButtonHitboxMarker = val.AddComponent<NativeMenuButtonHitboxMarker>();
			nativeMenuButtonHitboxMarker.SetHoverAction(onHover);
			nativeMenuButtonHitboxMarker.SetClickAction((UnityAction)delegate
			{
				Plugin.Logger.LogInfo((object)("Menu button '" + objectName + "' clicked."));
				UnityAction obj = onClick;
				if (obj != null)
				{
					obj.Invoke();
				}
			});
			((UnityEvent)val4.onClick).AddListener(new UnityAction(nativeMenuButtonHitboxMarker.InvokeClickAction));
			NativeMenuButtonAdapter nativeMenuButtonAdapter = new NativeMenuButtonAdapter(component);
			nativeMenuButtonAdapter.SetValue("buttonTextString", label);
			nativeMenuButtonAdapter.SetValue("customColors", true);
			nativeMenuButtonAdapter.SetValue("colorNormal", Color.white);
			nativeMenuButtonAdapter.SetValue("colorHover", Color.white);
			nativeMenuButtonAdapter.SetValue("colorClick", (object)new Color(1f, 0.77f, 0.12f, 1f));
			nativeMenuButtonAdapter.SetValue("doButtonEffect", false);
			nativeMenuButtonAdapter.SetValue("doHoverEffect", true);
			nativeMenuButtonAdapter.SetValue("resizeButton", false);
			nativeMenuButtonAdapter.SetValue("customHoverArea", false);
			nativeMenuButtonAdapter.SetValue("button", val4);
			nativeMenuButtonAdapter.SetValue("menuSelectableElement", val7);
			nativeMenuButtonAdapter.SetValue("rectTransform", val2);
			nativeMenuButtonAdapter.SetValue("rectTransformSelection", val6);
			nativeMenuButtonAdapter.SetValue("parentPage", ownerPage);
			GameObject val8 = new GameObject("VisualBackground", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val8.transform.SetParent(val.transform, false);
			val8.transform.SetAsFirstSibling();
			RectTransform val9 = (RectTransform)val8.transform;
			val9.anchorMin = Vector2.zero;
			val9.anchorMax = Vector2.one;
			val9.offsetMin = Vector2.zero;
			val9.offsetMax = Vector2.zero;
			Image component2 = val8.GetComponent<Image>();
			((Graphic)component2).color = backgroundColor;
			((Graphic)component2).raycastTarget = false;
			((Selectable)val7).targetGraphic = (Graphic)(object)component2;
			if (circleBackground)
			{
				component2.sprite = GetCircleSprite();
				component2.type = (Type)0;
				component2.preserveAspect = true;
			}
			GameObject val10 = new GameObject("Label", new Type[1] { typeof(RectTransform) });
			val10.transform.SetParent(val.transform, false);
			RectTransform val11 = (RectTransform)val10.transform;
			val11.anchorMin = Vector2.zero;
			val11.anchorMax = Vector2.one;
			val11.offsetMin = new Vector2(4f, 3f);
			val11.offsetMax = new Vector2(-4f, -3f);
			TextMeshProUGUI val12 = val10.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)fontSource != (Object)null)
			{
				((TMP_Text)val12).font = fontSource.font;
				((TMP_Text)val12).fontSharedMaterial = fontSource.fontSharedMaterial;
				((Graphic)val12).color = Color.white;
				((TMP_Text)val12).fontStyle = fontSource.fontStyle;
			}
			else
			{
				((Graphic)val12).color = Color.white;
			}
			((TMP_Text)val12).fontSize = (circleBackground ? 13f : 17f);
			((TMP_Text)val12).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val12).textWrappingMode = (TextWrappingModes)0;
			((Graphic)val12).raycastTarget = false;
			((TMP_Text)val12).text = label;
			nativeMenuButtonAdapter.SetValue("buttonText", val12);
			val.SetActive(true);
			nativeMenuButtonAdapter.SetValue("button", val4);
			nativeMenuButtonAdapter.SetValue("menuSelectableElement", val7);
			nativeMenuButtonAdapter.SetValue("buttonText", val12);
			val2.anchorMin = anchorMin;
			val2.anchorMax = anchorMax;
			val2.pivot = pivot;
			val2.anchoredPosition = position;
			val2.sizeDelta = size;
			nativeMenuButtonAdapter.SetValue("rectTransformSelection", val6);
			nativeMenuButtonAdapter.SetText(label);
			((TMP_Text)nativeMenuButtonAdapter.Text).fontSize = (circleBackground ? 13f : 17f);
			nativeMenuButtonAdapter.SetValue("rectTransformSelection", val6);
			nativeMenuButtonAdapter.SetValue("rectTransform", val2);
			((Selectable)val4).interactable = true;
			Plugin.Logger.LogDebug((object)$"Created REPO menu button '{objectName}' with screen hitbox {size.x:0}x{size.y}.");
			return nativeMenuButtonAdapter;
		}

		private static void SetSelectableMember(MenuSelectableElement selectable, string memberName, object value)
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(MenuSelectableElement), memberName);
			if (fieldInfo != null)
			{
				fieldInfo.SetValue(selectable, value);
				return;
			}
			MethodInfo methodInfo = AccessTools.Property(typeof(MenuSelectableElement), memberName)?.GetSetMethod(nonPublic: true);
			if (methodInfo != null)
			{
				methodInfo.Invoke(selectable, new object[1] { value });
			}
			else
			{
				Plugin.Logger.LogWarning((object)("Could not set MenuSelectableElement member '" + memberName + "' because no field or writable property exists."));
			}
		}

		private static Sprite GetCircleSprite()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_circleSprite != (Object)null)
			{
				return _circleSprite;
			}
			Texture2D val = new Texture2D(96, 96, (TextureFormat)4, false)
			{
				name = "REPOModSkillTree_NodeCircle",
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1
			};
			Color[] array = (Color[])(object)new Color[9216];
			float num = 47.5f;
			for (int i = 0; i < 96; i++)
			{
				for (int j = 0; j < 96; j++)
				{
					float num2 = Vector2.Distance(new Vector2((float)j, (float)i), new Vector2(num, num));
					float num3 = Mathf.Clamp01(46.75f - num2);
					array[i * 96 + j] = new Color(1f, 1f, 1f, num3);
				}
			}
			val.SetPixels(array);
			val.Apply();
			_circleSprite = Sprite.Create(val, new Rect(0f, 0f, 96f, 96f), new Vector2(0.5f, 0.5f), 96f);
			((Object)_circleSprite).name = "REPOModSkillTree_NodeCircle";
			return _circleSprite;
		}
	}
	internal sealed class NativeMenuButtonHitboxMarker : MonoBehaviour
	{
		private UnityAction _onHover;

		private UnityAction _onClick;

		private string _lastHitTestReason;

		private bool _hasClicked;

		private float _lastClickTime;

		private bool _missingMouseReported;

		private static bool _suppressNativeMenuClick;

		internal static bool SuppressNativeMenuClick => _suppressNativeMenuClick;

		internal static void SuppressNativeMenuClickForCurrentMousePress()
		{
			_suppressNativeMenuClick = true;
		}

		internal void SetHoverAction(UnityAction onHover)
		{
			_onHover = onHover;
		}

		internal void SetClickAction(UnityAction onClick)
		{
			_onClick = onClick;
		}

		internal void InvokeHoverAction()
		{
			UnityAction onHover = _onHover;
			if (onHover != null)
			{
				onHover.Invoke();
			}
		}

		internal void InvokeClickAction()
		{
			if (_onClick != null && (!_hasClicked || !(Time.unscaledTime - _lastClickTime < 0.35f)))
			{
				_hasClicked = true;
				_lastClickTime = Time.unscaledTime;
				_onClick.Invoke();
			}
		}

		internal bool RecordHitTest(string reason)
		{
			if (_lastHitTestReason == reason)
			{
				return false;
			}
			_lastHitTestReason = reason;
			return true;
		}

		private void Update()
		{
			if (_onClick == null || !((Behaviour)this).isActiveAndEnabled)
			{
				return;
			}
			Mouse current = Mouse.current;
			if (current == null)
			{
				if (!_missingMouseReported && ((Object)((Component)this).gameObject).name == "REPOModSkillTree_UpgradeEntry")
				{
					_missingMouseReported = true;
					Plugin.Logger.LogWarning((object)"UPGRADES direct-click fallback cannot find the current mouse.");
				}
				return;
			}
			_missingMouseReported = false;
			if (!current.leftButton.isPressed)
			{
				_suppressNativeMenuClick = false;
			}
			if (!current.leftButton.wasPressedThisFrame)
			{
				return;
			}
			MenuButton component = ((Component)this).GetComponent<MenuButton>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			MenuPage componentInParent = ((Component)this).GetComponentInParent<MenuPage>();
			MenuManager instance = MenuManager.instance;
			NativeMenuButtonAdapter nativeMenuButtonAdapter = new NativeMenuButtonAdapter(component);
			RectTransform value = nativeMenuButtonAdapter.GetValue<RectTransform>(AccessTools.Field(typeof(MenuButton), "rectTransformSelection"));
			if ((Object)(object)value == (Object)null || !NativeMenuButtonRegistrationPatch.IsPointerInside(value, nativeMenuButtonAdapter.GetValue<bool>(AccessTools.Field(typeof(MenuButton), "customHoverArea")) ? 0f : 10f))
			{
				return;
			}
			string pageInputBlockReason = NativeMenuButtonRegistrationPatch.GetPageInputBlockReason(componentInParent, instance);
			if (pageInputBlockReason != null)
			{
				LogBlockedUpgradeClick(pageInputBlockReason);
				return;
			}
			CanvasGroup component2 = ((Component)this).gameObject.GetComponent<CanvasGroup>();
			if (nativeMenuButtonAdapter.Disabled || (Object)(object)nativeMenuButtonAdapter.Button == (Object)null || !((Selectable)nativeMenuButtonAdapter.Button).interactable || ((Object)(object)component2 != (Object)null && (component2.alpha < 0.99f || !component2.interactable || !component2.blocksRaycasts)))
			{
				LogBlockedUpgradeClick($"disabled={nativeMenuButtonAdapter.Disabled}, buttonInteractable={(Object)(object)nativeMenuButtonAdapter.Button != (Object)null && ((Selectable)nativeMenuButtonAdapter.Button).interactable}, " + $"canvasAlpha={(((Object)(object)component2 != (Object)null) ? component2.alpha : 1f):0.00}, " + $"canvasInteractable={(Object)(object)component2 == (Object)null || component2.interactable}, " + $"canvasRaycasts={(Object)(object)component2 == (Object)null || component2.blocksRaycasts}");
				return;
			}
			Plugin.Logger.LogInfo((object)("Dispatched direct screen click fallback for " + ((Object)((Component)this).gameObject).name + "."));
			SuppressNativeMenuClickForCurrentMousePress();
			InvokeClickAction();
		}

		private void LogBlockedUpgradeClick(string reason)
		{
			if (((Object)((Component)this).gameObject).name == "REPOModSkillTree_UpgradeEntry")
			{
				Plugin.Logger.LogWarning((object)("UPGRADES click was blocked because " + reason + "."));
			}
		}
	}
	[HarmonyPatch(typeof(SemiFunc), "InputUIClick")]
	internal static class NativeMenuClickSuppressionPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref bool __result)
		{
			if (!NativeMenuButtonHitboxMarker.SuppressNativeMenuClick)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(MenuButton), "OnHoverStart")]
	internal static class NativeMenuButtonHoverActionPatch
	{
		[HarmonyPostfix]
		private static void Postfix(MenuButton __instance)
		{
			if (__instance != null)
			{
				((Component)__instance).GetComponent<NativeMenuButtonHitboxMarker>()?.InvokeHoverAction();
			}
		}
	}
	[HarmonyPatch(typeof(MenuButton), "RegisterHover")]
	internal static class NativeMenuButtonRegistrationPatch
	{
		private static readonly FieldInfo CurrentMenuPageField = AccessTools.Field(typeof(MenuManager), "currentMenuPage");

		private static readonly FieldInfo CurrentMenuIdField = AccessTools.Field(typeof(MenuManager), "currentMenuID");

		private static readonly FieldInfo CurrentMenuIdTransformField = AccessTools.Field(typeof(MenuManager), "currentMenuIDTransform");

		private static readonly PropertyInfo PageInteractableProperty = AccessTools.Property(typeof(MenuPage), "isInteractable");

		private static readonly FieldInfo PagePriorityField = AccessTools.Field(typeof(MenuPage), "interactionPriority");

		private static readonly MethodInfo HighestOpenPriorityMethod = AccessTools.Method(typeof(MenuManager), "HighestOpenPriority", (Type[])null, (Type[])null);

		private static bool _missingHudWarningLogged;

		private static bool _missingPageInteractivityReported;

		[HarmonyPrefix]
		private static bool Prefix(MenuButton __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			NativeMenuButtonHitboxMarker component = ((Component)__instance).GetComponent<NativeMenuButtonHitboxMarker>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			NativeMenuButtonAdapter nativeMenuButtonAdapter = new NativeMenuButtonAdapter(__instance);
			RectTransform value = nativeMenuButtonAdapter.GetValue<RectTransform>(AccessTools.Field(typeof(MenuButton), "rectTransformSelection"));
			MenuPage componentInParent = ((Component)__instance).GetComponentInParent<MenuPage>();
			MenuManager instance = MenuManager.instance;
			if (!IsVisibleAndInteractive(nativeMenuButtonAdapter, out var _))
			{
				RecordUpgradeButtonHitTest(__instance, component, "not-visible-or-interactive", isInside: false);
				ClearHover(nativeMenuButtonAdapter, instance);
				return false;
			}
			if ((Object)(object)value == (Object)null || (Object)(object)componentInParent == (Object)null || (Object)(object)instance == (Object)null || !((Component)value).gameObject.activeInHierarchy)
			{
				string reason = (((Object)(object)value == (Object)null) ? "missing-selection-rect" : (((Object)(object)componentInParent == (Object)null) ? "missing-page" : (((Object)(object)instance == (Object)null) ? "missing-manager" : "inactive-selection-rect")));
				RecordUpgradeButtonHitTest(__instance, component, reason, isInside: false);
				ClearHover(nativeMenuButtonAdapter, instance);
				return false;
			}
			object? obj = CurrentMenuPageField?.GetValue(instance);
			if ((Object)((obj is MenuPage) ? obj : null) != (Object)(object)componentInParent)
			{
				RecordUpgradeButtonHitTest(__instance, component, "another-page-current", isInside: false);
				ClearHover(nativeMenuButtonAdapter, instance);
				return false;
			}
			string pageInputBlockReason = GetPageInputBlockReason(componentInParent, instance);
			if (pageInputBlockReason != null)
			{
				RecordUpgradeButtonHitTest(__instance, component, pageInputBlockReason, isInside: false);
				ClearHover(nativeMenuButtonAdapter, instance);
				return false;
			}
			float xPadding = (nativeMenuButtonAdapter.GetValue<bool>(AccessTools.Field(typeof(MenuButton), "customHoverArea")) ? 0f : 10f);
			bool flag = IsPointerInside(value, xPadding);
			RecordUpgradeButtonHitTest(__instance, component, flag ? "inside" : "outside", flag);
			if (!flag)
			{
				ClearHover(nativeMenuButtonAdapter, instance);
				return false;
			}
			if (Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame)
			{
				NativeMenuButtonHitboxMarker.SuppressNativeMenuClickForCurrentMousePress();
			}
			string value2 = nativeMenuButtonAdapter.EnsureSelectableMenuId();
			if (string.IsNullOrEmpty(value2))
			{
				Plugin.Logger.LogError((object)"Could not register hover for a MOD menu button because its selectable ID is empty.");
				return false;
			}
			CurrentMenuIdField?.SetValue(instance, value2);
			CurrentMenuIdTransformField?.SetValue(instance, value);
			return false;
		}

		internal static bool IsPointerInside(RectTransform rect, float xPadding)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetPointerLocal(rect, out var localPoint))
			{
				return false;
			}
			Rect rect2 = rect.rect;
			if (localPoint.x >= ((Rect)(ref rect2)).xMin - xPadding && localPoint.x <= ((Rect)(ref rect2)).xMax + xPadding && localPoint.y >= ((Rect)(ref rect2)).yMin)
			{
				return localPoint.y <= ((Rect)(ref rect2)).yMax;
			}
			return false;
		}

		internal static string GetPageInputBlockReason(MenuPage page, MenuManager manager)
		{
			if ((Object)(object)page == (Object)null || (Object)(object)manager == (Object)null)
			{
				return "missing-page-or-manager";
			}
			if (!((Component)page).gameObject.activeInHierarchy || (Object)(object)UpgradeMenuPageRegistry.GetCurrentPage() != (Object)(object)page)
			{
				return "page-not-active-or-current";
			}
			if (PageInteractableProperty == null || PagePriorityField == null || HighestOpenPriorityMethod == null)
			{
				if (!_missingPageInteractivityReported)
				{
					_missingPageInteractivityReported = true;
					Plugin.Logger.LogError((object)"Cannot verify native menu page interactivity: required members are unavailable.");
				}
				return "missing-page-interactivity-members";
			}
			object value = PageInteractableProperty.GetValue(page, null);
			object value2 = PagePriorityField.GetValue(page);
			object obj = HighestOpenPriorityMethod.Invoke(manager, null);
			if (!(value is bool flag) || !(value2 is int num) || !(obj is int num2))
			{
				if (!_missingPageInteractivityReported)
				{
					_missingPageInteractivityReported = true;
					Plugin.Logger.LogError((object)"Cannot verify native menu page interactivity: unexpected member values.");
				}
				return "invalid-page-interactivity-values";
			}
			_missingPageInteractivityReported = false;
			if (!flag)
			{
				return "native-page-not-interactable";
			}
			if (num2 > num)
			{
				return $"higher-priority-page-{num2}-over-{num}";
			}
			CanvasGroup component = ((Component)page).GetComponent<CanvasGroup>();
			if ((Object)(object)component != (Object)null && (!component.interactable || !component.blocksRaycasts))
			{
				return "page-canvas-not-interactable";
			}
			return null;
		}

		internal static bool TryGetPointerLocal(RectTransform rect, out Vector3 localPoint)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			localPoint = Vector3.zero;
			HUDCanvas instance = HUDCanvas.instance;
			RectTransform val = (((Object)(object)instance != (Object)null) ? ((Component)instance).GetComponent<RectTransform>() : null);
			if ((Object)(object)val == (Object)null)
			{
				if (!_missingHudWarningLogged)
				{
					_missingHudWarningLogged = true;
					Plugin.Logger.LogWarning((object)"Cannot test MOD menu buttons while the HUD canvas is unavailable.");
				}
				return false;
			}
			_missingHudWarningLogged = false;
			Vector2 val2 = SemiFunc.UIMousePosToUIPos();
			Rect rect2 = val.rect;
			Vector2 val3 = val2 + ((Rect)(ref rect2)).min;
			localPoint = ((Transform)rect).InverseTransformPoint(((Transform)val).TransformPoint(new Vector3(val3.x, val3.y, 0f)));
			return true;
		}

		private static void RecordUpgradeButtonHitTest(MenuButton button, NativeMenuButtonHitboxMarker marker, string reason, bool isInside)
		{
			if (((Object)((Component)button).gameObject).name == "REPOModSkillTree_UpgradeEntry" && marker.RecordHitTest(reason))
			{
				Plugin.Logger.LogInfo((object)$"UPGRADES screen hit test: inside={isInside}, reason={reason}.");
			}
		}

		private static bool IsVisibleAndInteractive(NativeMenuButtonAdapter button, out CanvasGroup canvasGroup)
		{
			canvasGroup = button.GameObject.GetComponent<CanvasGroup>();
			if ((Object)(object)canvasGroup == (Object)null)
			{
				return true;
			}
			if (canvasGroup.alpha >= 0.99f && canvasGroup.interactable)
			{
				return canvasGroup.blocksRaycasts;
			}
			return false;
		}

		private static void ClearHover(NativeMenuButtonAdapter button, MenuManager manager)
		{
			button.ResetHoverState();
			if (!((Object)(object)manager == (Object)null))
			{
				string text = button.EnsureSelectableMenuId();
				string text2 = CurrentMenuIdField?.GetValue(manager) as string;
				if (!string.IsNullOrEmpty(text) && text2 == text)
				{
					CurrentMenuIdField?.SetValue(manager, string.Empty);
					CurrentMenuIdTransformField?.SetValue(manager, null);
				}
			}
		}
	}
	[BepInPlugin("REPOModSkillTree", "REPO Skill Tree", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		private float _nextRewardRetryAt;

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			CreditDataStore.Load();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "REPOModSkillTree");
			Logger.LogInfo((object)string.Format("Plugin {0} is loaded; saved balance is {1}K.", "REPOModSkillTree", CreditDataStore.TotalCredits));
		}

		private void Update()
		{
			UpgradeMultiplayerSync.Update();
			if (FloorHaulTracker.HasUncommittedRewards && !(Time.unscaledTime < _nextRewardRetryAt))
			{
				_nextRewardRetryAt = Time.unscaledTime + 5f;
				FloorHaulTracker.RetryUncommittedRewards();
			}
		}

		private void OnGUI()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			float num = 20f;
			if (FloorHaulTracker.HasUncommittedRewards)
			{
				GUI.Box(new Rect(((float)Screen.width - 560f) / 2f, num, 560f, 40f), "SKILL TREE: SAVE FAILED. Keep the game open while saving is retried.");
				num += 45f;
			}
			if (UpgradeMultiplayerSync.ShowHostRequiredWarning)
			{
				GUI.Box(new Rect(((float)Screen.width - 560f) / 2f, num, 560f, 40f), "SKILL TREE: host MOD required; permanent bonuses will not be added.");
			}
		}

		private void OnDestroy()
		{
			if (FloorHaulTracker.HasUncommittedRewards)
			{
				Logger.LogError((object)"The game is closing while cleared-floor rewards are still unsaved.");
			}
		}
	}
	internal sealed class UpgradePageTemplateMarker : MonoBehaviour
	{
	}
	internal static class UpgradeMenuPageRegistry
	{
		private static MenuPageIndex? _pageIndex;

		private static GameObject _pageTemplate;

		private static MenuManager _registeredManager;

		private static MenuPages _registeredEntry;

		private static GameObject _templateHost;

		internal static MenuPageIndex PageIndex => _pageIndex ?? throw new InvalidOperationException("The upgrade menu page has not been registered.");

		internal static bool IsCurrentPage()
		{
			return IsUpgradePage(GetCurrentPage());
		}

		internal static bool IsUpgradePage(MenuPage page)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)page != (Object)null && _pageIndex.HasValue && page.menuPageIndex == _pageIndex.Value)
			{
				return (Object)(object)((Component)page).GetComponent<UpgradePageTemplateMarker>() != (Object)null;
			}
			return false;
		}

		internal static MenuPage GetCurrentPage()
		{
			object? obj = AccessTools.Field(typeof(MenuManager), "currentMenuPage")?.GetValue(MenuManager.instance);
			return (MenuPage)((obj is MenuPage) ? obj : null);
		}

		internal static bool FitPageToCanvas(MenuPage page, MenuPage referencePage)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)page == (Object)null || (Object)(object)referencePage == (Object)null)
			{
				return false;
			}
			RectTransform component = ((Component)page).GetComponent<RectTransform>();
			RectTransform component2 = ((Component)referencePage).GetComponent<RectTransform>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null)
			{
				return false;
			}
			Rect rect = component2.rect;
			if (!(((Rect)(ref rect)).width <= 0f))
			{
				rect = component2.rect;
				if (!(((Rect)(ref rect)).height <= 0f))
				{
					component.anchorMin = component2.anchorMin;
					component.anchorMax = component2.anchorMax;
					component.pivot = component2.pivot;
					component.sizeDelta = component2.sizeDelta;
					component.anchoredPosition = component2.anchoredPosition;
					((Transform)component).localScale = ((Transform)component2).localScale;
					rect = component.rect;
					if (((Rect)(ref rect)).width > 0f)
					{
						rect = component.rect;
						return ((Rect)(ref rect)).height > 0f;
					}
					return false;
				}
			}
			rect = component.rect;
			if (((Rect)(ref rect)).width > 0f)
			{
				rect = component.rect;
				if (((Rect)(ref rect)).height > 0f)
				{
					Canvas componentInParent = ((Component)page).GetComponentInParent<Canvas>();
					ManualLogSource logger = Plugin.Logger;
					rect = component.rect;
					logger.LogInfo((object)("Main page has no measurable RectTransform; preserving the upgrade page's native Canvas geometry " + string.Format("(page={0}, canvas={1}).", ((Rect)(ref rect)).size, ((Object)(object)componentInParent != (Object)null) ? ((Object)componentInParent).name : "missing")));
					return true;
				}
			}
			Transform parent = ((Transform)component).parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if ((Object)(object)val != (Object)null)
			{
				rect = val.rect;
				if (((Rect)(ref rect)).width > 0f)
				{
					rect = val.rect;
					if (((Rect)(ref rect)).height > 0f)
					{
						component.anchorMin = Vector2.zero;
						component.anchorMax = Vector2.one;
						component.pivot = val.pivot;
						component.offsetMin = Vector2.zero;
						component.offsetMax = Vector2.zero;
						component.anchoredPosition = Vector2.zero;
						((Transform)component).localScale = Vector3.one;
						rect = component.rect;
						if (((Rect)(ref rect)).width > 0f)
						{
							rect = component.rect;
							return ((Rect)(ref rect)).height > 0f;
						}
						return false;
					}
				}
			}
			Canvas componentInParent2 = ((Component)page).GetComponentInParent<Canvas>();
			RectTransform val2 = (((Object)(object)componentInParent2 != (Object)null) ? ((Component)componentInParent2).GetComponent<RectTransform>() : null);
			if (!((Object)(object)((Transform)component).parent == (Object)null) && !((Object)(object)val2 == (Object)null))
			{
				rect = val2.rect;
				if (!(((Rect)(ref rect)).width <= 0f))
				{
					rect = val2.rect;
					if (!(((Rect)(ref rect)).height <= 0f))
					{
						Vector3[] array = (Vector3[])(object)new Vector3[4];
						val2.GetWorldCorners(array);
						float num = float.PositiveInfinity;
						float num2 = float.NegativeInfinity;
						float num3 = float.PositiveInfinity;
						float num4 = float.NegativeInfinity;
						Vector3[] array2 = array;
						foreach (Vector3 val3 in array2)
						{
							Vector3 val4 = ((Transform)component).parent.InverseTransformPoint(val3);
							num = Mathf.Min(num, val4.x);
							num2 = Mathf.Max(num2, val4.x);
							num3 = Mathf.Min(num3, val4.y);
							num4 = Mathf.Max(num4, val4.y);
						}
						if (num2 <= num || num4 <= num3)
						{
							Plugin.Logger.LogError((object)"Could not convert Canvas geometry to the upgrade page's parent space.");
							return false;
						}
						component.anchorMin = new Vector2(0.5f, 0.5f);
						component.anchorMax = new Vector2(0.5f, 0.5f);
						component.pivot = new Vector2(0.5f, 0.5f);
						component.sizeDelta = new Vector2(num2 - num, num4 - num3);
						((Transform)component).localScale = Vector3.one;
						((Transform)component).localRotation = Quaternion.identity;
						((Transform)component).localPosition = new Vector3((num + num2) * 0.5f, (num3 + num4) * 0.5f, ((Transform)component).localPosition.z);
						ManualLogSource logger2 = Plugin.Logger;
						rect = component.rect;
						logger2.LogInfo((object)$"Sized the independent upgrade page from Canvas geometry: {((Rect)(ref rect)).size}.");
						rect = component.rect;
						if (((Rect)(ref rect)).width > 0f)
						{
							rect = component.rect;
							return ((Rect)(ref rect)).height > 0f;
						}
						return false;
					}
				}
			}
			Plugin.Logger.LogError((object)"Neither the Main page, upgrade page, MenuHolder, nor Canvas has measurable geometry.");
			return false;
		}

		internal static bool EnsureRegistered()
		{
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected I4, but got Unknown
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: 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_01c5: Expected I4, but got Unknown
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Expected I4, but got Unknown
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Expected O, but got Unknown
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Expected O, but got Unknown
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invali