Decompiled source of CoopMod v0.2.7

CoopMod.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using ExitGames.Client.Photon;
using HarmonyLib;
using Peak;
using Peak.Afflictions;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using Zorro.Core;
using Zorro.Core.Serizalization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Co-op mod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Co-op mod")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("3228d7cf-9df9-4542-8bc9-3acc82920b68")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("com.peak.coopmod", "Co-op Mod", "0.0.7")]
public sealed class CoopMod : BaseUnityPlugin
{
	public const string PluginGuid = "com.peak.coopmod";

	public const string PluginName = "Co-op Mod";

	public const string PluginVersion = "0.0.7";

	private void Awake()
	{
		Freepass.Initialize(this);
		ShareStamina.Initialize(this);
		PairPlayerStartLog.EnsureCreated();
		OnlyEven.Initialize(this);
		Piggyback.Initialize(this);
		Latejoin.Initialize(this);
		Rolechanger.Initialize(this);
		SeparateRole.Initialize(this);
		ShareInventory.Initialize(this);
		ItemFix.Initialize(this);
		ShareDeath.Initialize(this);
		ShareAlive.Initialize(this);
	}

	private void OnDestroy()
	{
		ShareAlive.Shutdown();
		ShareDeath.Shutdown();
		ItemFix.Shutdown();
		ShareInventory.Shutdown();
		SeparateRole.Shutdown();
		Rolechanger.Shutdown();
		Latejoin.Shutdown();
		Piggyback.Shutdown();
		OnlyEven.Shutdown();
		ShareStamina.Shutdown();
		Freepass.Shutdown();
	}
}
public static class Freepass
{
	private sealed class FreepassState
	{
		public Character Climber;

		public Character Carrier;

		public Collider[] ClimberColliders;

		public Collider[] CarrierColliders;

		public Item Item;

		public Collider[] ItemColliders;

		public bool[] CarrierColliderEnabledBuffer;
	}

	private struct GroundedProxyState
	{
		public Character Climber;

		public bool Applied;

		public bool OriginalGrounded;
	}

	private struct CarrierRaycastProxyState
	{
		public FreepassState State;

		public bool Applied;
	}

	[HarmonyPatch(typeof(Item), "RPC_SetThrownData", new Type[]
	{
		typeof(int),
		typeof(float)
	})]
	private static class Item_RPC_SetThrownData_CarrierPass_Patch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(Item __instance, int characterID)
		{
			if (initialized && !((Object)(object)__instance == (Object)null) && !((Object)(object)GameUtils.instance == (Object)null))
			{
				PhotonView photonView = PhotonNetwork.GetPhotonView(characterID);
				Character climber = default(Character);
				if (!((Object)(object)photonView == (Object)null) && ((Component)photonView).TryGetComponent<Character>(ref climber) && TryGetPair(climber, out var carrier))
				{
					GameUtils.instance.IgnoreCollisions(carrier, __instance, 0.5f);
				}
			}
		}
	}

	[HarmonyPatch(typeof(RescueHook), "GetHit")]
	private static class RescueHook_GetHit_CarrierRaycastPass_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(RescueHook __instance, out CarrierRaycastProxyState __state)
		{
			__state = BeginCarrierRaycastPass(__instance);
		}

		[HarmonyFinalizer]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception, CarrierRaycastProxyState __state)
		{
			EndCarrierRaycastPass(__state);
			return __exception;
		}
	}

	[HarmonyPatch(typeof(RopeShooter), "WillAttach")]
	private static class RopeShooter_WillAttach_GroundedProxy_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(RopeShooter __instance, out GroundedProxyState __state)
		{
			__state = BeginGroundedProxy(((Object)(object)__instance != (Object)null) ? ((ItemComponent)__instance).item : null);
		}

		[HarmonyFinalizer]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception, GroundedProxyState __state)
		{
			EndGroundedProxy(__state);
			return __exception;
		}
	}

	[HarmonyPatch(typeof(RopeShooter), "OnPrimaryFinishedCast")]
	private static class RopeShooter_OnPrimaryFinishedCast_GroundedProxy_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(RopeShooter __instance, out GroundedProxyState __state)
		{
			__state = BeginGroundedProxy(((Object)(object)__instance != (Object)null) ? ((ItemComponent)__instance).item : null);
		}

		[HarmonyFinalizer]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception, GroundedProxyState __state)
		{
			EndGroundedProxy(__state);
			return __exception;
		}
	}

	[HarmonyPatch(typeof(VineShooter), "WillAttach")]
	private static class VineShooter_WillAttach_GroundedProxy_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(VineShooter __instance, out GroundedProxyState __state)
		{
			__state = BeginGroundedProxy(((Object)(object)__instance != (Object)null) ? ((ItemComponent)__instance).item : null);
		}

		[HarmonyFinalizer]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception, GroundedProxyState __state)
		{
			EndGroundedProxy(__state);
			return __exception;
		}
	}

	[HarmonyPatch(typeof(VineShooter), "OnPrimaryFinishedCast")]
	private static class VineShooter_OnPrimaryFinishedCast_GroundedProxy_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(VineShooter __instance, out GroundedProxyState __state)
		{
			__state = BeginGroundedProxy(((Object)(object)__instance != (Object)null) ? ((ItemComponent)__instance).item : null);
		}

		[HarmonyFinalizer]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception, GroundedProxyState __state)
		{
			EndGroundedProxy(__state);
			return __exception;
		}
	}

	[HarmonyPatch(typeof(Constructable), "TryUpdatePreview")]
	private static class Constructable_TryUpdatePreview_GroundedProxy_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(Constructable __instance, out GroundedProxyState __state)
		{
			__state = BeginGroundedProxy(((Object)(object)__instance != (Object)null) ? ((ItemComponent)__instance).item : null);
		}

		[HarmonyFinalizer]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception, GroundedProxyState __state)
		{
			EndGroundedProxy(__state);
			return __exception;
		}
	}

	[HarmonyPatch(typeof(CharacterItems), "RaycastClimbingSpikeStart")]
	private static class CharacterItems_RaycastClimbingSpikeStart_GroundedProxy_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(CharacterItems __instance, out GroundedProxyState __state)
		{
			Character climber = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<Character>() : null);
			__state = BeginGroundedProxy(climber);
		}

		[HarmonyFinalizer]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception, GroundedProxyState __state)
		{
			EndGroundedProxy(__state);
			return __exception;
		}
	}

	[HarmonyPatch(typeof(Action_RaycastSpawnSomething), "FixedUpdate")]
	private static class ActionRaycastSpawnSomething_FixedUpdate_GroundedProxy_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(Action_RaycastSpawnSomething __instance, out GroundedProxyState __state)
		{
			Item item = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<Item>() : null);
			__state = BeginGroundedProxy(item);
		}

		[HarmonyFinalizer]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception, GroundedProxyState __state)
		{
			EndGroundedProxy(__state);
			return __exception;
		}
	}

	[HarmonyPatch(typeof(CharacterItems), "FixedUpdate")]
	private static class CharacterItems_FixedUpdate_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(CharacterItems __instance)
		{
			if (IsCarriedClimberItems(__instance, out var climber, out var _))
			{
				UpdateFreepass(climber);
			}
		}
	}

	[HarmonyPatch(typeof(Character), "FixedUpdate")]
	private static class Character_FixedUpdate_Patch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(Character __instance)
		{
			UpdateFreepass(__instance);
		}
	}

	private const string HarmonyId = "com.peak.coopmod.freepass";

	private static Harmony harmony;

	private static bool initialized;

	private static readonly Dictionary<int, FreepassState> states = new Dictionary<int, FreepassState>();

	public static void Initialize(CoopMod plugin)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		if (!initialized && !((Object)(object)plugin == (Object)null))
		{
			harmony = new Harmony("com.peak.coopmod.freepass");
			harmony.CreateClassProcessor(typeof(CharacterItems_FixedUpdate_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(Character_FixedUpdate_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(RescueHook_GetHit_CarrierRaycastPass_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(Item_RPC_SetThrownData_CarrierPass_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(RopeShooter_WillAttach_GroundedProxy_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(RopeShooter_OnPrimaryFinishedCast_GroundedProxy_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(VineShooter_WillAttach_GroundedProxy_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(VineShooter_OnPrimaryFinishedCast_GroundedProxy_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(Constructable_TryUpdatePreview_GroundedProxy_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(CharacterItems_RaycastClimbingSpikeStart_GroundedProxy_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(ActionRaycastSpawnSomething_FixedUpdate_GroundedProxy_Patch)).Patch();
			initialized = true;
		}
	}

	public static void Shutdown()
	{
		if (initialized)
		{
			RestoreAll();
			if (harmony != null)
			{
				harmony.UnpatchSelf();
				harmony = null;
			}
			initialized = false;
		}
	}

	private static bool TryGetPair(Character climber, out Character carrier)
	{
		carrier = null;
		if ((Object)(object)climber == (Object)null || (Object)(object)climber.data == (Object)null || !climber.data.isCarried)
		{
			return false;
		}
		carrier = climber.data.carrier;
		if ((Object)(object)carrier == (Object)null || (Object)(object)carrier.data == (Object)null || (Object)(object)carrier.data.carriedPlayer != (Object)(object)climber)
		{
			carrier = null;
			return false;
		}
		return true;
	}

	private static Item GetHeldItem(Character climber)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Invalid comparison between Unknown and I4
		if ((Object)(object)climber == (Object)null || (Object)(object)climber.data == (Object)null)
		{
			return null;
		}
		Item currentItem = climber.data.currentItem;
		if ((Object)(object)currentItem == (Object)null || (int)currentItem.itemState != 1 || (Object)(object)currentItem.holderCharacter != (Object)(object)climber)
		{
			return null;
		}
		return currentItem;
	}

	private static Collider[] GetCharacterBodyColliders(Character character)
	{
		if ((Object)(object)character == (Object)null || character.refs == null || (Object)(object)character.refs.ragdoll == (Object)null)
		{
			return Array.Empty<Collider>();
		}
		RigCreatorCollider[] componentsInChildren = ((Component)character.refs.ragdoll).GetComponentsInChildren<RigCreatorCollider>(true);
		if (componentsInChildren == null || componentsInChildren.Length == 0)
		{
			return Array.Empty<Collider>();
		}
		HashSet<Collider> hashSet = new HashSet<Collider>();
		foreach (RigCreatorCollider val in componentsInChildren)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Collider component = ((Component)val).GetComponent<Collider>();
			if (!((Object)(object)component == (Object)null))
			{
				Character componentInParent = ((Component)component).GetComponentInParent<Character>();
				if (!((Object)(object)componentInParent != (Object)(object)character))
				{
					hashSet.Add(component);
				}
			}
		}
		if (hashSet.Count == 0)
		{
			return Array.Empty<Collider>();
		}
		Collider[] array = (Collider[])(object)new Collider[hashSet.Count];
		hashSet.CopyTo(array);
		return array;
	}

	private static Collider[] GetItemColliders(Item item)
	{
		if ((Object)(object)item == (Object)null)
		{
			return Array.Empty<Collider>();
		}
		Collider[] componentsInChildren = ((Component)item).GetComponentsInChildren<Collider>(true);
		if (componentsInChildren == null || componentsInChildren.Length == 0)
		{
			return Array.Empty<Collider>();
		}
		List<Collider> list = new List<Collider>(componentsInChildren.Length);
		foreach (Collider val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null))
			{
				Item componentInParent = ((Component)val).GetComponentInParent<Item>();
				if (!((Object)(object)componentInParent != (Object)(object)item))
				{
					list.Add(val);
				}
			}
		}
		return list.ToArray();
	}

	private static void SetCollisionIgnore(Collider[] first, Collider[] second, bool ignore)
	{
		if (first == null || second == null)
		{
			return;
		}
		foreach (Collider val in first)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			foreach (Collider val2 in second)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val == (Object)(object)val2) && Physics.GetIgnoreCollision(val, val2) != ignore)
				{
					Physics.IgnoreCollision(val, val2, ignore);
				}
			}
		}
	}

	private static void RestoreHeldItem(FreepassState state)
	{
		if (state != null && !((Object)(object)state.Item == (Object)null))
		{
			SetCollisionIgnore(state.ItemColliders, state.CarrierColliders, ignore: false);
			SetCollisionIgnore(state.ItemColliders, state.ClimberColliders, ignore: false);
			state.Item = null;
			state.ItemColliders = null;
		}
	}

	private static void ApplyHeldItemIsolation(FreepassState state, Item item)
	{
		if (state != null && !((Object)(object)item == (Object)null))
		{
			if ((Object)(object)state.Item != (Object)(object)item)
			{
				RestoreHeldItem(state);
				state.Item = item;
				state.ItemColliders = GetItemColliders(item);
			}
			SetCollisionIgnore(state.ItemColliders, state.CarrierColliders, ignore: true);
			SetCollisionIgnore(state.ItemColliders, state.ClimberColliders, ignore: true);
		}
	}

	private static FreepassState CreateState(Character climber, Character carrier)
	{
		Collider[] characterBodyColliders = GetCharacterBodyColliders(climber);
		Collider[] characterBodyColliders2 = GetCharacterBodyColliders(carrier);
		FreepassState freepassState = new FreepassState();
		freepassState.Climber = climber;
		freepassState.Carrier = carrier;
		freepassState.ClimberColliders = characterBodyColliders;
		freepassState.CarrierColliders = characterBodyColliders2;
		freepassState.CarrierColliderEnabledBuffer = new bool[characterBodyColliders2.Length];
		FreepassState freepassState2 = freepassState;
		SetCollisionIgnore(freepassState2.ClimberColliders, freepassState2.CarrierColliders, ignore: true);
		return freepassState2;
	}

	private static void RestoreState(int climberId)
	{
		if (states.TryGetValue(climberId, out var value))
		{
			if (value != null)
			{
				RestoreHeldItem(value);
				SetCollisionIgnore(value.ClimberColliders, value.CarrierColliders, ignore: false);
			}
			states.Remove(climberId);
		}
	}

	private static void RestoreAll()
	{
		List<int> list = new List<int>(states.Keys);
		for (int i = 0; i < list.Count; i++)
		{
			RestoreState(list[i]);
		}
	}

	private static FreepassState EnsureState(Character climber, Character carrier)
	{
		int instanceID = ((Object)climber).GetInstanceID();
		if (states.TryGetValue(instanceID, out var value))
		{
			if (value != null && (Object)(object)value.Climber == (Object)(object)climber && (Object)(object)value.Carrier == (Object)(object)carrier)
			{
				return value;
			}
			RestoreState(instanceID);
		}
		value = CreateState(climber, carrier);
		states[instanceID] = value;
		return value;
	}

	private static void UpdateFreepass(Character character)
	{
		if (!initialized || (Object)(object)character == (Object)null)
		{
			return;
		}
		if (!TryGetPair(character, out var carrier))
		{
			RestoreState(((Object)character).GetInstanceID());
			return;
		}
		FreepassState freepassState = EnsureState(character, carrier);
		if (freepassState != null)
		{
			SetCollisionIgnore(freepassState.ClimberColliders, freepassState.CarrierColliders, ignore: true);
			Item heldItem = GetHeldItem(character);
			if ((Object)(object)heldItem == (Object)null)
			{
				RestoreHeldItem(freepassState);
			}
			else
			{
				ApplyHeldItemIsolation(freepassState, heldItem);
			}
		}
	}

	private static bool IsCarriedClimberItems(CharacterItems items, out Character climber, out Character carrier)
	{
		climber = null;
		carrier = null;
		if ((Object)(object)items == (Object)null)
		{
			return false;
		}
		climber = ((Component)items).GetComponent<Character>();
		return TryGetPair(climber, out carrier);
	}

	private static CarrierRaycastProxyState BeginCarrierRaycastPass(RescueHook rescueHook)
	{
		CarrierRaycastProxyState result = default(CarrierRaycastProxyState);
		if (!initialized || (Object)(object)rescueHook == (Object)null || (Object)(object)((ItemComponent)rescueHook).item == (Object)null)
		{
			return result;
		}
		Character holderCharacter = ((ItemComponent)rescueHook).item.holderCharacter;
		if (!TryGetPair(holderCharacter, out var carrier))
		{
			return result;
		}
		FreepassState freepassState = EnsureState(holderCharacter, carrier);
		if (freepassState == null || freepassState.CarrierColliders == null || freepassState.CarrierColliderEnabledBuffer == null || freepassState.CarrierColliderEnabledBuffer.Length != freepassState.CarrierColliders.Length)
		{
			return result;
		}
		result.State = freepassState;
		result.Applied = true;
		for (int i = 0; i < freepassState.CarrierColliders.Length; i++)
		{
			Collider val = freepassState.CarrierColliders[i];
			if ((Object)(object)val == (Object)null)
			{
				freepassState.CarrierColliderEnabledBuffer[i] = false;
				continue;
			}
			bool enabled = val.enabled;
			freepassState.CarrierColliderEnabledBuffer[i] = enabled;
			if (enabled)
			{
				val.enabled = false;
			}
		}
		return result;
	}

	private static void EndCarrierRaycastPass(CarrierRaycastProxyState proxyState)
	{
		if (!proxyState.Applied || proxyState.State == null || proxyState.State.CarrierColliders == null || proxyState.State.CarrierColliderEnabledBuffer == null)
		{
			return;
		}
		Collider[] carrierColliders = proxyState.State.CarrierColliders;
		bool[] carrierColliderEnabledBuffer = proxyState.State.CarrierColliderEnabledBuffer;
		int num = Mathf.Min(carrierColliders.Length, carrierColliderEnabledBuffer.Length);
		for (int i = 0; i < num; i++)
		{
			Collider val = carrierColliders[i];
			if (!((Object)(object)val == (Object)null))
			{
				val.enabled = carrierColliderEnabledBuffer[i];
			}
		}
	}

	private static GroundedProxyState BeginGroundedProxy(Character climber)
	{
		GroundedProxyState result = default(GroundedProxyState);
		if (!initialized || (Object)(object)climber == (Object)null || (Object)(object)climber.data == (Object)null)
		{
			return result;
		}
		if (!TryGetPair(climber, out var carrier) || (Object)(object)carrier == (Object)null || (Object)(object)carrier.data == (Object)null)
		{
			return result;
		}
		result.Climber = climber;
		result.OriginalGrounded = climber.data.isGrounded;
		result.Applied = true;
		climber.data.isGrounded = carrier.data.isGrounded;
		return result;
	}

	private static GroundedProxyState BeginGroundedProxy(Item item)
	{
		if ((Object)(object)item == (Object)null)
		{
			return default(GroundedProxyState);
		}
		return BeginGroundedProxy(item.holderCharacter);
	}

	private static void EndGroundedProxy(GroundedProxyState state)
	{
		if (state.Applied && !((Object)(object)state.Climber == (Object)null) && !((Object)(object)state.Climber.data == (Object)null))
		{
			state.Climber.data.isGrounded = state.OriginalGrounded;
		}
	}
}
public static class ItemFix
{
	[StructLayout(LayoutKind.Explicit)]
	private struct FloatIntUnion
	{
		[FieldOffset(0)]
		public float FloatValue;

