Decompiled source of OnlineCoopBeta v0.1.1

BepInEx\patchers\SkulOnlineCoopV1.Preloader.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;

[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.Preloader")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SkulOnlineCoopV1.Preloader")]
[assembly: AssemblyTitle("SkulOnlineCoopV1.Preloader")]
[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.Preloader
{
	public static class PlayerContextPreloader
	{
		public static IEnumerable<string> TargetDLLs => new string[1] { "Assembly-CSharp.dll" };

		public static void Patch(ref AssemblyDefinition assembly)
		{
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			ModuleDefinition mainModule = assembly.MainModule;
			TypeDefinition val = mainModule.GetType("Level.LevelManager") ?? throw new InvalidOperationException("Skul Level.LevelManager was not found.");
			TypeDefinition val2 = mainModule.GetType("Characters.Character") ?? throw new InvalidOperationException("Skul Characters.Character was not found.");
			MethodDefinition val3 = ((IEnumerable<MethodDefinition>)val.Methods).Single((MethodDefinition method) => ((MemberReference)method).Name == "get_player" && ((MethodReference)method).Parameters.Count == 0);
			MethodDefinition val4 = AddResolver(mainModule, val, val2, val3);
			int num = 0;
			foreach (MethodDefinition item in from method in AllTypes((IEnumerable<TypeDefinition>)mainModule.Types).SelectMany((TypeDefinition type) => (IEnumerable<MethodDefinition>)type.Methods)
				where method.HasBody
				select method)
			{
				if (item.DeclaringType == val4.DeclaringType)
				{
					continue;
				}
				Instruction[] array = item.Body.Instructions.ToArray();
				foreach (Instruction val5 in array)
				{
					object operand = val5.Operand;
					MethodReference val6 = (MethodReference)((operand is MethodReference) ? operand : null);
					if (val6 != null && !(((MemberReference)((MemberReference)val6).DeclaringType).FullName != ((MemberReference)val).FullName) && !(((MemberReference)val6).Name != ((MemberReference)val3).Name) && val6.Parameters.Count == 0 && !(((MemberReference)val6.ReturnType).FullName != ((MemberReference)val2).FullName))
					{
						val5.OpCode = OpCodes.Call;
						val5.Operand = val4;
						num++;
					}
				}
			}
			Console.WriteLine($"[SkulOnlineCoopV1] Rewrote {num} LevelManager.player reads to PlayerExecutionContext.Resolve.");
		}

		private static MethodDefinition AddResolver(ModuleDefinition module, TypeDefinition levelManager, TypeDefinition character, MethodDefinition getter)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00ba: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_012f: 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_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Expected O, but got Unknown
			//IL_019d: 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_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Expected O, but got Unknown
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Expected O, but got Unknown
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			TypeDefinition type = module.GetType("SkulOnlineCoopV1.Runtime.PlayerExecutionContext");
			if (type != null)
			{
				return ((IEnumerable<MethodDefinition>)type.Methods).Single((MethodDefinition method) => ((MemberReference)method).Name == "Resolve");
			}
			TypeDefinition val = new TypeDefinition("SkulOnlineCoopV1.Runtime", "PlayerExecutionContext", (TypeAttributes)1048961, module.TypeSystem.Object);
			module.Types.Add(val);
			FieldDefinition val2 = new FieldDefinition("_activeCharacter", (FieldAttributes)17, (TypeReference)(object)character);
			val.Fields.Add(val2);
			MethodDefinition val3 = new MethodDefinition("SetCurrent", (MethodAttributes)22, module.TypeSystem.Void);
			((MethodReference)val3).Parameters.Add(new ParameterDefinition("player", (ParameterAttributes)0, (TypeReference)(object)character));
			val3.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
			val3.Body.Instructions.Add(Instruction.Create(OpCodes.Stsfld, (FieldReference)(object)val2));
			val3.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
			val.Methods.Add(val3);
			MethodDefinition val4 = new MethodDefinition("ClearCurrent", (MethodAttributes)22, module.TypeSystem.Void);
			val4.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
			val4.Body.Instructions.Add(Instruction.Create(OpCodes.Stsfld, (FieldReference)(object)val2));
			val4.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
			val.Methods.Add(val4);
			MethodDefinition val5 = new MethodDefinition("GetCurrent", (MethodAttributes)22, (TypeReference)(object)character);
			val5.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, (FieldReference)(object)val2));
			val5.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
			val.Methods.Add(val5);
			MethodDefinition val6 = new MethodDefinition("Resolve", (MethodAttributes)22, (TypeReference)(object)character);
			((MethodReference)val6).Parameters.Add(new ParameterDefinition("manager", (ParameterAttributes)0, (TypeReference)(object)levelManager));
			Instruction val7 = Instruction.Create(OpCodes.Pop);
			val6.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, (FieldReference)(object)val2));
			val6.Body.Instructions.Add(Instruction.Create(OpCodes.Dup));
			val6.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse_S, val7));
			val6.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
			val6.Body.Instructions.Add(val7);
			val6.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
			val6.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, (MethodReference)(object)getter));
			val6.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
			val.Methods.Add(val6);
			return val6;
		}

		private static IEnumerable<TypeDefinition> AllTypes(IEnumerable<TypeDefinition> roots)
		{
			foreach (TypeDefinition type in roots)
			{
				yield return type;
				foreach (TypeDefinition item in AllTypes((IEnumerable<TypeDefinition>)type.NestedTypes))
				{
					yield return item;
				}
			}
		}
	}
}

