using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using Characters; using Characters.AI; using Characters.Actions; using Characters.Controllers; using Characters.Gear; using Characters.Gear.Items; using Characters.Gear.Quintessences; using Characters.Gear.Weapons; using Characters.Operations.Attack; using Characters.Operations.Fx; using Characters.Player; using Characters.Projectiles; using Data; using GameResources; using HarmonyLib; using Level; using Level.Npc; using Microsoft.CodeAnalysis; using Services; using Singletons; using Steamworks; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("SkulOnlineCoopV1.Runtime")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SkulOnlineCoopV1.Runtime")] [assembly: AssemblyTitle("SkulOnlineCoopV1.Runtime")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SkulOnlineCoopV1.Runtime { [BepInPlugin("com.codex.skul.onlinecoop.v1.runtime", "Skul Online Co-op v1 Runtime", "1.0.88")] public sealed class CoopRuntimePlugin : BaseUnityPlugin { private struct ReplicatedAnimatorState { internal int StateHash; internal float NormalizedTime; } private sealed class GearReferenceComparer : IEqualityComparer { internal static readonly GearReferenceComparer Instance = new GearReferenceComparer(); public bool Equals(Gear? left, Gear? right) { return left == right; } public int GetHashCode(Gear gear) { return RuntimeHelpers.GetHashCode(gear); } } private readonly struct PendingStage { internal readonly int Chapter; internal readonly int Stage; internal readonly int Path; internal readonly int Node; internal readonly int Seed; internal PendingStage(int chapter, int stage, int path, int node, int seed) { Chapter = chapter; Stage = stage; Path = path; Node = node; Seed = seed; } } internal readonly struct DismantleReward { internal readonly uint DropId; internal readonly Type Type; internal readonly int Amount; internal DismantleReward(uint dropId, Type type, int amount) { //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) DropId = dropId; Type = type; Amount = amount; } } private readonly struct PendingClientWorldDrop { internal readonly byte Kind; internal readonly string Key; internal readonly Vector3 Position; internal readonly DroppedGear? Dropped; internal PendingClientWorldDrop(byte kind, string key, Vector3 position, DroppedGear? dropped) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Kind = kind; Key = key; Position = position; Dropped = dropped; } } internal static ManualLogSource Log; private Callback? _lobbyCreated; private Callback? _lobbyEntered; private Callback? _joinRequested; private Callback? _p2pRequested; private CSteamID _lobbyId; private float _nextTransformAt; private const int P2pChannel = 92; private const byte Protocol = 54; private const byte PlayerTransformPacket = 1; private const byte PlayerActionPacket = 2; private const byte WeaponStatePacket = 3; private const byte EnemySnapshotPacket = 4; private const byte ItemStatePacket = 5; private const byte EnemyDamageRequestPacket = 6; private const byte MapTransitionRequestPacket = 7; private const byte MapTransitionCommitPacket = 8; private const byte StageRequestPacket = 9; private const byte StageStatePacket = 10; private const byte PlayerHealthAuthorityPacket = 11; private const byte EnemyActionPacket = 12; private const byte WorldGearSpawnPacket = 13; private const byte WorldGearInteractionRequestPacket = 14; private const byte WorldGearDespawnPacket = 15; private const byte WorldGearSpawnRequestPacket = 16; private const byte WorldGearDismantleRewardRequestPacket = 17; private const byte WorldGearDismantleRewardGrantPacket = 18; private const byte WorldGearSpawnAcknowledgementPacket = 19; private const byte RewardObjectInteractionRequestPacket = 20; private const byte RewardObjectConsumedPacket = 21; private const byte GatesActivatedPacket = 22; private const byte CastleExitRequestPacket = 23; private const byte CastleExitCommitPacket = 24; private const byte EnemyLineTextPacket = 25; private float _nextEnemySnapshotAt; private float _nextHostEnemyTargetRefreshAt; private int _clientEnemyMapId; private float _nextClientEnemyCandidateRefreshAt; private float _nextWorldDropAt; private int _clientDropMapId; private bool _clientWorldAuthorityEstablished; private readonly HashSet _pendingWorldGearDrops = new HashSet(); private readonly HashSet _advertisedWorldGearDrops = new HashSet(); private readonly HashSet _requestedClientWorldGear = new HashSet(GearReferenceComparer.Instance); private readonly HashSet _replicatedClientGear = new HashSet(GearReferenceComparer.Instance); private readonly Dictionary _pendingClientWorldDrops = new Dictionary(); private uint _nextChestRewardGroupId; private readonly Dictionary> _chestRewardDropIds = new Dictionary>(); private readonly Dictionary> _chestRewardSelections = new Dictionary>(); private readonly HashSet _trackedHostChests = new HashSet(); private uint _nextClientWorldDropRequestId; private int _replicatedWorldGearCreationDepth; private int _replicatedNativeDropCallDepth; private readonly HashSet _applyingReplicatedItems = new HashSet(); private bool _advertiseFreshRunLocalItems; private PendingStage? _pendingStage; private PendingStage? _lastAppliedHostStage; private bool _applyingHostStage; private bool _applyingAuthoritativeCastleExit; private bool _resetPendingRun; private float _nextStageAdvertAt; private float _nextStageRequestAt; private bool _awaitingInitialHostStage; private uint _localStateSequence; private bool _steamReady; private float _nextSteamInitializationAttempt; private readonly Dictionary _enemyAnimatorStates = new Dictionary(); private readonly Dictionary _generatedEnemyHealthBars = new Dictionary(); private readonly Dictionary _replicatedEnemyHealth = new Dictionary(); private readonly Dictionary _replicatedEnemyHealthBarExpiry = new Dictionary(); private readonly HashSet _openedRandomWeaponBoxes = new HashSet(); private readonly HashSet _loggedUnboundEnemySnapshots = new HashSet(); private readonly List _clientEnemyCandidates = new List(); private string _lastAdvertisedWeaponState = string.Empty; private readonly HashSet _loggedLocalActionDiagnostics = new HashSet(); internal static CoopRuntimePlugin? Instance { get; private set; } internal CoopPlayerRegistry Players { get; } = new CoopPlayerRegistry(); internal CoopWorldRegistry World { get; } = new CoopWorldRegistry(); internal CoopDropRegistry Drops { get; } = new CoopDropRegistry(); private bool CreatingReplicatedWorldGear => _replicatedWorldGearCreationDepth > 0; private bool CreatingReplicatedNativeDrop => _replicatedNativeDropCallDepth > 0; internal bool IsHostAuthority => IsHost(); private void Awake() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Harmony val = new Harmony("com.codex.skul.onlinecoop.v1.runtime"); foreach (Type item in from candidate in ((object)this).GetType().Assembly.GetTypes() where candidate.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0 select candidate) { try { val.CreateClassProcessor(item).Patch(); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Skipped Harmony patch {item.FullName}: {arg}"); } } } private bool EnsureSteamReady() { if (_steamReady) { return true; } if (Time.unscaledTime < _nextSteamInitializationAttempt) { return false; } _nextSteamInitializationAttempt = Time.unscaledTime + 1f; try { _lobbyCreated = Callback.Create((DispatchDelegate)OnLobbyCreated); _lobbyEntered = Callback.Create((DispatchDelegate)OnLobbyEntered); _joinRequested = Callback.Create((DispatchDelegate)OnJoinRequested); _p2pRequested = Callback.Create((DispatchDelegate)OnP2pRequested); SteamNetworking.AllowP2PPacketRelay(true); _steamReady = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Steamworks callbacks initialized."); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Steamworks not ready yet: " + ex.Message)); return false; } } private void Update() { if (EnsureSteamReady()) { if (Input.GetKeyDown((KeyCode)287)) { CreateOrInviteLobby(); } if (Input.GetKeyDown((KeyCode)288)) { RefreshStageSync(); } if (Input.GetKeyDown((KeyCode)289)) { ApplyPendingStage(); } if (Input.GetKeyDown((KeyCode)290)) { LeaveLobby(); } RegisterLobbyPlayersWhenReady(); AdvertiseLocalLoadoutIfChanged(); ResetClientEnemyRegistryForMapChange(); RefreshClientEnemyCandidates(); ReceivePackets(); KeepReplicatedEnemyHealthBarsVisible(); RequestInitialHostStageUntilReceived(); EnforceHostWorldDropAuthority(); DisableClientEnemySimulation(); RefreshHostEnemyTargets(); SendLocalTransform(); SendEnemySnapshots(); SendWorldGearSpawns(); AdvertiseHostStageWhenReady(); } } private void OnDestroy() { LeaveLobby(); } private void CreateOrInviteLobby() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID != 0L) { SteamFriends.ActivateGameOverlayInviteDialog(_lobbyId); return; } SteamMatchmaking.CreateLobby((ELobbyType)1, 2); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Creating v1 two-player Steam lobby."); } private void OnLobbyCreated(LobbyCreated_t callback) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if ((int)callback.m_eResult != 1) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Lobby creation failed: {callback.m_eResult}"); return; } _lobbyId = new CSteamID(callback.m_ulSteamIDLobby); SteamMatchmaking.SetLobbyData(_lobbyId, "skul_online_coop_v1", "1"); SteamMatchmaking.SetLobbyData(_lobbyId, "host", SteamUser.GetSteamID().m_SteamID.ToString()); SteamFriends.ActivateGameOverlayInviteDialog(_lobbyId); } private void OnJoinRequested(GameLobbyJoinRequested_t callback) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) SteamMatchmaking.JoinLobby(callback.m_steamIDLobby); } private void OnLobbyEntered(LobbyEnter_t callback) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) _lobbyId = new CSteamID(callback.m_ulSteamIDLobby); if (SteamMatchmaking.GetLobbyData(_lobbyId, "skul_online_coop_v1") != "1") { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Not a Skul v1 lobby; leaving."); SteamMatchmaking.LeaveLobby(_lobbyId); _lobbyId = default(CSteamID); } else { _awaitingInitialHostStage = !IsHost(); _nextStageRequestAt = 0f; } } private void OnP2pRequested(P2PSessionRequest_t callback) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (IsLobbyMember(callback.m_steamIDRemote)) { SteamNetworking.AcceptP2PSessionWithUser(callback.m_steamIDRemote); } } private void RegisterLobbyPlayersWhenReady() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L) { return; } Character localPlayer = GetLocalPlayer(); if ((Object)(object)localPlayer == (Object)null) { return; } ulong steamID = SteamUser.GetSteamID().m_SteamID; Players.RegisterLocal(steamID, localPlayer); if (_advertiseFreshRunLocalItems) { ItemInventory val = localPlayer.playerComponents?.inventory?.item; if ((Object)(object)val != (Object)null) { SendLocalItems(val); SendLocalLoadout(localPlayer); _advertiseFreshRunLocalItems = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Advertised clean local inventory/loadout for the new run."); } } int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(_lobbyId); for (int i = 0; i < numLobbyMembers; i++) { ulong steamID2 = SteamMatchmaking.GetLobbyMemberByIndex(_lobbyId, i).m_SteamID; if (steamID2 != steamID && !Players.TryGet(steamID2, out Character _) && (Object)(object)Players.CreateRemotePlayer(steamID2, ((Component)localPlayer).transform.position + Vector3.right * 1.5f) != (Object)null) { SendLocalLoadout(localPlayer); ItemInventory val2 = localPlayer.playerComponents?.inventory?.item; if ((Object)(object)val2 != (Object)null) { SendLocalItems(val2); } } } } internal static Character? GetLocalPlayer() { try { Service instance = Singleton.Instance; object result; if (instance == null) { result = null; } else { LevelManager levelManager = instance.levelManager; result = ((levelManager != null) ? levelManager.player : null); } return (Character?)result; } catch { return null; } } internal void PrepareForNativeNewRun() { if (_lobbyId.m_SteamID == 0L) { return; } ulong[] array = Players.RemoteOwners(); foreach (ulong num in array) { if (!Players.TryGet(num, out Character character)) { continue; } ItemInventory val = character.playerComponents?.inventory?.item; if ((Object)(object)val == (Object)null) { continue; } _applyingReplicatedItems.Add(num); try { using (Players.Enter(num)) { val.RemoveAll(); } } finally { _applyingReplicatedItems.Remove(num); } } _lastAdvertisedWeaponState = string.Empty; _advertiseFreshRunLocalItems = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Cleared remote native item inventories before the new run."); } private void SendLocalTransform() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || Time.unscaledTime < _nextTransformAt) { return; } Character localPlayer = GetLocalPlayer(); if ((Object)(object)localPlayer == (Object)null) { return; } _nextTransformAt = Time.unscaledTime + 1f / 30f; Vector3 position = ((Component)localPlayer).transform.position; byte[] array = new byte[51]; array[0] = 1; array[1] = 54; Buffer.BlockCopy(BitConverter.GetBytes(++_localStateSequence), 0, array, 2, 4); Buffer.BlockCopy(BitConverter.GetBytes(position.x), 0, array, 6, 4); Buffer.BlockCopy(BitConverter.GetBytes(position.y), 0, array, 10, 4); array[14] = (byte)localPlayer.lookingDirection; Buffer.BlockCopy(BitConverter.GetBytes(position.z), 0, array, 15, 4); Animator characterAnimator = GetCharacterAnimator(localPlayer); AnimatorStateInfo val = (AnimatorStateInfo)(((Object)(object)characterAnimator == (Object)null) ? default(AnimatorStateInfo) : characterAnimator.GetCurrentAnimatorStateInfo(0)); Buffer.BlockCopy(BitConverter.GetBytes((!((Object)(object)characterAnimator == (Object)null)) ? ((AnimatorStateInfo)(ref val)).fullPathHash : 0), 0, array, 19, 4); Buffer.BlockCopy(BitConverter.GetBytes(((Object)(object)characterAnimator == (Object)null) ? 0f : ((AnimatorStateInfo)(ref val)).normalizedTime), 0, array, 23, 4); int value = 0; if ((Object)(object)characterAnimator != (Object)null) { AnimatorClipInfo[] currentAnimatorClipInfo = characterAnimator.GetCurrentAnimatorClipInfo(0); if (currentAnimatorClipInfo != null && currentAnimatorClipInfo.Length != 0 && (Object)(object)((AnimatorClipInfo)(ref currentAnimatorClipInfo[0])).clip != (Object)null) { value = Animator.StringToHash(((Object)((AnimatorClipInfo)(ref currentAnimatorClipInfo[0])).clip).name); } } Buffer.BlockCopy(BitConverter.GetBytes(value), 0, array, 27, 4); CharacterHealth health = localPlayer.health; Buffer.BlockCopy(BitConverter.GetBytes(((Object)(object)health == (Object)null) ? 0f : ((float)((Health)health).currentHealth)), 0, array, 31, 4); Buffer.BlockCopy(BitConverter.GetBytes(((Object)(object)health == (Object)null) ? 0f : ((float)((Health)health).maximumHealth)), 0, array, 35, 4); array[39] = (byte)(((Object)(object)health != (Object)null && ((Health)health).dead) ? 1 : 0); object obj = AccessTools.Field(typeof(CharacterAnimationController), "parameter")?.GetValue(localPlayer.animationController); array[40] = (byte)((obj != null && (bool)(AccessTools.Field(obj.GetType(), "walk")?.GetValue(obj) ?? ((object)false))) ? 1 : 0); array[41] = (byte)((obj != null && (bool)(AccessTools.Field(obj.GetType(), "grounded")?.GetValue(obj) ?? ((object)false))) ? 1 : 0); Buffer.BlockCopy(BitConverter.GetBytes((obj == null) ? 0f : ((float)(AccessTools.Field(obj.GetType(), "movementSpeed")?.GetValue(obj) ?? ((object)0f)))), 0, array, 42, 4); Buffer.BlockCopy(BitConverter.GetBytes((obj == null) ? 0f : ((float)(AccessTools.Field(obj.GetType(), "ySpeed")?.GetValue(obj) ?? ((object)0f)))), 0, array, 46, 4); array[50] = (byte)((obj != null && (bool)(AccessTools.Field(obj.GetType(), "flipX")?.GetValue(obj) ?? ((object)false))) ? 1 : 0); foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)1, 92); } } } private void ReceivePackets() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_0579: Unknown result type (might be due to invalid IL or missing references) //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Unknown result type (might be due to invalid IL or missing references) uint num = default(uint); uint num2 = default(uint); CSteamID val = default(CSteamID); while (SteamNetworking.IsP2PPacketAvailable(ref num, 92) && num != 0 && num <= 512) { byte[] array = new byte[num]; if (!SteamNetworking.ReadP2PPacket(array, num, ref num2, ref val, 92) || num2 != num || !IsLobbyMember(val) || array.Length < 2 || array[1] != 54) { continue; } if (array[0] == 9 && array.Length == 2 && IsHost()) { SendStageState(val); } else if (array[0] == 10 && array.Length == 22) { ReceiveStageState(array); } else if (array[0] == 11 && array.Length == 11 && !IsHost()) { ApplyHostPlayerHealth(array); } else if (array[0] == 12 && array.Length >= 21 && !IsHost()) { ApplyEnemyAction(array); } else if (array[0] == 13 && array.Length >= 16 && !IsHost()) { ReceiveWorldGearSpawn(array); } else if (array[0] == 16 && array.Length >= 16 && IsHost()) { ReceiveWorldGearSpawnRequest(val, array); } else if (array[0] == 19 && array.Length == 6 && !IsHost()) { ReceiveWorldGearSpawnAcknowledgement(array); } else if (array[0] == 14 && array.Length == 7 && IsHost()) { ApplyWorldGearInteractionRequest(val, array); } else if (array[0] == 15 && array.Length == 6 && !IsHost()) { ApplyWorldGearDespawn(array); } else if (array[0] == 20 && array.Length == 7 && IsHost()) { ApplyRewardObjectInteractionRequest(val, array); } else if (array[0] == 21 && array.Length == 7 && !IsHost()) { ApplyRewardObjectConsumed(array); } else if (array[0] == 22 && array.Length == 2 && !IsHost()) { ActivateClientMapGates(); } else if (array[0] == 23 && array.Length == 3 && IsHost()) { BeginHostCastleExit((Type)array[2]); } else if (array[0] == 24 && array.Length == 7 && !IsHost()) { ApplyHostCastleExit((Type)array[2], BitConverter.ToInt32(array, 3)); } else if (array[0] == 25 && array.Length >= 19 && !IsHost()) { ApplyEnemyLineText(array); } else { if (!Players.TryGet(val.m_SteamID, out Character _)) { continue; } if (array[0] == 1 && array.Length == 51) { Players.ApplyState(val.m_SteamID, BitConverter.ToUInt32(array, 2), new Vector3(BitConverter.ToSingle(array, 6), BitConverter.ToSingle(array, 10), BitConverter.ToSingle(array, 15)), (LookingDirection)array[14], BitConverter.ToInt32(array, 19), BitConverter.ToSingle(array, 23), BitConverter.ToInt32(array, 27), BitConverter.ToSingle(array, 31), BitConverter.ToSingle(array, 35), array[39] != 0, array[40] != 0, array[41] != 0, BitConverter.ToSingle(array, 42), BitConverter.ToSingle(array, 46), array[50] != 0); } else if (array[0] == 2 && array.Length >= 15) { byte b = array[8]; byte b2 = array[9]; byte b3 = array[14]; if (array.Length == 15 + b + b2 + b3) { short actionIndex = BitConverter.ToInt16(array, 10); short motionIndex = BitConverter.ToInt16(array, 12); string motionKey = Encoding.UTF8.GetString(array, 15, b); string weaponKey = ((b2 == 0) ? string.Empty : Encoding.UTF8.GetString(array, 15 + b, b2)); string actionPath = ((b3 == 0) ? string.Empty : Encoding.UTF8.GetString(array, 15 + b + b2, b3)); Players.ApplyAction(val.m_SteamID, motionKey, weaponKey, actionPath, actionIndex, motionIndex, BitConverter.ToSingle(array, 3), array[7] != 0, (LookingDirection)array[2]); } } else if (array[0] == 3 && array.Length >= 4) { byte selectedSlot = array[2]; byte b4 = array[3]; int num3 = 4; string[] array2 = new string[b4]; bool flag = b4 <= 2; int num4 = 0; while (flag && num4 < b4) { if (num3 >= array.Length || num3 + 1 + array[num3] > array.Length) { flag = false; break; } byte b5 = array[num3++]; array2[num4] = Encoding.UTF8.GetString(array, num3, b5); num3 += b5; num4++; } if (flag && num3 == array.Length) { Players.ApplyLoadout(val.m_SteamID, selectedSlot, array2); } } else if (array[0] == 5 && array.Length >= 11) { ulong num5 = BitConverter.ToUInt64(array, 2); byte b6 = array[10]; string[] array3 = new string[b6]; int num6 = 11; bool flag2 = num5 != 0; int num7 = 0; while (flag2 && num7 < b6) { if (num6 >= array.Length) { flag2 = false; break; } byte b7 = array[num6++]; if (num6 + b7 > array.Length) { flag2 = false; break; } array3[num7] = Encoding.UTF8.GetString(array, num6, b7); num6 += b7; num7++; } if (flag2 && num6 == array.Length && num5 != SteamUser.GetSteamID().m_SteamID) { ((MonoBehaviour)this).StartCoroutine(ApplyRemoteItems(num5, array3)); } } else if (array[0] == 4 && array.Length == 45 && !IsHost()) { ApplyEnemySnapshot(array); } else if (array[0] == 6 && array.Length == 25 && IsHost()) { ApplyClientEnemyDamage(val, array); } else if (array[0] == 7 && array.Length == 3 && IsHost()) { CommitMapTransition((NodeIndex)array[2]); } else if (array[0] == 8 && array.Length == 3) { ApplyMapTransition((NodeIndex)array[2]); } } } } internal void SendLocalWeapon(WeaponInventory inventory, Weapon weapon) { //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) Character localPlayer = GetLocalPlayer(); if (_lobbyId.m_SteamID == 0L || (Object)(object)((localPlayer == null) ? null : localPlayer.playerComponents?.inventory?.weapon) != (Object)(object)inventory || (Object)(object)weapon == (Object)null || !(AccessTools.Field(typeof(WeaponInventory), "weapons")?.GetValue(inventory) is Weapon[] array) || array.Length == 0) { return; } int num = Math.Min(array.Length, 2); string[] array2 = new string[num]; byte[][] array3 = new byte[num][]; int num2 = 4; for (int i = 0; i < num; i++) { array2[i] = (((Object)(object)array[i] == (Object)null) ? string.Empty : GetWeaponNetworkKey(array[i])); array3[i] = Encoding.UTF8.GetBytes(array2[i]); if (array3[i].Length > 255) { return; } num2 += 1 + array3[i].Length; } byte[] array4 = new byte[num2]; array4[0] = 3; array4[1] = 54; array4[2] = (byte)Mathf.Clamp(inventory.currentIndex, 0, num - 1); array4[3] = (byte)num; int num3 = 4; for (int j = 0; j < num; j++) { array4[num3++] = (byte)array3[j].Length; Buffer.BlockCopy(array3[j], 0, array4, num3, array3[j].Length); num3 += array3[j].Length; } foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array4, (uint)array4.Length, (EP2PSend)2, 92); } } } private void AdvertiseLocalLoadoutIfChanged() { if (_lobbyId.m_SteamID == 0L) { return; } Character? localPlayer = GetLocalPlayer(); WeaponInventory val = ((localPlayer == null) ? null : localPlayer.playerComponents?.inventory?.weapon); Weapon[] array = (((Object)(object)val == (Object)null) ? null : (AccessTools.Field(typeof(WeaponInventory), "weapons")?.GetValue(val) as Weapon[])); if ((Object)(object)val == (Object)null || array == null || array.Length == 0) { return; } int num = Math.Min(array.Length, 2); string[] array2 = new string[num]; for (int i = 0; i < num; i++) { array2[i] = (((Object)(object)array[i] == (Object)null) ? string.Empty : GetWeaponNetworkKey(array[i])); } string text = val.currentIndex + ":" + string.Join("|", array2); if (!string.Equals(text, _lastAdvertisedWeaponState, StringComparison.Ordinal)) { _lastAdvertisedWeaponState = text; Weapon val2 = val.polymorphOrCurrent ?? val.current; if ((Object)(object)val2 != (Object)null) { SendLocalWeapon(val, val2); } } } private void SendLocalLoadout(Character local) { WeaponInventory val = local.playerComponents?.inventory?.weapon; Weapon val2 = ((val != null) ? val.polymorphOrCurrent : null); if ((Object)(object)val2 != (Object)null) { SendLocalWeapon(val, val2); } } internal void SendLocalItems(ItemInventory inventory) { //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || (Object)(object)inventory == (Object)null) { return; } object? obj = AccessTools.Field(typeof(ItemInventory), "_character")?.GetValue(inventory); Character val = (Character)((obj is Character) ? obj : null); if ((Object)(object)val == (Object)null || !Players.TryGetSteamId(val, out var steamId) || _applyingReplicatedItems.Contains(steamId)) { return; } List items = inventory.items; if (items == null || items.Count > 255) { return; } byte[][] array = new byte[items.Count][]; int num = 11; for (int i = 0; i < items.Count; i++) { Item val2 = items[i]; if ((Object)(object)val2 == (Object)null) { array[i] = Array.Empty(); num++; continue; } if (!TryGetItemNetworkKey(val2, out string key)) { return; } array[i] = Encoding.UTF8.GetBytes(key); if (array[i].Length > 255) { return; } num += 1 + array[i].Length; } byte[] array2 = new byte[num]; array2[0] = 5; array2[1] = 54; Buffer.BlockCopy(BitConverter.GetBytes(steamId), 0, array2, 2, 8); array2[10] = (byte)items.Count; int num2 = 11; for (int j = 0; j < array.Length; j++) { array2[num2++] = (byte)array[j].Length; Buffer.BlockCopy(array[j], 0, array2, num2, array[j].Length); num2 += array[j].Length; } foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array2, (uint)array2.Length, (EP2PSend)2, 92); } } } private IEnumerator ApplyRemoteItems(ulong owner, string[] keys) { if (!Players.TryGet(owner, out Character remote)) { yield break; } ItemInventory inventory = remote.playerComponents?.inventory?.item; GearResource resources = GearResource.instance; if ((Object)(object)inventory == (Object)null || (Object)(object)resources == (Object)null) { yield break; } _applyingReplicatedItems.Add(owner); try { using (Players.Enter(owner)) { inventory.RemoveAll(); } ItemReference val = default(ItemReference); foreach (string text in keys) { if (string.IsNullOrEmpty(text)) { continue; } if (!resources.TryGetItemReferenceByGuid(text, ref val) && !resources.TryGetItemReferenceByName(text, ref val)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Remote item '" + text + "' could not be resolved.")); continue; } ItemRequest request = val.LoadAsync(); while (!((Request)(object)request).isDone) { yield return null; } if ((Object)(object)((Request)(object)request).asset != (Object)null) { using (Players.Enter(owner)) { inventory.TryEquip(((Request)(object)request).asset.Instantiate()); } } } using (Players.Enter(owner)) { PlayerComponents playerComponents = remote.playerComponents; if (playerComponents != null) { Inventory inventory2 = playerComponents.inventory; if (inventory2 != null) { inventory2.UpdateSynergy(); } } } } finally { _applyingReplicatedItems.Remove(owner); } } internal void SendLocalAction(Character character, Motion motion, float speedMultiplier, bool triggerOnStartAction) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || (Object)(object)character != (Object)(object)GetLocalPlayer() || (Object)(object)motion == (Object)null) { return; } byte[] bytes = Encoding.UTF8.GetBytes(motion.key ?? string.Empty); PlayerComponents playerComponents = character.playerComponents; object obj; if (playerComponents == null) { obj = null; } else { Inventory inventory = playerComponents.inventory; if (inventory == null) { obj = null; } else { WeaponInventory weapon = inventory.weapon; obj = ((weapon != null) ? weapon.polymorphOrCurrent : null); } } Weapon val = (Weapon)obj; byte[] array = (((Object)(object)val == (Object)null) ? Array.Empty() : Encoding.UTF8.GetBytes(GetWeaponNetworkKey(val))); TryGetMotionIdentity(character, motion, val, out string actionPath, out int motionIndex); byte[] bytes2 = Encoding.UTF8.GetBytes(actionPath); if (bytes.Length > 255 || array.Length > 255 || bytes2.Length > 255) { return; } TryGetMotionIndices(character, motion, out var actionIndex, out var motionIndex2); byte[] array2 = new byte[15 + bytes.Length + array.Length + bytes2.Length]; array2[0] = 2; array2[1] = 54; array2[2] = (byte)character.lookingDirection; Buffer.BlockCopy(BitConverter.GetBytes(speedMultiplier), 0, array2, 3, 4); array2[7] = (triggerOnStartAction ? ((byte)1) : ((byte)0)); array2[8] = (byte)bytes.Length; array2[9] = (byte)array.Length; Buffer.BlockCopy(BitConverter.GetBytes((short)actionIndex), 0, array2, 10, 2); Buffer.BlockCopy(BitConverter.GetBytes((short)motionIndex), 0, array2, 12, 2); array2[14] = (byte)bytes2.Length; Buffer.BlockCopy(bytes, 0, array2, 15, bytes.Length); if (array.Length != 0) { Buffer.BlockCopy(array, 0, array2, 15 + bytes.Length, array.Length); } if (bytes2.Length != 0) { Buffer.BlockCopy(bytes2, 0, array2, 15 + bytes.Length + array.Length, bytes2.Length); } string item = "sent|" + (motion.key ?? "") + "|" + actionIndex + ":" + motionIndex2; if (_loggedLocalActionDiagnostics.Add(item)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("Sent native local motion '{0}' path '{1}' [{2}] on weapon '{3}'.", motion.key ?? "", actionPath, motionIndex, ((val != null) ? ((Object)val).name : null) ?? "")); } foreach (CSteamID item2 in LobbyMembers()) { if (item2.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item2, array2, (uint)array2.Length, (EP2PSend)2, 92); } } } internal void NotifyCharacterAction(Character character, Motion motion, float speedMultiplier, bool triggerOnStartAction) { if ((Object)(object)character == (Object)(object)GetLocalPlayer()) { SendLocalAction(character, motion, speedMultiplier, triggerOnStartAction); } else if (IsHost() && IsEnemy(character)) { SendEnemyAction(character, motion, speedMultiplier, triggerOnStartAction); } } private void SendEnemyAction(Character enemy, Motion motion, float speedMultiplier, bool triggerOnStartAction) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || (Object)(object)motion == (Object)null || string.IsNullOrEmpty(motion.key)) { return; } byte[] bytes = Encoding.UTF8.GetBytes(motion.key); if (bytes.Length > 255) { return; } ulong steamId = 0uL; AIController val = ((Component)enemy).GetComponent() ?? ((Component)enemy).GetComponentInChildren(true); if ((Object)(object)((val != null) ? val.target : null) != (Object)null) { Players.TryGetSteamId(val.target, out steamId); } byte[] array = new byte[21 + bytes.Length]; array[0] = 12; array[1] = 54; Buffer.BlockCopy(BitConverter.GetBytes(World.GetOrAssignHostUnit(enemy)), 0, array, 2, 4); array[6] = (byte)enemy.lookingDirection; Buffer.BlockCopy(BitConverter.GetBytes(speedMultiplier), 0, array, 7, 4); array[11] = (triggerOnStartAction ? ((byte)1) : ((byte)0)); Buffer.BlockCopy(BitConverter.GetBytes(steamId), 0, array, 12, 8); array[20] = (byte)bytes.Length; Buffer.BlockCopy(bytes, 0, array, 21, bytes.Length); foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } } private static bool TryGetMotionIndices(Character character, Motion motion, out int actionIndex, out int motionIndex) { actionIndex = -1; motionIndex = -1; if (!(AccessTools.Property(typeof(Character), "actions")?.GetValue(character, null) is IList list)) { return false; } for (int i = 0; i < list.Count; i++) { if (!(AccessTools.Property(list[i].GetType(), "motions")?.GetValue(list[i], null) is Array array)) { continue; } for (int j = 0; j < array.Length; j++) { if (array.GetValue(j) == motion) { actionIndex = i; motionIndex = j; return true; } } } return false; } internal static Motion? FindMotion(Character character, string motionKey, Weapon? preferredWeapon = null) { if (!(AccessTools.Property(typeof(Character), "actions")?.GetValue(character, null) is IList list) || string.IsNullOrEmpty(motionKey)) { return null; } for (int i = 0; i < list.Count; i++) { if (!(AccessTools.Property(list[i].GetType(), "motions")?.GetValue(list[i], null) is Array array)) { continue; } for (int j = 0; j < array.Length; j++) { object? value = array.GetValue(j); Motion val = (Motion)((value is Motion) ? value : null); if ((Object)(object)val != (Object)null && string.Equals(val.key, motionKey, StringComparison.Ordinal) && ((Object)(object)preferredWeapon == (Object)null || (Object)(object)((Component)val).GetComponentInParent() == (Object)(object)preferredWeapon)) { return val; } } } return null; } internal static Motion? FindMotion(Character character, int actionIndex, int motionIndex, Weapon? preferredWeapon) { if (!(AccessTools.Property(typeof(Character), "actions")?.GetValue(character, null) is IList list) || actionIndex < 0 || actionIndex >= list.Count || motionIndex < 0) { return null; } object obj = list[actionIndex]; if (obj == null) { return null; } if (!(AccessTools.Property(obj.GetType(), "motions")?.GetValue(obj, null) is Array array) || motionIndex >= array.Length) { return null; } object? value = array.GetValue(motionIndex); Motion val = (Motion)((value is Motion) ? value : null); if ((Object)(object)val == (Object)null || ((Object)(object)preferredWeapon != (Object)null && (Object)(object)((Component)val).GetComponentInParent() != (Object)(object)preferredWeapon)) { return null; } return val; } private static void TryGetMotionIdentity(Character character, Motion motion, Weapon? activeWeapon, out string actionPath, out int motionIndex) { actionPath = string.Empty; motionIndex = -1; Action action = motion.action; if ((Object)(object)action == (Object)null) { return; } Transform val = (((Object)(object)activeWeapon != (Object)null && ((Component)action).transform.IsChildOf(((Component)activeWeapon).transform)) ? ((Component)activeWeapon).transform : ((Component)character).transform); actionPath = (((Object)(object)val == (Object)(object)((activeWeapon != null) ? ((Component)activeWeapon).transform : null)) ? "W:" : "C:") + RelativeTransformPath(((Component)action).transform, val); if (!(AccessTools.Property(((object)action).GetType(), "motions")?.GetValue(action, null) is Array array)) { return; } for (int i = 0; i < array.Length; i++) { if (array.GetValue(i) == motion) { motionIndex = i; break; } } } internal static Motion? FindMotion(Character character, string actionPath, int motionIndex, Weapon? preferredWeapon) { if (string.IsNullOrEmpty(actionPath) || motionIndex < 0 || actionPath.Length < 3 || actionPath[1] != ':') { return null; } Transform val = ((actionPath[0] == 'W' && (Object)(object)preferredWeapon != (Object)null) ? ((Component)preferredWeapon).transform : ((Component)character).transform); string b = actionPath.Substring(2); Action[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); foreach (Action val2 in componentsInChildren) { if (string.Equals(RelativeTransformPath(((Component)val2).transform, val), b, StringComparison.Ordinal) && AccessTools.Property(((object)val2).GetType(), "motions")?.GetValue(val2, null) is Array array && motionIndex < array.Length) { object? value = array.GetValue(motionIndex); return (Motion?)((value is Motion) ? value : null); } } return null; } private static string RelativeTransformPath(Transform target, Transform root) { if ((Object)(object)target == (Object)(object)root) { return "."; } Stack stack = new Stack(); Transform val = target; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { stack.Push(((Object)val).name + "#" + val.GetSiblingIndex()); val = val.parent; } if (!((Object)(object)val == (Object)(object)root)) { return string.Empty; } return string.Join("/", stack.ToArray()); } private static CharacterAnimation? GetCharacterAnimation(Character character) { try { PlayerComponents playerComponents = character.playerComponents; object obj; if (playerComponents == null) { obj = null; } else { Inventory inventory = playerComponents.inventory; if (inventory == null) { obj = null; } else { WeaponInventory weapon = inventory.weapon; obj = ((weapon != null) ? weapon.polymorphOrCurrent : null); } } Weapon val = (Weapon)obj; if ((Object)(object)((val != null) ? val.characterAnimation : null) != (Object)null && (Object)(object)GetAnimationRenderer(val.characterAnimation) != (Object)null) { return val.characterAnimation; } return ((Component)character).GetComponentInChildren(true); } catch { return null; } } private static SpriteRenderer? GetAnimationRenderer(CharacterAnimation animation) { object? obj = AccessTools.Field(typeof(CharacterAnimation), "_spriteRenderer")?.GetValue(animation); return (SpriteRenderer?)((obj is SpriteRenderer) ? obj : null); } internal static Animator? GetCharacterAnimator(Character character) { CharacterAnimation characterAnimation = GetCharacterAnimation(character); if (!((Object)(object)characterAnimation == (Object)null)) { object? obj = AccessTools.Field(typeof(CharacterAnimation), "_animator")?.GetValue(characterAnimation); return (Animator?)((obj is Animator) ? obj : null); } return null; } private static string GetWeaponNetworkKey(Weapon weapon) { GearResource instance = GearResource.instance; WeaponReference val = default(WeaponReference); if ((Object)(object)instance != (Object)null && instance.TryGetWeaponReferenceByName(((Object)weapon).name, ref val)) { return ((GearReference)val).guid; } return ((Object)weapon).name; } private static bool TryGetItemNetworkKey(Item item, out string key) { GearResource instance = GearResource.instance; ItemReference val = default(ItemReference); if ((Object)(object)instance != (Object)null && instance.TryGetItemReferenceByName(((Object)item).name, ref val)) { key = ((GearReference)val).guid; return !string.IsNullOrEmpty(key); } key = (((Object)(object)item == (Object)null) ? string.Empty : ((Object)item).name); return !string.IsNullOrEmpty(key); } private IEnumerable LobbyMembers() { int count = SteamMatchmaking.GetNumLobbyMembers(_lobbyId); for (int index = 0; index < count; index++) { yield return SteamMatchmaking.GetLobbyMemberByIndex(_lobbyId, index); } } private bool IsLobbyMember(CSteamID candidate) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID == candidate.m_SteamID) { return true; } } return false; } internal bool IsRemoteCharacter(Character character) { return Players.IsRemote(character); } internal void NotifyHostRemotePlayerHealth(Health health) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID != 0L && IsHost()) { Character val = ((Component)health).GetComponent() ?? ((Component)health).GetComponentInParent(); if (!((Object)(object)val == (Object)null) && Players.TryGetOwner(val, out var steamId)) { byte[] array = new byte[11] { 11, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes((float)health.currentHealth), 0, array, 2, 4); Buffer.BlockCopy(BitConverter.GetBytes((float)health.maximumHealth), 0, array, 6, 4); array[10] = (health.dead ? ((byte)1) : ((byte)0)); SteamNetworking.SendP2PPacket(new CSteamID(steamId), array, (uint)array.Length, (EP2PSend)2, 92); } } } internal void NotifyHostEnemyHealth(Health health) { if (_lobbyId.m_SteamID != 0L && IsHost()) { Character val = ((Component)health).GetComponent() ?? ((Component)health).GetComponentInParent(); if (!((Object)(object)val == (Object)null) && IsEnemy(val)) { SendEnemySnapshot(val, (EP2PSend)2, tookDamageEvent: true); } } } private static void ApplyHostPlayerHealth(byte[] packet) { Character? localPlayer = GetLocalPlayer(); CharacterHealth val = ((localPlayer != null) ? localPlayer.health : null); if (!((Object)(object)val == (Object)null)) { float num = BitConverter.ToSingle(packet, 6); float num2 = BitConverter.ToSingle(packet, 2); if (num > 0f && !float.IsNaN(num2) && !float.IsInfinity(num2)) { ((Health)val).SetHealth((double)Mathf.Clamp(num2, 0f, num), (double)num); } if (packet[10] != 0 && !((Health)val).dead) { ((Health)val).TryKill(); } } } internal bool IsHost() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID != 0L) { return SteamMatchmaking.GetLobbyData(_lobbyId, "host") == SteamUser.GetSteamID().m_SteamID.ToString(); } return false; } private void SendWorldGearSpawns() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) if (!IsHost() || Time.unscaledTime < _nextWorldDropAt) { return; } _nextWorldDropAt = Time.unscaledTime + 1f / 30f; Drops.PruneDestroyed(); HashSet currentlyAlive = new HashSet(); DroppedGear[] array = Object.FindObjectsOfType(); foreach (DroppedGear val in array) { Gear gear = val.gear; if ((Object)(object)gear == (Object)null || !TryGetWorldGearKey(gear, out byte kind, out string key)) { continue; } byte[] bytes = Encoding.UTF8.GetBytes(key); if (bytes.Length == 0 || bytes.Length > 255) { continue; } Vector3 position = ((Component)val).transform.position; uint orAssignHostDrop = Drops.GetOrAssignHostDrop(val); currentlyAlive.Add(orAssignHostDrop); if (!_advertisedWorldGearDrops.Contains(orAssignHostDrop)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Host world scan registered drop {orAssignHostDrop}: '{key}' at {position}."); } byte[] array2 = new byte[25 + bytes.Length]; array2[0] = 13; array2[1] = 54; Buffer.BlockCopy(BitConverter.GetBytes(orAssignHostDrop), 0, array2, 2, 4); array2[6] = kind; Buffer.BlockCopy(BitConverter.GetBytes(position.x), 0, array2, 7, 4); Buffer.BlockCopy(BitConverter.GetBytes(position.y), 0, array2, 11, 4); array2[15] = (byte)bytes.Length; Buffer.BlockCopy(bytes, 0, array2, 16, bytes.Length); Buffer.BlockCopy(BitConverter.GetBytes(Drops.GetChestRewardGroup(orAssignHostDrop)), 0, array2, 16 + bytes.Length, 4); Buffer.BlockCopy(BitConverter.GetBytes(val.price), 0, array2, 20 + bytes.Length, 4); array2[24 + bytes.Length] = (byte)val.priceCurrency; foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array2, (uint)array2.Length, (EP2PSend)2, 92); } } } uint[] array3 = _advertisedWorldGearDrops.Where((uint item) => !currentlyAlive.Contains(item)).ToArray(); foreach (uint id in array3) { SendWorldGearDespawn(id); } _advertisedWorldGearDrops.UnionWith(currentlyAlive); } private static bool TryGetWorldGearKey(Gear gear, out byte kind, out string key) { GearResource instance = GearResource.instance; key = string.Empty; kind = 0; if ((Object)(object)instance == (Object)null) { return false; } Weapon val = (Weapon)(object)((gear is Weapon) ? gear : null); if (val != null) { kind = 0; key = GetWeaponNetworkKey(val); return !string.IsNullOrEmpty(key); } Item val2 = (Item)(object)((gear is Item) ? gear : null); if (val2 != null) { kind = 1; ItemReference val3 = default(ItemReference); if (instance.TryGetItemReferenceByName(((Object)val2).name, ref val3)) { key = ((GearReference)val3).guid; } return !string.IsNullOrEmpty(key); } Quintessence val4 = (Quintessence)(object)((gear is Quintessence) ? gear : null); if (val4 != null) { kind = 2; EssenceReference val5 = default(EssenceReference); if (instance.TryGetEssenceReferenceByName(((Object)val4).name, ref val5)) { key = ((GearReference)val5).guid; } return !string.IsNullOrEmpty(key); } return false; } private void ReceiveWorldGearSpawn(byte[] packet) { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) byte b = packet[15]; if (b == 0 || packet.Length != 25 + b) { return; } Map instance = Map.Instance; int num = ((!((Object)(object)instance == (Object)null)) ? ((Object)instance).GetInstanceID() : 0); if (!_clientWorldAuthorityEstablished || _clientDropMapId != num) { _clientWorldAuthorityEstablished = true; _clientDropMapId = num; Drops.Clear(); _pendingWorldGearDrops.Clear(); _requestedClientWorldGear.Clear(); _replicatedClientGear.Clear(); DroppedGear[] array = Object.FindObjectsOfType(); for (int i = 0; i < array.Length; i++) { Object.Destroy((Object)(object)((Component)array[i]).gameObject); } } uint num2 = BitConverter.ToUInt32(packet, 2); if (num2 != 0) { byte kind = packet[6]; string key = Encoding.UTF8.GetString(packet, 16, b); Vector3 position = default(Vector3); ((Vector3)(ref position))..ctor(BitConverter.ToSingle(packet, 7), BitConverter.ToSingle(packet, 11), 0f); uint num3 = BitConverter.ToUInt32(packet, 16 + b); int num4 = BitConverter.ToInt32(packet, 20 + b); Type priceCurrency = (Type)packet[24 + b]; DroppedGear val = Drops.TryGetDrop(num2); if ((Object)(object)val != (Object)null) { ((Component)val).transform.position = position; val.price = Mathf.Max(0, num4); val.priceCurrency = priceCurrency; Drops.SetChestRewardGroup(num2, num3); } else if (!_pendingWorldGearDrops.Contains(num2)) { RetireMatchingTemporaryClientDrop(kind, key, position); _pendingWorldGearDrops.Add(num2); ((MonoBehaviour)this).StartCoroutine(CCreateWorldGearDrop(num2, kind, key, position, num3, Mathf.Max(0, num4), priceCurrency)); } } } private void ReceiveWorldGearSpawnRequest(CSteamID sender, byte[] packet) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) byte b = packet[15]; if (b == 0 || packet.Length != 16 + b) { return; } byte b2 = packet[2]; if (b2 <= 2) { uint num = BitConverter.ToUInt32(packet, 3); if (num != 0) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(BitConverter.ToSingle(packet, 7), BitConverter.ToSingle(packet, 11), 0f); string text = Encoding.UTF8.GetString(packet, 16, b); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Host accepted client world-drop request {num} from {sender.m_SteamID}: kind {b2}, key '{text}', at {val}."); ((MonoBehaviour)this).StartCoroutine(CCreateHostRequestedWorldGear(sender, num, b2, text, val)); } } } private IEnumerator CCreateHostRequestedWorldGear(CSteamID requester, uint requestId, byte kind, string key, Vector3 position) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) GearResource instance = GearResource.instance; Service instance2 = Singleton.Instance; LevelManager manager = ((instance2 != null) ? instance2.levelManager : null); if ((Object)(object)instance == (Object)null || (Object)(object)manager == (Object)null) { yield break; } Gear created = null; WeaponReference val = default(WeaponReference); ItemReference val2 = default(ItemReference); EssenceReference val3 = default(EssenceReference); if (kind == 0 && (instance.TryGetWeaponReferenceByGuid(key, ref val) || instance.TryGetWeaponReferenceByName(key, ref val))) { WeaponRequest request = val.LoadAsync(); while (!((Request)(object)request).isDone) { yield return null; } if ((Object)(object)((Request)(object)request).asset != (Object)null) { created = (Gear)(object)manager.DropWeapon(request, position); } } else if (kind == 1 && (instance.TryGetItemReferenceByGuid(key, ref val2) || instance.TryGetItemReferenceByName(key, ref val2))) { ItemRequest request2 = val2.LoadAsync(); while (!((Request)(object)request2).isDone) { yield return null; } if ((Object)(object)((Request)(object)request2).asset != (Object)null) { created = (Gear)(object)manager.DropItem(request2, position); } } else if (kind == 2 && (instance.TryGetEssenceReferenceByGuid(key, ref val3) || instance.TryGetEssenceReferenceByName(key, ref val3))) { EssenceRequest request3 = val3.LoadAsync(); while (!((Request)(object)request3).isDone) { yield return null; } if ((Object)(object)((Request)(object)request3).asset != (Object)null) { created = (Gear)(object)manager.DropQuintessence(request3, position); } } if ((Object)(object)created != (Object)null) { byte[] array = new byte[6] { 19, 54, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes(requestId), 0, array, 2, 4); SteamNetworking.SendP2PPacket(requester, array, (uint)array.Length, (EP2PSend)2, 92); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Host created and acknowledged client world drop {requestId}: kind {kind}, key '{key}', at {position}."); ((MonoBehaviour)this).StartCoroutine(CTraceHostRequestedWorldDrop(requestId, created)); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Host could not resolve requested world drop: kind {kind}, key '{key}'."); } } private IEnumerator CTraceHostRequestedWorldDrop(uint requestId, Gear created) { yield return null; TraceHostRequestedWorldDrop(requestId, created, "next-frame"); yield return (object)new WaitForSecondsRealtime(0.5f); TraceHostRequestedWorldDrop(requestId, created, "0.5s"); } private void TraceHostRequestedWorldDrop(uint requestId, Gear created, string phase) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) DroppedGear val = (((Object)(object)created == (Object)null) ? null : created.dropped); bool flag = (Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy; bool flag2 = (Object)(object)val != (Object)null && (Object)(object)Map.Instance != (Object)null && (Object)(object)((Component)val).transform.parent == (Object)(object)((Component)Map.Instance).transform; Vector3 val2 = (((Object)(object)val == (Object)null) ? Vector3.zero : ((Component)val).transform.position); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Host client-drop {requestId} {phase}: gearAlive={(Object)(object)created != (Object)null}, droppedAlive={(Object)(object)val != (Object)null}, active={flag}, mapParent={flag2}, position={val2}."); } private void EnforceHostWorldDropAuthority() { if (_lobbyId.m_SteamID == 0L || IsHost() || !_clientWorldAuthorityEstablished) { return; } Character localPlayer = GetLocalPlayer(); DroppedGear[] array = Object.FindObjectsOfType(); foreach (DroppedGear val in array) { Gear val2 = val.gear ?? ((Component)val).GetComponent(); if ((!((Object)(object)val2 != (Object)null) || !((Object)(object)val2.owner == (Object)(object)localPlayer)) && !Drops.TryGetDropId(val, out var _)) { Object.Destroy((Object)(object)((Component)val).gameObject); } } } internal bool HandleClientLocalWorldGearCreation(Gear gear, Vector3 position) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || IsHost() || CreatingReplicatedNativeDrop || (Object)(object)gear == (Object)null) { return false; } if (!_requestedClientWorldGear.Add(gear)) { return true; } if (!TryGetWorldGearKey(gear, out byte kind, out string key)) { return false; } byte[] bytes = Encoding.UTF8.GetBytes(key); if (bytes.Length == 0 || bytes.Length > 255) { return false; } uint num = ++_nextClientWorldDropRequestId; if (num == 0) { num = ++_nextClientWorldDropRequestId; } byte[] array = new byte[16 + bytes.Length]; array[0] = 16; array[1] = 54; array[2] = kind; Buffer.BlockCopy(BitConverter.GetBytes(num), 0, array, 3, 4); Buffer.BlockCopy(BitConverter.GetBytes(position.x), 0, array, 7, 4); Buffer.BlockCopy(BitConverter.GetBytes(position.y), 0, array, 11, 4); array[15] = (byte)bytes.Length; Buffer.BlockCopy(bytes, 0, array, 16, bytes.Length); foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } _pendingClientWorldDrops[num] = new PendingClientWorldDrop(kind, key, position, gear.dropped); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Requested host world drop {num}: kind {kind}, key '{key}', at {position}."); return true; } internal void HandleClientNativeLevelManagerDrop(Gear gear, Vector3 position) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)gear == (Object)null) && _lobbyId.m_SteamID != 0L && !IsHost() && !CreatingReplicatedNativeDrop && HandleClientLocalWorldGearCreation(gear, position) && (Object)(object)gear.dropped != (Object)null) { ((MonoBehaviour)this).StartCoroutine(CHideTemporaryClientWorldDrop(gear.dropped)); } } internal void HandleClientWeaponReplacementDrop(Weapon displaced) { //IL_004e: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)displaced == (Object)null || _lobbyId.m_SteamID == 0L || IsHost() || CreatingReplicatedNativeDrop) { return; } DroppedGear dropped = ((Gear)displaced).dropped; if ((Object)(object)dropped == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Native WeaponInventory.EquipAt returned a displaced weapon without DroppedGear."); return; } Vector3 position = ((Component)dropped).transform.position; bool flag = HandleClientLocalWorldGearCreation((Gear)(object)displaced, position); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Native WeaponInventory.EquipAt displaced '{((Object)displaced).name}': state={((Gear)displaced).state}, active={((Component)dropped).gameObject.activeInHierarchy}, requested={flag}, at {position}."); if (flag) { ((MonoBehaviour)this).StartCoroutine(CHideTemporaryClientWorldDrop(dropped)); } } internal void HandleClientGearDropped(Gear gear) { if (_lobbyId.m_SteamID != 0L && !IsHost() && !((Object)(object)gear == (Object)null)) { ((MonoBehaviour)this).StartCoroutine(CPromoteClientDroppedGearAfterNativeStateSettles(gear)); } } private IEnumerator CPromoteClientDroppedGearAfterNativeStateSettles(Gear gear) { yield return (object)new WaitForEndOfFrame(); if (!((Object)(object)gear == (Object)null) && !_replicatedClientGear.Contains(gear) && (int)gear.state == 0 && !((Object)(object)gear.dropped == (Object)null) && ((Component)gear.dropped).gameObject.activeInHierarchy) { if (gear.dropped.price > 0) { ((MonoBehaviour)this).StartCoroutine(CHideTemporaryClientWorldDrop(gear.dropped)); } else if (HandleClientLocalWorldGearCreation(gear, ((Component)gear.dropped).transform.position)) { ((MonoBehaviour)this).StartCoroutine(CHideTemporaryClientWorldDrop(gear.dropped)); } } } private IEnumerator CHideTemporaryClientWorldDrop(DroppedGear dropped) { yield return (object)new WaitForEndOfFrame(); if ((Object)(object)dropped != (Object)null && (Object)(object)((Component)dropped).gameObject != (Object)null) { ((Component)dropped).gameObject.SetActive(false); } } internal void ApplyRemoteAnimationParameters(CharacterAnimationController controller) { if (!((Object)(object)controller == (Object)null)) { Character componentInParent = ((Component)controller).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { Players.ApplyRemoteAnimationParameters(componentInParent, controller); } } } private void DisableClientEnemySimulation() { if (_lobbyId.m_SteamID == 0L || IsHost()) { return; } foreach (Character clientEnemyCandidate in _clientEnemyCandidates) { if ((Object)(object)clientEnemyCandidate == (Object)null) { continue; } AIController[] componentsInChildren = ((Component)clientEnemyCandidate).GetComponentsInChildren(true); foreach (AIController val in componentsInChildren) { if (((Behaviour)val).enabled) { ((Behaviour)val).enabled = false; } } if ((Object)(object)clientEnemyCandidate.animationController != (Object)null && ((Behaviour)clientEnemyCandidate.animationController).enabled) { ((Behaviour)clientEnemyCandidate.animationController).enabled = false; } } } private void ResetClientEnemyRegistryForMapChange() { if (_lobbyId.m_SteamID != 0L && !IsHost()) { int num = ((!((Object)(object)Map.Instance == (Object)null)) ? ((Object)Map.Instance).GetInstanceID() : 0); if (num != 0 && num != _clientEnemyMapId) { _clientEnemyMapId = num; World.Clear(); _enemyAnimatorStates.Clear(); _replicatedEnemyHealthBarExpiry.Clear(); _replicatedEnemyHealth.Clear(); _loggedUnboundEnemySnapshots.Clear(); _clientEnemyCandidates.Clear(); _nextClientEnemyCandidateRefreshAt = 0f; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Reset client enemy netId table for the newly loaded map."); } } } private void RefreshClientEnemyCandidates(bool force = false) { if (_lobbyId.m_SteamID == 0L || IsHost() || (!force && Time.unscaledTime < _nextClientEnemyCandidateRefreshAt)) { return; } _nextClientEnemyCandidateRefreshAt = Time.unscaledTime + 0.25f; _clientEnemyCandidates.Clear(); foreach (Character item in FindEnemies()) { if (!World.TryGetUnitId(item, out var _)) { _clientEnemyCandidates.Add(item); } } } private IEnumerator CCreateWorldGearDrop(uint id, byte kind, string key, Vector3 position, uint chestRewardGroup, int price, Type priceCurrency) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_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) _replicatedWorldGearCreationDepth++; try { GearResource instance = GearResource.instance; Service instance2 = Singleton.Instance; LevelManager manager = ((instance2 != null) ? instance2.levelManager : null); if ((Object)(object)instance == (Object)null || (Object)(object)manager == (Object)null || id == 0) { yield break; } Gear created = null; WeaponReference val = default(WeaponReference); ItemReference val2 = default(ItemReference); EssenceReference val3 = default(EssenceReference); if (kind == 0 && (instance.TryGetWeaponReferenceByGuid(key, ref val) || instance.TryGetWeaponReferenceByName(key, ref val))) { WeaponRequest request = val.LoadAsync(); while (!((Request)(object)request).isDone) { yield return null; } if ((Object)(object)((Request)(object)request).asset != (Object)null) { _replicatedNativeDropCallDepth++; try { created = (Gear)(object)manager.DropWeapon(request, position); } finally { _replicatedNativeDropCallDepth--; } } } else if (kind == 1 && (instance.TryGetItemReferenceByGuid(key, ref val2) || instance.TryGetItemReferenceByName(key, ref val2))) { ItemRequest request2 = val2.LoadAsync(); while (!((Request)(object)request2).isDone) { yield return null; } if ((Object)(object)((Request)(object)request2).asset != (Object)null) { _replicatedNativeDropCallDepth++; try { created = (Gear)(object)manager.DropItem(request2, position); } finally { _replicatedNativeDropCallDepth--; } } } else if (kind == 2 && (instance.TryGetEssenceReferenceByGuid(key, ref val3) || instance.TryGetEssenceReferenceByName(key, ref val3))) { EssenceRequest request3 = val3.LoadAsync(); while (!((Request)(object)request3).isDone) { yield return null; } if ((Object)(object)((Request)(object)request3).asset != (Object)null) { _replicatedNativeDropCallDepth++; try { created = (Gear)(object)manager.DropQuintessence(request3, position); } finally { _replicatedNativeDropCallDepth--; } } } if (!((Object)(object)created == (Object)null) && !((Object)(object)Drops.TryGetDrop(id) != (Object)null)) { _replicatedClientGear.Add(created); Gear obj = created; if ((Object)(object)((obj != null) ? obj.dropped : null) != (Object)null) { created.dropped.price = price; created.dropped.priceCurrency = priceCurrency; Drops.RegisterClientDrop(id, created.dropped); Drops.SetChestRewardGroup(id, chestRewardGroup); } } } finally { CoopRuntimePlugin coopRuntimePlugin = this; coopRuntimePlugin._replicatedWorldGearCreationDepth--; coopRuntimePlugin._pendingWorldGearDrops.Remove(id); } } private void RetireMatchingTemporaryClientDrop(byte kind, string key, Vector3 position) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) KeyValuePair[] array = _pendingClientWorldDrops.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair keyValuePair = array[i]; PendingClientWorldDrop value = keyValuePair.Value; if (value.Kind != kind || !string.Equals(value.Key, key, StringComparison.Ordinal)) { continue; } Vector3 val = value.Position - position; if (((Vector3)(ref val)).sqrMagnitude > 0.25f) { continue; } _pendingClientWorldDrops.Remove(keyValuePair.Key); if ((Object)(object)value.Dropped != (Object)null) { if ((Object)(object)value.Dropped.gear != (Object)null) { _requestedClientWorldGear.Remove(value.Dropped.gear); } Object.Destroy((Object)(object)((Component)value.Dropped).gameObject); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Retired temporary client world drop for host-issued '" + key + "'.")); break; } } private void ReceiveWorldGearSpawnAcknowledgement(byte[] packet) { uint num = BitConverter.ToUInt32(packet, 2); if (num == 0 || !_pendingClientWorldDrops.TryGetValue(num, out var value)) { return; } _pendingClientWorldDrops.Remove(num); if ((Object)(object)value.Dropped != (Object)null) { if ((Object)(object)value.Dropped.gear != (Object)null) { _requestedClientWorldGear.Remove(value.Dropped.gear); } Object.Destroy((Object)(object)((Component)value.Dropped).gameObject); } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Retired acknowledged temporary client world drop {num} for '{value.Key}'."); } internal bool RequestWorldGearInteraction(DroppedGear dropped, Character character, bool dismantle) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || IsHost() || (Object)(object)character != (Object)(object)GetLocalPlayer() || !Drops.TryGetDropId(dropped, out var id)) { return false; } if (dismantle) { return false; } byte[] array = new byte[7] { 14, 54, 0, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes(id), 0, array, 2, 4); array[6] = (dismantle ? ((byte)1) : ((byte)0)); foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } return false; } internal bool IsClientNetworkDrop(DroppedGear dropped) { uint id; if (_lobbyId.m_SteamID != 0L && !IsHost() && (Object)(object)dropped != (Object)null) { return Drops.TryGetDropId(dropped, out id); } return false; } internal bool TryGetNetworkDismantleReward(DroppedGear dropped, out DismantleReward reward) { reward = default(DismantleReward); if (_lobbyId.m_SteamID == 0L || (Object)(object)dropped == (Object)null || !Drops.TryGetDropId(dropped, out var id) || (Object)(object)dropped.gear == (Object)null) { return false; } return TryGetNetworkDismantleReward(dropped.gear, id, out reward); } private bool TryGetNetworkDismantleReward(Gear gear, uint dropId, out DismantleReward reward) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 reward = default(DismantleReward); if (_lobbyId.m_SteamID == 0L || (Object)(object)gear == (Object)null) { return false; } Item val = (Item)(object)((gear is Item) ? gear : null); int num = ((val != null && ((Gear)val).destructible) ? WitchBonus.instance.soul.ancientAlchemy.GetGoldByDiscard(val) : gear.currencyByDiscard); Type currencyTypeByDiscard = gear.currencyTypeByDiscard; if (num <= 0 || ((int)currencyTypeByDiscard != 0 && (int)currencyTypeByDiscard != 2)) { return false; } reward = new DismantleReward(dropId, currencyTypeByDiscard, num); return true; } internal bool PrepareSharedWorldItemDismantle(DroppedGear dropped, Character actor) { return false; } internal bool PrepareSharedInventoryItemDismantle(Item item) { return false; } internal void NotifyNetworkDismantleReward(DismantleReward reward) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || reward.Amount <= 0) { return; } Currency.currencies[reward.Type].Earn(reward.Amount); if (IsHost()) { byte[] array = BuildDismantleRewardPacket(18, reward.Type, reward.Amount); { foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } return; } } byte[] array2 = new byte[11] { 17, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes(reward.DropId), 0, array2, 2, 4); array2[6] = (byte)reward.Type; Buffer.BlockCopy(BitConverter.GetBytes(reward.Amount), 0, array2, 7, 4); foreach (CSteamID item2 in LobbyMembers()) { if (item2.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item2, array2, (uint)array2.Length, (EP2PSend)2, 92); } } } private void ReceiveDismantleRewardRequest(CSteamID sender, byte[] packet) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Invalid comparison between Unknown and I4 uint num = BitConverter.ToUInt32(packet, 2); Type val = (Type)packet[6]; int num2 = BitConverter.ToInt32(packet, 7); if (Players.TryGet(sender.m_SteamID, out Character _) && (num == 0 || !((Object)(object)Drops.TryGetDrop(num) == (Object)null)) && num2 > 0 && num2 <= 100000 && ((int)val == 0 || (int)val == 2)) { Currency.currencies[val].Earn(num2); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Granted shared client dismantle reward to host: {val} {num2} for drop {num}."); } } private void ReceiveDismantleRewardGrant(byte[] packet) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 Type val = (Type)packet[2]; int num = BitConverter.ToInt32(packet, 3); if (num > 0 && num <= 100000 && ((int)val == 0 || (int)val == 2)) { Currency.currencies[val].Earn(num); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Granted shared host dismantle reward to client: {val} {num}."); } } private static byte[] BuildDismantleRewardPacket(byte packetType, Type type, int amount) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[7] { packetType, 54, (byte)type, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes(amount), 0, array, 3, 4); return array; } internal void NotifyClientWorldGearDismantled(DroppedGear dropped) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || IsHost() || (Object)(object)dropped == (Object)null || !Drops.TryGetDropId(dropped, out var id)) { return; } byte[] array = new byte[7] { 14, 54, 0, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes(id), 0, array, 2, 4); array[6] = 1; foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } } private void ApplyWorldGearInteractionRequest(CSteamID sender, byte[] packet) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) uint num = BitConverter.ToUInt32(packet, 2); DroppedGear val = Drops.TryGetDrop(num); if ((Object)(object)val == (Object)null || !Players.TryGet(sender.m_SteamID, out Character _)) { return; } try { if (!TryResolveChestRewardSelection(num, destroyHostWorldCopy: true)) { SendWorldGearDespawn(num); Object.Destroy((Object)(object)((Component)val).gameObject); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Host could not process world-drop interaction {num}: {ex.Message}"); } } internal void NotifyWorldGearLooted(DroppedGear dropped) { if ((Object)(object)dropped != (Object)null && IsHost() && Drops.TryGetDropId(dropped, out var id) && !TryResolveChestRewardSelection(id, destroyHostWorldCopy: false)) { SendWorldGearDespawn(id); } } internal void NotifyWorldGearDestroyed(DroppedGear dropped) { if ((Object)(object)dropped != (Object)null && IsHost() && Drops.TryGetDropId(dropped, out var id)) { SendWorldGearDespawn(id); } } internal void NotifyWorldGearInteractionFinished(DroppedGear dropped) { if ((Object)(object)dropped != (Object)null && IsHost() && Drops.TryGetDropId(dropped, out var id)) { ((MonoBehaviour)this).StartCoroutine(CNotifyWorldGearDespawnIfConsumed(dropped, id)); } } private IEnumerator CNotifyWorldGearDespawnIfConsumed(DroppedGear dropped, uint id) { yield return (object)new WaitForEndOfFrame(); if (!TryResolveChestRewardSelection(id, destroyHostWorldCopy: false) && ((Object)(object)dropped == (Object)null || (Object)(object)dropped.gear == (Object)null) && !TryResolveChestRewardSelection(id, destroyHostWorldCopy: false)) { SendWorldGearDespawn(id); } } internal void NotifyHostChestOpened(Chest chest) { if ((Object)(object)chest != (Object)null && _lobbyId.m_SteamID != 0L && IsHost()) { ((MonoBehaviour)this).StartCoroutine(CRegisterHostChestRewards(chest)); } } private IEnumerator CRegisterHostChestRewards(Chest chest) { FieldInfo rewardsField = AccessTools.Field(typeof(Chest), "_rewards"); int frame = 0; while ((Object)(object)chest != (Object)null && frame < 300) { if (rewardsField?.GetValue(chest) is Gear[] array && array.Length == 3 && array.All((Gear gear) => (Object)(object)((gear != null) ? gear.dropped : null) != (Object)null)) { uint num = ++_nextChestRewardGroupId; if (num == 0) { num = ++_nextChestRewardGroupId; } HashSet hashSet = new HashSet(); Gear[] array2 = array; foreach (Gear val in array2) { uint orAssignHostDrop = Drops.GetOrAssignHostDrop(val.dropped); Drops.SetChestRewardGroup(orAssignHostDrop, num); hashSet.Add(orAssignHostDrop); } _chestRewardDropIds[num] = hashSet; _chestRewardSelections[num] = new HashSet(); _trackedHostChests.Add(chest); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Registered native chest reward group {num} with {hashSet.Count} drops; party limit is two pickups."); yield break; } yield return null; frame++; } ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not obtain Level.Chest._rewards after its native drop coroutine."); } internal bool ShouldRunNativeChestOnLoot(Chest chest) { if (_lobbyId.m_SteamID != 0L && IsHost() && !((Object)(object)chest == (Object)null)) { return !_trackedHostChests.Contains(chest); } return true; } private bool TryResolveChestRewardSelection(uint dropId, bool destroyHostWorldCopy) { uint chestRewardGroup = Drops.GetChestRewardGroup(dropId); if (chestRewardGroup == 0 || !_chestRewardDropIds.TryGetValue(chestRewardGroup, out HashSet value) || !_chestRewardSelections.TryGetValue(chestRewardGroup, out HashSet value2)) { return false; } if (!value2.Add(dropId)) { return true; } if (destroyHostWorldCopy) { DroppedGear val = Drops.TryGetDrop(dropId); if ((Object)(object)val != (Object)null) { Gear gear = val.gear; if ((Object)(object)((gear != null) ? gear.owner : null) == (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } } SendWorldGearDespawn(dropId); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Chest reward group {chestRewardGroup}: selection {value2.Count}/2 (drop {dropId})."); if (value2.Count < 2) { return true; } foreach (uint item in value) { SendWorldGearDespawn(item); DroppedGear val2 = Drops.TryGetDrop(item); if ((Object)(object)val2 != (Object)null) { Gear gear2 = val2.gear; if ((Object)(object)((gear2 != null) ? gear2.owner : null) == (Object)null) { Object.Destroy((Object)(object)((Component)val2).gameObject); } } } _chestRewardDropIds.Remove(chestRewardGroup); _chestRewardSelections.Remove(chestRewardGroup); SendGatesActivated(); return true; } private void SendGatesActivated() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[2] { 22, 54 }; foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } } private static void ActivateClientMapGates() { Map instance = Map.Instance; if ((Object)(object)instance == (Object)null) { return; } Gate[] componentsInChildren = ((Component)instance).GetComponentsInChildren(true); foreach (Gate val in componentsInChildren) { if (((Component)val).gameObject.activeInHierarchy) { ((InteractiveObject)val).Activate(); } } } private void SendWorldGearDespawn(uint id) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) _advertisedWorldGearDrops.Remove(id); byte[] array = new byte[6] { 15, 54, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes(id), 0, array, 2, 4); foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } } private void ApplyWorldGearDespawn(byte[] packet) { uint id = BitConverter.ToUInt32(packet, 2); DroppedGear val = Drops.TryGetDrop(id); if ((Object)(object)val == (Object)null) { return; } Gear val2 = val.gear ?? ((Component)val).GetComponent(); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.owner != (Object)null) { Drops.Unregister(id, val); return; } if (((Component)val).gameObject.activeInHierarchy) { Object.Destroy((Object)(object)((Component)val).gameObject); } Drops.Unregister(id, val); } internal bool RequestRewardObjectInteraction(Component rewardObject, Character actor, byte kind) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || IsHost() || (Object)(object)rewardObject == (Object)null || (Object)(object)actor != (Object)(object)GetLocalPlayer()) { return false; } byte[] array = new byte[7] { 20, 54, kind, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes(StableId(rewardObject.transform)), 0, array, 3, 4); foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } return true; } internal void NotifyHostRewardObjectOpened(Component rewardObject, byte kind) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || !IsHost() || (Object)(object)rewardObject == (Object)null) { return; } byte[] array = new byte[7] { 21, 54, kind, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes(StableId(rewardObject.transform)), 0, array, 3, 4); foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } } private void ApplyRewardObjectInteractionRequest(CSteamID sender, byte[] packet) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!Players.TryGet(sender.m_SteamID, out Character character)) { return; } byte b = packet[2]; int signature = BitConverter.ToInt32(packet, 3); try { using (Players.Enter(sender.m_SteamID)) { switch (b) { case 1: { Chest? obj2 = ((IEnumerable)Object.FindObjectsOfType()).FirstOrDefault((Func)((Chest candidate) => ((Component)candidate).gameObject.activeInHierarchy && StableId(((Component)candidate).transform) == signature)); if (obj2 != null) { ((InteractiveObject)obj2).InteractWith(character); } break; } case 2: { DroppedRandomWeaponBox? obj = ((IEnumerable)Object.FindObjectsOfType()).FirstOrDefault((Func)((DroppedRandomWeaponBox candidate) => ((Component)candidate).gameObject.activeInHierarchy && StableId(((Component)candidate).transform) == signature)); if (obj != null) { ((InteractiveObject)obj).InteractWith(character); } break; } } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Host could not open requested reward container: " + ex.Message)); } } private void ApplyRewardObjectConsumed(byte[] packet) { byte b = packet[2]; int signature = BitConverter.ToInt32(packet, 3); Component val = null; switch (b) { case 1: val = (Component)(object)((IEnumerable)Object.FindObjectsOfType()).FirstOrDefault((Func)((Chest candidate) => StableId(((Component)candidate).transform) == signature)); break; case 2: val = (Component)(object)((IEnumerable)Object.FindObjectsOfType()).FirstOrDefault((Func)((DroppedRandomWeaponBox candidate) => StableId(((Component)candidate).transform) == signature)); break; } if ((Object)(object)val != (Object)null) { val.gameObject.SetActive(false); } } internal void NotifyHostRandomWeaponBoxOpened(DroppedRandomWeaponBox box) { NotifyHostRewardObjectOpened((Component)(object)box, 2); if (_lobbyId.m_SteamID != 0L && IsHost() && !((Object)(object)box == (Object)null) && _openedRandomWeaponBoxes.Add(box)) { ((MonoBehaviour)this).StartCoroutine(CSpawnSecondNativeRandomWeapon(box)); } } private IEnumerator CSpawnSecondNativeRandomWeapon(DroppedRandomWeaponBox box) { yield return null; if ((Object)(object)box == (Object)null) { yield break; } object request = null; Vector3 dropPosition = default(Vector3); try { Random random = AccessTools.Field(typeof(DroppedRandomWeaponBox), "_random")?.GetValue(box) as Random; object obj = AccessTools.Field(typeof(DroppedRandomWeaponBox), "_rarityPossibilities")?.GetValue(box); object obj2 = AccessTools.Field(typeof(DroppedRandomWeaponBox), "_category")?.GetValue(box); object? obj3 = AccessTools.Field(typeof(DroppedRandomWeaponBox), "_dropPoint")?.GetValue(box); Transform val = (Transform)((obj3 is Transform) ? obj3 : null); if (random != null && obj != null && obj2 is Category val2 && (Object)(object)val != (Object)null) { object obj4 = AccessTools.Method(obj.GetType(), "Evaluate", new Type[1] { typeof(Random) }, (Type[])null)?.Invoke(obj, new object[1] { random }); MethodInfo methodInfo = AccessTools.Method(((object)Singleton.Instance.gearManager).GetType(), "GetWeaponByCategory", (Type[])null, (Type[])null); object obj5 = ((obj4 == null) ? null : methodInfo?.Invoke(Singleton.Instance.gearManager, new object[3] { random, obj4, val2 })); if (obj5 != null) { request = AccessTools.Method(obj5.GetType(), "LoadAsync", (Type[])null, (Type[])null)?.Invoke(obj5, null); dropPosition = val.position; } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not create the second native random skull reward: " + ex.Message)); yield break; } if (request == null) { yield break; } PropertyInfo complete = AccessTools.Property(request.GetType(), "isDone"); while (true) { object obj6 = complete?.GetValue(request, null); if (!(obj6 is bool) || (bool)obj6) { break; } yield return null; } try { if (AccessTools.Property(request.GetType(), "asset")?.GetValue(request, null) != null) { AccessTools.Method(((object)Singleton.Instance.levelManager).GetType(), "DropWeapon", new Type[2] { request.GetType(), typeof(Vector3) }, (Type[])null)?.Invoke(Singleton.Instance.levelManager, new object[2] { request, dropPosition }); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not drop the second native random skull reward: " + ex2.Message)); } } private void SendEnemySnapshots() { if (!IsHost() || Time.unscaledTime < _nextEnemySnapshotAt) { return; } _nextEnemySnapshotAt = Time.unscaledTime + 1f / 90f; World.PruneDestroyed(); foreach (Character item in FindEnemies()) { SendEnemySnapshot(item, (EP2PSend)1); } } private void RefreshHostEnemyTargets() { if (_lobbyId.m_SteamID == 0L || !IsHost() || Time.unscaledTime < _nextHostEnemyTargetRefreshAt) { return; } _nextHostEnemyTargetRefreshAt = Time.unscaledTime + 1f / 30f; Character[] array = Players.LiveCharacters().ToArray(); if (array.Length == 0) { return; } foreach (Character enemy in FindEnemies()) { Character val = array.Where((Character candidate) => (Object)(object)candidate != (Object)null && (Object)(object)candidate.collider != (Object)null && candidate.liveAndActive).OrderBy(delegate(Character candidate) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = ((Component)candidate).transform.position - ((Component)enemy).transform.position; return ((Vector3)(ref val2)).sqrMagnitude; }).FirstOrDefault(); if (!((Object)(object)val == (Object)null)) { AIController[] componentsInChildren = ((Component)enemy).GetComponentsInChildren(true); foreach (AIController obj in componentsInChildren) { Character lastAttacker = obj.lastAttacker; obj.target = (((Object)(object)lastAttacker != (Object)null && array.Contains(lastAttacker) && (Object)(object)lastAttacker.collider != (Object)null && lastAttacker.liveAndActive) ? lastAttacker : val); } } } } private void SendEnemySnapshot(Character enemy, EP2PSend sendMode, bool tookDamageEvent = false) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)((enemy != null) ? enemy.health : null) == (Object)null) { return; } Vector3 position = ((Component)enemy).transform.position; uint orAssignHostUnit = World.GetOrAssignHostUnit(enemy); float value = (float)((Health)enemy.health).currentHealth; byte[] array = new byte[45]; array[0] = 4; array[1] = 54; Buffer.BlockCopy(BitConverter.GetBytes(orAssignHostUnit), 0, array, 2, 4); Buffer.BlockCopy(BitConverter.GetBytes(StableId(((Component)enemy).transform)), 0, array, 6, 4); Buffer.BlockCopy(BitConverter.GetBytes(position.x), 0, array, 10, 4); Buffer.BlockCopy(BitConverter.GetBytes(position.y), 0, array, 14, 4); array[18] = (byte)enemy.lookingDirection; Buffer.BlockCopy(BitConverter.GetBytes(value), 0, array, 19, 4); Buffer.BlockCopy(BitConverter.GetBytes((float)((Health)enemy.health).maximumHealth), 0, array, 23, 4); array[27] = (((Health)enemy.health).dead ? ((byte)1) : ((byte)0)); Animator characterAnimator = GetCharacterAnimator(enemy); AnimatorStateInfo val = (AnimatorStateInfo)(((Object)(object)characterAnimator == (Object)null) ? default(AnimatorStateInfo) : characterAnimator.GetCurrentAnimatorStateInfo(0)); Buffer.BlockCopy(BitConverter.GetBytes((!((Object)(object)characterAnimator == (Object)null)) ? ((AnimatorStateInfo)(ref val)).fullPathHash : 0), 0, array, 28, 4); Buffer.BlockCopy(BitConverter.GetBytes(((Object)(object)characterAnimator == (Object)null) ? 0f : ((AnimatorStateInfo)(ref val)).normalizedTime), 0, array, 32, 4); int value2 = 0; if ((Object)(object)characterAnimator != (Object)null) { AnimatorClipInfo[] currentAnimatorClipInfo = characterAnimator.GetCurrentAnimatorClipInfo(0); if (currentAnimatorClipInfo != null && currentAnimatorClipInfo.Length != 0 && (Object)(object)((AnimatorClipInfo)(ref currentAnimatorClipInfo[0])).clip != (Object)null) { value2 = Animator.StringToHash(((Object)((AnimatorClipInfo)(ref currentAnimatorClipInfo[0])).clip).name); } } Buffer.BlockCopy(BitConverter.GetBytes(value2), 0, array, 36, 4); Buffer.BlockCopy(BitConverter.GetBytes(Animator.StringToHash(((Object)enemy).name)), 0, array, 40, 4); array[44] = (tookDamageEvent ? ((byte)1) : ((byte)0)); foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, sendMode, 92); } } } private void ApplyEnemySnapshot(byte[] packet) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) uint num = BitConverter.ToUInt32(packet, 2); int num2 = BitConverter.ToInt32(packet, 6); int nameHash = BitConverter.ToInt32(packet, 40); Vector2 snapshotPosition = new Vector2(BitConverter.ToSingle(packet, 10), BitConverter.ToSingle(packet, 14)); Character val = World.TryGetUnit(num); if ((Object)(object)val == (Object)null) { RefreshClientEnemyCandidates(force: true); foreach (Character clientEnemyCandidate in _clientEnemyCandidates) { if (StableId(((Component)clientEnemyCandidate).transform) == num2) { val = clientEnemyCandidate; break; } } if ((Object)(object)val == (Object)null) { val = _clientEnemyCandidates.Where((Character candidate) => (Object)(object)candidate != (Object)null && !World.TryGetUnitId(candidate, out var _) && (nameHash == 0 || Animator.StringToHash(((Object)candidate).name) == nameHash)).OrderBy(delegate(Character candidate) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) Vector2 val2 = Vector2.op_Implicit(((Component)candidate).transform.position) - snapshotPosition; return ((Vector2)(ref val2)).sqrMagnitude; }).FirstOrDefault(); } if ((Object)(object)val != (Object)null) { World.RegisterClientUnit(num, val); _clientEnemyCandidates.Remove(val); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Bound host enemy {num} to native '{((Object)val).name}' at {((Component)val).transform.position}."); } } if ((Object)(object)((val != null) ? val.health : null) == (Object)null) { if (_loggedUnboundEnemySnapshots.Add(num)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Could not bind host enemy {num} (name hash {nameHash}) at {snapshotPosition}."); } return; } AIController[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); for (int num3 = 0; num3 < componentsInChildren.Length; num3++) { ((Behaviour)componentsInChildren[num3]).enabled = false; } if ((Object)(object)val.animationController != (Object)null) { ((Behaviour)val.animationController).enabled = false; } ((Component)val).transform.position = new Vector3(BitConverter.ToSingle(packet, 10), BitConverter.ToSingle(packet, 14), ((Component)val).transform.position.z); ApplyReplicatedEnemyFacing(val, (LookingDirection)packet[18]); ApplyReplicatedEnemyAnimator((int)num, val, BitConverter.ToInt32(packet, 28), BitConverter.ToSingle(packet, 32)); float num4 = BitConverter.ToSingle(packet, 23); float num5 = BitConverter.ToSingle(packet, 19); float value; bool flag = !_replicatedEnemyHealth.TryGetValue(num, out value) || Mathf.Abs(value - num5) > 0.001f; _replicatedEnemyHealth[num] = num5; if (num4 > 0f) { ((Health)val.health).SetHealth((double)num5, (double)num4); } if (packet[44] != 0 || (flag && num5 < num4)) { ShowReplicatedEnemyHealthBar(val); } if (packet[27] != 0 && !((Health)val.health).dead) { ((Health)val.health).TryKill(); } } private void ApplyReplicatedEnemyAnimator(int enemyId, Character enemy, int stateHash, float normalizedTime) { Animator characterAnimator = GetCharacterAnimator(enemy); if ((Object)(object)characterAnimator == (Object)null || stateHash == 0) { return; } ((Behaviour)characterAnimator).enabled = true; float num = normalizedTime - Mathf.Floor(normalizedTime); if (_enemyAnimatorStates.TryGetValue(enemyId, out var value)) { float num2 = Mathf.Abs(num - value.NormalizedTime); num2 = Mathf.Min(num2, 1f - num2); if (value.StateHash == stateHash && num2 <= 0.2f) { value.NormalizedTime = num; _enemyAnimatorStates[enemyId] = value; return; } } try { characterAnimator.Play(stateHash, 0, num); characterAnimator.Update(0f); _enemyAnimatorStates[enemyId] = new ReplicatedAnimatorState { StateHash = stateHash, NormalizedTime = num }; } catch { } } private static void ApplyReplicatedEnemyFacing(Character enemy, LookingDirection direction) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) enemy.ForceToLookAt(direction); CharacterAnimationController animationController = enemy.animationController; if (animationController != null) { animationController.ForceUpdate(); } if ((Object)(object)enemy.attachWithFlip != (Object)null) { enemy.attachWithFlip.transform.localScale = (Vector3)(((int)direction == 0) ? Vector3.one : new Vector3(-1f, 1f, 1f)); } } private static IEnumerable FindEnemies() { Character[] array = Object.FindObjectsOfType(); foreach (Character val in array) { if ((Object)(object)val.health != (Object)null && IsEnemy(val)) { yield return val; } } } internal static bool IsEnemy(Character character) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Invalid comparison between Unknown and I4 if ((Object)(object)character != (Object)null && (int)character.type != 6 && (int)character.type != 8) { return (int)character.type != 7; } return false; } private static int StableId(Transform transform) { Stack stack = new Stack(); Transform val = transform; while ((Object)(object)val != (Object)null) { stack.Push(val.GetSiblingIndex() + ":" + ((Object)val).name); val = val.parent; } return Animator.StringToHash(string.Join("/", stack.ToArray())); } private void ApplyEnemyAction(byte[] packet) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) byte b = packet[20]; if (b == 0 || packet.Length != 21 + b) { return; } uint id = BitConverter.ToUInt32(packet, 2); Character val = World.TryGetUnit(id); if ((Object)(object)val == (Object)null) { return; } string text = Encoding.UTF8.GetString(packet, 21, b); Motion val2 = FindMotion(val, text); if ((Object)(object)val2 == (Object)null) { return; } ApplyReplicatedEnemyFacing(val, (LookingDirection)packet[6]); ulong num = BitConverter.ToUInt64(packet, 12); AIController val3 = ((Component)val).GetComponent() ?? ((Component)val).GetComponentInChildren(true); Character character = null; if (num != 0L) { if (!Players.TryGet(num, out character) && num == SteamUser.GetSteamID().m_SteamID) { character = GetLocalPlayer(); } if ((Object)(object)val3 != (Object)null && (Object)(object)character != (Object)null) { val3.target = character; } } try { using (EnemyReplayOperationContext.Enter(val2, character)) { using (((Object)(object)character == (Object)null) ? null : PlayerContextBridge.Enter(character)) { val.DoAction(val2, Mathf.Max(0.01f, BitConverter.ToSingle(packet, 7)), packet[11] != 0); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Could not replay host enemy motion '" + text + "': " + ex.Message)); } } internal void NotifyHostEnemyLineText(Character owner, SpawnEnemyLineText operation) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || !IsHost() || (Object)(object)owner == (Object)null || !IsEnemy(owner) || (Object)(object)operation == (Object)null) { return; } object? obj = AccessTools.Field(typeof(SpawnEnemyLineText), "_lineText")?.GetValue(operation); LineText val = (LineText)((obj is LineText) ? obj : null); object obj2 = (((Object)(object)val == (Object)null) ? null : AccessTools.Field(typeof(LineText), "_text")?.GetValue(val)); string text = ((obj2 == null) ? null : (AccessTools.Property(obj2.GetType(), "text")?.GetValue(obj2, null) as string)); if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(text)) { return; } byte[] bytes = Encoding.UTF8.GetBytes(text); if (bytes.Length > 255) { return; } Vector3 position = ((Component)val).transform.position; float value = (float)(AccessTools.Field(typeof(SpawnEnemyLineText), "_duration")?.GetValue(operation) ?? ((object)1.5f)); byte[] array = new byte[19 + bytes.Length]; array[0] = 25; array[1] = 54; Buffer.BlockCopy(BitConverter.GetBytes(World.GetOrAssignHostUnit(owner)), 0, array, 2, 4); Buffer.BlockCopy(BitConverter.GetBytes(position.x), 0, array, 6, 4); Buffer.BlockCopy(BitConverter.GetBytes(position.y), 0, array, 10, 4); Buffer.BlockCopy(BitConverter.GetBytes(value), 0, array, 14, 4); array[18] = (byte)bytes.Length; Buffer.BlockCopy(bytes, 0, array, 19, bytes.Length); foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } } private void ApplyEnemyLineText(byte[] packet) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) byte b = packet[18]; if (packet.Length == 19 + b) { Character? obj = World.TryGetUnit(BitConverter.ToUInt32(packet, 2)); LineText val = ((obj != null) ? ((Component)obj).GetComponentInChildren(true) : null); if (!((Object)(object)val == (Object)null)) { ((Component)val).transform.position = new Vector3(BitConverter.ToSingle(packet, 6), BitConverter.ToSingle(packet, 10), ((Component)val).transform.position.z); val.Display(Encoding.UTF8.GetString(packet, 19, b), Mathf.Max(0.01f, BitConverter.ToSingle(packet, 14))); } } } internal void NotifyClientEnemyDamage(Health health, Damage damage) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012c: 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) if (_lobbyId.m_SteamID == 0L || IsHost()) { return; } Character val = ((Component)health).GetComponent() ?? ((Component)health).GetComponentInParent(); if ((Object)(object)val == (Object)null || !IsEnemy(val)) { return; } float num = (float)((Damage)(ref damage)).amount; if (num <= 0f || float.IsNaN(num) || float.IsInfinity(num)) { return; } byte[] array = new byte[25]; array[0] = 6; array[1] = 54; if (!World.TryGetUnitId(val, out var id)) { return; } ShowReplicatedEnemyHealthBar(val); Buffer.BlockCopy(BitConverter.GetBytes(id), 0, array, 2, 4); Buffer.BlockCopy(BitConverter.GetBytes(num), 0, array, 6, 4); Buffer.BlockCopy(BitConverter.GetBytes(damage.hitPoint.x), 0, array, 10, 4); Buffer.BlockCopy(BitConverter.GetBytes(damage.hitPoint.y), 0, array, 14, 4); Buffer.BlockCopy(BitConverter.GetBytes(damage.stoppingPower), 0, array, 18, 4); array[22] = (byte)damage.attribute; array[23] = (byte)damage.attackType; array[24] = (byte)damage.motionType; foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } } private void ShowReplicatedEnemyHealthBar(Character enemy, bool beginVisibilityWindow = true) { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) List list = new List(); CharacterHealthBarAttacher[] componentsInChildren = ((Component)enemy).GetComponentsInChildren(true); foreach (CharacterHealthBarAttacher obj in componentsInChildren) { object? obj2 = AccessTools.Field(typeof(CharacterHealthBarAttacher), "_instanitated")?.GetValue(obj); CharacterHealthBar val = (CharacterHealthBar)((obj2 is CharacterHealthBar) ? obj2 : null); if ((Object)(object)val != (Object)null) { list.Add(val); } } list.AddRange(((Component)enemy).GetComponentsInChildren(true)); int instanceID = ((Object)enemy).GetInstanceID(); if (_generatedEnemyHealthBars.TryGetValue(instanceID, out CharacterHealthBar value)) { if ((Object)(object)value != (Object)null) { list.Add(value); } else { _generatedEnemyHealthBars.Remove(instanceID); } } if (list.Count == 0) { CharacterHealthBar val2 = null; Object[] array = Resources.FindObjectsOfTypeAll(typeof(CharacterHealthBarAttacher)); for (int i = 0; i < array.Length; i++) { CharacterHealthBarAttacher obj3 = (CharacterHealthBarAttacher)array[i]; object? obj4 = AccessTools.Field(typeof(CharacterHealthBarAttacher), "_healthBar")?.GetValue(obj3); val2 = (CharacterHealthBar)((obj4 is CharacterHealthBar) ? obj4 : null); if ((Object)(object)val2 != (Object)null) { break; } } if ((Object)(object)val2 != (Object)null) { CharacterHealthBar val3 = Object.Instantiate(val2, ((Component)enemy).transform); ((Component)val3).transform.position = ((Component)enemy).transform.position; val3.Initialize(enemy); if ((Object)(object)enemy.collider != (Object)null) { val3.SetWidth(enemy.collider.size.x * 32f); } _generatedEnemyHealthBars[instanceID] = val3; list.Add(val3); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)("No native CharacterHealthBar prefab is loaded for first-wave enemy " + ((Object)enemy).name + ".")); } } foreach (CharacterHealthBar item in list.Distinct()) { item.visible = true; object? obj5 = AccessTools.Field(typeof(CharacterHealthBar), "_container")?.GetValue(item); RectTransform val4 = (RectTransform)((obj5 is RectTransform) ? obj5 : null); if ((Object)(object)val4 != (Object)null) { ((Component)val4).gameObject.SetActive(true); } } if (beginVisibilityWindow) { _replicatedEnemyHealthBarExpiry[((Object)enemy).GetInstanceID()] = Time.unscaledTime + 3f; } } private void KeepReplicatedEnemyHealthBarsVisible() { if (IsHost() || _replicatedEnemyHealthBarExpiry.Count == 0) { return; } KeyValuePair[] array = _replicatedEnemyHealthBarExpiry.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair entry = array[i]; if (entry.Value <= Time.unscaledTime) { _replicatedEnemyHealthBarExpiry.Remove(entry.Key); continue; } Character val = ((IEnumerable)Object.FindObjectsOfType()).FirstOrDefault((Func)((Character candidate) => (Object)(object)candidate != (Object)null && ((Object)candidate).GetInstanceID() == entry.Key)); if ((Object)(object)val == (Object)null || (Object)(object)val.health == (Object)null || ((Health)val.health).dead) { _replicatedEnemyHealthBarExpiry.Remove(entry.Key); } else { ShowReplicatedEnemyHealthBar(val, beginVisibilityWindow: false); } } } private void ApplyClientEnemyDamage(CSteamID sender, byte[] packet) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) uint id = BitConverter.ToUInt32(packet, 2); Character val = World.TryGetUnit(id); if ((Object)(object)((val != null) ? val.health : null) == (Object)null || ((Health)val.health).dead) { return; } float num = BitConverter.ToSingle(packet, 6); if (num <= 0f || num > 1000000f || float.IsNaN(num) || float.IsInfinity(num)) { return; } float num2 = BitConverter.ToSingle(packet, 18); Attribute val2 = (Attribute)packet[22]; if (!Enum.IsDefined(typeof(Attribute), val2)) { val2 = (Attribute)2; } AttackType val3 = (AttackType)packet[23]; MotionType val4 = (MotionType)packet[24]; if (!Enum.IsDefined(typeof(AttackType), val3)) { val3 = (AttackType)4; } if (!Enum.IsDefined(typeof(MotionType), val4)) { val4 = (MotionType)8; } Vector2 val5 = default(Vector2); ((Vector2)(ref val5))..ctor(BitConverter.ToSingle(packet, 10), BitConverter.ToSingle(packet, 14)); Character localPlayer = GetLocalPlayer(); if ((Object)(object)localPlayer == (Object)null) { return; } Character character; Character val6 = (Players.TryGet(sender.m_SteamID, out character) ? character : localPlayer); Damage val7 = default(Damage); ((Damage)(ref val7))..ctor(new Attacker(val6), (double)num, val5, val2, val3, val4, 1.0, num2, 0.0, 1.0, 1.0, false, false, 0.0, 0.0, (short)0, (PriorityList)null, 1.0); if (Players.TryGet(sender.m_SteamID, out Character _)) { using (Players.Enter(sender.m_SteamID)) { ((Health)val.health).TakeDamage(ref val7); } } else { ((Health)val.health).TakeDamage(ref val7); } _nextEnemySnapshotAt = 0f; ((BaseUnityPlugin)this).Logger.LogDebug((object)$"Applied client hit from {sender.m_SteamID} to {((Object)val).name}: {num:F1}."); } private void RefreshStageSync() { //IL_005d: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Stage sync requires a co-op lobby."); return; } if (IsHost()) { SendStageStateToLobbyMembers(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Sent current host stage state."); return; } byte[] array = new byte[2] { 9, 54 }; foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Requested host stage state."); } private void RequestInitialHostStageUntilReceived() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (!_awaitingInitialHostStage || _lobbyId.m_SteamID == 0L || IsHost() || Time.unscaledTime < _nextStageRequestAt) { return; } _nextStageRequestAt = Time.unscaledTime + 0.5f; byte[] array = new byte[2] { 9, 54 }; foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } } private void AdvertiseHostStageWhenReady() { if (IsHost() && !(Time.unscaledTime < _nextStageAdvertAt)) { _nextStageAdvertAt = Time.unscaledTime + 0.25f; SendStageStateToLobbyMembers(); } } private void SendStageStateToLobbyMembers() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) byte[] array = BuildStageStatePacket(); if (array == null) { return; } foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } } private void SendStageState(CSteamID target) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) byte[] array = BuildStageStatePacket(); if (array != null) { SteamNetworking.SendP2PPacket(target, array, (uint)array.Length, (EP2PSend)2, 92); } } private static byte[]? BuildStageStatePacket() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected I4, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected I4, but got Unknown Service instance = Singleton.Instance; LevelManager obj = ((instance != null) ? instance.levelManager : null); Chapter val = ((obj != null) ? obj.currentChapter : null); IStageInfo val2 = ((val != null) ? val.currentStage : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return null; } byte[] array = new byte[22] { 10, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes((int)val.type), 0, array, 2, 4); Buffer.BlockCopy(BitConverter.GetBytes(val.stageIndex), 0, array, 6, 4); Buffer.BlockCopy(BitConverter.GetBytes(val2.pathIndex), 0, array, 10, 4); Buffer.BlockCopy(BitConverter.GetBytes((int)val2.nodeIndex), 0, array, 14, 4); Buffer.BlockCopy(BitConverter.GetBytes(Save.instance.randomSeed), 0, array, 18, 4); return array; } private void ReceiveStageState(byte[] packet) { _awaitingInitialHostStage = false; _pendingStage = new PendingStage(BitConverter.ToInt32(packet, 2), BitConverter.ToInt32(packet, 6), BitConverter.ToInt32(packet, 10), BitConverter.ToInt32(packet, 14), BitConverter.ToInt32(packet, 18)); PendingStage value = _pendingStage.Value; if ((!_lastAppliedHostStage.HasValue || !_lastAppliedHostStage.Value.Equals(value)) && !_applyingHostStage) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Host stage received: chapter {value.Chapter}, stage {value.Stage}, path {value.Path}, node {value.Node}, seed {value.Seed}. Applying automatically."); ((MonoBehaviour)this).StartCoroutine(CApplyReceivedHostStage(value)); } } private IEnumerator CApplyReceivedHostStage(PendingStage pending) { _applyingHostStage = true; for (int frame = 0; frame < 300; frame++) { Service instance = Singleton.Instance; if (!((Object)(object)((instance != null) ? instance.levelManager : null) == (Object)null)) { break; } yield return null; } if (_pendingStage.HasValue && _pendingStage.Value.Equals(pending)) { _resetPendingRun = !_lastAppliedHostStage.HasValue || (pending.Chapter == 1 && pending.Stage == 0 && pending.Path == 0 && pending.Node == 0 && (!_lastAppliedHostStage.HasValue || _lastAppliedHostStage.Value.Seed != pending.Seed)); ApplyPendingStage(); _lastAppliedHostStage = pending; } _applyingHostStage = false; } private void ApplyPendingStage() { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Invalid comparison between Unknown and I4 if (!_pendingStage.HasValue) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"No host stage received. Ask the host to press F7."); return; } Service instance = Singleton.Instance; LevelManager val = ((instance != null) ? instance.levelManager : null); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not apply host stage state yet."); return; } PendingStage value = _pendingStage.Value; if (_resetPendingRun) { _resetPendingRun = false; if (!SetRunSeed(value.Seed)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not set host random seed before ResetGame."); return; } val.onChapterLoaded += ApplyPendingAfterChapterLoad; val.ResetGame((Type)value.Chapter); } else if (!SetRunSeed(value.Seed)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not apply host stage state yet."); } else { Chapter currentChapter = val.currentChapter; if ((Object)(object)currentChapter == (Object)null || (int)currentChapter.type != value.Chapter) { val.onChapterLoaded += ApplyPendingAfterChapterLoad; val.Load((Type)value.Chapter); } else { EnterPendingStage(val, value); } } } private void ApplyPendingAfterChapterLoad() { Service instance = Singleton.Instance; LevelManager val = ((instance != null) ? instance.levelManager : null); if ((Object)(object)val != (Object)null) { val.onChapterLoaded -= ApplyPendingAfterChapterLoad; } if ((Object)(object)val != (Object)null && _pendingStage.HasValue) { EnterPendingStage(val, _pendingStage.Value); } } private void EnterPendingStage(LevelManager manager, PendingStage pending) { if (SetRunSeed(pending.Seed) && !((Object)(object)manager.currentChapter == (Object)null)) { manager.currentChapter.Enter(pending.Stage, pending.Path, pending.Node); _pendingStage = null; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Entered host stage with host random seed."); } } private static bool SetRunSeed(int seed) { try { object obj = AccessTools.Field(typeof(Save), "_randomSeed")?.GetValue(Save.instance); PropertyInfo propertyInfo = ((obj == null) ? null : AccessTools.Property(obj.GetType(), "value")); if (propertyInfo == null) { return false; } propertyInfo.SetValue(obj, seed, null); return true; } catch { return false; } } internal bool HandleGateAttempt(NodeIndex nodeIndex) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L) { return true; } if (IsHost()) { CommitMapTransition(nodeIndex); return false; } byte[] array = new byte[3] { 7, 54, (byte)nodeIndex }; foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Requested host map transition through {nodeIndex}."); return false; } internal bool HandleCastleExitLoad(LevelManager manager, Type target) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID == 0L || (Object)(object)((manager != null) ? manager.currentChapter : null) == (Object)null || (int)manager.currentChapter.type != 1 || (int)target == 1 || _applyingHostStage || _applyingAuthoritativeCastleExit) { return true; } if (IsHost()) { return true; } byte[] array = new byte[3] { 23, 54, (byte)target }; foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Requested host-authoritative Castle exit to {target}."); return false; } internal void NotifyHostCastleExitLoaded(Type target) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) if (_lobbyId.m_SteamID == 0L || !IsHost() || (int)target == 1) { return; } byte[] array = new byte[7] { 24, 54, (byte)target, 0, 0, 0, 0 }; Buffer.BlockCopy(BitConverter.GetBytes(Save.instance.randomSeed), 0, array, 3, 4); foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } } private void BeginHostCastleExit(Type target) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_004d: Unknown result type (might be due to invalid IL or missing references) Service instance = Singleton.Instance; LevelManager val = ((instance != null) ? instance.levelManager : null); if (val != null) { Chapter currentChapter = val.currentChapter; if ((int)((currentChapter != null) ? new Type?(currentChapter.type) : ((Type?)null)).GetValueOrDefault() == 1 && (int)target != 1) { val.Load(target); } } } private void ApplyHostCastleExit(Type target, int seed) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 //IL_0069: Unknown result type (might be due to invalid IL or missing references) Service instance = Singleton.Instance; LevelManager val = ((instance != null) ? instance.levelManager : null); if (val == null) { return; } Chapter currentChapter = val.currentChapter; if ((int)((currentChapter != null) ? new Type?(currentChapter.type) : ((Type?)null)).GetValueOrDefault() != 1) { return; } if (!SetRunSeed(seed)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not set host seed before Castle exit."); return; } _applyingAuthoritativeCastleExit = true; try { val.Load(target); } finally { _applyingAuthoritativeCastleExit = false; } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Entered host-authoritative Castle exit with seed {seed}."); } private void CommitMapTransition(NodeIndex nodeIndex) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[3] { 8, 54, (byte)nodeIndex }; foreach (CSteamID item in LobbyMembers()) { if (item.m_SteamID != SteamUser.GetSteamID().m_SteamID) { SteamNetworking.SendP2PPacket(item, array, (uint)array.Length, (EP2PSend)2, 92); } } ApplyMapTransition(nodeIndex); } private void ApplyMapTransition(NodeIndex nodeIndex) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) Service instance = Singleton.Instance; LevelManager val = ((instance != null) ? instance.levelManager : null); if (!((Object)(object)((val != null) ? val.currentChapter : null) == (Object)null)) { val.LoadNextMap(nodeIndex); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Following host map transition through {nodeIndex}."); } } private void LeaveLobby() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (_lobbyId.m_SteamID != 0L) { SteamMatchmaking.LeaveLobby(_lobbyId); _lobbyId = default(CSteamID); _pendingStage = null; _lastAppliedHostStage = null; _applyingHostStage = false; _resetPendingRun = false; _clientWorldAuthorityEstablished = false; _clientDropMapId = 0; _pendingWorldGearDrops.Clear(); _advertisedWorldGearDrops.Clear(); _requestedClientWorldGear.Clear(); _replicatedClientGear.Clear(); _pendingClientWorldDrops.Clear(); Drops.Clear(); _chestRewardDropIds.Clear(); _chestRewardSelections.Clear(); _trackedHostChests.Clear(); Players.ClearRemotes(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Left Skul co-op lobby."); } } } internal sealed class CoopWorldRegistry { private readonly Dictionary _units = new Dictionary(); private readonly Dictionary _idsByInstance = new Dictionary(); private uint _nextUnitId = 1u; internal IEnumerable> Units => _units; internal uint GetOrAssignHostUnit(Character unit) { int instanceID = ((Object)unit).GetInstanceID(); if (_idsByInstance.TryGetValue(instanceID, out var value)) { return value; } uint num = _nextUnitId++; if (num == 0) { num = _nextUnitId++; } _idsByInstance[instanceID] = num; _units[num] = unit; return num; } internal void RegisterClientUnit(uint id, Character unit) { if (id != 0 && !((Object)(object)unit == (Object)null)) { int instanceID = ((Object)unit).GetInstanceID(); if (_idsByInstance.TryGetValue(instanceID, out var value) && value != id) { _units.Remove(value); } _idsByInstance[instanceID] = id; _units[id] = unit; } } internal Character? TryGetUnit(uint id) { if (!_units.TryGetValue(id, out Character value) || !((Object)(object)value != (Object)null)) { return null; } return value; } internal bool TryGetUnitId(Character unit, out uint id) { if ((Object)(object)unit != (Object)null && _idsByInstance.TryGetValue(((Object)unit).GetInstanceID(), out id)) { return true; } id = 0u; return false; } internal void PruneDestroyed() { uint[] array = (from pair in _units where (Object)(object)pair.Value == (Object)null select pair.Key).ToArray(); foreach (uint key in array) { if (_units.TryGetValue(key, out Character value) && (Object)(object)value != (Object)null) { _idsByInstance.Remove(((Object)value).GetInstanceID()); } _units.Remove(key); } } internal void Clear() { _units.Clear(); _idsByInstance.Clear(); _nextUnitId = 1u; } } internal sealed class CoopDropRegistry { private readonly Dictionary _drops = new Dictionary(); private readonly Dictionary _idsByInstance = new Dictionary(); private readonly Dictionary _chestRewardGroups = new Dictionary(); private uint _nextDropId = 1u; internal uint GetOrAssignHostDrop(DroppedGear dropped) { int instanceID = ((Object)dropped).GetInstanceID(); if (_idsByInstance.TryGetValue(instanceID, out var value)) { return value; } uint num = _nextDropId++; if (num == 0) { num = _nextDropId++; } _idsByInstance[instanceID] = num; _drops[num] = dropped; return num; } internal void RegisterClientDrop(uint id, DroppedGear dropped) { if (id != 0 && !((Object)(object)dropped == (Object)null)) { int instanceID = ((Object)dropped).GetInstanceID(); if (_idsByInstance.TryGetValue(instanceID, out var value) && value != id) { _drops.Remove(value); } _idsByInstance[instanceID] = id; _drops[id] = dropped; } } internal void SetChestRewardGroup(uint id, uint group) { if (id != 0) { if (group == 0) { _chestRewardGroups.Remove(id); } else { _chestRewardGroups[id] = group; } } } internal uint GetChestRewardGroup(uint id) { if (!_chestRewardGroups.TryGetValue(id, out var value)) { return 0u; } return value; } internal DroppedGear? TryGetDrop(uint id) { if (!_drops.TryGetValue(id, out DroppedGear value) || !((Object)(object)value != (Object)null)) { return null; } return value; } internal bool TryGetDropId(DroppedGear dropped, out uint id) { if ((Object)(object)dropped != (Object)null && _idsByInstance.TryGetValue(((Object)dropped).GetInstanceID(), out id)) { return true; } id = 0u; return false; } internal void Unregister(uint id, DroppedGear dropped) { if (id != 0) { _drops.Remove(id); _chestRewardGroups.Remove(id); if ((Object)(object)dropped != (Object)null) { _idsByInstance.Remove(((Object)dropped).GetInstanceID()); } } } internal void Clear() { _drops.Clear(); _idsByInstance.Clear(); _chestRewardGroups.Clear(); } internal void PruneDestroyed() { uint[] array = (from pair in _drops where (Object)(object)pair.Value == (Object)null select pair.Key).ToArray(); foreach (uint key in array) { if (_drops.TryGetValue(key, out DroppedGear value) && (Object)(object)value != (Object)null) { _idsByInstance.Remove(((Object)value).GetInstanceID()); } _drops.Remove(key); _chestRewardGroups.Remove(key); } } } internal sealed class CoopPlayerRegistry { private readonly Dictionary _players = new Dictionary(); private ulong _localId; internal void RegisterLocal(ulong steamId, Character character) { _localId = steamId; if (_players.TryGetValue(steamId, out CoopNetworkPlayer value)) { value.BindLocal(character); return; } _players[steamId] = ((Component)character).gameObject.GetComponent() ?? ((Component)character).gameObject.AddComponent(); _players[steamId].Initialize(steamId, character, isLocal: true); } internal bool TryGet(ulong steamId, out Character character) { if (_players.TryGetValue(steamId, out CoopNetworkPlayer value) && (Object)(object)value.Character != (Object)null) { character = value.Character; return true; } character = null; return false; } internal bool IsRemote(Character character) { foreach (KeyValuePair player in _players) { if (player.Key != _localId && (Object)(object)player.Value.Character == (Object)(object)character) { return true; } } return false; } internal bool TryGetOwner(Character character, out ulong steamId) { foreach (KeyValuePair player in _players) { if (player.Key != _localId && !((Object)(object)player.Value.Character != (Object)(object)character)) { steamId = player.Key; return true; } } steamId = 0uL; return false; } internal bool TryGetSteamId(Character character, out ulong steamId) { foreach (KeyValuePair player in _players) { if (!((Object)(object)player.Value.Character != (Object)(object)character)) { steamId = player.Key; return true; } } steamId = 0uL; return false; } internal ulong[] RemoteOwners() { return _players.Keys.Where((ulong id) => id != _localId).ToArray(); } internal IEnumerable LiveCharacters() { foreach (CoopNetworkPlayer value in _players.Values) { if ((Object)(object)value.Character != (Object)null) { yield return value.Character; } } } internal Character? CreateRemotePlayer(ulong steamId, Vector3 position) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) if (_players.TryGetValue(steamId, out CoopNetworkPlayer value) && (Object)(object)value.Character != (Object)null) { return value.Character; } Character localPlayer = GetLocalPlayer(); if ((Object)(object)localPlayer == (Object)null) { return null; } CommonResource instance = CommonResource.instance; Character val = ((instance != null) ? instance.player : null); if ((Object)(object)val == (Object)null) { return null; } Character val2 = Object.Instantiate(val, ((Component)localPlayer).transform.parent); ((Object)val2).name = $"CoopPlayer_{steamId}"; ((Component)val2).transform.position = position; DisableLocalOnlyComponents(val2); CoopNetworkPlayer coopNetworkPlayer = ((Component)val2).gameObject.GetComponent() ?? ((Component)val2).gameObject.AddComponent(); coopNetworkPlayer.Initialize(steamId, val2, isLocal: false); _players[steamId] = coopNetworkPlayer; CoopRuntimePlugin.Log.LogInfo((object)$"Registered native remote player {steamId} as {((Object)val2).name}."); return val2; } internal IDisposable Enter(ulong steamId) { if (!_players.TryGetValue(steamId, out CoopNetworkPlayer value) || (Object)(object)value.Character == (Object)null) { throw new InvalidOperationException($"No registered CoopPlayer for Steam ID {steamId}."); } return PlayerContextBridge.Enter(value.Character); } internal void ApplyState(ulong steamId, uint sequence, Vector3 position, LookingDirection facing, int animatorStateHash, float normalizedTime, int clipHash, float currentHealth, float maximumHealth, bool dead, bool walk, bool grounded, float movementSpeed, float ySpeed, bool flipX) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (_players.TryGetValue(steamId, out CoopNetworkPlayer value)) { value.ApplyState(sequence, position, facing, animatorStateHash, normalizedTime, clipHash, currentHealth, maximumHealth, dead, walk, grounded, movementSpeed, ySpeed, flipX); } } internal void ApplyAction(ulong steamId, string motionKey, string weaponKey, string actionPath, int actionIndex, int motionIndex, float speedMultiplier, bool triggerOnStartAction, LookingDirection facing) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (_players.TryGetValue(steamId, out CoopNetworkPlayer value)) { value.ApplyAction(motionKey, weaponKey, actionPath, actionIndex, motionIndex, speedMultiplier, triggerOnStartAction, facing, this); } } internal void ApplyLoadout(ulong steamId, int selectedSlot, string[] weaponKeys) { if (_players.TryGetValue(steamId, out CoopNetworkPlayer value)) { value.ApplyLoadout(selectedSlot, weaponKeys, this); } } internal void ApplyRemoteAnimationParameters(Character character, CharacterAnimationController controller) { foreach (KeyValuePair player in _players) { if (player.Key != _localId && (Object)(object)player.Value.Character == (Object)(object)character) { player.Value.ApplyAnimationParameters(controller); break; } } } internal void ClearRemotes() { ulong[] array = _players.Keys.Where((ulong id) => id != _localId).ToArray(); foreach (ulong key in array) { if (_players.TryGetValue(key, out CoopNetworkPlayer value) && (Object)(object)value.Character != (Object)null) { ((Component)value.Character).gameObject.SetActive(false); } _players.Remove(key); } } private static Character? GetLocalPlayer() { try { Service instance = Singleton.Instance; object result; if (instance == null) { result = null; } else { LevelManager levelManager = instance.levelManager; result = ((levelManager != null) ? levelManager.player : null); } return (Character?)result; } catch { return null; } } private static void DisableLocalOnlyComponents(Character remote) { PlayerInput[] componentsInChildren = ((Component)remote).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Behaviour)componentsInChildren[i]).enabled = false; } PlayerCameraController[] componentsInChildren2 = ((Component)remote).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { ((Behaviour)componentsInChildren2[i]).enabled = false; } HandlePlayerDeath[] componentsInChildren3 = ((Component)remote).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren3.Length; i++) { ((Behaviour)componentsInChildren3[i]).enabled = false; } CharacterInteraction[] componentsInChildren4 = ((Component)remote).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren4.Length; i++) { ((Behaviour)componentsInChildren4[i]).enabled = false; } } } internal sealed class CoopNetworkPlayer : MonoBehaviour { private bool _isLocal; private uint _lastSequence; private bool _hasSnapshot; private Vector3 _targetPosition; private readonly Dictionary _weaponsByKey = new Dictionary(); private readonly Weapon?[] _weaponSlots = (Weapon?[])(object)new Weapon[2]; private readonly HashSet _loggedActionDiagnostics = new HashSet(); private int _lastAnimatorStateHash; private float _lastAnimatorTime; private bool _hasAnimationParameters; private bool _remoteWalk; private bool _remoteGrounded; private float _remoteMovementSpeed; private float _remoteYSpeed; private bool _remoteFlipX; internal ulong OwnerSteamId { get; private set; } internal Character? Character { get; private set; } internal void Initialize(ulong ownerSteamId, Character character, bool isLocal) { OwnerSteamId = ownerSteamId; Character = character; _isLocal = isLocal; } internal void BindLocal(Character character) { Character = character; _isLocal = true; } internal void ApplyState(uint sequence, Vector3 position, LookingDirection facing, int animatorStateHash, float normalizedTime, int clipHash, float currentHealth, float maximumHealth, bool dead, bool walk, bool grounded, float movementSpeed, float ySpeed, bool flipX) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (!_isLocal && !((Object)(object)Character == (Object)null) && (!_hasSnapshot || sequence > _lastSequence)) { _lastSequence = sequence; _hasSnapshot = true; _targetPosition = position; Character.ForceToLookAt(facing); _hasAnimationParameters = true; _remoteWalk = walk; _remoteGrounded = grounded; _remoteMovementSpeed = movementSpeed; _remoteYSpeed = ySpeed; _remoteFlipX = flipX; ApplyAnimatorState(animatorStateHash, normalizedTime, clipHash); ApplyHealthState(currentHealth, maximumHealth, dead); } } internal void ApplyAnimationParameters(CharacterAnimationController controller) { if (_isLocal || !_hasAnimationParameters || (Object)(object)controller == (Object)null) { return; } try { object obj = AccessTools.Field(typeof(CharacterAnimationController), "parameter")?.GetValue(controller); if (obj != null) { Type type = obj.GetType(); AccessTools.Field(type, "walk")?.SetValue(obj, _remoteWalk); AccessTools.Field(type, "grounded")?.SetValue(obj, _remoteGrounded); AccessTools.Field(type, "movementSpeed")?.SetValue(obj, _remoteMovementSpeed); AccessTools.Field(type, "ySpeed")?.SetValue(obj, _remoteYSpeed); AccessTools.Field(type, "flipX")?.SetValue(obj, _remoteFlipX); } } catch { } } internal void ApplyAction(string motionKey, string weaponKey, string actionPath, int actionIndex, int motionIndex, float speedMultiplier, bool triggerOnStartAction, LookingDirection facing, CoopPlayerRegistry registry) { //IL_01c9: Unknown result type (might be due to invalid IL or missing references) if (_isLocal || (Object)(object)Character == (Object)null) { return; } Weapon val = null; if (!string.IsNullOrEmpty(weaponKey) && _weaponsByKey.TryGetValue(weaponKey, out Weapon value)) { val = value; } string text = weaponKey + "|" + actionPath + "|" + motionIndex; if ((Object)(object)val == (Object)null && _loggedActionDiagnostics.Add("missing-weapon|" + text)) { CoopRuntimePlugin.Log.LogWarning((object)$"Remote action waiting for weapon '{weaponKey}', motion '{motionKey}', owner {OwnerSteamId}."); } Motion val2 = CoopRuntimePlugin.FindMotion(Character, actionPath, motionIndex, val) ?? CoopRuntimePlugin.FindMotion(Character, actionIndex, motionIndex, val) ?? CoopRuntimePlugin.FindMotion(Character, motionKey, val); if ((Object)(object)val2 == (Object)null) { if (_loggedActionDiagnostics.Add("missing-motion|" + text)) { CoopRuntimePlugin.Log.LogWarning((object)$"Remote motion '{motionKey}' was not found on weapon '{weaponKey}' for {OwnerSteamId}."); } return; } try { using (registry.Enter(OwnerSteamId)) { if ((Object)(object)val != (Object)null && (Object)(object)Character.playerComponents?.inventory?.weapon != (Object)null && (Object)(object)Character.playerComponents.inventory.weapon.current != (Object)(object)val) { AccessTools.PropertySetter(typeof(WeaponInventory), "current")?.Invoke(Character.playerComponents.inventory.weapon, new object[1] { val }); } Character.ForceToLookAt(facing); Character.DoAction(val2, Mathf.Max(0.01f, speedMultiplier), triggerOnStartAction); if (_loggedActionDiagnostics.Add("replayed|" + text)) { CoopRuntimePlugin.Log.LogInfo((object)$"Replayed native remote motion '{motionKey}' path '{actionPath}' [{motionIndex}] on weapon '{weaponKey}' for {OwnerSteamId}."); } } } catch (Exception ex) { CoopRuntimePlugin.Log.LogDebug((object)("Could not replay remote motion '" + motionKey + "': " + ex.Message)); } } internal void ApplyLoadout(int selectedSlot, string[] weaponKeys, CoopPlayerRegistry registry) { if (!_isLocal && weaponKeys != null && weaponKeys.Length != 0 && weaponKeys.Length <= _weaponSlots.Length) { ((MonoBehaviour)this).StartCoroutine(CApplyLoadout(selectedSlot, weaponKeys, registry)); } } private IEnumerator CApplyLoadout(int selectedSlot, string[] weaponKeys, CoopPlayerRegistry registry) { GearResource resources = GearResource.instance; if ((Object)(object)resources == (Object)null || (Object)(object)Character == (Object)null) { yield break; } HashSet requested = new HashSet(weaponKeys.Where((string value2) => !string.IsNullOrEmpty(value2))); KeyValuePair[] array = _weaponsByKey.Where>((KeyValuePair entry) => !requested.Contains(entry.Key)).ToArray(); for (int num = 0; num < array.Length; num++) { KeyValuePair keyValuePair = array[num]; if ((Object)(object)keyValuePair.Value != (Object)null) { keyValuePair.Value.EndUse(); ((Component)keyValuePair.Value).transform.SetParent((Transform)null); ((Component)keyValuePair.Value).gameObject.SetActive(false); } _weaponsByKey.Remove(keyValuePair.Key); } WeaponReference val = default(WeaponReference); for (int slot = 0; slot < weaponKeys.Length; slot++) { string key = weaponKeys[slot]; if (string.IsNullOrEmpty(key)) { _weaponSlots[slot] = null; continue; } if (_weaponsByKey.TryGetValue(key, out Weapon value) && (Object)(object)value != (Object)null) { _weaponSlots[slot] = value; continue; } if (!resources.TryGetWeaponReferenceByGuid(key, ref val) && !resources.TryGetWeaponReferenceByName(key, ref val)) { CoopRuntimePlugin.Log.LogWarning((object)("Remote weapon '" + key + "' could not be resolved.")); continue; } WeaponRequest request = val.LoadAsync(); while (!((Request)(object)request).isDone) { yield return null; } if (!((Object)(object)((Request)(object)request).asset == (Object)null)) { Weapon val2 = ((Request)(object)request).asset.Instantiate(); if (!((Object)(object)val2 == (Object)null)) { _weaponsByKey[key] = val2; _weaponSlots[slot] = val2; } } } if (selectedSlot < 0 || selectedSlot >= weaponKeys.Length || (Object)(object)_weaponSlots[selectedSlot] == (Object)null) { selectedSlot = Array.FindIndex(_weaponSlots, (Weapon entry) => (Object)(object)entry != (Object)null); } if (selectedSlot >= 0) { ApplyNativeLoadout(selectedSlot, registry); } } private void ApplyNativeLoadout(int selectedSlot, CoopPlayerRegistry registry) { //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Character == (Object)null || (Object)(object)_weaponSlots[selectedSlot] == (Object)null) { return; } Weapon val = _weaponSlots[selectedSlot]; WeaponInventory val2 = Character.playerComponents?.inventory?.weapon; if ((Object)(object)val2 == (Object)null) { return; } using (registry.Enter(OwnerSteamId)) { foreach (Weapon item in _weaponsByKey.Values.Distinct()) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)val)) { item.EndUse(); ((Component)item).transform.SetParent((Transform)null); ((Component)item).gameObject.SetActive(false); } } Weapon current2 = val2.current; if ((Object)(object)current2 != (Object)null && (Object)(object)current2 != (Object)(object)val) { ((Component)current2).gameObject.SetActive(false); current2.EndUse(); ((Component)current2).transform.SetParent((Transform)null); } val.SetOwner(Character); ((Gear)val).state = (State)1; ((Component)val).transform.SetParent(Character.@base); ((Component)val).transform.localPosition = Vector3.zero; ((Component)val).transform.localScale = Vector3.one; AccessTools.Method(typeof(WeaponInventory), "set_current", (Type[])null, (Type[])null)?.Invoke(val2, new object[1] { val }); AccessTools.Method(typeof(WeaponInventory), "set_currentIndex", (Type[])null, (Type[])null)?.Invoke(val2, new object[1] { selectedSlot }); if (AccessTools.Field(typeof(WeaponInventory), "weapons")?.GetValue(val2) is Weapon[] array) { for (int i = 0; i < array.Length && i < _weaponSlots.Length; i++) { array[i] = _weaponSlots[i]; } } AccessTools.Method(typeof(WeaponInventory), "StartUse", (Type[])null, (Type[])null)?.Invoke(val2, new object[1] { val }); } _lastAnimatorStateHash = 0; _lastAnimatorTime = 0f; CoopRuntimePlugin.Log.LogInfo((object)$"Applied native remote loadout for player {OwnerSteamId}: slot {selectedSlot}, {((Object)val).name}."); } private void ApplyAnimatorState(int stateHash, float normalizedTime, int clipHash) { Animator val = (((Object)(object)Character == (Object)null) ? null : CoopRuntimePlugin.GetCharacterAnimator(Character)); if ((Object)(object)val == (Object)null || stateHash == 0 || ((Object)(object)Character != (Object)null && (Object)(object)Character.motion != (Object)null && Character.motion.running && stateHash == _lastAnimatorStateHash)) { return; } float num = normalizedTime - Mathf.Floor(normalizedTime); try { float num2 = Mathf.Abs(num - _lastAnimatorTime); num2 = Mathf.Min(num2, 1f - num2); if (stateHash != _lastAnimatorStateHash || num2 > 0.2f) { val.Play(stateHash, 0, num); val.Update(0f); _lastAnimatorStateHash = stateHash; } _lastAnimatorTime = num; } catch { } } private void ApplyHealthState(float currentHealth, float maximumHealth, bool dead) { Character? character = Character; if (!((Object)(object)((character != null) ? character.health : null) == (Object)null) && !(maximumHealth <= 0f)) { ((Health)Character.health).SetHealth((double)currentHealth, (double)maximumHealth); if (dead && !((Health)Character.health).dead) { ((Health)Character.health).TryKill(); } } } private void LateUpdate() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (!_isLocal && !((Object)(object)Character == (Object)null) && _hasSnapshot) { Vector3 val = ((Component)Character).transform.position - _targetPosition; if (((Vector3)(ref val)).sqrMagnitude > 64f) { ((Component)Character).transform.position = _targetPosition; return; } float num = 1f - Mathf.Exp(-38f * Time.unscaledDeltaTime); ((Component)Character).transform.position = Vector3.Lerp(((Component)Character).transform.position, _targetPosition, num); } } } internal static class PlayerContextBridge { private sealed class ContextScope : IDisposable { private Character? _previous; private bool _disposed; internal ContextScope(Character? previous) { _previous = previous; } public void Dispose() { if (!_disposed) { _disposed = true; Character previous = _previous; _previous = null; SetCurrent?.Invoke(null, new object[1] { previous }); } } } private static readonly Type? ContextType = AccessTools.TypeByName("SkulOnlineCoopV1.Runtime.PlayerExecutionContext"); private static readonly MethodInfo? SetCurrent = ((ContextType == null) ? null : AccessTools.Method(ContextType, "SetCurrent", (Type[])null, (Type[])null)); private static readonly MethodInfo? GetCurrent = ((ContextType == null) ? null : AccessTools.Method(ContextType, "GetCurrent", (Type[])null, (Type[])null)); internal static IDisposable Enter(Character player) { if (SetCurrent == null || GetCurrent == null) { throw new InvalidOperationException("Skul v1 preloader is not active; refusing to run a second player unsafely."); } object? obj = GetCurrent.Invoke(null, null); Character previous = (Character)((obj is Character) ? obj : null); SetCurrent.Invoke(null, new object[1] { player }); return new ContextScope(previous); } internal static bool TryGetCurrent(out Character current) { object? obj = GetCurrent?.Invoke(null, null); Character val = (Character)((obj is Character) ? obj : null); if ((Object)(object)val == (Object)null) { current = null; return false; } current = val; return true; } } internal sealed class OwnerContextEnumerator : IEnumerator { private readonly IEnumerator _inner; private readonly Character _owner; private object? _current; public object Current => _current; internal OwnerContextEnumerator(IEnumerator inner, Character owner) { _inner = inner; _owner = owner; } public bool MoveNext() { bool flag; using (PlayerContextBridge.Enter(_owner)) { flag = _inner.MoveNext(); } if (!flag) { _current = null; return false; } object current = _inner.Current; _current = ((current is IEnumerator inner) ? new OwnerContextEnumerator(inner, _owner) : current); return true; } public void Reset() { _inner.Reset(); } } internal static class EnemyReplayOperationContext { private sealed class Scope : IDisposable { private Motion? _motion; private readonly Character _target; internal Scope(Motion motion, Character target) { _motion = motion; _target = target; } public void Dispose() { if (!((Object)(object)_motion == (Object)null)) { if (Targets.TryGetValue(_motion, out Character value) && (Object)(object)value == (Object)(object)_target) { Targets.Remove(_motion); } _motion = null; } } } private sealed class EmptyScope : IDisposable { internal static readonly EmptyScope Instance = new EmptyScope(); public void Dispose() { } } private static readonly Dictionary Targets = new Dictionary(); internal static IDisposable Enter(Motion motion, Character? target) { if ((Object)(object)motion == (Object)null || (Object)(object)target == (Object)null) { return EmptyScope.Instance; } Targets[motion] = target; return new Scope(motion, target); } internal static bool TryGet(Motion motion, out Character target) { return Targets.TryGetValue(motion, out target); } } internal static class RemoteCoroutineOwnerResolver { internal static bool TryResolve(MonoBehaviour behaviour, out Character owner) { owner = null; CoopPlayerRegistry coopPlayerRegistry = CoopRuntimePlugin.Instance?.Players; if (coopPlayerRegistry == null || (Object)(object)behaviour == (Object)null) { return false; } Character val = (Character)(object)((behaviour is Character) ? behaviour : null); Character val2; if (val != null) { val2 = val; } else { Projectile val3 = (Projectile)(object)((behaviour is Projectile) ? behaviour : null); if (val3 != null) { val2 = val3.owner; } else { Minion val4 = (Minion)(object)((behaviour is Minion) ? behaviour : null); val2 = ((val4 == null) ? ((Component)behaviour).GetComponentInParent() : val4.leader?.player); } } if ((Object)(object)val2 == (Object)null || !coopPlayerRegistry.IsRemote(val2)) { return false; } owner = val2; return true; } } [HarmonyPatch(typeof(MonoBehaviour), "StartCoroutine", new Type[] { typeof(IEnumerator) })] internal static class RemoteOwnedCoroutineContextPatch { private static void Prefix(MonoBehaviour __instance, ref IEnumerator routine) { if (routine != null && (RemoteCoroutineOwnerResolver.TryResolve(__instance, out Character owner) || PlayerContextBridge.TryGetCurrent(out owner))) { routine = new OwnerContextEnumerator(routine, owner); } } } [HarmonyPatch] internal static class NativeNewRunRemoteInventoryCleanupPatch { private static IEnumerable TargetMethods() { return from method in AccessTools.GetDeclaredMethods(typeof(LevelManager)) where string.Equals(method.Name, "ResetGame", StringComparison.Ordinal) select method; } private static void Prefix() { CoopRuntimePlugin.Instance?.PrepareForNativeNewRun(); } } [HarmonyPatch(typeof(Motion), "CRunOperations")] internal static class RemoteMotionOperationContextPatch { private static void Postfix(Motion __instance, ref IEnumerator __result) { CoopPlayerRegistry coopPlayerRegistry = CoopRuntimePlugin.Instance?.Players; if (__result != null && coopPlayerRegistry != null) { if (EnemyReplayOperationContext.TryGet(__instance, out Character target)) { __result = new OwnerContextEnumerator(__result, target); } else if (coopPlayerRegistry.IsRemote(__instance.owner)) { __result = new OwnerContextEnumerator(__result, __instance.owner); } } } } [HarmonyPatch(typeof(CharacterAnimationController), "Update")] internal static class RemoteCharacterAnimationParameterPatch { private static void Prefix(CharacterAnimationController __instance) { CoopRuntimePlugin.Instance?.ApplyRemoteAnimationParameters(__instance); } } [HarmonyPatch(typeof(Character), "DoAction", new Type[] { typeof(Motion), typeof(float), typeof(bool) })] internal static class LocalPlayerActionReplicationPatch { private static void Postfix(Character __instance, Motion motion, float speedMultiplier, bool triggerOnStartAction) { CoopRuntimePlugin.Instance?.NotifyCharacterAction(__instance, motion, speedMultiplier, triggerOnStartAction); } } [HarmonyPatch(typeof(WeaponInventory), "set_current")] internal static class LocalWeaponStateReplicationPatch { private static void Postfix(WeaponInventory __instance, Weapon value) { if ((Object)(object)value != (Object)null) { CoopRuntimePlugin.Instance?.SendLocalWeapon(__instance, value); } } } [HarmonyPatch(typeof(ItemInventory), "TryEquip")] internal static class LocalItemEquipReplicationPatch { private static void Postfix(ItemInventory __instance) { CoopRuntimePlugin.Instance?.SendLocalItems(__instance); } } [HarmonyPatch(typeof(ItemInventory), "RemoveAll")] internal static class LocalItemRemoveAllReplicationPatch { private static void Postfix(ItemInventory __instance) { CoopRuntimePlugin.Instance?.SendLocalItems(__instance); } } [HarmonyPatch] internal static class LocalItemRemoveReplicationPatch { private static MethodBase? TargetMethod() { return AccessTools.Method(typeof(ItemInventory), "Remove", new Type[1] { typeof(Item) }, (Type[])null); } private static void Postfix(ItemInventory __instance) { CoopRuntimePlugin.Instance?.SendLocalItems(__instance); } } [HarmonyPatch] internal static class ClientEnemyDamageAuthorityPatch { private static MethodBase? TargetMethod() { return AccessTools.Method(typeof(Health), "TakeDamage", new Type[2] { typeof(Damage).MakeByRefType(), typeof(double).MakeByRefType() }, (Type[])null); } private static bool Prefix(Health __instance, ref Damage damage) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) CoopRuntimePlugin instance = CoopRuntimePlugin.Instance; if ((Object)(object)instance == (Object)null || instance.IsHostAuthority) { return true; } Character character = ((Component)__instance).GetComponent() ?? ((Component)__instance).GetComponentInParent(); Character localPlayer = CoopRuntimePlugin.GetLocalPlayer(); if ((Object)(object)damage.attacker.character != (Object)null && instance.IsRemoteCharacter(damage.attacker.character)) { return false; } if (!CoopRuntimePlugin.IsEnemy(character)) { return false; } if ((Object)(object)damage.attacker.character != (Object)(object)localPlayer) { return false; } instance.NotifyClientEnemyDamage(__instance, damage); return false; } } [HarmonyPatch] internal static class HostRemotePlayerHealthAuthorityPatch { private static MethodBase? TargetMethod() { return AccessTools.Method(typeof(Health), "TakeDamage", new Type[2] { typeof(Damage).MakeByRefType(), typeof(double).MakeByRefType() }, (Type[])null); } private static void Postfix(Health __instance) { CoopRuntimePlugin? instance = CoopRuntimePlugin.Instance; instance?.NotifyHostRemotePlayerHealth(__instance); instance?.NotifyHostEnemyHealth(__instance); } } [HarmonyPatch(typeof(Health), "TryKill")] internal static class HostEnemyInstantDeathAuthorityPatch { private static void Postfix(Health __instance) { CoopRuntimePlugin.Instance?.NotifyHostEnemyHealth(__instance); } } [HarmonyPatch(typeof(Gear), "OnDropped")] internal static class ClientDroppedGearSpawnRequestPatch { private static void Postfix(Gear __instance) { CoopRuntimePlugin.Instance?.HandleClientGearDropped(__instance); } } [HarmonyPatch(typeof(Fox), "GetExtraHead")] internal static class FoxExtraRewardSelectionTracePatch { private static void Prefix() { CoopRuntimePlugin.Log.LogInfo((object)"Native Fox.GetExtraHead selected; awaiting its original extra WeaponRequest."); } } [HarmonyPatch(typeof(Ogre), "GetExtraItem")] internal static class OgreExtraRewardSelectionTracePatch { private static void Prefix() { CoopRuntimePlugin.Log.LogInfo((object)"Native Ogre.GetExtraItem selected; awaiting its original extra ItemRequest."); } } [HarmonyPatch(typeof(LevelManager), "DropWeapon", new Type[] { typeof(WeaponRequest), typeof(Vector3) })] internal static class NativeWeaponRequestDropTracePatch { private static void Postfix(Weapon __result, Vector3 position) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) CoopRuntimePlugin instance = CoopRuntimePlugin.Instance; if ((Object)(object)instance != (Object)null && !instance.IsHost()) { CoopRuntimePlugin.Log.LogInfo((object)"Native client LevelManager.DropWeapon(WeaponRequest) executed."); instance.HandleClientNativeLevelManagerDrop((Gear)(object)__result, position); } } } [HarmonyPatch(typeof(LevelManager), "DropItem", new Type[] { typeof(ItemRequest), typeof(Vector3) })] internal static class NativeItemRequestDropTracePatch { private static void Postfix(Item __result, Vector3 position) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) CoopRuntimePlugin instance = CoopRuntimePlugin.Instance; if ((Object)(object)instance != (Object)null && !instance.IsHost()) { CoopRuntimePlugin.Log.LogInfo((object)"Native client LevelManager.DropItem(ItemRequest) executed."); instance.HandleClientNativeLevelManagerDrop((Gear)(object)__result, position); } } } [HarmonyPatch(typeof(WeaponInventory), "EquipAt", new Type[] { typeof(Weapon), typeof(int) })] internal static class ClientWeaponInventoryReplacementDropPatch { private static void Postfix(Weapon __result) { CoopRuntimePlugin.Instance?.HandleClientWeaponReplacementDrop(__result); } } [HarmonyPatch(typeof(Skul), "Start")] internal static class DroppedSkulStartupPatch { private static bool Prefix(Skul __instance) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 Weapon componentInParent = ((Component)__instance).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null)) { return (int)((Gear)componentInParent).state > 0; } return true; } } [HarmonyPatch(typeof(DroppedGear), "InteractWith")] internal static class ClientDroppedGearLootRequestPatch { private static bool Prefix(DroppedGear __instance, Character character) { CoopRuntimePlugin instance = CoopRuntimePlugin.Instance; if ((Object)(object)__instance == (Object)null) { return true; } if (!((Object)(object)instance == (Object)null)) { return !instance.RequestWorldGearInteraction(__instance, character, dismantle: false); } return true; } } [HarmonyPatch(typeof(Chest), "InteractWith")] internal static class HostChestRewardRegistrationPatch { private static bool Prefix(Chest __instance, Character character) { return !(CoopRuntimePlugin.Instance?.RequestRewardObjectInteraction((Component)(object)__instance, character, 1) ?? false); } private static void Postfix(Chest __instance) { CoopRuntimePlugin? instance = CoopRuntimePlugin.Instance; instance?.NotifyHostRewardObjectOpened((Component)(object)__instance, 1); instance?.NotifyHostChestOpened(__instance); } } [HarmonyPatch(typeof(Chest), "OnLoot")] internal static class TwoPlayerChestLootLimitPatch { private static bool Prefix(Chest __instance) { return CoopRuntimePlugin.Instance?.ShouldRunNativeChestOnLoot(__instance) ?? true; } } [HarmonyPatch(typeof(DroppedRandomWeaponBox), "InteractWith")] internal static class RandomSkullBoxCoopPatch { private static bool Prefix(DroppedRandomWeaponBox __instance, Character character) { return !(CoopRuntimePlugin.Instance?.RequestRewardObjectInteraction((Component)(object)__instance, character, 2) ?? false); } private static void Postfix(DroppedRandomWeaponBox __instance) { CoopRuntimePlugin.Instance?.NotifyHostRandomWeaponBoxOpened(__instance); } } [HarmonyPatch(typeof(DroppedGear), "InteractWith")] internal static class HostDroppedGearLootReplicationPatch { private static void Postfix(DroppedGear __instance) { CoopRuntimePlugin.Instance?.NotifyWorldGearInteractionFinished(__instance); } } [HarmonyPatch(typeof(DroppedGear), "InteractWithByPressing")] internal static class NetworkDroppedGearDismantleRewardPatch { private static bool Prefix(DroppedGear __instance, Character character) { CoopRuntimePlugin instance = CoopRuntimePlugin.Instance; instance?.PrepareSharedWorldItemDismantle(__instance, character); if (!((Object)(object)instance == (Object)null)) { return !instance.RequestWorldGearInteraction(__instance, character, dismantle: true); } return true; } private static void Postfix(DroppedGear __instance) { CoopRuntimePlugin instance = CoopRuntimePlugin.Instance; if (!((Object)(object)__instance == (Object)null)) { if ((Object)(object)instance != (Object)null && instance.IsHost()) { instance.NotifyWorldGearDestroyed(__instance); } else { instance?.NotifyClientWorldGearDismantled(__instance); } } } } [HarmonyPatch(typeof(ItemInventory), "Discard", new Type[] { typeof(int) })] internal static class NetworkInventoryItemDismantleRewardPatch { private static void Prefix(ItemInventory __instance, int index) { if (!((Object)(object)__instance == (Object)null) && index >= 0 && index < __instance.items.Count) { CoopRuntimePlugin.Instance?.PrepareSharedInventoryItemDismantle(__instance.items[index]); } } } [HarmonyPatch(typeof(FireProjectile), "Run", new Type[] { typeof(Character) })] internal static class RemoteBasicProjectileAssetReferencePatch { private static void Prefix(FireProjectile __instance, Character owner) { CoopPlayerRegistry coopPlayerRegistry = CoopRuntimePlugin.Instance?.Players; if (coopPlayerRegistry == null || (Object)(object)owner == (Object)null || !coopPlayerRegistry.IsRemote(owner)) { return; } FieldInfo fieldInfo = AccessTools.Field(typeof(FireProjectile), "_projectile"); if (fieldInfo == null || fieldInfo.GetValue(__instance) != null) { return; } object obj = AccessTools.Field(typeof(FireProjectile), "_projectileReference")?.GetValue(__instance); if (obj == null) { return; } try { if (AccessTools.Method(obj.GetType(), "RuntimeKeyIsValid", (Type[])null, (Type[])null)?.Invoke(obj, null) as bool? != true) { return; } object obj2 = obj.GetType().GetMethods().FirstOrDefault((MethodInfo method) => method.Name == "LoadAssetAsync" && method.IsGenericMethodDefinition && method.GetParameters().Length == 0)?.MakeGenericMethod(typeof(GameObject)).Invoke(obj, null); if (obj2 != null) { object? obj3 = AccessTools.Method(obj2.GetType(), "WaitForCompletion", (Type[])null, (Type[])null)?.Invoke(obj2, null); GameObject val = (GameObject)((obj3 is GameObject) ? obj3 : null); Projectile val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent()); if (!((Object)(object)val2 == (Object)null)) { fieldInfo.SetValue(__instance, val2); AccessTools.Field(typeof(FireProjectile), "_projectileReferenceHandle")?.SetValue(__instance, obj2); CoopRuntimePlugin.Log.LogInfo((object)("Reloaded native basic-projectile reference for remote '" + ((Object)owner).name + "'.")); } } } catch (Exception ex) { CoopRuntimePlugin.Log.LogWarning((object)("Could not reload remote basic-projectile reference: " + ex.Message)); } } } [HarmonyPatch(typeof(Gate), "InteractWith")] internal static class GateCoopTransitionPatch { private static bool Prefix(Gate __instance) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) CoopRuntimePlugin instance = CoopRuntimePlugin.Instance; if ((Object)(object)instance == (Object)null) { return true; } if (!(AccessTools.Field(typeof(Gate), "_nodeIndex")?.GetValue(__instance) is NodeIndex nodeIndex)) { return true; } return instance.HandleGateAttempt(nodeIndex); } } [HarmonyPatch(typeof(LevelManager), "Load", new Type[] { typeof(Type) })] internal static class CastleExitCoopTransitionPatch { private static bool Prefix(LevelManager __instance, Type chapter) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return CoopRuntimePlugin.Instance?.HandleCastleExitLoad(__instance, chapter) ?? true; } private static void Postfix(Type chapter) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) CoopRuntimePlugin.Instance?.NotifyHostCastleExitLoaded(chapter); } } [HarmonyPatch(typeof(SpawnEnemyLineText), "Run")] internal static class HostEnemyLineTextReplicationPatch { private static void Postfix(SpawnEnemyLineText __instance, Character owner) { CoopRuntimePlugin.Instance?.NotifyHostEnemyLineText(owner, __instance); } } }