Decompiled source of Progress Editor v1.0.0

BepInEx/plugins/ProgressEditor/ProgressEditor.dll

Decompiled 21 hours ago
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using CG.Client.PlayerData;
using CG.Client.UserData;
using CG.Cloud;
using CG.Game;
using CG.Network;
using CG.Profile;
using Client.Player.Interactions;
using ExitGames.Client.Photon;
using Gameplay.Perks;
using HarmonyLib;
using Newtonsoft.Json;
using Photon.Pun;
using Photon.Realtime;
using ResourceAssets;
using UI.Core;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace VoidCrewProgressEditor;

internal static class ProfileUIRefresh
{
	private const BindingFlags Members = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private static readonly HashSet<string> reportedErrors = new HashSet<string>();

	internal static void RefreshCosmetics(ManualLogSource log)
	{
		ForSceneObjects("AchievementsUIController", log, delegate(object controller)
		{
			if (Field(controller, "tabHeader") != null)
			{
				Invoke(controller, "UpdateAllEntries", null);
				Invoke(controller, "UpdateUnclaimed", null);
				Invoke(controller, "SortEntries", null);
			}
		});
		ForSceneObjects("UI.PersonalLoadout.PersonalLoadoutTerminal", log, delegate(object terminal)
		{
			if (Field(terminal, "root") != null && Field(terminal, "selectionPanel") != null)
			{
				MethodInfo method = terminal.GetType().GetMethod("UpdateUnseen", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				if (method != null)
				{
					method.Invoke(terminal, null);
				}
				object obj = Field(terminal, "shownCategory");
				if (obj != null)
				{
					Invoke(terminal, "SelectedCategory", new object[2]
					{
						obj,
						Field(terminal, "selectedMultiSlotIndex")
					});
				}
			}
		});
	}

	internal static void RefreshShips(ManualLogSource log)
	{
		ForSceneObjects("UI.ShipLoadoutTerminal.ShipLoadoutTerminal", log, delegate(object terminal)
		{
			object obj = Field(terminal, "loadoutList");
			if (Field(terminal, "root") != null && obj != null)
			{
				if ((bool)Field(obj, "IgnoreRankRequirements"))
				{
					Invoke(obj, "RefreshLoadouts", null);
				}
				else
				{
					ShipLoadoutDataContainer instance = ResourceAssetContainer<ShipLoadoutDataContainer, ShipLoadoutData, ShipLoadoutDataDef>.Instance;
					if (!((Object)(object)instance == (Object)null))
					{
						List<ShipLoadoutDataDef> list = new List<ShipLoadoutDataDef>();
						list.AddRange(instance.GetUnlockedShipDefinitionsFromHighestRankPlayer());
						list.AddRange(instance.GetLockedShipDefinitionsFromHighestRankPlayer());
						if (list.Count != 0)
						{
							object value = obj.GetType().GetProperty("ShipListed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetValue(obj, null);
							Invoke(obj, "SetLoadouts", new object[2] { list, value });
						}
					}
				}
			}
		});
	}

	internal static void NotifyPlayerProperties(ManualLogSource log)
	{
		Attempt("player rank properties", log, delegate
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			PlayerProfile instance = PlayerProfile.Instance;
			if (instance != null && PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null)
			{
				Hashtable val = new Hashtable();
				((Dictionary<object, object>)(object)val).Add((object)"RP_PR", (object)instance.Profile.Rank);
				((Dictionary<object, object>)(object)val).Add((object)"RP_FR", (object)instance.Profile.FavorRank);
				PhotonNetwork.LocalPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			}
		});
	}

	internal static void Refresh(ManualLogSource log)
	{
		if (PlayerProfile.Instance == null)
		{
			return;
		}
		Attempt("rank event", log, delegate
		{
			if ((Object)(object)ClientGame.Current != (Object)null)
			{
				ClientGame.Current.ModelEventBus.OnRankChanged.Publish();
			}
		});
		RefreshShips(log);
		RefreshBars("TitleMenu", "_expBar", null, log);
		RefreshBars("EscapeMenu", "expBar", null, log);
		RefreshBars("UI.PersonalLoadout.PersonalLoadoutTerminal", "expBar", "rankingOverview", log);
		ForSceneObjects("RankingPanel", log, delegate(object panel)
		{
			object obj = Field(panel, "root");
			VisualElement val = (VisualElement)((obj is VisualElement) ? obj : null);
			if (val != null && Field(panel, "leftPanel") != null && Field(panel, "rightPanel") != null)
			{
				List<VisualElement> list = Field(panel, "rankEntries") as List<VisualElement>;
				int rank = PlayerProfile.Instance.Profile.Rank;
				if (list != null)
				{
					for (int i = 0; i < list.Count; i++)
					{
						list[i].RemoveFromClassList("rank__past");
						list[i].RemoveFromClassList("rank__current");
						list[i].RemoveFromClassList("rank__future");
						list[i].AddToClassList((i < rank) ? "rank__past" : ((i == rank) ? "rank__current" : "rank__future"));
					}
				}
				object[] args = new object[1];
				Invoke(panel, "Enter", args);
			}
		});
		RefreshBars("RankingPanel", "expBar", "root", log);
		ForSceneObjects("UI.Token.TokenTerminal", log, delegate(object terminal)
		{
			if (Field(terminal, "mainLabel") != null)
			{
				Invoke(terminal, "UpdateLeftSide", null);
				Invoke(terminal, "UpdateTrees", null);
			}
		});
	}

	private static void RefreshBars(string type, string barField, string rootField, ManualLogSource log)
	{
		ForSceneObjects(type, log, delegate(object owner)
		{
			object obj = Field(owner, barField);
			if (obj != null && (rootField == null || Field(owner, rootField) != null) && (rootField != null || Field(obj, "rankDisplay") != null))
			{
				Invoke(owner, "UpdateXpBar", null);
				Invoke(obj, "SkipToEndSequence", null);
			}
		});
	}

	private static object Field(object owner, string name)
	{
		FieldInfo field = owner.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field == null)
		{
			throw new MissingFieldException(owner.GetType().FullName, name);
		}
		return field.GetValue(owner);
	}

	private static void Invoke(object owner, string name, object[] args)
	{
		MethodInfo method = owner.GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (method == null)
		{
			throw new MissingMethodException(owner.GetType().FullName, name);
		}
		method.Invoke(owner, args);
	}

	private static void ForSceneObjects(string typeName, ManualLogSource log, Action<object> action)
	{
		//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)
		Type type = typeof(PlayerProfile).Assembly.GetType(typeName);
		if (type == null)
		{
			Attempt(typeName, log, delegate
			{
				throw new TypeLoadException(typeName);
			});
			return;
		}
		Object[] array = Resources.FindObjectsOfTypeAll(type);
		foreach (Object item in array)
		{
			Object obj = item;
			Component val = (Component)(object)((obj is Component) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Scene scene = val.gameObject.scene;
			if (((Scene)(ref scene)).IsValid())
			{
				Attempt(typeName, log, delegate
				{
					action(item);
				});
			}
		}
	}

	private static void Attempt(string label, ManualLogSource log, Action action)
	{
		try
		{
			action();
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex is TargetInvocationException && ex.InnerException != null) ? ex.InnerException : ex);
			string item = label + ": " + ex2.Message;
			if (reportedErrors.Add(item))
			{
				log.LogWarning((object)("Profile UI refresh skipped " + label + ": " + ex2));
			}
		}
	}
}
[BepInProcess("Void Crew.exe")]
[BepInPlugin("local.VoidCrewProgressEditor", "Progress Editor", "1.0.0")]
public sealed class ProgressEditor : BaseUnityPlugin
{
	internal string xp = "";

	internal string rank = "";

	internal string favor = "";

	internal string status = "";

	private ProgressUndoHistory progressHistory;

	private string lastError;

	private float refreshAt = -1f;

	private long favorSliderMaximum = 100L;

	private Channel rankChangedChannel;

	private bool rankReloadPending;

	private PlayerProfileData lastLoadedProfile;

	private long lastLoadedXp;

	private int lastLoadedRank;

	private int lastLoadedFavor;

	private PluginUnlockLedger pluginUnlocks;

	internal bool HasProgressUndo
	{
		get
		{
			try
			{
				return progressHistory != null && progressHistory.Peek(PlayerProfile.GetPlayerUniqueID()) != null;
			}
			catch
			{
				return false;
			}
		}
	}

	internal long FavorSliderMaximum
	{
		get
		{
			if (int.TryParse(favor, out var result))
			{
				favorSliderMaximum = Math.Max(favorSliderMaximum, result);
			}
			return favorSliderMaximum;
		}
	}