		[FieldOffset(0)]
		public int IntValue;
	}

	private struct ThrownItemState
	{
		public Character Character;

		public float Time;
	}

	[HarmonyPatch(typeof(RescueHook), "FixedUpdate")]
	private static class RescueHook_FixedUpdate_ContextPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(RescueHook __instance)
		{
			activeRescueHook = null;
			activeRescueClimber = null;
			activeRescueCanSend = false;
			Character val = (((Object)(object)__instance != (Object)null) ? __instance.playerHoldingItem : null);
			if (!((Object)(object)val == (Object)null) && SeparateRole.IsClimber(val))
			{
				activeRescueHook = __instance;
				activeRescueClimber = val;
				activeRescueCanSend = val.IsLocal && (Object)(object)((MonoBehaviourPun)__instance).photonView != (Object)null && ((MonoBehaviourPun)__instance).photonView.IsMine;
			}
		}

		[HarmonyFinalizer]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			activeRescueHook = null;
			activeRescueClimber = null;
			activeRescueCanSend = false;
			return __exception;
		}
	}

	[HarmonyPatch(typeof(Character), "AddForce", new Type[]
	{
		typeof(Vector3),
		typeof(float),
		typeof(float)
	})]
	private static class Character_AddForce_RescueTransportPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(Character __instance, Vector3 __0, float __1, float __2)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)activeRescueHook == (Object)null || (Object)(object)activeRescueClimber == (Object)null || (Object)(object)__instance != (Object)(object)activeRescueClimber || !SeparateRole.IsClimber(__instance))
			{
				return true;
			}
			if (activeRescueCanSend && TryGetCarrier(__instance, out var carrier))
			{
				SendRescueForce(__instance, carrier, __0, __1, __2, activeRescueHook.extraDragSelf);
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(RescueHook), "RPCA_RescueWall", new Type[]
	{
		typeof(bool),
		typeof(Vector3)
	})]
	private static class RescueHook_RPCA_RescueWall_TransportPatch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(RescueHook __instance)
		{
			Character val = (((Object)(object)__instance != (Object)null) ? __instance.playerHoldingItem : null);
			if (!((Object)(object)val == (Object)null) && val.IsLocal && !((Object)(object)((MonoBehaviourPun)__instance).photonView == (Object)null) && ((MonoBehaviourPun)__instance).photonView.IsMine && TryGetCarrier(val, out var carrier))
			{
				activeSelfRescueHook = __instance;
				SendRescueFall(val, carrier, __instance.selfFallSeconds);
			}
		}
	}

	[HarmonyPatch(typeof(RescueHook), "RPCA_LetGo")]
	private static class RescueHook_RPCA_LetGo_TransportPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(RescueHook __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)activeSelfRescueHook))
			{
				Character playerHoldingItem = __instance.playerHoldingItem;
				if ((Object)(object)playerHoldingItem != (Object)null && playerHoldingItem.IsLocal && (Object)(object)((MonoBehaviourPun)__instance).photonView != (Object)null && ((MonoBehaviourPun)__instance).photonView.IsMine && TryGetCarrier(playerHoldingItem, out var carrier))
				{
					SendRescueLetGo(playerHoldingItem, carrier, __instance.extraDragSelf);
				}
				activeSelfRescueHook = null;
			}
		}
	}

	[HarmonyPatch(typeof(RescueHook), "OnDestroy")]
	private static class RescueHook_OnDestroy_TransportPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(RescueHook __instance)
		{
			if ((Object)(object)__instance == (Object)(object)activeSelfRescueHook)
			{
				activeSelfRescueHook = null;
			}
		}
	}

	[HarmonyPatch(typeof(Item), "RPC_SetThrownData", new Type[]
	{
		typeof(int),
		typeof(float)
	})]
	private static class Item_RPC_SetThrownData_TrackPatch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(Item __instance, int characterID)
		{
			TrackThrownItem(__instance, characterID);
		}
	}

	[HarmonyPatch(typeof(WarpOnThrow), "OnCollisionEnter", new Type[] { typeof(Collision) })]
	private static class WarpOnThrow_OnCollisionEnter_TransportPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(WarpOnThrow __instance, Collision collision)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_0138: 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_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: 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_016e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || collision == null || (Object)(object)((ItemComponent)__instance).item == (Object)null || (int)((ItemComponent)__instance).item.itemState != 0 || (Object)(object)((MonoBehaviourPun)__instance).photonView == (Object)null || !((MonoBehaviourPun)__instance).photonView.IsMine || collision.contactCount <= 0 || !TryGetThrownItemState(((ItemComponent)__instance).item, out var state))
			{
				return;
			}
			Character character = state.Character;
			if (!TryGetCarrierReplica(character, out var carrier) || (Object)(object)((MonoBehaviourPun)carrier).photonView == (Object)null)
			{
				return;
			}
			int layer = collision.gameObject.layer;
			if ((LayerMask.op_Implicit(HelperFunctions.terrainMapMask) & (1 << layer)) == 0)
			{
				return;
			}
			Vector3 relativeVelocity = collision.relativeVelocity;
			if (!(((Vector3)(ref relativeVelocity)).magnitude <= __instance.minVelocity))
			{
				float num = Time.time - state.Time;
				if (!(num <= __instance.minTime) && !(num >= __instance.maxTime) && TryMarkWarpItem(((MonoBehaviourPun)__instance).photonView.ViewID))
				{
					ContactPoint val = collision.contacts[0];
					Vector3 val2 = ((ContactPoint)(ref val)).point + ((ContactPoint)(ref val)).normal * __instance.moveAwayFromWallDistance;
					((MonoBehaviourPun)carrier).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val2, true });
				}
			}
		}
	}

	[HarmonyPatch(typeof(Character), "WarpPlayerRPC", new Type[]
	{
		typeof(Vector3),
		typeof(bool)
	})]
	private static class Character_WarpPlayerRPC_CarriedCollisionPatch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(Character __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && SeparateRole.IsClimber(__instance))
			{
				TrackWarpClimber(__instance);
			}
		}
	}

	private const string HarmonyId = "com.peak.coopmod.itemfix";

	private const byte ItemMovementEventCode = 186;

	private const byte RescueForceAction = 1;

	private const byte RescueFallAction = 2;

	private const byte RescueLetGoAction = 3;

	private const byte WarpAction = 4;

	private const int HeaderLength = 9;

	private const int RescueForcePayloadLength = 33;

	private const int RescueFallPayloadLength = 13;

	private const int RescueLetGoPayloadLength = 13;

	private const int WarpPayloadLength = 22;

	private static Harmony harmony;

	private static RescueHook activeRescueHook;

	private static Character activeRescueClimber;

	private static bool activeRescueCanSend;

	private static RescueHook activeSelfRescueHook;

	private static readonly Dictionary<int, ThrownItemState> thrownItemStates = new Dictionary<int, ThrownItemState>();

	private static readonly Dictionary<int, float> recentWarpItems = new Dictionary<int, float>();

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

	private static readonly int[] targetActors = new int[1];

	private static readonly RaiseEventOptions raiseEventOptions = new RaiseEventOptions();

	public static void Initialize(CoopMod plugin)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		if (harmony == null && !((Object)(object)plugin == (Object)null))
		{
			harmony = new Harmony("com.peak.coopmod.itemfix");
			Patch(typeof(RescueHook_FixedUpdate_ContextPatch));
			Patch(typeof(Character_AddForce_RescueTransportPatch));
			Patch(typeof(RescueHook_RPCA_RescueWall_TransportPatch));
			Patch(typeof(RescueHook_RPCA_LetGo_TransportPatch));
			Patch(typeof(RescueHook_OnDestroy_TransportPatch));
			Patch(typeof(Item_RPC_SetThrownData_TrackPatch));
			Patch(typeof(WarpOnThrow_OnCollisionEnter_TransportPatch));
			Patch(typeof(Character_WarpPlayerRPC_CarriedCollisionPatch));
			PhotonNetwork.NetworkingClient.EventReceived += HandleEvent;
		}
	}

	public static void Shutdown()
	{
		PhotonNetwork.NetworkingClient.EventReceived -= HandleEvent;
		foreach (Character trackedWarpClimber in trackedWarpClimbers)
		{
			if ((Object)(object)trackedWarpClimber != (Object)null)
			{
				trackedWarpClimber.WarpCompleted -= OnWarpCompleted;
			}
		}
		trackedWarpClimbers.Clear();
		recentWarpItems.Clear();
		thrownItemStates.Clear();
		activeRescueHook = null;
		activeRescueClimber = null;
		activeRescueCanSend = false;
		activeSelfRescueHook = null;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
			harmony = null;
		}
	}

	private static void Patch(Type patchType)
	{
		harmony.CreateClassProcessor(patchType).Patch();
	}

	private static int GetActorNumber(Character character)
	{
		if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null || ((MonoBehaviourPun)character).photonView.Owner == null)
		{
			return -1;
		}
		return ((MonoBehaviourPun)character).photonView.Owner.ActorNumber;
	}

	private static bool TryGetCarrier(Character climber, out Character carrier)
	{
		carrier = null;
		if ((Object)(object)climber == (Object)null || (Object)(object)climber.data == (Object)null || !climber.IsLocal || !SeparateRole.IsClimber(climber))
		{
			return false;
		}
		carrier = climber.data.carrier;
		return (Object)(object)carrier != (Object)null && (Object)(object)carrier.data != (Object)null && SeparateRole.IsCarrier(carrier);
	}

	private static bool TryGetCarrierReplica(Character climber, out Character carrier)
	{
		carrier = null;
		if ((Object)(object)climber == (Object)null || (Object)(object)climber.data == (Object)null || !SeparateRole.IsClimber(climber))
		{
			return false;
		}
		carrier = climber.data.carrier;
		return (Object)(object)carrier != (Object)null && (Object)(object)carrier.data != (Object)null && (Object)(object)carrier.data.carriedPlayer == (Object)(object)climber && SeparateRole.IsCarrier(carrier);
	}

	private static void ApplyAcceleration(Character carrier, Vector3 force, float minRandomMultiplier, float maxRandomMultiplier)
	{
		//IL_006e: 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_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)carrier == (Object)null || carrier.refs == null || (Object)(object)carrier.refs.ragdoll == (Object)null || carrier.refs.ragdoll.partList == null)
		{
			return;
		}
		for (int i = 0; i < carrier.refs.ragdoll.partList.Count; i++)
		{
			Bodypart val = carrier.refs.ragdoll.partList[i];
			if (!((Object)(object)val == (Object)null))
			{
				Vector3 val2 = force;
				if (minRandomMultiplier != maxRandomMultiplier)
				{
					val2 *= Random.Range(minRandomMultiplier, maxRandomMultiplier);
				}
				val.AddForce(val2, (ForceMode)5);
			}
		}
	}

	private static void WriteInt32(byte[] buffer, ref int offset, int value)
	{
		buffer[offset++] = (byte)value;
		buffer[offset++] = (byte)(value >> 8);
		buffer[offset++] = (byte)(value >> 16);
		buffer[offset++] = (byte)(value >> 24);
	}

	private static int ReadInt32(byte[] buffer, ref int offset)
	{
		int result = buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24);
		offset += 4;
		return result;
	}

	private static void WriteSingle(byte[] buffer, ref int offset, float value)
	{
		FloatIntUnion floatIntUnion = new FloatIntUnion
		{
			FloatValue = value
		};
		WriteInt32(buffer, ref offset, floatIntUnion.IntValue);
	}

	private static float ReadSingle(byte[] buffer, ref int offset)
	{
		FloatIntUnion floatIntUnion = new FloatIntUnion
		{
			IntValue = ReadInt32(buffer, ref offset)
		};
		return floatIntUnion.FloatValue;
	}

	private static bool PrepareTarget(Character climber, Character carrier, out int sourceActor, out int targetActor)
	{
		sourceActor = GetActorNumber(climber);
		targetActor = GetActorNumber(carrier);
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null || sourceActor <= 0 || targetActor <= 0)
		{
			return false;
		}
		targetActors[0] = targetActor;
		raiseEventOptions.TargetActors = targetActors;
		return true;
	}

	private static void SendRescueForce(Character climber, Character carrier, Vector3 force, float minRandomMultiplier, float maxRandomMultiplier, float extraDrag)
	{
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: 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)
		if (PrepareTarget(climber, carrier, out var sourceActor, out var targetActor))
		{
			byte[] array = new byte[33];
			int offset = 0;
			array[offset++] = 1;
			WriteInt32(array, ref offset, sourceActor);
			WriteInt32(array, ref offset, targetActor);
			WriteSingle(array, ref offset, force.x);
			WriteSingle(array, ref offset, force.y);
			WriteSingle(array, ref offset, force.z);
			WriteSingle(array, ref offset, minRandomMultiplier);
			WriteSingle(array, ref offset, maxRandomMultiplier);
			WriteSingle(array, ref offset, extraDrag);
			PhotonNetwork.RaiseEvent((byte)186, (object)array, raiseEventOptions, SendOptions.SendUnreliable);
		}
	}

	private static void SendRescueFall(Character climber, Character carrier, float seconds)
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		if (PrepareTarget(climber, carrier, out var sourceActor, out var targetActor))
		{
			byte[] array = new byte[13];
			int offset = 0;
			array[offset++] = 2;
			WriteInt32(array, ref offset, sourceActor);
			WriteInt32(array, ref offset, targetActor);
			WriteSingle(array, ref offset, seconds);
			PhotonNetwork.RaiseEvent((byte)186, (object)array, raiseEventOptions, SendOptions.SendReliable);
		}
	}

	private static void SendRescueLetGo(Character climber, Character carrier, float extraDrag)
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		if (PrepareTarget(climber, carrier, out var sourceActor, out var targetActor))
		{
			byte[] array = new byte[13];
			int offset = 0;
			array[offset++] = 3;
			WriteInt32(array, ref offset, sourceActor);
			WriteInt32(array, ref offset, targetActor);
			WriteSingle(array, ref offset, extraDrag);
			PhotonNetwork.RaiseEvent((byte)186, (object)array, raiseEventOptions, SendOptions.SendReliable);
		}
	}

	private static void SendWarp(Character climber, Character carrier, Vector3 position, bool poof)
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: 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)
		if (PrepareTarget(climber, carrier, out var sourceActor, out var targetActor))
		{
			byte[] array = new byte[22];
			int offset = 0;
			array[offset++] = 4;
			WriteInt32(array, ref offset, sourceActor);
			WriteInt32(array, ref offset, targetActor);
			WriteSingle(array, ref offset, position.x);
			WriteSingle(array, ref offset, position.y);
			WriteSingle(array, ref offset, position.z);
			array[offset++] = (byte)(poof ? 1 : 0);
			PhotonNetwork.RaiseEvent((byte)186, (object)array, raiseEventOptions, SendOptions.SendReliable);
		}
	}

	private static void HandleEvent(EventData photonEvent)
	{
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
		if (photonEvent == null || photonEvent.Code != 186 || !(photonEvent.CustomData is byte[] array) || array.Length < 9)
		{
			return;
		}
		int offset = 0;
		byte b = array[offset++];
		int num = ReadInt32(array, ref offset);
		int num2 = ReadInt32(array, ref offset);
		Character localCharacter = Character.localCharacter;
		if ((Object)(object)localCharacter == (Object)null || !localCharacter.IsLocal || !SeparateRole.IsCarrier(localCharacter))
		{
			return;
		}
		int actorNumber = GetActorNumber(localCharacter);
		Character carriedPlayer = localCharacter.data.carriedPlayer;
		int actorNumber2 = GetActorNumber(carriedPlayer);
		if (num2 != actorNumber || num != actorNumber2 || photonEvent.Sender != num)
		{
			return;
		}
		switch (b)
		{
		case 1:
			if (array.Length >= 33)
			{
				Vector3 force = default(Vector3);
				((Vector3)(ref force))..ctor(ReadSingle(array, ref offset), ReadSingle(array, ref offset), ReadSingle(array, ref offset));
				float minRandomMultiplier = ReadSingle(array, ref offset);
				float maxRandomMultiplier = ReadSingle(array, ref offset);
				float num3 = ReadSingle(array, ref offset);
				if (localCharacter.refs != null && (Object)(object)localCharacter.refs.movement != (Object)null)
				{
					localCharacter.refs.movement.ApplyExtraDrag(num3, true);
				}
				localCharacter.data.sinceGrounded = 0f;
				ApplyAcceleration(localCharacter, force, minRandomMultiplier, maxRandomMultiplier);
			}
			break;
		case 2:
			if (array.Length >= 13 && !((Object)(object)((MonoBehaviourPun)localCharacter).photonView == (Object)null))
			{
				float num4 = ReadSingle(array, ref offset);
				((MonoBehaviourPun)localCharacter).photonView.RPC("RPCA_Fall", (RpcTarget)0, new object[2] { num4, 0f });
			}
			break;
		case 3:
			if (array.Length >= 13)
			{
				float num5 = ReadSingle(array, ref offset);
				if (localCharacter.refs != null && (Object)(object)localCharacter.refs.movement != (Object)null)
				{
					localCharacter.refs.movement.ApplyExtraDrag(num5, true);
				}
			}
			break;
		case 4:
			if (array.Length >= 22 && !((Object)(object)((MonoBehaviourPun)localCharacter).photonView == (Object)null))
			{
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(ReadSingle(array, ref offset), ReadSingle(array, ref offset), ReadSingle(array, ref offset));
				bool flag = array[offset] != 0;
				((MonoBehaviourPun)localCharacter).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, flag });
			}
			break;
		}
	}

	private static void TrackThrownItem(Item item, int characterViewId)
	{
		if (!((Object)(object)item == (Object)null))
		{
			PhotonView photonView = PhotonNetwork.GetPhotonView(characterViewId);
			Character character = null;
			if ((Object)(object)photonView != (Object)null)
			{
				((Component)photonView).TryGetComponent<Character>(ref character);
			}
			thrownItemStates[((Object)item).GetInstanceID()] = new ThrownItemState
			{
				Character = character,
				Time = Time.time
			};
		}
	}

	private static bool TryGetThrownItemState(Item item, out ThrownItemState state)
	{
		state = default(ThrownItemState);
		if ((Object)(object)item == (Object)null)
		{
			return false;
		}
		return thrownItemStates.TryGetValue(((Object)item).GetInstanceID(), out state) && (Object)(object)state.Character != (Object)null;
	}

	private static bool TryMarkWarpItem(int viewId)
	{
		if (viewId <= 0)
		{
			return true;
		}
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		if (recentWarpItems.TryGetValue(viewId, out var value) && realtimeSinceStartup < value)
		{
			return false;
		}
		recentWarpItems[viewId] = realtimeSinceStartup + 3f;
		return true;
	}

	private static void TrackWarpClimber(Character climber)
	{
		if (!((Object)(object)climber == (Object)null) && SeparateRole.IsClimber(climber) && !trackedWarpClimbers.Contains(climber))
		{
			trackedWarpClimbers.Add(climber);
			climber.WarpCompleted += OnWarpCompleted;
		}
	}

	private static void OnWarpCompleted(Character climber)
	{
		if ((Object)(object)climber != (Object)null)
		{
			climber.WarpCompleted -= OnWarpCompleted;
		}
		trackedWarpClimbers.Remove(climber);
		if (!((Object)(object)climber == (Object)null) && SeparateRole.IsClimber(climber) && climber.refs != null && !((Object)(object)climber.refs.ragdoll == (Object)null))
		{
			climber.refs.ragdoll.ToggleCollision(false);
		}
	}
}
public static class Latejoin
{
	[HarmonyPatch(typeof(CharacterCarrying), "Update")]
	private static class CharacterCarrying_Update_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(CharacterCarrying __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			if ((Object)(object)component == (Object)null || (Object)(object)component.data == (Object)null)
			{
				return true;
			}
			Character carriedPlayer = component.data.carriedPlayer;
			if (!IsLockedPair(component, carriedPlayer))
			{
				return true;
			}
			return ShouldAllowRelease(component, carriedPlayer);
		}
	}

	[HarmonyPatch(typeof(CharacterCarrying), "Drop", new Type[] { typeof(Character) })]
	private static class CharacterCarrying_Drop_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(CharacterCarrying __instance, Character target)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)target == (Object)null)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			if (!IsLockedPair(component, target))
			{
				return true;
			}
			return ShouldAllowRelease(component, target);
		}
	}

	[HarmonyPatch(typeof(CharacterCarrying), "RPCA_Drop", new Type[] { typeof(PhotonView) })]
	private static class CharacterCarrying_RPCA_Drop_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(CharacterCarrying __instance, PhotonView targetView)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)targetView == (Object)null)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			Character component2 = ((Component)targetView).GetComponent<Character>();
			if (!IsLockedPair(component, component2))
			{
				return true;
			}
			return ShouldAllowRelease(component, component2);
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(CharacterCarrying __instance, PhotonView targetView)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)targetView == (Object)null)
			{
				return;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			Character component2 = ((Component)targetView).GetComponent<Character>();
			if (!((Object)(object)component2 == (Object)null) && !((Object)(object)component2.data == (Object)null) && (!component2.data.isCarried || !((Object)(object)component2.data.carrier == (Object)(object)component)))
			{
				int actorNumber = GetActorNumber(component2);
				if (actorNumber > 0)
				{
					LockedRiderToCarrier.Remove(actorNumber);
				}
			}
		}
	}

	[HarmonyPatch(typeof(CharacterCarrying), "RPCA_StartCarry", new Type[] { typeof(PhotonView) })]
	private static class CharacterCarrying_RPCA_StartCarry_Patch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(CharacterCarrying __instance, PhotonView targetView)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)targetView == (Object)null))
			{
				Character component = ((Component)__instance).GetComponent<Character>();
				Character component2 = ((Component)targetView).GetComponent<Character>();
				if (IsLockedPair(component, component2) && !((Object)(object)component == (Object)null) && !((Object)(object)component.data == (Object)null) && !((Object)(object)component2 == (Object)null) && !((Object)(object)component2.data == (Object)null) && !((Object)(object)component.data.carriedPlayer != (Object)(object)component2) && component2.data.isCarried && !((Object)(object)component2.data.carrier != (Object)(object)component))
				{
					MakeRiderAlive(component2);
				}
			}
		}
	}

	private const string HarmonyId = "com.peak.coopmod.latejoin";

	private const byte PairEventCode = 193;

	private const byte PairAction = 1;

	private const byte PromoteCarrierAction = 2;

	private const byte RemovePairAction = 3;

	private static Harmony harmony;

	private static CoopMod plugin;

	private static LatejoinRuntime runtime;

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

	public static void Initialize(CoopMod owner)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		if (harmony == null && !((Object)(object)owner == (Object)null))
		{
			plugin = owner;
			harmony = new Harmony("com.peak.coopmod.latejoin");
			Patch(typeof(CharacterCarrying_Update_Patch));
			Patch(typeof(CharacterCarrying_Drop_Patch));
			Patch(typeof(CharacterCarrying_RPCA_Drop_Patch));
			Patch(typeof(CharacterCarrying_RPCA_StartCarry_Patch));
			runtime = ((Component)owner).gameObject.GetComponent<LatejoinRuntime>();
			if ((Object)(object)runtime == (Object)null)
			{
				runtime = ((Component)owner).gameObject.AddComponent<LatejoinRuntime>();
			}
			runtime.InitializeRuntime();
		}
	}

	public static void Shutdown()
	{
		LockedRiderToCarrier.Clear();
		if ((Object)(object)runtime != (Object)null)
		{
			runtime.ShutdownRuntime();
			Object.Destroy((Object)(object)runtime);
			runtime = null;
		}
		if (harmony != null)
		{
			harmony.UnpatchSelf();
			harmony = null;
		}
		plugin = null;
	}

	private static void Patch(Type patchType)
	{
		harmony.CreateClassProcessor(patchType).Patch();
	}

	internal static void HandlePairEvent(EventData photonEvent)
	{
		if (photonEvent == null || photonEvent.Code != 193 || !(photonEvent.CustomData is byte[] array) || array.Length < 9)
		{
			return;
		}
		int offset = 0;
		byte b = array[offset++];
		int num = ReadInt32(array, ref offset);
		int num2 = ReadInt32(array, ref offset);
		switch (b)
		{
		case 1:
		{
			RegisterPairActors(num, num2);
			Character rider = default(Character);
			if (PlayerHandler.TryGetCharacter(num2, ref rider))
			{
				MakeRiderAlive(rider);
			}
			break;
		}
		case 2:
			PromoteActorToCarrier(num);
			break;
		case 3:
			RemovePairsForActor(num);
			if (num2 > 0)
			{
				RemovePairsForActor(num2);
			}
			break;
		}
	}

	internal static bool StartLatejoinPair(Character carrier, Character rider)
	{
		if (!PhotonNetwork.IsMasterClient || !PhotonNetwork.InRoom || (Object)(object)carrier == (Object)null || (Object)(object)rider == (Object)null || (Object)(object)carrier.data == (Object)null || (Object)(object)rider.data == (Object)null || (Object)(object)((MonoBehaviourPun)carrier).photonView == (Object)null || (Object)(object)((MonoBehaviourPun)rider).photonView == (Object)null)
		{
			return false;
		}
		int actorNumber = GetActorNumber(carrier);
		int actorNumber2 = GetActorNumber(rider);
		if (actorNumber <= 0 || actorNumber2 <= 0 || actorNumber == actorNumber2)
		{
			return false;
		}
		RegisterPairActors(actorNumber, actorNumber2);
		BroadcastPairAction(1, actorNumber, actorNumber2);
		((MonoBehaviourPun)carrier).photonView.RPC("RPCA_StartCarry", (RpcTarget)0, new object[1] { ((MonoBehaviourPun)rider).photonView });
		if (!((Object)(object)carrier.data.carriedPlayer == (Object)(object)rider) || !rider.data.isCarried || !((Object)(object)rider.data.carrier == (Object)(object)carrier))
		{
			RemovePairsForActor(actorNumber2);
			BroadcastPairAction(3, actorNumber2, actorNumber);
			return false;
		}
		MakeRiderAlive(rider);
		return true;
	}

	internal static void PromoteCarrier(int actorNumber)
	{
		if (PhotonNetwork.IsMasterClient && actorNumber > 0)
		{
			PromoteActorToCarrier(actorNumber);
			BroadcastPairAction(2, actorNumber, 0);
		}
	}

	internal static bool IsActorLockedAsRider(int actorNumber)
	{
		return actorNumber > 0 && LockedRiderToCarrier.ContainsKey(actorNumber);
	}

	internal static bool IsActorLockedAsCarrier(int actorNumber)
	{
		if (actorNumber <= 0)
		{
			return false;
		}
		foreach (KeyValuePair<int, int> item in LockedRiderToCarrier)
		{
			if (item.Value == actorNumber)
			{
				return true;
			}
		}
		return false;
	}

	internal static void RemovePairsForActor(int actorNumber)
	{
		if (actorNumber <= 0 || LockedRiderToCarrier.Count == 0)
		{
			return;
		}
		List<int> list = null;
		foreach (KeyValuePair<int, int> item in LockedRiderToCarrier)
		{
			if (item.Key == actorNumber || item.Value == actorNumber)
			{
				if (list == null)
				{
					list = new List<int>();
				}
				list.Add(item.Key);
			}
		}
		if (list != null)
		{
			for (int i = 0; i < list.Count; i++)
			{
				LockedRiderToCarrier.Remove(list[i]);
			}
		}
	}

	internal static void ClearPairs()
	{
		LockedRiderToCarrier.Clear();
	}

	private static void RegisterPairActors(int carrierActor, int riderActor)
	{
		if (carrierActor > 0 && riderActor > 0 && carrierActor != riderActor)
		{
			RemovePairsForActor(riderActor);
			RemovePairsForActor(carrierActor);
			LockedRiderToCarrier[riderActor] = carrierActor;
		}
	}

	private static int GetActorNumber(Character character)
	{
		if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null || ((MonoBehaviourPun)character).photonView.Owner == null)
		{
			return -1;
		}
		return ((MonoBehaviourPun)character).photonView.Owner.ActorNumber;
	}

	private static bool IsLockedPair(Character carrier, Character rider)
	{
		if ((Object)(object)carrier == (Object)null || (Object)(object)rider == (Object)null)
		{
			return false;
		}
		int actorNumber = GetActorNumber(carrier);
		int actorNumber2 = GetActorNumber(rider);
		if (actorNumber <= 0 || actorNumber2 <= 0)
		{
			return false;
		}
		if (!LockedRiderToCarrier.TryGetValue(actorNumber2, out var value))
		{
			return false;
		}
		return value == actorNumber;
	}

	private static bool ShouldAllowRelease(Character carrier, Character rider)
	{
		if ((Object)(object)carrier == (Object)null || (Object)(object)rider == (Object)null || (Object)(object)carrier.data == (Object)null || (Object)(object)rider.data == (Object)null)
		{
			return true;
		}
		if (carrier.data.dead || rider.data.dead)
		{
			return true;
		}
		if (!rider.data.isCarried)
		{
			return true;
		}
		if ((Object)(object)rider.data.carrier != (Object)(object)carrier)
		{
			return true;
		}
		if ((Object)(object)carrier.data.carriedPlayer != (Object)(object)rider)
		{
			return true;
		}
		return false;
	}

	private static void MakeRiderAlive(Character rider)
	{
		if (!((Object)(object)rider == (Object)null) && !((Object)(object)rider.data == (Object)null) && !rider.data.dead)
		{
			rider.data.deathTimer = 0f;
			rider.data.passOutValue = 0f;
			rider.data.passedOutOnTheBeach = 0f;
			rider.data.fallSeconds = 0f;
			rider.data.passedOut = false;
			rider.data.fullyPassedOut = false;
			rider.data.ragdollControlClamp = 1f;
			rider.data.currentRagdollControll = 1f;
		}
	}

	private static void BroadcastPairAction(byte action, int firstActor, int secondActor)
	{
		//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_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Expected O, but got Unknown
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		if (PhotonNetwork.InRoom)
		{
			byte[] array = new byte[9];
			int offset = 0;
			array[offset++] = action;
			WriteInt32(array, ref offset, firstActor);
			WriteInt32(array, ref offset, secondActor);
			RaiseEventOptions val = new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)0
			};
			PhotonNetwork.RaiseEvent((byte)193, (object)array, val, SendOptions.SendReliable);
		}
	}

	private static void PromoteActorToCarrier(int actorNumber)
	{
		if (actorNumber <= 0)
		{
			return;
		}
		RemovePairsForActor(actorNumber);
		Character val = default(Character);
		if (!PlayerHandler.TryGetCharacter(actorNumber, ref val) || (Object)(object)val == (Object)null || (Object)(object)val.data == (Object)null)
		{
			return;
		}
		Character carrier = val.data.carrier;
		if ((Object)(object)carrier != (Object)null && (Object)(object)carrier.data != (Object)null && (Object)(object)carrier.data.carriedPlayer == (Object)(object)val)
		{
			carrier.data.carriedPlayer = null;
		}
		Character carriedPlayer = val.data.carriedPlayer;
		if ((Object)(object)carriedPlayer != (Object)null && (Object)(object)carriedPlayer.data != (Object)null && (Object)(object)carriedPlayer.data.carrier == (Object)(object)val)
		{
			carriedPlayer.data.carrier = null;
			carriedPlayer.data.isCarried = false;
		}
		val.data.isCarried = false;
		val.data.carrier = null;
		val.data.carriedPlayer = null;
		if (val.refs != null)
		{
			if ((Object)(object)val.refs.ragdoll != (Object)null)
			{
				val.refs.ragdoll.ToggleCollision(true);
			}
			if ((Object)(object)val.refs.animator != (Object)null)
			{
				val.refs.animator.SetBool("IsCarried", false);
			}
		}
		MakeRiderAlive(val);
	}

	private static void WriteInt32(byte[] buffer, ref int offset, int value)
	{
		buffer[offset++] = (byte)value;
		buffer[offset++] = (byte)(value >> 8);
		buffer[offset++] = (byte)(value >> 16);
		buffer[offset++] = (byte)(value >> 24);
	}

	private static int ReadInt32(byte[] buffer, ref int offset)
	{
		int result = buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24);
		offset += 4;
		return result;
	}
}
public sealed class LatejoinRuntime : MonoBehaviourPunCallbacks, IOnEventCallback
{
	private sealed class PendingPairPlan
	{
		public int ExistingActor;