BepInEx\plugins\SkulOnlineCoopV1.Runtime.dll

Decompiled a week ago
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<Gear>
		{
			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_t>? _lobbyCreated;

		private Callback<LobbyEnter_t>? _lobbyEntered;

		private Callback<GameLobbyJoinRequested_t>? _joinRequested;

		private Callback<P2PSessionRequest_t>? _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<uint> _pendingWorldGearDrops = new HashSet<uint>();

		private readonly HashSet<uint> _advertisedWorldGearDrops = new HashSet<uint>();

		private readonly HashSet<Gear> _requestedClientWorldGear = new HashSet<Gear>(GearReferenceComparer.Instance);

		private readonly HashSet<Gear> _replicatedClientGear = new HashSet<Gear>(GearReferenceComparer.Instance);

		private readonly Dictionary<uint, PendingClientWorldDrop> _pendingClientWorldDrops = new Dictionary<uint, PendingClientWorldDrop>();

		private uint _nextChestRewardGroupId;

		private readonly Dictionary<uint, HashSet<uint>> _chestRewardDropIds = new Dictionary<uint, HashSet<uint>>();

		private readonly Dictionary<uint, HashSet<uint>> _chestRewardSelections = new Dictionary<uint, HashSet<uint>>();

		private readonly HashSet<Chest> _trackedHostChests = new HashSet<Chest>();

		private uint _nextClientWorldDropRequestId;

		private int _replicatedWorldGearCreationDepth;

		private int _replicatedNativeDropCallDepth;

		private readonly HashSet<ulong> _applyingReplicatedItems = new HashSet<ulong>();

		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<int, ReplicatedAnimatorState> _enemyAnimatorStates = new Dictionary<int, ReplicatedAnimatorState>();

		private readonly Dictionary<int, CharacterHealthBar> _generatedEnemyHealthBars = new Dictionary<int, CharacterHealthBar>();

		private readonly Dictionary<uint, float> _replicatedEnemyHealth = new Dictionary<uint, float>();

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

		private readonly HashSet<DroppedRandomWeaponBox> _openedRandomWeaponBoxes = new HashSet<DroppedRandomWeaponBox>();

		private readonly HashSet<uint> _loggedUnboundEnemySnapshots = new HashSet<uint>();

		private readonly List<Character> _clientEnemyCandidates = new List<Character>();

		private string _lastAdvertisedWeaponState = string.Empty;

		private readonly HashSet<string> _loggedLocalActionDiagnostics = new HashSet<string>();

		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<LobbyCreated_t>.Create((DispatchDelegate<LobbyCreated_t>)OnLobbyCreated);
				_lobbyEntered = Callback<LobbyEnter_t>.Create((DispatchDelegate<LobbyEnter_t>)OnLobbyEntered);
				_joinRequested = Callback<GameLobbyJoinRequested_t>.Create((DispatchDelegate<GameLobbyJoinRequested_t>)OnJoinRequested);
				_p2pRequested = Callback<P2PSessionRequest_t>.Create((DispatchDelegate<P2PSessionRequest_t>)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<Service>.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<Item> 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<byte>();
					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<Item>)(object)request).isDone)
					{
						yield return null;
					}
					if ((Object)(object)((Request<Item>)(object)request).asset != (Object)null)
					{
						using (Players.Enter(owner))
						{
							inventory.TryEquip(((Request<Item>)(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<byte>() : 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 ?? "<empty>") + "|" + 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 ?? "<empty>", actionPath, motionIndex, ((val != null) ? ((Object)val).name : null) ?? "<none>"));
			}
			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<AIController>() ?? ((Component)enemy).GetComponentInChildren<AIController>(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<Weapon>() == (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<Weapon>() != (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<Action>(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<string> stack = new Stack<string>();
			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<CharacterAnimation>(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<CSteamID> 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<Character>() ?? ((Component)health).GetComponentInParent<Character>();
				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<Character>() ?? ((Component)health).GetComponentInParent<Character>();
				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<uint> currentlyAlive = new HashSet<uint>();
			DroppedGear[] array = Object.FindObjectsOfType<DroppedGear>();
			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<DroppedGear>();
				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<Service>.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<Weapon>)(object)request).isDone)
				{
					yield return null;
				}
				if ((Object)(object)((Request<Weapon>)(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<Item>)(object)request2).isDone)
				{
					yield return null;
				}
				if ((Object)(object)((Request<Item>)(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<Quintessence>)(object)request3).isDone)
				{
					yield return null;
				}
				if ((Object)(object)((Request<Quintessence>)(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<DroppedGear>();
			foreach (DroppedGear val in array)
			{
				Gear val2 = val.gear ?? ((Component)val).GetComponent<Gear>();
				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<Character>();
				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<AIController>(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<Service>.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<Weapon>)(object)request).isDone)
					{
						yield return null;
					}
					if ((Object)(object)((Request<Weapon>)(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<Item>)(object)request2).isDone)
					{
						yield return null;
					}
					if ((Object)(object)((Request<Item>)(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<Quintessence>)(object)request3).isDone)
					{
						yield return null;
					}
					if ((Object)(object)((Request<Quintessence>)(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<uint, PendingClientWorldDrop>[] array = _pendingClientWorldDrops.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<uint, PendingClientWorldDrop> 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<uint> hashSet = new HashSet<uint>();
					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<uint>();
					_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<uint> value) || !_chestRewardSelections.TryGetValue(chestRewardGroup, out HashSet<uint> 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<Gate>(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<Gear>();
			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<Chest>)Object.FindObjectsOfType<Chest>()).FirstOrDefault((Func<Chest, bool>)((Chest candidate) => ((Component)candidate).gameObject.activeInHierarchy && StableId(((Component)candidate).transform) == signature));
						if (obj2 != null)
						{
							((InteractiveObject)obj2).InteractWith(character);
						}
						break;
					}
					case 2:
					{
						DroppedRandomWeaponBox? obj = ((IEnumerable<DroppedRandomWeaponBox>)Object.FindObjectsOfType<DroppedRandomWeaponBox>()).FirstOrDefault((Func<DroppedRandomWeaponBox, bool>)((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<Chest>)Object.FindObjectsOfType<Chest>()).FirstOrDefault((Func<Chest, bool>)((Chest candidate) => StableId(((Component)candidate).transform) == signature));
				break;
			case 2:
				val = (Component)(object)((IEnumerable<DroppedRandomWeaponBox>)Object.FindObjectsOfType<DroppedRandomWeaponBox>()).FirstOrDefault((Func<DroppedRandomWeaponBox, bool>)((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) ? ob