	private void Awake()
	{
		((MonoBehaviour)this).useGUILayout = false;
		try
		{
			pluginUnlocks = new PluginUnlockLedger();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
		}
		try
		{
			progressHistory = new ProgressUndoHistory(Path.Combine(Paths.ConfigPath, "ProgressEditor-rank-history.json"));
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)ex2);
		}
		SteamAwardGuard.Install(((BaseUnityPlugin)this).Logger);
		try
		{
			PauseProgressScreen.Install(this);
		}
		catch (Exception ex3)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Pause menu integration failed: " + ex3));
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Progress Editor initialized. Use Edit Progress in the main or pause menu.");
	}

	private void ReportError(Exception ex)
	{
		status = "Editor error: " + ex.Message + " (see BepInEx log).";
		string text = ex.ToString();
		if (lastError != text)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)text);
			lastError = text;
		}
	}

	internal void NativeLog(string text)
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)text);
	}

	internal void NativeError(Exception ex)
	{
		((BaseUnityPlugin)this).Logger.LogError((object)ex);
	}

	internal void OpenNativeEditor()
	{
		try
		{
			Reload();
		}
		catch (Exception ex)
		{
			ReportError(ex);
		}
	}

	private void Update()
	{
		BindRankChangedEvent();
		if (refreshAt >= 0f && Time.unscaledTime >= refreshAt)
		{
			refreshAt = -1f;
			ProfileUIRefresh.Refresh(((BaseUnityPlugin)this).Logger);
		}
		if (rankReloadPending)
		{
			rankReloadPending = false;
			ProfileUIRefresh.RefreshShips(((BaseUnityPlugin)this).Logger);
			try
			{
				if (TryProfile(out var _, out var data) && (!object.ReferenceEquals(data, lastLoadedProfile) || data.Xp != lastLoadedXp || data.Rank != lastLoadedRank || data.FavorRank != lastLoadedFavor))
				{
					Reload();
				}
			}
			catch (Exception ex)
			{
				ReportError(ex);
			}
		}
		PauseProgressScreen.UpdateOpenScreens();
	}

	private void BindRankChangedEvent()
	{
		ClientGame current = ClientGame.Current;
		Channel objA = (((Object)(object)current != (Object)null && (Object)(object)current.ModelEventBus != (Object)null) ? current.ModelEventBus.OnRankChanged : null);
		if (!object.ReferenceEquals(objA, rankChangedChannel))
		{
			UnbindRankChangedEvent();
			rankChangedChannel = objA;
			if (rankChangedChannel != null)
			{
				rankChangedChannel.Subscribe((Action)OnProfileRankChanged, (AutoUnsubscribeCollection)null);
				rankReloadPending = true;
			}
		}
	}

	private void OnProfileRankChanged()
	{
		rankReloadPending = true;
	}

	private void UnbindRankChangedEvent()
	{
		if (rankChangedChannel != null)
		{
			rankChangedChannel.Unsubscribe((Action)OnProfileRankChanged);
		}
		rankChangedChannel = null;
	}

	private void OnDisable()
	{
		UnbindRankChangedEvent();
	}

	private void OnDestroy()
	{
		UnbindRankChangedEvent();
	}

	private bool TryProfile(out CloudPlayerProfileDataSync cloud, out PlayerProfileData data)
	{
		cloud = null;
		data = null;
		PlayerProfile instance = PlayerProfile.Instance;
		if (instance == null)
		{
			return false;
		}
		IPlayerProfileData profile = instance.Profile;
		cloud = (CloudPlayerProfileDataSync)(object)((profile is CloudPlayerProfileDataSync) ? profile : null);
		object source = GetSource(cloud);
		PhotonPlayerDataSync wrapper = (PhotonPlayerDataSync)((source is PhotonPlayerDataSync) ? source : null);
		object source2 = GetSource(wrapper);
		data = (PlayerProfileData)((source2 is PlayerProfileData) ? source2 : null);
		return data != null;
	}

	private static object GetSource(object wrapper)
	{
		if (wrapper == null)
		{
			return null;
		}
		Type type = wrapper.GetType();
		while (type != null)
		{
			PropertyInfo property = type.GetProperty("source", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				return property.GetValue(wrapper, null);
			}
			type = type.BaseType;
		}
		return null;
	}

	private void Reload()
	{
		if (!TryProfile(out var _, out var data))
		{
			status = "Profile unavailable. Load your profile first.";
			return;
		}
		xp = data.Xp.ToString(CultureInfo.InvariantCulture);
		rank = data.Rank.ToString(CultureInfo.InvariantCulture);
		favor = data.FavorRank.ToString(CultureInfo.InvariantCulture);
		favorSliderMaximum = Math.Max(100, data.FavorRank);
		lastLoadedProfile = data;
		lastLoadedXp = data.Xp;
		lastLoadedRank = data.Rank;
		lastLoadedFavor = data.FavorRank;
		status = "Values loaded from your profile.";
	}

	internal bool IsCosmeticCategoryEnabled(string category)
	{
		try
		{
			return pluginUnlocks != null && pluginUnlocks.IsEnabled(category);
		}
		catch
		{
			return false;
		}
	}

	internal void SetCosmeticCategory(string category, bool enabled)
	{
		try
		{
			if (category != "Lootbox" && category != "Seasonal" && category != "Achievement")
			{
				throw new ArgumentException("Unknown cosmetic category.");
			}
			if (pluginUnlocks == null)
			{
				throw new InvalidOperationException("Plugin unlock ledger is unavailable.");
			}
			pluginUnlocks.SetEnabled(category, enabled);
			RefreshProfileDisplays();
			ProfileUIRefresh.RefreshCosmetics(((BaseUnityPlugin)this).Logger);
			status = (enabled ? (category + " cosmetics enabled.") : (category + " plugin unlocks removed; previous ownership and achievement state restored."));
			((BaseUnityPlugin)this).Logger.LogInfo((object)status);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
			status = "Cosmetic change failed: " + ex.Message;
		}
	}

	internal static bool TryGetMaximumXp(string rankText, out long maximum)
	{
		maximum = 0L;
		if (!int.TryParse(rankText, NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result > 30)
		{
			return false;
		}
		PlayerRanksTable instance = PlayerRanksTable.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			return false;
		}
		if (result == 30)
		{
			maximum = instance.FavorXpPerRank;
		}
		else
		{
			if (instance.titles == null || instance.titles.Length <= result + 1 || instance.titles[result + 1] == null)
			{
				return false;
			}
			maximum = instance.titles[result + 1].rankExp;
		}
		return maximum > 0;
	}

	internal void Apply()
	{
		if (!long.TryParse(xp, NumberStyles.None, CultureInfo.InvariantCulture, out var result) || !int.TryParse(rank, NumberStyles.None, CultureInfo.InvariantCulture, out var result2) || !int.TryParse(favor, NumberStyles.None, CultureInfo.InvariantCulture, out var result3))
		{
			status = "Use non-negative whole numbers within the field's integer range.";
			return;
		}
		if (result2 > 30)
		{
			status = "Rank must be between 0 and 30; nothing changed.";
			return;
		}
		string text = ProgressValidation.ValidateFavor(result2, result3);
		if (text != null)
		{
			status = text;
			return;
		}
		PlayerRanksTable instance = PlayerRanksTable.Instance;
		if ((Object)(object)instance == (Object)null || (result2 < 30 && (instance.titles == null || instance.titles.Length <= result2 + 1 || instance.titles[result2 + 1] == null)))
		{
			status = "The game's XP thresholds are not loaded; nothing changed.";
			return;
		}
		long maximumXp = ((result2 == 30) ? instance.FavorXpPerRank : instance.titles[result2 + 1].rankExp);
		string text2 = ProgressValidation.Validate(result, result2, maximumXp);
		if (text2 != null)
		{
			status = text2;
			return;
		}
		if (!TryProfile(out var cloud, out var data))
		{
			status = "Profile unavailable; nothing changed.";
			return;
		}
		if (data.Xp == result && data.Rank == result2 && data.FavorRank == result3)
		{
			status = "No values changed.";
			return;
		}
		try
		{
			GeneSnapshot geneSnapshot = GeneSnapshot.Capture();
			GenePlan genePlan = ((result2 < data.Rank) ? new GenePlan(geneSnapshot) : null);
			if (progressHistory == null)
			{
				throw new InvalidOperationException("Rank undo history is unavailable; edit cancelled.");
			}
			int num = Math.Max(0, data.Rank - result2);
			progressHistory.Push(PlayerProfile.GetPlayerUniqueID(), new ProgressUndoEntry
			{
				savedUtc = DateTime.UtcNow.ToString("o"),
				xp = data.Xp,
				rank = data.Rank,
				favor = data.FavorRank,
				loadouts = geneSnapshot.SaveLevels()
			});
			SetValues(cloud, data, result, result2, result3, publish: false);
			string text3 = "";
			if (num > 0)
			{
				List<int> removed;
				List<Dictionary<PerkBuff, int>> target = genePlan.Reduce(geneSnapshot, num, out removed);
				geneSnapshot.Commit(target);
				for (int i = 0; i < removed.Count; i++)
				{
					string text4 = "Loadout " + (i + 1) + ": removed " + removed[i] + "/" + num + " gene points. ";
					text3 += text4;
					((BaseUnityPlugin)this).Logger.LogInfo((object)text4);
				}
			}
			RefreshProfileDisplays();
			Reload();
			status = "Applied. " + text3;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
			status = "Edit failed or sync incomplete. Reload to inspect; undo is available if values changed.";
		}
	}

	internal void Undo()
	{
		if (!TryProfile(out var cloud, out var data))
		{
			status = "Profile unavailable; undo was not applied.";
			return;
		}
		try
		{
			if (progressHistory == null)
			{
				throw new InvalidOperationException("Rank undo history is unavailable.");
			}
			string playerUniqueID = PlayerProfile.GetPlayerUniqueID();
			ProgressUndoEntry progressUndoEntry = progressHistory.Peek(playerUniqueID);
			if (progressUndoEntry == null)
			{
				status = "No saved rank edits to undo.";
				return;
			}
			GeneSnapshot geneSnapshot = GeneSnapshot.Capture();
			List<Dictionary<PerkBuff, int>> target = geneSnapshot.ResolveLevels(progressUndoEntry.loadouts);
			SetValues(cloud, data, progressUndoEntry.xp, progressUndoEntry.rank, progressUndoEntry.favor, publish: false);
			geneSnapshot.Commit(target);
			progressHistory.Pop(playerUniqueID, progressUndoEntry);
			RefreshProfileDisplays();
			Reload();
			status = "Restored rank, XP, favor rank, and saved gene loadouts from history.";
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
			status = "Undo failed or sync incomplete; the history entry was retained if restoration did not finish.";
		}
	}

	private static void SetValues(CloudPlayerProfileDataSync cloud, PlayerProfileData data, long newXp, int newRank, int newFavor, bool publish)
	{
		data.Xp = newXp;
		data.Rank = newRank;
		data.FavorRank = newFavor;
		cloud.AddXp(0L);
		if (publish)
		{
			PublishRankChanged();
		}
	}

	private void RefreshProfileDisplays()
	{
		ProfileUIRefresh.NotifyPlayerProperties(((BaseUnityPlugin)this).Logger);
		ProfileUIRefresh.Refresh(((BaseUnityPlugin)this).Logger);
		refreshAt = Time.unscaledTime + 0.25f;
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Refreshed profile displays; one follow-up refresh scheduled.");
	}

	private static void PublishRankChanged()
	{
		if (GameSessionManager.ActiveSession != null && (Object)(object)ClientGame.Current != (Object)null)
		{
			ClientGame.Current.ModelEventBus.OnRankChanged.Publish();
		}
	}
}
internal sealed class CosmeticPlan
{
	internal readonly Dictionary<GUIDUnion, IResourceAssetContainer> Items = new Dictionary<GUIDUnion, IResourceAssetContainer>();

	internal readonly HashSet<GUIDUnion> Achievements = new HashSet<GUIDUnion>();

	private static bool IsCosmetic(IUnlockableDataContainer owner)
	{
		//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_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Expected I4, but got Unknown
		EUnlockCategory category = owner.Category;
		switch (category - 9)
		{
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
		case 12:
			return true;
		default:
			return false;
		}
	}