		public int JoinActor;

		public int CarrierActor;

		public int RiderActor;
	}

	private const float ScanInterval = 0.5f;

	private readonly HashSet<int> knownActors = new HashSet<int>();

	private readonly HashSet<int> pendingJoinActors = new HashSet<int>();

	private readonly Dictionary<int, PendingPairPlan> pendingPairPlans = new Dictionary<int, PendingPairPlan>();

	private static readonly Random roleRandom = new Random();

	private bool runtimeInitialized;

	private string activeRoomName;

	private float nextScanTime;

	private bool needsSurvivorNormalization;

	internal void InitializeRuntime()
	{
		if (!runtimeInitialized)
		{
			runtimeInitialized = true;
			SceneManager.sceneLoaded += OnSceneLoaded;
			RefreshRoomSnapshot();
		}
	}

	internal void ShutdownRuntime()
	{
		if (runtimeInitialized)
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			knownActors.Clear();
			pendingJoinActors.Clear();
			pendingPairPlans.Clear();
			activeRoomName = null;
			needsSurvivorNormalization = false;
			runtimeInitialized = false;
		}
	}

	public override void OnEnable()
	{
		((MonoBehaviourPunCallbacks)this).OnEnable();
	}

	public override void OnDisable()
	{
		((MonoBehaviourPunCallbacks)this).OnDisable();
	}

	public void OnEvent(EventData photonEvent)
	{
		Latejoin.HandlePairEvent(photonEvent);
	}

	public override void OnJoinedRoom()
	{
		RefreshRoomSnapshot();
	}

	public override void OnLeftRoom()
	{
		knownActors.Clear();
		pendingJoinActors.Clear();
		pendingPairPlans.Clear();
		activeRoomName = null;
		needsSurvivorNormalization = false;
		Latejoin.ClearPairs();
	}

	public override void OnMasterClientSwitched(Player newMasterClient)
	{
		if (PhotonNetwork.IsMasterClient)
		{
			needsSurvivorNormalization = true;
		}
	}

	public override void OnPlayerEnteredRoom(Player newPlayer)
	{
		if (newPlayer != null)
		{
			int actorNumber = newPlayer.ActorNumber;
			knownActors.Add(actorNumber);
			pendingJoinActors.Add(actorNumber);
		}
	}

	public override void OnPlayerLeftRoom(Player otherPlayer)
	{
		if (otherPlayer != null)
		{
			int actorNumber = otherPlayer.ActorNumber;
			knownActors.Remove(actorNumber);
			pendingJoinActors.Remove(actorNumber);
			RemovePendingPairPlansForActor(actorNumber);
			Latejoin.RemovePairsForActor(actorNumber);
			needsSurvivorNormalization = true;
		}
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		pendingJoinActors.Clear();
		pendingPairPlans.Clear();
		needsSurvivorNormalization = false;
		Latejoin.ClearPairs();
		RefreshRoomSnapshot();
	}

	private void Update()
	{
		if (!runtimeInitialized)
		{
			return;
		}
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		if (realtimeSinceStartup < nextScanTime)
		{
			return;
		}
		nextScanTime = realtimeSinceStartup + 0.5f;
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			knownActors.Clear();
			pendingJoinActors.Clear();
			pendingPairPlans.Clear();
			activeRoomName = null;
			needsSurvivorNormalization = false;
			Latejoin.ClearPairs();
			return;
		}
		string name = PhotonNetwork.CurrentRoom.Name;
		if (!string.Equals(activeRoomName, name, StringComparison.Ordinal))
		{
			RefreshRoomSnapshot();
			return;
		}
		DetectNewActors();
		RemoveMissingActors();
		if (!PhotonNetwork.IsMasterClient || IsAirportScene())
		{
			return;
		}
		if (needsSurvivorNormalization)
		{
			if (!NormalizeSurvivorsAfterLeave())
			{
				return;
			}
			needsSurvivorNormalization = false;
		}
		ProcessPendingPairPlans();
		AssignPendingJoiners();
		AssignUnpairedSurvivors();
	}

	private void RefreshRoomSnapshot()
	{
		knownActors.Clear();
		pendingJoinActors.Clear();
		pendingPairPlans.Clear();
		needsSurvivorNormalization = false;
		Latejoin.ClearPairs();
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			activeRoomName = null;
			return;
		}
		activeRoomName = PhotonNetwork.CurrentRoom.Name;
		Player[] playerList = PhotonNetwork.PlayerList;
		if (playerList == null)
		{
			return;
		}
		foreach (Player val in playerList)
		{
			if (val != null)
			{
				knownActors.Add(val.ActorNumber);
			}
		}
	}

	private void DetectNewActors()
	{
		Player[] playerList = PhotonNetwork.PlayerList;
		if (playerList == null)
		{
			return;
		}
		foreach (Player val in playerList)
		{
			if (val != null)
			{
				int actorNumber = val.ActorNumber;
				if (knownActors.Add(actorNumber))
				{
					pendingJoinActors.Add(actorNumber);
				}
			}
		}
	}

	private void RemoveMissingActors()
	{
		if (knownActors.Count == 0)
		{
			return;
		}
		List<int> list = null;
		foreach (int knownActor in knownActors)
		{
			if (PhotonNetwork.CurrentRoom.GetPlayer(knownActor, false) == null)
			{
				if (list == null)
				{
					list = new List<int>();
				}
				list.Add(knownActor);
			}
		}
		if (list != null)
		{
			for (int i = 0; i < list.Count; i++)
			{
				int num = list[i];
				knownActors.Remove(num);
				pendingJoinActors.Remove(num);
				RemovePendingPairPlansForActor(num);
				Latejoin.RemovePairsForActor(num);
			}
		}
	}

	private bool NormalizeSurvivorsAfterLeave()
	{
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			return false;
		}
		Player[] playerList = PhotonNetwork.PlayerList;
		if (playerList == null || playerList.Length == 0)
		{
			return false;
		}
		if (playerList.Length == 1)
		{
			Player val = playerList[0];
			if (val == null)
			{
				return false;
			}
			Character character = default(Character);
			if (!PlayerHandler.TryGetCharacter(val.ActorNumber, ref character) || !CharacterReady(character))
			{
				return false;
			}
			Latejoin.PromoteCarrier(val.ActorNumber);
			return true;
		}
		List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
		if (allPlayerCharacters == null)
		{
			return false;
		}
		for (int i = 0; i < allPlayerCharacters.Count; i++)
		{
			Character val2 = allPlayerCharacters[i];
			if (!CharacterReady(val2))
			{
				continue;
			}
			int actorNumber = GetActorNumber(val2);
			if (actorNumber <= 0 || PhotonNetwork.CurrentRoom.GetPlayer(actorNumber, false) == null)
			{
				continue;
			}
			bool flag = false;
			if (val2.data.isCarried || (Object)(object)val2.data.carrier != (Object)null)
			{
				Character carrier = val2.data.carrier;
				int actorNumber2 = GetActorNumber(carrier);
				if ((Object)(object)carrier == (Object)null || actorNumber2 <= 0 || PhotonNetwork.CurrentRoom.GetPlayer(actorNumber2, false) == null)
				{
					flag = true;
				}
			}
			Character carriedPlayer = val2.data.carriedPlayer;
			if ((Object)(object)carriedPlayer != (Object)null)
			{
				int actorNumber3 = GetActorNumber(carriedPlayer);
				if (actorNumber3 <= 0 || PhotonNetwork.CurrentRoom.GetPlayer(actorNumber3, false) == null)
				{
					flag = true;
				}
			}
			if (flag)
			{
				Latejoin.PromoteCarrier(actorNumber);
			}
		}
		return true;
	}

	private void ProcessPendingPairPlans()
	{
		if (pendingPairPlans.Count != 0)
		{
			List<PendingPairPlan> list = new List<PendingPairPlan>(pendingPairPlans.Values);
			for (int i = 0; i < list.Count; i++)
			{
				TryCompletePendingPair(list[i]);
			}
		}
	}

	private static bool IsAirportScene()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		return ((Scene)(ref activeScene)).IsValid() && string.Equals(((Scene)(ref activeScene)).name, "Airport", StringComparison.Ordinal);
	}

	private void AssignUnpairedSurvivors()
	{
		if (IsAirportScene())
		{
			return;
		}
		List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
		if (allPlayerCharacters == null || allPlayerCharacters.Count < 2)
		{
			return;
		}
		List<Character> list = new List<Character>();
		for (int i = 0; i < allPlayerCharacters.Count; i++)
		{
			Character val = allPlayerCharacters[i];
			if (CharacterReady(val) && !val.data.dead)
			{
				int actorNumber = GetActorNumber(val);
				if (actorNumber > 0 && PhotonNetwork.CurrentRoom.GetPlayer(actorNumber, false) != null && !pendingJoinActors.Contains(actorNumber) && !ActorHasPendingPlan(actorNumber) && !IsActuallyPaired(val))
				{
					Latejoin.RemovePairsForActor(actorNumber);
					list.Add(val);
				}
			}
		}
		if (list.Count < 2)
		{
			return;
		}
		ShuffleCharacters(list);
		for (int j = 0; j + 1 < list.Count; j += 2)
		{
			Character val2 = list[j];
			Character val3 = list[j + 1];
			int actorNumber2 = GetActorNumber(val2);
			int actorNumber3 = GetActorNumber(val3);
			if (actorNumber2 > 0 && actorNumber3 > 0 && actorNumber2 != actorNumber3)
			{
				bool flag = roleRandom.Next(0, 2) == 0;
				PendingPairPlan value = new PendingPairPlan
				{
					ExistingActor = actorNumber2,
					JoinActor = actorNumber3,
					CarrierActor = (flag ? actorNumber3 : actorNumber2),
					RiderActor = (flag ? actorNumber2 : actorNumber3)
				};
				pendingPairPlans[actorNumber3] = value;
				WarpJoinerToExisting(val3, val2);
			}
		}
	}

	private bool ActorHasPendingPlan(int actorNumber)
	{
		if (actorNumber <= 0 || pendingPairPlans.Count == 0)
		{
			return false;
		}
		foreach (KeyValuePair<int, PendingPairPlan> pendingPairPlan in pendingPairPlans)
		{
			PendingPairPlan value = pendingPairPlan.Value;
			if (value == null || (value.JoinActor != actorNumber && value.ExistingActor != actorNumber && value.CarrierActor != actorNumber && value.RiderActor != actorNumber))
			{
				continue;
			}
			return true;
		}
		return false;
	}

	private static bool IsActuallyPaired(Character character)
	{
		if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null)
		{
			return false;
		}
		if (character.data.isCarried)
		{
			Character carrier = character.data.carrier;
			if ((Object)(object)carrier != (Object)null && (Object)(object)carrier.data != (Object)null && (Object)(object)carrier.data.carriedPlayer == (Object)(object)character)
			{
				return true;
			}
		}
		Character carriedPlayer = character.data.carriedPlayer;
		if ((Object)(object)carriedPlayer != (Object)null && (Object)(object)carriedPlayer.data != (Object)null && carriedPlayer.data.isCarried && (Object)(object)carriedPlayer.data.carrier == (Object)(object)character)
		{
			return true;
		}
		return false;
	}

	private static void ShuffleCharacters(List<Character> characters)
	{
		for (int num = characters.Count - 1; num > 0; num--)
		{
			int index = roleRandom.Next(0, num + 1);
			Character value = characters[num];
			characters[num] = characters[index];
			characters[index] = value;
		}
	}

	private void AssignPendingJoiners()
	{
		if (pendingJoinActors.Count == 0)
		{
			return;
		}
		List<int> list = new List<int>(pendingJoinActors);
		Character val = default(Character);
		for (int i = 0; i < list.Count; i++)
		{
			int num = list[i];
			if (PhotonNetwork.CurrentRoom.GetPlayer(num, false) == null)
			{
				pendingJoinActors.Remove(num);
				pendingPairPlans.Remove(num);
			}
			else
			{
				if (pendingPairPlans.ContainsKey(num) || !PlayerHandler.TryGetCharacter(num, ref val) || !CharacterReady(val) || val.data.dead)
				{
					continue;
				}
				if (IsCharacterAlreadyPaired(val, num))
				{
					pendingJoinActors.Remove(num);
					continue;
				}
				Character val2 = FindUnpairedExistingFor(num);
				if (!((Object)(object)val2 == (Object)null))
				{
					int actorNumber = GetActorNumber(val2);
					if (actorNumber > 0)
					{
						bool flag = roleRandom.Next(0, 2) == 0;
						PendingPairPlan value = new PendingPairPlan
						{
							ExistingActor = actorNumber,
							JoinActor = num,
							CarrierActor = (flag ? num : actorNumber),
							RiderActor = (flag ? actorNumber : num)
						};
						pendingPairPlans[num] = value;
						WarpJoinerToExisting(val, val2);
					}
				}
			}
		}
	}

	private void TryCompletePendingPair(PendingPairPlan plan)
	{
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		if (plan == null)
		{
			return;
		}
		if (PhotonNetwork.CurrentRoom.GetPlayer(plan.JoinActor, false) == null || PhotonNetwork.CurrentRoom.GetPlayer(plan.ExistingActor, false) == null)
		{
			pendingPairPlans.Remove(plan.JoinActor);
			pendingJoinActors.Remove(plan.JoinActor);
		}
		else
		{
			Character val = default(Character);
			Character val2 = default(Character);
			if (!PlayerHandler.TryGetCharacter(plan.JoinActor, ref val) || !PlayerHandler.TryGetCharacter(plan.ExistingActor, ref val2) || !CharacterReady(val) || !CharacterReady(val2) || val.data.dead || val2.data.dead)
			{
				return;
			}
			if (IsCharacterAlreadyPaired(val, plan.JoinActor) || IsCharacterAlreadyPaired(val2, plan.ExistingActor))
			{
				pendingPairPlans.Remove(plan.JoinActor);
				pendingJoinActors.Remove(plan.JoinActor);
			}
			else
			{
				if (val.warping)
				{
					return;
				}
				if (Vector3.Distance(val.Center, val2.Center) > 2f)
				{
					WarpJoinerToExisting(val, val2);
					return;
				}
				Character carrier = ((plan.CarrierActor == plan.JoinActor) ? val : val2);
				Character rider = ((plan.RiderActor == plan.JoinActor) ? val : val2);
				if (Latejoin.StartLatejoinPair(carrier, rider))
				{
					pendingPairPlans.Remove(plan.JoinActor);
					pendingJoinActors.Remove(plan.JoinActor);
				}
			}
		}
	}

	private static void WarpJoinerToExisting(Character joiner, Character existing)
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)joiner == (Object)null) && !((Object)(object)existing == (Object)null) && !((Object)(object)((MonoBehaviourPun)joiner).photonView == (Object)null))
		{
			((MonoBehaviourPun)joiner).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { existing.Center, false });
		}
	}

	private static bool IsCharacterAlreadyPaired(Character character, int actorNumber)
	{
		if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null)
		{
			return true;
		}
		return character.data.isCarried || (Object)(object)character.data.carrier != (Object)null || (Object)(object)character.data.carriedPlayer != (Object)null || Latejoin.IsActorLockedAsRider(actorNumber) || Latejoin.IsActorLockedAsCarrier(actorNumber);
	}

	private Character FindUnpairedExistingFor(int joinActor)
	{
		List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
		if (allPlayerCharacters == null || allPlayerCharacters.Count == 0)
		{
			return null;
		}
		Character result = null;
		int num = int.MaxValue;
		for (int i = 0; i < allPlayerCharacters.Count; i++)
		{
			Character val = allPlayerCharacters[i];
			if (CharacterReady(val))
			{
				int actorNumber = GetActorNumber(val);
				if (actorNumber > 0 && actorNumber != joinActor && !pendingJoinActors.Contains(actorNumber) && !val.data.dead && !IsCharacterAlreadyPaired(val, actorNumber) && actorNumber < num)
				{
					num = actorNumber;
					result = val;
				}
			}
		}
		return result;
	}

	private void RemovePendingPairPlansForActor(int actorNumber)
	{
		if (actorNumber <= 0 || pendingPairPlans.Count == 0)
		{
			return;
		}
		List<int> list = null;
		foreach (KeyValuePair<int, PendingPairPlan> pendingPairPlan in pendingPairPlans)
		{
			PendingPairPlan value = pendingPairPlan.Value;
			if (value == null || value.JoinActor == actorNumber || value.ExistingActor == actorNumber || value.CarrierActor == actorNumber || value.RiderActor == actorNumber)
			{
				if (list == null)
				{
					list = new List<int>();
				}
				list.Add(pendingPairPlan.Key);
			}
		}
		if (list == null)
		{
			return;
		}
		for (int i = 0; i < list.Count; i++)
		{
			int num = list[i];
			pendingPairPlans.Remove(num);
			if (num != actorNumber)
			{
				pendingJoinActors.Add(num);
			}
		}
	}

	private static bool CharacterReady(Character character)
	{
		return (Object)(object)character != (Object)null && (Object)(object)character.data != (Object)null && character.refs != null && (Object)(object)character.refs.carriying != (Object)null && (Object)(object)((MonoBehaviourPun)character).photonView != (Object)null && (Object)(object)character.player != (Object)null;
	}

	private static int GetActorNumber(Character character)
	{
		if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null || ((MonoBehaviourPun)character).photonView.Owner == null)
		{
			return -1;
		}
		return ((MonoBehaviourPun)character).photonView.Owner.ActorNumber;
	}
}
public sealed class PairPlayerStartLog : MonoBehaviour
{
	private const string LogColor = "#FFB347";

