Decompiled source of LobbyControlMidSessionJoin v0.4.1

BepInEx\plugins\LobbyControlMidSessionJoin\LobbyControlMidSessionJoin.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Events;
using UnityEngine.Video;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("ClientNetworkTransform")]
[assembly: IgnoresAccessChecksTo("com.olegknyazev.softmask")]
[assembly: IgnoresAccessChecksTo("DissonanceVoip")]
[assembly: IgnoresAccessChecksTo("DunGen")]
[assembly: IgnoresAccessChecksTo("DunGen.Integration.ASPP")]
[assembly: IgnoresAccessChecksTo("DunGen.Integration.UnityNav")]
[assembly: IgnoresAccessChecksTo("EasyTextEffects")]
[assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Jobs")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.XR.CoreUtils")]
[assembly: IgnoresAccessChecksTo("Unity.XR.Management")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.ConformanceAutomation")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MetaQuestSupport")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MockRuntime")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.OculusQuestSupport")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.RuntimeDebugger")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.SpatialTracking")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: IgnoresAccessChecksTo("UnityEngine.XR.LegacyInputHelpers")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LobbyControlMidSessionJoin")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.1.0")]
[assembly: AssemblyInformationalVersion("0.4.1+b98ad5a4f0e93b9d27dd1d4309b48d1f55726c4a")]
[assembly: AssemblyProduct("LobbyControlMidSessionJoin")]
[assembly: AssemblyTitle("LobbyControlMidSessionJoin")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LobbyControlMidSessionJoin
{
	internal static class LobbyControlBridge
	{
		private const BindingFlags STATIC_FLAGS = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly string[] ConnectionMemberNames = new string[6] { "_allowNewConnection", "allowNewConnection", "AllowNewConnection", "_acceptingConnections", "acceptingConnections", "AcceptingConnections" };

		private static readonly string[] LobbyModificationMemberNames = new string[3] { "CanModifyLobby", "_canModifyLobby", "canModifyLobby" };

		private static readonly Type? LateJoinType = AccessTools.TypeByName("LobbyControl.Patches.LateJoinPatches") ?? AccessTools.TypeByName("LobbyControl.Patches.LateJoin") ?? AccessTools.TypeByName("LobbyControl.Patches.ConnectionQueuePatches");

		private static readonly Type? MainType = AccessTools.TypeByName("LobbyControl.LobbyControl") ?? AccessTools.TypeByName("LobbyControl.Plugin");

		private static readonly MemberInfo? AllowNewConnection = FindBooleanMember(LateJoinType, ConnectionMemberNames);

		private static readonly MemberInfo? CanModifyLobby = FindBooleanMember(MainType, LobbyModificationMemberNames);

		internal static bool Available
		{
			get
			{
				if (!(AllowNewConnection != null))
				{
					return CanModifyLobby != null;
				}
				return true;
			}
		}

		internal static void PermitConnections(bool value)
		{
			bool flag = TrySetBooleanMember(AllowNewConnection, value);
			bool flag2 = TrySetBooleanMember(CanModifyLobby, value);
			if (!flag && !flag2)
			{
				Plugin.Log.LogWarning((object)"LobbyControl compatibility bridge could not find a supported connection-state member. LobbyControl will still handle its own queue and approval flow.");
			}
			else
			{
				Plugin.Debug($"LobbyControl bridge: allowUpdated={flag}, " + $"canModifyUpdated={flag2}, value={value}");
			}
		}

		private static MemberInfo? FindBooleanMember(Type? type, IEnumerable<string> names)
		{
			if (type == null)
			{
				return null;
			}
			foreach (string name in names)
			{
				FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field?.FieldType == typeof(bool))
				{
					return field;
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property?.PropertyType == typeof(bool) && property.SetMethod != null)
				{
					return property;
				}
			}
			return null;
		}

		private static bool TrySetBooleanMember(MemberInfo? member, bool value)
		{
			if (member == null)
			{
				return false;
			}
			try
			{
				if (!(member is FieldInfo fieldInfo))
				{
					if (member is PropertyInfo propertyInfo)
					{
						propertyInfo.SetValue(null, value);
						return true;
					}
					return false;
				}
				fieldInfo.SetValue(null, value);
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not update LobbyControl member " + member.DeclaringType?.FullName + "." + member.Name + ": " + ex.Message));
				return false;
			}
		}
	}
	internal static class MidJoinState
	{
		internal static int SnapshotsSent;

		internal static int LandingSequencesSuppressed;

		internal static bool ClientLateJoinSyncActive;

		internal static bool ClientLateJoinSyncCompleted;

		internal static bool ClientPlayerPositioned;

		internal static string LastStatus = "No synchronization attempted yet.";

		internal static bool IsActiveMoon
		{
			get
			{
				StartOfRound instance = StartOfRound.Instance;
				if ((Object)(object)instance != (Object)null && !instance.inShipPhase)
				{
					return instance.shipHasLanded;
				}
				return false;
			}
		}

		internal static void ResetClientState()
		{
			ClientLateJoinSyncActive = false;
			ClientLateJoinSyncCompleted = false;
			ClientPlayerPositioned = false;
		}
	}
	internal static class NetworkSync
	{
		private const uint GENERATE_LEVEL_RPC_ID = 3073943002u;

		private const uint FINISH_GENERATING_LEVEL_RPC_ID = 2729232387u;

		private const float GENERATION_TIMEOUT_SECONDS = 60f;

		private const float SNAPSHOT_ACK_TIMEOUT_SECONDS = 10f;

		private static readonly MethodInfo? BeginSendClientRpc = AccessTools.Method(typeof(NetworkBehaviour), "__beginSendClientRpc", (Type[])null, (Type[])null);

		private static readonly MethodInfo? EndSendClientRpc = AccessTools.Method(typeof(NetworkBehaviour), "__endSendClientRpc", (Type[])null, (Type[])null);

		private static readonly Dictionary<ulong, int> ActiveSynchronizations = new Dictionary<ulong, int>();

		private static int _nextSynchronizationId;

		internal static void StartLateClientSynchronization(StartOfRound owner, ulong clientId)
		{
			if (ActiveSynchronizations.ContainsKey(clientId))
			{
				Plugin.Debug($"Ignored duplicate synchronization request for client {clientId}.");
				return;
			}
			int num = ++_nextSynchronizationId;
			ActiveSynchronizations[clientId] = num;
			try
			{
				((MonoBehaviour)owner).StartCoroutine(SynchronizeLateClientGuarded(clientId, num));
			}
			catch
			{
				if (IsCurrentSynchronization(clientId, num))
				{
					ActiveSynchronizations.Remove(clientId);
				}
				throw;
			}
		}

		internal static void ResetSynchronizations()
		{
			ActiveSynchronizations.Clear();
			_nextSynchronizationId = 0;
		}

		internal static void HandleClientDisconnected(ulong clientId)
		{
			ActiveSynchronizations.Remove(clientId);
			WorldStateSync.ClearSnapshotAcknowledgement(clientId);
			RoundManager.Instance?.playersFinishedGeneratingFloor.Remove(clientId);
			Plugin.Debug($"Cleared late-join synchronization state for disconnected client {clientId}.");
		}

		private static bool IsCurrentSynchronization(ulong clientId, int synchronizationId)
		{
			if (ActiveSynchronizations.TryGetValue(clientId, out var value))
			{
				return value == synchronizationId;
			}
			return false;
		}

		private static IEnumerator SynchronizeLateClientGuarded(ulong clientId, int synchronizationId)
		{
			try
			{
				yield return SynchronizeLateClientCore(clientId, synchronizationId);
			}
			finally
			{
				if (IsCurrentSynchronization(clientId, synchronizationId))
				{
					ActiveSynchronizations.Remove(clientId);
					WorldStateSync.ClearSnapshotAcknowledgement(clientId);
					RoundManager.Instance?.playersFinishedGeneratingFloor.Remove(clientId);
				}
			}
		}

		private static IEnumerator SynchronizeLateClientCore(ulong clientId, int synchronizationId)
		{
			if (!Plugin.Enabled.Value || !MidJoinState.IsActiveMoon)
			{
				yield break;
			}
			NetworkManager network = NetworkManager.Singleton;
			RoundManager manager = RoundManager.Instance;
			if ((Object)(object)network == (Object)null || (Object)(object)manager == (Object)null || !network.IsServer)
			{
				yield break;
			}
			yield return null;
			yield return null;
			if (!IsCurrentSynchronization(clientId, synchronizationId))
			{
				yield break;
			}
			if (!IsClientConnected(network, clientId))
			{
				SetStatus($"Client {clientId} disconnected before synchronization.");
				yield break;
			}
			if (!MidJoinState.IsActiveMoon)
			{
				SetStatus("Round left the landed state before synchronization.");
				yield break;
			}
			try
			{
				WorldStateSync.ResetSnapshotAcknowledgement(clientId);
				WorldStateSync.SendSnapshot(clientId, includeInterior: false);
				SetStatus($"Waiting for client {clientId} to acknowledge the landed ship snapshot.");
			}
			catch (Exception ex)
			{
				SetStatus("Landed ship snapshot synchronization failed: " + ex.Message);
				Plugin.Log.LogError((object)ex);
				yield break;
			}
			float acknowledgementDeadline = Time.realtimeSinceStartup + 10f;
			float nextSnapshotResend = Time.realtimeSinceStartup + 0.5f;
			while (!WorldStateSync.HasSnapshotAcknowledgement(clientId))
			{
				if (!IsCurrentSynchronization(clientId, synchronizationId))
				{
					yield break;
				}
				if (!IsClientConnected(network, clientId))
				{
					WorldStateSync.ClearSnapshotAcknowledgement(clientId);
					SetStatus($"Client {clientId} disconnected before acknowledging the landed ship state.");
					yield break;
				}
				if (!MidJoinState.IsActiveMoon)
				{
					WorldStateSync.ClearSnapshotAcknowledgement(clientId);
					SetStatus("Round left the landed state before the late client acknowledged ship state.");
					yield break;
				}
				if (Time.realtimeSinceStartup >= acknowledgementDeadline)
				{
					WorldStateSync.ClearSnapshotAcknowledgement(clientId);
					SetStatus($"Timed out waiting for client {clientId} to acknowledge the landed ship state.");
					yield break;
				}
				if (Time.realtimeSinceStartup >= nextSnapshotResend)
				{
					try
					{
						WorldStateSync.SendSnapshot(clientId, includeInterior: false);
					}
					catch (Exception ex2)
					{
						Plugin.Debug("Could not resend landed ship snapshot: " + ex2.Message);
					}
					nextSnapshotResend = Time.realtimeSinceStartup + 0.5f;
				}
				yield return null;
			}
			WorldStateSync.ClearSnapshotAcknowledgement(clientId);
			try
			{
				manager.playersFinishedGeneratingFloor.Remove(clientId);
				SendGenerateLevelRpc(manager, clientId);
				SetStatus($"Waiting for client {clientId} to finish generating the interior.");
			}
			catch (Exception ex3)
			{
				SetStatus("Native moon generation synchronization failed: " + ex3.Message);
				Plugin.Log.LogError((object)ex3);
				yield break;
			}
			if (StartOfRound.Instance.currentLevel.spawnEnemiesAndScrap)
			{
				float deadline = Time.realtimeSinceStartup + 60f;
				while (!manager.playersFinishedGeneratingFloor.Contains(clientId))
				{
					if (!IsCurrentSynchronization(clientId, synchronizationId))
					{
						yield break;
					}
					if (!IsClientConnected(network, clientId))
					{
						SetStatus($"Client {clientId} disconnected while generating the interior.");
						yield break;
					}
					if (!MidJoinState.IsActiveMoon)
					{
						SetStatus("Round left the landed state while the late client was generating.");
						yield break;
					}
					if (Time.realtimeSinceStartup >= deadline)
					{
						SetStatus($"Timed out waiting for client {clientId} to finish generating the interior.");
						yield break;
					}
					yield return null;
				}
			}
			if (!IsCurrentSynchronization(clientId, synchronizationId) || !IsClientConnected(network, clientId))
			{
				yield break;
			}
			try
			{
				SendEmptyClientRpc((NetworkBehaviour)(object)manager, 2729232387u, clientId);
				manager.playersFinishedGeneratingFloor.Remove(clientId);
			}
			catch (Exception ex4)
			{
				SetStatus("Late-client finalization failed: " + ex4.Message);
				Plugin.Log.LogError((object)ex4);
				yield break;
			}
			yield return (object)new WaitForSeconds(0.25f);
			if (!IsCurrentSynchronization(clientId, synchronizationId) || !IsClientConnected(network, clientId))
			{
				yield break;
			}
			try
			{
				WorldStateSync.SendSnapshot(clientId, includeInterior: true);
				MidJoinState.SnapshotsSent++;
				SetStatus($"Completed ship, interior, door, and lighting synchronization for client {clientId}.");
			}
			catch (Exception ex5)
			{
				SetStatus("Late-client world-state synchronization failed: " + ex5.Message);
				Plugin.Log.LogError((object)ex5);
			}
		}

		private static bool IsClientConnected(NetworkManager network, ulong clientId)
		{
			return network.ConnectedClients.ContainsKey(clientId);
		}

		private static void SendGenerateLevelRpc(RoundManager manager, ulong clientId)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0054: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected I4, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Expected I4, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.currentLevel == (Object)null)
			{
				throw new InvalidOperationException("Round state is not ready.");
			}
			ClientRpcParams rpcParams = TargetClient(clientId);
			FastBufferWriter val = BeginRpc((NetworkBehaviour)(object)manager, 3073943002u, rpcParams);
			BytePacker.WriteValueBitPacked(val, instance.randomMapSeed);
			BytePacker.WriteValueBitPacked(val, instance.currentLevelID);
			BytePacker.WriteValueBitPacked(val, instance.currentLevel.moldSpreadIterations);
			BytePacker.WriteValueBitPacked(val, instance.currentLevel.moldStartPosition);
			MoldSpreadManager val2 = Object.FindObjectOfType<MoldSpreadManager>();
			bool flag = (Object)(object)val2 != (Object)null && instance.currentLevelID >= 0;
			((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives));
			if (flag)
			{
				int[] array = val2.planetMoldStates[instance.currentLevelID].destroyedMold.ToArray();
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(array, default(ForPrimitives));
			}
			BytePacker.WriteValueBitPacked(val, instance.currentLevel.currentWeather + 255);
			EndRpc((NetworkBehaviour)(object)manager, val, 3073943002u, rpcParams);
			Plugin.Debug($"Started native level sync client={clientId}, seed={instance.randomMapSeed}, " + $"level={instance.currentLevelID}, mold={instance.currentLevel.moldSpreadIterations}/" + $"{instance.currentLevel.moldStartPosition}, weather={(int)instance.currentLevel.currentWeather}, " + $"moldState={flag}");
		}

		private static void SendEmptyClientRpc(NetworkBehaviour target, uint rpcId, ulong clientId)
		{
			//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_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0013: Unknown result type (might be due to invalid IL or missing references)
			ClientRpcParams rpcParams = TargetClient(clientId);
			FastBufferWriter writer = BeginRpc(target, rpcId, rpcParams);
			EndRpc(target, writer, rpcId, rpcParams);
		}

		private static FastBufferWriter BeginRpc(NetworkBehaviour target, uint rpcId, ClientRpcParams rpcParams)
		{
			//IL_003c: 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 (BeginSendClientRpc == null || EndSendClientRpc == null)
			{
				throw new MissingMethodException("Unity Netcode ClientRpc send methods were not found.");
			}
			return (FastBufferWriter)BeginSendClientRpc.Invoke(target, new object[3]
			{
				rpcId,
				rpcParams,
				(object)(RpcDelivery)0
			});
		}

		private static void EndRpc(NetworkBehaviour target, FastBufferWriter writer, uint rpcId, ClientRpcParams rpcParams)
		{
			//IL_000e: 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)
			EndSendClientRpc.Invoke(target, new object[4]
			{
				writer,
				rpcId,
				rpcParams,
				(object)(RpcDelivery)0
			});
		}

		private static ClientRpcParams TargetClient(ulong clientId)
		{
			//IL_0002: 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_0025: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			return new ClientRpcParams
			{
				Send = new ClientRpcSendParams
				{
					TargetClientIds = new List<ulong> { clientId }
				}
			};
		}

		private static void SetStatus(string status)
		{
			MidJoinState.LastStatus = status;
			Plugin.Debug(status);
		}
	}
	[HarmonyPatch]
	internal static class Patches
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(GameNetworkManager), "ConnectionApproval")]
		private static void ConnectionApprovalPostfix(GameNetworkManager __instance, ConnectionApprovalRequest request, ConnectionApprovalResponse response)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Enabled.Value && MidJoinState.IsActiveMoon && request.ClientNetworkId != NetworkManager.Singleton.LocalClientId && !response.Approved && response.Reason == "Ship has already landed!")
			{
				response.Approved = true;
				response.Reason = string.Empty;
				response.CreatePlayerObject = true;
				response.Pending = false;
				Plugin.Debug("Overrode LobbyControl's landed-ship rejection.");
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(StartOfRound), "StartGame")]
		private static void StartGamePostfix(StartOfRound __instance)
		{
			if (((NetworkBehaviour)__instance).IsServer && Plugin.Enabled.Value)
			{
				LobbyControlBridge.PermitConnections(value: true);
				if (Plugin.AutoOpenLobby.Value)
				{
					GameNetworkManager.Instance.SetLobbyJoinable(true);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "OnShipLandedMiscEvents")]
		private static void ShipLandedPostfix(StartOfRound __instance)
		{
			if (((NetworkBehaviour)__instance).IsServer && Plugin.Enabled.Value)
			{
				LobbyControlBridge.PermitConnections(value: true);
				if (Plugin.AutoOpenLobby.Value)
				{
					GameNetworkManager.Instance.SetLobbyJoinable(true);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "Start")]
		private static void StartOfRoundStartPostfix()
		{
			WorldStateSync.RegisterHandler();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
		private static void ConnectClientToPlayerObjectPostfix()
		{
			WorldStateSync.RegisterHandler();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameNetworkManager), "SetInstanceValuesBackToDefault")]
		private static void ResetNetworkStatePostfix()
		{
			WorldStateSync.UnregisterHandler();
			NetworkSync.ResetSynchronizations();
			MidJoinState.ResetClientState();
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(StartOfRound), "openingDoorsSequence")]
		private static bool OpeningDoorsSequencePrefix(StartOfRound __instance, ref IEnumerator __result)
		{
			if (!Plugin.Enabled.Value || ((NetworkBehaviour)__instance).IsServer || !MidJoinState.ClientLateJoinSyncActive)
			{
				return true;
			}
			MidJoinState.LandingSequencesSuppressed++;
			__result = WorldStateSync.RunLateJoinLandedSequence(__instance);
			Plugin.Debug("Suppressed the native openingDoorsSequence for a mid-session joining client.");
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "SetShipReadyToLand")]
		private static void SetShipReadyToLandPostfix(StartOfRound __instance)
		{
			WorldStateSync.RestoreLevelInformationOverlayForOrbit(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "OnPlayerConnectedClientRpc")]
		private static void PlayerConnectedPostfix(StartOfRound __instance, ulong clientId)
		{
			if (((NetworkBehaviour)__instance).IsServer && clientId != 0L && MidJoinState.IsActiveMoon)
			{
				NetworkSync.StartLateClientSynchronization(__instance, clientId);
			}
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(TerminalAccessibleObject), "InitializeValues")]
		private static bool TerminalAccessibleObjectInitializeValuesPrefix(TerminalAccessibleObject __instance)
		{
			return !WorldStateSync.ShouldDeferTerminalInitialization(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(RoundManager), "TurnOnAllLights")]
		private static bool TurnOnAllLightsPrefix(RoundManager __instance, bool on)
		{
			if (!WorldStateSync.ShouldBlockFacilityPowerOn(__instance, on))
			{
				return true;
			}
			Plugin.Debug("Blocked a delayed client-local facility lights-on call after permanent apparatus power loss.");
			return false;
		}
	}
	[BepInPlugin("nukemaster619.LobbyControlMidSessionJoin", "LobbyControl Mid-Session Join", "0.4.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal static Plugin Instance;

		public const string Guid = "nukemaster619.LobbyControlMidSessionJoin";

		public const string Name = "LobbyControl Mid-Session Join";

		public const string Version = "0.4.1";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> AutoOpenLobby;

		internal static ConfigEntry<bool> SpawnInShip;

		internal static ConfigEntry<bool> DebugLogging;

		private Harmony? _harmony;

		private void Awake()
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Allow players to join while the ship is landed on a moon.");
			AutoOpenLobby = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoOpenLobby", true, "Keep/reopen the Steam lobby while a moon round is active.");
			SpawnInShip = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SpawnInShip", true, "Move a newly joined local player to the ship after level synchronization.");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Enabled", false, "Write verbose synchronization information to the BepInEx log.");
			_harmony = new Harmony("nukemaster619.LobbyControlMidSessionJoin");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LobbyControl Mid-Session Join 0.4.1 loaded.");
		}

		internal static void Debug(string text)
		{
			if (DebugLogging.Value)
			{
				Log.LogInfo((object)("[debug] " + text));
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
	internal static class TerminalCommands
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(Terminal __instance, ref TerminalNode __result)
		{
			string[] array = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded).Trim().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0 || !array[0].Equals("midjoin", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			__result = Node(Execute(array));
			return false;
		}

		private static string Execute(string[] args)
		{
			if (!GameNetworkManager.Instance.isHostingGame)
			{
				return "MIDJOIN commands are host-only.\n\n";
			}
			if (args.Length == 1 || args[1].Equals("help", StringComparison.OrdinalIgnoreCase))
			{
				return "MIDJOIN COMMANDS\n\nmidjoin status\nmidjoin enable|disable\nmidjoin debug on|off\nmidjoin autoopen on|off\nmidjoin spawninship on|off\n\n";
			}
			switch (args[1].ToLowerInvariant())
			{
			case "status":
				return Status();
			case "enable":
				Plugin.Enabled.Value = true;
				LobbyControlBridge.PermitConnections(value: true);
				return "Mid-session joining enabled.\n\n";
			case "disable":
				Plugin.Enabled.Value = false;
				return "Mid-session joining disabled.\n\n";
			case "debug":
				return SetBool(args, Plugin.DebugLogging, "Debug logging");
			case "autoopen":
				return SetBool(args, Plugin.AutoOpenLobby, "Automatic lobby reopening");
			case "spawninship":
				return SetBool(args, Plugin.SpawnInShip, "Spawn-in-ship");
			default:
				return "Unknown MIDJOIN command. Type 'midjoin help'.\n\n";
			}
		}

		private static string SetBool(string[] args, ConfigEntry<bool> entry, string label)
		{
			if (args.Length < 3 || (args[2] != "on" && args[2] != "off"))
			{
				return "Usage: midjoin " + args[1] + " on|off\n\n";
			}
			entry.Value = args[2] == "on";
			return label + ": " + (entry.Value ? "ON" : "OFF") + "\n\n";
		}

		private static string Status()
		{
			StartOfRound instance = StartOfRound.Instance;
			string text = (((Object)(object)instance == (Object)null) ? "no round" : (instance.inShipPhase ? "orbit/ship phase" : (instance.shipHasLanded ? "landed moon" : "transition")));
			return "MID-SESSION JOIN STATUS\n\n" + $"Enabled: {Plugin.Enabled.Value}\n" + "Phase: " + text + "\nLobbyControl bridge: " + (LobbyControlBridge.Available ? "OK" : "NOT FOUND") + "\n" + $"Native syncs sent: {MidJoinState.SnapshotsSent}\n" + $"Auto-open lobby: {Plugin.AutoOpenLobby.Value}\n" + $"Spawn in ship: {Plugin.SpawnInShip.Value}\n" + $"Debug: {Plugin.DebugLogging.Value}\n" + "Last result: " + MidJoinState.LastStatus + "\n\n";
		}

		private static TerminalNode Node(string text)
		{
			TerminalNode obj = ScriptableObject.CreateInstance<TerminalNode>();
			obj.displayText = text;
			obj.clearPreviousText = true;
			obj.maxCharactersToType = 50;
			return obj;
		}
	}
	internal static class WorldStateSync
	{
		private sealed class WorldSnapshot
		{
			internal bool IncludeInterior;

			internal bool SpawnInShip;

			internal bool InShipPhase;

			internal bool ShipHasLanded;

			internal bool ShipIsLeaving;

			internal bool ShipDoorsEnabled;

			internal bool HangarDoorsClosed;

			internal bool NewGameIsLoading;

			internal bool TravellingToNewLevel;

			internal bool ShipAmbiancePlaying;

			internal bool ShipTravelAudioPlaying;

			internal bool PowerOffPermanently;

			internal bool PowerOn;

			internal int CurrentWeather;

			internal bool CurrentPlanetActive;

			internal bool OuterSpaceSunActive;

			internal bool StarSphereActive;

			internal TransformSnapshot ShipTransform = new TransformSnapshot();

			internal TransformSnapshot CurrentPlanetTransform = new TransformSnapshot();

			internal AnimatorSnapshot ShipAnimator = new AnimatorSnapshot();

			internal AnimatorSnapshot ShipBodyAnimator = new AnimatorSnapshot();

			internal AnimatorSnapshot ShipDoorsAnimator = new AnimatorSnapshot();

			internal AnimatorSnapshot CurrentPlanetAnimator = new AnimatorSnapshot();

			internal AnimatorSnapshot OuterSpaceSunAnimator = new AnimatorSnapshot();

			internal readonly List<DoorSnapshot> Doors = new List<DoorSnapshot>();

			internal readonly List<TerminalDoorSnapshot> TerminalDoors = new List<TerminalDoorSnapshot>();
		}

		private sealed class TransformSnapshot
		{
			internal bool Exists;

			internal Vector3 LocalPosition;

			internal Quaternion LocalRotation;

			internal Vector3 LocalScale;
		}

		private sealed class AnimatorSnapshot
		{
			internal bool Exists;

			internal bool Enabled;

			internal float Speed;

			internal readonly List<AnimatorParameterSnapshot> Parameters = new List<AnimatorParameterSnapshot>();

			internal readonly List<AnimatorLayerSnapshot> Layers = new List<AnimatorLayerSnapshot>();
		}

		private sealed class AnimatorParameterSnapshot
		{
			internal int NameHash;

			internal AnimatorControllerParameterType Type;

			internal bool BoolValue;

			internal int IntValue;

			internal float FloatValue;
		}

		private sealed class AnimatorLayerSnapshot
		{
			internal int StateHash;

			internal float NormalizedTime;

			internal float Weight;
		}

		private sealed class DoorSnapshot
		{
			internal Vector3 Position;

			internal bool IsOpen;

			internal bool IsLocked;

			internal bool IsPickingLock;

			internal float LockPickTimeLeft;

			internal bool TriggerInteractable;

			internal float TriggerTimeToHold;

			internal float TriggerSpeedMultiplier;
		}

		private sealed class TerminalDoorSnapshot
		{
			internal Vector3 Position;

			internal bool IsOpen;

			internal bool IsPoweredOn;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__ReceiveSnapshot;

			public static HandleNamedMessageDelegate <1>__ReceiveSnapshotAcknowledgement;

			public static Action<ulong> <2>__HandleClientDisconnected;
		}

		private const string MESSAGE_NAME = "LobbyControlMidSessionJoin.WorldState.v3";

		private const string ACK_MESSAGE_NAME = "LobbyControlMidSessionJoin.WorldStateAck.v1";

		private const int MESSAGE_VERSION = 3;

		private const float OBJECT_MATCH_DISTANCE = 0.75f;

		private const float APPLY_TIMEOUT_SECONDS = 15f;

		private const BindingFlags INSTANCE_FIELD_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly FieldInfo? ShipTravelCoroutineField = FindInstanceField(typeof(StartOfRound), "shipTravelCoroutine");

		private static readonly MethodInfo? SetWeatherEffectsMethod = typeof(TimeOfDay).GetMethod("SetWeatherEffects", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);

		private static readonly FieldInfo? DoorIsOpenedField = FindInstanceField(typeof(DoorLock), "isDoorOpened");

		private static readonly FieldInfo? TerminalDoorOpenField = FindInstanceField(typeof(TerminalAccessibleObject), "isDoorOpen");

		private static readonly FieldInfo? TerminalPoweredField = FindInstanceField(typeof(TerminalAccessibleObject), "isPoweredOn");

		private static readonly FieldInfo? TerminalInitializedValuesField = FindInstanceField(typeof(TerminalAccessibleObject), "initializedValues");

		private static readonly FieldInfo? TerminalMapRadarTextField = FindInstanceField(typeof(TerminalAccessibleObject), "mapRadarText");

		private static readonly FieldInfo? TerminalMapRadarBoxField = FindInstanceField(typeof(TerminalAccessibleObject), "mapRadarBox");

		private static readonly FieldInfo? LoadingScreenAnimatorField = FindInstanceField(typeof(HUDManager), "LoadingScreen");

		private static readonly FieldInfo? LegacyLoadingDarkenScreenField = FindInstanceField(typeof(HUDManager), "loadingDarkenScreen");

		private static readonly FieldInfo? RoundPowerLightsCoroutineField = FindInstanceField(typeof(RoundManager), "powerLightsCoroutine");

		private static readonly FieldInfo? RoundFlickerLightsCoroutineField = FindInstanceField(typeof(RoundManager), "flickerLightsCoroutine");

		private static readonly FieldInfo? MapScreenIsScreenOnField = FindInstanceField(typeof(ManualCameraRenderer), "isScreenOn");

		private static readonly FieldInfo? MapScreenEnabledOnLocalClientField = FindInstanceField(typeof(ManualCameraRenderer), "screenEnabledOnLocalClient");

		private static readonly FieldInfo? MapScreenUpdateCoroutineField = FindInstanceField(typeof(ManualCameraRenderer), "updateMapCameraCoroutine");

		private static readonly FieldInfo? MapScreenSyncingTargetField = FindInstanceField(typeof(ManualCameraRenderer), "syncingTargetPlayer");

		private static readonly FieldInfo? MapScreenSyncingSwitchField = FindInstanceField(typeof(ManualCameraRenderer), "syncingSwitchScreen");

		private static readonly FieldInfo? PlayerFallValueField = FindInstanceField(typeof(PlayerControllerB), "fallValue");

		private static readonly FieldInfo? PlayerFallValueUncappedField = FindInstanceField(typeof(PlayerControllerB), "fallValueUncapped");

		private static readonly FieldInfo? PlayerTakingFallDamageField = FindInstanceField(typeof(PlayerControllerB), "takingFallDamage");

		private static readonly FieldInfo? PlayerFallingFromJumpField = FindInstanceField(typeof(PlayerControllerB), "isFallingFromJump");

		private static readonly FieldInfo? PlayerAverageVelocityField = FindInstanceField(typeof(PlayerControllerB), "averageVelocity");

		private static readonly FieldInfo? PlayerPreviousYField = FindInstanceField(typeof(PlayerControllerB), "previousYPosition");

		private static readonly FieldInfo? PlayerExternalForcesField = FindInstanceField(typeof(PlayerControllerB), "externalForces");

		private static readonly FieldInfo? PlayerIsInElevatorField = FindInstanceField(typeof(PlayerControllerB), "isInElevator");

		private static readonly FieldInfo? PlayerIsInHangarField = FindInstanceField(typeof(PlayerControllerB), "isInHangarShipRoom");

		private static readonly FieldInfo? PlayerIsInsideFactoryField = FindInstanceField(typeof(PlayerControllerB), "isInsideFactory");

		private static readonly FieldInfo? PlayerVelocityLastFrameField = FindInstanceField(typeof(PlayerControllerB), "velocityLastFrame");

		private static readonly FieldInfo? PlayerIsSlidingField = FindInstanceField(typeof(PlayerControllerB), "isPlayerSliding");

		private static readonly FieldInfo? PlayerSlidingTimerField = FindInstanceField(typeof(PlayerControllerB), "playerSlidingTimer");

		private static readonly FieldInfo? PlayerIsFallingNoJumpField = FindInstanceField(typeof(PlayerControllerB), "isFallingNoJump");

		private static readonly FieldInfo? PlayerTeleportedLastFrameField = FindInstanceField(typeof(PlayerControllerB), "teleportedLastFrame");

		private static readonly FieldInfo? PlayerWasInElevatorLastFrameField = FindInstanceField(typeof(PlayerControllerB), "wasInElevatorLastFrame");

		private static readonly FieldInfo? PlayerPreviousElevatorPositionField = FindInstanceField(typeof(PlayerControllerB), "previousElevatorPosition");

		private static readonly FieldInfo? PlayerOldPositionField = FindInstanceField(typeof(PlayerControllerB), "oldPlayerPosition");

		private static readonly FieldInfo? PlayerServerPositionField = FindInstanceField(typeof(PlayerControllerB), "serverPlayerPosition");

		private static readonly FieldInfo? PlayerSnapToServerPositionField = FindInstanceField(typeof(PlayerControllerB), "snapToServerPosition");

		private static readonly FieldInfo? PlayerUpdatePositionForNewClientField = FindInstanceField(typeof(PlayerControllerB), "updatePositionForNewlyJoinedClient");

		private static readonly HashSet<ulong> ShipSnapshotAcknowledgements = new HashSet<ulong>();

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

		private static NetworkManager? _registeredNetwork;

		private static WorldSnapshot? _latestClientSnapshot;

		private static Coroutine? _applySnapshotCoroutine;

		internal static void RegisterHandler()
		{
			//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_004c: Expected O, but got Unknown
			//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_0077: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			if (!((Object)(object)singleton == (Object)null) && singleton.CustomMessagingManager != null && _registeredNetwork != singleton)
			{
				UnregisterHandler();
				CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
				object obj = <>O.<0>__ReceiveSnapshot;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = ReceiveSnapshot;
					<>O.<0>__ReceiveSnapshot = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("LobbyControlMidSessionJoin.WorldState.v3", (HandleNamedMessageDelegate)obj);
				CustomMessagingManager customMessagingManager2 = singleton.CustomMessagingManager;
				object obj2 = <>O.<1>__ReceiveSnapshotAcknowledgement;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val2 = ReceiveSnapshotAcknowledgement;
					<>O.<1>__ReceiveSnapshotAcknowledgement = val2;
					obj2 = (object)val2;
				}
				customMessagingManager2.RegisterNamedMessageHandler("LobbyControlMidSessionJoin.WorldStateAck.v1", (HandleNamedMessageDelegate)obj2);
				singleton.OnClientDisconnectCallback += HandleClientDisconnected;
				_registeredNetwork = singleton;
				Plugin.Debug("Registered targeted world-state synchronization handler.");
			}
		}

		internal static void UnregisterHandler()
		{
			NetworkManager registeredNetwork = _registeredNetwork;
			_registeredNetwork = null;
			_latestClientSnapshot = null;
			ShipSnapshotAcknowledgements.Clear();
			DeferredTerminalInitializations.Clear();
			if ((Object)(object)registeredNetwork != (Object)null && _applySnapshotCoroutine != null)
			{
				((MonoBehaviour)registeredNetwork).StopCoroutine(_applySnapshotCoroutine);
				_applySnapshotCoroutine = null;
			}
			if ((Object)(object)registeredNetwork == (Object)null)
			{
				return;
			}
			registeredNetwork.OnClientDisconnectCallback -= HandleClientDisconnected;
			if (registeredNetwork.CustomMessagingManager == null)
			{
				return;
			}
			try
			{
				registeredNetwork.CustomMessagingManager.UnregisterNamedMessageHandler("LobbyControlMidSessionJoin.WorldState.v3");
				registeredNetwork.CustomMessagingManager.UnregisterNamedMessageHandler("LobbyControlMidSessionJoin.WorldStateAck.v1");
			}
			catch (Exception ex)
			{
				Plugin.Debug("Could not unregister world-state handler: " + ex.Message);
			}
		}

		private static void HandleClientDisconnected(ulong clientId)
		{
			NetworkSync.HandleClientDisconnected(clientId);
			ShipSnapshotAcknowledgements.Remove(clientId);
			NetworkManager registeredNetwork = _registeredNetwork;
			if (!((Object)(object)registeredNetwork == (Object)null) && clientId == registeredNetwork.LocalClientId)
			{
				UnregisterHandler();
				MidJoinState.ResetClientState();
			}
		}

		internal static void ResetSnapshotAcknowledgement(ulong clientId)
		{
			ShipSnapshotAcknowledgements.Remove(clientId);
		}

		internal static bool HasSnapshotAcknowledgement(ulong clientId)
		{
			return ShipSnapshotAcknowledgements.Contains(clientId);
		}

		internal static void ClearSnapshotAcknowledgement(ulong clientId)
		{
			ShipSnapshotAcknowledgements.Remove(clientId);
		}

		internal static void SendSnapshot(ulong clientId, bool includeInterior)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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)
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsServer || singleton.CustomMessagingManager == null)
			{
				throw new InvalidOperationException("The server custom messaging manager is not ready.");
			}
			RegisterHandler();
			WorldSnapshot worldSnapshot = CaptureSnapshot(includeInterior);
			int num = 32768 + worldSnapshot.Doors.Count * 80 + worldSnapshot.TerminalDoors.Count * 64;
			FastBufferWriter writer = default(FastBufferWriter);
			((FastBufferWriter)(ref writer))..ctor(num, (Allocator)2, -1);
			try
			{
				WriteSnapshot(ref writer, worldSnapshot);
				NetworkDelivery val = (NetworkDelivery)((((FastBufferWriter)(ref writer)).Capacity > 1300) ? 4 : 2);
				singleton.CustomMessagingManager.SendNamedMessage("LobbyControlMidSessionJoin.WorldState.v3", clientId, writer, val);
			}
			finally
			{
				((FastBufferWriter)(ref writer)).Dispose();
			}
			Plugin.Debug(string.Format("Sent {0} world snapshot to client {1}: ", includeInterior ? "complete" : "ship-only", clientId) + $"doors={worldSnapshot.Doors.Count}, terminalDoors={worldSnapshot.TerminalDoors.Count}, " + $"power={worldSnapshot.PowerOn}, permanentPowerLoss={worldSnapshot.PowerOffPermanently}, " + $"weather={(object)(LevelWeatherType)worldSnapshot.CurrentWeather}, landed={worldSnapshot.ShipHasLanded}");
		}

		private static WorldSnapshot CaptureSnapshot(bool includeInterior)
		{
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected I4, but got Unknown
			StartOfRound val = StartOfRound.Instance ?? throw new InvalidOperationException("StartOfRound is not ready.");
			RoundManager instance = RoundManager.Instance;
			BreakerBox val2 = Object.FindObjectOfType<BreakerBox>();
			bool flag = false;
			LungProp[] array = Object.FindObjectsOfType<LungProp>();
			for (int i = 0; i < array.Length; i++)
			{
				if (!array[i].isLungDocked)
				{
					flag = true;
					break;
				}
			}
			bool flag2 = (Object)(object)instance != (Object)null && (instance.powerOffPermanently || flag);
			WorldSnapshot worldSnapshot = new WorldSnapshot
			{
				IncludeInterior = includeInterior,
				SpawnInShip = Plugin.SpawnInShip.Value,
				InShipPhase = val.inShipPhase,
				ShipHasLanded = val.shipHasLanded,
				ShipIsLeaving = val.shipIsLeaving,
				ShipDoorsEnabled = val.shipDoorsEnabled,
				HangarDoorsClosed = val.hangarDoorsClosed,
				NewGameIsLoading = val.newGameIsLoading,
				TravellingToNewLevel = val.travellingToNewLevel,
				ShipAmbiancePlaying = ((Object)(object)val.shipAmbianceAudio != (Object)null && val.shipAmbianceAudio.isPlaying),
				ShipTravelAudioPlaying = ((Object)(object)val.ship3DAudio != (Object)null && val.ship3DAudio.isPlaying),
				PowerOffPermanently = flag2,
				PowerOn = ((Object)(object)instance != (Object)null && !flag2 && ((Object)(object)val2 == (Object)null || val2.isPowerOn)),
				CurrentWeather = (int)val.currentLevel.currentWeather,
				ShipTransform = CaptureTransform(((Object)(object)val.shipAnimatorObject != (Object)null) ? ((Component)val.shipAnimatorObject).transform : val.elevatorTransform),
				CurrentPlanetTransform = CaptureTransform(((Object)(object)val.currentPlanetPrefab != (Object)null) ? val.currentPlanetPrefab.transform : null),
				CurrentPlanetActive = ((Object)(object)val.currentPlanetPrefab != (Object)null && val.currentPlanetPrefab.activeSelf),
				OuterSpaceSunActive = ((Object)(object)val.outerSpaceSunAnimator != (Object)null && ((Component)val.outerSpaceSunAnimator).gameObject.activeSelf),
				StarSphereActive = ((Object)(object)val.starSphereObject != (Object)null && val.starSphereObject.activeSelf),
				ShipAnimator = CaptureAnimator(val.shipAnimator),
				ShipBodyAnimator = CaptureAnimator(((Object)(object)val.shipAnimatorObject != (Object)null) ? ((Component)val.shipAnimatorObject).GetComponent<Animator>() : null),
				ShipDoorsAnimator = CaptureAnimator(val.shipDoorsAnimator),
				CurrentPlanetAnimator = CaptureAnimator(val.currentPlanetAnimator),
				OuterSpaceSunAnimator = CaptureAnimator(val.outerSpaceSunAnimator)
			};
			if (!includeInterior)
			{
				return worldSnapshot;
			}
			DoorLock[] array2 = Object.FindObjectsOfType<DoorLock>();
			foreach (DoorLock door in array2)
			{
				worldSnapshot.Doors.Add(CaptureDoor(door));
			}
			TerminalAccessibleObject[] array3 = Object.FindObjectsOfType<TerminalAccessibleObject>();
			foreach (TerminalAccessibleObject val3 in array3)
			{
				if (val3.isBigDoor)
				{
					worldSnapshot.TerminalDoors.Add(CaptureTerminalDoor(val3));
				}
			}
			return worldSnapshot;
		}

		private static DoorSnapshot CaptureDoor(DoorLock door)
		{
			//IL_0038: 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)
			AnimatedObjectTrigger component = ((Component)door).GetComponent<AnimatedObjectTrigger>();
			InteractTrigger component2 = ((Component)door).GetComponent<InteractTrigger>();
			bool isOpen = (((Object)(object)component != (Object)null) ? component.boolValue : ReadField(DoorIsOpenedField, door, fallback: false));
			return new DoorSnapshot
			{
				Position = ((Component)door).transform.position,
				IsOpen = isOpen,
				IsLocked = door.isLocked,
				IsPickingLock = door.isPickingLock,
				LockPickTimeLeft = door.lockPickTimeLeft,
				TriggerInteractable = ((Object)(object)component2 == (Object)null || component2.interactable),
				TriggerTimeToHold = (component2?.timeToHold ?? 0.3f),
				TriggerSpeedMultiplier = (component2?.timeToHoldSpeedMultiplier ?? 1f)
			};
		}

		private static TerminalDoorSnapshot CaptureTerminalDoor(TerminalAccessibleObject door)
		{
			//IL_0013: 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)
			AnimatedObjectTrigger component = ((Component)door).GetComponent<AnimatedObjectTrigger>();
			return new TerminalDoorSnapshot
			{
				Position = ((Component)door).transform.position,
				IsOpen = ReadField(TerminalDoorOpenField, door, (Object)(object)component != (Object)null && component.boolValue),
				IsPoweredOn = ReadField(TerminalPoweredField, door, fallback: true)
			};
		}

		private static TransformSnapshot CaptureTransform(Transform? transform)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)transform == (Object)null)
			{
				return new TransformSnapshot();
			}
			return new TransformSnapshot
			{
				Exists = true,
				LocalPosition = transform.localPosition,
				LocalRotation = transform.localRotation,
				LocalScale = transform.localScale
			};
		}

		private static AnimatorSnapshot CaptureAnimator(Animator? animator)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Invalid comparison between Unknown and I4
			//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_006f: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected I4, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			AnimatorSnapshot animatorSnapshot = new AnimatorSnapshot();
			if ((Object)(object)animator == (Object)null)
			{
				return animatorSnapshot;
			}
			animatorSnapshot.Exists = true;
			animatorSnapshot.Enabled = ((Behaviour)animator).enabled;
			animatorSnapshot.Speed = animator.speed;
			AnimatorControllerParameter[] parameters = animator.parameters;
			foreach (AnimatorControllerParameter val in parameters)
			{
				if ((int)val.type != 9)
				{
					AnimatorParameterSnapshot animatorParameterSnapshot = new AnimatorParameterSnapshot
					{
						NameHash = val.nameHash,
						Type = val.type
					};
					AnimatorControllerParameterType type = val.type;
					switch (type - 1)
					{
					case 3:
						animatorParameterSnapshot.BoolValue = animator.GetBool(val.nameHash);
						break;
					case 2:
						animatorParameterSnapshot.IntValue = animator.GetInteger(val.nameHash);
						break;
					case 0:
						animatorParameterSnapshot.FloatValue = animator.GetFloat(val.nameHash);
						break;
					}
					animatorSnapshot.Parameters.Add(animatorParameterSnapshot);
				}
			}
			for (int j = 0; j < animator.layerCount; j++)
			{
				AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(j);
				animatorSnapshot.Layers.Add(new AnimatorLayerSnapshot
				{
					StateHash = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash,
					NormalizedTime = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime,
					Weight = animator.GetLayerWeight(j)
				});
			}
			return animatorSnapshot;
		}

		private static void ReceiveSnapshot(ulong senderClientId, FastBufferReader reader)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || senderClientId != 0L)
			{
				return;
			}
			try
			{
				WorldSnapshot snapshot = (_latestClientSnapshot = ReadSnapshot(ref reader));
				if (!MidJoinState.ClientLateJoinSyncCompleted)
				{
					MidJoinState.ClientLateJoinSyncActive = true;
				}
				if (_applySnapshotCoroutine != null)
				{
					((MonoBehaviour)singleton).StopCoroutine(_applySnapshotCoroutine);
				}
				_applySnapshotCoroutine = ((MonoBehaviour)singleton).StartCoroutine(ApplySnapshot(snapshot));
				SendSnapshotAcknowledgement();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to receive late-join world snapshot: " + ex));
			}
		}

		private static void SendSnapshotAcknowledgement()
		{
			//IL_003a: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsClient || singleton.IsServer || singleton.CustomMessagingManager == null)
			{
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
			try
			{
				int num = 3;
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				singleton.CustomMessagingManager.SendNamedMessage("LobbyControlMidSessionJoin.WorldStateAck.v1", 0uL, val, (NetworkDelivery)2);
			}
			finally
			{
				((FastBufferWriter)(ref val)).Dispose();
			}
		}

		private static void ReceiveSnapshotAcknowledgement(ulong senderClientId, FastBufferReader reader)
		{
			//IL_0022: 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)
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsServer || senderClientId == 0L)
			{
				return;
			}
			try
			{
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				if (num == 3)
				{
					ShipSnapshotAcknowledgements.Add(senderClientId);
					Plugin.Debug($"Client {senderClientId} acknowledged the landed ship snapshot.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Debug($"Could not read landed ship snapshot acknowledgement from client {senderClientId}: " + ex.Message);
			}
		}

		private static IEnumerator ApplySnapshot(WorldSnapshot snapshot)
		{
			float deadline = Time.realtimeSinceStartup + 15f;
			while ((Object)(object)StartOfRound.Instance == (Object)null)
			{
				if (Time.realtimeSinceStartup >= deadline)
				{
					yield break;
				}
				yield return null;
			}
			ApplyWeatherState(snapshot);
			ApplyShipState(snapshot, !MidJoinState.ClientPlayerPositioned, ShouldHoldShipAnimations());
			yield return null;
			ApplyShipState(snapshot, moveLocalPlayer: false, ShouldHoldShipAnimations());
			if (snapshot.IncludeInterior)
			{
				while (((Object)(object)RoundManager.Instance == (Object)null || !RoundManager.Instance.dungeonCompletedGenerating) && Time.realtimeSinceStartup < deadline)
				{
					yield return null;
				}
				yield return null;
				yield return null;
				ApplyInteriorState(snapshot);
			}
			yield return (object)new WaitForSeconds(0.25f);
			ApplyShipState(snapshot, moveLocalPlayer: false, ShouldHoldShipAnimations());
			if (snapshot.IncludeInterior)
			{
				ApplyInteriorState(snapshot);
				yield return StabilizePowerState(snapshot);
				yield return StabilizeWeatherState(snapshot);
				MidJoinState.ClientLateJoinSyncCompleted = true;
				MidJoinState.ClientLateJoinSyncActive = false;
				ApplyShipState(snapshot, moveLocalPlayer: false, holdAnimations: false);
			}
			MidJoinState.LastStatus = (snapshot.IncludeInterior ? "Applied ship, weather, door, lock, and facility-power snapshot." : "Applied landed ship snapshot.");
			Plugin.Debug(MidJoinState.LastStatus);
			_applySnapshotCoroutine = null;
		}

		private static void ApplyWeatherState(WorldSnapshot snapshot)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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)
			StartOfRound instance = StartOfRound.Instance;
			TimeOfDay instance2 = TimeOfDay.Instance;
			if (!((Object)(object)instance?.currentLevel == (Object)null) && !((Object)(object)instance2 == (Object)null))
			{
				LevelWeatherType val = (LevelWeatherType)snapshot.CurrentWeather;
				instance.currentLevel.currentWeather = val;
				instance2.currentLevelWeather = val;
				try
				{
					SetWeatherEffectsMethod?.Invoke(instance2, null);
				}
				catch (Exception ex)
				{
					Plugin.Debug("Could not invoke TimeOfDay.SetWeatherEffects: " + ex.Message);
				}
				ForceWeatherEffectObjects(instance2, val);
				Plugin.Debug($"Applied authoritative late-join weather state: {val}.");
			}
		}

		private static void ForceWeatherEffectObjects(TimeOfDay timeOfDay, LevelWeatherType weather)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected I4, but got Unknown
			WeatherEffect[] effects = timeOfDay.effects;
			if (effects == null)
			{
				return;
			}
			int num = (int)weather;
			for (int i = 0; i < effects.Length; i++)
			{
				WeatherEffect val = effects[i];
				if (val != null)
				{
					bool flag = (val.effectEnabled = i == num);
					val.transitioning = false;
					if ((Object)(object)val.effectObject != (Object)null && val.effectObject.activeSelf != flag)
					{
						val.effectObject.SetActive(flag);
					}
					if ((Object)(object)val.effectPermanentObject != (Object)null && val.effectPermanentObject.activeSelf != flag)
					{
						val.effectPermanentObject.SetActive(flag);
					}
				}
			}
		}

		private static IEnumerator StabilizeWeatherState(WorldSnapshot snapshot)
		{
			float deadline = Time.realtimeSinceStartup + 2f;
			while (Time.realtimeSinceStartup < deadline && !((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsClient)
			{
				ApplyWeatherState(snapshot);
				yield return (object)new WaitForSecondsRealtime(0.2f);
			}
		}

		private static bool ShouldHoldShipAnimations()
		{
			if (MidJoinState.ClientLateJoinSyncActive)
			{
				return !MidJoinState.ClientLateJoinSyncCompleted;
			}
			return false;
		}

		private static void ApplyShipState(WorldSnapshot snapshot, bool moveLocalPlayer, bool holdAnimations)
		{
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				StopShipTravelCoroutine(instance);
				instance.inShipPhase = snapshot.InShipPhase;
				instance.shipHasLanded = snapshot.ShipHasLanded;
				instance.shipIsLeaving = snapshot.ShipIsLeaving;
				instance.shipDoorsEnabled = snapshot.ShipDoorsEnabled;
				instance.hangarDoorsClosed = snapshot.HangarDoorsClosed;
				instance.newGameIsLoading = snapshot.NewGameIsLoading;
				instance.travellingToNewLevel = snapshot.TravellingToNewLevel;
				ApplyAnimator(instance.shipAnimator, snapshot.ShipAnimator, holdAnimations);
				ApplyAnimator(((Object)(object)instance.shipAnimatorObject != (Object)null) ? ((Component)instance.shipAnimatorObject).GetComponent<Animator>() : null, snapshot.ShipBodyAnimator, holdAnimations);
				ApplyAnimator(instance.shipDoorsAnimator, snapshot.ShipDoorsAnimator, holdAnimations);
				ApplyAnimator(instance.currentPlanetAnimator, snapshot.CurrentPlanetAnimator, holdAnimations);
				ApplyAnimator(instance.outerSpaceSunAnimator, snapshot.OuterSpaceSunAnimator, holdAnimations);
				ApplyTransform(((Object)(object)instance.shipAnimatorObject != (Object)null) ? ((Component)instance.shipAnimatorObject).transform : instance.elevatorTransform, snapshot.ShipTransform);
				ApplyTransform(((Object)(object)instance.currentPlanetPrefab != (Object)null) ? instance.currentPlanetPrefab.transform : null, snapshot.CurrentPlanetTransform);
				if ((Object)(object)instance.currentPlanetPrefab != (Object)null)
				{
					instance.currentPlanetPrefab.SetActive(snapshot.CurrentPlanetActive);
				}
				if ((Object)(object)instance.outerSpaceSunAnimator != (Object)null)
				{
					((Component)instance.outerSpaceSunAnimator).gameObject.SetActive(snapshot.OuterSpaceSunActive);
				}
				if ((Object)(object)instance.starSphereObject != (Object)null)
				{
					instance.starSphereObject.SetActive(snapshot.StarSphereActive);
				}
				SynchronizeAudio(instance.shipAmbianceAudio, snapshot.ShipAmbiancePlaying);
				SynchronizeAudio(instance.ship3DAudio, snapshot.ShipTravelAudioPlaying);
				PlayerControllerB val = instance.localPlayerController ?? GameNetworkManager.Instance?.localPlayerController;
				if (!((Object)(object)val == (Object)null) && !val.isPlayerDead && snapshot.SpawnInShip && moveLocalPlayer && MoveLocalPlayerIntoShip(instance, val))
				{
					MidJoinState.ClientPlayerPositioned = true;
					ResetPlayerMotion(instance, val);
					Plugin.Debug($"Positioned the local late-join player at {((Component)val).transform.position} and cleared stale motion state.");
				}
			}
		}

		internal static IEnumerator RunLateJoinLandedSequence(StartOfRound round)
		{
			float deadline = Time.realtimeSinceStartup + 15f + 60f;
			WorldSnapshot latestClientSnapshot = _latestClientSnapshot;
			if (latestClientSnapshot != null)
			{
				ApplyShipState(latestClientSnapshot, !MidJoinState.ClientPlayerPositioned, holdAnimations: true);
			}
			ApplyImmediateLandedState(round, resetPlayerMotion: true);
			RestoreShipRadarMonitor(round);
			while (MidJoinState.ClientLateJoinSyncActive && Time.realtimeSinceStartup < deadline && (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer)
			{
				yield return null;
			}
			WorldSnapshot latestClientSnapshot2 = _latestClientSnapshot;
			if (latestClientSnapshot2 != null)
			{
				ApplyShipState(latestClientSnapshot2, moveLocalPlayer: false, holdAnimations: false);
			}
			ApplyImmediateLandedState(round, resetPlayerMotion: true);
			yield return null;
			RestoreShipRadarMonitor(round);
		}

		private static void RestoreShipRadarMonitor(StartOfRound round)
		{
			try
			{
				ManualCameraRenderer mapScreen = round.mapScreen;
				DisableLevelInformationOverlay(round, mapScreen);
				if ((Object)(object)mapScreen == (Object)null || (Object)(object)mapScreen.mapCamera == (Object)null)
				{
					return;
				}
				Coroutine val = ReadField<Coroutine>(MapScreenUpdateCoroutineField, mapScreen, null);
				if (val != null)
				{
					((MonoBehaviour)mapScreen).StopCoroutine(val);
				}
				mapScreen.overrideCameraForOtherUse = false;
				mapScreen.currentCameraDisabled = false;
				mapScreen.cam = mapScreen.mapCamera;
				SetField(MapScreenIsScreenOnField, mapScreen, true);
				SetField(MapScreenEnabledOnLocalClientField, mapScreen, true);
				SetField(MapScreenUpdateCoroutineField, mapScreen, null);
				SetField(MapScreenSyncingTargetField, mapScreen, false);
				SetField(MapScreenSyncingSwitchField, mapScreen, false);
				mapScreen.SwitchScreenOn(true);
				if (mapScreen.radarTargets == null || mapScreen.radarTargets.Count == 0)
				{
					RebuildRadarTargets(round, mapScreen);
				}
				if (mapScreen.radarTargets != null && mapScreen.radarTargets.Count > 0)
				{
					int num = (mapScreen.targetTransformIndex = FindUsableRadarTarget(mapScreen));
					TransformAndName val2 = mapScreen.radarTargets[num];
					mapScreen.targetedPlayer = (((Object)(object)val2.transform != (Object)null) ? ((Component)val2.transform).GetComponent<PlayerControllerB>() : null);
					if ((Object)(object)round.mapScreenPlayerName != (Object)null)
					{
						((TMP_Text)round.mapScreenPlayerName).text = "MONITORING: " + val2.name;
					}
					mapScreen.SwitchRadarTargetAndSync(num);
				}
				((Behaviour)mapScreen.mapCamera).enabled = true;
				Plugin.Debug($"Restored landed radar renderer: targets={mapScreen.radarTargets?.Count ?? 0}, " + $"target={mapScreen.targetTransformIndex}, camera={((Object)mapScreen.cam).name}.");
			}
			catch (Exception ex)
			{
				Plugin.Debug("Could not restore the landed ship radar monitor: " + ex);
			}
		}

		private static void DisableLevelInformationOverlay(StartOfRound round, ManualCameraRenderer? mapScreen)
		{
			if ((Object)(object)round.screenLevelDescription != (Object)null)
			{
				((Behaviour)round.screenLevelDescription).enabled = false;
				((Component)round.screenLevelDescription).gameObject.SetActive(false);
			}
			if ((Object)(object)round.screenLevelVideoReel != (Object)null)
			{
				VideoPlayer screenLevelVideoReel = round.screenLevelVideoReel;
				screenLevelVideoReel.Stop();
				((Behaviour)screenLevelVideoReel).enabled = false;
				if ((Object)(object)((Component)screenLevelVideoReel).gameObject != (Object)null && ((Object)(object)mapScreen == (Object)null || (Object)(object)((Component)screenLevelVideoReel).gameObject != (Object)(object)((Component)mapScreen).gameObject))
				{
					((Component)screenLevelVideoReel).gameObject.SetActive(false);
				}
				else
				{
					DisableVideoOverlayRenderers(screenLevelVideoReel, mapScreen);
				}
			}
			if ((Object)(object)round.radarCanvas != (Object)null)
			{
				((Component)round.radarCanvas).gameObject.SetActive(true);
				((Behaviour)round.radarCanvas).enabled = true;
			}
			if ((Object)(object)round.mapScreenPlayerName != (Object)null)
			{
				((Component)round.mapScreenPlayerName).gameObject.SetActive(true);
				((Behaviour)round.mapScreenPlayerName).enabled = true;
			}
			if ((Object)(object)mapScreen != (Object)null && (Object)(object)mapScreen.mapCameraStationaryUI != (Object)null)
			{
				((Component)mapScreen.mapCameraStationaryUI).gameObject.SetActive(true);
			}
		}

		internal static void RestoreLevelInformationOverlayForOrbit(StartOfRound round)
		{
			if ((Object)(object)round == (Object)null || !round.inShipPhase)
			{
				return;
			}
			if ((Object)(object)round.screenLevelDescription != (Object)null)
			{
				((Component)round.screenLevelDescription).gameObject.SetActive(true);
			}
			if ((Object)(object)round.screenLevelVideoReel != (Object)null)
			{
				VideoPlayer screenLevelVideoReel = round.screenLevelVideoReel;
				if ((Object)(object)((Component)screenLevelVideoReel).gameObject != (Object)null)
				{
					((Component)screenLevelVideoReel).gameObject.SetActive(true);
				}
				Renderer[] componentsInChildren = ((Component)screenLevelVideoReel).GetComponentsInChildren<Renderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].enabled = true;
				}
				Renderer targetMaterialRenderer = screenLevelVideoReel.targetMaterialRenderer;
				if ((Object)(object)targetMaterialRenderer != (Object)null)
				{
					targetMaterialRenderer.enabled = true;
				}
				((Behaviour)screenLevelVideoReel).enabled = true;
			}
		}

		private static void DisableVideoOverlayRenderers(VideoPlayer videoPlayer, ManualCameraRenderer? mapScreen)
		{
			Renderer val = (Renderer)(object)mapScreen?.mesh;
			Renderer targetMaterialRenderer = videoPlayer.targetMaterialRenderer;
			if ((Object)(object)targetMaterialRenderer != (Object)null && (Object)(object)targetMaterialRenderer != (Object)(object)val)
			{
				targetMaterialRenderer.enabled = false;
			}
			Renderer[] componentsInChildren = ((Component)videoPlayer).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if ((Object)(object)val2 != (Object)(object)val)
				{
					val2.enabled = false;
				}
			}
		}

		private static void RebuildRadarTargets(StartOfRound round, ManualCameraRenderer mapScreen)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			if (mapScreen.radarTargets == null)
			{
				mapScreen.radarTargets = new List<TransformAndName>();
			}
			mapScreen.radarTargets.Clear();
			PlayerControllerB[] allPlayerScripts = round.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null))
				{
					mapScreen.radarTargets.Add(new TransformAndName(((Component)val).transform, val.playerUsername, false));
				}
			}
		}

		private static int FindUsableRadarTarget(ManualCameraRenderer mapScreen)
		{
			int count = mapScreen.radarTargets.Count;
			int num = Mathf.Clamp(mapScreen.targetTransformIndex, 0, count - 1);
			for (int i = 0; i < count; i++)
			{
				int num2 = (num + i) % count;
				TransformAndName val = mapScreen.radarTargets[num2];
				if (val != null && (Object)(object)val.transform != (Object)null)
				{
					return num2;
				}
			}
			return 0;
		}

		private static void ApplyImmediateLandedState(StartOfRound round, bool resetPlayerMotion)
		{
			StopShipTravelCoroutine(round);
			round.inShipPhase = false;
			round.shipHasLanded = true;
			round.shipIsLeaving = false;
			round.newGameIsLoading = false;
			round.travellingToNewLevel = false;
			if ((Object)(object)GameNetworkManager.Instance != (Object)null)
			{
				GameNetworkManager.Instance.gameHasStarted = true;
			}
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HideLoadingScreen(HUDManager.Instance);
			}
			StartMatchLever val = Object.FindObjectOfType<StartMatchLever>();
			if ((Object)(object)val != (Object)null && (Object)(object)val.triggerScript != (Object)null)
			{
				val.triggerScript.timeToHold = 0.7f;
				val.triggerScript.animationString = "SA_PushLeverBack";
				val.triggerScript.disabledHoverTip = string.Empty;
				val.triggerScript.interactable = true;
				val.hasDisplayedTimeWarning = false;
			}
			HangarShipDoor val2 = Object.FindObjectOfType<HangarShipDoor>();
			if ((Object)(object)val2 != (Object)null)
			{
				val2.SetDoorButtonsEnabled(round.shipDoorsEnabled);
			}
			if ((Object)(object)round.currentLevel != (Object)null && round.currentLevel.planetHasTime && (Object)(object)TimeOfDay.Instance != (Object)null)
			{
				TimeOfDay.Instance.currentDayTimeStarted = true;
				TimeOfDay.Instance.movingGlobalTimeForward = true;
			}
			if (resetPlayerMotion)
			{
				PlayerControllerB val3 = round.localPlayerController ?? GameNetworkManager.Instance?.localPlayerController;
				if ((Object)(object)val3 != (Object)null && !val3.isPlayerDead)
				{
					ResetPlayerMotion(round, val3);
				}
			}
		}

		private static void HideLoadingScreen(HUDManager hud)
		{
			if ((Object)(object)hud.loadingText != (Object)null)
			{
				((Behaviour)hud.loadingText).enabled = false;
			}
			object? obj = LoadingScreenAnimatorField?.GetValue(hud);
			Animator val = (Animator)((obj is Animator) ? obj : null);
			if (val != null)
			{
				val.SetBool("IsLoading", false);
			}
			object? obj2 = LegacyLoadingDarkenScreenField?.GetValue(hud);
			Behaviour val2 = (Behaviour)((obj2 is Behaviour) ? obj2 : null);
			if (val2 != null)
			{
				val2.enabled = false;
			}
		}

		private static void ApplyInteriorState(WorldSnapshot snapshot)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			RoundManager instance = RoundManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			ApplyPowerState(instance, snapshot.PowerOn, snapshot.PowerOffPermanently);
			DoorLock[] candidates = Object.FindObjectsOfType<DoorLock>();
			HashSet<int> hashSet = new HashSet<int>();
			int num = 0;
			foreach (DoorSnapshot door in snapshot.Doors)
			{
				DoorLock val = FindClosest<DoorLock>(candidates, hashSet, door.Position, (Func<DoorLock, bool>?)null);
				if (!((Object)(object)val == (Object)null))
				{
					ApplyDoor(val, door);
					hashSet.Add(((Object)val).GetInstanceID());
					num++;
				}
			}
			TerminalAccessibleObject[] candidates2 = Object.FindObjectsOfType<TerminalAccessibleObject>();
			HashSet<int> hashSet2 = new HashSet<int>();
			int num2 = 0;
			foreach (TerminalDoorSnapshot terminalDoor in snapshot.TerminalDoors)
			{
				TerminalAccessibleObject val2 = FindClosest<TerminalAccessibleObject>(candidates2, hashSet2, terminalDoor.Position, (Func<TerminalAccessibleObject, bool>?)((TerminalAccessibleObject x) => x.isBigDoor));
				if (!((Object)(object)val2 == (Object)null))
				{
					ApplyTerminalDoor(val2, terminalDoor);
					hashSet2.Add(((Object)val2).GetInstanceID());
					num2++;
				}
			}
			Plugin.Debug($"Applied interior snapshot: regularDoors={num}/{snapshot.Doors.Count}, " + $"terminalDoors={num2}/{snapshot.TerminalDoors.Count}, power={snapshot.PowerOn}");
		}

		private static IEnumerator StabilizePowerState(WorldSnapshot snapshot)
		{
			float deadline = Time.realtimeSinceStartup + (snapshot.PowerOffPermanently ? 3f : 0.75f);
			while (Time.realtimeSinceStartup < deadline)
			{
				RoundManager instance = RoundManager.Instance;
				if ((Object)(object)instance == (Object)null || (Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsClient)
				{
					break;
				}
				ApplyPowerState(instance, snapshot.PowerOn, snapshot.PowerOffPermanently);
				yield return (object)new WaitForSecondsRealtime(0.1f);
			}
		}

		internal static bool ShouldBlockFacilityPowerOn(RoundManager manager, bool powerOn)
		{
			if (!powerOn || (Object)(object)manager == (Object)null || !manager.powerOffPermanently)
			{
				return false;
			}
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)null && singleton.IsClient)
			{
				return !singleton.IsServer;
			}
			return false;
		}

		private static void ApplyPowerState(RoundManager manager, bool powerOn, bool permanentlyOff)
		{
			if (permanentlyOff)
			{
				powerOn = false;
			}
			StopRoundCoroutine(manager, RoundFlickerLightsCoroutineField);
			StopRoundCoroutine(manager, RoundPowerLightsCoroutineField);
			manager.powerOffPermanently = permanentlyOff;
			BreakerBox val = Object.FindObjectOfType<BreakerBox>();
			if ((Object)(object)val != (Object)null)
			{
				val.isPowerOn = powerOn;
			}
			LungProp[] array = Object.FindObjectsOfType<LungProp>();
			foreach (LungProp val2 in array)
			{
				if (permanentlyOff)
				{
					val2.isLungDocked = false;
				}
			}
			((UnityEvent<bool>)(object)manager.onPowerSwitch).Invoke(powerOn);
			manager.TurnOnAllLights(powerOn);
		}

		private static void StopRoundCoroutine(RoundManager manager, FieldInfo? field)
		{
			object? obj = field?.GetValue(manager);
			Coroutine val = (Coroutine)((obj is Coroutine) ? obj : null);
			if (val != null)
			{
				((MonoBehaviour)manager).StopCoroutine(val);
				field.SetValue(manager, null);
			}
		}

		private static void ApplyDoor(DoorLock door, DoorSnapshot snapshot)
		{
			door.isLocked = snapshot.IsLocked;
			door.isPickingLock = snapshot.IsPickingLock;
			door.lockPickTimeLeft = snapshot.LockPickTimeLeft;
			SetAnimatedBoolean(((Component)door).GetComponent<AnimatedObjectTrigger>(), snapshot.IsOpen);
			door.SetDoorAsOpen(snapshot.IsOpen);
			SetField(DoorIsOpenedField, door, snapshot.IsOpen);
			InteractTrigger component = ((Component)door).GetComponent<InteractTrigger>();
			if ((Object)(object)component != (Object)null)
			{
				component.interactable = snapshot.TriggerInteractable;
				component.timeToHold = snapshot.TriggerTimeToHold;
				component.timeToHoldSpeedMultiplier = snapshot.TriggerSpeedMultiplier;
				component.hoverTip = (snapshot.IsLocked ? "Locked (pickable)" : "Use door : [LMB]");
				component.holdTip = (snapshot.IsLocked ? "Picking lock" : string.Empty);
			}
			NavMeshObstacle component2 = ((Component)door).GetComponent<NavMeshObstacle>();
			if ((Object)(object)component2 != (Object)null)
			{
				((Behaviour)component2).enabled = !snapshot.IsOpen;
				component2.carving = snapshot.IsLocked && !snapshot.IsOpen;
				component2.carveOnlyStationary = true;
			}
		}

		private static void ApplyTerminalDoor(TerminalAccessibleObject door, TerminalDoorSnapshot snapshot)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			SetField(TerminalDoorOpenField, door, snapshot.IsOpen);
			SetField(TerminalPoweredField, door, snapshot.IsPoweredOn);
			SetAnimatedBoolean(((Component)door).GetComponent<AnimatedObjectTrigger>(), snapshot.IsOpen || !snapshot.IsPoweredOn);
			if (!HasTerminalMonitorUi(door))
			{
				QueueTerminalInitialization(door);
				return;
			}
			try
			{
				SetField(TerminalPoweredField, door, true);
				SetField(TerminalDoorOpenField, door, !snapshot.IsOpen);
				door.SetDoorOpen(snapshot.IsOpen);
				SetField(TerminalDoorOpenField, door, snapshot.IsOpen);
				door.OnPowerSwitch(snapshot.IsPoweredOn);
			}
			catch (Exception ex)
			{
				Plugin.Debug($"Terminal door native state application failed at {((Component)door).transform.position}: {ex.Message}");
			}
			SetField(TerminalDoorOpenField, door, snapshot.IsOpen);
			SetField(TerminalPoweredField, door, snapshot.IsPoweredOn);
		}

		internal static bool ShouldDeferTerminalInitialization(TerminalAccessibleObject door)
		{
			if ((Object)(object)door == (Object)null || !IsLateClient())
			{
				return false;
			}
			if (IsTerminalMonitorReady())
			{
				return false;
			}
			QueueTerminalInitialization(door);
			return true;
		}

		private static bool IsLateClient()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (Plugin.Enabled.Value && (Object)(object)singleton != (Object)null && singleton.IsClient && !singleton.IsServer)
			{
				return MidJoinState.ClientLateJoinSyncActive;
			}
			return false;
		}

		private static bool IsTerminalMonitorReady()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.objectCodePrefab != (Object)null && (Object)(object)instance.mapScreen != (Object)null)
			{
				return (Object)(object)instance.mapScreen.mapCameraStationaryUI != (Object)null;
			}
			return false;
		}

		private static bool HasTerminalMonitorUi(TerminalAccessibleObject door)
		{
			object? obj = TerminalMapRadarTextField?.GetValue(door);
			Object val = (Object)((obj is Object) ? obj : null);
			if (val != null && val != (Object)null)
			{
				object? obj2 = TerminalMapRadarBoxField?.GetValue(door);
				Object val2 = (Object)((obj2 is Object) ? obj2 : null);
				if (val2 != null)
				{
					return val2 != (Object)null;
				}
			}
			return false;
		}

		private static void QueueTerminalInitialization(TerminalAccessibleObject door)
		{
			if ((Object)(object)door == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)door).GetInstanceID();
			if (DeferredTerminalInitializations.Add(instanceID))
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton == (Object)null)
				{
					DeferredTerminalInitializations.Remove(instanceID);
				}
				else
				{
					((MonoBehaviour)singleton).StartCoroutine(InitializeTerminalWhenReady(door, instanceID));
				}
			}
		}

		private static IEnumerator InitializeTerminalWhenReady(TerminalAccessibleObject door, int instanceId)
		{
			float deadline = Time.realtimeSinceStartup + 15f;
			while ((Object)(object)door != (Object)null && !IsTerminalMonitorReady() && Time.realtimeSinceStartup < deadline)
			{
				yield return null;
			}
			if ((Object)(object)door == (Object)null || !IsTerminalMonitorReady())
			{
				DeferredTerminalInitializations.Remove(instanceId);
				yield break;
			}
			try
			{
				if (!HasTerminalMonitorUi(door))
				{
					SetField(TerminalInitializedValuesField, door, false);
					door.InitializeValues();
				}
				if (HasTerminalMonitorUi(door))
				{
					bool flag = ReadField(TerminalPoweredField, door, fallback: true);
					door.OnPowerSwitch(flag);
					Plugin.Debug($"Initialized deferred secure-door monitor UI at {((Component)door).transform.position}.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Debug("Deferred secure-door monitor initialization failed: " + ex.Message);
			}
			finally
			{
				DeferredTerminalInitializations.Remove(instanceId);
			}
		}

		private static void SetAnimatedBoolean(AnimatedObjectTrigger? animated, bool value)
		{
			if (!((Object)(object)animated == (Object)null))
			{
				animated.boolValue = value;
				if ((Object)(object)animated.triggerAnimator != (Object)null && !string.IsNullOrEmpty(animated.animationString))
				{
					animated.triggerAnimator.SetBool(animated.animationString, value);
				}
				if ((Object)(object)animated.triggerAnimatorB != (Object)null)
				{
					animated.triggerAnimatorB.SetBool("on", value);
				}
			}
		}

		private static T? FindClosest<T>(T[] candidates, HashSet<int> used, Vector3 position, Func<T, bool>? predicate = null) where T : Component
		{
			//IL_0059: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			T result = default(T);
			float num = 0.5625f;
			foreach (T val in candidates)
			{
				if (!((Object)(object)val == (Object)null) && !used.Contains(((Object)(object)val).GetInstanceID()) && (predicate == null || predicate(val)))
				{
					Vector3 val2 = ((Component)val).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (!(sqrMagnitude > num))
					{
						num = sqrMagnitude;
						result = val;
					}
				}
			}
			return result;
		}

		private static void StopShipTravelCoroutine(StartOfRound round)
		{
			if (ShipTravelCoroutineField == null)
			{
				return;
			}
			try
			{
				object? value = ShipTravelCoroutineField.GetValue(round);
				Coroutine val = (Coroutine)((value is Coroutine) ? value : null);
				if (val != null)
				{
					((MonoBehaviour)round).StopCoroutine(val);
				}
				ShipTravelCoroutineField.SetValue(round, null);
			}
			catch (Exception ex)
			{
				Plugin.Debug("Could not stop stale ship-travel coroutine: " + ex.Message);
			}
		}

		private static bool MoveLocalPlayerIntoShip(StartOfRound round, PlayerControllerB player)
		{
			//IL_004f: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			int num = Array.IndexOf(round.allPlayerScripts, player);
			if (num < 0 || num >= round.playerSpawnPositions.Length)
			{
				num = Mathf.Clamp(round.thisClientPlayerId, 0, round.playerSpawnPositions.Length - 1);
			}
			if (num < 0 || num >= round.playerSpawnPositions.Length)
			{
				return false;
			}
			Transform val = round.playerSpawnPositions[num];
			player.TeleportPlayer(val.position, false, 0f, false, true);
			((Component)player).transform.SetPositionAndRotation(val.position, val.rotation);
			player.ResetZAndXRotation();
			SetField(PlayerIsInElevatorField, player, true);
			SetField(PlayerIsInHangarField, player, true);
			SetField(PlayerIsInsideFactoryField, player, false);
			Physics.SyncTransforms();
			return true;
		}

		private static void ResetPlayerMotion(StartOfRound round, PlayerControllerB player)
		{
			//IL_0006: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)player).transform.position;
			SetField(PlayerFallValueField, player, 0f);
			SetField(PlayerFallValueUncappedField, player, -7f);
			SetField(PlayerTakingFallDamageField, player, false);
			SetField(PlayerFallingFromJumpField, player, false);
			SetField(PlayerIsFallingNoJumpField, player, false);
			SetField(PlayerAverageVelocityField, player, 0f);
			SetField(PlayerVelocityLastFrameField, player, Vector3.zero);
			SetField(PlayerPreviousYField, player, position.y);
			SetField(PlayerExternalForcesField, player, Vector3.zero);
			SetField(PlayerIsSlidingField, player, false);
			SetField(PlayerSlidingTimerField, player, 0f);
			SetField(PlayerTeleportedLastFrameField, player, true);
			SetField(PlayerWasInElevatorLastFrameField, player, true);
			SetField(PlayerPreviousElevatorPositionField, player, ((Object)(object)round.elevatorTransform != (Object)null) ? round.elevatorTransform.position : Vector3.zero);
			SetField(PlayerOldPositionField, player, position);
			SetField(PlayerServerPositionField, player, position);
			SetField(PlayerSnapToServerPositionField, player, false);
			SetField(PlayerUpdatePositionForNewClientField, player, false);
		}

		private static void SynchronizeAudio(AudioSource? source, bool shouldPlay)
		{
			if ((Object)(object)source == (Object)null)
			{
				return;
			}
			if (shouldPlay)
			{
				if (!source.isPlaying && (Object)(object)source.clip != (Object)null)
				{
					source.Play();
				}
			}
			else if (source.isPlaying)
			{
				source.Stop();
			}
		}

		private static void ApplyTransform(Transform? transform, TransformSnapshot snapshot)
		{
			//IL_0014: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)transform == (Object)null) && snapshot.Exists)
			{
				transform.localPosition = snapshot.LocalPosition;
				transform.localRotation = snapshot.LocalRotation;
				transform.localScale = snapshot.LocalScale;
			}
		}

		private static void ApplyAnimator(Animator? animator, AnimatorSnapshot snapshot, bool holdAnimation)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			//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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected I4, but got Unknown
			if ((Object)(object)animator == (Object)null || !snapshot.Exists)
			{
				return;
			}
			bool enabled = snapshot.Enabled;
			((Behaviour)animator).enabled = true;
			AnimatorControllerParameter[] parameters = animator.parameters;
			foreach (AnimatorControllerParameter val in parameters)
			{
				if ((int)val.type == 9)
				{
					animator.ResetTrigger(val.nameHash);
				}
			}
			foreach (AnimatorParameterSnapshot parameter in snapshot.Parameters)
			{
				AnimatorControllerParameterType type = parameter.Type;
				switch (type - 1)
				{
				case 3:
					animator.SetBool(parameter.NameHash, parameter.BoolValue);
					break;
				case 2:
					animator.SetInteger(parameter.NameHash, parameter.IntValue);
					break;
				case 0:
					animator.SetFloat(parameter.NameHash, parameter.FloatValue);
					break;
				}
			}
			int num = Math.Min(animator.layerCount, snapshot.Layers.Count);
			for (int j = 0; j < num; j++)
			{
				AnimatorLayerSnapshot animatorLayerSnapshot = snapshot.Layers[j];
				animator.SetLayerWeight(j, animatorLayerSnapshot.Weight);
				if (animatorLayerSnapshot.StateHash != 0)
				{
					animator.Play(animatorLayerSnapshot.StateHash, j, Mathf.Clamp01(animatorLayerSnapshot.NormalizedTime));
				}
			}
			animator.Update(0f);
			animator.speed = (holdAnimation ? 0f : snapshot.Speed);
			((Behaviour)animator).enabled = enabled;
		}

		private static FieldInfo? FindInstanceField(Type type, string name)
		{
			return type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}

		private static bool ReadField(FieldInfo? field, object target, bool fallback)
		{
			if (field == null)
			{
				return fallback;
			}
			try
			{
				return (field.GetValue(target) is bool flag) ? flag : fallback;
			}
			catch
			{
				return fallback;
			}
		}

		private static T ReadField<T>(FieldInfo? field, object target, T fallback)
		{
			if (field == null)
			{
				return fallback;
			}
			try
			{
				return (T)((field.GetValue(target) is T val) ? ((object)val) : ((object)fallback));
			}
			catch
			{
				return fallback;
			}
		}

		private static void SetField(FieldInfo? field, object target, object? value)
		{
			if (field == null)
			{
				return;
			}
			try
			{
				field.SetValue(target, value);
			}
			catch (Exception ex)
			{
				Plugin.Debug("Could not set " + field.DeclaringType?.Name + "." + field.Name + ": " + ex.Message);
			}
		}

		private static void WriteSnapshot(ref FastBufferWriter writer, WorldSnapshot snapshot)
		{
			//IL_0007: 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_001c: 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_0031: 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)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_008b: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			int num = 3;
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref num, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.IncludeInterior, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.SpawnInShip, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.InShipPhase, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.ShipHasLanded, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.ShipIsLeaving, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.ShipDoorsEnabled, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.HangarDoorsClosed, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.NewGameIsLoading, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.TravellingToNewLevel, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.ShipAmbiancePlaying, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.ShipTravelAudioPlaying, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.PowerOffPermanently, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.PowerOn, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref snapshot.CurrentWeather, default(ForPrimitives));
			WriteTransform(ref writer, snapshot.ShipTransform);
			WriteTransform(ref writer, snapshot.CurrentPlanetTransform);
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.CurrentPlanetActive, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.OuterSpaceSunActive, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref snapshot.StarSphereActive, default(For