	internal CosmeticPlan(string category)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: 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_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_0369: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_038f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: 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_02d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d9: Invalid comparison between Unknown and I4
		//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b6: Invalid comparison between Unknown and I4
		//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e3: Invalid comparison between Unknown and I4
		//IL_0440: Unknown result type (might be due to invalid IL or missing references)
		//IL_0403: Unknown result type (might be due to invalid IL or missing references)
		//IL_0409: Invalid comparison between Unknown and I4
		//IL_040f: Unknown result type (might be due to invalid IL or missing references)
		//IL_03db: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_049b: Unknown result type (might be due to invalid IL or missing references)
		GUIDUnion val = GUIDUnion.Empty();
		if (category == "Hunter")
		{
			HashSet<GUIDUnion> hashSet = new HashSet<GUIDUnion>();
			List<AchievementDef> list = new List<AchievementDef>(((ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>)(object)ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>.Instance).AssetDescriptions);
			if (((ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>)(object)ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>.Instance).RuntimeDescriptions != null)
			{
				list.AddRange(((ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>)(object)ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>.Instance).RuntimeDescriptions);
			}
			foreach (AchievementDef item in list)
			{
				IResourceAssetContextInfo contextInfo = item.ContextInfo;
				ContextInfo val2 = (ContextInfo)(object)((contextInfo is ContextInfo) ? contextInfo : null);
				string text = (((Object)(object)val2 == (Object)null || val2.HeaderDefaultableLocalizedString == null) ? "" : val2.HeaderDefaultableLocalizedString.FallBackString);
				string text2 = Regex.Replace((text + " " + (((Object)(object)val2 == (Object)null) ? "" : val2.HeaderText) + " " + ((ResourceAssetDef<Achievement>)(object)item).Path + " " + ((ResourceAssetDef<Achievement>)(object)item).Asset.AchievementID).ToLowerInvariant(), "[^a-z0-9]", "");
				if (text2.Contains("hunterofhollow") || text2.Contains("hunterofthehollow"))
				{
					hashSet.Add(((ResourceAssetDef<Achievement>)(object)item).AssetGuid);
				}
			}
			if (hashSet.Count != 1)
			{
				throw new InvalidOperationException("Hunter of Hollow could not be identified uniquely; nothing unlocked.");
			}
			foreach (GUIDUnion item2 in hashSet)
			{
				val = item2;
			}
			Achievements.Add(val);
		}
		ResourceAssetContainerRegister instance = ResourceAssetContainerRegister.Instance;
		UnlockContainer instance2 = ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>.Instance;
		RewardPoolContainer instance3 = ResourceAssetContainer<RewardPoolContainer, RewardPool, RewardPoolDef>.Instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || (Object)(object)instance3 == (Object)null)
		{
			throw new InvalidOperationException("Cosmetic definitions are not loaded.");
		}
		HashSet<GUIDUnion> hashSet2 = new HashSet<GUIDUnion>();
		HashSet<GUIDUnion> hashSet3 = new HashSet<GUIDUnion>();
		HashSet<GUIDUnion> hashSet4 = new HashSet<GUIDUnion>();
		List<RewardPoolDef> list2 = new List<RewardPoolDef>(((ResourceAssetContainer<RewardPoolContainer, RewardPool, RewardPoolDef>)(object)instance3).AssetDescriptions);
		if (((ResourceAssetContainer<RewardPoolContainer, RewardPool, RewardPoolDef>)(object)instance3).RuntimeDescriptions != null)
		{
			list2.AddRange(((ResourceAssetContainer<RewardPoolContainer, RewardPool, RewardPoolDef>)(object)instance3).RuntimeDescriptions);
		}
		if (category == "Lootbox" || category == "Seasonal")
		{
			foreach (RewardPoolDef item3 in list2)
			{
				RewardPool asset = ((ResourceAssetDef<RewardPool>)(object)item3).Asset;
				if ((Object)(object)asset == (Object)null || asset.Rewards == null)
				{
					throw new InvalidOperationException("A reward pool could not be read.");
				}
				foreach (UnlockItemRef reward in asset.Rewards)
				{
					hashSet4.Add(((ResourceAssetRef)reward).AssetGuid);
					if ((int)item3.category == 0)
					{
						hashSet2.Add(((ResourceAssetRef)reward).AssetGuid);
					}
					if ((int)item3.category == 1 || (int)item3.category == 2)
					{
						hashSet3.Add(((ResourceAssetRef)reward).AssetGuid);
					}
				}
			}
		}
		List<UnlockItemDef> list3 = new List<UnlockItemDef>(((ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>)(object)instance2).AssetDescriptions);
		if (((ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>)(object)instance2).RuntimeDescriptions != null)
		{
			list3.AddRange(((ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>)(object)instance2).RuntimeDescriptions);
		}
		foreach (UnlockItemDef item4 in list3)
		{
			IUnlockableDataContainer val3 = instance.FindOwner(((ResourceAssetDef<Object>)(object)item4).AssetGuid);
			if (val3 == null || !IsCosmetic(val3))
			{
				continue;
			}
			UnlockOptions unlockOptions = item4.UnlockOptions;
			bool num;
			if (!(category == "Seasonal"))
			{
				if (!(category == "Lootbox"))
				{
					if ((int)unlockOptions.UnlockCriteria != 6)
					{
						continue;
					}
					if (!(category != "Hunter"))
					{
						if (!((ResourceAssetRef)(object)unlockOptions.RequiredAchievement != (ResourceAssetRef)null))
						{
							continue;
						}
						num = ((ResourceAssetRef)unlockOptions.RequiredAchievement).AssetGuid == val;
						goto IL_0432;
					}
				}
				else if (!hashSet2.Contains(((ResourceAssetDef<Object>)(object)item4).AssetGuid))
				{
					if ((int)unlockOptions.UnlockCriteria != 4)
					{
						continue;
					}
					num = !hashSet4.Contains(((ResourceAssetDef<Object>)(object)item4).AssetGuid);
					goto IL_0432;
				}
				goto IL_0438;
			}
			num = hashSet3.Contains(((ResourceAssetDef<Object>)(object)item4).AssetGuid);
			goto IL_0432;
			IL_0438:
			Items[((ResourceAssetDef<Object>)(object)item4).AssetGuid] = (IResourceAssetContainer)(object)val3;
			if (category == "Achievement" || category == "Hunter")
			{
				AchievementRef requiredAchievement = unlockOptions.RequiredAchievement;
				if ((ResourceAssetRef)(object)requiredAchievement == (ResourceAssetRef)null || (Object)(object)((ResourceAssetRef<AchievementContainer, Achievement, AchievementDef>)(object)requiredAchievement).Asset == (Object)null)
				{
					throw new InvalidOperationException("A cosmetic achievement definition could not be read.");
				}
				Achievements.Add(((ResourceAssetRef)requiredAchievement).AssetGuid);
			}
			continue;
			IL_0432:
			if (!num)
			{
				continue;
			}
			goto IL_0438;
		}
	}
}
[Serializable]
public sealed class PluginItemRecord
{
	public string id;

	public bool unseen;

	public List<string> categories = new List<string>();
}
[Serializable]
public sealed class PluginAchievementRecord
{
	public string id;

	public string steamId;

	public string metricId;

	public List<string> categories = new List<string>();

	public bool completed;

	public bool claimed;

	public bool metricExisted;

	public int metricProgress;

	public int liveProgress;
}
[Serializable]
public sealed class PluginUnlockData
{
	public string account;

	public int categorySchema;

	public List<string> enabledCategories = new List<string>();

	public List<PluginItemRecord> items = new List<PluginItemRecord>();

	public List<PluginAchievementRecord> achievements = new List<PluginAchievementRecord>();
}
internal sealed class PluginUnlockLedger
{
	private readonly string path = Path.Combine(Paths.ConfigPath, "ProgressEditor-plugin-unlocks.json");

	internal PluginUnlockData Data = new PluginUnlockData();

	internal bool HasChanges
	{
		get
		{
			if (Data.items.Count <= 0)
			{
				return Data.achievements.Count > 0;
			}
			return true;
		}
	}

	internal PluginUnlockLedger()
	{
		if (File.Exists(path))
		{
			Data = JsonUtility.FromJson<PluginUnlockData>(File.ReadAllText(path));
			if (Data == null || Data.items == null || Data.achievements == null)
			{
				throw new InvalidOperationException("Plugin unlock ledger is invalid; unlock actions disabled.");
			}
		}
		SteamAwardGuard.Ledger = this;
	}

	internal void CheckAccount()
	{
		string playerUniqueID = PlayerProfile.GetPlayerUniqueID();
		if (string.IsNullOrEmpty(playerUniqueID))
		{
			throw new InvalidOperationException("Player account is not ready.");
		}
		if (HasChanges && Data.account != playerUniqueID)
		{
			throw new InvalidOperationException("The unlock ledger belongs to another account.");
		}
		if (!HasChanges && !string.IsNullOrEmpty(Data.account) && Data.account != playerUniqueID)
		{
			Data.enabledCategories = new List<string>();
			Data.categorySchema = 1;
		}
		Data.account = playerUniqueID;
	}

	internal void Save()
	{
		string sourceFileName = path + ".tmp";
		File.WriteAllText(sourceFileName, JsonUtility.ToJson((object)Data, true));
		if (File.Exists(path))
		{
			File.Replace(sourceFileName, path, path + ".bak");
		}
		else
		{
			File.Move(sourceFileName, path);
		}
	}

	internal void PrepareCategories()
	{
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		CheckAccount();
		if (Data.enabledCategories == null)
		{
			Data.enabledCategories = new List<string>();
		}
		foreach (PluginItemRecord item in Data.items)
		{
			if (item.categories == null)
			{
				item.categories = new List<string>();
			}
		}
		foreach (PluginAchievementRecord achievement in Data.achievements)
		{
			if (achievement.categories == null)
			{
				achievement.categories = new List<string>();
			}
		}
		if (Data.categorySchema >= 1)
		{
			return;
		}
		string[] array = new string[3] { "Lootbox", "Seasonal", "Achievement" };
		foreach (string text in array)
		{
			CosmeticPlan cosmeticPlan = new CosmeticPlan(text);
			bool flag = false;
			foreach (PluginItemRecord item2 in Data.items)
			{
				if (cosmeticPlan.Items.ContainsKey(new GUIDUnion(item2.id)))
				{
					if (!item2.categories.Contains(text))
					{
						item2.categories.Add(text);
					}
					flag = true;
				}
			}
			foreach (PluginAchievementRecord achievement2 in Data.achievements)
			{
				if (cosmeticPlan.Achievements.Contains(new GUIDUnion(achievement2.id)))
				{
					if (!achievement2.categories.Contains(text))
					{
						achievement2.categories.Add(text);
					}
					flag = true;
				}
			}
			if (flag && !Data.enabledCategories.Contains(text))
			{
				Data.enabledCategories.Add(text);
			}
		}
		Data.categorySchema = 1;
		Save();
	}

	internal bool IsEnabled(string category)
	{
		PrepareCategories();
		return Data.enabledCategories.Contains(category);
	}

	internal void SetEnabled(string category, bool enabled)
	{
		PrepareCategories();
		if (enabled)
		{
			Apply(new CosmeticPlan(category), category);
			return;
		}
		List<PluginItemRecord> items = Data.items.FindAll((PluginItemRecord r) => r.categories.Contains(category) && r.categories.Count == 1);
		List<PluginAchievementRecord> achievements = Data.achievements.FindAll((PluginAchievementRecord r) => r.categories.Contains(category) && r.categories.Count == 1);
		UndoRecords(items, achievements);
		foreach (PluginItemRecord item in Data.items)
		{
			item.categories.Remove(category);
		}
		foreach (PluginAchievementRecord achievement in Data.achievements)
		{
			achievement.categories.Remove(category);
		}
		Data.enabledCategories.Remove(category);
		Save();
	}