	private const float LogDuration = 8f;

	private static PairPlayerStartLog instance;

	private string currentDisplayedColoredText = "";

	private float nativeLogExpireTime = 0f;

	private Coroutine nativeLogCoroutine;

	public static void EnsureCreated()
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		if (!((Object)(object)instance != (Object)null))
		{
			GameObject val = new GameObject("PairPlayerStartLog");
			Object.DontDestroyOnLoad((Object)(object)val);
			instance = val.AddComponent<PairPlayerStartLog>();
		}
	}

	private void Awake()
	{
		if ((Object)(object)instance != (Object)null && (Object)(object)instance != (Object)(object)this)
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
			return;
		}
		instance = this;
		Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
	}

	private void OnDestroy()
	{
		if ((Object)(object)instance == (Object)(object)this)
		{
			instance = null;
		}
	}

	private string GetLocalizedMessage()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Expected I4, but got Unknown
		Language cURRENT_LANGUAGE = LocalizedText.CURRENT_LANGUAGE;
		Language val = cURRENT_LANGUAGE;
		return (int)val switch
		{
			0 => "An even number of players is required to start.", 
			1 => "Un nombre pair de joueurs est requis pour commencer.", 
			2 => "È necessario un numero pari di giocatori per iniziare.", 
			3 => "Zum Starten ist eine gerade Anzahl von Spielern erforderlich.", 
			4 => "Se necesita un número par de jugadores para empezar.", 
			5 => "Se necesita un número par de jugadores para comenzar.", 
			6 => "É necessário um número par de jogadores para começar.", 
			7 => "Для начала требуется четное количество игроков.", 
			8 => "Для початку потрібна парна кількість гравців.", 
			9 => "需要偶数名玩家才能开始游戏。", 
			10 => "需要偶數名玩家才能開始遊戲。", 
			11 => "開始するには偶数人のプレイヤーが必要です。", 
			12 => "짝수 플레이어가 있어야 시작할 수 있습니다.", 
			13 => "Do rozpoczęcia wymagana jest parzysta liczba graczy.", 
			14 => "Başlamak için çift sayıda oyuncu gereklidir.", 
			_ => "An even number of players is required to start.", 
		};
	}

	public static void ShowEvenPlayerRequired()
	{
		EnsureCreated();
		if (!((Object)(object)instance == (Object)null))
		{
			instance.ShowNativeGameLog();
		}
	}

	private void ShowNativeGameLog()
	{
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		PlayerConnectionLog val = Object.FindFirstObjectByType<PlayerConnectionLog>();
		if ((Object)(object)val == (Object)null)
		{
			Debug.LogWarning((object)"[PairPlayerStartLog] PlayerConnectionLog was not found.");
			return;
		}
		if ((Object)(object)val.text == (Object)null)
		{
			Debug.LogWarning((object)"[PairPlayerStartLog] PlayerConnectionLog text was not found.");
			return;
		}
		string localizedMessage = GetLocalizedMessage();
		string text = "<color=#FFB347>" + localizedMessage + "</color>";
		RemoveCurrentLogMessage(val);
		currentDisplayedColoredText = text;
		TextMeshProUGUI text2 = val.text;
		((TMP_Text)text2).text = ((TMP_Text)text2).text + text + "\n";
		if (Object.op_Implicit((Object)(object)val.sfxJoin))
		{
			val.sfxJoin.Play(default(Vector3));
		}
		else
		{
			Debug.LogWarning((object)"[PairPlayerStartLog] PEAK join sound was not found.");
		}
		nativeLogExpireTime = Time.realtimeSinceStartup + 8f;
		if (nativeLogCoroutine == null)
		{
			nativeLogCoroutine = ((MonoBehaviour)this).StartCoroutine(NativeLogTimeoutRoutine());
		}
	}

	private void RemoveCurrentLogMessage(PlayerConnectionLog playerLog)
	{
		if (!((Object)(object)playerLog == (Object)null) && !((Object)(object)playerLog.text == (Object)null) && !string.IsNullOrEmpty(currentDisplayedColoredText))
		{
			string oldValue = currentDisplayedColoredText + "\n";
			((TMP_Text)playerLog.text).text = ((TMP_Text)playerLog.text).text.Replace(oldValue, "");
		}
	}

	private IEnumerator NativeLogTimeoutRoutine()
	{
		while (Time.realtimeSinceStartup < nativeLogExpireTime)
		{
			yield return null;
		}
		PlayerConnectionLog playerLog = Object.FindFirstObjectByType<PlayerConnectionLog>();
		if ((Object)(object)playerLog != (Object)null && (Object)(object)playerLog.text != (Object)null)
		{
			RemoveCurrentLogMessage(playerLog);
		}
		currentDisplayedColoredText = "";
		nativeLogCoroutine = null;
	}
}
public static class OnlyEven
{
	[HarmonyPatch(typeof(AirportCheckInKiosk), "StartGame", new Type[] { typeof(int) })]
	private static class AirportCheckInKiosk_StartGame_Patch
	{
		private static bool Prefix()
		{
			if (CanStartGame())
			{
				return true;
			}
			ShowBlockedMessage("Game start");
			return false;
		}
	}

