Decompiled source of PEAK Quick Resume v2.3.0

PEAKQuickResume.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Peak;
using Peak.Network;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core;
using Zorro.Core.Serizalization;
using Zorro.UI;
using Zorro.UI.Modal;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PEAKQuickResume")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.3.0.0")]
[assembly: AssemblyInformationalVersion("2.3.0+a5afea9b4fa2d0354c7375d3ee999de07feb3231")]
[assembly: AssemblyProduct("PEAKQuickResume")]
[assembly: AssemblyTitle("PEAKQuickResume")]
[assembly: AssemblyVersion("2.3.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PEAKQuickResume
{
	public static class AchievementDebugLogging
	{
		private static ManualLogSource _log;

		public static void Apply(Harmony harmony, ManualLogSource log)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0051: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Expected O, but got Unknown
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Expected O, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Expected O, but got Unknown
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Expected O, but got Unknown
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Expected O, but got Unknown
			_log = log;
			try
			{
				Type typeFromHandle = typeof(AchievementManager);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "RecordMaxHeight", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AchievementDebugLogging), "RecordMaxHeight_Prefix", (Type[])null), new HarmonyMethod(typeof(AchievementDebugLogging), "RecordMaxHeight_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "IncrementSteamStat", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AchievementDebugLogging), "IncrementSteamStat_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "SetRunBasedInt", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AchievementDebugLogging), "SetRunBasedInt_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "SetRunBasedFloat", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AchievementDebugLogging), "SetRunBasedFloat_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "AddToRunBasedFruitsEaten", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AchievementDebugLogging), "FruitsEaten_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "AddToShroomBerriesEaten", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AchievementDebugLogging), "ShroomBerries_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "AddToNonToxicMushroomsEaten", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AchievementDebugLogging), "NonToxicMushrooms_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "AddToGourmandRequirementsEaten", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AchievementDebugLogging), "GourmandEaten_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "ThrowAchievement", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AchievementDebugLogging), "ThrowAchievement_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "TestWonRun", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AchievementDebugLogging), "TestWonRun_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeFromHandle, "TestRespawnChestOpened", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AchievementDebugLogging), "TestRespawnChestOpened_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				log.LogInfo((object)"AchievementDebugLogging: patched AchievementManager for [achievement-debug] logging.");
			}
			catch (Exception arg)
			{
				log.LogError((object)$"AchievementDebugLogging.Apply failed (non-fatal): {arg}");
			}
		}

		private static void RecordMaxHeight_Prefix(out int __state)
		{
			__state = 0;
			try
			{
				AchievementManager instance = Singleton<AchievementManager>.Instance;
				if (instance != null)
				{
					instance.GetSteamStatInt((STEAMSTATTYPE)5, ref __state);
				}
			}
			catch
			{
			}
		}

		private static void RecordMaxHeight_Postfix(int meters, int __state)
		{
			try
			{
				AchievementManager instance = Singleton<AchievementManager>.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				int num = default(int);
				instance.GetSteamStatInt((STEAMSTATTYPE)5, ref num);
				int runBasedInt = instance.GetRunBasedInt((RUNBASEDVALUETYPE)9);
				int num2 = num - __state;
				if (num2 != 0)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)($"[achievement-debug] HighAltitudeBadge: altitude check at {meters}m (this run's MaxHeightReached was {runBasedInt}m) " + $"-> CREDITED {num2}m to the permanent HeightClimbed stat (now {num}m total). If this happened right after a teleport/load, the fix did not work."));
					}
				}
				else
				{
					ManualLogSource log2 = _log;
					if (log2 != null)
					{
						log2.LogInfo((object)($"[achievement-debug] HighAltitudeBadge: altitude check at {meters}m (this run's MaxHeightReached was {runBasedInt}m) " + $"-> no credit (HeightClimbed stat stays at {num}m total). Correct behavior right after a teleport/load."));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = _log;
				if (log3 != null)
				{
					log3.LogWarning((object)("[achievement-debug] RecordMaxHeight_Postfix failed: " + ex.Message));
				}
			}
		}

		private static void IncrementSteamStat_Postfix(STEAMSTATTYPE steamStatType, int value, int __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((int)steamStatType == 5)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)$"[achievement-debug] HighAltitudeBadge: IncrementSteamStat(HeightClimbed, +{value}m) -> new total {__result}m.");
					}
				}
				else
				{
					ManualLogSource log2 = _log;
					if (log2 != null)
					{
						log2.LogInfo((object)$"[achievement-debug] Steam stat '{steamStatType}' incremented by {value} -> new total {__result}.");
					}
				}
			}
			catch
			{
			}
		}

		private static void SetRunBasedInt_Postfix(RUNBASEDVALUETYPE type, int value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if ((int)type == 6)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)$"[achievement-debug] PlundererBadge: {value}/15 luggages opened this run.");
				}
			}
			else if ((int)type == 15)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogInfo((object)$"[achievement-debug] JesterBadge: {value}/3 clown luggages opened this run.");
				}
			}
			else if ((int)type == 2)
			{
				ManualLogSource log3 = _log;
				if (log3 != null)
				{
					log3.LogInfo((object)$"[achievement-debug] ClutchBadge: {value}/3 scouts resurrected this run.");
				}
			}
			else
			{
				ManualLogSource log4 = _log;
				if (log4 != null)
				{
					log4.LogInfo((object)$"[achievement-debug] run-based int '{type}' set to {value}.");
				}
			}
		}

		private static void SetRunBasedFloat_Postfix(RUNBASEDVALUETYPE type, float value)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"[achievement-debug] run-based float '{type}' set to {value}.");
			}
		}

		private static void FruitsEaten_Postfix()
		{
			(int, int, int, int) eatenCounts = AchievementProgressIO.GetEatenCounts();
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"[achievement-debug] ForagingBadge: {eatenCounts.Item1}/5 different berries eaten this run.");
			}
		}

		private static void ShroomBerries_Postfix()
		{
			(int, int, int, int) eatenCounts = AchievementProgressIO.GetEatenCounts();
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"[achievement-debug] AdvancedMycologyBadge: {eatenCounts.Item2}/5 different Shroomberries eaten this run.");
			}
		}

		private static void NonToxicMushrooms_Postfix()
		{
			(int, int, int, int) eatenCounts = AchievementProgressIO.GetEatenCounts();
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"[achievement-debug] MycologyBadge: {eatenCounts.Item3}/4 different non-toxic mushrooms eaten this run.");
			}
		}

		private static void GourmandEaten_Postfix()
		{
			(int, int, int, int) eatenCounts = AchievementProgressIO.GetEatenCounts();
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"[achievement-debug] GourmandBadge: {eatenCounts.Item4}/4 required items cooked+eaten this run (coconut half, honeycomb, yellow winterberry, egg).");
			}
		}

		private static void TestWonRun_Postfix()
		{
			AchievementProgressIO.LogSnapshot("run-won", _log);
		}

		private static void TestRespawnChestOpened_Prefix(RespawnChest chest, Character opener)
		{
			try
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)("[achievement-debug] TestRespawnChestOpened: chest='" + ((chest != null) ? ((Object)chest).name : null) + "' opener='" + ((opener != null) ? opener.characterName : null) + "' " + $"(opener.IsLocal={((opener != null) ? new bool?(opener.IsLocal) : ((bool?)null))}). Character.AllCharacters snapshot:"));
				}
				foreach (Character allCharacter in Character.AllCharacters)
				{
					string arg = "?";
					try
					{
						arg = (((Object)(object)((allCharacter != null) ? allCharacter.player : null) != (Object)null) ? NetworkingUtilities.GetUserId(allCharacter.player) : "(no player)");
					}
					catch
					{
					}
					ManualLogSource log2 = _log;
					if (log2 != null)
					{
						log2.LogInfo((object)($"  - '{((allCharacter != null) ? allCharacter.characterName : null)}' instanceId={((allCharacter != null) ? new int?(((Object)allCharacter).GetInstanceID()) : ((int?)null))} userId={arg} " + $"dead={((allCharacter != null) ? new bool?(allCharacter.data.dead) : ((bool?)null))} fullyPassedOut={allCharacter?.data.fullyPassedOut} passedOut={allCharacter?.data.passedOut}"));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = _log;
				if (log3 != null)
				{
					log3.LogWarning((object)("[achievement-debug] TestRespawnChestOpened_Prefix failed: " + ex.Message));
				}
			}
		}

		private static void ThrowAchievement_Prefix(ACHIEVEMENTTYPE type)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				AchievementManager instance = Singleton<AchievementManager>.Instance;
				bool flag = (Object)(object)instance != (Object)null && instance.IsAchievementUnlocked(type);
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)$"[achievement-debug] ThrowAchievement({type}) called - already unlocked: {flag}.");
				}
			}
			catch
			{
			}
		}
	}
	public static class AchievementProgressIO
	{
		private static readonly Type NativeType = typeof(SerializableRunBasedValues);

		private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.NonPublic;

		private static readonly FieldInfo FRunBasedInts = NativeType.GetField("runBasedInts", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo FRunBasedFloats = NativeType.GetField("runBasedFloats", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo FFruits = NativeType.GetField("runBasedFruitsEaten", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo FShroomBerries = NativeType.GetField("shroomBerriesEaten", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo FNonToxicMushrooms = NativeType.GetField("nonToxicMushroomsEaten", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo FGourmand = NativeType.GetField("gourmandRequirementsEaten", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo FEarnedThisRun = NativeType.GetField("achievementsEarnedThisRun", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo FCompletedAscents = NativeType.GetField("completedAscentsThisRun", BindingFlags.Instance | BindingFlags.NonPublic);

		private static bool AnyFieldMissing()
		{
			if (!(FRunBasedInts == null) && !(FRunBasedFloats == null) && !(FFruits == null) && !(FShroomBerries == null) && !(FNonToxicMushrooms == null) && !(FGourmand == null) && !(FEarnedThisRun == null))
			{
				return FCompletedAscents == null;
			}
			return true;
		}

		public static (int fruits, int shroomBerries, int nonToxicMushrooms, int gourmand) GetEatenCounts()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)Singleton<AchievementManager>.Instance == (Object)null || AnyFieldMissing())
				{
					return (fruits: 0, shroomBerries: 0, nonToxicMushrooms: 0, gourmand: 0);
				}
				object obj = Singleton<AchievementManager>.Instance.runBasedValueData;
				int item = (FFruits.GetValue(obj) as List<ushort>)?.Count ?? 0;
				int item2 = (FShroomBerries.GetValue(obj) as List<ushort>)?.Count ?? 0;
				int item3 = (FNonToxicMushrooms.GetValue(obj) as List<ushort>)?.Count ?? 0;
				int item4 = (FGourmand.GetValue(obj) as List<ushort>)?.Count ?? 0;
				return (fruits: item, shroomBerries: item2, nonToxicMushrooms: item3, gourmand: item4);
			}
			catch
			{
				return (fruits: 0, shroomBerries: 0, nonToxicMushrooms: 0, gourmand: 0);
			}
		}

		public static OwnSavedAchievementProgress CaptureLocal(ManualLogSource log)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)Singleton<AchievementManager>.Instance == (Object)null)
				{
					return null;
				}
				return ToSaved(Singleton<AchievementManager>.Instance.runBasedValueData, log);
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("AchievementProgressIO.CaptureLocal failed (non-fatal): " + ex.Message));
				}
				return null;
			}
		}

		public static OwnSavedAchievementProgress ToSaved(object boxedNative, ManualLogSource log)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected I4, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected I4, but got Unknown
			try
			{
				if (boxedNative == null || AnyFieldMissing())
				{
					return null;
				}
				OwnSavedAchievementProgress ownSavedAchievementProgress = new OwnSavedAchievementProgress();
				if (FRunBasedInts.GetValue(boxedNative) is Dictionary<RUNBASEDVALUETYPE, int> dictionary)
				{
					foreach (KeyValuePair<RUNBASEDVALUETYPE, int> item in dictionary)
					{
						ownSavedAchievementProgress.runBasedInts[(int)item.Key] = item.Value;
					}
				}
				if (FRunBasedFloats.GetValue(boxedNative) is Dictionary<RUNBASEDVALUETYPE, float> dictionary2)
				{
					foreach (KeyValuePair<RUNBASEDVALUETYPE, float> item2 in dictionary2)
					{
						ownSavedAchievementProgress.runBasedFloats[(int)item2.Key] = item2.Value;
					}
				}
				if (FFruits.GetValue(boxedNative) is List<ushort> collection)
				{
					ownSavedAchievementProgress.runBasedFruitsEaten = new List<ushort>(collection);
				}
				if (FShroomBerries.GetValue(boxedNative) is List<ushort> collection2)
				{
					ownSavedAchievementProgress.shroomBerriesEaten = new List<ushort>(collection2);
				}
				if (FNonToxicMushrooms.GetValue(boxedNative) is List<ushort> collection3)
				{
					ownSavedAchievementProgress.nonToxicMushroomsEaten = new List<ushort>(collection3);
				}
				if (FGourmand.GetValue(boxedNative) is List<ushort> collection4)
				{
					ownSavedAchievementProgress.gourmandRequirementsEaten = new List<ushort>(collection4);
				}
				if (FEarnedThisRun.GetValue(boxedNative) is List<ACHIEVEMENTTYPE> source)
				{
					ownSavedAchievementProgress.achievementsEarnedThisRun = source.Select((ACHIEVEMENTTYPE a) => (int)a).ToList();
				}
				if (FCompletedAscents.GetValue(boxedNative) is List<int> collection5)
				{
					ownSavedAchievementProgress.completedAscentsThisRun = new List<int>(collection5);
				}
				return ownSavedAchievementProgress;
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("AchievementProgressIO.ToSaved failed (non-fatal): " + ex.Message));
				}
				return null;
			}
		}

		public static void ApplyLocal(OwnSavedAchievementProgress saved, ManualLogSource log)
		{
			//IL_0012: 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)
			try
			{
				if ((Object)(object)Singleton<AchievementManager>.Instance == (Object)null)
				{
					return;
				}
				object obj = SerializableRunBasedValues.ConstructNew();
				if (saved != null && !AnyFieldMissing())
				{
					Dictionary<RUNBASEDVALUETYPE, int> dictionary = new Dictionary<RUNBASEDVALUETYPE, int>();
					if (saved.runBasedInts != null)
					{
						foreach (KeyValuePair<int, int> runBasedInt in saved.runBasedInts)
						{
							if (runBasedInt.Key != 9)
							{
								dictionary[(RUNBASEDVALUETYPE)runBasedInt.Key] = runBasedInt.Value;
							}
						}
					}
					FRunBasedInts.SetValue(obj, dictionary);
					Dictionary<RUNBASEDVALUETYPE, float> dictionary2 = new Dictionary<RUNBASEDVALUETYPE, float>();
					if (saved.runBasedFloats != null)
					{
						foreach (KeyValuePair<int, float> runBasedFloat in saved.runBasedFloats)
						{
							dictionary2[(RUNBASEDVALUETYPE)runBasedFloat.Key] = runBasedFloat.Value;
						}
					}
					FRunBasedFloats.SetValue(obj, dictionary2);
					FFruits.SetValue(obj, new List<ushort>(saved.runBasedFruitsEaten ?? new List<ushort>()));
					FShroomBerries.SetValue(obj, new List<ushort>(saved.shroomBerriesEaten ?? new List<ushort>()));
					FNonToxicMushrooms.SetValue(obj, new List<ushort>(saved.nonToxicMushroomsEaten ?? new List<ushort>()));
					FGourmand.SetValue(obj, new List<ushort>(saved.gourmandRequirementsEaten ?? new List<ushort>()));
					List<ACHIEVEMENTTYPE> value = (saved.achievementsEarnedThisRun ?? new List<int>()).Select((int i) => (ACHIEVEMENTTYPE)i).ToList();
					FEarnedThisRun.SetValue(obj, value);
					FCompletedAscents.SetValue(obj, new List<int>(saved.completedAscentsThisRun ?? new List<int>()));
				}
				Singleton<AchievementManager>.Instance.InitRunBasedValues((SerializableRunBasedValues)obj);
				Player localPlayer = Player.localPlayer;
				if (localPlayer != null)
				{
					localPlayer.OnAchievementProgressChanged();
				}
				if (saved != null)
				{
					log.Trace("[achievement-debug] Restored this run's achievement progress from save:\n" + FormatDump(saved));
				}
				else
				{
					log.Trace("[achievement-debug] No saved achievement progress found - primed a fresh baseline (matches vanilla's own fresh-run behavior).");
				}
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("AchievementProgressIO.ApplyLocal failed (non-fatal): " + ex.Message));
				}
			}
		}

		private static string FormatDump(OwnSavedAchievementProgress saved)
		{
			string text = ((saved.runBasedInts != null && saved.runBasedInts.Count > 0) ? string.Join(", ", saved.runBasedInts.Select((KeyValuePair<int, int> kv) => $"{(object)(RUNBASEDVALUETYPE)kv.Key}={kv.Value}")) : "(none)");
			string text2 = ((saved.runBasedFloats != null && saved.runBasedFloats.Count > 0) ? string.Join(", ", saved.runBasedFloats.Select((KeyValuePair<int, float> kv) => $"{(object)(RUNBASEDVALUETYPE)kv.Key}={kv.Value}")) : "(none)");
			return "  ints: " + text + "\n  floats: " + text2 + "\n" + $"  fruitsEaten={saved.runBasedFruitsEaten?.Count ?? 0}, shroomBerriesEaten={saved.shroomBerriesEaten?.Count ?? 0}, " + $"nonToxicMushroomsEaten={saved.nonToxicMushroomsEaten?.Count ?? 0}, gourmandRequirementsEaten={saved.gourmandRequirementsEaten?.Count ?? 0}\n" + "  completedAscentsThisRun=[" + string.Join(",", saved.completedAscentsThisRun ?? new List<int>()) + "]";
		}

		public static void LogSnapshot(string tag, ManualLogSource log)
		{
			try
			{
				OwnSavedAchievementProgress ownSavedAchievementProgress = CaptureLocal(log);
				if (ownSavedAchievementProgress == null)
				{
					log.Trace("[achievement-debug] SNAPSHOT[" + tag + "]: AchievementManager not available, nothing to snapshot.");
					return;
				}
				string text = (((Object)(object)Character.localCharacter != (Object)null) ? Character.localCharacter.characterName : "(unknown)");
				log.Trace("[achievement-debug] SNAPSHOT[" + tag + "] for " + text + ":\n" + FormatDump(ownSavedAchievementProgress));
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("AchievementProgressIO.LogSnapshot(" + tag + ") failed (non-fatal): " + ex.Message));
				}
			}
		}

		public static string ToJson(OwnSavedAchievementProgress saved)
		{
			try
			{
				return (saved == null) ? null : JsonConvert.SerializeObject((object)saved);
			}
			catch
			{
				return null;
			}
		}

		public static OwnSavedAchievementProgress FromJson(string json, ManualLogSource log)
		{
			try
			{
				return string.IsNullOrEmpty(json) ? null : JsonConvert.DeserializeObject<OwnSavedAchievementProgress>(json);
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("AchievementProgressIO.FromJson failed (non-fatal): " + ex.Message));
				}
				return null;
			}
		}

		public static void RestoreAllPlayers(SaveSelection selection, OwnLoadEntryPoints entryPoints, ManualLogSource log, HashSet<string> alreadyRestored = null)
		{
			try
			{
				bool offline = selection.Offline;
				Player[] array = Object.FindObjectsByType<Player>((FindObjectsSortMode)0);
				log.Trace($"[achievement-debug] RestoreAllPlayers: {array.Length} player object(s) found.");
				Player[] array2 = array;
				foreach (Player val in array2)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					string text = (offline ? "" : NetworkingUtilities.GetUserId(val));
					if (alreadyRestored != null && alreadyRestored.Contains(text))
					{
						continue;
					}
					PhotonView component = ((Component)val).GetComponent<PhotonView>();
					OwnSavedAchievementProgress saved = null;
					if (selection.TryGetPlayerFile(text, out var path) && File.Exists(path))
					{
						try
						{
							saved = JsonConvert.DeserializeObject<OwnSaveData>(File.ReadAllText(path))?.achievementProgress;
						}
						catch (Exception ex)
						{
							if (log != null)
							{
								log.LogWarning((object)("AchievementProgressIO.RestoreAllPlayers: could not read save for userId '" + text + "': " + ex.Message));
							}
						}
					}
					else
					{
						log.Trace("AchievementProgressIO: skipping restore for '" + text + "' - no save file in this checkpoint's save event; priming a fresh baseline instead.");
					}
					if (offline || ((Object)(object)component != (Object)null && component.IsMine))
					{
						log.Trace("[achievement-debug] RestoreAllPlayers: '" + text + "' is this machine - applying locally.");
						ApplyLocal(saved, log);
						alreadyRestored?.Add(text);
					}
					else if (PhotonNetwork.IsMasterClient && (Object)(object)component != (Object)null)
					{
						entryPoints?.Network?.RestoreAchievementProgressFor(component, text, ToJson(saved));
						alreadyRestored?.Add(text);
					}
					else
					{
						log.Trace("[achievement-debug] RestoreAllPlayers: '" + text + "' NOT restored - " + string.Format("isMasterClient={0}, playerView={1}.", PhotonNetwork.IsMasterClient, ((Object)(object)component == (Object)null) ? "null" : "present"));
					}
				}
			}
			catch (Exception ex2)
			{
				if (log != null)
				{
					log.LogWarning((object)("AchievementProgressIO.RestoreAllPlayers failed (non-fatal): " + ex2.Message));
				}
			}
		}
	}
	public static class AchievementSubscriptionFix
	{
		private static ManualLogSource _log;

		private static MethodInfo _unsubscribe;

		public static void Apply(Harmony harmony, ManualLogSource log)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			_log = log;
			try
			{
				_unsubscribe = AccessTools.Method(typeof(AchievementManager), "UnsubscribeFromEvents", (Type[])null, (Type[])null);
				harmony.Patch((MethodBase)AccessTools.Method(typeof(AchievementManager), "SubscribeToEvents", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AchievementSubscriptionFix), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				log.LogInfo((object)"AchievementSubscriptionFix: patched AchievementManager.SubscribeToEvents (one achievement-event handler per manager, no double credit after a resume).");
			}
			catch (Exception arg)
			{
				log.LogError((object)$"AchievementSubscriptionFix.Apply failed (non-fatal): {arg}");
			}
		}

		private static void Prefix(AchievementManager __instance)
		{
			try
			{
				PurgeDestroyedSubscribers();
				if ((Object)(object)__instance != (Object)null)
				{
					_unsubscribe?.Invoke(__instance, null);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("AchievementSubscriptionFix.Prefix failed (non-fatal, subscribing anyway): " + ex.Message));
				}
			}
		}

		private static void PurgeDestroyedSubscribers()
		{
			int num = 0;
			FieldInfo[] fields = typeof(GlobalEvents).GetFields(BindingFlags.Static | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!typeof(Delegate).IsAssignableFrom(fieldInfo.FieldType) || !(fieldInfo.GetValue(null) is Delegate obj))
				{
					continue;
				}
				List<Delegate> list = new List<Delegate>();
				Delegate[] invocationList = obj.GetInvocationList();
				foreach (Delegate obj2 in invocationList)
				{
					object? target = obj2.Target;
					Object val = (Object)((target is Object) ? target : null);
					if (val != null && val == (Object)null)
					{
						num++;
					}
					else
					{
						list.Add(obj2);
					}
				}
				if (list.Count != obj.GetInvocationList().Length)
				{
					fieldInfo.SetValue(null, (list.Count == 0) ? null : Delegate.Combine(list.ToArray()));
				}
			}
			if (num > 0)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)($"AchievementSubscriptionFix: dropped {num} GlobalEvents handler(s) " + "belonging to destroyed objects (leftovers from a previous run)."));
				}
			}
		}
	}
	internal static class AfflictionArrayCompat
	{
		public static int CopyOverlap(float[] saved, float[] live)
		{
			if (saved == null || live == null)
			{
				return 0;
			}
			int num = Math.Min(saved.Length, live.Length);
			if (num <= 0)
			{
				return 0;
			}
			Array.Copy(saved, live, num);
			return num;
		}
	}
	public static class AncientStatueRestore
	{
		private const float StatueSearchRadius = 100f;

		private const float ItemSearchRadius = 8f;

		public static void Capture(Vector3 fallbackPos, HashSet<Item> claimed, ManualLogSource log, out OwnSavedStatueState state)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: 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_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			state = null;
			try
			{
				Vector3 val = CampfireAreaHelpers.ResolveNearestCampfirePos(fallbackPos);
				RespawnChest val2 = FindNearestStatue(val);
				if ((Object)(object)val2 == (Object)null)
				{
					log.Trace($"AncientStatueRestore.Capture: no Ancient Statue found within {100f}m of {val}.");
					return;
				}
				state = new OwnSavedStatueState
				{
					broken = ((Luggage)val2).IsOpen
				};
				log.Trace($"AncientStatueRestore.Capture: found statue '{((Object)val2).name}' at {((Component)val2).transform.position} " + $"({Vector3.Distance(((Component)val2).transform.position, val):F1}m from search center), broken={state.broken}.");
				if (!state.broken)
				{
					return;
				}
				Item val3 = CampfireAreaHelpers.FindNearestFreeItem(((Component)val2).transform.position, 8f, claimed);
				if ((Object)(object)val3 == (Object)null)
				{
					log.Trace("AncientStatueRestore.Capture: statue is broken but no unclaimed ground item found nearby.");
					return;
				}
				OwnSavedPositionedItem ownSavedPositionedItem = new OwnSavedPositionedItem
				{
					itemId = val3.itemID,
					posX = ((Component)val3).transform.position.x,
					posY = ((Component)val3).transform.position.y,
					posZ = ((Component)val3).transform.position.z,
					rotX = ((Component)val3).transform.rotation.x,
					rotY = ((Component)val3).transform.rotation.y,
					rotZ = ((Component)val3).transform.rotation.z,
					rotW = ((Component)val3).transform.rotation.w
				};
				foreach (KeyValuePair<string, OwnItemStateEntry> item in OwnItemStateIO.ReadItemStateValues(val3.data))
				{
					ownSavedPositionedItem.values[item.Key] = new OwnSavedEntry
					{
						type = item.Value.TypeName,
						value = item.Value.Value
					};
				}
				state.item = ownSavedPositionedItem;
				claimed?.Add(val3);
				log.Trace($"AncientStatueRestore.Capture: statue holds item '{((Object)val3).name}' (id={ownSavedPositionedItem.itemId}) at {((Component)val3).transform.position}.");
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("AncientStatueRestore.Capture failed (non-fatal): " + ex.Message));
				}
			}
		}

		public static void Restore(OwnSaveData data, Vector3 fallbackPos, ManualLogSource log)
		{
			//IL_0028: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			if (data?.ancientStatue == null || !data.ancientStatue.broken)
			{
				log.Trace("AncientStatueRestore.Restore: nothing to restore for this load (statue was unbroken when saved, or no save data).");
				return;
			}
			try
			{
				Vector3 val = CampfireAreaHelpers.ResolveNearestCampfirePos(fallbackPos);
				RespawnChest val2 = FindNearestStatue(val);
				if ((Object)(object)val2 == (Object)null)
				{
					if (log != null)
					{
						log.LogWarning((object)$"AncientStatueRestore: no Ancient Statue found within {100f}m of {val}, nothing to restore.");
					}
					return;
				}
				log.Trace($"AncientStatueRestore: found statue '{((Object)val2).name}' at {((Component)val2).transform.position} " + $"({Vector3.Distance(((Component)val2).transform.position, val):F1}m from search center), currently open={((Luggage)val2).IsOpen}.");
				if (((Luggage)val2).IsOpen)
				{
					return;
				}
				val2.Break();
				log.Trace("AncientStatueRestore: restored the Ancient Statue to its broken state.");
				OwnSavedPositionedItem item = data.ancientStatue.item;
				Item val3 = default(Item);
				if (item == null || !ItemDatabase.TryGetItem(item.itemId, ref val3) || !((Object)(object)val3 != (Object)null))
				{
					return;
				}
				Vector3 val4 = default(Vector3);
				((Vector3)(ref val4))..ctor(item.posX, item.posY, item.posZ);
				Quaternion val5 = default(Quaternion);
				((Quaternion)(ref val5))..ctor(item.rotX, item.rotY, item.rotZ, item.rotW);
				GameObject val6 = PhotonNetwork.InstantiateItemRoom(((Object)val3).name, val4, val5);
				if ((Object)(object)val6 != (Object)null)
				{
					PhotonView val7 = default(PhotonView);
					if (((Spawner)val2).isKinematic && val6.TryGetComponent<PhotonView>(ref val7))
					{
						val7.RPC("SetKinematicRPC", (RpcTarget)3, new object[3] { true, val4, val5 });
					}
					CampfireAreaHelpers.ApplySavedItemValues(val6, item.values, log);
					log.Trace($"AncientStatueRestore: respawned saved item {item.itemId} at {val4} on the Ancient Statue.");
				}
				else if (log != null)
				{
					log.LogWarning((object)$"AncientStatueRestore: InstantiateItemRoom returned null for item {item.itemId}.");
				}
			}
			catch (Exception arg)
			{
				if (log != null)
				{
					log.LogError((object)$"AncientStatueRestore.Restore failed (non-fatal): {arg}");
				}
			}
		}

		private static RespawnChest FindNearestStatue(Vector3 nearPos)
		{
			//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)
			RespawnChest result = null;
			float num = float.MaxValue;
			RespawnChest[] array = Object.FindObjectsByType<RespawnChest>((FindObjectsSortMode)0);
			foreach (RespawnChest val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					float num2 = Vector3.Distance(((Component)val).transform.position, nearPos);
					if (num2 <= 100f && num2 < num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}
	}
	internal static class AreaNameCompat
	{
		public static string ResolveAreaName(Segment segment, string legacyName, ManualLogSource log)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected I4, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if ((int)segment == 6)
			{
				return "NADIR";
			}
			try
			{
				MountainProgressHandler instance = Singleton<MountainProgressHandler>.Instance;
				ProgressPoint[] array = (((Object)(object)instance != (Object)null) ? instance.progressPoints : null);
				if (array == null)
				{
					return legacyName;
				}
				int num = (int)segment;
				if (num < 0 || num >= array.Length)
				{
					return legacyName;
				}
				string text = array[num]?.title;
				if (string.IsNullOrEmpty(text))
				{
					return legacyName;
				}
				if (text != legacyName)
				{
					log.Trace($"AreaNameCompat: segment {segment} resolved to area '{text}' (legacy naming would have said '{legacyName}').");
				}
				return text;
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)$"AreaNameCompat: could not resolve the area name for {segment} ({ex.Message}); using '{legacyName}'.");
				}
				return legacyName;
			}
		}
	}
	public static class BackpackSaveMitigation
	{
		private class TrackedDrop
		{
			public string UserId;

			public Backpack Backpack;
		}

		private class PendingRestore
		{
			public string UserId;

			public SaveTarget Target;

			public JArray BackpackItemStates;

			public int BackpackViewId;

			public int BackpackType;

			public JObject BackpackOwnValues;
		}

		private const byte BackpackSlotId = 3;

		private const float WatchRadius = 50f;

		private static ManualLogSource _log;

		private static Campfire _watchedCampfire;

		private static readonly Dictionary<string, TrackedDrop> _tracked = new Dictionary<string, TrackedDrop>();

		private static readonly List<PendingRestore> _pending = new List<PendingRestore>();

		public static void Apply(Harmony harmony, ManualLogSource log)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			_log = log;
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(CharacterItems), "DropItemRpc", (Type[])null, (Type[])null);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(BackpackSaveMitigation), "OnDropItemRpc", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Campfire), "Light_Rpc", (Type[])null, (Type[])null);
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(BackpackSaveMitigation), "OnLightRpc", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				log.LogInfo((object)"BackpackSaveMitigation: patched DropItemRpc/Light_Rpc (dropped-backpack save mitigation).");
			}
			catch (Exception arg)
			{
				log.LogError((object)$"BackpackSaveMitigation.Apply failed (non-fatal): {arg}");
			}
		}

		private static void OnDropItemRpc(byte slotID, Vector3 spawnPos, Character ___character)
		{
			//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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (slotID != 3 || !IsHostMachine() || (Object)(object)___character == (Object)null)
				{
					return;
				}
				Campfire val = FindNearestUnlitCampfire();
				if ((Object)(object)val == (Object)null || Vector3.Distance(((Component)val).transform.position, spawnPos) > 50f)
				{
					return;
				}
				Backpack val2 = FindNearestGroundBackpack(spawnPos);
				if (!((Object)(object)val2 == (Object)null))
				{
					if ((Object)(object)_watchedCampfire != (Object)(object)val)
					{
						_tracked.Clear();
						_watchedCampfire = val;
					}
					string text = SafeUserId(___character);
					if (_tracked.ContainsKey(text))
					{
						_log.Trace("[backpack-mitigation] Replacing an earlier tracked drop for userId '" + text + "' with this newer one (the earlier one now falls through to WorldItemRestore's normal ground-item save).");
					}
					_tracked[text] = new TrackedDrop
					{
						UserId = text,
						Backpack = val2
					};
					_log.Trace("[backpack-mitigation] Tracking a dropped backpack near the unlit campfire (owner userId '" + text + "').");
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogError((object)$"[backpack-mitigation] OnDropItemRpc failed (non-fatal): {arg}");
				}
			}
		}

		private static void OnLightRpc(Campfire __instance, bool updateSegment)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected I4, but got Unknown
			try
			{
				if (!updateSegment || !IsHostMachine())
				{
					return;
				}
				if ((Object)(object)_watchedCampfire != (Object)(object)__instance)
				{
					_tracked.Clear();
					_watchedCampfire = null;
					return;
				}
				foreach (TrackedDrop value in _tracked.Values)
				{
					if (!((Object)(object)value.Backpack == (Object)null) && (int)((Item)value.Backpack).itemState == 0 && !(Vector3.Distance(((Component)__instance).transform.position, ((Component)value.Backpack).transform.position) > 50f) && !PlayerAlreadyHasBackpack(value.UserId) && TryBuildBackpackItemStates(value.Backpack, out var states) && ((JContainer)states).Count != 0)
					{
						SaveTarget saveTarget = (RunLauncher.IsCustomRun ? SaveTarget.Custom() : SaveTarget.Normal(Ascents.currentAscent));
						_pending.Add(new PendingRestore
						{
							UserId = value.UserId,
							Target = saveTarget,
							BackpackItemStates = states,
							BackpackViewId = ((MonoBehaviourPun)value.Backpack).photonView.ViewID,
							BackpackType = (int)value.Backpack.backpackType,
							BackpackOwnValues = BuildBackpackOwnValues(value.Backpack)
						});
						_log.Trace($"[backpack-mitigation] Queued a backpack restore for userId '{value.UserId}' ({saveTarget}, {((JContainer)states).Count} item(s)).");
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogError((object)$"[backpack-mitigation] OnLightRpc failed (non-fatal): {arg}");
				}
			}
			finally
			{
				_tracked.Clear();
				_watchedCampfire = null;
			}
		}

		public static void ApplyPendingRestores(bool offline, string stamp, ManualLogSource log)
		{
			if (_pending.Count == 0)
			{
				return;
			}
			foreach (PendingRestore restore in _pending)
			{
				if (SaveArchive.PatchSaveFile(OwnSavePaths.For(restore.Target, offline, restore.UserId, stamp), delegate(JObject json)
				{
					json["hasBackpack"] = JToken.op_Implicit(true);
					json["backpackType"] = JToken.op_Implicit(restore.BackpackType);
					json["backpackItemStates"] = (JToken)(object)restore.BackpackItemStates;
					if (restore.BackpackOwnValues != null)
					{
						json["backpackOwnValues"] = (JToken)(object)restore.BackpackOwnValues;
					}
				}, log))
				{
					log.Trace("[backpack-mitigation] Restored a dropped backpack into the save for userId '" + restore.UserId + "'.");
				}
				else if (log != null)
				{
					log.LogWarning((object)("[backpack-mitigation] Could not find a save file for userId '" + restore.UserId + "' to restore the dropped backpack into."));
				}
			}
			_pending.Clear();
		}

		public static HashSet<int> GetPendingBackpackViewIds()
		{
			HashSet<int> hashSet = new HashSet<int>();
			foreach (PendingRestore item in _pending)
			{
				hashSet.Add(item.BackpackViewId);
			}
			return hashSet;
		}

		private static bool TryBuildBackpackItemStates(Backpack backpack, out JArray states)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Expected O, but got Unknown
			states = new JArray();
			try
			{
				BackpackData val = default(BackpackData);
				if (((Item)backpack).data == null || !((Item)backpack).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val) || val?.itemSlots == null)
				{
					return false;
				}
				for (byte b = 0; b < val.itemSlots.Length; b++)
				{
					ItemSlot val2 = val.itemSlots[b];
					if (val2 != null && !val2.IsEmpty() && !((Object)(object)val2.prefab == (Object)null) && val2.data != null)
					{
						JObject val3 = new JObject();
						foreach (KeyValuePair<string, OwnItemStateEntry> item in OwnItemStateIO.ReadItemStateValues(val2.data))
						{
							val3[item.Key] = (JToken)new JObject
							{
								["type"] = JToken.op_Implicit(item.Value.TypeName),
								["value"] = JToken.op_Implicit(item.Value.Value)
							};
						}
						states.Add((JToken)new JObject
						{
							["slotIndex"] = JToken.op_Implicit(b),
							["itemId"] = JToken.op_Implicit(val2.prefab.itemID),
							["values"] = (JToken)(object)val3
						});
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[backpack-mitigation] Could not read dropped backpack contents: " + ex.Message));
				}
				return false;
			}
		}

		private static JObject BuildBackpackOwnValues(Backpack backpack)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			try
			{
				if (((Item)(backpack?)).data == null)
				{
					return null;
				}
				JObject val = new JObject();
				foreach (KeyValuePair<string, OwnItemStateEntry> item in OwnItemStateIO.ReadItemStateValues(((Item)backpack).data))
				{
					val[item.Key] = (JToken)new JObject
					{
						["type"] = JToken.op_Implicit(item.Value.TypeName),
						["value"] = JToken.op_Implicit(item.Value.Value)
					};
				}
				return (((JContainer)val).Count > 0) ? val : null;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[backpack-mitigation] Could not read the dropped backpack's own stats: " + ex.Message));
				}
				return null;
			}
		}

		private static bool PlayerAlreadyHasBackpack(string userId)
		{
			try
			{
				foreach (Character allPlayerCharacter in PlayerHandler.GetAllPlayerCharacters())
				{
					if (!(SafeUserId(allPlayerCharacter) != userId))
					{
						return BackpackTypeCompat.HasAny(allPlayerCharacter.player);
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static Campfire FindNearestUnlitCampfire()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Character localCharacter = Character.localCharacter;
				if ((Object)(object)localCharacter == (Object)null)
				{
					return null;
				}
				Vector3 center = localCharacter.Center;
				Campfire result = null;
				float num = float.MaxValue;
				Campfire[] array = Object.FindObjectsByType<Campfire>((FindObjectsSortMode)0);
				foreach (Campfire val in array)
				{
					if (!val.Lit)
					{
						float num2 = Vector3.Distance(((Component)val).transform.position, center);
						if (num2 < num)
						{
							num = num2;
							result = val;
						}
					}
				}
				return result;
			}
			catch
			{
				return null;
			}
		}

		private static Backpack FindNearestGroundBackpack(Vector3 near)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Backpack result = null;
			float num = float.MaxValue;
			Backpack[] array = Object.FindObjectsByType<Backpack>((FindObjectsSortMode)0);
			foreach (Backpack val in array)
			{
				if ((int)((Item)val).itemState == 0)
				{
					float num2 = Vector3.Distance(((Component)val).transform.position, near);
					if (num2 < num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		private static string SafeUserId(Character c)
		{
			try
			{
				Player owner = ((MonoBehaviourPun)c).photonView.Owner;
				return ((owner != null) ? owner.UserId : null) ?? "";
			}
			catch
			{
				return "";
			}
		}

		private static bool IsHostMachine()
		{
			if (!PhotonNetwork.OfflineMode)
			{
				return PhotonNetwork.IsMasterClient;
			}
			return true;
		}
	}
	internal static class BackpackTypeCompat
	{
		public const int NoBackpack = 0;

		public const int PlainBackpack = 1;

		public static bool HasAny(Player p)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if (p?.backpackSlot != null)
			{
				return (int)p.backpackSlot.backpackType > 0;
			}
			return false;
		}

		public static bool HasAny(BackpackSlot slot)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			if (slot != null)
			{
				return (int)slot.backpackType > 0;
			}
			return false;
		}

		public static int Capture(Player p)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected I4, but got Unknown
			if (p?.backpackSlot == null)
			{
				return 0;
			}
			return (int)p.backpackSlot.backpackType;
		}

		public static int FromSave(bool legacyHasBackpack, int savedBackpackType)
		{
			if (savedBackpackType != 0)
			{
				return savedBackpackType;
			}
			return legacyHasBackpack ? 1 : 0;
		}

		public static bool TryResolveItemId(int backpackType, out ushort itemId, ManualLogSource log)
		{
			//IL_0009: 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_00ce: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			itemId = 0;
			if (backpackType == 0)
			{
				return false;
			}
			BackpackType val = (BackpackType)backpackType;
			string text = PrefabNameFor(backpackType);
			try
			{
				Dictionary<ushort, Item> dictionary = SingletonAsset<ItemDatabase>.Instance?.itemLookup;
				if (dictionary != null)
				{
					foreach (KeyValuePair<ushort, Item> item in dictionary)
					{
						Item value = item.Value;
						Backpack val2 = (Backpack)(object)((value is Backpack) ? value : null);
						if (val2 != null && val2.backpackType == val)
						{
							itemId = item.Key;
							return true;
						}
					}
				}
				Item val3 = default(Item);
				if (ItemDatabase.TryGetItem(text, ref val3) && (Object)(object)val3 != (Object)null)
				{
					itemId = val3.itemID;
					return true;
				}
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)$"BackpackTypeCompat: backpack lookup for type {val} failed ({ex.Message}) - skipping the backpack restore.");
				}
				return false;
			}
			if (log != null)
			{
				log.LogWarning((object)$"BackpackTypeCompat: no prefab for backpack type {val} ('{text}') in the item database - skipping the backpack restore.");
			}
			return false;
		}

		public static void EnsureFuelCaptured(Item fuelSource, ItemInstanceData data, Dictionary<string, OwnSavedEntry> values, ManualLogSource log)
		{
			if ((Object)(object)fuelSource == (Object)null || values == null || values.ContainsKey("Fuel"))
			{
				return;
			}
			try
			{
				JetpackItem component = ((Component)fuelSource).GetComponent<JetpackItem>();
				if (!((Object)(object)component == (Object)null))
				{
					FloatItemData val = default(FloatItemData);
					float fuel;
					string arg;
					if (data != null && data.TryGetDataEntry<FloatItemData>((DataEntryKey)10, ref val) && val != null)
					{
						fuel = val.Value;
						arg = "stored entry";
					}
					else if (fuelSource.data == data && TryReadLiveFuel(component, out fuel))
					{
						arg = "live JetpackItem.fuel";
					}
					else
					{
						fuel = component.startingFuel;
						arg = "startingFuel default";
					}
					values["Fuel"] = new OwnSavedEntry
					{
						type = typeof(FloatItemData).AssemblyQualifiedName,
						value = fuel
					};
					if (log != null)
					{
						log.LogInfo((object)("OwnSaveCapture: '" + ((Object)fuelSource).name + "' had no saved Fuel value; stamped " + $"Fuel={fuel:0.###} from its {arg} (without this it would restore as a full tank)."));
					}
				}
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("BackpackTypeCompat: could not capture jetpack fuel (" + ex.Message + "); it may come back full."));
				}
			}
		}

		private static bool TryReadLiveFuel(JetpackItem jetpack, out float fuel)
		{
			fuel = 0f;
			FieldInfo field = typeof(JetpackItem).GetField("fuel", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return false;
			}
			if (!(field.GetValue(jetpack) is float num))
			{
				return false;
			}
			fuel = num;
			return true;
		}

		private static string PrefabNameFor(int backpackType)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected I4, but got Unknown
			BackpackType val = (BackpackType)backpackType;
			return (val - 2) switch
			{
				0 => "Fannypack", 
				1 => "Jetpack", 
				2 => "Rocketpack", 
				_ => "Backpack", 
			};
		}
	}
	internal static class CampfireAreaHelpers
	{
		private const float CampfireSearchRadius = 30f;

		public static Vector3 ResolveNearestCampfirePos(Vector3 fallbackPos)
		{
			//IL_0090: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Campfire val = null;
				float num = float.MaxValue;
				Campfire[] array = Object.FindObjectsByType<Campfire>((FindObjectsSortMode)0);
				foreach (Campfire val2 in array)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						float num2 = Vector3.Distance(((Component)val2).transform.position, fallbackPos);
						if (num2 <= 30f && num2 < num)
						{
							num = num2;
							val = val2;
						}
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					return ((Component)val).transform.position;
				}
				if (NadirSearchRadius.CurrentlyInNadir())
				{
					Vector3 val3 = ResolveNearestSoulPillarPos(fallbackPos);
					if (val3 != fallbackPos)
					{
						return val3;
					}
				}
			}
			catch
			{
			}
			return fallbackPos;
		}

		private static Vector3 ResolveNearestSoulPillarPos(Vector3 fallbackPos)
		{
			//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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			ScoutmasterSoulPillar val = null;
			float num = float.MaxValue;
			ScoutmasterSoulPillar[] array = Object.FindObjectsByType<ScoutmasterSoulPillar>((FindObjectsSortMode)0);
			foreach (ScoutmasterSoulPillar val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					float num2 = Vector3.Distance(((Component)val2).transform.position, fallbackPos);
					if (num2 <= 80f && num2 < num)
					{
						num = num2;
						val = val2;
					}
				}
			}
			if (!((Object)(object)val != (Object)null))
			{
				return fallbackPos;
			}
			return ((Component)val).transform.position;
		}

		public static bool IsFreeWorldItem(Item item, bool includeBackpacks = false)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null || (int)item.itemState != 0)
			{
				return false;
			}
			if (!includeBackpacks && item is Backpack)
			{
				return false;
			}
			if ((Object)(object)((Component)item).GetComponentInParent<Player>(true) != (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)item).GetComponentInParent<Character>(true) != (Object)null)
			{
				return false;
			}
			return true;
		}

		public static Item FindNearestFreeItem(Vector3 pos, float radius, HashSet<Item> exclude = null)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			Item result = null;
			float num = float.MaxValue;
			Item[] array = Object.FindObjectsByType<Item>((FindObjectsSortMode)0);
			foreach (Item val in array)
			{
				if (IsFreeWorldItem(val) && (exclude == null || !exclude.Contains(val)))
				{
					float num2 = Vector3.Distance(((Component)val).transform.position, pos);
					if (num2 <= radius && num2 < num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		public static List<Item> FindFreeItemsWithin(Vector3 pos, float radius, bool includeBackpacks = false, HashSet<Item> exclude = null)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			return (from item in Object.FindObjectsByType<Item>((FindObjectsSortMode)0)
				where IsFreeWorldItem(item, includeBackpacks) && (exclude == null || !exclude.Contains(item)) && Vector3.Distance(((Component)item).transform.position, pos) <= radius
				orderby Vector3.Distance(((Component)item).transform.position, pos)
				select item).ToList();
		}

		public static ItemInstanceData BuildItemInstanceData(Dictionary<string, OwnSavedEntry> values, ManualLogSource log)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			ItemInstanceData val = new ItemInstanceData(Guid.NewGuid());
			ItemInstanceDataHandler.AddInstanceData(val);
			if (values == null)
			{
				return val;
			}
			foreach (KeyValuePair<string, OwnSavedEntry> value2 in values)
			{
				if (OwnItemStateIO.TryGetKey(value2.Key, out var key))
				{
					OwnSavedEntry value = value2.Value;
					if (value != null && !OwnItemStateIO.TrySetOrCreateEntry(val, key, value.type, value.value, log) && log != null)
					{
						log.LogWarning((object)("CampfireAreaHelpers.BuildItemInstanceData: could not apply '" + value2.Key + "'."));
					}
				}
			}
			return val;
		}

		public static void PushItemInstanceData(GameObject spawned, ItemInstanceData instanceData, ManualLogSource log)
		{
			if ((Object)(object)spawned == (Object)null || instanceData == null)
			{
				return;
			}
			PhotonView val = default(PhotonView);
			if (!spawned.TryGetComponent<PhotonView>(ref val))
			{
				if (log != null)
				{
					log.LogWarning((object)"CampfireAreaHelpers.PushItemInstanceData: spawned item has no PhotonView.");
				}
			}
			else
			{
				val.RPC("SetItemInstanceDataRPC", (RpcTarget)0, new object[1] { instanceData });
			}
		}

		public static void ApplySavedItemValues(GameObject spawned, Dictionary<string, OwnSavedEntry> values, ManualLogSource log)
		{
			if (values != null && values.Count != 0)
			{
				PushItemInstanceData(spawned, BuildItemInstanceData(values, log), log);
			}
		}
	}
	public static class CampfireAutoSavePatch
	{
		private static PluginConfig _cfg;

		private static OwnLoadEntryPoints _entryPoints;

		private static OwnNetwork _network;

		private static ManualLogSource _log;

		public static void Apply(Harmony harmony, PluginConfig cfg, OwnLoadEntryPoints entryPoints, OwnNetwork network, ManualLogSource log)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Campfire), "Light_Rpc", (Type[])null, (Type[])null);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(CampfireAutoSavePatch), "Postfix", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				log.LogInfo((object)"CampfireAutoSavePatch: patched Campfire.Light_Rpc (canonical autosave, reached on the host however the fire was lit).");
				_cfg = cfg;
				_entryPoints = entryPoints;
				_network = network;
				_log = log;
			}
			catch (Exception arg)
			{
				log.LogError((object)$"CampfireAutoSavePatch.Apply failed (non-fatal): {arg}");
			}
		}

		private static void Postfix(Campfire __instance, bool updateSegment)
		{
			try
			{
				if (!updateSegment || ((Object)__instance).name.Contains("PortableStovetop_Placed") || ((Object)(object)_entryPoints != (Object)null && _entryPoints.RecentlyLitCampfireUntil > Time.time))
				{
					return;
				}
				_entryPoints?.ArmRecentlyLitCampfireCooldown(32f);
				_entryPoints?.ArmRecentlyLoadedCooldown(30f);
				if (PhotonNetwork.OfflineMode || PhotonNetwork.IsMasterClient)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogInfo((object)"CampfireAutoSavePatch: campfire lit -> autosave triggered.");
					}
					AchievementProgressIO.LogSnapshot("campfire-lit", _log);
					if (PhotonNetwork.OfflineMode)
					{
						OwnSaveCapture.SavePlayerOffline(_cfg, _log, _network?.MessageOverlay, __instance);
						return;
					}
					_network?.RecentlyLitCampfireOthers();
					OwnSaveCapture.SavePlayerCoop(_cfg, _log, _network, __instance);
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogError((object)$"CampfireAutoSavePatch.Postfix failed (non-fatal): {arg}");
				}
			}
		}
	}
	internal static class CampfireIgniteBuffCompat
	{
		public static (float extraStamina, int petrifyAmount) Apply(Campfire campfire, Character character, float rawExtraStamina, int rawPetrifyAmount, float[] currentStatuses)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)campfire == (Object)null || (Object)(object)character == (Object)null)
			{
				return (extraStamina: rawExtraStamina, petrifyAmount: rawPetrifyAmount);
			}
			if (Vector3.Distance(((Component)campfire).transform.position, character.Center) > campfire.moraleBoostRadius)
			{
				return (extraStamina: rawExtraStamina, petrifyAmount: rawPetrifyAmount);
			}
			float num = 1f - (float)rawPetrifyAmount * 0.01f;
			float item = Mathf.Clamp(rawExtraStamina + campfire.moraleBoostBaseline, 0f, num);
			int item2 = Mathf.Clamp(rawPetrifyAmount - 20, 0, 100);
			int num2 = 0;
			if (currentStatuses != null && num2 < currentStatuses.Length)
			{
				currentStatuses[num2] = Mathf.Clamp(currentStatuses[num2] - 0.2f, 0f, 1f);
			}
			return (extraStamina: item, petrifyAmount: item2);
		}
	}
	public static class DeathStateRestore
	{
		private const string ReviveRpcName = "ReviveCharacter";

		public static HashSet<string> ResolveSavedDeadUserIds(SaveSelection selection, ManualLogSource log)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			if (selection == null || selection.Offline || !PhotonNetwork.IsMasterClient)
			{
				return hashSet;
			}
			try
			{
				int num = 0;
				Player[] array = Object.FindObjectsByType<Player>((FindObjectsSortMode)0);
				foreach (Player val in array)
				{
					Character val2 = (((Object)(object)val != (Object)null) ? val.character : null);
					if (!((Object)(object)val2 == (Object)null))
					{
						string userId = NetworkingUtilities.GetUserId(val2.player);
						if (WasSavedDead(selection, userId, log))
						{
							hashSet.Add(userId);
						}
						else
						{
							num++;
						}
					}
				}
				if (hashSet.Count > 0 && num == 0)
				{
					if (log != null)
					{
						log.LogWarning((object)($"DeathStateRestore: the loaded checkpoint has all {hashSet.Count} player(s) " + "recorded as dead; skipping the death restore entirely rather than ending the run on load."));
					}
					hashSet.Clear();
				}
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("DeathStateRestore.ResolveSavedDeadUserIds failed (non-fatal, everyone stays alive): " + ex.Message));
				}
				hashSet.Clear();
			}
			return hashSet;
		}

		public static void ApplySavedDeaths(HashSet<string> deadUserIds, OwnLoadEntryPoints entryPoints, ManualLogSource log)
		{
			if (deadUserIds == null || deadUserIds.Count == 0 || !PhotonNetwork.IsMasterClient)
			{
				return;
			}
			try
			{
				Player[] array = Object.FindObjectsByType<Player>((FindObjectsSortMode)0);
				foreach (Player val in array)
				{
					Character val2 = (((Object)(object)val != (Object)null) ? val.character : null);
					if ((Object)(object)val2 == (Object)null || !deadUserIds.Contains(NetworkingUtilities.GetUserId(val2.player)) || val2.data.dead)
					{
						continue;
					}
					try
					{
						SuppressWatchdogFor(val, val2, entryPoints, log);
						((MonoBehaviourPun)val2).photonView.RPC("RPCA_SetDead", (RpcTarget)0, Array.Empty<object>());
						log.Trace("DeathStateRestore: restored " + val2.characterName + " as dead (they were dead when this checkpoint was saved).");
					}
					catch (Exception ex)
					{
						if (log != null)
						{
							log.LogWarning((object)("DeathStateRestore: could not restore " + val2.characterName + " as dead (non-fatal): " + ex.Message));
						}
					}
				}
			}
			catch (Exception ex2)
			{
				if (log != null)
				{
					log.LogWarning((object)("DeathStateRestore.ApplySavedDeaths failed (non-fatal, everyone stays alive): " + ex2.Message));
				}
			}
		}

		public static void EnsureUnsavedPlayersAlive(HashSet<string> deadUserIds, ManualLogSource log)
		{
			if (!PhotonNetwork.IsMasterClient || PhotonNetwork.OfflineMode)
			{
				return;
			}
			try
			{
				Player[] array = Object.FindObjectsByType<Player>((FindObjectsSortMode)0);
				foreach (Player val in array)
				{
					Character val2 = (((Object)(object)val != (Object)null) ? val.character : null);
					if ((Object)(object)val2 == (Object)null || (Object)(object)((MonoBehaviourPun)val2).photonView == (Object)null || (deadUserIds != null && deadUserIds.Contains(NetworkingUtilities.GetUserId(val2.player))) || !val2.data.dead)
					{
						continue;
					}
					try
					{
						((MonoBehaviourPun)val2).photonView.RPC("ReviveCharacter", (RpcTarget)0, new object[1] { false });
						if (log != null)
						{
							log.LogInfo((object)("DeathStateRestore: " + val2.characterName + " died during the load and this checkpoint records no death for them - revived so they come back alive."));
						}
					}
					catch (Exception ex)
					{
						if (log != null)
						{
							log.LogWarning((object)("DeathStateRestore: could not revive " + val2.characterName + " (non-fatal): " + ex.Message));
						}
					}
				}
			}
			catch (Exception ex2)
			{
				if (log != null)
				{
					log.LogWarning((object)("DeathStateRestore.EnsureUnsavedPlayersAlive failed (non-fatal): " + ex2.Message));
				}
			}
		}

		private static void SuppressWatchdogFor(Player player, Character ch, OwnLoadEntryPoints entryPoints, ManualLogSource log)
		{
			try
			{
				PhotonView component = ((Component)player).GetComponent<PhotonView>();
				if ((Object)(object)component != (Object)null && component.IsMine)
				{
					entryPoints?.Network?.Watchdog?.SuppressForRestoredDeath();
				}
				else if ((Object)(object)component != (Object)null)
				{
					entryPoints?.Network?.SuppressWatchdogForRestoredDeath(component, NetworkingUtilities.GetUserId(ch.player));
				}
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("DeathStateRestore: could not suppress the teleport watchdog for " + ch.characterName + " (non-fatal, they may see a spurious teleport-bug hint): " + ex.Message));
				}
			}
		}

		private static bool WasSavedDead(SaveSelection selection, string userId, ManualLogSource log)
		{
			if (!selection.TryGetPlayerFile(userId, out var path))
			{
				log.Trace("DeathStateRestore: '" + userId + "' has no file in this checkpoint's save event (joined after it was written, most likely) - restoring them alive.");
				return false;
			}
			try
			{
				return JsonConvert.DeserializeObject<OwnSaveData>(File.ReadAllText(path))?.isDead ?? false;
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("DeathStateRestore: could not read the save for '" + userId + "' (" + ex.Message + ") - restoring them alive."));
				}
				return false;
			}
		}
	}
	internal static class DebugLog
	{
		public static void Trace(this ManualLogSource log, string message)
		{
			if (log != null && Plugin.DebugLoggingEnabled)
			{
				log.LogInfo((object)message);
			}
		}
	}
	public static class DeployableRestore
	{
		private const float SearchRadius = 30f;

		private const int MaxPerType = 20;

		public static void CaptureStoves(Vector3 fallbackPos, ManualLogSource log, out List<OwnSavedDeployableState> states)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Capture("PortableStovetop_Placed", "Portable Stove", fallbackPos, log, out states);
		}

		public static void CaptureCannons(Vector3 fallbackPos, ManualLogSource log, out List<OwnSavedDeployableState> states)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Capture("ScoutCannon_Placed", "Scout Cannon", fallbackPos, log, out states);
		}

		public static void RestoreStoves(OwnSaveData data, Vector3 fallbackPos, ManualLogSource log)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Restore("PortableStovetop_Placed", "Portable Stove", data?.portableStoves, fallbackPos, log);
		}

		public static void RestoreCannons(OwnSaveData data, Vector3 fallbackPos, ManualLogSource log)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Restore("ScoutCannon_Placed", "Scout Cannon", data?.scoutCannons, fallbackPos, log);
		}

		private static void Capture(string prefabNameNeedle, string label, Vector3 fallbackPos, ManualLogSource log, out List<OwnSavedDeployableState> states)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			states = new List<OwnSavedDeployableState>();
			try
			{
				Vector3 val = CampfireAreaHelpers.ResolveNearestCampfirePos(fallbackPos);
				float num = NadirSearchRadius.ForCurrentSegment(30f);
				List<PhotonView> list = FindPlayerPlaced(prefabNameNeedle, val, num);
				foreach (PhotonView item in list)
				{
					if (states.Count >= 20)
					{
						if (log != null)
						{
							log.LogWarning((object)$"DeployableRestore.Capture({label}): hit the {20}-item cap within {num}m of {val}, stopping early.");
						}
						break;
					}
					Transform transform = ((Component)item).transform;
					states.Add(new OwnSavedDeployableState
					{
						posX = transform.position.x,
						posY = transform.position.y,
						posZ = transform.position.z,
						rotX = transform.rotation.x,
						rotY = transform.rotation.y,
						rotZ = transform.rotation.z,
						rotW = transform.rotation.w
					});
				}
				log.Trace($"DeployableRestore.Capture({label}): found {list.Count} player-placed within {num}m of {val}, saved {states.Count}.");
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("DeployableRestore.Capture(" + label + ") failed (non-fatal): " + ex.Message));
				}
			}
		}

		private static void Restore(string prefabName, string label, List<OwnSavedDeployableState> saved, Vector3 fallbackPos, ManualLogSource log)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if (saved == null || saved.Count == 0)
			{
				log.Trace("DeployableRestore.Restore(" + label + "): nothing to restore for this load.");
				return;
			}
			try
			{
				int num = 0;
				Vector3 val = default(Vector3);
				Quaternion val2 = default(Quaternion);
				foreach (OwnSavedDeployableState item in saved)
				{
					if (item == null)
					{
						continue;
					}
					((Vector3)(ref val))..ctor(item.posX, item.posY, item.posZ);
					((Quaternion)(ref val2))..ctor(item.rotX, item.rotY, item.rotZ, item.rotW);
					if ((Object)(object)PhotonNetwork.Instantiate(prefabName, val, val2, (byte)0, (object[])null) == (Object)null)
					{
						if (log != null)
						{
							log.LogWarning((object)("DeployableRestore.Restore(" + label + "): PhotonNetwork.Instantiate('" + prefabName + "') returned null."));
						}
					}
					else
					{
						num++;
					}
				}
				log.Trace($"DeployableRestore.Restore({label}): restored {num}/{saved.Count} within range of the loaded campfire.");
			}
			catch (Exception arg)
			{
				if (log != null)
				{
					log.LogError((object)$"DeployableRestore.Restore({label}) failed (non-fatal): {arg}");
				}
			}
		}

		internal static List<PhotonView> FindPlayerPlaced(string nameNeedle, Vector3 center, float radius)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			List<PhotonView> list = new List<PhotonView>();
			PhotonView[] array = Object.FindObjectsByType<PhotonView>((FindObjectsSortMode)0);
			foreach (PhotonView val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Object)((Component)val).gameObject).name.Contains(nameNeedle))
				{
					bool isRoomView;
					try
					{
						isRoomView = val.IsRoomView;
					}
					catch
					{
						continue;
					}
					if (!isRoomView && val.CreatorActorNr > 0 && Vector3.Distance(((Component)val).transform.position, center) <= radius)
					{
						list.Add(val);
					}
				}
			}
			return list;
		}
	}
	public static class FairootsCompat
	{
		private const float MaxWaitSeconds = 25f;

		private static MethodInfo _shouldHold;

		private static bool _resolved;

		private static bool _loggedUnavailable;

		public static IEnumerator WaitUntilReady(ManualLogSource log, Action onFrame = null)
		{
			if (!Resolve(log))
			{
				yield break;
			}
			float waited = 0f;
			bool everWaited = false;
			while (waited < 25f && ShouldHold(log))
			{
				if (!everWaited)
				{
					everWaited = true;
					log.Trace("FairootsCompat: Fairoots is preparing the Roots biome - holding the loading screen.");
				}
				onFrame?.Invoke();
				waited += Time.unscaledDeltaTime;
				yield return null;
			}
			if (waited >= 25f)
			{
				if (log != null)
				{
					log.LogWarning((object)$"FairootsCompat: Fairoots still busy after {25f:F0}s - taking the loading screen down anyway.");
				}
			}
			else if (everWaited)
			{
				log.Trace($"FairootsCompat: Fairoots finished after {waited:F1}s - continuing.");
			}
		}

		private static bool ShouldHold(ManualLogSource log)
		{
			try
			{
				object obj = _shouldHold.Invoke(null, null);
				bool flag = default(bool);
				int num;
				if (obj is bool)
				{
					flag = (bool)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("FairootsCompat: Fairoots' hold check threw (" + ex.GetType().Name + "); not waiting on it."));
				}
				_shouldHold = null;
				return false;
			}
		}

		private static bool Resolve(ManualLogSource log)
		{
			if (_resolved)
			{
				return _shouldHold != null;
			}
			_resolved = true;
			try
			{
				Type type = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => string.Equals(a.GetName().Name, "Fairoots", StringComparison.OrdinalIgnoreCase))?.GetType("Fairoots.FairootsInterop");
				if (type == null)
				{
					return false;
				}
				_shouldHold = type.GetMethod("ShouldHoldLoadingScreen", BindingFlags.Static | BindingFlags.Public);
				if (_shouldHold == null || _shouldHold.ReturnType != typeof(bool))
				{
					_shouldHold = null;
					if (!_loggedUnavailable)
					{
						_loggedUnavailable = true;
						if (log != null)
						{
							log.LogWarning((object)"FairootsCompat: Fairoots is installed but Fairoots.FairootsInterop.ShouldHoldLoadingScreen() was not found - the loading screen will not wait for it. Mod update?");
						}
					}
					return false;
				}
				log.Trace("FairootsCompat: Fairoots detected - the loading screen will wait for its Roots setup.");
				return true;
			}
			catch (Exception ex)
			{
				_shouldHold = null;
				if (log != null)
				{
					log.LogWarning((object)("FairootsCompat: could not resolve Fairoots (non-fatal): " + ex.GetType().Name + ": " + ex.Message));
				}
				return false;
			}
		}
	}
	public static class GameUpdateModalSuppressPatch
	{
		private static ManualLogSource _log;

		private static OwnMessageOverlay _messageOverlay;

		private static bool _noticeShownThisSession;

		public static void Apply(Harmony harmony, ManualLogSource log, OwnMessageOverlay messageOverlay)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			_log = log;
			_messageOverlay = messageOverlay;
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Modal), "OpenModal", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					log.LogWarning((object)"GameUpdateModalSuppressPatch: Modal.OpenModal not found; the vanilla 'game updated, close to continue' popup can still force-quit the game at the Airport.");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(GameUpdateModalSuppressPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				log.LogInfo((object)"GameUpdateModalSuppressPatch: patched Modal.OpenModal.");
			}
			catch (Exception arg)
			{
				log.LogError((object)$"GameUpdateModalSuppressPatch.Apply failed (non-fatal): {arg}");
			}
		}

		private static bool Prefix(HeaderModalOption headerContent)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				DefaultHeaderModalOption val = (DefaultHeaderModalOption)(object)((headerContent is DefaultHeaderModalOption) ? headerContent : null);
				if (val == null)
				{
					return true;
				}
				if (!IsOutOfDateTitle(val.Title))
				{
					return true;
				}
				_log.LogWarning((object)"Suppressed the vanilla game-update modal (would have force-quit on the only button). The game server reports a newer build is available. DO NOT update or restart PEAK until everyone is done with this save - the currently running game keeps working fine, but an update mid-save (especially a map-pool rotation) can make this save load the wrong island for good.");
				if ((Object)(object)_messageOverlay != (Object)null && !_noticeShownThisSession)
				{
					_noticeShownThisSession = true;
					_messageOverlay.Show(MessagesLocalization.Get(MsgKey.GameUpdateDialogSuppressed), new Color(1f, 0.55f, 0.3f, 1f), 12f);
				}
				return false;
			}
			catch (Exception arg)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogError((object)$"GameUpdateModalSuppressPatch.Prefix failed (non-fatal, letting the vanilla modal through): {arg}");
				}
				return true;
			}
		}

		private static bool IsOutOfDateTitle(string title)
		{
			if (string.IsNullOrEmpty(title))
			{
				return false;
			}
			if (!(title == LocalizedText.GetText("VERSIONOUTOFDATE", true)))
			{
				return title == LocalizedText.GetText("MODAL_OUTOFDATE_TITLE", true);
			}
			return true;
		}
	}
	internal static class GameVersionCompat
	{
		public const string NoVersionDisplay = "v?.??.?";

		public const string LegacySettingsVersion6GameVersion = "1.64.a";

		public static string Current => Application.version;

		public static string Display(string version)
		{
			return "v" + version;
		}

		public static bool IsOlderThan(string version, string current)
		{
			if (string.IsNullOrEmpty(version))
			{
				return true;
			}
			if (version == current)
			{
				return false;
			}
			if (TryParse(version, out var major, out var minor, out var letter) && TryParse(current, out var major2, out var minor2, out letter))
			{
				if (major != major2)
				{
					return major < major2;
				}
				return minor < minor2;
			}
			return true;
		}

		private static bool TryParse(string version, out int major, out int minor, out char letter)
		{
			major = 0;
			minor = 0;
			letter = '\0';
			if (string.IsNullOrEmpty(version))
			{
				return false;
			}
			string[] array = version.Split('.');
			if (array.Length != 3)
			{
				return false;
			}
			if (!int.TryParse(array[0], out major))
			{
				return false;
			}
			if (!int.TryParse(array[1], out minor))
			{
				return false;
			}
			if (array[2].Length != 1)
			{
				return false;
			}
			letter = array[2][0];
			return true;
		}
	}
	internal static class HeightAchievementGuard
	{
		private static ManualLogSource _log;

		private static bool _patched;

		private static int _suppressDepth;

		private static float _suppressedUntil = -1f;

		private const float MaxSuppressionSeconds = 180f;

		private static bool Suppressed
		{
			get
			{
				if (_suppressDepth > 0 && Time.realtimeSinceStartup >= _suppressedUntil)
				{
					_suppressDepth = 0;
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)"HeightAchievementGuard: the no-credit window outlasted its safety timeout (a load that never finished?); height credit resumes normally from here.");
					}
				}
				return _suppressDepth > 0;
			}
		}

		public static void Apply(Harmony harmony, ManualLogSource log)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			_log = log;
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(AchievementManager), "RecordMaxHeight", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					log.LogWarning((object)"HeightAchievementGuard: AchievementManager.RecordMaxHeight not found - loading a save may inflate the HeightClimbed stat.");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(HeightAchievementGuard), "RecordMaxHeightPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_patched = true;
				log.LogInfo((object)"HeightAchievementGuard: patched AchievementManager.RecordMaxHeight (no height credit while loading).");
			}
			catch (Exception arg)
			{
				log.LogError((object)$"HeightAchievementGuard.Apply failed (non-fatal): {arg}");
			}
		}

		private static bool RecordMaxHeightPrefix(AchievementManager __instance, int meters)
		{
			if (!Suppressed)
			{
				return true;
			}
			try
			{
				if ((Object)(object)__instance != (Object)null && meters >= 25)
				{
					int runBasedInt = __instance.GetRunBasedInt((RUNBASEDVALUETYPE)9);
					if (meters >= runBasedInt + 5)
					{
						__instance.SetRunBasedInt((RUNBASEDVALUETYPE)9, meters);
					}
				}
			}
			catch
			{
			}
			return false;
		}

		public static void Suppress(string reason)
		{
			if (_patched)
			{
				_suppressDepth++;
				_suppressedUntil = Time.realtimeSinceStartup + 180f;
				if (_suppressDepth == 1)
				{
					_log.Trace("HeightAchievementGuard: height credit paused (" + reason + ").");
				}
			}
		}

		public static void Release(string reason)
		{
			if (_patched && Suppressed)
			{
				_suppressDepth--;
				if (_suppressDepth <= 0)
				{
					SeedMarkFromCurrentAltitude();
					_log.Trace("HeightAchievementGuard: height credit resumed (" + reason + ").");
				}
			}
		}

		private static void SeedMarkFromCurrentAltitude()
		{
			try
			{
				Character localCharacter = Character.localCharacter;
				AchievementManager instance = Singleton<AchievementManager>.Instance;
				CharacterStats val = (((Object)(object)localCharacter != (Object)null && localCharacter.refs != null) ? localCharacter.refs.stats : null);
				if ((Object)(object)localCharacter == (Object)null || (Object)(object)instance == (Object)null || (Object)(object)val == (Object)null)
				{
					return;
				}
				int num = Mathf.RoundToInt(val.heightInMeters);
				if (num < 25)
				{
					return;
				}
				int runBasedInt = instance.GetRunBasedInt((RUNBASEDVALUETYPE)9);
				if (runBasedInt < num)
				{
					instance.SetRunBasedInt((RUNBASEDVALUETYPE)9, num);
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogInfo((object)($"HeightAchievementGuard: set this run's height mark to {num}m (was {runBasedInt}m) " + "so the altitude you were restored at isn't credited as a fresh climb."));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("HeightAchievementGuard: could not seed the height mark (" + ex.Message + "); the HeightClimbed stat may gain your current altitude once."));
				}
			}
		}
	}
	public class HelpScreen : MonoBehaviour
	{
		private ManualLogSource _log;

		private PluginConfig _cfg;

		private GameObject _root;

		private Image _dimImage;

		private float _dimFadeElapsed;

		private const float DimFadeDuration = 0.25f;

		private Image _panelFillImage;

		private Image _grainImage;

		private RectTransform _panelRect;

		private RectTransform _bodyRect;

		private TextMeshProUGUI _titleText;

		private TextMeshProUGUI _bodyText;

		private TMP_FontAsset _font;

		private GameObject _loadingRoot;

		private bool _uiWarmedUp;

		private bool _warmingUp;

		private int _jagFrame;

		private float _jagFrameTimer;

		private int _lastWidth;

		private int _lastHeight;

		private const float BodyFontSize = 20f;

		private const float TitleFontSize = 27f;

		private const float FooterGap = 14f;

		private const float TitleBodyGap = 10f;

		private TextMeshProUGUI _footerKeyText;

		private TextMeshProUGUI _footerLabelText;

		private RectTransform _footerRow;

		public bool IsOpen { get; private set; }

		private bool MinimalUi
		{
			get
			{
				if (_cfg != null)
				{
					return _cfg.MinimalPickerUi.Value;
				}
				return false;
			}
		}

		public void Init(ManualLogSource log, PluginConfig cfg)
		{
			_log = log;
			_cfg = cfg;
		}

		public void Open()
		{
			IsOpen = true;
			if (!_uiWarmedUp)
			{
				EnsureLoadingUi();
				GameObject loadingRoot = _loadingRoot;
				if (loadingRoot != null)
				{
					loadingRoot.SetActive(true);
				}
				if (!_warmingUp)
				{
					_warmingUp = true;
					((MonoBehaviour)this).StartCoroutine(WarmUpThenShow());
				}
			}
			else
			{
				ShowReal(skipDimFade: false);
			}
		}

		public void Close()
		{
			GameObject root = _root;
			if (root != null)
			{
				root.SetActive(false);
			}
			GameObject loadingRoot = _loadingRoot;
			if (loadingRoot != null)
			{
				loadingRoot.SetActive(false);
			}
			IsOpen = false;
		}

		private IEnumerator WarmUpThenShow()
		{
			yield return null;
			ShowReal(skipDimFade: true);
			GameObject loadingRoot = _loadingRoot;
			if (loadingRoot != null)
			{
				loadingRoot.SetActive(false);
			}
			_uiWarmedUp = true;
			_warmingUp = false;
		}

		private void ShowReal(bool skipDimFade)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			EnsureUi();
			RebuildContent();
			GameObject root = _root;
			if (root != null)
			{
				root.SetActive(true);
			}
			if (skipDimFade)
			{
				if ((Object)(object)_dimImage != (Object)null)
				{
					((Graphic)_dimImage).color = SavePicker.DimColor;
				}
				_dimFadeElapsed = 0.25f;
			}
			else
			{
				if ((Object)(object)_dimImage != (Object)null)
				{
					((Graphic)_dimImage).color = new Color(SavePicker.DimColor.r, SavePicker.DimColor.g, SavePicker.DimColor.b, 0f);
				}
				_dimFadeElapsed = 0f;
			}
		}

		private void Update()
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOpen || (Object)(object)_root == (Object)null || !_root.activeSelf)
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				Close();
				PauseSuppressPatch.SuppressNextOpen();
				return;
			}
			if ((Object)(object)_dimImage != (Object)null && _dimFadeElapsed < 0.25f)
			{
				_dimFadeElapsed += Time.unscaledDeltaTime;
				float num = Mathf.Clamp01(_dimFadeElapsed / 0.25f);
				((Graphic)_dimImage).color = new Color(SavePicker.DimColor.r, SavePicker.DimColor.g, SavePicker.DimColor.b, SavePicker.DimColor.a * num);
			}
			if (MinimalUi)
			{
				return;
			}
			_jagFrameTimer += Time.unscaledDeltaTime;
			if (_jagFrameTimer >= 0.5f)
			{
				_jagFrameTimer -= 0.5f;
				_jagFrame = (_jagFrame + 1) % 3;
				if ((Object)(object)_panelFillImage != (Object)null)
				{
					_panelFillImage.sprite = SavePicker.PanelSprite(_lastWidth, _lastHeight, _jagFrame, minimal: false);
				}
			}
		}

		private void EnsureLoadingUi()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			if ((Object)(object)_loadingRoot != (Object)null)
			{
				return;
			}
			try
			{
				if ((Object)(object)_font == (Object)null)
				{
					_font = SavePicker.FindGameFont();
				}
				_loadingRoot = new GameObject("PEAKQuickResume_HelpScreen_Loading", new Type[1] { typeof(RectTransform) });
				_loadingRoot.transform.SetParent(((Component)this).transform, false);
				Canvas obj = _loadingRoot.AddComponent<Canvas>();
				obj.renderMode = (RenderMode)0;
				obj.sortingOrder = 30001;
				SavePicker.ApplyWidescreenScaler(obj);
				GameObject val = new GameObject("Dim", new Type[1] { typeof(RectTransform) });
				val.transform.SetParent(_loadingRoot.transform, false);
				((Graphic)val.AddComponent<Image>()).color = SavePicker.DimColor;
				SavePicker.StretchFull((RectTransform)val.transform);
				TextMeshProUGUI obj2 = MakeText("LoadingText", 27f, (TextAlignmentOptions)514, SavePicker.TitleColor);
				((TMP_Text)obj2).transform.SetParent(_loadingRoot.transform, false);
				SavePicker.ApplyChromeTextStyle(obj2);
				((TMP_Text)obj2).text = SavePickerLocalization.Get(PickerText.Loading);
				SavePicker.StretchFull((RectTransform)((TMP_Text)obj2).transform);
				_loadingRoot.SetActive(false);
			}
			catch (Exception arg)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogError((object)$"HelpScreen.EnsureLoadingUi failed (non-fatal): {arg}");
				}
			}
		}

		private void EnsureUi()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Expected O, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Expected O, but got Unknown
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: 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_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: 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_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Expected O, but got Unknown
			//IL_0308: 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_0340: Expected O, but got Unknown
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to i