	internal void Apply(CosmeticPlan plan, string category)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_0170: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: 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_0235: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Invalid comparison between Unknown and I4
		//IL_0257: 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_0283: Unknown result type (might be due to invalid IL or missing references)
		//IL_042a: Unknown result type (might be due to invalid IL or missing references)
		//IL_044a: Unknown result type (might be due to invalid IL or missing references)
		//IL_044f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0480: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0509: Unknown result type (might be due to invalid IL or missing references)
		//IL_050e: Unknown result type (might be due to invalid IL or missing references)
		//IL_051b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0541: Unknown result type (might be due to invalid IL or missing references)
		//IL_052f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0555: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bd: Unknown result type (might be due to invalid IL or missing references)
		CheckAccount();
		PlayerProfile instance = PlayerProfile.Instance;
		if (plan.Achievements.Count > 0 && !SteamAwardGuard.Ready)
		{
			throw new InvalidOperationException("Steam-award guard is unavailable; achievement unlock cancelled.");
		}
		foreach (GUIDUnion id in plan.Achievements)
		{
			List<PluginAchievementRecord> achievements = Data.achievements;
			Predicate<PluginAchievementRecord> match = delegate(PluginAchievementRecord r)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				string id2 = r.id;
				GUIDUnion val2 = id;
				return id2 == ((GUIDUnion)(ref val2)).AsHex();
			};
			if (achievements.Exists(match))
			{
				PluginAchievementRecord pluginAchievementRecord = Data.achievements.Find(delegate(PluginAchievementRecord r)
				{
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					//IL_000c: Unknown result type (might be due to invalid IL or missing references)
					string id2 = r.id;
					GUIDUnion val2 = id;
					return id2 == ((GUIDUnion)(ref val2)).AsHex();
				});
				if (!pluginAchievementRecord.categories.Contains(category))
				{
					pluginAchievementRecord.categories.Add(category);
				}
			}
			else
			{
				if (instance.Achievements.IsCompleted(id) && instance.Achievements.IsClaimed(id))
				{
					continue;
				}
				Achievement asset = ((ResourceAssetDef<Achievement>)(object)((ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>)(object)ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>.Instance).GetAssetDefById(id, true)).Asset;
				PluginAchievementRecord pluginAchievementRecord2 = new PluginAchievementRecord();
				GUIDUnion val = id;
				pluginAchievementRecord2.id = ((GUIDUnion)(ref val)).AsHex();
				pluginAchievementRecord2.steamId = asset.AchievementID;
				pluginAchievementRecord2.completed = instance.Achievements.IsCompleted(id);
				pluginAchievementRecord2.claimed = instance.Achievements.IsClaimed(id);
				PluginAchievementRecord record = pluginAchievementRecord2;
				if ((int)asset.Source == 0 && asset.LocalMetric != null)
				{
					record.liveProgress = asset.LocalMetric.Progress;
					foreach (PluginAchievementRecord achievement in Data.achievements)
					{
						Achievement asset2 = ((ResourceAssetDef<Achievement>)(object)((ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>)(object)ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>.Instance).GetAssetDefById(new GUIDUnion(achievement.id), true)).Asset;
						if ((int)asset2.Source == 0 && asset2.LocalMetric == asset.LocalMetric)
						{
							record.liveProgress = achievement.liveProgress;
							break;
						}
					}
				}
				if ((int)asset.Source == 1 && (ResourceAssetRef)(object)asset.ExternalMetric != (ResourceAssetRef)null)
				{
					GUIDUnion assetGuid = ((ResourceAssetRef)asset.ExternalMetric).AssetGuid;
					record.metricId = ((GUIDUnion)(ref assetGuid)).AsHex();
					record.metricExisted = instance.Metrics.TrackedMetricProgress.TryGetValue(assetGuid, out record.metricProgress);
					if ((Object)(object)((ResourceAssetRef<TrackedMetricContainer, TrackedMetric, TrackedMetricDef>)(object)asset.ExternalMetric).Asset != (Object)null && ((ResourceAssetRef<TrackedMetricContainer, TrackedMetric, TrackedMetricDef>)(object)asset.ExternalMetric).Asset.Metric != null)
					{
						record.liveProgress = ((ResourceAssetRef<TrackedMetricContainer, TrackedMetric, TrackedMetricDef>)(object)asset.ExternalMetric).Asset.Metric.Progress;
					}
					PluginAchievementRecord pluginAchievementRecord3 = Data.achievements.Find((PluginAchievementRecord r) => r.metricId == record.metricId);
					if (pluginAchievementRecord3 != null)
					{
						record.metricProgress = pluginAchievementRecord3.metricProgress;
						record.metricExisted = pluginAchievementRecord3.metricExisted;
						record.liveProgress = pluginAchievementRecord3.liveProgress;
					}
				}
				record.categories.Add(category);
				Data.achievements.Add(record);
			}
		}
		foreach (KeyValuePair<GUIDUnion, IResourceAssetContainer> item in plan.Items)
		{
			List<PluginItemRecord> items = Data.items;
			Predicate<PluginItemRecord> match2 = delegate(PluginItemRecord r)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				string id2 = r.id;
				KeyValuePair<GUIDUnion, IResourceAssetContainer> keyValuePair6 = item;
				GUIDUnion key2 = keyValuePair6.Key;
				return id2 == ((GUIDUnion)(ref key2)).AsHex();
			};
			PluginItemRecord pluginItemRecord = items.Find(match2);
			if (pluginItemRecord != null)
			{
				if (!pluginItemRecord.categories.Contains(category))
				{
					pluginItemRecord.categories.Add(category);
				}
				continue;
			}
			ICategorisedCollection unlockedItems = instance.UnlockedItems;
			KeyValuePair<GUIDUnion, IResourceAssetContainer> keyValuePair = item;
			IReadOnlyList<GUIDUnion> itemsInCategory = unlockedItems.GetItemsInCategory(keyValuePair.Value, true);
			KeyValuePair<GUIDUnion, IResourceAssetContainer> keyValuePair2 = item;
			if (!itemsInCategory.Contains(keyValuePair2.Key))
			{
				PluginItemRecord pluginItemRecord2 = new PluginItemRecord();
				KeyValuePair<GUIDUnion, IResourceAssetContainer> keyValuePair3 = item;
				GUIDUnion key = keyValuePair3.Key;
				pluginItemRecord2.id = ((GUIDUnion)(ref key)).AsHex();
				ICategorisedCollection unseen = instance.Unseen;
				KeyValuePair<GUIDUnion, IResourceAssetContainer> keyValuePair4 = item;
				IResourceAssetContainer value = keyValuePair4.Value;
				KeyValuePair<GUIDUnion, IResourceAssetContainer> keyValuePair5 = item;
				pluginItemRecord2.unseen = unseen.HasItem(value, keyValuePair5.Key);
				pluginItemRecord = pluginItemRecord2;
				pluginItemRecord.categories.Add(category);
				Data.items.Add(pluginItemRecord);
			}
		}
		if (!Data.enabledCategories.Contains(category))
		{
			Data.enabledCategories.Add(category);
		}
		Save();
		foreach (GUIDUnion achievement2 in plan.Achievements)
		{
			if (!instance.Achievements.CompletedAchievements.Contains(achievement2))
			{
				instance.Achievements.CompletedAchievements.Add(achievement2);
			}
			if (!instance.Achievements.ClaimedAchievements.Contains(achievement2))
			{
				instance.Achievements.ClaimedAchievements.Add(achievement2);
			}
		}
		foreach (KeyValuePair<GUIDUnion, IResourceAssetContainer> item2 in plan.Items)
		{
			if (!instance.UnlockedItems.GetItemsInCategory(item2.Value, true).Contains(item2.Key))
			{
				instance.UnlockedItems.AddItem(item2.Value, item2.Key, true);
			}
		}
		if (plan.Achievements.Count > 0)
		{
			CloudProfileWriter.WritePlayerAchievementsProgress(instance.Achievements);
			CloudProfileWriter.WritePlayerClaimedAchievements(instance.Achievements);
		}
	}

	internal void Undo()
	{
		PrepareCategories();
		UndoRecords(new List<PluginItemRecord>(Data.items), new List<PluginAchievementRecord>(Data.achievements));
		Data.enabledCategories.Clear();
		Save();
	}

	private void UndoRecords(List<PluginItemRecord> items, List<PluginAchievementRecord> achievements)
	{
		//IL_002f: 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)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: 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_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_0290: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		CheckAccount();
		PlayerProfile instance = PlayerProfile.Instance;
		Dictionary<string, IResourceAssetContainer> dictionary = new Dictionary<string, IResourceAssetContainer>();
		foreach (PluginItemRecord item in items)
		{
			IResourceAssetContainer val = (IResourceAssetContainer)(object)ResourceAssetContainerRegister.Instance.FindOwner(new GUIDUnion(item.id));
			if (val == null)
			{
				throw new InvalidOperationException("A recorded unlock cannot be resolved; undo cancelled.");
			}
			dictionary.Add(item.id, val);
		}
		foreach (PluginAchievementRecord achievement in achievements)
		{
			if ((Object)(object)((ResourceAssetDef<Achievement>)(object)((ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>)(object)ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>.Instance).GetAssetDefById(new GUIDUnion(achievement.id), true)).Asset == (Object)null)
			{
				throw new InvalidOperationException("A recorded achievement cannot be resolved; undo cancelled.");
			}
		}
		GUIDUnion val2 = default(GUIDUnion);
		GUIDUnion key = default(GUIDUnion);
		foreach (PluginAchievementRecord achievement2 in achievements)
		{
			((GUIDUnion)(ref val2))..ctor(achievement2.id);
			Achievement asset = ((ResourceAssetDef<Achievement>)(object)((ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>)(object)ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>.Instance).GetAssetDefById(val2, true)).Asset;
			SetMembership(instance.Achievements.CompletedAchievements, val2, achievement2.completed);
			SetMembership(instance.Achievements.ClaimedAchievements, val2, achievement2.claimed);
			if (MetricStillUsed(achievement2, achievements))
			{
				continue;
			}
			if ((int)asset.Source == 0 && asset.LocalMetric != null)
			{
				SetMetricWithoutEvents(asset.LocalMetric, achievement2.liveProgress);
			}
			if (!string.IsNullOrEmpty(achievement2.metricId))
			{
				((GUIDUnion)(ref key))..ctor(achievement2.metricId);
				if (achievement2.metricExisted)
				{
					instance.Metrics.TrackedMetricProgress[key] = achievement2.metricProgress;
				}
				else
				{
					instance.Metrics.TrackedMetricProgress.Remove(key);
				}
				if ((Object)(object)((ResourceAssetRef<TrackedMetricContainer, TrackedMetric, TrackedMetricDef>)(object)asset.ExternalMetric).Asset != (Object)null && ((ResourceAssetRef<TrackedMetricContainer, TrackedMetric, TrackedMetricDef>)(object)asset.ExternalMetric).Asset.Metric != null)
				{
					SetMetricWithoutEvents(((ResourceAssetRef<TrackedMetricContainer, TrackedMetric, TrackedMetricDef>)(object)asset.ExternalMetric).Asset.Metric, achievement2.liveProgress);
				}
			}
		}
		GUIDUnion val3 = default(GUIDUnion);
		foreach (PluginItemRecord item2 in items)
		{
			((GUIDUnion)(ref val3))..ctor(item2.id);
			instance.UnlockedItems.RemoveItem(dictionary[item2.id], val3);
			if (item2.unseen)
			{
				instance.Unseen.AddItem(dictionary[item2.id], val3, true);
			}
			else
			{
				instance.Unseen.RemoveItem(dictionary[item2.id], val3);
			}
		}
		CloudProfileWriter.WritePlayerAchievementsProgress(instance.Achievements);
		CloudProfileWriter.WritePlayerClaimedAchievements(instance.Achievements);
		instance.Metrics.Save();
		foreach (PluginItemRecord item3 in items)
		{
			Data.items.Remove(item3);
		}
		foreach (PluginAchievementRecord achievement3 in achievements)
		{
			Data.achievements.Remove(achievement3);
		}
	}

	private bool MetricStillUsed(PluginAchievementRecord record, List<PluginAchievementRecord> removing)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: 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)
		Achievement asset = ((ResourceAssetDef<Achievement>)(object)((ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>)(object)ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>.Instance).GetAssetDefById(new GUIDUnion(record.id), true)).Asset;
		foreach (PluginAchievementRecord achievement in Data.achievements)
		{
			if (removing.Contains(achievement))
			{
				continue;
			}
			if (!string.IsNullOrEmpty(record.metricId) && record.metricId == achievement.metricId)
			{
				return true;
			}
			if ((int)asset.Source == 0 && asset.LocalMetric != null)
			{
				Achievement asset2 = ((ResourceAssetDef<Achievement>)(object)((ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>)(object)ResourceAssetContainer<AchievementContainer, Achievement, AchievementDef>.Instance).GetAssetDefById(new GUIDUnion(achievement.id), true)).Asset;
				if ((int)asset2.Source == 0 && asset2.LocalMetric == asset.LocalMetric)
				{
					return true;
				}
			}
		}
		return false;
	}

	private static void SetMembership(List<GUIDUnion> list, GUIDUnion id, bool present)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: 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_0020: Unknown result type (might be due to invalid IL or missing references)
		if (present)
		{
			if (!list.Contains(id))
			{
				list.Add(id);
			}
		}
		else
		{
			list.RemoveAll((GUIDUnion existing) => existing == id);
		}
	}

	private static void SetMetricWithoutEvents(PlayerMetric metric, int progress)
	{
		typeof(PlayerMetric).GetField("progress", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(metric, progress);
	}
}
internal static class SteamAwardGuard
{
	internal static PluginUnlockLedger Ledger;