	[HarmonyPatch(typeof(AirportCheckInKiosk), "LoadIslandMaster", new Type[]
	{
		typeof(int),
		typeof(byte[])
	})]
	private static class AirportCheckInKiosk_LoadIslandMaster_Patch
	{
		private static bool Prefix()
		{
			if (CanStartGame())
			{
				return true;
			}
			ShowBlockedMessage("Master scene load");
			return false;
		}
	}

	private const string HarmonyId = "com.peak.coopmod.onlyeven";

	private static Harmony harmony;

	private static bool initialized;

	public static ConfigEntry<bool> AllowOnePlayer;

	public static ConfigEntry<bool> AllowThreePlayers;

	public static void Initialize(CoopMod plugin)
	{
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		if (!initialized)
		{
			if ((Object)(object)plugin == (Object)null)
			{
				Debug.LogError((object)"[OnlyEven] CoopMod instance is null.");
				return;
			}
			AllowOnePlayer = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Player Count", "Allow 1 Player", false, "1명인 상태에서도 게임 시작을 허용합니다.");
			AllowThreePlayers = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Player Count", "Allow 3 Players", false, "3명인 상태에서도 게임 시작을 허용합니다.");
			harmony = new Harmony("com.peak.coopmod.onlyeven");
			harmony.CreateClassProcessor(typeof(AirportCheckInKiosk_StartGame_Patch)).Patch();
			harmony.CreateClassProcessor(typeof(AirportCheckInKiosk_LoadIslandMaster_Patch)).Patch();
			initialized = true;
			Debug.Log((object)"[OnlyEven] Initialized.");
			Debug.Log((object)("[OnlyEven] Allow 1 Player: " + AllowOnePlayer.Value));
			Debug.Log((object)("[OnlyEven] Allow 3 Players: " + AllowThreePlayers.Value));
		}
	}

