Decompiled source of Summit to Shore v1.0.0

tony4twenty-Summit to Shore.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Peak;
using Photon.Pun;
using UnityEngine;
using UnityEngine.SceneManagement;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyTitle("Summit to Shore")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Summit to Shore")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f56ddae7-f2fc-44ba-8cd8-3e9f356dca3f")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace SummitToShore
{
	[BepInPlugin("tony4twentys.Summit_to_Shore", "Summit to Shore", "1.0.0")]
	[BepInProcess("PEAK.exe")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "tony4twentys.Summit_to_Shore";

		public const string PluginName = "Summit to Shore";

		public const string PluginVersion = "1.0.0";

		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static ConfigEntry<int> CrashTakeChance { get; private set; }

		private void Awake()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			CrashTakeChance = ((BaseUnityPlugin)this).Config.Bind<int>("End Cutscene", "CrashTakeChance", 15, new ConfigDescription("Percent chance the rescue heli explodes on the fly-away (0 = always steer 45° out, 100 = always crash).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			SceneManager.sceneLoaded += OnSceneLoaded;
			_harmony = new Harmony("tony4twentys.Summit_to_Shore");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Summit to Shore v1.0.0 loaded.");
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			ReverseRun.ResetForScene(((Scene)(ref scene)).name);
		}
	}
	internal static class ReverseRun
	{
		private struct PlaneNodeDump
		{
			public string RelPath;

			public bool Active;

			public Vector3 LocalPos;

			public Quaternion LocalRot;

			public Vector3 LocalScale;
		}

		private const string CrashedPlaneName = "crashed plane";

		private const string EmbeddedPlaneDumpName = "SummitToShore.PlaneDump.txt";

		private const string EmbeddedPlayerDumpName = "SummitToShore.PlayerDump.txt";

		private static readonly Quaternion DumpedPlaneRot = new Quaternion(-0.11304f, -0.33602f, 0.03631f, 0.93434f);

		private static readonly Vector3 CitadelFlagStanding = new Vector3(6.04f, 1233.954f, 2242.54f);

		private static readonly Vector3 KilnFlagStanding = new Vector3(19.34f, 1233.954f, 2242.54f);

		private static readonly Vector3 DumpedPlayerCenter = new Vector3(9.19f, 1221.62f, 2230.23f);

		private static readonly Vector3 BingBongLocalPos = new Vector3(-13.96797f, -6.62793f, -11.88213f);

		private static readonly Quaternion BingBongLocalRot = new Quaternion(0.37629f, -0.7051f, 0.42452f, 0.42546f);

		private static readonly string[] PeakPlatformNames = new string[2] { "Peak_Kiln Variant", "Peak" };

		private static readonly List<Segment> ReversedOrder = new List<Segment>(8);

		private static readonly HashSet<int> NonProgressCampfires = new HashSet<int>();

		private static bool _scanned;

		private static bool _layoutApplied;

		private static bool _started;

		private static bool _starting;

		private const float CrashSiteRadius = 50f;

		private static bool _openedShore;

		private static int _unlocksDone;

		private static bool _won;

		private static bool _heliSummoned;

		private static bool _endgameMoved;

		private static bool _flareBoxMoved;

		private static bool _playedPeakTitle;

		private static bool _playedShoreTitle;

		private static bool _waiting;

		private static Vector3 _shoreAnchor;

		private static bool _hasShoreAnchor;

		private static bool _hasShoreStinger;

		private static Vector3 _shoreStinger;

		private static bool _campfireTransition;

		private static List<Vector3> _spawnDeck;

		private static List<Vector3> _spawnPool;

		private static Transform _spawnedBingBong;

		private const float MaxBingBongFromPlane = 40f;

		internal static bool HasWon => _won;

		internal static bool IsActive
		{
			get
			{
				if (_scanned)
				{
					return ReversedOrder.Count > 0;
				}
				return false;
			}
		}

		internal static bool IsRunning
		{
			get
			{
				if (IsActive)
				{
					return _started;
				}
				return false;
			}
		}

		internal static bool IsStarting => _starting;

		internal static void ResetForScene(string sceneName)
		{
			ReversedOrder.Clear();
			NonProgressCampfires.Clear();
			_campfireTransition = false;
			_scanned = false;
			_layoutApplied = false;
			_started = false;
			_starting = false;
			_openedShore = false;
			_unlocksDone = 0;
			_won = false;
			_heliSummoned = false;
			_endgameMoved = false;
			_flareBoxMoved = false;
			_playedPeakTitle = false;
			_playedShoreTitle = false;
			_waiting = false;
			_hasShoreAnchor = false;
			_hasShoreStinger = false;
			_spawnDeck = null;
			_spawnPool = null;
			_spawnedBingBong = null;
			if (!string.IsNullOrEmpty(sceneName) && sceneName.StartsWith("Level_", StringComparison.OrdinalIgnoreCase) && (Object)(object)Plugin.Instance != (Object)null)
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(WaitForGenerationThenApply());
			}
		}

		internal static IEnumerator WaitForGenerationThenApply()
		{
			if (!_waiting)
			{
				_waiting = true;
				float elapsed = 0f;
				while (elapsed < 90f && !_scanned && !MapHandler.ExistsAndInitialized)
				{
					elapsed += Time.unscaledDeltaTime;
					yield return null;
				}
				yield return null;
				ScanIfNeeded();
				ApplyStartLayout();
				_waiting = false;
			}
		}

		internal static void ScanIfNeeded()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Invalid comparison between Unknown and I4
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Invalid comparison between Unknown and I4
			//IL_0112: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			if (_scanned || !MapHandler.Exists)
			{
				return;
			}
			MapHandler instance = Singleton<MapHandler>.Instance;
			MapSegment[] segments = instance.segments;
			if (segments == null || segments.Length == 0)
			{
				return;
			}
			ReversedOrder.Clear();
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < segments.Length; i++)
			{
				MapSegment val = segments[i];
				if (val == null || (Object)(object)val.segmentParent == (Object)null)
				{
					continue;
				}
				Segment val2 = (Segment)(byte)i;
				if ((int)val2 != 6 && (int)val2 != 5 && (int)val.biome != 17)
				{
					ReversedOrder.Add(val2);
					if (stringBuilder.Length > 0)
					{
						stringBuilder.Append(" -> ");
					}
					stringBuilder.Append(val2).Append(" (").Append(val.biome)
						.Append(')');
				}
			}
			if (ReversedOrder.Count == 0)
			{
				return;
			}
			ReversedOrder.Reverse();
			_scanned = true;
			StringBuilder stringBuilder2 = new StringBuilder();
			for (int j = 0; j < ReversedOrder.Count; j++)
			{
				if (j > 0)
				{
					stringBuilder2.Append(" -> ");
				}
				stringBuilder2.Append(ReversedOrder[j]);
			}
			Plugin.Log.LogInfo((object)$"Scanned climb: {stringBuilder}");
			Plugin.Log.LogInfo((object)$"Reversed run: {stringBuilder2}");
			LogClimbSlots(instance);
		}

		internal static void ApplyStartLayout()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (!MapHandler.Exists)
			{
				return;
			}
			try
			{
				ScanIfNeeded();
				if (IsActive)
				{
					CaptureShoreAnchor();
					if (!_layoutApplied)
					{
						MoveFlareBoxToShore();
						_layoutApplied = true;
						Plugin.Log.LogInfo((object)$"Start layout applied. Shore flare drop {_shoreAnchor}. Plane moves after Citadel/Peak load.");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("ApplyStartLayout failed: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		internal static void TryStartFromPeak(bool timerActive)
		{
			if (!_started && !_starting && !_won && timerActive && GameHandler.IsOnIsland && MapHandler.ExistsAndInitialized && !Quicksave.ShouldUseSaveData)
			{
				ScanIfNeeded();
				ApplyStartLayout();
				if (IsActive && !((Object)(object)Plugin.Instance == (Object)null))
				{
					_starting = true;
					((MonoBehaviour)Plugin.Instance).StartCoroutine(StartFromPeakRoutine());
				}
			}
		}

		private static IEnumerator StartFromPeakRoutine()
		{
			while ((Object)(object)Character.localCharacter == (Object)null)
			{
				yield return null;
			}
			yield return (object)new WaitForSeconds(2.5f);
			if (_won)
			{
				_starting = false;
				yield break;
			}
			if (_started && (int)GetCurrentSegment() != 0)
			{
				_starting = false;
				yield break;
			}
			Segment top = GetTopClimbSegment();
			Plugin.Log.LogInfo((object)$"Starting reverse run: JumpToSegment({top}), then warp to Peak.");
			SuppressEndgameObjects();
			if (PhotonNetwork.IsMasterClient)
			{
				try
				{
					MapHandler.JumpToSegment(top);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)$"JumpToSegment({top}) failed: {ex.GetType().Name}: {ex.Message}");
					_starting = false;
					yield break;
				}
			}
			float timeoutAt = Time.time + 10f;
			while (Time.time < timeoutAt && GetCurrentSegment() != top)
			{
				yield return (object)new WaitForSeconds(0.1f);
			}
			if (GetCurrentSegment() != top)
			{
				Plugin.Log.LogError((object)$"Timed out waiting for {top}. Staying on Shore; reverse start aborted.");
				_starting = false;
				yield break;
			}
			Plugin.Log.LogInfo((object)$"{top} is loaded. Waiting for Kiln/Citadel warp to finish, then enabling the Peak (flag) platform.");
			yield return (object)new WaitForSeconds(1.5f);
			EnablePeakPlatform();
			SuppressEndgameObjects();
			DisableRisingHazards();
			yield return null;
			yield return null;
			Vector3 peakStandingPosition = GetPeakStandingPosition();
			List<Vector3> playerSpawnPositions = GetPlayerSpawnPositions(peakStandingPosition);
			Plugin.Log.LogInfo((object)$"Summit flag {peakStandingPosition}. {playerSpawnPositions.Count} player spawn(s), first {playerSpawnPositions[0]}.");
			MoveCrashedPlaneToPosition(peakStandingPosition);
			MoveSpawnPointsToDumps(playerSpawnPositions);
			if (PhotonNetwork.IsMasterClient)
			{
				WarpEveryoneToAssignedSpawns(playerSpawnPositions);
			}
			yield return (object)new WaitForSeconds(0.35f);
			SuppressEndgameObjects();
			try
			{
				UnlightProgressCampfires();
				PatchCampfiresForDescent();
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)("Campfire setup failed: " + ex2.GetType().Name + ": " + ex2.Message));
			}
			finally
			{
				_started = true;
				_starting = false;
			}
			ParkEndgameAtShore();
			PlayPeakTitle();
			Plugin.Log.LogInfo((object)$"Reverse run ready at {GetCurrentSegment()}. Light the Kiln/Temple fire to open the next lower biome; fog will unload the previous segment and leave its campfire leftover.");
			if (!PhotonNetwork.IsMasterClient)
			{
				yield break;
			}
			try
			{
				SpawnCrashedPlaneItems();
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogError((object)("Crashed-plane item spawn failed: " + ex3.GetType().Name + ": " + ex3.Message));
			}
		}

		internal static bool ShouldBlockSegmentAdvance(Campfire fire)
		{
			if (!IsRunning || (Object)(object)fire == (Object)null)
			{
				return false;
			}
			return NonProgressCampfires.Contains(((Object)fire).GetInstanceID());
		}

		internal static bool ShouldSkipAutoLight()
		{
			if (!IsActive)
			{
				return _starting;
			}
			return true;
		}

		internal static void AdvanceFromCampfire()
		{
			//IL_0061: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (!IsActive || _won || _campfireTransition || _starting)
			{
				return;
			}
			if (!TryGetNextSegment(out var next))
			{
				if (!_openedShore && (int)GetCurrentSegment() == 0 && (Object)(object)Plugin.Instance != (Object)null)
				{
					Plugin.Log.LogWarning((object)"Still on Shore after reverse start — retrying Kiln jump + Peak warp.");
					((MonoBehaviour)Plugin.Instance).StartCoroutine(StartFromPeakRoutine());
				}
				return;
			}
			if ((int)next == 0)
			{
				_openedShore = true;
			}
			Plugin.Log.LogInfo((object)$"Campfire: {GetCurrentSegment()} -> {next}");
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(DescendByReveal(next));
			}
		}

		private static IEnumerator DescendByReveal(Segment next)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			_campfireTransition = true;
			try
			{
				yield return ReverseGoToSegment(next);
				DisableRisingHazards();
				SuppressEndgameObjects();
				yield return (object)new WaitForSeconds(0.2f);
				PatchCampfiresForDescent();
				_unlocksDone++;
				if ((int)next != 0)
				{
					PlaySegmentTitle(next);
				}
				Plugin.Log.LogInfo((object)$"Opened {next} for descent. Current={GetCurrentSegment()}.");
			}
			finally
			{
				_campfireTransition = false;
			}
		}

		private static IEnumerator ReverseGoToSegment(Segment next)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null || instance.segments == null)
			{
				yield break;
			}
			int startIndex = GetClimbIndex(GetCurrentSegment());
			int nextIndex = GetClimbIndex(next);
			if (nextIndex < 0 || nextIndex >= instance.segments.Length)
			{
				Plugin.Log.LogWarning((object)$"Reverse GoToSegment: no slot for {next}.");
				yield break;
			}
			MapSegment startSlot = ((startIndex >= 0 && startIndex < instance.segments.Length) ? instance.segments[startIndex] : null);
			MapSegment nextSlot = instance.segments[nextIndex];
			if (nextSlot == null || (Object)(object)nextSlot.segmentParent == (Object)null)
			{
				Plugin.Log.LogWarning((object)$"Reverse GoToSegment: {next} has no parent.");
				yield break;
			}
			Plugin.Log.LogInfo((object)$"Reverse GoToSegment {GetCurrentSegment()} -> {next}. Fog, unload {startIndex} mesh, keep leftover fire, enable {nextIndex}.");
			try
			{
				if ((Object)(object)Character.localCharacter != (Object)null && (Object)(object)Character.localCharacter.data != (Object)null)
				{
					Character.localCharacter.data.DestroyCheckpointFlags();
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("DestroyCheckpointFlags failed: " + ex.Message));
			}
			SetCurrentSegment(instance, nextIndex);
			if ((int)next == 0)
			{
				_openedShore = true;
			}
			yield return WaitForFogCatchUpSafe();
			yield return (object)new WaitForSecondsRealtime(1f);
			UnloadSegmentKeepCampfire(startSlot, startIndex);
			yield return null;
			EnableOpenedSegment(nextSlot, next);
			if ((int)next == 0)
			{
				ActivateNamedCampfire("Beach_Campfire");
			}
			Segment next2;
			bool flag = TryGetNextSegment(out next2);
			if (flag)
			{
				ArmGateCampfire(next2);
			}
			HideOlderCampfires(startSlot, nextSlot, flag ? GetClimbSlot(next2) : null);
			if (PhotonNetwork.IsMasterClient)
			{
				SpawnSegmentItems(nextSlot, next);
			}
			try
			{
				if ((Object)(object)nextSlot.dayNightProfile != (Object)null && (Object)(object)DayNightManager.instance != (Object)null)
				{
					DayNightManager.instance.BlendProfiles(nextSlot.dayNightProfile);
				}
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogWarning((object)("Day/night blend failed: " + ex2.Message));
			}
			yield return OpenFogForDescent();
			try
			{
				if ((int)next != 4 && (Object)(object)Singleton<OrbFogHandler>.Instance != (Object)null)
				{
					Singleton<OrbFogHandler>.Instance.SetFogOrigin(nextIndex);
				}
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogWarning((object)("Fog origin failed: " + ex3.Message));
			}
		}

		private static void EnableOpenedSegment(MapSegment slot, Segment id)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			if (slot != null && !((Object)(object)slot.segmentParent == (Object)null))
			{
				try
				{
					MapHandler.ActivateWithoutMessageQueue(slot.segmentParent);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("ActivateWithoutMessageQueue failed: " + ex.Message));
					ActivateInHierarchy(slot.segmentParent);
				}
				EnableBiomeRoot(slot.segmentParent);
				EnableSubsteps(slot.segmentParent);
				if ((Object)(object)slot.segmentCampfire != (Object)null)
				{
					ActivateInHierarchy(slot.segmentCampfire);
					slot.segmentCampfire.SetActive(true);
				}
				if ((Object)(object)slot.wallNext != (Object)null)
				{
					slot.wallNext.SetActive(true);
				}
				if ((Object)(object)slot.wallPrevious != (Object)null)
				{
					slot.wallPrevious.SetActive(true);
				}
				LogSegmentContents(slot.segmentParent, id);
			}
		}

		private static void ArmGateCampfire(Segment gate)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			MapSegment climbSlot = GetClimbSlot(gate);
			if (climbSlot == null || (Object)(object)climbSlot.segmentCampfire == (Object)null)
			{
				Plugin.Log.LogWarning((object)$"No leftover campfire to arm for {gate}.");
				return;
			}
			ActivateInHierarchy(climbSlot.segmentCampfire);
			climbSlot.segmentCampfire.SetActive(true);
			if ((Object)(object)climbSlot.segmentParent != (Object)null)
			{
				climbSlot.segmentParent.SetActive(false);
			}
			UnlightCampfire(climbSlot.segmentCampfire.GetComponentInChildren<Campfire>(true));
			Plugin.Log.LogInfo((object)$"Armed next leftover campfire for {gate} at '{GetPath(climbSlot.segmentCampfire.transform)}' pos={climbSlot.segmentCampfire.transform.position}.");
		}

		private static void HideOlderCampfires(MapSegment startSlot, MapSegment openedSlot, MapSegment gateSlot)
		{
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null || instance.segments == null)
			{
				return;
			}
			for (int i = 0; i < instance.segments.Length; i++)
			{
				MapSegment val = instance.segments[i];
				if (val != null && !((Object)(object)val.segmentCampfire == (Object)null) && !SameCampfireRoot(val, startSlot) && !SameCampfireRoot(val, openedSlot) && !SameCampfireRoot(val, gateSlot))
				{
					val.segmentCampfire.SetActive(false);
				}
			}
		}

		private static bool SameCampfireRoot(MapSegment a, MapSegment b)
		{
			if (a != null && b != null && (Object)(object)a.segmentCampfire != (Object)null)
			{
				return (Object)(object)a.segmentCampfire == (Object)(object)b.segmentCampfire;
			}
			return false;
		}

		private static void UnloadSegmentKeepCampfire(MapSegment slot, int index)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (slot != null)
			{
				if ((Object)(object)slot.segmentCampfire != (Object)null)
				{
					ActivateInHierarchy(slot.segmentCampfire);
					Plugin.Log.LogInfo((object)$"Kept leftover campfire '{GetPath(slot.segmentCampfire.transform)}' at {slot.segmentCampfire.transform.position}.");
				}
				if ((Object)(object)slot.segmentParent != (Object)null && slot.segmentParent.activeSelf)
				{
					slot.segmentParent.SetActive(false);
					Plugin.Log.LogInfo((object)$"Unloaded previous segment parent '{((Object)slot.segmentParent).name}' (index {index}) after fog.");
				}
				if ((Object)(object)slot.wallNext != (Object)null)
				{
					slot.wallNext.SetActive(false);
				}
				if ((Object)(object)slot.wallPrevious != (Object)null)
				{
					slot.wallPrevious.SetActive(false);
				}
			}
		}

		private static MapSegment GetClimbSlot(Segment id)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			MapHandler instance = Singleton<MapHandler>.Instance;
			int climbIndex = GetClimbIndex(id);
			if ((Object)(object)instance == (Object)null || instance.segments == null || climbIndex < 0 || climbIndex >= instance.segments.Length)
			{
				return null;
			}
			return instance.segments[climbIndex];
		}

		private static IEnumerator WaitForFogCatchUpSafe()
		{
			OrbFogHandler instance = Singleton<OrbFogHandler>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				yield break;
			}
			IEnumerator wait;
			try
			{
				wait = instance.WaitForFogCatchUp();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Fog catch-up failed to start: " + ex.Message));
				yield break;
			}
			while (true)
			{
				bool flag;
				try
				{
					flag = wait.MoveNext();
				}
				catch (Exception ex2)
				{
					Plugin.Log.LogWarning((object)("Fog catch-up failed: " + ex2.Message));
					break;
				}
				if (!flag)
				{
					break;
				}
				yield return wait.Current;
			}
		}

		private static void SpawnItemsUnder(GameObject root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			ISpawner[] componentsInChildren = root.GetComponentsInChildren<ISpawner>(true);
			int num = 0;
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				ISpawner obj = componentsInChildren[i];
				MonoBehaviour val = (MonoBehaviour)(object)((obj is MonoBehaviour) ? obj : null);
				if (componentsInChildren[i] != null && (!((Object)(object)val != (Object)null) || !IsUnderCrashedPlane(((Component)val).transform)))
				{
					try
					{
						num += componentsInChildren[i].TrySpawnItems()?.Count ?? 0;
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("Spawner failed: " + ex.GetType().Name + ": " + ex.Message));
					}
				}
			}
			Plugin.Log.LogInfo((object)$"Spawned {num} item(s) under '{((Object)root).name}'.");
		}

		private static void UnlightProgressCampfires()
		{
			Campfire[] array = Object.FindObjectsByType<Campfire>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			int num = 0;
			foreach (Campfire val in array)
			{
				if (!((Object)(object)val == (Object)null) && !NonProgressCampfires.Contains(((Object)val).GetInstanceID()) && IsDescentGateCampfire(val))
				{
					UnlightCampfire(val);
					num++;
					Plugin.Log.LogInfo((object)("Unlit progress campfire '" + ((Object)val).name + "' (" + GetPath(((Component)val).transform) + ")."));
				}
			}
			Plugin.Log.LogInfo((object)$"Reset {num} progress campfire(s) so they can be lit for descent.");
		}

		private static bool IsDescentGateCampfire(Campfire fire)
		{
			if ((Object)(object)fire == (Object)null)
			{
				return false;
			}
			string path = GetPath(((Component)fire).transform);
			string name = ((Object)((Component)fire).gameObject).name;
			if (path.IndexOf("crashed plane", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			if (name.IndexOf("Temple", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Kiln", StringComparison.OrdinalIgnoreCase) >= 0 || path.IndexOf("Gloom Temple", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null || instance.segments == null)
			{
				return false;
			}
			for (int i = 0; i < instance.segments.Length; i++)
			{
				MapSegment val = instance.segments[i];
				if (val != null && (Object)(object)val.segmentCampfire != (Object)null && ((Component)fire).transform.IsChildOf(val.segmentCampfire.transform))
				{
					return true;
				}
			}
			return false;
		}

		private static void UnlightCampfire(Campfire fire)
		{
			if ((Object)(object)fire == (Object)null)
			{
				return;
			}
			try
			{
				fire.forceLit = false;
			}
			catch
			{
			}
			try
			{
				fire.beenBurningFor = 0f;
				fire.state = (FireState)0;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not reset '" + ((Object)fire).name + "' state: " + ex.Message));
			}
		}

		private static IEnumerator OpenFogForDescent()
		{
			OrbFogHandler instance = Singleton<OrbFogHandler>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				yield break;
			}
			IEnumerator reveal;
			try
			{
				reveal = instance.WaitForReveal();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Fog reveal failed to start: " + ex.Message));
				yield break;
			}
			while (true)
			{
				bool flag;
				try
				{
					flag = reveal.MoveNext();
				}
				catch (Exception ex2)
				{
					Plugin.Log.LogWarning((object)("Fog reveal failed: " + ex2.Message));
					break;
				}
				if (!flag)
				{
					break;
				}
				yield return reveal.Current;
			}
		}

		internal static void NotifyJumpedTo(Segment segment)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (IsRunning && !_won && (int)segment == 0)
			{
				_openedShore = true;
			}
		}

		internal static bool IsAtShore(Vector3 position)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (!IsRunning || !_openedShore)
			{
				return false;
			}
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null || (int)instance.GetCurrentSegment() != 0)
			{
				return false;
			}
			CacheShoreStinger();
			if (_hasShoreStinger && position.z > _shoreStinger.z)
			{
				return false;
			}
			if (_hasShoreAnchor)
			{
				return Vector3.Distance(position, _shoreAnchor) <= 50f;
			}
			return _hasShoreStinger;
		}

		internal static bool IsHelicopterWinActive()
		{
			if (_heliSummoned || _won)
			{
				return true;
			}
			PeakHandler instance = Singleton<PeakHandler>.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				return instance.summonedHelicopter;
			}
			return false;
		}

		internal static void MarkRunWon()
		{
			_won = true;
		}

		internal static bool PrepareShoreHelicopter()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!IsRunning || !_openedShore)
			{
				return false;
			}
			ParkEndgameAtShore();
			_heliSummoned = true;
			Plugin.Log.LogInfo((object)$"Shore flare accepted at crash site {_shoreAnchor}. Vanilla helicopter / rope / countdown will run there.");
			return true;
		}

		internal static void TickReverseProgress()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsRunning || _playedShoreTitle || !_openedShore)
			{
				return;
			}
			Character localCharacter = Character.localCharacter;
			if (!((Object)(object)localCharacter == (Object)null) && !((Object)(object)localCharacter.data == (Object)null) && !localCharacter.data.dead)
			{
				CacheShoreStinger();
				if (_hasShoreStinger && !(localCharacter.Center.z > _shoreStinger.z))
				{
					PlayProgressPoint(FindProgressPoint((BiomeType)0, "SHORE"), "shore walk");
					_playedShoreTitle = true;
				}
			}
		}

		internal static void EnableShoreForCutscene()
		{
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null || instance.segments == null || instance.segments.Length == 0)
			{
				return;
			}
			try
			{
				if (instance.segments.Length > 3 && instance.segments[3] != null && (Object)(object)instance.segments[3].segmentParent != (Object)null)
				{
					Transform parent = instance.segments[3].segmentParent.transform.parent;
					if ((Object)(object)parent != (Object)null)
					{
						((Component)parent).gameObject.SetActive(false);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not hide vanilla cutscene biome 3: " + ex.Message));
			}
			MapSegment climbSlot = GetClimbSlot((Segment)0);
			if (climbSlot != null && (Object)(object)climbSlot.segmentParent != (Object)null)
			{
				ActivateInHierarchy(climbSlot.segmentParent);
				Plugin.Log.LogInfo((object)"Enabled Shore for the end cutscene backdrop.");
			}
			ShoreCutsceneCameraHold.AttachToEndCutscenes();
			ShoreCutscenePilot.AttachToEndCutscenes();
		}

		internal static void BringLatePlayer(Character character)
		{
			if (IsRunning && !((Object)(object)character == (Object)null) && !character.isBot && PhotonNetwork.IsMasterClient && !((Object)(object)Plugin.Instance == (Object)null))
			{
				PhotonView photonView = ((MonoBehaviourPun)character).photonView;
				if (!((Object)(object)photonView == (Object)null) && photonView.Owner != null)
				{
					((MonoBehaviour)Plugin.Instance).StartCoroutine(BringLatePlayerRoutine(character));
				}
			}
		}

		private static IEnumerator BringLatePlayerRoutine(Character character)
		{
			yield return (object)new WaitForSeconds(3f);
			if (!IsRunning || (Object)(object)character == (Object)null)
			{
				yield break;
			}
			Vector3 val = ClaimRandomSpawn(GetPlayerSpawnPositions(GetPeakStandingPosition()));
			if (GetCurrentSegment() != GetTopClimbSegment())
			{
				Campfire currentCampfire = MapHandler.CurrentCampfire;
				if ((Object)(object)currentCampfire != (Object)null)
				{
					val = ((Component)currentCampfire).transform.position;
				}
			}
			((MonoBehaviourPun)character).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, false });
		}

		private static void RevealEntireClimb(bool spawnItems)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			//IL_008e: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Invalid comparison between Unknown and I4
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null || instance.segments == null)
			{
				return;
			}
			for (int i = 0; i < instance.segments.Length; i++)
			{
				Segment val = (Segment)(byte)i;
				if ((int)val != 6 && (int)val != 5)
				{
					MapSegment val2 = instance.segments[i];
					if (val2 != null && !((Object)(object)val2.segmentParent == (Object)null) && (int)val2.biome != 17)
					{
						EnableSlotGeometry(val2, val);
					}
				}
			}
			EnablePeakExtras(instance);
			ActivateNamedCampfire("Campfire-Temple");
			ActivateNamedCampfire("Campfire-Kiln");
			ActivateNamedCampfire("Beach_Campfire");
			Segment topClimbSegment = GetTopClimbSegment();
			int climbIndex = GetClimbIndex(topClimbSegment);
			if (spawnItems && PhotonNetwork.IsMasterClient && climbIndex >= 0 && climbIndex < instance.segments.Length)
			{
				SpawnSegmentItems(instance.segments[climbIndex], topClimbSegment);
			}
		}

		private static void RevealSegment(Segment target, bool spawnItems, bool keepOthers)
		{
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Invalid comparison between Unknown and I4
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Invalid comparison between Unknown and I4
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				MapHandler instance = Singleton<MapHandler>.Instance;
				if ((Object)(object)instance == (Object)null || instance.segments == null)
				{
					return;
				}
				int climbIndex = GetClimbIndex(target);
				if (climbIndex < 0 || climbIndex >= instance.segments.Length)
				{
					Plugin.Log.LogWarning((object)$"RevealSegment: no climb slot for {target}.");
					return;
				}
				MapSegment val = instance.segments[climbIndex];
				if (val == null || (Object)(object)val.segmentParent == (Object)null)
				{
					Plugin.Log.LogWarning((object)$"RevealSegment: {target} has no parent.");
					return;
				}
				if (!keepOthers)
				{
					DisableAllSegments(instance);
				}
				EnableSlotGeometry(val, target);
				if ((int)target == 4 || (int)target == 5)
				{
					EnablePeakExtras(instance);
				}
				ActivateNamedCampfire("Campfire-Temple");
				ActivateNamedCampfire("Campfire-Kiln");
				if ((int)target == 0)
				{
					ActivateNamedCampfire("Beach_Campfire");
				}
				SetCurrentSegment(instance, climbIndex);
				if (spawnItems && PhotonNetwork.IsMasterClient)
				{
					SpawnSegmentItems(val, target);
				}
				try
				{
					if ((Object)(object)val.dayNightProfile != (Object)null && (Object)(object)DayNightManager.instance != (Object)null)
					{
						DayNightManager.instance.BlendProfiles(val.dayNightProfile);
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Day/night blend failed: " + ex.Message));
				}
				try
				{
					if ((Object)(object)Singleton<OrbFogHandler>.Instance != (Object)null)
					{
						Singleton<OrbFogHandler>.Instance.SetFogOrigin(climbIndex);
					}
				}
				catch (Exception ex2)
				{
					Plugin.Log.LogWarning((object)("Fog origin failed: " + ex2.Message));
				}
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogError((object)$"RevealSegment({target}) failed: {ex3.GetType().Name}: {ex3.Message}");
			}
		}

		private static void EnableSlotGeometry(MapSegment slot, Segment id)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (slot != null && !((Object)(object)slot.segmentParent == (Object)null))
			{
				ActivateInHierarchy(slot.segmentParent);
				EnableBiomeRoot(slot.segmentParent);
				EnableSubsteps(slot.segmentParent);
				if ((Object)(object)slot.segmentCampfire != (Object)null)
				{
					ActivateInHierarchy(slot.segmentCampfire);
					slot.segmentCampfire.SetActive(true);
				}
				if ((Object)(object)slot.wallNext != (Object)null)
				{
					slot.wallNext.SetActive(true);
				}
				if ((Object)(object)slot.wallPrevious != (Object)null)
				{
					slot.wallPrevious.SetActive(true);
				}
				LogSegmentContents(slot.segmentParent, id);
			}
		}

		private static void SpawnSegmentItems(MapSegment slot, Segment target)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<ISpawner> list = new List<ISpawner>();
				list.AddRange(slot.segmentParent.GetComponentsInChildren<ISpawner>(true));
				if (((int)target == 4 || (int)target == 5) && (Object)(object)Singleton<PeakHandler>.Instance != (Object)null)
				{
					list.AddRange(((Component)Singleton<PeakHandler>.Instance).GetComponentsInChildren<ISpawner>(true));
				}
				Plugin.Log.LogInfo((object)$"Spawning items in {target} from {list.Count} spawners. Parent: {((Object)slot.segmentParent).name}");
				for (int i = 0; i < list.Count; i++)
				{
					try
					{
						ISpawner obj = list[i];
						if (obj != null)
						{
							obj.TrySpawnItems();
						}
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)$"Spawner {i} failed: {ex.GetType().Name}: {ex.Message}");
					}
				}
				if ((Object)(object)slot.segmentCampfire != (Object)null)
				{
					MapHandler.SpawnCampfireItems(slot.segmentCampfire, false);
				}
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)("SpawnSegmentItems failed: " + ex2.GetType().Name + ": " + ex2.Message));
			}
		}

		private static void EnablePeakPlatform()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			Transform val = FindPeakPlatform();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No Peak / Peak_Kiln Variant platform found under the top climb segment.");
				return;
			}
			ActivateInHierarchy(((Component)val).gameObject);
			Plugin.Log.LogInfo((object)$"Enabled Peak platform '{GetPath(val)}' at {val.position}.");
			MoveFlareBoxToShore();
		}

		private static Transform FindChildNamed(Transform parent, string name)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			Transform[] componentsInChildren = ((Component)parent).GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)componentsInChildren[i] != (Object)null && ((Object)componentsInChildren[i]).name.Equals(name, StringComparison.OrdinalIgnoreCase))
				{
					return componentsInChildren[i];
				}
			}
			return null;
		}

		private static Transform FindChildByRelativePath(Transform root, string relPath)
		{
			if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(relPath) || relPath == ".")
			{
				return root;
			}
			Transform val = root;
			string[] array = relPath.Split(new char[1] { '/' });
			for (int i = 0; i < array.Length; i++)
			{
				Transform val2 = null;
				for (int j = 0; j < val.childCount; j++)
				{
					Transform child = val.GetChild(j);
					if (((Object)child).name == array[i])
					{
						val2 = child;
						break;
					}
				}
				if ((Object)(object)val2 == (Object)null)
				{
					return null;
				}
				val = val2;
			}
			return val;
		}

		private static string GetRelativePath(Transform node, Transform root)
		{
			if ((Object)(object)node == (Object)null || (Object)(object)root == (Object)null || (Object)(object)node == (Object)(object)root)
			{
				return ".";
			}
			List<string> list = new List<string>();
			Transform val = node;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			if ((Object)(object)val != (Object)(object)root)
			{
				return null;
			}
			list.Reverse();
			return string.Join("/", list);
		}

		private static void EnablePeakExtras(MapHandler map)
		{
			EnablePeakPlatform();
			SuppressEndgameObjects();
		}

		private static void SuppressEndgameObjects()
		{
			PeakGatePortal[] array = Object.FindObjectsByType<PeakGatePortal>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			foreach (PeakGatePortal val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					((Behaviour)val).enabled = false;
					((Component)val).gameObject.SetActive(false);
				}
			}
			PeakHandler instance = Singleton<PeakHandler>.Instance;
			if (!((Object)(object)instance == (Object)null) && !IsHelicopterWinActive())
			{
				if ((Object)(object)instance.peakSequence != (Object)null)
				{
					instance.peakSequence.SetActive(false);
				}
				if ((Object)(object)instance.endCutscene != (Object)null)
				{
					instance.endCutscene.SetActive(false);
				}
				if ((Object)(object)instance.endCutsceneFinal != (Object)null)
				{
					instance.endCutsceneFinal.SetActive(false);
				}
			}
		}

		private static void ParkEndgameAtShore()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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)
			//IL_0040: 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)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_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)
			//IL_0068: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			PeakHandler instance = Singleton<PeakHandler>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			KeepEndgameAlive(instance);
			if (!_endgameMoved && _hasShoreAnchor)
			{
				GameObject peakSequence = instance.peakSequence;
				Vector3 val = _shoreAnchor + Vector3.up * 8f;
				Vector3 val2 = (((Object)(object)peakSequence != (Object)null) ? peakSequence.transform.position : val);
				Vector3 val3 = val - val2;
				OffsetEndgameRoot(peakSequence, val3, "peakSequence", null);
				OffsetEndgameRoot(instance.endCutscene, val3, "endCutscene", peakSequence);
				OffsetEndgameRoot(instance.endCutsceneFinal, val3, "endCutsceneFinal", peakSequence);
				OffsetEndgameRoot(instance.endCutsceneFinalSpecialDay, val3, "endCutsceneFinalSpecialDay", peakSequence);
				if ((Object)(object)peakSequence != (Object)null)
				{
					peakSequence.SetActive(false);
				}
				_endgameMoved = true;
				Plugin.Log.LogInfo((object)$"Parked helicopter / end cutscene at shore crash site {val} (delta {val3}).");
			}
		}

		private static void KeepEndgameAlive(PeakHandler peakHandler)
		{
			if ((Object)(object)peakHandler == (Object)null)
			{
				return;
			}
			Transform transform = ((Component)peakHandler).transform;
			if ((Object)(object)transform.parent != (Object)null)
			{
				Plugin.Log.LogInfo((object)("Unparented PeakHandler from '" + GetPath(transform.parent) + "' so Kiln unload cannot hide the helicopter."));
				transform.SetParent((Transform)null, true);
			}
			PeakSequence[] componentsInChildren = ((Component)peakHandler).GetComponentsInChildren<PeakSequence>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)componentsInChildren[i] != (Object)null)
				{
					((Behaviour)componentsInChildren[i]).enabled = true;
				}
			}
		}

		private static void OffsetEndgameRoot(GameObject go, Vector3 delta, string label, GameObject alreadyMoved)
		{
			//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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)go == (Object)null || ((Vector3)(ref delta)).sqrMagnitude < 0.01f)
			{
				return;
			}
			Transform transform = go.transform;
			if (!((Object)(object)alreadyMoved != (Object)null) || (!((Object)(object)transform == (Object)(object)alreadyMoved.transform) && !transform.IsChildOf(alreadyMoved.transform)))
			{
				PeakHandler instance = Singleton<PeakHandler>.Instance;
				if ((Object)(object)transform.parent != (Object)null && ((Object)(object)instance == (Object)null || (Object)(object)transform.parent != (Object)(object)((Component)instance).transform))
				{
					transform.SetParent((Transform)null, true);
				}
				Vector3 position = transform.position;
				transform.position = position + delta;
				Plugin.Log.LogInfo((object)$"Moved {label} '{((Object)go).name}' {position} -> {transform.position}.");
			}
		}

		private static void PlayPeakTitle()
		{
			if (!_playedPeakTitle)
			{
				ProgressPoint val = FindProgressPoint((BiomeType)5, "PEAK");
				if (val == null)
				{
					val = FindLastProgressPoint();
				}
				PlayProgressPoint(val, "peak start");
				_playedPeakTitle = true;
			}
		}

		private unsafe static void PlaySegmentTitle(Segment segment)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			MapSegment climbSlot = GetClimbSlot(segment);
			BiomeType val = (BiomeType)((climbSlot != null) ? ((int)climbSlot.biome) : 0);
			if ((int)segment == 0)
			{
				val = (BiomeType)0;
			}
			PlayProgressPoint(FindProgressPoint(val, ((object)(*(Segment*)(&segment))/*cast due to .constrained prefix*/).ToString()), $"unlock {segment}");
			if ((int)val == 0)
			{
				_playedShoreTitle = true;
			}
		}

		private static void PlayProgressPoint(ProgressPoint point, string reason)
		{
			if (point == null || (Object)(object)GUIManager.instance == (Object)null)
			{
				Plugin.Log.LogWarning((object)("No progress title to play (" + reason + ")."));
				return;
			}
			try
			{
				GUIManager.instance.SetHeroTitle(point.localizedTitle, point.clip, false);
				MountainProgressHandler.SetRichPresence(point);
				Plugin.Log.LogInfo((object)("Played '" + point.title + "' stinger (" + reason + ")."));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not play '" + point.title + "' stinger: " + ex.Message));
			}
		}

		private static ProgressPoint FindProgressPoint(BiomeType biome, string titleHint)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			MountainProgressHandler instance = Singleton<MountainProgressHandler>.Instance;
			if ((Object)(object)instance == (Object)null || instance.progressPoints == null)
			{
				return null;
			}
			ProgressPoint val = null;
			for (int i = 0; i < instance.progressPoints.Length; i++)
			{
				ProgressPoint val2 = instance.progressPoints[i];
				if (val2 != null)
				{
					if (val2.biome == biome)
					{
						return val2;
					}
					if (val == null && !string.IsNullOrEmpty(titleHint) && !string.IsNullOrEmpty(val2.title) && val2.title.IndexOf(titleHint, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						val = val2;
					}
				}
			}
			return val;
		}

		private static ProgressPoint FindLastProgressPoint()
		{
			MountainProgressHandler instance = Singleton<MountainProgressHandler>.Instance;
			if ((Object)(object)instance == (Object)null || instance.progressPoints == null || instance.progressPoints.Length == 0)
			{
				return null;
			}
			return instance.progressPoints[instance.progressPoints.Length - 1];
		}

		private static void CacheShoreStinger()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (!_hasShoreStinger)
			{
				ProgressPoint val = FindProgressPoint((BiomeType)0, "SHORE");
				if (val != null && !((Object)(object)val.transform == (Object)null))
				{
					_shoreStinger = val.transform.position;
					_hasShoreStinger = true;
					Plugin.Log.LogInfo((object)$"Shore stinger line at {_shoreStinger}. Crash site {_shoreAnchor} (flare only on the beach side, within {50f}m).");
				}
			}
		}

		private static void EnableBiomeRoot(GameObject segmentParent)
		{
			if ((Object)(object)segmentParent == (Object)null || (Object)(object)segmentParent.transform.parent == (Object)null)
			{
				return;
			}
			Transform parent = segmentParent.transform.parent;
			ActivateInHierarchy(((Component)parent).gameObject);
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if (!((Object)(object)child == (Object)null) && !((Object)(object)((Component)child).gameObject == (Object)(object)segmentParent) && (Object)(object)((Component)child).GetComponent<EnablingSubstep>() != (Object)null)
				{
					((Component)child).gameObject.SetActive(true);
				}
			}
		}

		private static void EnableSubsteps(GameObject parent)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			EnablingSubstep[] componentsInChildren = parent.GetComponentsInChildren<EnablingSubstep>(true);
			int num = 0;
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (!((Object)(object)componentsInChildren[i] == (Object)null) && !((Component)componentsInChildren[i]).gameObject.activeSelf)
				{
					((Component)componentsInChildren[i]).gameObject.SetActive(true);
					num++;
				}
			}
			Plugin.Log.LogInfo((object)$"Enabled {num}/{componentsInChildren.Length} EnablingSubstep(s) under {((Object)parent).name}.");
		}

		private static void DisableAllSegments(MapHandler map)
		{
			if (map.segments == null)
			{
				return;
			}
			for (int i = 0; i < map.segments.Length; i++)
			{
				MapSegment val = map.segments[i];
				if (val != null)
				{
					if ((Object)(object)val.segmentParent != (Object)null)
					{
						val.segmentParent.SetActive(false);
					}
					if ((Object)(object)val.segmentCampfire != (Object)null)
					{
						val.segmentCampfire.SetActive(false);
					}
				}
			}
		}

		private static void DisableRisingHazards()
		{
			int num = 0;
			List<LavaRising> aLL_LAVA = LavaRising.ALL_LAVA;
			if (aLL_LAVA != null)
			{
				for (int i = 0; i < aLL_LAVA.Count; i++)
				{
					LavaRising val = aLL_LAVA[i];
					if (!((Object)(object)val == (Object)null))
					{
						((Behaviour)val).enabled = false;
						val.ended = true;
						val.started = false;
						num++;
					}
				}
			}
			Plugin.Log.LogInfo((object)$"Stopped {num} rising lava/gloom field(s) for reverse descent.");
		}

		private static void PatchCampfiresForDescent()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			Campfire[] array = Object.FindObjectsByType<Campfire>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			int num = 0;
			foreach (Campfire val in array)
			{
				if ((Object)(object)val == (Object)null || NonProgressCampfires.Contains(((Object)val).GetInstanceID()) || !TryGetDescentTargetForCampfire(val, out var next))
				{
					continue;
				}
				try
				{
					if (val.advanceToSegment != next)
					{
						val.advanceToSegment = next;
						num++;
						Plugin.Log.LogInfo((object)$"Patched campfire '{((Object)val).name}' advanceToSegment -> {next} ({GetPath(((Component)val).transform)})");
					}
				}
				catch (Exception ex)
				{
					try
					{
						Traverse.Create((object)val).Field("advanceToSegment").SetValue((object)next);
						num++;
						Plugin.Log.LogInfo((object)$"Traverse-patched campfire '{((Object)val).name}' -> {next}");
					}
					catch (Exception ex2)
					{
						Plugin.Log.LogWarning((object)("Could not patch '" + ((Object)val).name + "': " + ex.Message + " / " + ex2.Message));
					}
				}
			}
			Plugin.Log.LogInfo((object)$"Patched {num} campfire(s) for descent.");
		}

		private static bool TryGetDescentTargetForCampfire(Campfire fire, out Segment next)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			next = (Segment)0;
			if ((Object)(object)fire == (Object)null)
			{
				return false;
			}
			if (GetPath(((Component)fire).transform).IndexOf("crashed plane", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			if (!TryGetCampfireOwner(fire, out var owner))
			{
				return false;
			}
			return TryGetNextAfter(owner, out next);
		}

		private static bool TryGetCampfireOwner(Campfire fire, out Segment owner)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Expected I4, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected I4, but got Unknown
			owner = (Segment)0;
			if ((Object)(object)fire == (Object)null)
			{
				return false;
			}
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null || instance.segments == null)
			{
				return false;
			}
			int num = int.MaxValue;
			bool flag = false;
			for (int i = 0; i < instance.segments.Length; i++)
			{
				Segment val = (Segment)(byte)i;
				if ((int)val == 6 || (int)val == 5)
				{
					continue;
				}
				MapSegment val2 = instance.segments[i];
				if (val2 != null && (BelongsToSlotCampfire(fire, val2) || BelongsToSlotParent(fire, val2)))
				{
					int num2 = IndexInReversed(val);
					if (num2 < 0)
					{
						num2 = 100 + i;
					}
					if (num2 < num)
					{
						num = num2;
						owner = (Segment)(int)val;
						flag = true;
					}
				}
			}
			if (flag)
			{
				return true;
			}
			string path = GetPath(((Component)fire).transform);
			string name = ((Object)((Component)fire).gameObject).name;
			if (name.IndexOf("Temple", StringComparison.OrdinalIgnoreCase) >= 0 || path.IndexOf("Gloom Temple", StringComparison.OrdinalIgnoreCase) >= 0 || path.IndexOf("Campfire-Temple", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Kiln", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				owner = (Segment)(int)GetTopClimbSegment();
				return true;
			}
			return false;
		}

		private static bool BelongsToSlotCampfire(Campfire fire, MapSegment slot)
		{
			if ((Object)(object)fire == (Object)null || slot == null || (Object)(object)slot.segmentCampfire == (Object)null)
			{
				return false;
			}
			Transform transform = slot.segmentCampfire.transform;
			if (!((Object)(object)((Component)fire).transform == (Object)(object)transform) && !((Component)fire).transform.IsChildOf(transform))
			{
				return transform.IsChildOf(((Component)fire).transform);
			}
			return true;
		}

		private static bool BelongsToSlotParent(Campfire fire, MapSegment slot)
		{
			if ((Object)(object)fire != (Object)null && slot != null && (Object)(object)slot.segmentParent != (Object)null)
			{
				return ((Component)fire).transform.IsChildOf(slot.segmentParent.transform);
			}
			return false;
		}

		private static bool TryGetNextAfter(Segment current, out Segment next)
		{
			//IL_0003: 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_002e: Expected I4, but got Unknown
			next = (Segment)0;
			int num = IndexInReversed(current);
			if (num < 0 || num + 1 >= ReversedOrder.Count)
			{
				return false;
			}
			next = (Segment)(int)ReversedOrder[num + 1];
			return true;
		}

		private static void LogClimbSlots(MapHandler map)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)map == (Object)null || map.segments == null)
			{
				return;
			}
			for (int i = 0; i < map.segments.Length; i++)
			{
				MapSegment val = map.segments[i];
				if (val != null && !((Object)(object)val.segmentParent == (Object)null))
				{
					string text = (((Object)(object)val.segmentCampfire != (Object)null) ? $"{GetPath(val.segmentCampfire.transform)} on={val.segmentCampfire.activeSelf}/{val.segmentCampfire.activeInHierarchy} at {val.segmentCampfire.transform.position}" : "none");
					Plugin.Log.LogInfo((object)$"Slot {i} {(object)(Segment)(byte)i}: parent='{((Object)val.segmentParent).name}' parentOn={val.segmentParent.activeSelf}/{val.segmentParent.activeInHierarchy}; campfire {text}");
				}
			}
		}

		private static string GetPath(Transform transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return "";
			}
			List<string> list = new List<string>();
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}

		private static Vector3 RemapFromFlag(Vector3 dumpedWorld, Vector3 standingPos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return standingPos + (dumpedWorld - CitadelFlagStanding);
		}

		private static List<Vector3> GetPlayerSpawnPositions(Vector3 standingPos)
		{
			//IL_000f: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = LoadPlayerSpawnDumps();
			if (list.Count == 0)
			{
				list.Add(DumpedPlayerCenter);
			}
			List<Vector3> list2 = new List<Vector3>(list.Count);
			for (int i = 0; i < list.Count; i++)
			{
				list2.Add(RemapFromFlag(list[i], standingPos));
			}
			return list2;
		}

		private static void ResetSpawnDeck(List<Vector3> spots)
		{
			_spawnDeck = ((spots != null) ? new List<Vector3>(spots) : new List<Vector3>());
			_spawnPool = new List<Vector3>(_spawnDeck);
		}

		private static Vector3 ClaimRandomSpawn(List<Vector3> fallbackSpots)
		{
			//IL_005d: 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 (_spawnPool == null || _spawnPool.Count == 0)
			{
				if (_spawnDeck != null && _spawnDeck.Count > 0)
				{
					_spawnPool = new List<Vector3>(_spawnDeck);
				}
				else if (fallbackSpots != null && fallbackSpots.Count > 0)
				{
					ResetSpawnDeck(fallbackSpots);
				}
			}
			if (_spawnPool == null || _spawnPool.Count == 0)
			{
				return GetPeakStandingPosition();
			}
			int index = Random.Range(0, _spawnPool.Count);
			Vector3 result = _spawnPool[index];
			_spawnPool.RemoveAt(index);
			return result;
		}

		private static void MoveSpawnPointsToDumps(List<Vector3> spots)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			List<SpawnPoint> allSpawnPoints = SpawnPoint.allSpawnPoints;
			if (allSpawnPoints == null || spots == null || spots.Count == 0)
			{
				return;
			}
			List<Vector3> list = new List<Vector3>(spots);
			List<SpawnPoint> list2 = new List<SpawnPoint>();
			for (int i = 0; i < allSpawnPoints.Count; i++)
			{
				if ((Object)(object)allSpawnPoints[i] != (Object)null)
				{
					list2.Add(allSpawnPoints[i]);
				}
			}
			list2.Sort((SpawnPoint a, SpawnPoint b) => a.index.CompareTo(b.index));
			for (int num = 0; num < list2.Count; num++)
			{
				if (list.Count == 0)
				{
					list.AddRange(spots);
				}
				int index = Random.Range(0, list.Count);
				Vector3 position = list[index];
				list.RemoveAt(index);
				((Component)list2[num]).transform.SetParent((Transform)null, true);
				((Component)list2[num]).transform.position = position;
			}
			Plugin.Log.LogInfo((object)$"Moved {list2.Count} scout spawn point(s) onto {spots.Count} baked spawn(s).");
		}

		private static void WarpEveryoneToAssignedSpawns(List<Vector3> spots)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
			if (allPlayerCharacters == null || spots == null || spots.Count == 0)
			{
				return;
			}
			ResetSpawnDeck(spots);
			Plugin.Log.LogInfo((object)$"Warping {allPlayerCharacters.Count} player(s) across {spots.Count} baked spawn(s), unique random claims.");
			for (int i = 0; i < allPlayerCharacters.Count; i++)
			{
				Character val = allPlayerCharacters[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((MonoBehaviourPun)val).photonView == (Object)null))
				{
					Vector3 val2 = ClaimRandomSpawn(spots);
					Plugin.Log.LogInfo((object)$"Scout '{val.characterName}' claimed spawn {val2} ({_spawnPool.Count} pad(s) left).");
					((MonoBehaviourPun)val).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val2, false });
				}
			}
		}

		private static bool SetCurrentSegment(MapHandler map, int index)
		{
			if ((Object)(object)map == (Object)null)
			{
				return false;
			}
			try
			{
				map.currentSegment = index;
				Plugin.Log.LogInfo((object)$"Set currentSegment={index} ({(object)(Segment)(byte)index}).");
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not set currentSegment: " + ex.GetType().Name + ": " + ex.Message));
				return false;
			}
		}

		private static Segment GetCurrentSegment()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return (Segment)0;
			}
			return instance.GetCurrentSegment();
		}

		private static void CaptureShoreAnchor()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//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)
			if (_hasShoreAnchor)
			{
				return;
			}
			Vector3 val = Vector3.zero;
			int num = 0;
			List<SpawnPoint> allSpawnPoints = SpawnPoint.allSpawnPoints;
			if (allSpawnPoints != null)
			{
				for (int i = 0; i < allSpawnPoints.Count; i++)
				{
					if (!((Object)(object)allSpawnPoints[i] == (Object)null))
					{
						val += ((Component)allSpawnPoints[i]).transform.position;
						num++;
					}
				}
			}
			if (num > 0)
			{
				_shoreAnchor = val / (float)num;
				_hasShoreAnchor = true;
				CacheShoreStinger();
				return;
			}
			Transform val2 = (((Object)(object)SpawnPoint.LocalSpawnPoint != (Object)null) ? ((Component)SpawnPoint.LocalSpawnPoint).transform : null);
			if ((Object)(object)val2 != (Object)null)
			{
				_shoreAnchor = val2.position;
				_hasShoreAnchor = true;
			}
		}

		private static void ActivateInHierarchy(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return;
			}
			Transform val = go.transform;
			while ((Object)(object)val != (Object)null)
			{
				if (!((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(true);
				}
				if (!((Object)(object)((Component)val).GetComponent<MapHandler>() != (Object)null))
				{
					val = val.parent;
					continue;
				}
				break;
			}
		}

		private static void ActivateNamedCampfire(string name)
		{
			Transform val = FindNamedTransform(name);
			if (!((Object)(object)val == (Object)null))
			{
				ActivateInHierarchy(((Component)val).gameObject);
				((Component)val).gameObject.SetActive(true);
			}
		}

		private static void MoveCrashedPlaneToPosition(Vector3 standingPos)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			Transform val = FindNamedTransform("crashed plane");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Crashed plane not found — Peak start will still work.");
				return;
			}
			val.SetParent((Transform)null, true);
			((Component)val).gameObject.SetActive(true);
			if (TryLoadEmbeddedPlaneDump(out var dump, out var rootRot))
			{
				val.SetPositionAndRotation(standingPos, rootRot);
				ApplyPlaneDumpLocals(val, dump);
			}
			else
			{
				val.SetPositionAndRotation(standingPos, DumpedPlaneRot);
				Plugin.Log.LogWarning((object)"No plane dump available — placed wreck root on the flag with default rotation.");
			}
			HidePlanePiece(val, "Wings.004");
			MarkPlaneCampfiresNonProgress(val);
			Plugin.Log.LogInfo((object)$"Moved crashed plane to flag {standingPos}.");
		}

		private static Transform FindPlaneCampfire(Transform plane)
		{
			Campfire componentInChildren = ((Component)plane).GetComponentInChildren<Campfire>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				return ((Component)componentInChildren).transform;
			}
			return FindChildNamed(plane, "Campfire_Flame");
		}

		private static void GatherPlaneSpawners(Transform plane, List<Transform> dest)
		{
			for (int i = 0; i < plane.childCount; i++)
			{
				Transform child = plane.GetChild(i);
				if (!((Object)(object)child == (Object)null) && ((Object)child).name.IndexOf("Spawner", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					ISpawner component = ((Component)child).GetComponent<ISpawner>();
					if (component != null && !(component is EndgameFlareSpawner))
					{
						dest.Add(child);
					}
				}
			}
		}

		private static void PlaceSpawnersAroundFire(List<Transform> spawners, Vector3 firePos)
		{
			//IL_00c3: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			int count = spawners.Count;
			if (count == 0)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < count; i++)
			{
				if (!IsBingBongName(((Object)spawners[i]).name))
				{
					num2++;
				}
			}
			if (num2 < 1)
			{
				num2 = 1;
			}
			for (int j = 0; j < count; j++)
			{
				if (!IsBingBongName(((Object)spawners[j]).name))
				{
					float num3 = (float)num * (float)Math.PI * 2f / (float)num2;
					num++;
					Vector3 val = firePos + new Vector3(Mathf.Cos(num3) * 2.25f, 0.2f, Mathf.Sin(num3) * 2.25f);
					spawners[j].SetPositionAndRotation(val, Quaternion.identity);
				}
			}
			Plugin.Log.LogInfo((object)$"Moved {count} plane item spawner(s) into a ring around the wreck campfire at {firePos}.");
		}

		private static bool TryGetSeatPose(Transform plane, out Vector3 dest, out Quaternion rot)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_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)
			dest = Vector3.zero;
			rot = Quaternion.identity;
			Transform val = FindChildByRelativePath(plane, "Back Half/Frame.002");
			if ((Object)(object)val == (Object)null)
			{
				val = FindChildNamed(plane, "Frame.002");
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Blue seat Frame.002 not found — leaving BingBong in the fire ring.");
				return false;
			}
			if (TryGetSeatTop(val, out dest))
			{
				dest += Vector3.up * 0.25f;
			}
			else
			{
				dest = val.position + Vector3.up * 1.15f;
			}
			rot = val.rotation;
			return true;
		}

		private static bool TryGetBingBongPlacePose(Transform plane, out Vector3 dest, out Quaternion rot)
		{
			if (TryGetBingBongWorldPose(plane, out dest, out rot))
			{
				return true;
			}
			return TryGetSeatPose(plane, out dest, out rot);
		}

		private static bool TryGetSeatTop(Transform seat, out Vector3 point)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			point = Vector3.zero;
			Renderer[] componentsInChildren = ((Component)seat).GetComponentsInChildren<Renderer>(true);
			bool flag = false;
			Bounds val = default(Bounds);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (!((Object)(object)componentsInChildren[i] == (Object)null))
				{
					if (!flag)
					{
						val = componentsInChildren[i].bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref val)).Encapsulate(componentsInChildren[i].bounds);
					}
				}
			}
			if (!flag)
			{
				return false;
			}
			point = new Vector3(((Bounds)(ref val)).center.x, ((Bounds)(ref val)).max.y, ((Bounds)(ref val)).center.z);
			return true;
		}

		private static void SpawnCrashedPlaneItems()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: 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_0085: 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)
			Transform val = FindNamedTransform("crashed plane");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			List<Transform> list = new List<Transform>();
			GatherPlaneSpawners(val, list);
			Transform val2 = FindPlaneCampfire(val);
			if ((Object)(object)val2 != (Object)null)
			{
				PlaceSpawnersAroundFire(list, val2.position);
			}
			else
			{
				Plugin.Log.LogWarning((object)"Plane campfire not found — spawning items at their dumped spawner poses.");
			}
			Vector3 dest;
			Quaternion rot;
			bool flag = TryGetBingBongPlacePose(val, out dest, out rot);
			Transform val3 = FindBingBongSpawner(list);
			if (flag && (Object)(object)val3 != (Object)null)
			{
				val3.SetPositionAndRotation(dest, rot);
				Plugin.Log.LogInfo((object)$"BingBong spawner aimed at {dest}.");
			}
			Plugin.Log.LogInfo((object)"Spawning crashed-plane starter items.");
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				Transform val4 = list[i];
				ISpawner component = ((Component)val4).GetComponent<ISpawner>();
				if (component == null)
				{
					continue;
				}
				try
				{
					StripSpawnTracker(((Component)val4).gameObject);
					List<PhotonView> list2 = component.TrySpawnItems();
					int num2 = list2?.Count ?? 0;
					num += num2;
					if (IsBingBongName(((Object)val4).name) && list2 != null)
					{
						for (int j = 0; j < list2.Count; j++)
						{
							if ((Object)(object)list2[j] != (Object)null)
							{
								_spawnedBingBong = ((Component)list2[j]).transform;
								break;
							}
						}
					}
					Plugin.Log.LogInfo((object)$"Plane spawner '{((Object)val4).name}' spawned {num2} item(s) at {val4.position}.");
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Plane spawner '" + ((Object)val4).name + "' failed: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
			if (flag)
			{
				MoveBingBongItem(FindSpawnedBingBong(val), dest, rot);
			}
			Plugin.Log.LogInfo((object)$"Spawned {num} starting item(s) from the crashed plane.");
		}

		private static bool IsBingBongName(string name)
		{
			if (!string.IsNullOrEmpty(name))
			{
				return name.IndexOf("BingBong", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static Transform FindBingBongSpawner(List<Transform> spawners)
		{
			if (spawners == null)
			{
				return null;
			}
			for (int i = 0; i < spawners.Count; i++)
			{
				if ((Object)(object)spawners[i] != (Object)null && IsBingBongName(((Object)spawners[i]).name))
				{
					return spawners[i];
				}
			}
			return null;
		}

		private static Transform FindSpawnedBingBong(Transform plane)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			Item[] array = Object.FindObjectsByType<Item>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			Transform val = null;
			float num = float.MaxValue;
			Vector3 val2 = (((Object)(object)plane != (Object)null) ? plane.position : Vector3.zero);
			foreach (Item val3 in array)
			{
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				string name = ((Object)((Component)val3).gameObject).name;
				if (IsBingBongName(name) && name.IndexOf("Spawner", StringComparison.OrdinalIgnoreCase) < 0)
				{
					Vector3 val4 = val3.Center();
					float num2 = (((Object)(object)plane != (Object)null) ? Vector3.Distance(val4, val2) : 0f);
					if ((Object)(object)plane != (Object)null && num2 > 40f)
					{
						Plugin.Log.LogInfo((object)$"Ignoring far BingBong '{name}' at {val4} ({num2:0.#}m from wreck).");
					}
					else if (num2 < num)
					{
						num = num2;
						val = val3.transform;
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				_spawnedBingBong = val;
			}
			return val;
		}

		private static bool TryLoadBingBongDump(out Vector3 localPos, out Quaternion localRot)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			localPos = BingBongLocalPos;
			localRot = BingBongLocalRot;
			return true;
		}

		private static bool TryGetBingBongWorldPose(Transform plane, out Vector3 worldPos, out Quaternion worldRot)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0034: 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)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			worldPos = Vector3.zero;
			worldRot = Quaternion.identity;
			if (!TryLoadBingBongDump(out var localPos, out var localRot) || (Object)(object)plane == (Object)null)
			{
				return false;
			}
			worldPos = plane.TransformPoint(localPos);
			worldRot = plane.rotation * localRot;
			return true;
		}

		private static void MoveBingBongItem(Transform bing, Vector3 dest, Quaternion rot)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)bing == (Object)null))
			{
				bing.SetPositionAndRotation(dest, rot);
				Rigidbody component = ((Component)bing).GetComponent<Rigidbody>();
				if ((Object)(object)component != (Object)null)
				{
					component.position = dest;
					component.rotation = rot;
					component.linearVelocity = Vector3.zero;
					component.angularVelocity = Vector3.zero;
				}
				Plugin.Log.LogInfo((object)$"Moved spawned BingBong to {dest}.");
			}
		}

		private static void StripSpawnTracker(GameObject host)
		{
			SpawnedItemTracker component = host.GetComponent<SpawnedItemTracker>();
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
		}

		private static bool IsUnderCrashedPlane(Transform t)
		{
			while ((Object)(object)t != (Object)null)
			{
				if (((Object)t).name.Equals("crashed plane", StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
				t = t.parent;
			}
			return false;
		}

		private static void HidePlanePiece(Transform plane, string name)
		{
			Transform val = FindChildNamed(plane, name);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Could not hide '" + name + "' — not found under crashed plane."));
				return;
			}
			((Component)val).gameObject.SetActive(false);
			Plugin.Log.LogInfo((object)("Hid crashed plane piece '" + name + "'."));
		}

		private static void ApplyPlaneDumpLocals(Transform plane, List<PlaneNodeDump> dump)
		{
			//IL_005c: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			for (int i = 0; i < dump.Count; i++)
			{
				PlaneNodeDump planeNodeDump = dump[i];
				if (!(planeNodeDump.RelPath == "."))
				{
					Transform val = FindChildByRelativePath(plane, planeNodeDump.RelPath);
					if ((Object)(object)val == (Object)null)
					{
						Plugin.Log.LogWarning((object)("Dump child '" + planeNodeDump.RelPath + "' not found under crashed plane."));
						continue;
					}
					val.localPosition = planeNodeDump.LocalPos;
					val.localRotation = planeNodeDump.LocalRot;
					val.localScale = planeNodeDump.LocalScale;
					((Component)val).gameObject.SetActive(planeNodeDump.Active);
					num++;
				}
			}
			Plugin.Log.LogInfo((object)$"Applied {num} dumped crashed-plane child pose(s).");
		}

		private static List<Vector3> LoadPlayerSpawnDumps()
		{
			List<Vector3> list = LoadEmbeddedPlayerSpawns();
			if (list.Count > 0)
			{
				Plugin.Log.LogInfo((object)$"Loaded {list.Count} baked-in player spawn(s).");
			}
			return list;
		}

		private static List<Vector3> LoadEmbeddedPlayerSpawns()
		{
			Stream manifestResourceStream = typeof(ReverseRun).Assembly.GetManifestResourceStream("SummitToShore.PlayerDump.txt");
			if (manifestResourceStream == null)
			{
				return new List<Vector3>();
			}
			string text;
			using (manifestResourceStream)
			{
				using StreamReader streamReader = new StreamReader(manifestResourceStream);
				text = streamReader.ReadToEnd();
			}
			return ParsePlayerSpawnLines(text.Split(new string[2] { "\r\n", "\n" }, StringSplitOptions.None));
		}

		private static List<Vector3> ParsePlayerSpawnLines(string[] lines)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			if (lines == null)
			{
				return list;
			}
			for (int i = 0; i < lines.Length; i++)
			{
				string text = lines[i].Trim();
				if (text.StartsWith("SPAWN | ", StringComparison.Ordinal) && TryParseVec3(text.Substring(8), out var value))
				{
					list.Add(value);
				}
			}
			if (list.Count == 0)
			{
				for (int j = 0; j < lines.Length; j++)
				{
					string text2 = lines[j].Trim();
					if (text2.StartsWith("CENTER | ", StringComparison.Ordinal) && TryParseVec3(text2.Substring(9), out var value2))
					{
						list.Add(value2);
						break;
					}
				}
			}
			return list;
		}

		private static bool TryLoadEmbeddedPlaneDump(out List<PlaneNodeDump> dump, out Quaternion rootRot)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			dump = new List<PlaneNodeDump>();
			rootRot = DumpedPlaneRot;
			Stream manifestResourceStream = typeof(ReverseRun).Assembly.GetManifestResourceStream("SummitToShore.PlaneDump.txt");
			if (manifestResourceStream == null)
			{
				Plugin.Log.LogWarning((object)"Embedded crashed-plane dump is missing from the DLL.");
				return false;
			}
			try
			{
				string text;
				using (manifestResourceStream)
				{
					using StreamReader streamReader = new StreamReader(manifestResourceStream);
					text = streamReader.ReadToEnd();
				}
				return TryParsePlaneDump(text.Split(new string[2] { "\r\n", "\n" }, StringSplitOptions.None), "embedded dump", out dump, out rootRot);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read embedded plane dump: " + ex.Message));
				return false;
			}
		}

		private static bool TryParsePlaneDump(string[] lines, string source, out List<PlaneNodeDump> dump, out Quaternion rootRot)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			dump = new List<PlaneNodeDump>();
			rootRot = DumpedPlaneRot;
			bool flag = false;
			for (int i = 0; i < lines.Length; i++)
			{
				if (lines[i].IndexOf("dump v2", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				Plugin.Log.LogInfo((object)("Plane dump '" + source + "' is not v2. Using the baked-in layout."));
				return false;
			}
			bool flag2 = false;
			PlaneNodeDump item = default(PlaneNodeDump);
			for (int j = 0; j < lines.Length; j++)
			{
				string text = lines[j].Trim();
				if (text.Length == 0 || text[0] == '#')
				{
					continue;
				}
				string[] array = text.Split(new string[1] { " | " }, StringSplitOptions.None);
				if (array.Length == 0)
				{
					continue;
				}
				if (array[0] == "ROOT")
				{
					if (array.Length < 4 || !TryParseQuat(array[3], out rootRot))
					{
						Plugin.Log.LogWarning((object)("Plane dump '" + source + "' has an invalid ROOT line."));
						return false;
					}
					flag2 = true;
					continue;
				}
				if (array[0] != "CHILD" || array.Length < 6)
				{
					Plugin.Log.LogWarning((object)("Plane dump '" + source + "' has an unexpected line '" + text + "'."));
					return false;
				}
				item.RelPath = array[1];
				item.Active = array[2] == "1";
				if (!TryParseVec3(array[3], out item.LocalPos) || !TryParseQuat(array[4], out item.LocalRot) || !TryParseVec3(array[5], out item.LocalScale))
				{
					Plugin.Log.LogWarning((object)("Plane dump child '" + array[1] + "' has invalid numbers."));
					return false;
				}
				dump.Add(item);
			}
			if (!flag2 || dump.Count == 0)
			{
				Plugin.Log.LogWarning((object)("Plane dump '" + source + "' has no ROOT/CHILD data."));
				return false;
			}
			Plugin.Log.LogInfo((object)$"Loaded crashed-plane dump with {dump.Count} child pose(s) from {source}.");
			return true;
		}

		private static bool TryParseVec3(string text, out Vector3 value)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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)
			value = Vector3.zero;
			string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length != 3)
			{
				return false;
			}
			if (!float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
			{
				return false;
			}
			value = new Vector3(result, result2, result3);
			return true;
		}

		private static bool TryParseQuat(string text, out Quaternion value)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			value = Quaternion.identity;
			string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length != 4)
			{
				return false;
			}
			if (!float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) || !float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4))
			{
				return false;
			}
			value = new Quaternion(result, result2, result3, result4);
			return true;
		}

		private static void MarkPlaneCampfiresNonProgress(Transform plane)
		{
			Campfire[] componentsInChildren = ((Component)plane).GetComponentsInChildren<Campfire>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (!((Object)(object)componentsInChildren[i] == (Object)null))
				{
					NonProgressCampfires.Add(((Object)componentsInChildren[i]).GetInstanceID());
					Plugin.Log.LogInfo((object)("Plane campfire '" + ((Object)componentsInChildren[i]).name + "' will light but will not skip a biome."));
				}
			}
		}

		private static void MoveFlareBoxToShore()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (_hasShoreAnchor && !_flareBoxMoved)
			{
				Transform val = FindPeakFlareBox();
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)"Peak flare 'box' not found — flares will not sit in the crate.");
					return;
				}
				Vector3 position = val.position;
				ActivateInHierarchy(((Component)val).gameObject);
				val.SetParent((Transform)null, true);
				val.SetPositionAndRotation(_shoreAnchor, val.rotation);
				MoveLooseFlaresWithBox(position, _shoreAnchor);
				SpawnFlaresInBox(val);
				_flareBoxMoved = true;
				Plugin.Log.LogInfo((object)$"Moved flare box '{GetPath(val)}' {position} -> {_shoreAnchor}.");
			}
		}

		private static Transform FindPeakFlareBox()
		{
			Transform val = FindChildNamed(FindPeakPlatform(), "box");
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			for (int i = 0; i < PeakPlatformNames.Length; i++)
			{
				val = FindChildNamed(FindNamedTransform(PeakPlatformNames[i]), "box");
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private static void MoveLooseFlaresWithBox(Vector3 from, Vector3 dest)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = dest - from;
			Item[] array = Object.FindObjectsByType<Item>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			int num = 0;
			foreach (Item val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.holderCharacter != (Object)null) && ((Object)val2).name.IndexOf("Flare", StringComparison.OrdinalIgnoreCase) >= 0 && !(Vector3.Distance(val2.transform.position, from) > 20f))
				{
					Transform transform = val2.transform;
					transform.position += val;
					num++;
				}
			}
			if (num > 0)
			{
				Plugin.Log.LogInfo((object)$"Moved {num} already-spawned flare(s) with the crate.");
			}
		}

		private static void SpawnFlaresInBox(Transform box)
		{
			if ((Object)(object)box == (Object)null || !PhotonNetwork.IsMasterClient)
			{
				return;
			}
			ISpawner[] componentsInChildren = ((Component)box).GetComponentsInChildren<ISpawner>(true);
			int num = 0;
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (componentsInChildren[i] == null)
				{
					continue;
				}
				try
				{
					List<PhotonView> list = componentsInChildren[i].TrySpawnItems();
					if (list != null)
					{
						num += list.Count;
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Flare box spawner failed: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
			Plugin.Log.LogInfo((object)$"Spawned {num} flare(s) in the shore crate.");
		}

		private static Vector3 GetPeakStandingPosition()
		{
			//IL_0010: 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_0015: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			bool flag = IsKilnPeakRoll();
			Vector3 val = (flag ? KilnFlagStanding : CitadelFlagStanding);
			Plugin.Log.LogInfo((object)string.Format("Using {0} crash site {1}.", flag ? "Kiln/Caldera" : "Citadel/Gloom", val));
			return val;
		}

		private static Transform FindPeakPlatform()
		{
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null || instance.segments == null)
			{
				return null;
			}
			int lastClimbIndex = GetLastClimbIndex(instance);
			if (lastClimbIndex < 0 || (Object)(object)instance.segments[lastClimbIndex].segmentParent == (Object)null)
			{
				return null;
			}
			return FindNamedPeakPlatform(instance.segments[lastClimbIndex].segmentParent.transform);
		}

		private static Transform FindNamedPeakPlatform(Transform parent)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			for (int i = 0; i < PeakPlatformNames.Length; i++)
			{
				Transform val = FindChildNamed(parent, PeakPlatformNames[i]);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private static bool IsKilnPeakRoll()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			MapHandler instance = Singleton<MapHandler>.Instance;
			int lastClimbIndex = GetLastClimbIndex(instance);
			if ((Object)(object)instance == (Object)null || lastClimbIndex < 0 || instance.segments == null || lastClimbIndex >= instance.segments.Length)
			{
				return false;
			}
			MapSegment val = instance.segments[lastClimbIndex];
			if (val == null)
			{
				return false;
			}
			if ((int)val.biome == 3)
			{
				return true;
			}
			if ((Object)(object)val.segmentParent != (Object)null)
			{
				return ((Object)val.segmentParent).name.IndexOf("Volcano", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static int GetLastClimbIndex(MapHandler map)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Invalid comparison between Unknown and I4
			if (map.segments == null)
			{
				return -1;
			}
			for (int num = map.segments.Length - 1; num >= 0; num--)
			{
				MapSegment val = map.segments[num];
				if (val != null && !((Object)(object)val.segmentParent == (Object)null) && (byte)num != 6 && (byte)num != 5 && (int)val.biome != 17)
				{
					return num;
				}
			}
			return -1;
		}

		private static int GetClimbIndex(Segment segment)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected I4, but got Unknown
			if ((int)segment == 5)
			{
				return GetLastClimbIndex(Singleton<MapHandler>.Instance);
			}
			return (int)segment;
		}

		private static Transform