	internal static bool Ready;

	private static ManualLogSource logger;

	internal static void Install(ManualLogSource log)
	{
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Expected O, but got Unknown
		logger = log;
		try
		{
			Type type = null;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				type = assembly.GetType("Steamworks.SteamUserStats");
				if (type != null)
				{
					break;
				}
			}
			if (type == null)
			{
				throw new TypeLoadException("SteamUserStats not loaded");
			}
			MethodInfo method = type.GetMethod("SetAchievement", new Type[1] { typeof(string) });
			if (method == null)
			{
				throw new MissingMethodException("SteamUserStats.SetAchievement");
			}
			new Harmony("local.VoidCrewProgressEditor.SteamAwardGuard").Patch((MethodBase)method, new HarmonyMethod(typeof(SteamAwardGuard).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Ready = true;
			log.LogInfo((object)"Steam-award guard installed for plugin-tracked achievements.");
		}
		catch (Exception ex)
		{
			Ready = false;
			log.LogError((object)("Steam-award guard failed; achievement unlocks disabled: " + ex));
		}
	}

	private static bool Prefix(string __0, ref bool __result)
	{
		if (Ledger == null || !Ledger.Data.achievements.Exists((PluginAchievementRecord r) => r.steamId == __0))
		{
			return true;
		}
		__result = false;
		if (logger != null)
		{
			logger.LogInfo((object)("Blocked Steam achievement award for plugin-tracked achievement: " + __0));
		}
		return false;
	}
}
internal sealed class GeneSnapshot
{
	internal IPlayerPerkData Owner;

	internal List<PerkLoadout> Loadouts;

	internal List<Dictionary<PerkBuff, int>> Levels;

	internal static GeneSnapshot Capture()
	{
		IPlayerPerkData perks = PlayerProfile.Instance.Perks;
		if (perks == null || perks.Loadouts == null)
		{
			throw new InvalidOperationException("Gene loadouts are not available.");
		}
		GeneSnapshot geneSnapshot = new GeneSnapshot();
		geneSnapshot.Owner = perks;
		geneSnapshot.Loadouts = perks.Loadouts;
		geneSnapshot.Levels = new List<Dictionary<PerkBuff, int>>();
		GeneSnapshot geneSnapshot2 = geneSnapshot;
		foreach (PerkLoadout loadout in geneSnapshot2.Loadouts)
		{
			if (loadout == null || loadout.Perks == null)
			{
				throw new InvalidOperationException("A gene loadout could not be read.");
			}
			geneSnapshot2.Levels.Add(new Dictionary<PerkBuff, int>(loadout.Perks));
		}
		return geneSnapshot2;
	}

	internal List<SavedGeneLoadout> SaveLevels()
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		List<SavedGeneLoadout> list = new List<SavedGeneLoadout>();
		foreach (Dictionary<PerkBuff, int> level in Levels)
		{
			SavedGeneLoadout savedGeneLoadout = new SavedGeneLoadout();
			foreach (KeyValuePair<PerkBuff, int> item in level)
			{
				List<SavedGenePoint> points = savedGeneLoadout.points;
				SavedGenePoint savedGenePoint = new SavedGenePoint();
				GUIDUnion containerGuid = ((SelfReferencingScriptableObject)item.Key).ContainerGuid;
				savedGenePoint.id = ((GUIDUnion)(ref containerGuid)).AsHex();
				savedGenePoint.level = item.Value;
				points.Add(savedGenePoint);
			}
			list.Add(savedGeneLoadout);
		}
		return list;
	}

	internal List<Dictionary<PerkBuff, int>> ResolveLevels(List<SavedGeneLoadout> saved)
	{
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		CheckOwner();
		if (saved == null || saved.Count != Loadouts.Count)
		{
			throw new InvalidOperationException("Saved gene loadout count differs; undo cancelled.");
		}
		ResourceAssetContainerRegister instance = ResourceAssetContainerRegister.Instance;
		ResourceAssetContainer<PerkBuffContainer, PerkBuff, PerkBuffDef> val = (((Object)(object)instance == (Object)null) ? null : instance.GetContainer<PerkBuffContainer, PerkBuff, PerkBuffDef>());
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Gene definitions are not loaded.");
		}
		List<Dictionary<PerkBuff, int>> list = new List<Dictionary<PerkBuff, int>>();
		foreach (SavedGeneLoadout item in saved)
		{
			Dictionary<PerkBuff, int> dictionary = new Dictionary<PerkBuff, int>();
			foreach (SavedGenePoint point in item.points)
			{
				PerkBuff val2 = ((ResourceAssetDef<PerkBuff>)(object)val.GetAssetDefById(new GUIDUnion(point.id), true))?.Asset;
				if ((Object)(object)val2 == (Object)null || point.level < 0 || point.level > val2.Levels.Count || dictionary.ContainsKey(val2))
				{
					throw new InvalidOperationException("A saved gene allocation cannot be restored; undo cancelled.");
				}
				dictionary.Add(val2, point.level);
			}
			list.Add(dictionary);
		}
		return list;
	}

	internal void CheckOwner()
	{
		if (!object.ReferenceEquals(PlayerProfile.Instance.Perks, Owner) || !object.ReferenceEquals(Owner.Loadouts, Loadouts) || Loadouts.Count != Levels.Count)
		{
			throw new InvalidOperationException("Gene loadouts changed since the edit; restoration was not applied.");
		}
	}

	internal void Commit(List<Dictionary<PerkBuff, int>> target)
	{
		CheckOwner();
		int activeLoudoutIndex = Owner.ActiveLoudoutIndex;
		if (activeLoudoutIndex < 0 || activeLoudoutIndex >= Loadouts.Count)
		{
			throw new InvalidOperationException("Active gene loadout index is invalid.");
		}
		List<int> list = new List<int>();
		PerkBuff val = null;
		for (int i = 0; i < target.Count; i++)
		{
			Dictionary<PerkBuff, int> perks = Loadouts[i].Perks;
			bool flag = perks.Count != target[i].Count;
			foreach (KeyValuePair<PerkBuff, int> item in perks)
			{
				if (!target[i].TryGetValue(item.Key, out var value) || value != item.Value)
				{
					flag = true;
					if (i == activeLoudoutIndex)
					{
						val = item.Key;
					}
				}
			}
			if (!flag)
			{
				foreach (KeyValuePair<PerkBuff, int> item2 in target[i])
				{
					if (!perks.ContainsKey(item2.Key))
					{
						flag = true;
						break;
					}
				}
			}
			if (!flag)
			{
				continue;
			}
			if (i == activeLoudoutIndex && (Object)(object)val == (Object)null)
			{
				using Dictionary<PerkBuff, int>.Enumerator enumerator3 = target[i].GetEnumerator();
				if (enumerator3.MoveNext())
				{
					val = enumerator3.Current.Key;
				}
			}
			list.Add(i);
		}
		foreach (int item3 in list)
		{
			Loadouts[item3].Perks.Clear();
			foreach (KeyValuePair<PerkBuff, int> item4 in target[item3])
			{
				Loadouts[item3].Perks.Add(item4.Key, item4.Value);
			}
		}
		foreach (int item5 in list)
		{
			CloudProfileWriter.WritePerkLoadout(item5, Loadouts[item5].Perks);
		}
		if ((Object)(object)val != (Object)null)
		{
			Loadouts[activeLoudoutIndex].Perks.TryGetValue(val, out var value2);
			Owner.SetPerkBuffLevel(val, value2);
		}
		if (list.Count > 0)
		{
			TokenTerminalEvents.Instance.OnPerkLoadoutChanged?.Invoke();
		}
	}
}
internal sealed class GenePlan
{
	private readonly List<PerkBuff> buffs = new List<PerkBuff>();

	private readonly Dictionary<PerkBuff, GeneNode> definitions = new Dictionary<PerkBuff, GeneNode>();