	public static void Shutdown()
	{
		if (initialized)
		{
			if (harmony != null)
			{
				harmony.UnpatchSelf();
				harmony = null;
			}
			AllowOnePlayer = null;
			AllowThreePlayers = null;
			initialized = false;
			Debug.Log((object)"[OnlyEven] Shutdown.");
		}
	}

	public static int GetCurrentPlayerCount()
	{
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			return 0;
		}
		return PhotonNetwork.CurrentRoom.PlayerCount;
	}

	public static bool CanStartGame()
	{
		int currentPlayerCount = GetCurrentPlayerCount();
		if (currentPlayerCount >= 2 && currentPlayerCount % 2 == 0)
		{
			return true;
		}
		if (currentPlayerCount == 1 && AllowOnePlayer != null && AllowOnePlayer.Value)
		{
			return true;
		}
		if (currentPlayerCount == 3 && AllowThreePlayers != null && AllowThreePlayers.Value)
		{
			return true;
		}
		return false;
	}

	private static void ShowBlockedMessage(string source)
	{
		Debug.Log((object)("[OnlyEven] " + source + " blocked. PlayerCount=" + GetCurrentPlayerCount()));
		PairPlayerStartLog.ShowEvenPlayerRequired();
	}
}
public static class Piggyback
{
	public enum RolePreferenceMode : byte
	{
		Random,
		Climber,
		Carrier
	}

