Decompiled source of Parachuted v1.0.1

tony4twentys-Parachuted.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PEAKLib.Core;
using Photon.Pun;
using Photon.Realtime;
using PhotonCustomPropsUtils;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Parachuted")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Parachuted")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("223e22f1-d786-4698-9c76-78d5633cbf2b")]
[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: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace Parachuted
{
	[BepInPlugin("tony4twentys.Parachuted", "Parachuted", "1.0.0")]
	[BepInProcess("PEAK.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(CharacterSpawner), "SpawnMyPlayerCharacter")]
		private static class Patch_SpawnMyPlayerCharacter
		{
			private static void Prefix(SpawnFlavor spawnFlavor, Transform spawnOverride, ref Vector3 spawnOffset)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: 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_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				if (IsModActive && IsShorePassedOutSpawn(spawnFlavor, spawnOverride))
				{
					Vector3 shoreSpawnOffset = GetShoreSpawnOffset();
					spawnOffset += shoreSpawnOffset;
					HideCrashedPlaneWreckage();
					Debug.Log((object)$"[Parachuted] Shore spawn offset {shoreSpawnOffset} (up {DropHeight:0.#}m, ocean {OceanOffset:0.#}m).");
				}
			}

			private static void Postfix(SpawnFlavor spawnFlavor, Transform spawnOverride, Character __result)
			{
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)__result == (Object)null) && IsModActive && IsShorePassedOutSpawn(spawnFlavor, spawnOverride))
				{
					ArmFreeParachute(__result);
				}
			}
		}

		[HarmonyPatch(typeof(Character), "FixedUpdate")]
		private static class Patch_CharacterFixedUpdate
		{
			private static void Prefix(Character __instance)
			{
				RestoreFreeParachuteFlag(__instance);
			}
		}

		[HarmonyPatch(typeof(Character), "Update")]
		private static class Patch_CharacterUpdate
		{
			private static void Postfix(Character __instance)
			{
				RestoreFreeParachuteFlag(__instance);
			}
		}

		[HarmonyPatch(typeof(CharacterBalloons), "RPC_SetParachute")]
		private static class Patch_RPC_SetParachute
		{
			private static void Postfix(CharacterBalloons __instance, bool open)
			{
				if (open && !((Object)(object)__instance == (Object)null))
				{
					Character val = ((Component)__instance).GetComponentInParent<Character>();
					if ((Object)(object)val == (Object)null)
					{
						val = Character.localCharacter;
					}
					ConsumeFreeParachute(val);
				}
			}
		}

		[HarmonyPatch(typeof(Campfire), "Awake")]
		private static class Patch_CampfireAwake
		{
			private static void Prefix(Campfire __instance)
			{
				if (IsModActive && IsShoreWreckCampfire(__instance))
				{
					_shoreWreckFires.Add(__instance);
					__instance.forceLit = false;
					__instance.nameOverride = "";
				}
			}

			private static void Postfix(Campfire __instance)
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Invalid comparison between Unknown and I4
				if (!((Object)(object)__instance == (Object)null) && _shoreWreckFires.Contains(__instance))
				{
					__instance.forceLit = false;
					if ((int)__instance.state != 2)
					{
						__instance.state = (FireState)0;
					}
					__instance.disableWhenLit = null;
					ApplyUnlitVisuals(__instance);
					_preparedCampfires.Add(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Campfire), "Light_Rpc")]
		private static class Patch_CampfireLightRpc
		{
			private static Exception Finalizer(Campfire __instance, Exception __exception)
			{
				if ((Object)(object)__instance != (Object)null && (_preparedCampfires.Contains(__instance) || _shoreWreckFires.Contains(__instance)))
				{
					ShowLitVisuals(__instance);
				}
				return __exception;
			}
		}

		public const string PluginGuid = "tony4twentys.Parachuted";

		public const string PluginName = "Parachuted";

		public const string PluginVersion = "1.0.0";

		public const string PhotonCustomPropsPluginGuid = "com.snosz.photoncustompropsutils";

		private const ushort ParachuteItemId = 176;

		private const string CrashedPlaneName = "crashed plane";

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

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

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

		private static ConfigEntry<float> _dropHeight;

		private static ConfigEntry<float> _oceanOffset;

		private static ConfigEntry<bool> _giveParachute;

		private static ConfigEntry<bool> _hideCrashedPlane;

		private Harmony _harmony;

		private Coroutine _hideWreckageRoutine;

		private static bool _wreckageHidden;

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

		private static readonly HashSet<Character> _freeParachuteCharacters = new HashSet<Character>();

		private static readonly HashSet<Campfire> _preparedCampfires = new HashSet<Campfire>();

		private static readonly HashSet<Campfire> _shoreWreckFires = new HashSet<Campfire>();

		internal static bool SyncedGiveParachute = true;

		internal static float SyncedDropHeight = 100f;

		internal static float SyncedOceanOffset = 80f;

		internal static bool SyncedHideCrashedPlane = true;

		private bool _applyingRemoteConfig;

		internal static Plugin Instance { get; private set; }

		public ManualLogSource Logger => ((BaseUnityPlugin)this).Logger;

		public static bool IsModActive => ParachutedModAuthorizationService.IsGameplayEnabled;

		private static float DropHeight => Mathf.Max(0f, SyncedDropHeight);

		private static float OceanOffset => SyncedOceanOffset;

		private void Awake()
		{
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			Instance = this;
			_giveParachute = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "GiveParachute", true, "On a Level_* shore sky-drop, open a parachute without putting item 176 in inventory (won't clash with other starter-item mods). Host-synced.");
			_dropHeight = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DropHeight", 100f, "Meters to raise the shore spawn into the sky. Host-synced.");
			_oceanOffset = ((BaseUnityPlugin)this).Config.Bind<float>("General", "OceanOffset", 80f, "Meters from the shore spawn out to sea (opposite the spawn facing / inland climb) so you parachute toward the campfire. Negative flips inland. Host-synced.");
			_hideCrashedPlane = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "HideCrashedPlane", true, "Hide the crashed plane fuselage/wings (keeps luggage and item spawners). Scene meshes are not networked — every client with this mod hides their own copy. Host-synced.");
			_giveParachute.SettingChanged += OnGameplaySettingChanged;
			_dropHeight.SettingChanged += OnGameplaySettingChanged;
			_oceanOffset.SettingChanged += OnGameplaySettingChanged;
			_hideCrashedPlane.SettingChanged += OnGameplaySettingChanged;
			ApplySnapshot(BuildSnapshot(), fromRemote: false);
			ParachutedModAuthorizationService.Initialize();
			SceneManager.sceneLoaded += OnSceneLoaded;
			SubscribeEvents();
			_harmony = new Harmony("tony4twentys.Parachuted");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Logger.LogInfo((object)"Parachuted v1.0.0 loaded (host handshake + config sync).");
		}

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

		internal void OnGameplayEnabled()
		{
			if (IsGameplayLevel())
			{
				ScheduleHideWreckage();
			}
		}

		private void OnGameplaySettingChanged(object sender, EventArgs e)
		{
			if (!_applyingRemoteConfig && (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient))
			{
				ParachutedModAuthorizationService.OnHostConfigChangedLocally();
			}
		}

		internal ParachutedConfigSnapshot BuildSnapshot()
		{
			return new ParachutedConfigSnapshot
			{
				GiveParachute = (_giveParachute == null || _giveParachute.Value),
				DropHeight = ((_dropHeight != null) ? Mathf.Max(0f, _dropHeight.Value) : 100f),
				OceanOffset = ((_oceanOffset != null) ? _oceanOffset.Value : 80f),
				HideCrashedPlane = (_hideCrashedPlane == null || _hideCrashedPlane.Value)
			};
		}

		internal void ApplySnapshot(ParachutedConfigSnapshot snapshot, bool fromRemote)
		{
			if (snapshot != null)
			{
				_applyingRemoteConfig = true;
				try
				{
					SyncedGiveParachute = snapshot.GiveParachute;
					SyncedDropHeight = Mathf.Max(0f, snapshot.DropHeight);
					SyncedOceanOffset = snapshot.OceanOffset;
					SyncedHideCrashedPlane = snapshot.HideCrashedPlane;
				}
				finally
				{
					_applyingRemoteConfig = false;
				}
				if (fromRemote)
				{
					Logger.LogInfo((object)$"[Parachuted] Applied host config (chute={SyncedGiveParachute}, drop={SyncedDropHeight:0.#}, ocean={SyncedOceanOffset:0.#}, hidePlane={SyncedHideCrashedPlane}).");
				}
				if (IsModActive && IsGameplayLevel())
				{
					ScheduleHideWreckage();
				}
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			ResetSession();
			SubscribeEvents();
			ScheduleHideWreckage();
		}

		private static void ResetSession()
		{
			_needsParachute.Clear();
			_lateOrReconnect.Clear();
			_disconnectedUserIds.Clear();
			_wreckageHidden = false;
			_preparedCampfires.Clear();
			_shoreWreckFires.Clear();
			_freeParachuteActors.Clear();
			_freeParachuteCharacters.Clear();
		}

		private void SubscribeEvents()
		{
			UnsubscribeEvents();
			PlayerHandler.CharacterRegistered = (Action<Character>)Delegate.Combine(PlayerHandler.CharacterRegistered, new Action<Character>(OnCharacterRegistered));
			GlobalEvents.OnPlayerConnected = (Action<Player>)Delegate.Combine(GlobalEvents.OnPlayerConnected, new Action<Player>(OnPlayerConnected));
			GlobalEvents.OnPlayerDisconnected = (Action<Player>)Delegate.Combine(GlobalEvents.OnPlayerDisconnected, new Action<Player>(OnPlayerDisconnected));
		}

		private void UnsubscribeEvents()
		{
			PlayerHandler.CharacterRegistered = (Action<Character>)Delegate.Remove(PlayerHandler.CharacterRegistered, new Action<Character>(OnCharacterRegistered));
			GlobalEvents.OnPlayerConnected = (Action<Player>)Delegate.Remove(GlobalEvents.OnPlayerConnected, new Action<Player>(OnPlayerConnected));
			GlobalEvents.OnPlayerDisconnected = (Action<Player>)Delegate.Remove(GlobalEvents.OnPlayerDisconnected, new Action<Player>(OnPlayerDisconnected));
		}

		private static void OnPlayerConnected(Player player)
		{
			if (player != null && PhotonNetwork.IsMasterClient && IsGameplayLevel() && (Object)(object)Character.localCharacter != (Object)null)
			{
				_lateOrReconnect.Add(player.ActorNumber);
			}
		}

		private static void OnPlayerDisconnected(Player player)
		{
			if (player != null)
			{
				if (!string.IsNullOrEmpty(player.UserId))
				{
					_disconnectedUserIds.Add(player.UserId);
				}
				_needsParachute.Remove(player.ActorNumber);
				_lateOrReconnect.Remove(player.ActorNumber);
			}
		}

		private static void OnCharacterRegistered(Character character)
		{
			try
			{
				if (PhotonNetwork.IsMasterClient && IsGameplayLevel() && IsModActive && TryGetActorNumber(character, out var actorNumber))
				{
					Player owner = ((MonoBehaviourPun)character).photonView.Owner;
					if (owner != null && !string.IsNullOrEmpty(owner.UserId) && _disconnectedUserIds.Remove(owner.UserId))
					{
						_lateOrReconnect.Add(actorNumber);
					}
					if (!_lateOrReconnect.Contains(actorNumber))
					{
						_needsParachute.Add(actorNumber);
					}
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[Parachuted] OnCharacterRegistered failed: {arg}");
			}
		}

		private static void ArmFreeParachute(Character character)
		{
			if ((Object)(object)character == (Object)null || !IsModActive || !SyncedGiveParachute)
			{
				return;
			}
			_freeParachuteCharacters.Add(character);
			if (TryGetActorNumber(character, out var actorNumber))
			{
				_freeParachuteActors.Add(actorNumber);
			}
			try
			{
				if ((Object)(object)character.data != (Object)null)
				{
					character.data.hasParachute = true;
					character.data.currentParachuteItem = null;
					character.data.currentParachuteSlot = null;
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[Parachuted] ArmFreeParachute failed: {arg}");
			}
			Debug.Log((object)"[Parachuted] Armed a free parachute (no inventory item).");
		}

		private static bool WantsFreeParachute(Character character)
		{
			if ((Object)(object)character == (Object)null || !IsModActive || !SyncedGiveParachute)
			{
				return false;
			}
			if (_freeParachuteCharacters.Contains(character))
			{
				return true;
			}
			int actorNumber;
			return TryGetActorNumber(character, out actorNumber) && _freeParachuteActors.Contains(actorNumber);
		}

		private static void RestoreFreeParachuteFlag(Character character)
		{
			if (!((Object)(object)character?.data == (Object)null) && WantsFreeParachute(character))
			{
				character.data.hasParachute = true;
			}
		}

		private static void ConsumeFreeParachute(Character character)
		{
			if (!((Object)(object)character == (Object)null))
			{
				_freeParachuteCharacters.Remove(character);
				if (TryGetActorNumber(character, out var actorNumber))
				{
					_freeParachuteActors.Remove(actorNumber);
				}
			}
		}

		private static bool IsShorePassedOutSpawn(SpawnFlavor spawnFlavor, Transform spawnOverride)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)spawnFlavor != 1)
			{
				return false;
			}
			if ((Object)(object)spawnOverride != (Object)null)
			{
				return false;
			}
			return IsGameplayLevel();
		}

		private static Vector3 GetShoreSpawnOffset()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_003a: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.up * DropHeight;
			float oceanOffset = OceanOffset;
			if (Mathf.Abs(oceanOffset) < 0.01f)
			{
				return val;
			}
			if (TryGetOceanBackDirection(out var direction))
			{
				val += direction * oceanOffset;
			}
			return val;
		}

		private static bool TryGetOceanBackDirection(out Vector3 direction)
		{
			//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_0027: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			direction = Vector3.zero;
			SpawnPoint localSpawnPoint = SpawnPoint.LocalSpawnPoint;
			if ((Object)(object)localSpawnPoint != (Object)null)
			{
				direction = -((Component)localSpawnPoint).transform.forward;
				direction.y = 0f;
				if (((Vector3)(ref direction)).sqrMagnitude > 0.01f)
				{
					((Vector3)(ref direction)).Normalize();
					return true;
				}
			}
			if (TryFindPlaneHalves(out var front, out var back, out var plane))
			{
				if ((Object)(object)plane != (Object)null)
				{
					direction = -plane.forward;
					direction.y = 0f;
					if (((Vector3)(ref direction)).sqrMagnitude > 0.01f)
					{
						((Vector3)(ref direction)).Normalize();
						return true;
					}
				}
				if ((Object)(object)front != (Object)null && (Object)(object)back != (Object)null)
				{
					Vector3 val = back.position - front.position;
					val.y = 0f;
					Vector3 val2 = (((Object)(object)localSpawnPoint != (Object)null) ? ((Component)localSpawnPoint).transform.forward : Vector3.forward);
					val2.y = 0f;
					if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
					{
						val2 = Vector3.forward;
					}
					((Vector3)(ref val2)).Normalize();
					Vector3 val3 = Vector3.Cross(Vector3.up, (((Vector3)(ref val)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val)).normalized : Vector3.right);
					val3.y = 0f;
					if (((Vector3)(ref val3)).sqrMagnitude > 0.01f)
					{
						((Vector3)(ref val3)).Normalize();
						direction = ((Vector3.Dot(val3, -val2) >= 0f) ? val3 : (-val3));
						return true;
					}
				}
			}
			return false;
		}

		private static bool TryFindPlaneHalves(out Transform front, out Transform back, out Transform plane)
		{
			front = null;
			back = null;
			plane = null;
			GameObject val = GameObject.Find("crashed plane");
			if ((Object)(object)val == (Object)null)
			{
				Transform[] array = Object.FindObjectsByType<Transform>((FindObjectsInactive)1, (FindObjectsSortMode)0);
				foreach (Transform val2 in array)
				{
					if ((Object)(object)val2 != (Object)null && ((Object)val2).name.Equals("crashed plane", StringComparison.OrdinalIgnoreCase))
					{
						val = ((Component)val2).gameObject;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			plane = val.transform;
			Transform[] componentsInChildren = val.GetComponentsInChildren<Transform>(true);
			foreach (Transform val3 in componentsInChildren)
			{
				if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3 == (Object)(object)plane))
				{
					if (IsFrontHalfName(((Object)val3).name))
					{
						front = val3;
					}
					else if (IsBackHalfName(((Object)val3).name))
					{
						back = val3;
					}
				}
			}
			return (Object)(object)front != (Object)null || (Object)(object)back != (Object)null || (Object)(object)plane != (Object)null;
		}

		private static bool IsFrontHalfName(string name)
		{
			return name != null && name.IndexOf("front half", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static bool IsBackHalfName(string name)
		{
			return name != null && name.IndexOf("back half", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static bool IsWreckageName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			if (IsFrontHalfName(name) || IsBackHalfName(name))
			{
				return true;
			}
			return name.IndexOf("Wings", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private void ScheduleHideWreckage()
		{
			if (_hideWreckageRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_hideWreckageRoutine);
			}
			if (IsModActive && IsGameplayLevel())
			{
				_hideWreckageRoutine = ((MonoBehaviour)this).StartCoroutine(HideWreckageRoutine());
			}
		}

		private static IEnumerator HideWreckageRoutine()
		{
			yield return null;
			HideCrashedPlaneWreckage();
			yield return (object)new WaitForSeconds(1f);
			HideCrashedPlaneWreckage();
			yield return (object)new WaitForSeconds(3f);
			HideCrashedPlaneWreckage();
		}

		private static void HideCrashedPlaneWreckage()
		{
			if (!IsModActive || !IsGameplayLevel() || !TryFindPlaneHalves(out var front, out var back, out var plane))
			{
				return;
			}
			if (SyncedHideCrashedPlane && !_wreckageHidden)
			{
				int num = 0;
				try
				{
					num += HideIfWreckage(front);
					num += HideIfWreckage(back);
					if ((Object)(object)plane != (Object)null)
					{
						Transform[] array = (Transform[])(object)new Transform[plane.childCount];
						for (int i = 0; i < plane.childCount; i++)
						{
							array[i] = plane.GetChild(i);
						}
						foreach (Transform val in array)
						{
							if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)front) && !((Object)(object)val == (Object)(object)back))
							{
								num += HideIfWreckage(val);
							}
						}
					}
				}
				catch (Exception arg)
				{
					Debug.LogError((object)$"[Parachuted] Hide wreckage failed: {arg}");
				}
				if (num > 0)
				{
					_wreckageHidden = true;
					Debug.Log((object)$"[Parachuted] Hid {num} crashed-plane wreckage object(s). Campfires reparented; luggage/spawners left in place.");
				}
			}
			if (_preparedCampfires.Count == 0)
			{
				MakeCrashedPlaneCampfiresUnlit(plane);
			}
		}

		private static int HideIfWreckage(Transform t)
		{
			if ((Object)(object)t == (Object)null || !IsWreckageName(((Object)t).name))
			{
				return 0;
			}
			if (!((Component)t).gameObject.activeSelf)
			{
				return 0;
			}
			RescueCampfiresFromWreckage(t);
			if ((Object)(object)((Component)t).GetComponent<Campfire>() != (Object)null || (Object)(object)((Component)t).GetComponentInChildren<Campfire>(true) != (Object)null)
			{
				HideWreckageVisualsKeepingCampfires(t);
				return 1;
			}
			((Component)t).gameObject.SetActive(false);
			return 1;
		}

		private static void RescueCampfiresFromWreckage(Transform wreckage)
		{
			if ((Object)(object)wreckage == (Object)null)
			{
				return;
			}
			Transform val = (((Object)(object)wreckage.parent != (Object)null) ? wreckage.parent : wreckage);
			Campfire[] componentsInChildren = ((Component)wreckage).GetComponentsInChildren<Campfire>(true);
			int num = 0;
			foreach (Campfire val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				Transform campfireVisualRoot = GetCampfireVisualRoot(val2);
				if (!((Object)(object)campfireVisualRoot == (Object)(object)wreckage) && campfireVisualRoot.IsChildOf(wreckage))
				{
					campfireVisualRoot.SetParent(val, true);
					if (!((Component)campfireVisualRoot).gameObject.activeSelf)
					{
						((Component)campfireVisualRoot).gameObject.SetActive(true);
					}
					num++;
				}
			}
			if (num > 0)
			{
				Debug.Log((object)$"[Parachuted] Reparented {num} campfire(s) off '{((Object)wreckage).name}' so the fire stays in the world.");
			}
		}

		private static void HideWreckageVisualsKeepingCampfires(Transform wreckage)
		{
			Renderer[] componentsInChildren = ((Component)wreckage).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).GetComponentInParent<Campfire>() != (Object)null))
				{
					val.enabled = false;
				}
			}
			Collider[] componentsInChildren2 = ((Component)wreckage).GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren2)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).GetComponentInParent<Campfire>() != (Object)null))
				{
					val2.enabled = false;
				}
			}
		}

		private static void MakeCrashedPlaneCampfiresUnlit(Transform plane)
		{
			if (!((Object)(object)plane == (Object)null))
			{
				Campfire[] componentsInChildren = ((Component)plane).GetComponentsInChildren<Campfire>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					MakeCampfireUnlitAndLightable(componentsInChildren[i]);
				}
			}
		}

		private static Transform GetCampfireVisualRoot(Campfire fire)
		{
			Transform val = ((Component)fire).transform;
			Transform val2 = null;
			while ((Object)(object)val != (Object)null)
			{
				if (((Object)val).name.IndexOf("Campfire_Flame", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					val2 = val;
				}
				val = val.parent;
			}
			return ((Object)(object)val2 != (Object)null) ? val2 : ((Component)fire).transform;
		}

		private static bool IsShoreWreckCampfire(Campfire fire)
		{
			if ((Object)(object)fire == (Object)null)
			{
				return false;
			}
			if (!string.IsNullOrEmpty(fire.nameOverride) && fire.nameOverride.Equals("FLAME", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			Transform val = ((Component)fire).transform;
			while ((Object)(object)val != (Object)null)
			{
				if (((Object)val).name.IndexOf("Campfire_Flame", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static void MakeCampfireUnlitAndLightable(Campfire fire)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)fire == (Object)null || _preparedCampfires.Contains(fire))
			{
				return;
			}
			try
			{
				if ((int)fire.state != 2)
				{
					fire.forceLit = false;
					fire.state = (FireState)0;
					fire.beenBurningFor = 0f;
					fire.nameOverride = "";
					fire.disableWhenLit = null;
					ApplyUnlitVisuals(fire);
					EnsureCampfireCollider(fire, GetCampfireVisualRoot(fire));
					SnapCampfireToGround(GetCampfireVisualRoot(fire));
					_preparedCampfires.Add(fire);
					Transform campfireVisualRoot = GetCampfireVisualRoot(fire);
					Debug.Log((object)$"[Parachuted] '{((Object)campfireVisualRoot).name}' is unlit and lightable (state={fire.state}, forceLit={fire.forceLit}, enableWhenLit={NameOf((Object)(object)fire.enableWhenLit)}, logRoot={NameOf((Object)(object)fire.logRoot)}).");
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[Parachuted] MakeCampfireUnlitAndLightable failed: {arg}");
			}
		}

		private static string NameOf(Object obj)
		{
			return (obj != (Object)null) ? obj.name : "null";
		}

		private static void ApplyUnlitVisuals(Campfire fire)
		{
			Transform campfireVisualRoot = GetCampfireVisualRoot(fire);
			if ((Object)(object)campfireVisualRoot != (Object)null && !((Component)campfireVisualRoot).gameObject.activeSelf)
			{
				((Component)campfireVisualRoot).gameObject.SetActive(true);
			}
			BindLitReferences(fire, campfireVisualRoot);
			SetChildActive(campfireVisualRoot, "Base", active: false);
			SetChildActive(campfireVisualRoot, "Collider", active: true);
			SetChildActive(campfireVisualRoot, "Campfire", active: true);
			EnableLogs(fire);
			if ((Object)(object)fire.enableWhenLit != (Object)null)
			{
				ArmEnableWhenLit(fire.enableWhenLit);
			}
			SetChildActive(campfireVisualRoot, "VFX_Smoke_Lit", active: true);
			SetChildActive(campfireVisualRoot, "VFX_Smoke_Off", active: true);
			StopParticles(fire.smokeParticlesLit);
			StopParticles(fire.smokeParticlesOff);
		}

		private static void BindLitReferences(Campfire fire, Transform root)
		{
			if ((Object)(object)fire.enableWhenLit == (Object)null)
			{
				Transform val = FindNamedChild(root, "EnableWhenLit");
				if ((Object)(object)val != (Object)null)
				{
					fire.enableWhenLit = ((Component)val).gameObject;
				}
			}
			if ((Object)(object)fire.smokeParticlesLit == (Object)null)
			{
				Transform val2 = FindNamedChild(root, "VFX_Smoke_Lit");
				if ((Object)(object)val2 != (Object)null)
				{
					fire.smokeParticlesLit = ((Component)val2).GetComponent<ParticleSystem>();
					if ((Object)(object)fire.smokeParticlesLit == (Object)null)
					{
						fire.smokeParticlesLit = ((Component)val2).GetComponentInChildren<ParticleSystem>(true);
					}
				}
			}
			if ((Object)(object)fire.fireParticles == (Object)null && (Object)(object)fire.enableWhenLit != (Object)null)
			{
				fire.fireParticles = fire.enableWhenLit.GetComponentInChildren<ParticleSystem>(true);
			}
		}

		private static void EnableLogs(Campfire fire)
		{
			Transform campfireVisualRoot = GetCampfireVisualRoot(fire);
			SetChildActive(campfireVisualRoot, "Logs", active: true);
			EnableVisuals(FindNamedChild(campfireVisualRoot, "Logs"));
			if ((Object)(object)fire.logRoot == (Object)null)
			{
				return;
			}
			Transform val = fire.logRoot;
			while ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(true);
				if ((Object)(object)val == (Object)(object)campfireVisualRoot)
				{
					break;
				}
				val = val.parent;
			}
			EnableVisuals(fire.logRoot);
		}

		private static void ArmEnableWhenLit(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return;
			}
			go.SetActive(false);
			Transform[] componentsInChildren = go.GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (!((Object)(object)componentsInChildren[i] == (Object)null) && !((Object)(object)componentsInChildren[i] == (Object)(object)go.transform))
				{
					((Component)componentsInChildren[i]).gameObject.SetActive(true);
				}
			}
		}

		private static void ShowLitVisuals(Campfire fire)
		{
			if (!((Object)(object)fire == (Object)null))
			{
				Transform campfireVisualRoot = GetCampfireVisualRoot(fire);
				BindLitReferences(fire, campfireVisualRoot);
				SetChildActive(campfireVisualRoot, "Base", active: false);
				EnableLogs(fire);
				if ((Object)(object)fire.enableWhenLit != (Object)null)
				{
					EnableVisuals(fire.enableWhenLit.transform);
				}
				SetChildActive(campfireVisualRoot, "EnableWhenLit", active: true);
				SetChildActive(campfireVisualRoot, "VFX_Smoke_Lit", active: true);
				if ((Object)(object)fire.smokeParticlesLit != (Object)null)
				{
					((Component)fire.smokeParticlesLit).gameObject.SetActive(true);
					fire.smokeParticlesLit.Play(true);
				}
				if ((Object)(object)fire.fireParticles != (Object)null)
				{
					((Component)fire.fireParticles).gameObject.SetActive(true);
					fire.fireParticles.Play(true);
				}
			}
		}

		private static void EnsureCampfireCollider(Campfire fire, Transform root)
		{
			Transform val = FindNamedChild(root, "Collider");
			if (!((Object)(object)val == (Object)null))
			{
				((Component)val).gameObject.SetActive(true);
				Collider component = ((Component)val).GetComponent<Collider>();
				if ((Object)(object)component != (Object)null)
				{
					component.enabled = true;
				}
				if (!((Object)(object)((Component)val).GetComponentInParent<Campfire>() == (Object)(object)fire))
				{
					val.SetParent(((Component)fire).transform, true);
				}
			}
		}

		private static void SnapCampfireToGround(Transform root)
		{
			//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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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)
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			Vector3 val = root.position + Vector3.up * 8f;
			RaycastHit[] array = Physics.RaycastAll(val, Vector3.down, 40f);
			float num = float.NegativeInfinity;
			bool flag = false;
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val2 = array[i];
				if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null) && !((Component)((RaycastHit)(ref val2)).collider).transform.IsChildOf(root) && !((Object)(object)((Component)((RaycastHit)(ref val2)).collider).transform == (Object)(object)root) && ((RaycastHit)(ref val2)).point.y > num)
				{
					num = ((RaycastHit)(ref val2)).point.y;
					flag = true;
				}
			}
			if (flag)
			{
				Vector3 position = root.position;
				position.y = num;
				root.position = position;
			}
		}

		private static void EnableVisuals(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			((Component)root).gameObject.SetActive(true);
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)componentsInChildren[i] != (Object)null)
				{
					((Component)componentsInChildren[i]).gameObject.SetActive(true);
				}
			}
			Renderer[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Renderer>(true);
			for (int j = 0; j < componentsInChildren2.Length; j++)
			{
				if ((Object)(object)componentsInChildren2[j] != (Object)null)
				{
					componentsInChildren2[j].enabled = true;
				}
			}
		}

		private static void StopParticles(ParticleSystem ps)
		{
			if (!((Object)(object)ps == (Object)null))
			{
				ps.Stop(true, (ParticleSystemStopBehavior)0);
			}
		}

		private static Transform FindNamedChild(Transform root, string childName)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((Object)val).name.Equals(childName, StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return null;
		}

		private static void SetChildActive(Transform root, string childName, bool active)
		{
			Transform val = FindNamedChild(root, childName);
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(active);
			}
		}

		private static bool HasParachute(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			try
			{
				if ((Object)(object)character.data != (Object)null && character.data.hasParachute)
				{
					return true;
				}
				CharacterData data = character.data;
				if ((Object)(object)((data != null) ? data.currentItem : null) != (Object)null && character.data.currentItem.itemID == 176)
				{
					return true;
				}
				Player player = character.player;
				if ((Object)(object)player == (Object)null)
				{
					return false;
				}
				if (SlotHasParachute(player.tempFullSlot))
				{
					return true;
				}
				ItemSlot[] itemSlots = player.itemSlots;
				if (itemSlots == null)
				{
					return false;
				}
				for (int i = 0; i < itemSlots.Length; i++)
				{
					if (SlotHasParachute(itemSlots[i]))
					{
						return true;
					}
				}
			}
			catch
			{
				return false;
			}
			return false;
		}

		private static bool SlotHasParachute(ItemSlot slot)
		{
			return slot != null && !slot.IsEmpty() && (Object)(object)slot.prefab != (Object)null && slot.prefab.itemID == 176;
		}

		private static bool TryGetActorNumber(Character character, out int actorNumber)
		{
			actorNumber = 0;
			if ((Object)(object)character == (Object)null || character.isBot)
			{
				return false;
			}
			PhotonView photonView = ((MonoBehaviourPun)character).photonView;
			if (((photonView != null) ? photonView.Owner : null) == null)
			{
				return false;
			}
			actorNumber = photonView.Owner.ActorNumber;
			return true;
		}

		private static bool IsGameplayLevel()
		{
			//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)
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).name != null && ((Scene)(ref activeScene)).name.IndexOf("Level_", StringComparison.OrdinalIgnoreCase) >= 0;
		}
	}
	internal static class ParachutedModAuthorizationService
	{
		public const string RoomConfigPropertyKey = "parachutedConfigV1";

		private static PhotonScopedManager _photonManager;

		private static bool _photonManagerReady;

		private static bool _hostHasParachutedMod;

		private static string _pendingHostConfigPayload;

		public static bool IsGameplayEnabled { get; private set; }

		public static void Initialize()
		{
			Networking.AddHostHasPluginListeners("tony4twentys.Parachuted", (Action)OnHostHasParachutedMod, (Action)OnHostMissingParachutedMod);
			if (PhotonCustomPropsUtilsPlugin.IsReady)
			{
				SetupPhotonManager();
			}
			else
			{
				PhotonCustomPropsUtilsPlugin.OnReady += SetupPhotonManager;
			}
			if (!PhotonNetwork.InRoom)
			{
				SetSoloAuthorized();
			}
		}

		public static void SetSoloAuthorized()
		{
			_hostHasParachutedMod = true;
			IsGameplayEnabled = true;
			ParachutedConfigSyncService.ApplyLocalAuthoritativeConfig();
		}

		private static void SetupPhotonManager()
		{
			if (_photonManagerReady)
			{
				return;
			}
			_photonManagerReady = true;
			_photonManager = PhotonCustomPropsUtilsPlugin.GetManager("tony4twentys.Parachuted");
			_photonManager.RegisterOnJoinedRoom((Action<Player>)delegate
			{
				if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && _hostHasParachutedMod)
				{
					ParachutedConfigSyncService.ApplyLocalAuthoritativeConfig();
					PublishHostConfigIfMaster();
				}
			});
			_photonManager.RegisterRoomProperty<string>("parachutedConfigV1", (RoomEventType)2, (Action<string>)delegate(string value)
			{
				if (!PhotonNetwork.IsMasterClient && !string.IsNullOrEmpty(value))
				{
					if (!_hostHasParachutedMod)
					{
						_pendingHostConfigPayload = value;
					}
					else
					{
						ParachutedConfigSyncService.ApplyRemoteSnapshot(value);
					}
				}
			});
		}

		private static void OnHostHasParachutedMod()
		{
			if (PhotonNetwork.InRoom)
			{
				_hostHasParachutedMod = true;
				IsGameplayEnabled = true;
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					instance.Logger.LogInfo((object)"[Parachuted] Host handshake OK — gameplay enabled.");
				}
				if (PhotonNetwork.IsMasterClient)
				{
					ParachutedConfigSyncService.ApplyLocalAuthoritativeConfig();
					PublishHostConfigIfMaster();
				}
				else if (!string.IsNullOrEmpty(_pendingHostConfigPayload))
				{
					ParachutedConfigSyncService.ApplyRemoteSnapshot(_pendingHostConfigPayload);
					_pendingHostConfigPayload = null;
				}
				Plugin.Instance?.OnGameplayEnabled();
			}
		}

		private static void OnHostMissingParachutedMod()
		{
			if (PhotonNetwork.InRoom)
			{
				_hostHasParachutedMod = false;
				IsGameplayEnabled = false;
				_pendingHostConfigPayload = null;
				ParachutedConfigSyncService.ClearRemoteHostConfig();
				ParachutedConfigSyncService.ApplyLocalAuthoritativeConfig();
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					instance.Logger.LogWarning((object)"[Parachuted] Host missing mod — gameplay disabled (anti-cheat).");
				}
			}
		}

		public static void OnHostConfigChangedLocally()
		{
			if (!PhotonNetwork.InRoom)
			{
				ParachutedConfigSyncService.ApplyLocalAuthoritativeConfig();
			}
			else if (IsGameplayEnabled && PhotonNetwork.IsMasterClient)
			{
				ParachutedConfigSyncService.ApplyLocalAuthoritativeConfig();
				PublishHostConfigIfMaster();
			}
		}

		private static void PublishHostConfigIfMaster()
		{
			if (_photonManager != null && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && !((Object)(object)Plugin.Instance == (Object)null))
			{
				string text = ParachutedConfigSyncService.Serialize(Plugin.Instance.BuildSnapshot());
				_photonManager.SetRoomProperty("parachutedConfigV1", (object)text);
				Plugin.Instance.Logger.LogInfo((object)"[Parachuted] Host published gameplay config.");
			}
		}
	}
	internal sealed class ParachutedConfigSnapshot
	{
		public bool GiveParachute = true;

		public float DropHeight = 100f;

		public float OceanOffset = 80f;

		public bool HideCrashedPlane = true;
	}
	internal static class ParachutedConfigSyncService
	{
		public const int SchemaVersion = 1;

		public const char PairSeparator = ';';

		public const char KeyValueSeparator = '=';

		public static bool HasRemoteHostConfig { get; private set; }

		public static void ClearRemoteHostConfig()
		{
			HasRemoteHostConfig = false;
		}

		public static void ApplyLocalAuthoritativeConfig()
		{
			if (!((Object)(object)Plugin.Instance == (Object)null))
			{
				ClearRemoteHostConfig();
				Plugin.Instance.ApplySnapshot(Plugin.Instance.BuildSnapshot(), fromRemote: false);
			}
		}

		public static void ApplyRemoteSnapshot(string payload)
		{
			if (PhotonNetwork.IsMasterClient || string.IsNullOrEmpty(payload))
			{
				return;
			}
			if (!TryDeserialize(payload, out var snapshot))
			{
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					instance.Logger.LogError((object)"[Parachuted] Failed to apply host config snapshot.");
				}
			}
			else
			{
				HasRemoteHostConfig = true;
				Plugin.Instance?.ApplySnapshot(snapshot, fromRemote: true);
			}
		}

		public static string Serialize(ParachutedConfigSnapshot snapshot)
		{
			if (snapshot == null)
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(96);
			AppendPair(stringBuilder, "v", 1.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "chute", snapshot.GiveParachute ? "1" : "0");
			AppendPair(stringBuilder, "drop", snapshot.DropHeight.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "ocean", snapshot.OceanOffset.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "hidePlane", snapshot.HideCrashedPlane ? "1" : "0");
			return stringBuilder.ToString();
		}

		public static bool TryDeserialize(string payload, out ParachutedConfigSnapshot snapshot)
		{
			snapshot = new ParachutedConfigSnapshot();
			if (string.IsNullOrEmpty(payload))
			{
				return false;
			}
			string[] array = payload.Split(new char[1] { ';' });
			int result = 0;
			bool flag = false;
			foreach (string text in array)
			{
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				int num = text.IndexOf('=');
				if (num > 0)
				{
					string text2 = text.Substring(0, num);
					string text3 = text.Substring(num + 1);
					switch (text2)
					{
					case "v":
						flag = int.TryParse(text3, NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
						break;
					case "chute":
						snapshot.GiveParachute = text3 == "1";
						break;
					case "drop":
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out snapshot.DropHeight);
						break;
					case "ocean":
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out snapshot.OceanOffset);
						break;
					case "hidePlane":
						snapshot.HideCrashedPlane = text3 == "1";
						break;
					}
				}
			}
			return flag && result >= 1 && result <= 1;
		}

		private static void AppendPair(StringBuilder builder, string key, string value)
		{
			if (builder.Length > 0)
			{
				builder.Append(';');
			}
			builder.Append(key);
			builder.Append('=');
			builder.Append(value ?? string.Empty);
		}
	}
}