	internal GenePlan(GeneSnapshot snapshot)
	{
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Expected I4, but got Unknown
		ResourceAssetContainerRegister instance = ResourceAssetContainerRegister.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			throw new InvalidOperationException("Gene-tree registry is not loaded.");
		}
		ResourceAssetContainer<PerkTreeContainer, PerkTree, PerkTreeDef> container = instance.GetContainer<PerkTreeContainer, PerkTree, PerkTreeDef>();
		if ((Object)(object)container == (Object)null)
		{
			throw new InvalidOperationException("Gene-tree definitions are not loaded.");
		}
		List<PerkTreeDef> list = new List<PerkTreeDef>(container.AssetDescriptions);
		if (container.RuntimeDescriptions != null)
		{
			list.AddRange(container.RuntimeDescriptions);
		}
		list.Sort((PerkTreeDef a, PerkTreeDef b) => ((int)a.perkTree).CompareTo((int)b.perkTree));
		foreach (PerkTreeDef item in list)
		{
			PerkTree asset = ((ResourceAssetDef<PerkTree>)(object)item).Asset;
			if ((Object)(object)asset == (Object)null || asset.Perks == null)
			{
				continue;
			}
			foreach (PerkBuffRef perk in asset.Perks)
			{
				PerkBuff asset2 = ((ResourceAssetRef<PerkBuffContainer, PerkBuff, PerkBuffDef>)(object)perk).Asset;
				if (!((Object)(object)asset2 == (Object)null) && !definitions.ContainsKey(asset2))
				{
					definitions.Add(asset2, new GeneNode
					{
						Id = buffs.Count,
						Tree = (int)item.perkTree,
						Row = asset2.Row,
						Column = asset2.Column
					});
					buffs.Add(asset2);
				}
			}
		}
		foreach (Dictionary<PerkBuff, int> level in snapshot.Levels)
		{
			foreach (KeyValuePair<PerkBuff, int> item2 in level)
			{
				if ((Object)(object)item2.Key == (Object)null || item2.Value < 0 || !definitions.ContainsKey(item2.Key))
				{
					throw new InvalidOperationException("An allocated gene node cannot be mapped to a tree. Edit cancelled.");
				}
			}
		}
	}

	internal List<Dictionary<PerkBuff, int>> Reduce(GeneSnapshot snapshot, int decrease, out List<int> removed)
	{
		List<Dictionary<PerkBuff, int>> list = new List<Dictionary<PerkBuff, int>>();
		removed = new List<int>();
		foreach (Dictionary<PerkBuff, int> level in snapshot.Levels)
		{
			List<GeneNode> list2 = new List<GeneNode>();
			foreach (KeyValuePair<PerkBuff, int> item in level)
			{
				GeneNode geneNode = definitions[item.Key].Copy();
				geneNode.Points = item.Value;
				list2.Add(geneNode);
			}
			removed.Add(GeneReduction.Remove(list2, decrease));
			Dictionary<PerkBuff, int> dictionary = new Dictionary<PerkBuff, int>();
			foreach (GeneNode item2 in list2)
			{
				if (item2.Points > 0)
				{
					dictionary.Add(buffs[item2.Id], item2.Points);
				}
			}
			list.Add(dictionary);
		}
		return list;
	}
}
public sealed class GeneNode
{
	public int Id;

	public int Tree;

	public int Row;

	public int Column;

	public int Points;

	public GeneNode Copy()
	{
		return (GeneNode)MemberwiseClone();
	}
}
public static class GeneReduction
{
	public static int Remove(List<GeneNode> nodes, int count)
	{
		if (count < 0)
		{
			throw new ArgumentOutOfRangeException("count");
		}
		int i;
		for (i = 0; i < count; i++)
		{
			SortedDictionary<int, long> sortedDictionary = new SortedDictionary<int, long>();
			foreach (GeneNode node in nodes)
			{
				if (node.Points < 0)
				{
					throw new InvalidOperationException("Negative gene allocation.");
				}
				if (!sortedDictionary.ContainsKey(node.Tree))
				{
					sortedDictionary.Add(node.Tree, 0L);
				}
				sortedDictionary[node.Tree] += node.Points;
			}
			int num = -1;
			long num2 = 0L;
			foreach (KeyValuePair<int, long> item in sortedDictionary)
			{
				if (item.Value > num2)
				{
					num = item.Key;
					num2 = item.Value;
				}
			}
			if (num2 == 0)
			{
				break;
			}
			GeneNode geneNode = null;
			foreach (GeneNode node2 in nodes)
			{
				if (node2.Tree == num && node2.Points != 0 && (geneNode == null || node2.Row > geneNode.Row || (node2.Row == geneNode.Row && node2.Column < geneNode.Column) || (node2.Row == geneNode.Row && node2.Column == geneNode.Column && node2.Id < geneNode.Id)))
				{
					geneNode = node2;
				}
			}
			geneNode.Points--;
		}
		return i;
	}
}
[Serializable]
internal sealed class SavedGenePoint
{
	public string id;

	public int level;
}
[Serializable]
internal sealed class SavedGeneLoadout
{
	public List<SavedGenePoint> points = new List<SavedGenePoint>();
}
[Serializable]
internal sealed class ProgressUndoEntry
{
	public string savedUtc;

	public long xp;

	public int rank;

	public int favor;

	public List<SavedGeneLoadout> loadouts = new List<SavedGeneLoadout>();
}
[Serializable]
internal sealed class ProgressUndoAccount
{
	public string account;

	public List<ProgressUndoEntry> entries = new List<ProgressUndoEntry>();
}
[Serializable]
internal sealed class ProgressUndoData
{
	public int schema = 1;

	public List<ProgressUndoAccount> accounts = new List<ProgressUndoAccount>();
}
internal sealed class ProgressUndoHistory
{
	private readonly string path;

	private readonly ProgressUndoData data;

	internal ProgressUndoHistory(string filename)
	{
		path = filename;
		data = (File.Exists(path) ? JsonConvert.DeserializeObject<ProgressUndoData>(File.ReadAllText(path)) : new ProgressUndoData());
		if (data == null || data.schema != 1 || data.accounts == null)
		{
			throw new InvalidOperationException("Rank undo history is invalid; edits disabled to preserve it.");
		}
		HashSet<string> hashSet = new HashSet<string>();
		foreach (ProgressUndoAccount account in data.accounts)
		{
			if (account == null || string.IsNullOrEmpty(account.account) || !hashSet.Add(account.account) || account.entries == null || account.entries.Count > 10)
			{
				throw new InvalidOperationException("Rank undo history contains an invalid account.");
			}
			foreach (ProgressUndoEntry entry in account.entries)
			{
				if (entry == null || entry.rank < 0 || entry.rank > 30 || entry.xp < 0 || entry.favor < 0 || (entry.rank < 30 && entry.favor > 0) || entry.loadouts == null)
				{
					throw new InvalidOperationException("Rank undo history contains an invalid snapshot.");
				}
				foreach (SavedGeneLoadout loadout in entry.loadouts)
				{
					if (loadout == null || loadout.points == null)
					{
						throw new InvalidOperationException("Invalid gene snapshot.");
					}
					HashSet<string> hashSet2 = new HashSet<string>();
					foreach (SavedGenePoint point in loadout.points)
					{
						if (point == null || string.IsNullOrEmpty(point.id) || point.level < 0 || !hashSet2.Add(point.id))
						{
							throw new InvalidOperationException("Invalid gene snapshot.");
						}
					}
				}
			}
		}
	}

	private ProgressUndoAccount Find(string id)
	{
		if (string.IsNullOrEmpty(id))
		{
			throw new InvalidOperationException("Player account is not ready.");
		}
		return data.accounts.Find((ProgressUndoAccount a) => a.account == id);
	}

	internal ProgressUndoEntry Peek(string account)
	{
		ProgressUndoAccount progressUndoAccount = Find(account);
		if (progressUndoAccount != null && progressUndoAccount.entries.Count != 0)
		{
			return progressUndoAccount.entries[progressUndoAccount.entries.Count - 1];
		}
		return null;
	}

	internal void Push(string account, ProgressUndoEntry entry)
	{
		ProgressUndoAccount progressUndoAccount = Find(account);
		bool flag = progressUndoAccount == null;
		if (flag)
		{
			ProgressUndoAccount progressUndoAccount2 = new ProgressUndoAccount();
			progressUndoAccount2.account = account;
			progressUndoAccount = progressUndoAccount2;
			data.accounts.Add(progressUndoAccount);
		}
		List<ProgressUndoEntry> entries = new List<ProgressUndoEntry>(progressUndoAccount.entries);
		progressUndoAccount.entries.Add(entry);
		if (progressUndoAccount.entries.Count > 10)
		{
			progressUndoAccount.entries.RemoveAt(0);
		}
		try
		{
			Save();
		}
		catch
		{
			progressUndoAccount.entries = entries;
			if (flag)
			{
				data.accounts.Remove(progressUndoAccount);
			}
			throw;
		}
	}

	internal void Pop(string account, ProgressUndoEntry expected)
	{
		ProgressUndoAccount progressUndoAccount = Find(account);
		if (progressUndoAccount == null || progressUndoAccount.entries.Count == 0 || !object.ReferenceEquals(Peek(account), expected))
		{
			throw new InvalidOperationException("Rank undo history changed; entry was not removed.");
		}
		progressUndoAccount.entries.RemoveAt(progressUndoAccount.entries.Count - 1);
		try
		{
			Save();
		}
		catch
		{
			progressUndoAccount.entries.Add(expected);
			throw;
		}
	}

	private void Save()
	{
		Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path)));
		string sourceFileName = path + ".tmp";
		File.WriteAllText(sourceFileName, JsonConvert.SerializeObject((object)data, (Formatting)1));
		if (File.Exists(path))
		{
			File.Replace(sourceFileName, path, path + ".bak");
		}
		else
		{
			File.Move(sourceFileName, path);
		}
	}
}
public static class ProgressValidation
{
	public static string ValidateFavor(int rank, int favorRank)
	{
		if (favorRank < 0)
		{
			return "Favor rank must be non-negative; nothing changed.";
		}
		if (rank != 30 && favorRank > 0)
		{
			return "Favor rank must be 0 unless rank is 30; nothing changed.";
		}
		return null;
	}

	public static string Validate(long xp, int rank, long maximumXp)
	{
		if (rank < 0 || rank > 30)
		{
			return "Rank must be between 0 and 30; nothing changed.";
		}
		if (xp < 0)
		{
			return "XP must be non-negative; nothing changed.";
		}
		if (maximumXp <= 0)
		{
			return "The game's XP threshold is unavailable; nothing changed.";
		}
		if (xp >= maximumXp)
		{
			return "XP must be less than " + maximumXp + " for rank " + rank + "; nothing changed.";
		}
		return null;
	}
}
internal sealed class MainMenuRankPreview
{
	private sealed class NativeSize
	{
		internal float Width;

		internal float Height;

		internal Scale Scale;
	}

	private static VisualTreeAsset titleAsset;

	private static float mainBarOffsetX = 72f;

	private static float mainBarWidth = 633f;

	private static float mainBarHeight = 131f;

	private static float mainBackgroundWidth = 563f;

	private static readonly Dictionary<string, NativeSize> nativeSizes = new Dictionary<string, NativeSize>();

	private readonly VisualElement host;

	private readonly ProgressEditor plugin;

	private VisualElement bar;

	private VisualElement card;

	private long lastXp = -1L;

	private int lastRank = -1;

	private int lastFavor = -1;

	private bool failed;

	private string lastName;