	[HarmonyPatch(typeof(CharacterCarrying), "RPCA_StartCarry", new Type[] { typeof(PhotonView) })]
	private static class CharacterCarrying_RPCA_StartCarry_Patch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(CharacterCarrying __instance, PhotonView targetView)
		{
			if (initialPairingWindow && !((Object)(object)__instance == (Object)null) && !((Object)(object)targetView == (Object)null))
			{
				Character component = ((Component)__instance).GetComponent<Character>();
				Character component2 = ((Component)targetView).GetComponent<Character>();
				if (CharacterReady(component) && CharacterReady(component2) && !((Object)(object)component.data.carriedPlayer != (Object)(object)component2) && component2.data.isCarried && !((Object)(object)component2.data.carrier != (Object)(object)component))
				{
					RegisterLockedPair(component, component2);
					MakeRiderAlive(component2);
				}
			}
		}
	}

	[HarmonyPatch(typeof(CharacterCarrying), "Update")]
	private static class CharacterCarrying_Update_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(CharacterCarrying __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			if ((Object)(object)component == (Object)null || (Object)(object)component.data == (Object)null)
			{
				return true;
			}
			Character carriedPlayer = component.data.carriedPlayer;
			if (!IsLockedPair(component, carriedPlayer))
			{
				return true;
			}
			if (ShouldAllowRelease(component, carriedPlayer))
			{
				return true;
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(CharacterCarrying), "Drop", new Type[] { typeof(Character) })]
	private static class CharacterCarrying_Drop_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(CharacterCarrying __instance, Character target)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)target == (Object)null)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			if (!IsLockedPair(component, target))
			{
				return true;
			}
			return ShouldAllowRelease(component, target);
		}
	}

	[HarmonyPatch(typeof(CharacterCarrying), "RPCA_Drop", new Type[] { typeof(PhotonView) })]
	private static class CharacterCarrying_RPCA_Drop_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(CharacterCarrying __instance, PhotonView targetView)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)targetView == (Object)null)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			Character component2 = ((Component)targetView).GetComponent<Character>();
			if (!IsLockedPair(component, component2))
			{
				return true;
			}
			return ShouldAllowRelease(component, component2);
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(CharacterCarrying __instance, PhotonView targetView)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)targetView == (Object)null))
			{
				Character component = ((Component)__instance).GetComponent<Character>();
				Character component2 = ((Component)targetView).GetComponent<Character>();
				if (!((Object)(object)component2 == (Object)null) && !((Object)(object)component2.data == (Object)null) && (!component2.data.isCarried || !((Object)(object)component2.data.carrier == (Object)(object)component)))
				{
					RemoveLockedPair(component, component2);
				}
			}
		}
	}

	private const string HarmonyId = "com.peak.coopmod.piggyback";

	private const float CharacterSpawnTimeout = 30f;

	private const string RolePreferencePropertyKey = "CoopMod.RolePreference";

	public static ConfigEntry<RolePreferenceMode> RolePreference;

	private static Harmony harmony;

	private static CoopMod plugin;

	private static Coroutine assignmentCoroutine;

	private static bool initialPairingWindow;

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

	public static void Initialize(CoopMod owner)
	{
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Expected O, but got Unknown
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		if (harmony == null && !((Object)(object)owner == (Object)null))
		{
			plugin = owner;
			RolePreference = ((BaseUnityPlugin)plugin).Config.Bind<RolePreferenceMode>("Co-op Role", "Role Preference", RolePreferenceMode.Random, "역할 배정 선호도입니다. Random은 무작위, Climber는 등반자만, Carrier는 운반자만 배정됩니다.");
			RolePreference.SettingChanged += OnRolePreferenceChanged;
			PublishLocalRolePreference();
			harmony = new Harmony("com.peak.coopmod.piggyback");
			Patch(typeof(CharacterCarrying_RPCA_StartCarry_Patch));
			Patch(typeof(CharacterCarrying_Update_Patch));
			Patch(typeof(CharacterCarrying_Drop_Patch));
			Patch(typeof(CharacterCarrying_RPCA_Drop_Patch));
			SceneManager.sceneLoaded += OnSceneLoaded;
			HandleSceneLoaded(SceneManager.GetActiveScene());
		}
	}

	public static void Shutdown()
	{
		SceneManager.sceneLoaded -= OnSceneLoaded;
		StopAssignmentCoroutine();
		LockedRiderToCarrier.Clear();
		initialPairingWindow = false;
		if (RolePreference != null)
		{
			RolePreference.SettingChanged -= OnRolePreferenceChanged;
			RolePreference = null;
		}
		if (harmony != null)
		{
			harmony.UnpatchSelf();
			harmony = null;
		}
		plugin = null;
	}

	private static void Patch(Type patchType)
	{
		harmony.CreateClassProcessor(patchType).Patch();
	}

	private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		HandleSceneLoaded(scene);
	}

	private static void HandleSceneLoaded(Scene scene)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		StopAssignmentCoroutine();
		LockedRiderToCarrier.Clear();
		initialPairingWindow = false;
		if (!((Object)(object)plugin == (Object)null) && IsGameplayScene(scene))
		{
			initialPairingWindow = true;
			assignmentCoroutine = ((MonoBehaviour)plugin).StartCoroutine(WaitForPlayersAndAssignTeams());
		}
	}

	private static void StopAssignmentCoroutine()
	{
		if ((Object)(object)plugin != (Object)null && assignmentCoroutine != null)
		{
			((MonoBehaviour)plugin).StopCoroutine(assignmentCoroutine);
		}
		assignmentCoroutine = null;
	}

	private static bool IsGameplayScene(Scene scene)
	{
		if (!((Scene)(ref scene)).IsValid())
		{
			return false;
		}
		return ((Scene)(ref scene)).name.Contains("Island") || ((Scene)(ref scene)).name.Contains("Level_");
	}

	private static bool IsOnShore()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Invalid comparison between Unknown and I4
		if (!GameHandler.IsOnIsland)
		{
			return false;
		}
		return (int)MapHandler.CurrentSegmentNumber == 0;
	}

	private static IEnumerator WaitForPlayersAndAssignTeams()
	{
		float timeoutTime = Time.realtimeSinceStartup + 30f;
		while (Time.realtimeSinceStartup < timeoutTime)
		{
			if ((Object)(object)plugin == (Object)null)
			{
				assignmentCoroutine = null;
				yield break;
			}
			if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
			{
				yield return null;
				continue;
			}
			PublishLocalRolePreference();
			if (!GameHandler.IsOnIsland)
			{
				yield return null;
				continue;
			}
			if (!IsOnShore())
			{
				initialPairingWindow = false;
				assignmentCoroutine = null;
				yield break;
			}
			int playerCount = PhotonNetwork.CurrentRoom.PlayerCount;
			if (playerCount != 2 && playerCount != 4)
			{
				initialPairingWindow = false;
				assignmentCoroutine = null;
				yield break;
			}
			if (!PhotonNetwork.IsMasterClient)
			{
				assignmentCoroutine = null;
				yield break;
			}
			if (AllPlayerCharactersReady() && AllRolePreferencesReady())
			{
				AssignTeamsByPreference();
				assignmentCoroutine = null;
				yield break;
			}
			yield return null;
		}
		initialPairingWindow = false;
		assignmentCoroutine = null;
	}

	private static bool AllPlayerCharactersReady()
	{
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			return false;
		}
		Player[] playerList = PhotonNetwork.PlayerList;
		if (playerList == null || playerList.Length != PhotonNetwork.CurrentRoom.PlayerCount)
		{
			return false;
		}
		if (playerList.Length != 2 && playerList.Length != 4)
		{
			return false;
		}
		Character character = default(Character);
		for (int i = 0; i < playerList.Length; i++)
		{
			if (!PlayerHandler.TryGetCharacter(playerList[i].ActorNumber, ref character))
			{
				return false;
			}
			if (!CharacterReady(character))
			{
				return false;
			}
		}
		return true;
	}

	private static bool CharacterReady(Character character)
	{
		return (Object)(object)character != (Object)null && (Object)(object)character.data != (Object)null && character.refs != null && (Object)(object)character.refs.carriying != (Object)null && (Object)(object)((MonoBehaviourPun)character).photonView != (Object)null && (Object)(object)character.player != (Object)null;
	}

	private static void OnRolePreferenceChanged(object sender, EventArgs e)
	{
		PublishLocalRolePreference();
	}

	private static void PublishLocalRolePreference()
	{
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Expected O, but got Unknown
		//IL_00ae: Expected O, but got Unknown
		if (RolePreference != null && PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null)
		{
			byte value = (byte)RolePreference.Value;
			if (PhotonNetwork.LocalPlayer.CustomProperties == null || !((Dictionary<object, object>)(object)PhotonNetwork.LocalPlayer.CustomProperties).TryGetValue((object)"CoopMod.RolePreference", out object value2) || ((!(value2 is byte) || (byte)value2 != value) && (!(value2 is int) || (int)value2 != value)))
			{
				Hashtable val = new Hashtable();
				((Dictionary<object, object>)val).Add((object)"CoopMod.RolePreference", (object)value);
				Hashtable val2 = val;
				PhotonNetwork.LocalPlayer.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null);
			}
		}
	}

	private static bool AllRolePreferencesReady()
	{
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			return false;
		}
		Player[] playerList = PhotonNetwork.PlayerList;
		if (playerList == null || playerList.Length == 0)
		{
			return false;
		}
		for (int i = 0; i < playerList.Length; i++)
		{
			if (playerList[i] == null || playerList[i].CustomProperties == null || !((Dictionary<object, object>)(object)playerList[i].CustomProperties).ContainsKey((object)"CoopMod.RolePreference"))
			{
				return false;
			}
		}
		return true;
	}

	private static RolePreferenceMode GetRolePreference(Player player)
	{
		if (player == null || player.CustomProperties == null)
		{
			return RolePreferenceMode.Random;
		}
		if (!((Dictionary<object, object>)(object)player.CustomProperties).TryGetValue((object)"CoopMod.RolePreference", out object value))
		{
			return RolePreferenceMode.Random;
		}
		if (value is byte b && b <= 2)
		{
			return (RolePreferenceMode)b;
		}
		if (value is int num && num >= 0 && num <= 2)
		{
			return (RolePreferenceMode)num;
		}
		return RolePreferenceMode.Random;
	}

	private static void Shuffle(List<int> values, Random random)
	{
		if (values != null && random != null)
		{
			for (int num = values.Count - 1; num > 0; num--)
			{
				int index = random.Next(num + 1);
				int value = values[num];
				values[num] = values[index];
				values[index] = value;
			}
		}
	}

	private static void AssignTeamsByPreference()
	{
		if (!PhotonNetwork.IsMasterClient || !PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			return;
		}
		Player[] playerList = PhotonNetwork.PlayerList;
		if (playerList == null || (playerList.Length != 2 && playerList.Length != 4))
		{
			return;
		}
		int num = playerList.Length / 2;
		List<int> list = new List<int>(num);
		List<int> list2 = new List<int>(num);
		List<int> list3 = new List<int>(playerList.Length);
		for (int i = 0; i < playerList.Length; i++)
		{
			switch (GetRolePreference(playerList[i]))
			{
			case RolePreferenceMode.Carrier:
				list.Add(playerList[i].ActorNumber);
				break;
			case RolePreferenceMode.Climber:
				list2.Add(playerList[i].ActorNumber);
				break;
			default:
				list3.Add(playerList[i].ActorNumber);
				break;
			}
		}
		if (list.Count > num || list2.Count > num)
		{
			initialPairingWindow = false;
			return;
		}
		int num2 = num - list.Count;
		int num3 = num - list2.Count;
		if (num2 + num3 != list3.Count)
		{
			initialPairingWindow = false;
			return;
		}
		Random random = new Random(Environment.TickCount ^ PhotonNetwork.ServerTimestamp);
		Shuffle(list3, random);
		for (int j = 0; j < num2; j++)
		{
			list.Add(list3[j]);
		}
		for (int k = num2; k < list3.Count; k++)
		{
			list2.Add(list3[k]);
		}
		Shuffle(list, random);
		Shuffle(list2, random);
		Character val = default(Character);
		Character val2 = default(Character);
		for (int l = 0; l < num; l++)
		{
			if (PlayerHandler.TryGetCharacter(list[l], ref val) && PlayerHandler.TryGetCharacter(list2[l], ref val2) && CharacterReady(val) && CharacterReady(val2) && !((Object)(object)val == (Object)(object)val2) && !((Object)(object)val.data.carriedPlayer != (Object)null) && !val2.data.isCarried && !((Object)(object)val2.data.carrier != (Object)null) && !val.data.dead && !val2.data.dead)
			{
				((MonoBehaviourPun)val).photonView.RPC("RPCA_StartCarry", (RpcTarget)0, new object[1] { ((MonoBehaviourPun)val2).photonView });
			}
		}
	}

	private static int GetActorNumber(Character character)
	{
		if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null || ((MonoBehaviourPun)character).photonView.Owner == null)
		{
			return -1;
		}
		return ((MonoBehaviourPun)character).photonView.Owner.ActorNumber;
	}

	private static void RegisterLockedPair(Character carrier, Character rider)
	{
		if (!CharacterReady(carrier) || !CharacterReady(rider))
		{
			return;
		}
		int actorNumber = GetActorNumber(carrier);
		int actorNumber2 = GetActorNumber(rider);
		if (actorNumber > 0 && actorNumber2 > 0 && actorNumber != actorNumber2)
		{
			LockedRiderToCarrier[actorNumber2] = actorNumber;
			int expectedPairCount = GetExpectedPairCount();
			if (expectedPairCount > 0 && LockedRiderToCarrier.Count >= expectedPairCount)
			{
				initialPairingWindow = false;
			}
		}
	}

	private static void RemoveLockedPair(Character carrier, Character rider)
	{
		if ((Object)(object)rider == (Object)null)
		{
			return;
		}
		int actorNumber = GetActorNumber(rider);
		if (actorNumber <= 0 || !LockedRiderToCarrier.TryGetValue(actorNumber, out var value))
		{
			return;
		}
		if ((Object)(object)carrier != (Object)null)
		{
			int actorNumber2 = GetActorNumber(carrier);
			if (actorNumber2 > 0 && value != actorNumber2)
			{
				return;
			}
		}
		LockedRiderToCarrier.Remove(actorNumber);
	}

	private static bool IsLockedPair(Character carrier, Character rider)
	{
		if ((Object)(object)carrier == (Object)null || (Object)(object)rider == (Object)null)
		{
			return false;
		}
		int actorNumber = GetActorNumber(carrier);
		int actorNumber2 = GetActorNumber(rider);
		if (actorNumber <= 0 || actorNumber2 <= 0)
		{
			return false;
		}
		if (!LockedRiderToCarrier.TryGetValue(actorNumber2, out var value))
		{
			return false;
		}
		return value == actorNumber;
	}

	private static int GetExpectedPairCount()
	{
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			return 0;
		}
		return PhotonNetwork.CurrentRoom.PlayerCount switch
		{
			2 => 1, 
			4 => 2, 
			_ => 0, 
		};
	}

	private static Character ResolveCharacter(Component component)
	{
		if ((Object)(object)component == (Object)null)
		{
			return null;
		}
		Character component2 = component.GetComponent<Character>();
		if ((Object)(object)component2 != (Object)null)
		{
			return component2;
		}
		return component.GetComponentInParent<Character>();
	}

	private static void MakeRiderAlive(Character rider)
	{
		if (!((Object)(object)rider == (Object)null) && !((Object)(object)rider.data == (Object)null) && !rider.data.dead)
		{
			rider.data.deathTimer = 0f;
			rider.data.passOutValue = 0f;
			rider.data.passedOutOnTheBeach = 0f;
			rider.data.fallSeconds = 0f;
			rider.data.passedOut = false;
			rider.data.fullyPassedOut = false;
			rider.data.ragdollControlClamp = 1f;
			rider.data.currentRagdollControll = 1f;
		}
	}

	private static bool ShouldAllowRelease(Character carrier, Character rider)
	{
		if ((Object)(object)carrier == (Object)null || (Object)(object)rider == (Object)null || (Object)(object)carrier.data == (Object)null || (Object)(object)rider.data == (Object)null)
		{
			return true;
		}
		if (carrier.data.dead || rider.data.dead)
		{
			return true;
		}
		if (!rider.data.isCarried)
		{
			return true;
		}
		if ((Object)(object)rider.data.carrier != (Object)(object)carrier)
		{
			return true;
		}
		if ((Object)(object)carrier.data.carriedPlayer != (Object)(object)rider)
		{
			return true;
		}
		return false;
	}
}
public static class Rolechanger
{
	private sealed class PairActors
	{
		public int CarrierActor;

