Decompiled source of CoopMod v0.2.7
CoopMod.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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