	internal static void Capture(UIDocument document)
	{
		//IL_007d: 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_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)document == (Object)null || (Object)(object)document.visualTreeAsset == (Object)null)
		{
			return;
		}
		titleAsset = document.visualTreeAsset;
		VisualElement val = ((document.rootVisualElement == null) ? null : UQueryExtensions.Q<VisualElement>(document.rootVisualElement, "mainmenu", (string)null));
		VisualElement val2 = ((val == null) ? null : UQueryExtensions.Q<VisualElement>(val, "background", (string)null));
		VisualElement val3 = ((document.rootVisualElement == null) ? null : UQueryExtensions.Q<VisualElement>(document.rootVisualElement, "ExpProgressBar", (string)null));
		if (val2 == null || val3 == null)
		{
			return;
		}
		Rect worldBound = val3.worldBound;
		if (!(((Rect)(ref worldBound)).width > 0f))
		{
			return;
		}
		Rect worldBound2 = val2.worldBound;
		if (!(((Rect)(ref worldBound2)).height > 0f))
		{
			return;
		}
		Rect worldBound3 = val3.worldBound;
		mainBarOffsetX = VisualElementExtensions.WorldToLocal(val2, ((Rect)(ref worldBound3)).position).x;
		mainBarWidth = val3.resolvedStyle.width;
		mainBarHeight = val3.resolvedStyle.height;
		mainBackgroundWidth = val2.resolvedStyle.width;
		string[] array = new string[7] { "MainBarContainer", "MainBar", "ProgressBar", "RankDisplayVE", "LowerText", "LowerRank", "LowerEXP" };
		foreach (string text in array)
		{
			VisualElement val4 = UQueryExtensions.Q<VisualElement>(val3, text, (string)null);
			if (val4 != null && !(val4.resolvedStyle.width <= 0f) && !(val4.resolvedStyle.height <= 0f))
			{
				nativeSizes[text] = new NativeSize
				{
					Width = val4.resolvedStyle.width,
					Height = val4.resolvedStyle.height,
					Scale = val4.resolvedStyle.scale
				};
			}
		}
	}

	internal MainMenuRankPreview(VisualElement container, ProgressEditor owner)
	{
		host = container;
		plugin = owner;
	}

	internal void Update()
	{
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Expected O, but got Unknown
		//IL_0106: 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_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_0216: Unknown result type (might be due to invalid IL or missing references)
		//IL_0241: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		//IL_028b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f4: 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_02fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0334: Unknown result type (might be due to invalid IL or missing references)
		//IL_0339: Unknown result type (might be due to invalid IL or missing references)
		//IL_033a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0341: Unknown result type (might be due to invalid IL or missing references)
		//IL_0343: Unknown result type (might be due to invalid IL or missing references)
		//IL_0344: Unknown result type (might be due to invalid IL or missing references)
		//IL_034b: 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_0355: Unknown result type (might be due to invalid IL or missing references)
		//IL_036d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0388: Unknown result type (might be due to invalid IL or missing references)
		//IL_039e: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_05fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0601: Unknown result type (might be due to invalid IL or missing references)
		//IL_065a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0660: 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_0427: Unknown result type (might be due to invalid IL or missing references)
		//IL_043d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0455: Unknown result type (might be due to invalid IL or missing references)
		//IL_045a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0490: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_075b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0760: Unknown result type (might be due to invalid IL or missing references)
		//IL_07d0: Unknown result type (might be due to invalid IL or missing references)
		if (failed)
		{
			return;
		}
		try
		{
			if (bar == null)
			{
				if ((Object)(object)titleAsset == (Object)null)
				{
					TitleMenu[] array = Resources.FindObjectsOfTypeAll<TitleMenu>();
					foreach (TitleMenu val in array)
					{
						Capture(val.UIDoc);
					}
				}
				if ((Object)(object)titleAsset == (Object)null)
				{
					return;
				}
				TemplateContainer val2 = titleAsset.CloneTree();
				bar = UQueryExtensions.Q<VisualElement>((VisualElement)(object)val2, "ExpProgressBar", (string)null);
				if (bar == null)
				{
					throw new InvalidOperationException("Main menu rank display asset is missing.");
				}
				CopySheets((VisualElement)(object)val2, host);
				TitleMenu[] array2 = Resources.FindObjectsOfTypeAll<TitleMenu>();
				foreach (TitleMenu val3 in array2)
				{
					Capture(val3.UIDoc);
				}
				VisualElement val4 = new VisualElement();
				val4.name = "ProgressEditorProfileCard";
				card = val4;
				host.style.width = StyleLength.op_Implicit(mainBarWidth + 24f);
				host.style.maxWidth = StyleLength.op_Implicit((StyleKeyword)3);
				host.style.flexShrink = StyleFloat.op_Implicit(0f);
				card.style.width = StyleLength.op_Implicit(mainBarWidth);
				card.style.maxWidth = StyleLength.op_Implicit((StyleKeyword)3);
				card.style.height = StyleLength.op_Implicit(350f);
				card.style.position = StyleEnum<Position>.op_Implicit((Position)0);
				card.style.overflow = StyleEnum<Overflow>.op_Implicit((Overflow)0);
				RankCardDiamond rankCardDiamond = new RankCardDiamond();
				((VisualElement)rankCardDiamond).name = "ProgressEditorRankDiamond";
				RankCardDiamond rankCardDiamond2 = rankCardDiamond;
				((VisualElement)rankCardDiamond2).style.position = StyleEnum<Position>.op_Implicit((Position)1);
				((VisualElement)rankCardDiamond2).style.left = StyleLength.op_Implicit(0f - mainBarOffsetX);
				((VisualElement)rankCardDiamond2).style.top = StyleLength.op_Implicit(0f);
				((VisualElement)rankCardDiamond2).style.width = StyleLength.op_Implicit(mainBackgroundWidth);
				float artworkHeight = mainBackgroundWidth * rankCardDiamond2.AspectRatio;
				((VisualElement)rankCardDiamond2).style.height = StyleLength.op_Implicit(artworkHeight);
				card.style.height = StyleLength.op_Implicit(artworkHeight);
				card.Add((VisualElement)(object)rankCardDiamond2);
				bar.RemoveFromHierarchy();
				bar.style.position = StyleEnum<Position>.op_Implicit((Position)1);
				bar.style.left = StyleLength.op_Implicit(0f);
				bar.style.top = StyleLength.op_Implicit((artworkHeight - mainBarHeight) / 2f);
				IStyle style = bar.style;
				StyleLength right = (bar.style.bottom = StyleLength.op_Implicit((StyleKeyword)2));
				style.right = right;
				IStyle style2 = bar.style;
				IStyle style3 = bar.style;
				IStyle style4 = bar.style;
				StyleLength val6 = (bar.style.marginRight = StyleLength.op_Implicit(0f));
				StyleLength val8 = (style4.marginLeft = val6);
				StyleLength marginTop = (style3.marginBottom = val8);
				style2.marginTop = marginTop;
				bar.style.height = StyleLength.op_Implicit(mainBarHeight);
				bar.style.width = StyleLength.op_Implicit(mainBarWidth);
				bar.style.maxWidth = StyleLength.op_Implicit((StyleKeyword)3);
				bar.style.flexShrink = StyleFloat.op_Implicit(0f);
				foreach (KeyValuePair<string, NativeSize> nativeSize in nativeSizes)
				{
					VisualElement val11 = UQueryExtensions.Q<VisualElement>(bar, nativeSize.Key, (string)null);
					if (val11 != null)
					{
						val11.style.width = StyleLength.op_Implicit(nativeSize.Value.Width);
						val11.style.height = StyleLength.op_Implicit(nativeSize.Value.Height);
						val11.style.flexShrink = StyleFloat.op_Implicit(0f);
						val11.style.scale = StyleScale.op_Implicit(nativeSize.Value.Scale);
					}
				}
				bar.style.minWidth = StyleLength.op_Implicit(0f);
				bar.style.display = StyleEnum<DisplayStyle>.op_Implicit((DisplayStyle)0);
				bar.RemoveFromClassList("hidden-element");
				card.Add(bar);
				host.Add(card);
				RankDisplayVE centerBadge = UQueryExtensions.Q<RankDisplayVE>(bar, (string)null, (string)null);
				EventCallback<GeometryChangedEvent> val12 = delegate
				{
					//IL_000e: 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_002d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0032: Unknown result type (might be due to invalid IL or missing references)
					//IL_0053: Unknown result type (might be due to invalid IL or missing references)
					//IL_0058: Unknown result type (might be due to invalid IL or missing references)
					//IL_005c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0061: Unknown result type (might be due to invalid IL or missing references)
					//IL_009b: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
					//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
					//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
					if (centerBadge != null)
					{
						Rect worldBound = ((VisualElement)centerBadge).worldBound;
						if (!(((Rect)(ref worldBound)).height <= 0f))
						{
							Rect worldBound2 = bar.worldBound;
							if (!(((Rect)(ref worldBound2)).height <= 0f))
							{
								VisualElement obj = bar;
								Rect worldBound3 = ((VisualElement)centerBadge).worldBound;
								float y = VisualElementExtensions.WorldToLocal(obj, ((Rect)(ref worldBound3)).center).y;
								float num4 = artworkHeight / 2f - y;
								if (!float.IsNaN(num4) && !float.IsInfinity(num4))
								{
									StyleLength top = bar.style.top;
									Length value = ((StyleLength)(ref top)).value;
									if (Mathf.Abs(((Length)(ref value)).value - num4) > 0.1f)
									{
										bar.style.top = StyleLength.op_Implicit(num4);
									}
								}
							}
						}
					}
				};
				((CallbackEventHandler)bar).RegisterCallback<GeometryChangedEvent>(val12, (TrickleDown)0);
				if (centerBadge != null)
				{
					((CallbackEventHandler)centerBadge).RegisterCallback<GeometryChangedEvent>(val12, (TrickleDown)0);
				}
				SetText("PlayerName", "");
			}
			PlayerProfile instance = PlayerProfile.Instance;
			if (instance == null || instance.Profile == null)
			{
				return;
			}
			int rank = instance.Profile.Rank;
			int favorRank = instance.Profile.FavorRank;
			long xp = instance.Profile.Xp;
			string text = PlayerProfile.SanitizedUserAccountNickname() ?? "";
			if (rank == lastRank && favorRank == lastFavor && xp == lastXp && text == lastName)
			{
				return;
			}
			SetText("PlayerName", text);
			List<XpSliderData> sequence = XPSliderFactory.GetSequence(rank, favorRank, xp, new List<XPSource>());
			if (sequence == null || sequence.Count == 0)
			{
				return;
			}
			XpSliderData val13 = sequence[sequence.Count - 1];
			bar.EnableInClassList("style__metem-rank", !val13.IsInFavorLevels);
			bar.EnableInClassList("style__favor-level", val13.IsInFavorLevels);
			RankDisplayVE val14 = UQueryExtensions.Q<RankDisplayVE>(bar, (string)null, (string)null);
			if (val14 != null)
			{
				val14.Show(val13.Rank, val13.IsInFavorLevels, false, default(Times));
			}
			SetText("RankNumber", val13.Rank.ToString());
			SetText("Title", ". " + val13.title);
			SetText("CurrentXp", val13.TargetXP.ToString());
			SetText("MaxXp", val13.MaxXP.ToString());
			float num = ((val13.MaxXP > 0) ? ((float)Math.Max(0.0, Math.Min(100.0, (double)val13.TargetXP * 100.0 / (double)val13.MaxXP))) : 0f);
			string[] array3 = new string[2] { "FrontProgress", "BackProgress" };
			foreach (string text2 in array3)
			{
				VisualElement val15 = UQueryExtensions.Q<VisualElement>(bar, text2, (string)null);
				if (val15 != null)
				{
					val15.style.width = StyleLength.op_Implicit(Length.Percent(num));
				}
			}
			string[] array4 = new string[4] { "SourceContainer", "RankUpContainer", "RankRewards", "TotalXP" };
			foreach (string text3 in array4)
			{
				VisualElement val16 = UQueryExtensions.Q<VisualElement>(bar, text3, (string)null);
				if (val16 != null)
				{
					val16.style.display = StyleEnum<DisplayStyle>.op_Implicit((DisplayStyle)1);
				}
			}
			lastRank = rank;
			lastFavor = favorRank;
			lastXp = xp;
			lastName = text;
		}
		catch (Exception ex)
		{
			failed = true;
			plugin.NativeError(ex);
		}
	}