		public int RiderActor;
	}

	[HarmonyPatch(typeof(Campfire), "Light_Rpc", new Type[]
	{
		typeof(bool),
		typeof(float)
	})]
	private static class Campfire_LightRpc_Patch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(Campfire __instance, bool updateSegment)
		{
			if (!((Object)(object)__instance == (Object)null) && updateSegment && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
			{
				PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
				if (!((Object)(object)component == (Object)null) && component.ViewID > 0)
				{
					RequestCampfireShuffle(component.ViewID);
				}
			}
		}
	}

	[HarmonyPatch(typeof(CharacterCarrying), "Update")]
	private static class CharacterCarrying_Update_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(CharacterCarrying __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			if ((Object)(object)component == (Object)null || (Object)(object)component.data == (Object)null)
			{
				return true;
			}
			Character carriedPlayer = component.data.carriedPlayer;
			if (!IsLockedPair(component, carriedPlayer))
			{
				return true;
			}
			return ShouldAllowRelease(component, carriedPlayer);
		}
	}

	[HarmonyPatch(typeof(CharacterCarrying), "Drop", new Type[] { typeof(Character) })]
	private static class CharacterCarrying_Drop_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(CharacterCarrying __instance, Character target)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)target == (Object)null)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			if (!IsLockedPair(component, target))
			{
				return true;
			}
			return ShouldAllowRelease(component, target);
		}
	}

	[HarmonyPatch(typeof(CharacterCarrying), "RPCA_Drop", new Type[] { typeof(PhotonView) })]
	private static class CharacterCarrying_RPCA_Drop_Patch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(CharacterCarrying __instance, PhotonView targetView)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)targetView == (Object)null)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			Character component2 = ((Component)targetView).GetComponent<Character>();
			if (!IsLockedPair(component, component2))
			{
				return true;
			}
			return ShouldAllowRelease(component, component2);
		}
	}

	private const string HarmonyId = "com.peak.coopmod.rolechanger";

	private const byte SwapEventCode = 194;

	private const byte ShuffleAction = 1;

	private static Harmony harmony;

	private static CoopMod plugin;

	private static RolechangerRuntime runtime;

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

	private static readonly Random random = new Random();

	public static void Initialize(CoopMod owner)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		if (harmony == null && !((Object)(object)owner == (Object)null))
		{
			plugin = owner;
			harmony = new Harmony("com.peak.coopmod.rolechanger");
			Patch(typeof(Campfire_LightRpc_Patch));
			Patch(typeof(Charact