	private void SetText(string name, string value)
	{
		Label val = UQueryExtensions.Q<Label>(bar, name, (string)null);
		if (val != null)
		{
			((TextElement)val).text = value;
		}
	}

	private static void CopySheets(VisualElement source, VisualElement destination)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: 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_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		while (true)
		{
			int num2 = num;
			VisualElementStyleSheetSet styleSheets = source.styleSheets;
			if (num2 >= ((VisualElementStyleSheetSet)(ref styleSheets)).count)
			{
				break;
			}
			VisualElementStyleSheetSet styleSheets2 = destination.styleSheets;
			VisualElementStyleSheetSet styleSheets3 = source.styleSheets;
			if (!((VisualElementStyleSheetSet)(ref styleSheets2)).Contains(((VisualElementStyleSheetSet)(ref styleSheets3))[num]))
			{
				VisualElementStyleSheetSet styleSheets4 = destination.styleSheets;
				VisualElementStyleSheetSet styleSheets5 = source.styleSheets;
				((VisualElementStyleSheetSet)(ref styleSheets4)).Add(((VisualElementStyleSheetSet)(ref styleSheets5))[num]);
			}
			num++;
		}
		foreach (VisualElement item in source.Children())
		{
			CopySheets(item, destination);
		}
	}
}
internal sealed class PauseProgressScreen
{
	private static ProgressEditor plugin;

	private static readonly Dictionary<object, PauseProgressScreen> screens = new Dictionary<object, PauseProgressScreen>();

	private readonly VisualElement overlay;

	private readonly Button entry;

	private readonly Button progressUndo;

	private readonly List<Action> synchronize = new List<Action>();

	private readonly List<Slider> sliders = new List<Slider>();

	private VisualElement contentHost;

	private VisualElement tabHost;

	private VisualTreeAsset settingsAsset;

	private float tabFontSize = 28f;

	private float tabInset = 48f;

	private VisualElement settingsTabLead;

	private VisualElement settingsTabTail;

	private float rowHeight = 64f;

	private float rowTop;

	private float rowBottom = 14f;

	private float rowPaddingTop;

	private float rowPaddingBottom;

	private readonly List<string> tabTextClasses = new List<string>();

	private bool open;

	private readonly object pauseMenu;

	private readonly VisualElement screenRoot;

	private readonly bool titleMenu;

	internal static bool IsOpen
	{
		get
		{
			foreach (PauseProgressScreen value in screens.Values)
			{
				if (value.open)
				{
					return true;
				}
			}
			return false;
		}
	}

	internal static void Install(ProgressEditor owner)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Expected O, but got Unknown
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Expected O, but got Unknown
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Expected O, but got Unknown
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Expected O, but got Unknown
		plugin = owner;
		Type type = typeof(PlayerProfile).Assembly.GetType("EscapeMenu");
		Harmony val = new Harmony("local.VoidCrewProgressEditor.PauseMenu");
		string[] array = new string[2] { "OnInitialize", "OnEnter" };
		foreach (string name in array)
		{
			val.Patch((MethodBase)type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), (HarmonyMethod)null, new HarmonyMethod(typeof(PauseProgressScreen).GetMethod("Ensure", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		val.Patch((MethodBase)type.GetMethod("OnExit", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(PauseProgressScreen).GetMethod("BeforeExit", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		Type type2 = typeof(PlayerProfile).Assembly.GetType("MainMenu");
		val.Patch((MethodBase)type2.GetMethod("StartAsTitleMenu", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), (HarmonyMethod)null, new HarmonyMethod(typeof(PauseProgressScreen).GetMethod("EnsureTitle", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		string[] array2 = new string[2] { "Shutdown", "Dispose" };
		foreach (string name2 in array2)
		{
			val.Patch((MethodBase)type2.GetMethod(name2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(PauseProgressScreen).GetMethod("RemoveTitle", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
	}

	private static object Field(object owner, string name)
	{
		FieldInfo field = owner.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (!(field == null))
		{
			return field.GetValue(owner);
		}
		return null;
	}

	private static void EnsureTitle(object __instance)
	{
		try
		{
			object obj = Field(__instance, "_mainmenuRoot");
			VisualElement val = (VisualElement)((obj is VisualElement) ? obj : null);
			object obj2 = Field(__instance, "_settingsButton");
			Button val2 = (Button)((obj2 is Button) ? obj2 : null);
			if (val == null || val2 == null || ((VisualElement)val2).parent == null)
			{
				return;
			}
			VisualElement root = val;
			UIDocument[] array = Resources.FindObjectsOfTypeAll<UIDocument>();
			foreach (UIDocument val3 in array)
			{
				if (val3.rootVisualElement != null && val3.rootVisualElement.Contains(val))
				{
					root = val3.rootVisualElement;
					MainMenuRankPreview.Capture(val3);
					break;
				}
			}
			EnsureScreen(__instance, root, val2, title: true);
		}
		catch (Exception ex)
		{
			plugin.NativeError(ex);
		}
	}

	private static void RemoveTitle(object __instance)
	{
		if (screens.TryGetValue(__instance, out var value))
		{
			value.open = false;
			((VisualElement)value.entry).RemoveFromHierarchy();
			value.overlay.RemoveFromHierarchy();
			screens.Remove(__instance);
		}
	}

	private static void EnsureScreen(object owner, VisualElement root, Button settings, bool title)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		if (screens.TryGetValue(owner, out var value))
		{
			if (root.Contains((VisualElement)(object)value.entry) && root.Contains(value.overlay))
			{
				return;
			}
			RemoveTitle(owner);
		}
		List<VisualElement> stale = new List<VisualElement>();
		UQueryExtensions.Query<VisualElement>(root, (string)null, (string)null).ForEach((Action<VisualElement>)delegate(VisualElement element)
		{
			if (element.name == "ProgressEditorMenuEntry" || element.name == "ProgressEditorScreen")
			{
				stale.Add(element);
			}
		});
		foreach (VisualElement item in stale)
		{
			item.RemoveFromHierarchy();
		}
		PauseProgressScreen value2 = new PauseProgressScreen(root, settings, owner, title);
		screens.Add(owner, value2);
		plugin.NativeLog(title ? "Added Edit Progress above Settings in the main menu." : "Added Edit Progress after Settings in the pause menu.");
	}

	private static void Ensure(object __instance)
	{
		try
		{
			object obj = Field(__instance, "UIDoc");
			UIDocument val = (UIDocument)((obj is UIDocument) ? obj : null);
			if ((Object)(object)val == (Object)null || val.rootVisualElement == null)
			{
				return;
			}
			object obj2 = Field(__instance, "_mainMenu");
			if (obj2 != null)
			{
				object obj3 = Field(obj2, "_settingsButton");
				Button val2 = (Button)((obj3 is Button) ? obj3 : null);
				if (val2 != null && ((VisualElement)val2).parent != null)
				{
					EnsureScreen(__instance, val.rootVisualElement, val2, title: false);
				}
			}
		}
		catch (Exception ex)
		{
			plugin.NativeError(ex);
		}
	}

	private static bool BeforeExit(object __instance, ref bool __result)
	{
		if (!screens.TryGetValue(__instance, out var value) || !value.open)
		{
			return true;
		}
		value.Close();
		__result = false;
		return false;
	}

	private PauseProgressScreen(VisualElement root, Button settings, object menu, bool title)
	{
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Expected O, but got Unknown
		//IL_0126: 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_0168: 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_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0225: Unknown result type (might be due to invalid IL or missing references)
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_0237: Expected O, but got Unknown
		//IL_0256: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_0297: Unknown result type (might be due to invalid IL or missing references)
		//IL_029e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_030d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0312: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: 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_0358: Unknown result type (might be due to invalid IL or missing references)
		//IL_0371: Unknown result type (might be due to invalid IL or missing references)
		//IL_037b: Expected O, but got Unknown
		//IL_0399: Unknown result type (might be due to invalid IL or missing references)
		//IL_039e: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03be: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0419: Unknown result type (might be due to invalid IL or missing references)
		//IL_041e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0439: Unknown result type (might be due to invalid IL or missing references)
		//IL_0454: Unknown result type (might be due to invalid IL or missing references)
		//IL_047b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0480: Unknown result type (might be due to invalid IL or missing references)
		//IL_0481: Unknown result type (might be due to invalid IL or missing references)
		//IL_0488: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0500: Expected O, but got Unknown
		//IL_0515: Unknown result type (might be due to invalid IL or missing references)
		//IL_051c: Expected O, but got Unknown
		//IL_053c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0546: Unknown result type (might be due to invalid IL or missing references)
		//IL_054d: Expected O, but got Unknown
		//IL_0567: Unknown result type (might be due to invalid IL or missing references)
		//IL_057c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0581: Unknown result type (might be due to invalid IL or missing references)
		//IL_0596: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bc: Expected O, but got Unknown
		//IL_05d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_05eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0605: Unknown result type (might be due to invalid IL or missing references)
		//IL_061a: Unknown result type (might be due to invalid IL or missing references)
		//IL_062f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0640: Unknown result type (might be due to invalid IL or missing references)
		//IL_0687: Unknown result type (might be due to invalid IL or missing references)
		//IL_068e: Expected O, but got Unknown
		//IL_06a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_06b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_06ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_06e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_06e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_06fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0715: Unknown result type (might be due to invalid IL or missing references)
		//IL_075f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0775: Unknown result type (might be due to invalid IL or missing references)
		//IL_078b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0795: Unknown result type (might be due to invalid IL or missing references)
		//IL_079c: Expected O, but got Unknown
		//IL_07c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_07d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_07ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_07fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0729: Unknown result type (might be due to invalid IL or missing references)
		//IL_0730: Expected O, but got Unknown
		//IL_0851: Unknown result type (might be due to invalid IL or missing references)
		//IL_0867: Unknown result type (might be due to invalid IL or missing references)
		//IL_0886: Unknown result type (might be due to invalid IL or missing references)
		//IL_088d: Expected O, but got Unknown
		//IL_08a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_08a9: Expected O, but got Unknown
		//IL_081b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0822: Expected O, but got Unknown
		//IL_094a: Unknown result type (might be due to invalid IL or missing references)
		//IL_094f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0950: Unknown result type (might be due to invalid IL or missing references)
		//IL_0957: Unknown result type (might be due to invalid IL or missing references)
		//IL_096c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0973: Expected O, but got Unknown
		//IL_099b: Unknown result type (might be due to invalid IL or missing references)
		//IL_09b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c15: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c2b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c41: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c8a: Unknown result type (might be du