Decompiled source of Simple Multi Player v1.7.7

WKMultiPlayerMod.dll

Decompiled 3 weeks ago
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DG.Tweening;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Steamworks;
using Steamworks.Data;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using WKMPMod.Asset;
using WKMPMod.Component;
using WKMPMod.Core;
using WKMPMod.Data;
using WKMPMod.MK_Component;
using WKMPMod.NetWork;
using WKMPMod.Patch;
using WKMPMod.RemotePlayer;
using WKMPMod.UI;
using WKMPMod.Util;
using WKMPMod.World;
using WKMPModTemp.World;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WKMultiPlayerMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.7.7.0")]
[assembly: AssemblyInformationalVersion("1.7.7+5b29bc1ad5d0619e4009adabd3b2154c7256cbe6")]
[assembly: AssemblyProduct("WKMultiPlayerMod")]
[assembly: AssemblyTitle("WKMultiPlayerMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.7.7.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
public abstract class Singleton<T> where T : Singleton<T>
{
	private static readonly Lazy<T> _instance = new Lazy<T>(CreateInstance, isThreadSafe: true);

	public static T Instance => _instance.Value;

	public static bool IsCreated => _instance.IsValueCreated;

	private static T CreateInstance()
	{
		try
		{
			ConstructorInfo constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (constructor == null)
			{
				throw new InvalidOperationException("Singleton<" + typeof(T).Name + ">: Type must have a parameterless constructor");
			}
			return (T)constructor.Invoke(null);
		}
		catch (Exception innerException)
		{
			throw new InvalidOperationException("Singleton<" + typeof(T).Name + ">: Failed to create instance", innerException);
		}
	}

	protected Singleton()
	{
		if (_instance.IsValueCreated)
		{
			throw new InvalidOperationException("Singleton<" + typeof(T).Name + ">: Instance already exists. Use " + typeof(T).Name + ".Instance instead.");
		}
	}
}
namespace WKMPModTemp.World
{
	public enum ItemSyncAction : byte
	{
		SnapshotReset = 0,
		SnapshotFinalize = 1,
		Create = 2,
		PickupRequest = 3,
		Remove = 5,
		PickupReject = 6
	}
	public static class ItemSyncManager
	{
		private sealed class PendingLocalDrop
		{
			public Item_Object ItemObject { get; }

			public string PrefabKey { get; }

			public float CreatedAt { get; }

			public PendingLocalDrop(Item_Object itemObject, string prefabKey, float createdAt)
			{
				ItemObject = itemObject;
				PrefabKey = prefabKey;
				CreatedAt = createdAt;
			}
		}

		private const float CandidateMatchDistanceSqr = 0.5f;

		private const float LocalDropMatchDistanceSqr = 25f;

		private const float LocalDropMaxAge = 3f;

		private const float VelocityEpsilonSqr = 0.0025f;

		private const float StableIdPositionPrecision = 20f;

		private const float StableIdRotationPrecision = 5f;

		private const int SnapshotItemsPerFrame = 10;

		private static readonly FieldRef<Item, Item_Object> _dropObjectField = AccessTools.FieldRefAccess<Item, Item_Object>("dropObject");

		private static readonly Func<Item, bool> _inHand = AccessTools.MethodDelegate<Func<Item, bool>>(AccessTools.Method(typeof(Item), "InHand", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Dictionary<string, NetworkedItem> _items = new Dictionary<string, NetworkedItem>();

		private static readonly List<Item_Object> _clientCandidates = new List<Item_Object>();

		private static readonly List<PendingLocalDrop> _pendingLocalDrops = new List<PendingLocalDrop>();

		private static readonly List<Item_Object> _snapshotCandidates = new List<Item_Object>();

		private static readonly Dictionary<ulong, Coroutine> _snapshotRoutines = new Dictionary<ulong, Coroutine>();

		private static ulong _nextLocalItemId = 1uL;

		private static Coroutine _prepareRoutine;

		private static Coroutine _hostDiscoveryRoutine;

		private static bool _hostSceneItemsRegistered;

		private static readonly HashSet<string> _blacklistedPrefabNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Item_Flashlight", "Item_Flaregun", "Item_Cryogun", "Item_Handgun", "Item_Handgun_Debug", "Item_10mm_Ammo" };

		private static readonly HashSet<string> _blacklistedItemTags = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "artifact", "disk", "trinket" };

		public static bool ApplyingRemoteState { get; private set; }

		public static void NotifyWorldInitialized()
		{
			ResetState();
			if (!((Object)(object)MonoSingleton<MPCore>.Instance == (Object)null))
			{
				_prepareRoutine = ((MonoBehaviour)MonoSingleton<MPCore>.Instance).StartCoroutine(PrepareWorldRoutine());
			}
		}

		public static void ResetState()
		{
			if (_prepareRoutine != null && (Object)(object)MonoSingleton<MPCore>.Instance != (Object)null)
			{
				((MonoBehaviour)MonoSingleton<MPCore>.Instance).StopCoroutine(_prepareRoutine);
				_prepareRoutine = null;
			}
			if (_hostDiscoveryRoutine != null && (Object)(object)MonoSingleton<MPCore>.Instance != (Object)null)
			{
				((MonoBehaviour)MonoSingleton<MPCore>.Instance).StopCoroutine(_hostDiscoveryRoutine);
				_hostDiscoveryRoutine = null;
			}
			if ((Object)(object)MonoSingleton<MPCore>.Instance != (Object)null)
			{
				foreach (Coroutine value in _snapshotRoutines.Values)
				{
					if (value != null)
					{
						((MonoBehaviour)MonoSingleton<MPCore>.Instance).StopCoroutine(value);
					}
				}
			}
			_snapshotRoutines.Clear();
			foreach (NetworkedItem value2 in _items.Values)
			{
				if (!((Object)(object)value2 == (Object)null) && !((Object)(object)((Component)value2).gameObject == (Object)null) && value2.WasInstantiatedBySync)
				{
					Object.Destroy((Object)(object)((Component)value2).gameObject);
				}
			}
			_items.Clear();
			_clientCandidates.Clear();
			_pendingLocalDrops.Clear();
			_snapshotCandidates.Clear();
			_hostSceneItemsRegistered = false;
			ApplyingRemoteState = false;
			MPMain.LogInfo("[P2P ItemSync] ResetState completed.");
		}

		public static void SendSnapshotToClient(ulong clientId)
		{
			if (MPCore.CanSync && MonoSingleton<MPSteamworks>.Instance.IsHost && !((Object)(object)MonoSingleton<MPCore>.Instance == (Object)null) && clientId != 0L && clientId != MPSteamworks.UserSteamId)
			{
				if (_snapshotRoutines.TryGetValue(clientId, out Coroutine value) && value != null)
				{
					((MonoBehaviour)MonoSingleton<MPCore>.Instance).StopCoroutine(value);
				}
				_snapshotRoutines[clientId] = ((MonoBehaviour)MonoSingleton<MPCore>.Instance).StartCoroutine(SendSnapshotToClientRoutine(clientId));
			}
		}

		public static void SpawnSyncedWorldDrop(string prefabKey, Vector3 position, Quaternion rotation, Vector3 velocity)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!ApplyingRemoteState && MPCore.CanSync && !string.IsNullOrWhiteSpace(prefabKey))
			{
				Item_Object val = InstantiateWorldItem(prefabKey, position, rotation);
				if (!((Object)(object)val == (Object)null))
				{
					SyncAndBroadcast(val);
				}
			}
		}

		public static NetworkedItem SyncAndBroadcast(Item_Object itemObject)
		{
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)itemObject == (Object)null || (Object)(object)((Component)itemObject).gameObject == (Object)null)
			{
				return null;
			}
			NetworkedItem networkedItem = ((Component)itemObject).GetComponent<NetworkedItem>();
			if ((Object)(object)networkedItem == (Object)null || string.IsNullOrEmpty(networkedItem.NetworkId))
			{
				networkedItem = GetOrCreateIdentity(((Component)itemObject).gameObject);
				networkedItem.NetworkId = $"{MPSteamworks.UserSteamId}:p2p:{_nextLocalItemId++}";
				networkedItem.PrefabKey = GetPrefabKey(itemObject);
				networkedItem.OwnerId = MPSteamworks.UserSteamId;
				networkedItem.IsRemote = false;
				networkedItem.WasInstantiatedBySync = false;
				_items[networkedItem.NetworkId] = networkedItem;
				MPMain.LogTest("[P2P ItemSync] SyncAndBroadcast - Created P2P Identity: " + ((Object)itemObject).name + " → " + networkedItem.NetworkId);
			}
			else if (!_items.ContainsKey(networkedItem.NetworkId))
			{
				_items[networkedItem.NetworkId] = networkedItem;
			}
			BroadcastCreate(networkedItem, itemObject, GetVelocity(itemObject), isDropSpawn: false);
			return networkedItem;
		}

		public static void DespawnAndBroadcast(Item_Object itemObject)
		{
			if (!((Object)(object)itemObject == (Object)null))
			{
				NetworkedItem component = ((Component)itemObject).GetComponent<NetworkedItem>();
				if ((Object)(object)component != (Object)null && !string.IsNullOrEmpty(component.NetworkId))
				{
					MPMain.LogTest("[P2P ItemSync] DespawnAndBroadcast - Broadcasting global destruction: " + component.NetworkId);
					BroadcastRemove(0uL, component.NetworkId);
					Forget(component.NetworkId);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)itemObject).gameObject);
				}
			}
		}

		public static void ForceCleanupItemPhysicalAndInventory(string networkId)
		{
			if (string.IsNullOrEmpty(networkId))
			{
				return;
			}
			MPMain.LogTest("[P2P ItemSync] ForceCleanup - Double-Destruction: " + networkId);
			MPMain.LogTest("ForceCleanupItemPhysicalAndInventory A");
			Inventory inventory = ENT_Player.GetInventory();
			if (inventory?.bagItems != null)
			{
				for (int num = inventory.bagItems.Count - 1; num >= 0; num--)
				{
					Item val = inventory.bagItems[num];
					if (val != null)
					{
						Item_Object val2 = _dropObjectField.Invoke(val);
						if (!((Object)(object)val2 == (Object)null))
						{
							NetworkedItem component = ((Component)val2).GetComponent<NetworkedItem>();
							MPMain.LogTest("ForceCleanupItemPhysicalAndInventory AA");
							if (!((Object)(object)component == (Object)null) && !(component.NetworkId != networkId))
							{
								MPMain.LogTest("ForceCleanupItemPhysicalAndInventory AB");
								inventory.bagItems.RemoveAt(num);
								if (_inHand(val))
								{
									inventory.ClearItemFromHand(val);
								}
								val.hasBeenDestroyed = true;
								MPMain.LogTest("[P2P ItemSync] ForceCleanup - Evicted '" + val.itemName + "' from inventory.");
							}
						}
					}
				}
			}
			if (inventory?.itemHands != null)
			{
				ItemHand[] itemHands = inventory.itemHands;
				foreach (ItemHand val3 in itemHands)
				{
					if (val3 == null || val3.currentItem == null)
					{
						continue;
					}
					Item currentItem = val3.currentItem;
					Item_Object val4 = _dropObjectField.Invoke(currentItem);
					if (!((Object)(object)val4 == (Object)null))
					{
						NetworkedItem component2 = ((Component)val4).GetComponent<NetworkedItem>();
						if (!((Object)(object)component2 == (Object)null) && !(component2.NetworkId != networkId))
						{
							inventory.ClearItemFromHand(currentItem);
							currentItem.hasBeenDestroyed = true;
							MPMain.LogWarning("[P2P ItemSync] API 3 - Removed stale/rejected item '" + currentItem.itemName + "' directly from Player Hands!");
						}
					}
				}
			}
			if (inventory != null)
			{
				inventory.RescanInventory();
			}
			if (!_items.TryGetValue(networkId, out NetworkedItem value) || (Object)(object)value == (Object)null)
			{
				MPMain.LogTest("ForceCleanupItemPhysicalAndInventory B");
				return;
			}
			Item_Object component3 = ((Component)value).GetComponent<Item_Object>();
			if ((Object)(object)component3 != (Object)null)
			{
				MPMain.LogTest("ForceCleanupItemPhysicalAndInventory C");
				RemoveCandidate(component3);
				if (component3.itemData != null)
				{
					_dropObjectField.Invoke(component3.itemData) = null;
				}
			}
			if ((Object)(object)((Component)value).gameObject != (Object)null)
			{
				MPMain.LogTest("ForceCleanupItemPhysicalAndInventory D");
				((Component)value).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)value).gameObject);
			}
			MPMain.LogTest("ForceCleanupItemPhysicalAndInventory E");
			_items.Remove(networkId);
		}

		public static void NotifyLocalPickup(Item_Object itemObject)
		{
			if (ApplyingRemoteState || (Object)(object)itemObject == (Object)null || !MPCore.CanSync || IsPendingLocalDrop(itemObject))
			{
				return;
			}
			NetworkedItem component = ((Component)itemObject).GetComponent<NetworkedItem>();
			if (!((Object)(object)component == (Object)null) && !string.IsNullOrEmpty(component.NetworkId))
			{
				MPMain.LogInfo($"[P2P ItemSync] LocalPickup: {((Object)itemObject).name}, ID={component.NetworkId}, Owner={component.OwnerId}");
				if (component.OwnerId == MPSteamworks.UserSteamId)
				{
					BroadcastRemove(MPSteamworks.UserSteamId, component.NetworkId);
					Forget(component.NetworkId);
				}
				else
				{
					SendPickupRequestToOwner(component.NetworkId, component.OwnerId);
				}
			}
		}

		public static void NotifyLocalDrop(Item item)
		{
			if (!ApplyingRemoteState && item != null && MPCore.CanSync)
			{
				Item_Object itemObject = _dropObjectField.Invoke(item);
				if (IsSyncableDropItem(itemObject))
				{
					SyncAndBroadcast(itemObject);
				}
			}
		}

		public static void HandleItemState(ulong senderId, DataReader reader)
		{
			MPMain.LogTest("HandleItemState");
			ItemSyncAction itemSyncAction = (ItemSyncAction)reader.GetByte();
			try
			{
				switch (itemSyncAction)
				{
				case ItemSyncAction.SnapshotReset:
					MPMain.LogTest("HandleSnapshotReset");
					HandleSnapshotReset();
					break;
				case ItemSyncAction.SnapshotFinalize:
					MPMain.LogTest("HandleSnapshotFinalize");
					HandleSnapshotFinalize();
					break;
				case ItemSyncAction.Create:
					MPMain.LogTest("HandleCreate");
					HandleCreate(senderId, reader);
					break;
				case ItemSyncAction.PickupRequest:
					MPMain.LogTest("HandlePickupRequest");
					HandlePickupRequest(senderId, reader);
					break;
				case ItemSyncAction.Remove:
					MPMain.LogTest("HandleRemove");
					HandleRemove(reader);
					break;
				case ItemSyncAction.PickupReject:
					MPMain.LogTest("HandlePickupReject");
					HandlePickupReject(reader);
					break;
				case (ItemSyncAction)4:
					break;
				}
			}
			catch (Exception ex)
			{
				MPMain.LogError($"[P2P ItemSync] HandleItemState failed for action {itemSyncAction}: {ex.Message}");
			}
		}

		private static void HandleSnapshotReset()
		{
			if (!MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				ResetState();
				CaptureSceneCandidates(snapshotCandidate: true);
			}
		}

		private static void HandleSnapshotFinalize()
		{
			if (MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				return;
			}
			int num = 0;
			for (int num2 = _snapshotCandidates.Count - 1; num2 >= 0; num2--)
			{
				Item_Object val = _snapshotCandidates[num2];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null))
				{
					NetworkedItem component = ((Component)val).GetComponent<NetworkedItem>();
					if (!((Object)(object)component != (Object)null) || string.IsNullOrEmpty(component.NetworkId) || !_items.ContainsKey(component.NetworkId))
					{
						((Component)val).gameObject.SetActive(false);
						num++;
					}
				}
			}
			_snapshotCandidates.Clear();
		}

		private static void HandleCreate(ulong senderId, DataReader reader)
		{
			//IL_0010: 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)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			string text = reader.GetString();
			string text2 = reader.GetString();
			Vector3 vector = reader.GetVector3();
			Quaternion quaternion = reader.GetQuaternion();
			Vector3 vector2 = reader.GetVector3();
			bool flag = reader.GetBool();
			if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2))
			{
				return;
			}
			if (_items.TryGetValue(text, out NetworkedItem value) && (Object)(object)value != (Object)null)
			{
				ApplyCreate(value, vector, quaternion, vector2, flag, skipDropCallbacks: true);
				return;
			}
			Item_Object val = (flag ? FindPendingLocalDrop(text2, vector) : null);
			bool wasSnapshotCandidate = false;
			if ((Object)(object)val == (Object)null)
			{
				val = FindSceneItemByStableId(text);
				if ((Object)(object)val != (Object)null)
				{
					wasSnapshotCandidate = _snapshotCandidates.Contains(val);
					RemoveCandidate(val);
				}
				else if ((Object)(object)val == (Object)null)
				{
					val = FindClientCandidate(text2, vector, out wasSnapshotCandidate);
				}
			}
			Item_Object val2 = val;
			bool wasInstantiatedBySync = false;
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = InstantiateWorldItem(text2, vector, quaternion);
				wasInstantiatedBySync = (Object)(object)val2 != (Object)null;
			}
			if (!((Object)(object)val2 == (Object)null))
			{
				NetworkedItem orCreateIdentity = GetOrCreateIdentity(((Component)val2).gameObject);
				if (text.StartsWith("sceneitem:", StringComparison.Ordinal))
				{
					orCreateIdentity.StableSceneId = text;
				}
				orCreateIdentity.NetworkId = text;
				orCreateIdentity.PrefabKey = text2;
				orCreateIdentity.OwnerId = senderId;
				orCreateIdentity.IsRemote = true;
				orCreateIdentity.WasInstantiatedBySync = wasInstantiatedBySync;
				_items[text] = orCreateIdentity;
				bool skipDropCallbacks = !wasSnapshotCandidate && (Object)(object)val != (Object)null && flag;
				ApplyCreate(orCreateIdentity, vector, quaternion, vector2, flag, skipDropCallbacks);
			}
		}

		private static void HandlePickupRequest(ulong requesterId, DataReader reader)
		{
			string text = reader.GetString();
			if (!string.IsNullOrEmpty(text))
			{
				MPMain.LogInfo($"[P2P ItemSync] PickupRequest from {requesterId} for {text}");
				if (!_items.TryGetValue(text, out NetworkedItem value))
				{
					MPMain.LogTest("HandlePickupRequest A");
					SendPickupReject(requesterId, text);
				}
				else if (IsItemInInventory(value))
				{
					MPMain.LogWarning("[P2P ItemSync] PickupRequest denied: Item " + text + " is already in local inventory.");
					SendPickupReject(requesterId, text);
				}
				else if (value.OwnerId == MPSteamworks.UserSteamId)
				{
					MPMain.LogTest("HandlePickupRequest B");
					BroadcastRemove(requesterId, text);
					Forget(text);
				}
				else
				{
					MPMain.LogTest("HandlePickupRequest C");
					SendPickupReject(requesterId, text);
				}
			}
		}

		private static void HandlePickupReject(DataReader reader)
		{
			string text = reader.GetString();
			if (!string.IsNullOrEmpty(text))
			{
				MPMain.LogWarning("[P2P ItemSync] PickupReject received! Rolling back inventory for " + text);
				ForceCleanupItemPhysicalAndInventory(text);
			}
		}

		private static void HandleRemove(DataReader reader)
		{
			string text = reader.GetString();
			ulong uLong = reader.GetULong();
			if (!string.IsNullOrEmpty(text))
			{
				if (uLong == MPSteamworks.UserSteamId)
				{
					Forget(text);
				}
				else
				{
					ForceCleanupItemPhysicalAndInventory(text);
				}
			}
		}

		private static void SendPickupRequestToOwner(string networkId, ulong ownerId)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, ownerId, PacketType.ItemStateSync);
			writer.Put((byte)3);
			writer.Put(networkId);
			MonoSingleton<MPSteamworks>.Instance.SendToPeer(SteamId.op_Implicit(ownerId), writer, (SendType)8, 0);
		}

		private static void SendPickupReject(ulong targetId, string networkId)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, targetId, PacketType.ItemStateSync);
			writer.Put((byte)6);
			writer.Put(networkId);
			MonoSingleton<MPSteamworks>.Instance.SendToPeer(SteamId.op_Implicit(targetId), writer, (SendType)8, 0);
		}

		private static void BroadcastCreate(NetworkedItem identity, Item_Object itemObject, Vector3 velocity, bool isDropSpawn)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)identity == (Object)null) && !((Object)(object)itemObject == (Object)null) && !string.IsNullOrEmpty(identity.NetworkId))
			{
				DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, 0uL, PacketType.ItemStateSync);
				writer.Put((byte)2);
				writer.Put(identity.NetworkId);
				writer.Put(identity.PrefabKey);
				writer.Put(((Component)itemObject).transform.position);
				writer.Put(((Component)itemObject).transform.rotation);
				writer.Put(velocity);
				writer.Put(isDropSpawn);
				MonoSingleton<MPSteamworks>.Instance.Broadcast(writer, (SendType)8, 0);
			}
		}

		private static void BroadcastRemove(ulong holderId, string networkId)
		{
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, 0uL, PacketType.ItemStateSync);
			writer.Put((byte)5);
			writer.Put(networkId);
			writer.Put(holderId);
			MonoSingleton<MPSteamworks>.Instance.Broadcast(writer, (SendType)8, 0);
		}

		private static void SendSnapshotReset(ulong clientId)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, clientId, PacketType.ItemStateSync);
			writer.Put((byte)0);
			MonoSingleton<MPSteamworks>.Instance.SendToPeer(SteamId.op_Implicit(clientId), writer, (SendType)8, 0);
		}

		private static void SendSnapshotFinalize(ulong clientId)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, clientId, PacketType.ItemStateSync);
			writer.Put((byte)1);
			MonoSingleton<MPSteamworks>.Instance.SendToPeer(SteamId.op_Implicit(clientId), writer, (SendType)8, 0);
		}

		private static void SendCreate(ulong clientId, NetworkedItem identity, Item_Object itemObject, Vector3 velocity, bool isDropSpawn)
		{
			//IL_005e: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)identity == (Object)null) && !((Object)(object)itemObject == (Object)null) && !string.IsNullOrEmpty(identity.NetworkId))
			{
				DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, clientId, PacketType.ItemStateSync);
				writer.Put((byte)2);
				writer.Put(identity.NetworkId);
				writer.Put(identity.PrefabKey);
				writer.Put(((Component)itemObject).transform.position);
				writer.Put(((Component)itemObject).transform.rotation);
				writer.Put(velocity);
				writer.Put(isDropSpawn);
				MonoSingleton<MPSteamworks>.Instance.SendToPeer(SteamId.op_Implicit(clientId), writer, (SendType)8, 0);
			}
		}

		private static IEnumerator PrepareWorldRoutine()
		{
			yield return (object)new WaitUntil((Func<bool>)(() => WorldLoader.isLoaded && WorldLoader.initialized));
			yield return null;
			yield return null;
			if (MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				yield return RegisterHostSceneItemsRoutine();
				if ((Object)(object)MonoSingleton<MPCore>.Instance != (Object)null && _hostDiscoveryRoutine == null)
				{
					_hostDiscoveryRoutine = ((MonoBehaviour)MonoSingleton<MPCore>.Instance).StartCoroutine(HostDiscoveryRoutine());
				}
			}
			else if (MPCore.IsInLobby)
			{
				CaptureSceneCandidates(snapshotCandidate: true);
			}
		}

		private static IEnumerator SendSnapshotToClientRoutine(ulong clientId)
		{
			yield return (object)new WaitUntil((Func<bool>)(() => WorldLoader.isLoaded && WorldLoader.initialized));
			if (!_hostSceneItemsRegistered)
			{
				yield return RegisterHostSceneItemsRoutine();
			}
			SendSnapshotReset(clientId);
			List<NetworkedItem> snapshot = new List<NetworkedItem>(EnumerateKnownHostWorldItems());
			int sentThisFrame = 0;
			foreach (NetworkedItem identity in snapshot)
			{
				if ((Object)(object)identity == (Object)null || (Object)(object)((Component)identity).gameObject == (Object)null)
				{
					continue;
				}
				Item_Object itemObject = ((Component)identity).GetComponent<Item_Object>();
				if (IsSyncableWorldItem(itemObject))
				{
					SendCreate(clientId, identity, itemObject, GetVelocity(itemObject), isDropSpawn: false);
					int num = sentThisFrame + 1;
					sentThisFrame = num;
					if (num >= 10)
					{
						sentThisFrame = 0;
						yield return null;
					}
				}
			}
			SendSnapshotFinalize(clientId);
			_snapshotRoutines.Remove(clientId);
		}

		private static IEnumerator RegisterHostSceneItemsRoutine()
		{
			if (!MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				yield break;
			}
			int registeredThisFrame = 0;
			int totalRegistered = 0;
			foreach (Item_Object itemObject in EnumerateSceneItems())
			{
				string prefabKey = GetPrefabKey(itemObject);
				if (!string.IsNullOrEmpty(prefabKey))
				{
					RegisterHostItem(itemObject, prefabKey, preferStableSceneIdentity: true);
					totalRegistered++;
					int num = registeredThisFrame + 1;
					registeredThisFrame = num;
					if (num >= 10)
					{
						registeredThisFrame = 0;
						yield return null;
					}
				}
			}
			_hostSceneItemsRegistered = true;
		}

		private static IEnumerator HostDiscoveryRoutine()
		{
			WaitForSecondsRealtime wait = new WaitForSecondsRealtime(0.5f);
			while ((Object)(object)MonoSingleton<MPCore>.Instance != (Object)null)
			{
				if (MPCore.CanSync && MonoSingleton<MPSteamworks>.Instance.IsHost && _hostSceneItemsRegistered)
				{
					DiscoverAndBroadcastNewHostWorldItems();
				}
				yield return wait;
			}
			_hostDiscoveryRoutine = null;
		}

		private static void DiscoverAndBroadcastNewHostWorldItems()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			foreach (Item_Object item in EnumerateSceneItems())
			{
				if (TryPrepareNewHostWorldItem(item, out string prefabKey))
				{
					NetworkedItem identity = RegisterHostItem(item, prefabKey, preferStableSceneIdentity: true);
					BroadcastCreate(identity, item, GetVelocity(item), isDropSpawn: false);
				}
			}
		}

		private static NetworkedItem RegisterHostItem(Item_Object itemObject, string prefabKey, bool preferStableSceneIdentity = false)
		{
			NetworkedItem orCreateIdentity = GetOrCreateIdentity(((Component)itemObject).gameObject);
			if (preferStableSceneIdentity)
			{
				TryAssignStableSceneIdentity(itemObject, orCreateIdentity);
			}
			if (string.IsNullOrEmpty(orCreateIdentity.NetworkId))
			{
				orCreateIdentity.NetworkId = $"scene:{MonoSingleton<MPSteamworks>.Instance.HostSteamId}:item:{_nextLocalItemId++}";
			}
			orCreateIdentity.PrefabKey = prefabKey;
			orCreateIdentity.OwnerId = MonoSingleton<MPSteamworks>.Instance.HostSteamId;
			orCreateIdentity.IsRemote = false;
			orCreateIdentity.WasInstantiatedBySync = false;
			_items[orCreateIdentity.NetworkId] = orCreateIdentity;
			return orCreateIdentity;
		}

		private static bool TryPrepareNewHostWorldItem(Item_Object itemObject, out string prefabKey)
		{
			prefabKey = string.Empty;
			if (!IsSyncableWorldItem(itemObject))
			{
				return false;
			}
			prefabKey = GetPrefabKey(itemObject);
			if (string.IsNullOrEmpty(prefabKey))
			{
				return false;
			}
			NetworkedItem component = ((Component)itemObject).GetComponent<NetworkedItem>();
			if ((Object)(object)component == (Object)null || string.IsNullOrEmpty(component.NetworkId))
			{
				return true;
			}
			return !_items.ContainsKey(component.NetworkId);
		}

		private static IEnumerable<NetworkedItem> EnumerateKnownHostWorldItems()
		{
			foreach (NetworkedItem identity in _items.Values)
			{
				if (!((Object)(object)identity == (Object)null) && !((Object)(object)((Component)identity).gameObject == (Object)null))
				{
					Item_Object itemObject = ((Component)identity).GetComponent<Item_Object>();
					if (IsSyncableWorldItem(itemObject))
					{
						yield return identity;
					}
				}
			}
		}

		private static void ApplyCreate(NetworkedItem identity, Vector3 position, Quaternion rotation, Vector3 velocity, bool isDropSpawn, bool skipDropCallbacks)
		{
			//IL_0030: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)identity == (Object)null || (Object)(object)((Component)identity).gameObject == (Object)null)
			{
				return;
			}
			ApplyingRemoteState = true;
			try
			{
				((Component)identity).transform.SetPositionAndRotation(position, rotation);
				Item_Object component = ((Component)identity).GetComponent<Item_Object>();
				if (component?.itemData != null)
				{
					_dropObjectField.Invoke(component.itemData) = component;
				}
				if (isDropSpawn && (Object)(object)component != (Object)null && !skipDropCallbacks)
				{
					component.OnDrop();
				}
				Rigidbody rigidbody = GetRigidbody(((Component)identity).gameObject);
				if ((Object)(object)rigidbody != (Object)null)
				{
					rigidbody.isKinematic = false;
					rigidbody.velocity = velocity;
				}
				((Component)identity).gameObject.SetActive(true);
			}
			finally
			{
				ApplyingRemoteState = false;
			}
		}

		private static void Forget(string networkId)
		{
			if (!_items.TryGetValue(networkId, out NetworkedItem value) || (Object)(object)value == (Object)null)
			{
				TryForgetUnknownSceneItem(networkId);
				return;
			}
			Item_Object component = ((Component)value).GetComponent<Item_Object>();
			if ((Object)(object)component != (Object)null)
			{
				RemoveCandidate(component);
			}
			if ((Object)(object)((Component)value).gameObject != (Object)null)
			{
				if ((Object)(object)component != (Object)null && component.itemData != null && (component.itemData.inBag || _inHand(component.itemData)))
				{
					value.NetworkId = string.Empty;
					value.StableSceneId = string.Empty;
					value.WasInstantiatedBySync = false;
				}
				else
				{
					((Component)value).gameObject.SetActive(false);
					if (value.WasInstantiatedBySync)
					{
						Object.Destroy((Object)(object)((Component)value).gameObject);
					}
					else
					{
						value.NetworkId = string.Empty;
						value.StableSceneId = string.Empty;
					}
				}
			}
			_items.Remove(networkId);
		}

		private static bool TryForgetUnknownSceneItem(string networkId)
		{
			if (string.IsNullOrEmpty(networkId) || !networkId.StartsWith("sceneitem:", StringComparison.Ordinal))
			{
				return false;
			}
			Item_Object val = FindSceneItemByStableId(networkId);
			if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null)
			{
				return false;
			}
			NetworkedItem component = ((Component)val).GetComponent<NetworkedItem>();
			if ((Object)(object)component != (Object)null && string.IsNullOrEmpty(component.NetworkId))
			{
				component.NetworkId = string.Empty;
				component.StableSceneId = string.Empty;
			}
			RemoveCandidate(val);
			((Component)val).gameObject.SetActive(false);
			_items.Remove(networkId);
			return true;
		}

		private static Item_Object InstantiateWorldItem(string prefabKey, Vector3 position, Quaternion rotation)
		{
			//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)
			GameObject assetGameObject = CL_AssetManager.GetAssetGameObject(prefabKey, "");
			if ((Object)(object)assetGameObject == (Object)null)
			{
				return null;
			}
			ApplyingRemoteState = true;
			try
			{
				GameObject val = Object.Instantiate<GameObject>(assetGameObject, position, rotation);
				Transform currentLevelParentRoot = WorldLoader.GetCurrentLevelParentRoot();
				if ((Object)(object)currentLevelParentRoot != (Object)null)
				{
					val.transform.SetParent(currentLevelParentRoot);
				}
				Item_Object val2 = val.GetComponent<Item_Object>() ?? val.GetComponentInChildren<Item_Object>(true);
				if (val2?.itemData != null)
				{
					val2.itemData.InitializeItemData(val2);
				}
				return val2;
			}
			finally
			{
				ApplyingRemoteState = false;
			}
		}

		private static void CaptureSceneCandidates(bool snapshotCandidate)
		{
			foreach (Item_Object item in EnumerateSceneItems())
			{
				RememberCandidate(item, snapshotCandidate);
			}
		}

		private static IEnumerable<Item_Object> EnumerateSceneItems()
		{
			Item_Object[] array = Object.FindObjectsOfType<Item_Object>();
			foreach (Item_Object itemObject in array)
			{
				if (IsSyncableWorldItem(itemObject) && !IsBlacklisted(itemObject))
				{
					yield return itemObject;
				}
			}
		}

		private static void RememberCandidate(Item_Object itemObject, bool snapshotCandidate)
		{
			if (!IsSyncableWorldItem(itemObject))
			{
				return;
			}
			NetworkedItem orCreateIdentity = GetOrCreateIdentity(((Component)itemObject).gameObject);
			if (snapshotCandidate && TryAssignStableSceneIdentity(itemObject, orCreateIdentity))
			{
				orCreateIdentity.PrefabKey = GetPrefabKey(itemObject);
				_items[orCreateIdentity.NetworkId] = orCreateIdentity;
				return;
			}
			if (!string.IsNullOrEmpty(orCreateIdentity.NetworkId))
			{
				_items[orCreateIdentity.NetworkId] = orCreateIdentity;
				return;
			}
			if (!_clientCandidates.Contains(itemObject))
			{
				_clientCandidates.Add(itemObject);
			}
			if (snapshotCandidate && !_snapshotCandidates.Contains(itemObject))
			{
				_snapshotCandidates.Add(itemObject);
			}
		}

		private static void RemoveCandidate(Item_Object itemObject)
		{
			_clientCandidates.Remove(itemObject);
			_snapshotCandidates.Remove(itemObject);
			RemovePendingLocalDrop(itemObject);
		}

		private static Item_Object FindClientCandidate(string prefabKey, Vector3 position, out bool wasSnapshotCandidate)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			RemoveDestroyedCandidates();
			Item_Object val = null;
			float num = float.MaxValue;
			wasSnapshotCandidate = false;
			foreach (Item_Object clientCandidate in _clientCandidates)
			{
				if (IsSyncableWorldItem(clientCandidate) && PrefabKeysMatch(prefabKey, GetPrefabKey(clientCandidate)))
				{
					Vector3 val2 = ((Component)clientCandidate).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (!(sqrMagnitude > 0.5f) && !(sqrMagnitude >= num))
					{
						val = clientCandidate;
						num = sqrMagnitude;
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				wasSnapshotCandidate = _snapshotCandidates.Contains(val);
				RemoveCandidate(val);
			}
			return val;
		}

		private static void RemoveDestroyedCandidates()
		{
			for (int num = _clientCandidates.Count - 1; num >= 0; num--)
			{
				if (!IsSyncableWorldItem(_clientCandidates[num]))
				{
					_clientCandidates.RemoveAt(num);
				}
			}
			for (int num2 = _snapshotCandidates.Count - 1; num2 >= 0; num2--)
			{
				if (!IsSyncableWorldItem(_snapshotCandidates[num2]))
				{
					_snapshotCandidates.RemoveAt(num2);
				}
			}
			RemoveDestroyedPendingLocalDrops();
		}

		private static Item_Object FindPendingLocalDrop(string prefabKey, Vector3 position)
		{
			//IL_004d: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			RemoveDestroyedPendingLocalDrops();
			Item_Object val = null;
			float num = float.MaxValue;
			for (int num2 = _pendingLocalDrops.Count - 1; num2 >= 0; num2--)
			{
				PendingLocalDrop pendingLocalDrop = _pendingLocalDrops[num2];
				if (PrefabKeysMatch(prefabKey, pendingLocalDrop.PrefabKey))
				{
					Vector3 val2 = ((Component)pendingLocalDrop.ItemObject).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (!(sqrMagnitude > 25f) && !(sqrMagnitude >= num))
					{
						val = pendingLocalDrop.ItemObject;
						num = sqrMagnitude;
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				RemoveCandidate(val);
			}
			return val;
		}

		private static bool IsPendingLocalDrop(Item_Object itemObject)
		{
			if ((Object)(object)itemObject == (Object)null)
			{
				return false;
			}
			RemoveDestroyedPendingLocalDrops();
			foreach (PendingLocalDrop pendingLocalDrop in _pendingLocalDrops)
			{
				if ((Object)(object)pendingLocalDrop.ItemObject == (Object)(object)itemObject)
				{
					return true;
				}
			}
			return false;
		}

		private static void RemovePendingLocalDrop(Item_Object itemObject)
		{
			if ((Object)(object)itemObject == (Object)null)
			{
				return;
			}
			for (int num = _pendingLocalDrops.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)_pendingLocalDrops[num].ItemObject == (Object)(object)itemObject)
				{
					_pendingLocalDrops.RemoveAt(num);
				}
			}
		}

		private static void RemoveDestroyedPendingLocalDrops()
		{
			float num = Time.time - 3f;
			for (int num2 = _pendingLocalDrops.Count - 1; num2 >= 0; num2--)
			{
				PendingLocalDrop pendingLocalDrop = _pendingLocalDrops[num2];
				if (!IsSyncableWorldItem(pendingLocalDrop.ItemObject) || pendingLocalDrop.CreatedAt < num)
				{
					_pendingLocalDrops.RemoveAt(num2);
				}
			}
		}

		private static bool TryAssignStableSceneIdentity(Item_Object itemObject, NetworkedItem identity)
		{
			if ((Object)(object)itemObject == (Object)null || (Object)(object)identity == (Object)null)
			{
				return false;
			}
			if (!string.IsNullOrEmpty(identity.NetworkId))
			{
				return false;
			}
			string stableSceneItemId = GetStableSceneItemId(itemObject);
			if (string.IsNullOrEmpty(stableSceneItemId))
			{
				return false;
			}
			identity.StableSceneId = stableSceneItemId;
			identity.NetworkId = stableSceneItemId;
			return true;
		}

		private static string GetStableSceneItemId(Item_Object itemObject)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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)
			if ((Object)(object)itemObject == (Object)null || (Object)(object)((Component)itemObject).gameObject == (Object)null)
			{
				return string.Empty;
			}
			Scene scene = ((Component)itemObject).gameObject.scene;
			if (((Scene)(ref scene)).IsValid())
			{
				scene = ((Component)itemObject).gameObject.scene;
				if (!string.IsNullOrEmpty(((Scene)(ref scene)).name))
				{
					NetworkedItem component = ((Component)itemObject).GetComponent<NetworkedItem>();
					if ((Object)(object)component != (Object)null && !string.IsNullOrEmpty(component.StableSceneId))
					{
						return component.StableSceneId;
					}
					string text = BuildTransformPath(((Component)itemObject).transform);
					if (string.IsNullOrEmpty(text))
					{
						return string.Empty;
					}
					string text2 = BuildStableTransformAnchor(((Component)itemObject).transform);
					string[] obj = new string[6] { "sceneitem:", null, null, null, null, null };
					scene = ((Component)itemObject).gameObject.scene;
					obj[1] = ((Scene)(ref scene)).name;
					obj[2] = ":";
					obj[3] = text;
					obj[4] = "|";
					obj[5] = text2;
					return string.Concat(obj);
				}
			}
			return string.Empty;
		}

		private static Item_Object FindSceneItemByStableId(string networkId)
		{
			if (string.IsNullOrEmpty(networkId) || !networkId.StartsWith("sceneitem:", StringComparison.Ordinal))
			{
				return null;
			}
			foreach (Item_Object item in EnumerateSceneItems())
			{
				if (string.Equals(GetStableSceneItemId(item), networkId, StringComparison.Ordinal))
				{
					return item;
				}
			}
			return null;
		}

		private static bool IsSyncableWorldItem(Item_Object itemObject)
		{
			//IL_003d: 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)
			if ((Object)(object)itemObject == (Object)null || (Object)(object)((Component)itemObject).gameObject == (Object)null)
			{
				return false;
			}
			if (!((Component)itemObject).gameObject.activeInHierarchy)
			{
				return false;
			}
			Scene scene = ((Component)itemObject).gameObject.scene;
			if (string.IsNullOrEmpty(((Scene)(ref scene)).name))
			{
				return false;
			}
			if (itemObject.itemData == null)
			{
				return false;
			}
			if (itemObject.itemData.inBag)
			{
				return false;
			}
			return true;
		}

		private static bool IsSyncableDropItem(Item_Object itemObject)
		{
			//IL_003d: 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)
			if ((Object)(object)itemObject == (Object)null || (Object)(object)((Component)itemObject).gameObject == (Object)null)
			{
				return false;
			}
			if (!((Component)itemObject).gameObject.activeInHierarchy)
			{
				return false;
			}
			Scene scene = ((Component)itemObject).gameObject.scene;
			if (string.IsNullOrEmpty(((Scene)(ref scene)).name))
			{
				return false;
			}
			if (itemObject.itemData == null)
			{
				return false;
			}
			if (itemObject.itemData.inBag)
			{
				return false;
			}
			return true;
		}

		private static Rigidbody GetRigidbody(GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return null;
			}
			return gameObject.GetComponent<Rigidbody>() ?? gameObject.GetComponentInChildren<Rigidbody>();
		}

		private static NetworkedItem GetOrCreateIdentity(GameObject gameObject)
		{
			return gameObject.GetComponent<NetworkedItem>() ?? gameObject.AddComponent<NetworkedItem>();
		}

		private static string BuildTransformPath(Transform transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder();
			Stack<string> stack = new Stack<string>();
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				stack.Push($"{MPUtil.CleanCloneName(((Object)val).name)}[{val.GetSiblingIndex()}]");
				val = val.parent;
			}
			while (stack.Count > 0)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('/');
				}
				stringBuilder.Append(stack.Pop());
			}
			return stringBuilder.ToString();
		}

		private static Vector3 GetVelocity(Item_Object itemObject)
		{
			//IL_0021: 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_0018: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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)
			Rigidbody rigidbody = GetRigidbody(((Component)itemObject).gameObject);
			if ((Object)(object)rigidbody == (Object)null)
			{
				return Vector3.zero;
			}
			Vector3 velocity = rigidbody.velocity;
			return (((Vector3)(ref velocity)).sqrMagnitude > 0.0025f) ? rigidbody.velocity : Vector3.zero;
		}

		private static int Quantize(float value, float precision)
		{
			return Mathf.RoundToInt(value * precision);
		}

		private static float NormalizeAngle(float value)
		{
			value %= 360f;
			if (value < 0f)
			{
				value += 360f;
			}
			return value;
		}

		private static string BuildStableTransformAnchor(Transform transform)
		{
			//IL_0018: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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)
			if ((Object)(object)transform == (Object)null)
			{
				return string.Empty;
			}
			Vector3 localPosition = transform.localPosition;
			Vector3 localEulerAngles = transform.localEulerAngles;
			return $"lp:{Quantize(localPosition.x, 20f)},{Quantize(localPosition.y, 20f)},{Quantize(localPosition.z, 20f)}" + $"|lr:{Quantize(NormalizeAngle(localEulerAngles.x), 5f)},{Quantize(NormalizeAngle(localEulerAngles.y), 5f)},{Quantize(NormalizeAngle(localEulerAngles.z), 5f)}";
		}

		private static string GetPrefabKey(Item_Object itemObject)
		{
			if ((Object)(object)itemObject == (Object)null)
			{
				return string.Empty;
			}
			if (itemObject.itemData != null && !string.IsNullOrEmpty(itemObject.itemData.prefabName))
			{
				return itemObject.itemData.prefabName;
			}
			return MPUtil.CleanCloneName(((Object)((Component)itemObject).gameObject).name);
		}

		private static bool PrefabKeysMatch(string a, string b)
		{
			if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b))
			{
				return false;
			}
			return string.Equals(MPUtil.CleanCloneName(a), MPUtil.CleanCloneName(b), StringComparison.OrdinalIgnoreCase);
		}

		private static bool IsItemInInventory(NetworkedItem identity)
		{
			if ((Object)(object)identity == (Object)null || (Object)(object)((Component)identity).gameObject == (Object)null)
			{
				return false;
			}
			Item_Object component = ((Component)identity).GetComponent<Item_Object>();
			if ((Object)(object)component == (Object)null || component.itemData == null)
			{
				return false;
			}
			bool inBag = component.itemData.inBag;
			bool flag = _inHand(component.itemData);
			return inBag || flag;
		}

		public static bool IsBlacklisted(Item item)
		{
			return item != null && (_blacklistedPrefabNames.Contains(MPUtil.CleanCloneName(item.prefabName)) || _blacklistedItemTags.Intersect(item.itemTags).Any());
		}

		public static bool IsBlacklisted(Item_Object itemObj)
		{
			return (Object)(object)itemObj != (Object)null && IsBlacklisted(itemObj.itemData);
		}
	}
}
namespace WKMPMod.World
{
	public enum PitonSyncAction : byte
	{
		Create,
		Update,
		Remove
	}
	public static class ClimbableItemSyncManager
	{
		private const float PeriodicUpdateInterval = 0.15f;

		private const float PositionEpsilonSqr = 0.0004f;

		private const float RotationEpsilon = 0.5f;

		private const float SecureAmountEpsilon = 0.01f;

		private static List<GameObject> CapturedPitons = new List<GameObject>();

		private static readonly FieldRef<Projectile, GameEntity> _projectileSourceEntityField = AccessTools.FieldRefAccess<Projectile, GameEntity>("sourceEntity");

		private static readonly Dictionary<string, NetworkedClimableItem> _pitons = new Dictionary<string, NetworkedClimableItem>();

		private static ulong _nextLocalId = 1uL;

		public static bool ApplyingRemoteState { get; private set; }

		public static void SaveCapturedPiton(GameObject go)
		{
			if ((Object)(object)go != (Object)null && (Object)(object)go.GetComponentInChildren<CL_Handhold>(true) != (Object)null)
			{
				CapturedPitons.Add(go);
			}
		}

		public static void RegisterNewLocalPiton(HandItem_Piton source)
		{
			if (!MPCore.CanSync || ApplyingRemoteState || (Object)(object)source == (Object)null || CapturedPitons.Count == 0)
			{
				CapturedPitons.Clear();
				return;
			}
			foreach (GameObject capturedPiton in CapturedPitons)
			{
				GameObject climbableRoot = GetClimbableRoot(capturedPiton);
				if (!((Object)(object)climbableRoot == (Object)null))
				{
					RegisterLocalClimbable(climbableRoot, ((Object)source.pitonWorldObject).name);
				}
			}
			CapturedPitons.Clear();
		}

		public static void RegisterNewLocalProjectileClimbable(Projectile source, RaycastHit hit)
		{
			if (!MPCore.CanSync || ApplyingRemoteState || (Object)(object)source == (Object)null || !IsLocalProjectile(source))
			{
				CapturedPitons.Clear();
				return;
			}
			foreach (GameObject capturedPiton in CapturedPitons)
			{
				GameObject climbableRoot = GetClimbableRoot(capturedPiton);
				if (!((Object)(object)climbableRoot == (Object)null))
				{
					RegisterLocalClimbable(climbableRoot, ((Object)(object)climbableRoot != (Object)null) ? ((Object)climbableRoot).name : ((Object)((Component)source).gameObject).name);
				}
			}
			CapturedPitons.Clear();
		}

		public static void BroadcastHammerUpdate(CL_Handhold handhold)
		{
			if (MPCore.CanSync && !ApplyingRemoteState && !((Object)(object)handhold == (Object)null))
			{
				NetworkedClimableItem networkedClimableItem = FindIdentity(handhold);
				if (!((Object)(object)networkedClimableItem == (Object)null) && !string.IsNullOrEmpty(networkedClimableItem.NetworkId))
				{
					Broadcast(networkedClimableItem, PitonSyncAction.Update, force: true);
				}
			}
		}

		public static void BroadcastPeriodicUpdate(CL_Handhold handhold)
		{
			if (!MPCore.CanSync || ApplyingRemoteState || (Object)(object)handhold == (Object)null)
			{
				return;
			}
			NetworkedClimableItem networkedClimableItem = FindIdentity(handhold);
			if ((Object)(object)networkedClimableItem == (Object)null || string.IsNullOrEmpty(networkedClimableItem.NetworkId))
			{
				return;
			}
			if (!((Component)networkedClimableItem).gameObject.activeSelf)
			{
				Broadcast(networkedClimableItem, PitonSyncAction.Remove, force: true);
			}
			else if (!(Time.time - networkedClimableItem.LastSentTime < 0.15f))
			{
				CL_Handhold trackedHandhold = GetTrackedHandhold(((Component)networkedClimableItem).gameObject);
				if (HasMeaningfulStateChange(networkedClimableItem, trackedHandhold))
				{
					Broadcast(networkedClimableItem, PitonSyncAction.Update, force: false);
				}
			}
		}

		public static void HandlePitonState(ulong senderId, DataReader reader)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_0087: 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)
			PitonSyncAction pitonSyncAction = (PitonSyncAction)reader.GetByte();
			string text = reader.GetString();
			string prefabKey = reader.GetString();
			Vector3 vector = reader.GetVector3();
			Quaternion quaternion = reader.GetQuaternion();
			float secureAmount = reader.GetFloat();
			bool secure = reader.GetBool();
			bool active = reader.GetBool();
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			ApplyingRemoteState = true;
			try
			{
				switch (pitonSyncAction)
				{
				case PitonSyncAction.Create:
					ApplyCreate(senderId, text, prefabKey, vector, quaternion, secureAmount, secure, active);
					break;
				case PitonSyncAction.Update:
					ApplyUpdate(text, vector, quaternion, secureAmount, secure, active);
					break;
				case PitonSyncAction.Remove:
					ApplyRemove(text);
					break;
				}
			}
			catch (Exception ex)
			{
				MPMain.LogError($"[MP ClimbableSync] Failed to apply {pitonSyncAction} for {text}: {ex.Message}");
			}
			finally
			{
				ApplyingRemoteState = false;
			}
		}

		private static void RegisterLocalClimbable(GameObject root, string prefabKey)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			string text = MPUtil.CleanCloneName(prefabKey);
			if (!string.IsNullOrEmpty(text))
			{
				NetworkedClimableItem orCreateIdentity = GetOrCreateIdentity(root);
				if (string.IsNullOrEmpty(orCreateIdentity.NetworkId))
				{
					orCreateIdentity.NetworkId = $"{MPSteamworks.UserSteamId}:{_nextLocalId++}";
					orCreateIdentity.OwnerId = MPSteamworks.UserSteamId;
					orCreateIdentity.IsRemote = false;
				}
				orCreateIdentity.PrefabKey = text;
				_pitons[orCreateIdentity.NetworkId] = orCreateIdentity;
				Broadcast(orCreateIdentity, PitonSyncAction.Create, force: true);
			}
		}

		private static void ApplyCreate(ulong senderId, string networkId, string prefabKey, Vector3 position, Quaternion rotation, float secureAmount, bool secure, bool active)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			if (_pitons.TryGetValue(networkId, out NetworkedClimableItem value) && (Object)(object)value != (Object)null)
			{
				value.PrefabKey = MPUtil.CleanCloneName(prefabKey);
				ApplyState(value, position, rotation, secureAmount, secure, active);
				return;
			}
			GameObject handholdPrefab = MPAssetManager.GetHandholdPrefab(prefabKey);
			if ((Object)(object)handholdPrefab == (Object)null)
			{
				MPMain.LogError("[MP ClimbableSync] Could not resolve prefab '" + prefabKey + "' for " + networkId + ".");
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(handholdPrefab, position, rotation);
			Transform currentLevelParentRoot = WorldLoader.GetCurrentLevelParentRoot();
			if ((Object)(object)currentLevelParentRoot != (Object)null)
			{
				val.transform.SetParent(currentLevelParentRoot);
			}
			TryAddPlacedObjectToLevel(val);
			NetworkedClimableItem orCreateIdentity = GetOrCreateIdentity(val);
			orCreateIdentity.NetworkId = networkId;
			orCreateIdentity.PrefabKey = MPUtil.CleanCloneName(prefabKey);
			orCreateIdentity.OwnerId = senderId;
			orCreateIdentity.IsRemote = true;
			_pitons[networkId] = orCreateIdentity;
			ApplyState(orCreateIdentity, position, rotation, secureAmount, secure, active);
		}

		private static void ApplyUpdate(string networkId, Vector3 position, Quaternion rotation, float secureAmount, bool secure, bool active)
		{
			//IL_0021: 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 (_pitons.TryGetValue(networkId, out NetworkedClimableItem value) && !((Object)(object)value == (Object)null))
			{
				ApplyState(value, position, rotation, secureAmount, secure, active);
			}
		}

		private static void ApplyRemove(string networkId)
		{
			if (_pitons.TryGetValue(networkId, out NetworkedClimableItem value) && !((Object)(object)value == (Object)null))
			{
				if ((Object)(object)((Component)value).gameObject != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)value).gameObject);
				}
				_pitons.Remove(networkId);
			}
		}

		private static void ApplyState(NetworkedClimableItem identity, Vector3 position, Quaternion rotation, float secureAmount, bool secure, bool active)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)identity).transform;
			transform.position = position;
			transform.rotation = rotation;
			CL_Handhold trackedHandhold = GetTrackedHandhold(((Component)identity).gameObject);
			if ((Object)(object)trackedHandhold != (Object)null)
			{
				trackedHandhold.Initialize();
				trackedHandhold.secureAmount = secureAmount;
				trackedHandhold.secure = secure;
			}
			((Component)identity).gameObject.SetActive(active);
			RecordState(identity, trackedHandhold);
		}

		private static GameObject GetClimbableRoot(GameObject obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return null;
			}
			Transform val = (WorldLoader.initialized ? WorldLoader.GetCurrentLevelParentRoot() : null);
			Transform val2 = obj.transform;
			while ((Object)(object)val2.parent != (Object)null && (Object)(object)val2.parent != (Object)(object)val)
			{
				val2 = val2.parent;
			}
			return ((Component)val2).gameObject;
		}

		private static CL_Handhold GetTrackedHandhold(GameObject root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			return root.GetComponent<CL_Handhold>() ?? root.GetComponentInChildren<CL_Handhold>(true);
		}

		private static NetworkedClimableItem FindIdentity(CL_Handhold handhold)
		{
			return ((Component)handhold).GetComponent<NetworkedClimableItem>() ?? ((Component)handhold).GetComponentInParent<NetworkedClimableItem>();
		}

		private static bool IsLocalProjectile(Projectile projectile)
		{
			ENT_Player player = ENT_Player.GetPlayer();
			if ((Object)(object)projectile == (Object)null || (Object)(object)player == (Object)null || _projectileSourceEntityField == null)
			{
				return false;
			}
			GameEntity val = _projectileSourceEntityField.Invoke(projectile);
			return (Object)(object)val == (Object)(object)player;
		}

		private static void TryAddPlacedObjectToLevel(GameObject climbableObject)
		{
			if (!WorldLoader.initialized || (Object)(object)climbableObject == (Object)null)
			{
				return;
			}
			try
			{
				M_Level level = WorldLoader.instance.GetCurrentLevel().GetLevel();
				typeof(M_Level).GetMethod("AddPlacedObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(level, new object[1] { climbableObject });
			}
			catch (Exception ex)
			{
				MPMain.LogWarning("[MP ClimbableSync] Could not register remote climbable as placed object: " + ex.Message);
			}
		}

		private static NetworkedClimableItem GetOrCreateIdentity(GameObject obj)
		{
			NetworkedClimableItem networkedClimableItem = obj.GetComponent<NetworkedClimableItem>();
			if ((Object)(object)networkedClimableItem == (Object)null)
			{
				networkedClimableItem = obj.AddComponent<NetworkedClimableItem>();
			}
			return networkedClimableItem;
		}

		private static void Broadcast(NetworkedClimableItem identity, PitonSyncAction action, bool force)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)identity == (Object)null || string.IsNullOrEmpty(identity.NetworkId))
			{
				return;
			}
			CL_Handhold trackedHandhold = GetTrackedHandhold(((Component)identity).gameObject);
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, 0uL, PacketType.PitonStateSync);
			writer.Put((byte)action);
			writer.Put(identity.NetworkId);
			writer.Put(identity.PrefabKey ?? string.Empty);
			writer.Put(((Component)identity).transform.position);
			writer.Put(((Component)identity).transform.rotation);
			writer.Put(((Object)(object)trackedHandhold != (Object)null) ? trackedHandhold.secureAmount : 0f);
			writer.Put((Object)(object)trackedHandhold != (Object)null && trackedHandhold.secure);
			writer.Put(((Component)identity).gameObject.activeSelf);
			if (action == PitonSyncAction.Create || action == PitonSyncAction.Remove)
			{
				MonoSingleton<MPSteamworks>.Instance.Broadcast(writer, (SendType)8, 0);
			}
			else if (action == PitonSyncAction.Update)
			{
				foreach (ulong item in MonoSingleton<LocalPlayer>.Instance._nearPlayersBuffer)
				{
					MonoSingleton<MPSteamworks>.Instance.SendToPeer(SteamId.op_Implicit(item), writer, (SendType)0, 0);
				}
			}
			RecordState(identity, trackedHandhold);
			if (force)
			{
				MPMain.LogInfo($"[MP ClimbableSync] Sent {action} for {identity.NetworkId} ({identity.PrefabKey})");
			}
		}

		private static bool HasMeaningfulStateChange(NetworkedClimableItem identity, CL_Handhold handhold)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (identity.LastActive != ((Component)identity).gameObject.activeSelf)
			{
				return true;
			}
			Vector3 val = identity.LastPosition - ((Component)identity).transform.position;
			if (((Vector3)(ref val)).sqrMagnitude > 0.0004f)
			{
				return true;
			}
			if (Quaternion.Angle(identity.LastRotation, ((Component)identity).transform.rotation) > 0.5f)
			{
				return true;
			}
			if ((Object)(object)handhold == (Object)null)
			{
				return false;
			}
			if (Mathf.Abs(identity.LastSecureAmount - handhold.secureAmount) > 0.01f)
			{
				return true;
			}
			return identity.LastSecure != handhold.secure;
		}

		private static void RecordState(NetworkedClimableItem identity, CL_Handhold handhold)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			identity.LastSentTime = Time.time;
			identity.LastPosition = ((Component)identity).transform.position;
			identity.LastRotation = ((Component)identity).transform.rotation;
			identity.LastActive = ((Component)identity).gameObject.activeSelf;
			if ((Object)(object)handhold != (Object)null)
			{
				identity.LastSecureAmount = handhold.secureAmount;
				identity.LastSecure = handhold.secure;
			}
		}
	}
	public enum ItemSyncAction : byte
	{
		SnapshotReset,
		SnapshotFinalize,
		Create,
		PickupRequest,
		DropRequest,
		Remove
	}
	public static class ItemSyncManager
	{
		private sealed class PendingLocalDrop
		{
			public Item_Object ItemObject { get; }

			public string PrefabKey { get; }

			public float CreatedAt { get; }

			public PendingLocalDrop(Item_Object itemObject, string prefabKey, float createdAt)
			{
				ItemObject = itemObject;
				PrefabKey = prefabKey;
				CreatedAt = createdAt;
			}
		}

		private const float CandidateMatchDistanceSqr = 0.5f;

		private const float LocalDropMatchDistanceSqr = 25f;

		private const float LocalDropMaxAge = 3f;

		private const float LocalDropPickupSuppressWindow = 0.2f;

		private const float VelocityEpsilonSqr = 0.0025f;

		private const float WorldReadyTimeout = 12f;

		private const float StableIdPositionPrecision = 20f;

		private const float StableIdRotationPrecision = 5f;

		private const int SnapshotItemsPerFrame = 10;

		private static readonly FieldRef<Item, Item_Object> _dropObjectField = AccessTools.FieldRefAccess<Item, Item_Object>("dropObject");

		private static readonly Dictionary<string, NetworkedItem> _items = new Dictionary<string, NetworkedItem>();

		private static readonly List<Item_Object> _clientCandidates = new List<Item_Object>();

		private static readonly List<PendingLocalDrop> _pendingLocalDrops = new List<PendingLocalDrop>();

		private static readonly List<Item_Object> _snapshotCandidates = new List<Item_Object>();

		private static readonly Dictionary<ulong, Coroutine> _snapshotRoutines = new Dictionary<ulong, Coroutine>();

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

		private static ulong _nextHostItemId = 1uL;

		private static Coroutine _prepareRoutine;

		private static Coroutine _hostDiscoveryRoutine;

		private static bool _hostSceneItemsRegistered;

		private static readonly HashSet<string> _blacklistedPrefabNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Item_Flashlight", "Item_Flaregun", "Item_Cryogun", "Item_Handgun", "Item_Handgun_Debug", "Item_10mm_Ammo" };

		private static readonly HashSet<string> _blacklistedItemTags = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "artifact", "disk" };

		public static bool ApplyingRemoteState { get; private set; }

		public static void NotifyWorldInitialized()
		{
			ResetState();
			if ((Object)(object)MonoSingleton<MPCore>.Instance == (Object)null)
			{
				MPMain.LogWarning("[MP ItemSync] Prepare skipped: MPCore.Instance is null.");
			}
			else
			{
				_prepareRoutine = ((MonoBehaviour)MonoSingleton<MPCore>.Instance).StartCoroutine(PrepareWorldRoutine());
			}
		}

		public static void ResetState()
		{
			if (_prepareRoutine != null && (Object)(object)MonoSingleton<MPCore>.Instance != (Object)null)
			{
				((MonoBehaviour)MonoSingleton<MPCore>.Instance).StopCoroutine(_prepareRoutine);
				_prepareRoutine = null;
			}
			if (_hostDiscoveryRoutine != null && (Object)(object)MonoSingleton<MPCore>.Instance != (Object)null)
			{
				((MonoBehaviour)MonoSingleton<MPCore>.Instance).StopCoroutine(_hostDiscoveryRoutine);
				_hostDiscoveryRoutine = null;
			}
			if ((Object)(object)MonoSingleton<MPCore>.Instance != (Object)null)
			{
				foreach (Coroutine value in _snapshotRoutines.Values)
				{
					if (value != null)
					{
						((MonoBehaviour)MonoSingleton<MPCore>.Instance).StopCoroutine(value);
					}
				}
			}
			_snapshotRoutines.Clear();
			foreach (NetworkedItem value2 in _items.Values)
			{
				if (!((Object)(object)value2 == (Object)null) && !((Object)(object)((Component)value2).gameObject == (Object)null) && value2.WasInstantiatedBySync)
				{
					Object.Destroy((Object)(object)((Component)value2).gameObject);
				}
			}
			_items.Clear();
			_clientCandidates.Clear();
			_pendingLocalDrops.Clear();
			_snapshotCandidates.Clear();
			_suppressedPickupObjects.Clear();
			_hostSceneItemsRegistered = false;
			ApplyingRemoteState = false;
			MPMain.LogInfo("[MP ItemSync] ResetState completed.");
		}

		public static void SendSnapshotToClient(ulong clientId)
		{
			if (MPCore.CanSync && MonoSingleton<MPSteamworks>.Instance.IsHost && !((Object)(object)MonoSingleton<MPCore>.Instance == (Object)null) && clientId != 0L && clientId != MPSteamworks.UserSteamId)
			{
				if (_snapshotRoutines.TryGetValue(clientId, out Coroutine value) && value != null)
				{
					((MonoBehaviour)MonoSingleton<MPCore>.Instance).StopCoroutine(value);
				}
				_snapshotRoutines[clientId] = ((MonoBehaviour)MonoSingleton<MPCore>.Instance).StartCoroutine(SendSnapshotToClientRoutine(clientId));
			}
		}

		public static void NotifyLocalPickup(Item_Object itemObject)
		{
			if (ApplyingRemoteState || (Object)(object)itemObject == (Object)null || !MPCore.CanSync)
			{
				return;
			}
			if (IsPendingLocalDrop(itemObject))
			{
				MPMain.LogInfo("[MP ItemSync] Suppressed pickup for pending local drop. Item=" + ((Object)itemObject).name);
			}
			else
			{
				if (ShouldSuppressLocalPickup(itemObject))
				{
					return;
				}
				NetworkedItem component = ((Component)itemObject).GetComponent<NetworkedItem>();
				if ((Object)(object)component == (Object)null || string.IsNullOrEmpty(component.NetworkId))
				{
					MPMain.LogWarning("[MP ItemSync] Pickup ignored: missing NetworkedItem or NetworkId. Item=" + ((Object)itemObject).name + ", PrefabKey=" + GetPrefabKey(itemObject) + ", " + $"HasIdentity={(Object)(object)component != (Object)null}");
					return;
				}
				MPMain.LogInfo("[MP ItemSync] Local pickup. " + $"Host={MonoSingleton<MPSteamworks>.Instance.IsHost}, " + "Item=" + ((Object)itemObject).name + ", NetworkId=" + component.NetworkId + ", PrefabKey=" + component.PrefabKey);
				if (MonoSingleton<MPSteamworks>.Instance.IsHost)
				{
					BroadcastRemove(component.NetworkId);
					Forget(component.NetworkId);
				}
				else
				{
					SendPickupRequest(component.NetworkId);
				}
			}
		}

		public static void NotifyLocalDrop(Item item)
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			if (ApplyingRemoteState || item == null || !MPCore.CanSync)
			{
				return;
			}
			Item_Object val = _dropObjectField.Invoke(item);
			if (!IsSyncableWorldItem(val))
			{
				return;
			}
			string prefabKey = GetPrefabKey(val);
			if (!string.IsNullOrEmpty(prefabKey))
			{
				if (MonoSingleton<MPSteamworks>.Instance.IsHost)
				{
					NetworkedItem networkedItem = RegisterHostItem(val, prefabKey);
					Vector3 velocity = GetVelocity(val);
					RememberSuppressedPickup(val);
					MPMain.LogInfo("[MP ItemSync] Host local drop. Item=" + ((Object)val).name + ", NetworkId=" + networkedItem.NetworkId + ", PrefabKey=" + prefabKey);
					BroadcastCreate(networkedItem, val, velocity, isDropSpawn: true);
				}
				else
				{
					RememberCandidate(val, snapshotCandidate: false);
					RememberPendingLocalDrop(val, prefabKey);
					RememberSuppressedPickup(val);
					MPMain.LogInfo("[MP ItemSync] Client local drop request. Item=" + ((Object)val).name + ", PrefabKey=" + prefabKey);
					SendDropRequest(prefabKey, ((Component)val).transform.position, ((Component)val).transform.rotation, GetVelocity(val));
				}
			}
		}

		public static void SpawnSyncedWorldDrop(string prefabKey, Vector3 position, Quaternion rotation, Vector3 velocity)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if (ApplyingRemoteState || !MPCore.CanSync || string.IsNullOrWhiteSpace(prefabKey))
			{
				return;
			}
			if (!MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				SendDropRequest(prefabKey, position, rotation, velocity);
				return;
			}
			Item_Object val = InstantiateWorldItem(prefabKey, position, rotation);
			if ((Object)(object)val == (Object)null)
			{
				MPMain.LogWarning("[MP ItemSync] Could not instantiate synced drop '" + prefabKey + "'.");
				return;
			}
			NetworkedItem identity = RegisterHostItem(val, prefabKey);
			RememberSuppressedPickup(val);
			ApplyCreate(identity, position, rotation, velocity, isDropSpawn: true, skipDropCallbacks: false);
			BroadcastCreate(identity, val, velocity, isDropSpawn: true);
		}

		public static void HandleItemState(ulong senderId, DataReader reader)
		{
			ItemSyncAction itemSyncAction = (ItemSyncAction)reader.GetByte();
			try
			{
				switch (itemSyncAction)
				{
				case ItemSyncAction.SnapshotReset:
					HandleSnapshotReset();
					break;
				case ItemSyncAction.SnapshotFinalize:
					HandleSnapshotFinalize();
					break;
				case ItemSyncAction.Create:
					HandleCreate(senderId, reader);
					break;
				case ItemSyncAction.PickupRequest:
					HandlePickupRequest(reader);
					break;
				case ItemSyncAction.DropRequest:
					HandleDropRequest(senderId, reader);
					break;
				case ItemSyncAction.Remove:
					HandleRemove(reader);
					break;
				}
			}
			catch (Exception ex)
			{
				MPMain.LogError($"[MP ItemSync] Failed to apply {itemSyncAction}: {ex.Message}");
			}
		}

		private static IEnumerator PrepareWorldRoutine()
		{
			MPMain.LogInfo("[MP ItemSync] PrepareWorldRoutine started. " + $"IsHost={MonoSingleton<MPSteamworks>.Instance.IsHost}, IsInLobby={MPCore.IsInLobby}, CanSync={MPCore.CanSync}, " + $"WorldInitialized={WorldLoader.initialized}, WorldLoaded={WorldLoader.isLoaded}");
			yield return WaitForWorldReady();
			yield return null;
			yield return null;
			if (MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				yield return RegisterHostSceneItemsRoutine();
				if ((Object)(object)MonoSingleton<MPCore>.Instance != (Object)null && _hostDiscoveryRoutine == null)
				{
					_hostDiscoveryRoutine = ((MonoBehaviour)MonoSingleton<MPCore>.Instance).StartCoroutine(HostDiscoveryRoutine());
				}
			}
			else if (MPCore.IsInLobby)
			{
				CaptureSceneCandidates(snapshotCandidate: true);
				MPMain.LogInfo("[MP ItemSync] Captured client scene candidates. " + $"Candidates={_clientCandidates.Count}, SnapshotCandidates={_snapshotCandidates.Count}");
			}
			else
			{
				MPMain.LogInfo("[MP ItemSync] Prepare skipped candidate capture because client is not in lobby.");
			}
			_prepareRoutine = null;
			MPMain.LogInfo("[MP ItemSync] PrepareWorldRoutine finished. " + $"Items={_items.Count}, HostSceneItemsRegistered={_hostSceneItemsRegistered}");
		}

		private static IEnumerator SendSnapshotToClientRoutine(ulong clientId)
		{
			yield return WaitForWorldReady();
			if (!_hostSceneItemsRegistered)
			{
				yield return RegisterHostSceneItemsRoutine();
			}
			SendSnapshotReset(clientId);
			List<NetworkedItem> snapshot = new List<NetworkedItem>(EnumerateKnownHostWorldItems());
			int sentThisFrame = 0;
			foreach (NetworkedItem identity in snapshot)
			{
				if ((Object)(object)identity == (Object)null || (Object)(object)((Component)identity).gameObject == (Object)null)
				{
					continue;
				}
				Item_Object itemObject = ((Component)identity).GetComponent<Item_Object>();
				if (IsSyncableWorldItem(itemObject))
				{
					SendCreate(clientId, identity, itemObject, GetVelocity(itemObject), isDropSpawn: false);
					sentThisFrame++;
					if (sentThisFrame >= 10)
					{
						sentThisFrame = 0;
						yield return null;
					}
				}
			}
			SendSnapshotFinalize(clientId);
			_snapshotRoutines.Remove(clientId);
			MPMain.LogInfo($"[MP ItemSync] Sent item snapshot to {clientId}. Items={snapshot.Count}");
		}

		private static IEnumerator WaitForWorldReady()
		{
			float elapsed = 0f;
			while ((!WorldLoader.initialized || !WorldLoader.isLoaded) && elapsed < 12f)
			{
				elapsed += Time.unscaledDeltaTime;
				yield return null;
			}
			MPMain.LogInfo("[MP ItemSync] World ready wait finished. " + $"Elapsed={elapsed:F2}, Initialized={WorldLoader.initialized}, Loaded={WorldLoader.isLoaded}");
		}

		private static IEnumerator RegisterHostSceneItemsRoutine()
		{
			if (!MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				yield break;
			}
			int registeredThisFrame = 0;
			int totalRegistered = 0;
			foreach (Item_Object itemObject in EnumerateSceneItems())
			{
				string prefabKey = GetPrefabKey(itemObject);
				if (!string.IsNullOrEmpty(prefabKey))
				{
					RegisterHostItem(itemObject, prefabKey, preferStableSceneIdentity: true);
					totalRegistered++;
					registeredThisFrame++;
					if (registeredThisFrame >= 10)
					{
						registeredThisFrame = 0;
						yield return null;
					}
				}
			}
			_hostSceneItemsRegistered = true;
			MPMain.LogInfo($"[MP ItemSync] Registered host scene items. Items={totalRegistered}");
		}

		private static IEnumerator HostDiscoveryRoutine()
		{
			WaitForSecondsRealtime wait = new WaitForSecondsRealtime(0.5f);
			while ((Object)(object)MonoSingleton<MPCore>.Instance != (Object)null)
			{
				if (MPCore.CanSync && MonoSingleton<MPSteamworks>.Instance.IsHost && _hostSceneItemsRegistered)
				{
					DiscoverAndBroadcastNewHostWorldItems();
				}
				yield return wait;
			}
			_hostDiscoveryRoutine = null;
		}

		private static void DiscoverAndBroadcastNewHostWorldItems()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Item_Object item in EnumerateSceneItems())
			{
				if (TryPrepareNewHostWorldItem(item, out string prefabKey))
				{
					NetworkedItem networkedItem = RegisterHostItem(item, prefabKey, preferStableSceneIdentity: true);
					RememberSuppressedPickup(item);
					MPMain.LogInfo("[MP ItemSync] Registered dynamic host world item. Item=" + ((Object)item).name + ", NetworkId=" + networkedItem.NetworkId + ", PrefabKey=" + prefabKey);
					BroadcastCreate(networkedItem, item, GetVelocity(item), isDropSpawn: false);
				}
			}
		}

		private static bool TryPrepareNewHostWorldItem(Item_Object itemObject, out string prefabKey)
		{
			prefabKey = string.Empty;
			if (!IsSyncableWorldItem(itemObject))
			{
				return false;
			}
			prefabKey = GetPrefabKey(itemObject);
			if (string.IsNullOrEmpty(prefabKey))
			{
				return false;
			}
			NetworkedItem component = ((Component)itemObject).GetComponent<NetworkedItem>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			if (string.IsNullOrEmpty(component.NetworkId))
			{
				return true;
			}
			return !_items.ContainsKey(component.NetworkId);
		}

		private static IEnumerable<NetworkedItem> EnumerateKnownHostWorldItems()
		{
			foreach (NetworkedItem identity in _items.Values)
			{
				if (!((Object)(object)identity == (Object)null) && !((Object)(object)((Component)identity).gameObject == (Object)null))
				{
					Item_Object itemObject = ((Component)identity).GetComponent<Item_Object>();
					if (IsSyncableWorldItem(itemObject))
					{
						yield return identity;
					}
				}
			}
		}

		private static NetworkedItem RegisterHostItem(Item_Object itemObject, string prefabKey, bool preferStableSceneIdentity = false)
		{
			NetworkedItem orCreateIdentity = GetOrCreateIdentity(((Component)itemObject).gameObject);
			if (preferStableSceneIdentity)
			{
				TryAssignStableSceneIdentity(itemObject, orCreateIdentity);
			}
			if (string.IsNullOrEmpty(orCreateIdentity.NetworkId))
			{
				orCreateIdentity.NetworkId = $"{MPSteamworks.UserSteamId}:item:{_nextHostItemId++}";
			}
			orCreateIdentity.PrefabKey = prefabKey;
			orCreateIdentity.OwnerId = MPSteamworks.UserSteamId;
			orCreateIdentity.IsRemote = false;
			orCreateIdentity.WasInstantiatedBySync = false;
			if (_items.TryGetValue(orCreateIdentity.NetworkId, out NetworkedItem value) && (Object)(object)value != (Object)null && (Object)(object)value != (Object)(object)orCreateIdentity)
			{
				MPMain.LogWarning("[MP ItemSync] Duplicate NetworkId detected. NetworkId=" + orCreateIdentity.NetworkId + ", Existing=" + ((Object)value).name + ", New=" + ((Object)itemObject).name);
			}
			_items[orCreateIdentity.NetworkId] = orCreateIdentity;
			return orCreateIdentity;
		}

		private static void HandleSnapshotReset()
		{
			if (!MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				MPMain.LogInfo("[MP ItemSync] Received snapshot reset.");
				ResetState();
				CaptureSceneCandidates(snapshotCandidate: true);
			}
		}

		private static void HandleSnapshotFinalize()
		{
			if (MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				return;
			}
			int num = 0;
			for (int num2 = _snapshotCandidates.Count - 1; num2 >= 0; num2--)
			{
				Item_Object val = _snapshotCandidates[num2];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null))
				{
					NetworkedItem component = ((Component)val).GetComponent<NetworkedItem>();
					if (!((Object)(object)component != (Object)null) || string.IsNullOrEmpty(component.NetworkId) || !_items.ContainsKey(component.NetworkId))
					{
						((Component)val).gameObject.SetActive(false);
						num++;
					}
				}
			}
			_snapshotCandidates.Clear();
			MPMain.LogInfo($"[MP ItemSync] Snapshot finalized. Hidden unmatched scene items={num}.");
		}

		private static void HandleCreate(ulong senderId, DataReader reader)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: 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_0256: Unknown result type (might be due to invalid IL or missing references)
			if (MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				return;
			}
			string text = reader.GetString();
			string text2 = reader.GetString();
			Vector3 vector = reader.GetVector3();
			Quaternion quaternion = reader.GetQuaternion();
			Vector3 vector2 = reader.GetVector3();
			bool flag = reader.GetBool();
			if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2))
			{
				return;
			}
			if (_items.TryGetValue(text, out NetworkedItem value) && (Object)(object)value != (Object)null)
			{
				ApplyCreate(value, vector, quaternion, vector2, flag, skipDropCallbacks: true);
				return;
			}
			Item_Object val = (flag ? FindPendingLocalDrop(text2, vector) : null);
			bool wasSnapshotCandidate = false;
			if ((Object)(object)val == (Object)null)
			{
				val = FindSceneItemByStableId(text);
				if ((Object)(object)val != (Object)null)
				{
					wasSnapshotCandidate = _snapshotCandidates.Contains(val);
					RemoveCandidate(val);
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				val = FindClientCandidate(text2, vector, out wasSnapshotCandidate);
			}
			Item_Object val2 = val;
			bool wasInstantiatedBySync = false;
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = InstantiateWorldItem(text2, vector, quaternion);
				wasInstantiatedBySync = (Object)(object)val2 != (Object)null;
			}
			if ((Object)(object)val2 == (Object)null)
			{
				MPMain.LogWarning("[MP ItemSync] Could not create item '" + text2 + "' for " + text + ".");
				return;
			}
			NetworkedItem orCreateIdentity = GetOrCreateIdentity(((Component)val2).gameObject);
			if (text.StartsWith("sceneitem:", StringComparison.Ordinal))
			{
				orCreateIdentity.StableSceneId = text;
			}
			orCreateIdentity.NetworkId = text;
			orCreateIdentity.PrefabKey = text2;
			orCreateIdentity.OwnerId = senderId;
			orCreateIdentity.IsRemote = true;
			orCreateIdentity.WasInstantiatedBySync = wasInstantiatedBySync;
			if (_items.TryGetValue(text, out NetworkedItem value2) && (Object)(object)value2 != (Object)null && (Object)(object)value2 != (Object)(object)orCreateIdentity)
			{
				MPMain.LogWarning("[MP ItemSync] Duplicate client NetworkId detected on create. NetworkId=" + text + ", Existing=" + ((Object)value2).name + ", New=" + ((Object)val2).name);
			}
			_items[text] = orCreateIdentity;
			bool skipDropCallbacks = !wasSnapshotCandidate && (Object)(object)val != (Object)null && flag;
			ApplyCreate(orCreateIdentity, vector, quaternion, vector2, flag, skipDropCallbacks);
		}

		private static void HandlePickupRequest(DataReader reader)
		{
			if (!MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				return;
			}
			string text = reader.GetString();
			MPMain.LogInfo("[MP ItemSync] Host received pickup request. NetworkId=" + text);
			if (!string.IsNullOrEmpty(text))
			{
				if (!_items.ContainsKey(text))
				{
					MPMain.LogWarning("[MP ItemSync] Pickup request ignored. Unknown NetworkId=" + text);
					return;
				}
				BroadcastRemove(text);
				Forget(text);
			}
		}

		private static void HandleDropRequest(ulong senderId, DataReader reader)
		{
			//IL_0021: 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_0028: 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)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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)
			if (!MonoSingleton<MPSteamworks>.Instance.IsHost)
			{
				return;
			}
			string text = reader.GetString();
			Vector3 vector = reader.GetVector3();
			Quaternion quaternion = reader.GetQuaternion();
			Vector3 vector2 = reader.GetVector3();
			if (!string.IsNullOrEmpty(text))
			{
				Item_Object val = InstantiateWorldItem(text, vector, quaternion);
				if ((Object)(object)val == (Object)null)
				{
					MPMain.LogWarning("[MP ItemSync] Could not instantiate dropped item '" + text + "'.");
					return;
				}
				NetworkedItem networkedItem = RegisterHostItem(val, text);
				networkedItem.OwnerId = senderId;
				MPMain.LogInfo("[MP ItemSync] Host accepted drop request. " + $"Sender={senderId}, Item={((Object)val).name}, NetworkId={networkedItem.NetworkId}, PrefabKey={text}");
				ApplyCreate(networkedItem, vector, quaternion, vector2, isDropSpawn: true, skipDropCallbacks: false);
				BroadcastCreate(networkedItem, val, vector2, isDropSpawn: true);
			}
		}

		private static void HandleRemove(DataReader reader)
		{
			string text = reader.GetString();
			MPMain.LogInfo("[MP ItemSync] Received remove. NetworkId=" + text);
			if (!string.IsNullOrEmpty(text))
			{
				Forget(text);
			}
		}

		private static void ApplyCreate(NetworkedItem identity, Vector3 position, Quaternion rotation, Vector3 velocity, bool isDropSpawn, bool skipDropCallbacks)
		{
			//IL_0030: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)identity == (Object)null || (Object)(object)((Component)identity).gameObject == (Object)null)
			{
				return;
			}
			ApplyingRemoteState = true;
			try
			{
				((Component)identity).transform.position = position;
				((Component)identity).transform.rotation = rotation;
				Item_Object component = ((Component)identity).GetComponent<Item_Object>();
				if ((Object)(object)component != (Object)null && component.itemData != null)
				{
					_dropObjectField.Invoke(component.itemData) = component;
				}
				if (isDropSpawn && (Object)(object)component != (Object)null && !skipDropCallbacks)
				{
					component.OnDrop();
				}
				Rigidbody rigidbody = GetRigidbody(((Component)identity).gameObject);
				if ((Object)(object)rigidbody != (Object)null)
				{
					rigidbody.isKinematic = false;
					rigidbody.velocity = velocity;
				}
				((Component)identity).gameObject.SetActive(true);
			}
			finally
			{
				ApplyingRemoteState = false;
			}
		}

		private static void Forget(string networkId)
		{
			if (!_items.TryGetValue(networkId, out NetworkedItem value) || (Object)(object)value == (Object)null)
			{
				if (!TryForgetUnknownSceneItem(networkId))
				{
					MPMain.LogWarning("[MP ItemSync] Forget ignored. Unknown NetworkId=" + networkId);
				}
				return;
			}
			Item_Object component = ((Component)value).GetComponent<Item_Object>();
			if ((Object)(object)component != (Object)null)
			{
				RemoveCandidate(component);
			}
			MPMain.LogInfo("[MP ItemSync] Forget item. NetworkId=" + networkId + ", Item=" + (((Object)(object)((Component)value).gameObject != (Object)null) ? ((Object)((Component)value).gameObject).name : "null") + ", " + $"WasInstantiatedBySync={value.WasInstantiatedBySync}");
			if ((Object)(object)((Component)value).gameObject != (Object)null)
			{
				((Component)value).gameObject.SetActive(false);
				if (value.WasInstantiatedBySync)
				{
					Object.Destroy((Object)(object)((Component)value).gameObject);
				}
			}
			_items.Remove(networkId);
		}

		private static bool TryForgetUnknownSceneItem(string networkId)
		{
			if (string.IsNullOrEmpty(networkId))
			{
				return false;
			}
			if (!networkId.StartsWith("sceneitem:", StringComparison.Ordinal))
			{
				return false;
			}
			Item_Object val = FindSceneItemByStableId(networkId);
			if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null)
			{
				return false;
			}
			NetworkedItem component = ((Component)val).GetComponent<NetworkedItem>();
			if ((Object)(object)component != (Object)null && string.IsNullOrEmpty(component.NetworkId))
			{
				component.NetworkId = networkId;
				component.StableSceneId = networkId;
			}
			RemoveCandidate(val);
			((Component)val).gameObject.SetActive(false);
			_items.Remove(networkId);
			MPMain.LogWarning("[MP ItemSync] Forgot unknown scene item by stable ID fallback. NetworkId=" + networkId + ", Item=" + ((Object)val).name);
			return true;
		}

		private static void SendSnapshotReset(ulong clientId)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, clientId, PacketType.ItemStateSync);
			writer.Put((byte)0);
			MonoSingleton<MPSteamworks>.Instance.SendToPeer(SteamId.op_Implicit(clientId), writer, (SendType)8, 0);
		}

		private static void SendSnapshotFinalize(ulong clientId)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, clientId, PacketType.ItemStateSync);
			writer.Put((byte)1);
			MonoSingleton<MPSteamworks>.Instance.SendToPeer(SteamId.op_Implicit(clientId), writer, (SendType)8, 0);
		}

		private static void SendCreate(ulong clientId, NetworkedItem identity, Item_Object itemObject, Vector3 velocity, bool isDropSpawn)
		{
			//IL_005e: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)identity == (Object)null) && !((Object)(object)itemObject == (Object)null) && !string.IsNullOrEmpty(identity.NetworkId))
			{
				DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, clientId, PacketType.ItemStateSync);
				writer.Put((byte)2);
				writer.Put(identity.NetworkId);
				writer.Put(identity.PrefabKey);
				writer.Put(((Component)itemObject).transform.position);
				writer.Put(((Component)itemObject).transform.rotation);
				writer.Put(velocity);
				writer.Put(isDropSpawn);
				MonoSingleton<MPSteamworks>.Instance.SendToPeer(SteamId.op_Implicit(clientId), writer, (SendType)8, 0);
			}
		}

		private static void BroadcastCreate(NetworkedItem identity, Item_Object itemObject, Vector3 velocity, bool isDropSpawn)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)identity == (Object)null) && !((Object)(object)itemObject == (Object)null) && !string.IsNullOrEmpty(identity.NetworkId))
			{
				DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, 0uL, PacketType.ItemStateSync);
				writer.Put((byte)2);
				writer.Put(identity.NetworkId);
				writer.Put(identity.PrefabKey);
				writer.Put(((Component)itemObject).transform.position);
				writer.Put(((Component)itemObject).transform.rotation);
				writer.Put(velocity);
				writer.Put(isDropSpawn);
				MonoSingleton<MPSteamworks>.Instance.Broadcast(writer, (SendType)8, 0);
			}
		}

		private static void BroadcastRemove(string networkId)
		{
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, 0uL, PacketType.ItemStateSync);
			writer.Put((byte)5);
			writer.Put(networkId);
			MPMain.LogInfo("[MP ItemSync] Broadcast remove. NetworkId=" + networkId);
			MonoSingleton<MPSteamworks>.Instance.Broadcast(writer, (SendType)8, 0);
		}

		private static void SendPickupRequest(string networkId)
		{
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, MonoSingleton<MPSteamworks>.Instance.HostSteamId, PacketType.ItemStateSync);
			writer.Put((byte)3);
			writer.Put(networkId);
			MPMain.LogInfo("[MP ItemSync] Sent pickup request. NetworkId=" + networkId);
			MonoSingleton<MPSteamworks>.Instance.SendToHost(writer, (SendType)8, 0);
		}

		private static void SendDropRequest(string prefabKey, Vector3 position, Quaternion rotation, Vector3 velocity)
		{
			//IL_0029: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			DataWriter writer = MPWriterPool.GetWriter(MPSteamworks.UserSteamId, MonoSingleton<MPSteamworks>.Instance.HostSteamId, PacketType.ItemStateSync);
			writer.Put((byte)4);
			writer.Put(prefabKey);
			writer.Put(position);
			writer.Put(rotation);
			writer.Put(velocity);
			MonoSingleton<MPSteamworks>.Instance.SendToHost(writer, (SendType)8, 0);
		}

		private static void CaptureSceneCandidates(bool snapshotCandidate)
		{
			foreach (Item_Object item in EnumerateSceneItems())
			{
				RememberCandidate(item, snapshotCandidate);
			}
		}

		private static IEnumerable<Item_Object> EnumerateSceneItems()
		{
			Item_Object[] array = Object.FindObjectsOfType<Item_Object>();
			foreach (Item_Object itemObject in array)
			{
				if (IsSyncableWorldItem(itemObject) && !IsBlacklisted(itemObject))
				{
					yield return itemObject;
				}
			}
		}

		private static void RememberCandidate(Item_Object itemObject, bool snapshotCandidate)
		{
			if (!IsSyncableWorldItem(itemObject))
			{
				return;
			}
			NetworkedItem orCreateIdentity = GetOrCreateIdentity(((Component)itemObject).gameObject);
			if (snapshotCandidate && TryAssignStableSceneIdentity(itemObject, orCreateIdentity))
			{
				orCreateIdentity.PrefabKey = GetPrefabKey(itemObject);
				if (_items.TryGetValue(orCreateIdentity.NetworkId, out NetworkedItem value) && (Object)(object)value != (Object)null && (Object)(object)value != (Object)(object)orCreateIdentity)
				{
					MPMain.LogWarning("[MP ItemSync] Duplicate client candidate NetworkId detected. NetworkId=" + orCreateIdentity.NetworkId + ", Existing=" + ((Object)value).name + ", New=" + ((Object)itemObject).name);
				}
				_items[orCreateIdentity.NetworkId] = orCreateIdentity;
			}
			else if (!string.IsNullOrEmpty(orCreateIdentity.NetworkId))
			{
				if (_items.TryGetValue(orCreateIdentity.NetworkId, out NetworkedItem value2) && (Object)(object)value2 != (Object)null && (Object)(object)value2 != (Object)(object)orCreateIdentity)
				{
					MPMain.LogWarning("[MP ItemSync] Duplicate remembered NetworkId detected. NetworkId=" + orCreateIdentity.NetworkId + ", Existing=" + ((Object)value2).name + ", New=" + ((Object)itemObject).name);
				}
				_items[orCreateIdentity.NetworkId] = orCreateIdentity;
			}
			else
			{
				if (!_clientCandidates.Contains(itemObject))
				{
					_clientCandidates.Add(itemObject);
				}
				if (snapshotCandidate && !_snapshotCandidates.Contains(itemObject))
				{
					_snapshotCandidates.Add(itemObject);
				}
			}
		}

		private static void RemoveCandidate(Item_Object itemObject)
		{
			_clientCandidates.Remove(itemObject);
			_snapshotCandidates.Remove(itemObject);
			RemovePendingLocalDrop(itemObject);
		}

	

WKMultiPlayerMod.Shared.dll

Decompiled 3 weeks ago
using System;
using System.Buffers;
using System.Buffers.Binary;
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 Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using WKMPMod.Data;
using WKMPMod.Util;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WKMultiPlayerMod.Shared")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+5b29bc1ad5d0619e4009adabd3b2154c7256cbe6")]
[assembly: AssemblyProduct("WKMultiPlayerMod.Shared")]
[assembly: AssemblyTitle("WKMultiPlayerMod.Shared")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace WKMPMod.Util
{
	public static class DictionaryExtensions
	{
		public static List<ulong> FindByKeySuffix<T>(this Dictionary<ulong, T> dictionary, ulong suffix)
		{
			List<ulong> list = new List<ulong>();
			if (dictionary == null || dictionary.Count == 0)
			{
				return list;
			}
			ulong num = CalculateDivisor(suffix);
			foreach (KeyValuePair<ulong, T> item in dictionary)
			{
				if (item.Key % num == suffix)
				{
					list.Add(item.Key);
				}
			}
			return list;
		}

		private static ulong CalculateDivisor(ulong suffix)
		{
			if (suffix == 0)
			{
				return 10uL;
			}
			ulong num;
			for (num = 1uL; num <= suffix; num *= 10)
			{
			}
			return num;
		}

		public static Dictionary<K, byte> SetDifference<K>(Dictionary<K, byte> minuend, Dictionary<K, byte> subtrahend)
		{
			Dictionary<K, byte> dictionary = new Dictionary<K, byte>();
			foreach (var (key, b2) in minuend)
			{
				if (subtrahend.TryGetValue(key, out var value))
				{
					if (b2 > value)
					{
						dictionary[key] = (byte)(b2 - value);
					}
				}
				else
				{
					dictionary[key] = b2;
				}
			}
			return dictionary;
		}
	}
	public class TickTimer
	{
		private float _interval;

		private float _lastTickTime;

		public float Progress => Mathf.Clamp01((Time.time - _lastTickTime) / _interval);

		public float TimeRemaining => Mathf.Max(0f, _interval - (Time.time - _lastTickTime));

		public bool IsTickReached => Time.time - _lastTickTime >= _interval;

		public TickTimer(float tick)
		{
			_interval = tick;
			_lastTickTime = 0f - _interval;
		}

		public TickTimer(int hz)
		{
			_interval = 1f / (float)hz;
			_lastTickTime = 0f - _interval;
		}

		public void SetInterval(float tick)
		{
			_interval = tick;
		}

		public void SetFrequency(float hz)
		{
			_interval = 1f / hz;
		}

		public void Reset()
		{
			_lastTickTime = Time.time;
		}

		public bool TryTick()
		{
			if (Time.time - _lastTickTime >= _interval)
			{
				_lastTickTime = Time.time;
				return true;
			}
			return false;
		}

		public void ForceTick()
		{
			_lastTickTime = Time.time;
		}
	}
}
namespace WKMPMod.MK_Component
{
	public class MK_CL_Handhold : MonoBehaviour
	{
		public UnityEvent activeEvent = new UnityEvent();

		public UnityEvent stopEvent = new UnityEvent();

		public Renderer handholdRenderer;
	}
	public class MK_ObjectTagger : MonoBehaviour
	{
		public List<string> tags = new List<string>();
	}
	public class MK_RemoteEntity : MonoBehaviour
	{
		public ulong playerId;
	}
	public class MK_RemoteHand : MonoBehaviour
	{
		[Header("左右手")]
		public byte hand;

		[Header("距离设置")]
		[Tooltip("当当前位置与目标位置超过此距离时直接瞬移")]
		public float teleportThreshold = 50f;

		[Tooltip("平滑移动的最大距离限制")]
		public float fastSmoothDistance = 10f;

		[Header("拉拽参数")]
		public float basePullStrength = 0.2f;

		public void Teleport(Vector3 position)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.position = position;
		}
	}
}
namespace WKMPMod.RemotePlayer
{
	public class DefaultModelExtension : ICustomModelExtension
	{
		private static readonly string[] TintColorProperties = new string[3] { "_BaseColor", "_Color", "_MainColor" };

		private const string TMP_DISTANCE_FIELD_OVERLAY_MAT = "assets/projects/materials/textmeshpro_distance field overlay.mat";

		private const string GAME_TMP_FONT_ASSET = "Ticketing SDF";

		public string ModelId => "default";

		public string PrefabAssetName => "CapsulePlayerPrefab";

		public string SpawnEffectAssetName => null;

		public string DeathEffectAssetName => null;

		public string DamageEffectAssetName => null;

		public void OnPrefabLoaded(GameObject prefabTemplate, IAssetHelper assetHelper)
		{
			FixTMPComponent(prefabTemplate, assetHelper);
		}

		public void OnPlayerInstanceCreated(GameObject playerInstance)
		{
		}

		private void FixTMPComponent(GameObject prefab, IAssetHelper assetHelper)
		{
			TMP_Text[] componentsInChildren = prefab.GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val in componentsInChildren)
			{
				Debug.Log((object)("RPSlugcatFactory.SpecializingTMPComponent" + ((Object)val).name));
				TMP_FontAsset val2 = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset f) => ((Object)f).name == "Ticketing SDF"));
				if ((Object)(object)val2 == (Object)null)
				{
					Debug.LogError((object)"RPSlugcatFactory.FontAssetNotFoundTicketing SDF");
					continue;
				}
				val.font = val2;
				Material customAsset = assetHelper.GetCustomAsset<Material>("assets/projects/materials/textmeshpro_distance field overlay.mat");
				Material fontMaterial = val.fontMaterial;
				if ((Object)(object)fontMaterial != (Object)null && (Object)(object)customAsset != (Object)null)
				{
					fontMaterial.shader = customAsset.shader;
					Debug.Log((object)"RPSlugcatFactory.ImplementOverlayViaShader");
				}
				else
				{
					Debug.LogError((object)"RPSlugcatFactory.UnableToLoadMaterialassets/projects/materials/textmeshpro_distance field overlay.mat");
				}
			}
		}

		public void ApplyPlayerColor(GameObject instance, Color32 color)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = instance.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)((Component)val).GetComponent<TMP_Text>() != (Object)null)
				{
					continue;
				}
				Color val2 = (((Object)((Component)val).transform).name.StartsWith("Eyes") ? GetContrastColor(Color32.op_Implicit(color)) : Color32.op_Implicit(color));
				Material[] materials = val.materials;
				foreach (Material val3 in materials)
				{
					if ((Object)(object)val3 == (Object)null)
					{
						continue;
					}
					string[] tintColorProperties = TintColorProperties;
					foreach (string text in tintColorProperties)
					{
						if (val3.HasProperty(text))
						{
							Color color2 = val3.GetColor(text);
							val3.SetColor(text, new Color(val2.r, val2.g, val2.b, (float)(int)(byte)Mathf.Clamp(Mathf.RoundToInt(color2.a * 255f), 0, 255)));
						}
					}
				}
			}
		}

		private static Color GetContrastColor(Color color)
		{
			//IL_0006: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			float num = 0.299f * color.r + 0.587f * color.g + 0.114f * color.b;
			return (num > 0.5f) ? Color.black : Color.white;
		}

		public void Crouching(bool isCrouching)
		{
		}
	}
	public interface ICustomModelExtension
	{
		string ModelId { get; }

		string PrefabAssetName { get; }

		string SpawnEffectAssetName { get; }

		string DeathEffectAssetName { get; }

		string DamageEffectAssetName { get; }

		void OnPrefabLoaded(GameObject prefab, IAssetHelper assetHelper);

		void OnPlayerInstanceCreated(GameObject playerInstance);

		void ApplyPlayerColor(GameObject instance, Color32 color);

		void Crouching(bool isCrouching);
	}
	public interface IAssetHelper
	{
		T GetCustomAsset<T>(string assetName) where T : Object;
	}
	public class SlugcatModelExtension : ICustomModelExtension
	{
		private static readonly string[] TintColorProperties = new string[3] { "_BaseColor", "_Color", "_MainColor" };

		private const string TMP_DISTANCE_FIELD_OVERLAY_MAT = "assets/projects/materials/textmeshpro_distance field overlay.mat";

		private const string GAME_TMP_FONT_ASSET = "Ticketing SDF";

		public string ModelId => "slugcat";

		public string PrefabAssetName => "SlugcatPlayerPrefab";

		public string SpawnEffectAssetName => null;

		public string DeathEffectAssetName => null;

		public string DamageEffectAssetName => null;

		public void OnPrefabLoaded(GameObject prefabTemplate, IAssetHelper assetHelper)
		{
			FixTMPComponent(prefabTemplate, assetHelper);
		}

		public void OnPlayerInstanceCreated(GameObject playerInstance)
		{
		}

		private void FixTMPComponent(GameObject prefab, IAssetHelper assetHelper)
		{
			TMP_Text[] componentsInChildren = prefab.GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val in componentsInChildren)
			{
				Debug.Log((object)("RPSlugcatFactory.SpecializingTMPComponent" + ((Object)val).name));
				TMP_FontAsset val2 = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset f) => ((Object)f).name == "Ticketing SDF"));
				if ((Object)(object)val2 == (Object)null)
				{
					Debug.LogError((object)"RPSlugcatFactory.FontAssetNotFoundTicketing SDF");
					continue;
				}
				val.font = val2;
				Material customAsset = assetHelper.GetCustomAsset<Material>("assets/projects/materials/textmeshpro_distance field overlay.mat");
				Material fontMaterial = val.fontMaterial;
				if ((Object)(object)fontMaterial != (Object)null && (Object)(object)customAsset != (Object)null)
				{
					fontMaterial.shader = customAsset.shader;
					Debug.Log((object)"RPSlugcatFactory.ImplementOverlayViaShader");
				}
				else
				{
					Debug.LogError((object)"RPSlugcatFactory.UnableToLoadMaterialassets/projects/materials/textmeshpro_distance field overlay.mat");
				}
			}
		}

		public void ApplyPlayerColor(GameObject instance, Color32 color)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = instance.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)((Component)val).GetComponent<TMP_Text>() != (Object)null)
				{
					continue;
				}
				Color val2 = (((Object)((Component)val).transform).name.StartsWith("Eyes") ? GetContrastColor(Color32.op_Implicit(color)) : Color32.op_Implicit(color));
				Material[] materials = val.materials;
				foreach (Material val3 in materials)
				{
					if ((Object)(object)val3 == (Object)null)
					{
						continue;
					}
					string[] tintColorProperties = TintColorProperties;
					foreach (string text in tintColorProperties)
					{
						if (val3.HasProperty(text))
						{
							Color color2 = val3.GetColor(text);
							val3.SetColor(text, new Color(val2.r, val2.g, val2.b, (float)(int)(byte)Mathf.Clamp(Mathf.RoundToInt(color2.a * 255f), 0, 255)));
						}
					}
				}
			}
		}

		private static Color GetContrastColor(Color color)
		{
			//IL_0006: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			float num = 0.299f * color.r + 0.587f * color.g + 0.114f * color.b;
			return (num > 0.5f) ? Color.black : Color.white;
		}

		public void Crouching(bool isCrouching)
		{
		}
	}
}
namespace WKMPMod.Data
{
	public class DataReader
	{
		private ReadOnlyMemory<byte> _data;

		private int _position;

		public int AvailableBytes => _data.Length - _position;

		public void SetSource(ArraySegment<byte> source)
		{
			_data = source;
			_position = 0;
		}

		public void SetSource(byte[] source)
		{
			_data = source;
			_position = 0;
		}

		public void SetSource(byte[] source, int offset, int length)
		{
			_data = new ReadOnlyMemory<byte>(source, offset, length);
			_position = 0;
		}

		public bool GetBool()
		{
			bool result = _data.Span[_position] != 0;
			_position++;
			return result;
		}

		public byte GetByte()
		{
			byte result = _data.Span[_position];
			_position++;
			return result;
		}

		public short GetShort()
		{
			short result = BinaryPrimitives.ReadInt16LittleEndian(_data.Span.Slice(_position));
			_position += 2;
			return result;
		}

		public ushort GetUShort()
		{
			ushort result = BinaryPrimitives.ReadUInt16LittleEndian(_data.Span.Slice(_position));
			_position += 2;
			return result;
		}

		public int GetInt()
		{
			int result = BinaryPrimitives.ReadInt32LittleEndian(_data.Span.Slice(_position));
			_position += 4;
			return result;
		}

		public uint GetUInt()
		{
			uint result = BinaryPrimitives.ReadUInt32LittleEndian(_data.Span.Slice(_position));
			_position += 4;
			return result;
		}

		public long GetLong()
		{
			long result = BinaryPrimitives.ReadInt64LittleEndian(_data.Span.Slice(_position));
			_position += 8;
			return result;
		}

		public ulong GetULong()
		{
			ulong result = BinaryPrimitives.ReadUInt64LittleEndian(_data.Span.Slice(_position));
			_position += 8;
			return result;
		}

		public float GetFloat()
		{
			int value = BinaryPrimitives.ReadInt32LittleEndian(_data.Span.Slice(_position));
			_position += 4;
			return BitConverter.Int32BitsToSingle(value);
		}

		public double GetDouble()
		{
			long value = BinaryPrimitives.ReadInt64LittleEndian(_data.Span.Slice(_position));
			_position += 8;
			return BitConverter.Int64BitsToDouble(value);
		}

		public byte? GetNullableByte()
		{
			if (!GetBool())
			{
				return null;
			}
			return GetByte();
		}

		public int? GetNullableInt()
		{
			if (!GetBool())
			{
				return null;
			}
			return GetInt();
		}

		public float? GetNullableFloat()
		{
			if (!GetBool())
			{
				return null;
			}
			return GetFloat();
		}

		public Vector3 GetVector3()
		{
			//IL_0060: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			ReadOnlySpan<byte> source = _data.Span.Slice(_position);
			float num = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(source));
			float num2 = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(source.Slice(4)));
			float num3 = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(source.Slice(8)));
			_position += 12;
			return new Vector3(num, num2, num3);
		}

		public Quaternion GetQuaternion()
		{
			//IL_0077: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			ReadOnlySpan<byte> source = _data.Span.Slice(_position);
			float num = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(source));
			float num2 = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(source.Slice(4)));
			float num3 = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(source.Slice(8)));
			float num4 = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(source.Slice(12)));
			_position += 16;
			return new Quaternion(num, num2, num3, num4);
		}

		public string GetString()
		{
			int num = GetInt();
			if (num <= 0)
			{
				return string.Empty;
			}
			if (num > AvailableBytes)
			{
				throw new Exception("String length out of range");
			}
			string result = Encoding.UTF8.GetString(_data.Span.Slice(_position, num));
			_position += num;
			return result;
		}

		public ReadOnlySpan<byte> GetBytes()
		{
			int num = GetInt();
			ReadOnlySpan<byte> result = _data.Span.Slice(_position, num);
			_position += num;
			return result;
		}

		public ReadOnlyMemory<byte> GetMemory()
		{
			int num = GetInt();
			ReadOnlyMemory<byte> result = _data.Slice(_position, num);
			_position += num;
			return result;
		}

		public Dictionary<string, byte> GetStringByteDict()
		{
			int num = GetInt();
			Dictionary<string, byte> dictionary = new Dictionary<string, byte>();
			for (int i = 0; i < num; i++)
			{
				string key = GetString();
				byte value = GetByte();
				dictionary[key] = value;
			}
			return dictionary;
		}

		public List<string> GetStringList()
		{
			List<string> list = new List<string>();
			int num = GetInt();
			for (int i = 0; i < num; i++)
			{
				list.Add(GetString());
			}
			return list;
		}

		public Dictionary<string, string> GetStringStringDict()
		{
			int num = GetInt();
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			for (int i = 0; i < num; i++)
			{
				string key = GetString();
				string value = GetString();
				dictionary[key] = value;
			}
			return dictionary;
		}

		public T Get<T>() where T : INetworkSerializable, new()
		{
			T result = new T();
			result.Deserialize(this);
			return result;
		}

		public void GetOut<T>(out T value) where T : struct, INetworkSerializable
		{
			value = default(T);
			value.Deserialize(this);
		}

		public void GetRef<T>(ref T value) where T : struct, INetworkSerializable
		{
			value.Deserialize(this);
		}

		public List<T> GetList<T>() where T : INetworkSerializable, new()
		{
			int num = GetInt();
			if (num <= 0)
			{
				return new List<T>(0);
			}
			List<T> list = new List<T>(num);
			for (int i = 0; i < num; i++)
			{
				T item = new T();
				item.Deserialize(this);
				list.Add(item);
			}
			return list;
		}

		public void GetList<T>(List<T> existingList) where T : INetworkSerializable, new()
		{
			int num = GetInt();
			existingList.Clear();
			for (int i = 0; i < num; i++)
			{
				T item = new T();
				item.Deserialize(this);
				existingList.Add(item);
			}
		}
	}
	public class DataWriter : IDisposable
	{
		private byte[] _buffer;

		private int _position;

		private readonly ArrayPool<byte> _pool;

		public ArraySegment<byte> Data => new ArraySegment<byte>(_buffer, 0, _position);

		public DataWriter(int initialCapacity = 1024)
		{
			_pool = ArrayPool<byte>.Shared;
			_buffer = _pool.Rent(initialCapacity);
			_position = 0;
		}

		public byte[] ToArray()
		{
			byte[] array = new byte[_position];
			Array.Copy(_buffer, 0, array, 0, _position);
			return array;
		}

		public void CopyDataTo(byte[] target, int targetOffset = 0)
		{
			if (target.Length - targetOffset < _position)
			{
				throw new ArgumentException("Target buffer is too small");
			}
			Array.Copy(_buffer, 0, target, targetOffset, _position);
		}

		public void Reset()
		{
			_position = 0;
		}

		public DataWriter Put(bool value)
		{
			EnsureCapacity(1);
			_buffer[_position] = (byte)(value ? 1u : 0u);
			_position++;
			return this;
		}

		public DataWriter Put(byte value)
		{
			EnsureCapacity(1);
			_buffer[_position] = value;
			_position++;
			return this;
		}

		public DataWriter Put(short value)
		{
			EnsureCapacity(2);
			BinaryPrimitives.WriteInt16LittleEndian(_buffer.AsSpan(_position), value);
			_position += 2;
			return this;
		}

		public DataWriter Put(ushort value)
		{
			EnsureCapacity(2);
			BinaryPrimitives.WriteUInt16LittleEndian(_buffer.AsSpan(_position), value);
			_position += 2;
			return this;
		}

		public DataWriter Put(int value)
		{
			EnsureCapacity(4);
			BinaryPrimitives.WriteInt32LittleEndian(_buffer.AsSpan(_position), value);
			_position += 4;
			return this;
		}

		public DataWriter Put(uint value)
		{
			EnsureCapacity(4);
			BinaryPrimitives.WriteUInt32LittleEndian(_buffer.AsSpan(_position), value);
			_position += 4;
			return this;
		}

		public DataWriter Put(long value)
		{
			EnsureCapacity(8);
			BinaryPrimitives.WriteInt64LittleEndian(_buffer.AsSpan(_position), value);
			_position += 8;
			return this;
		}

		public DataWriter Put(ulong value)
		{
			EnsureCapacity(8);
			BinaryPrimitives.WriteUInt64LittleEndian(_buffer.AsSpan(_position), value);
			_position += 8;
			return this;
		}

		public DataWriter Put(float value)
		{
			EnsureCapacity(4);
			int value2 = BitConverter.SingleToInt32Bits(value);
			BinaryPrimitives.WriteInt32LittleEndian(_buffer.AsSpan(_position), value2);
			_position += 4;
			return this;
		}

		public DataWriter Put(double value)
		{
			EnsureCapacity(8);
			long value2 = BitConverter.DoubleToInt64Bits(value);
			BinaryPrimitives.WriteInt64LittleEndian(_buffer.AsSpan(_position), value2);
			_position += 8;
			return this;
		}

		public DataWriter Put(byte? value)
		{
			if (!value.HasValue)
			{
				Put(value: false);
			}
			else
			{
				Put(value: true);
				Put(value.Value);
			}
			return this;
		}

		public DataWriter Put(int? value)
		{
			if (!value.HasValue)
			{
				Put(value: false);
			}
			else
			{
				Put(value: true);
				Put(value.Value);
			}
			return this;
		}

		public DataWriter Put(float? value)
		{
			if (!value.HasValue)
			{
				Put(value: false);
			}
			else
			{
				Put(value: true);
				Put(value.Value);
			}
			return this;
		}

		public DataWriter Put(byte[] value)
		{
			if (value == null)
			{
				return Put(0);
			}
			return Put(value, 0, value.Length);
		}

		public DataWriter Put(byte[] value, int offset, int length)
		{
			if (value == null)
			{
				EnsureCapacity(4);
				BinaryPrimitives.WriteInt32LittleEndian(_buffer.AsSpan(_position), 0);
				_position += 4;
				return this;
			}
			Put(length);
			EnsureCapacity(length);
			Array.Copy(value, offset, _buffer, _position, length);
			_position += length;
			return this;
		}

		public DataWriter Put(ReadOnlySpan<byte> value)
		{
			Put(value.Length);
			EnsureCapacity(value.Length);
			value.CopyTo(_buffer.AsSpan(_position));
			_position += value.Length;
			return this;
		}

		public DataWriter Put(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				Put(0);
				return this;
			}
			int maxByteCount = Encoding.UTF8.GetMaxByteCount(value.Length);
			EnsureCapacity(maxByteCount + 4);
			int position = _position;
			_position += 4;
			int bytes = Encoding.UTF8.GetBytes(value, 0, value.Length, _buffer, _position);
			BinaryPrimitives.WriteInt32LittleEndian(_buffer.AsSpan(position), bytes);
			_position += bytes;
			return this;
		}

		public DataWriter Put(Vector3 value)
		{
			//IL_001d: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			EnsureCapacity(12);
			Span<byte> destination = _buffer.AsSpan(_position);
			BinaryPrimitives.WriteInt32LittleEndian(destination, BitConverter.SingleToInt32Bits(value.x));
			BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(4), BitConverter.SingleToInt32Bits(value.y));
			BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(8), BitConverter.SingleToInt32Bits(value.z));
			_position += 12;
			return this;
		}

		public DataWriter Put(Quaternion value)
		{
			//IL_001d: 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_004f: 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)
			EnsureCapacity(16);
			Span<byte> destination = _buffer.AsSpan(_position);
			BinaryPrimitives.WriteInt32LittleEndian(destination, BitConverter.SingleToInt32Bits(value.x));
			BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(4), BitConverter.SingleToInt32Bits(value.y));
			BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(8), BitConverter.SingleToInt32Bits(value.z));
			BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(12), BitConverter.SingleToInt32Bits(value.w));
			_position += 16;
			return this;
		}

		public DataWriter Put(Dictionary<string, byte> dict)
		{
			if (dict == null)
			{
				Put(0);
				return this;
			}
			Put(dict.Count);
			foreach (KeyValuePair<string, byte> item in dict)
			{
				Put(item.Key).Put(item.Value);
			}
			return this;
		}

		public DataWriter Put(IReadOnlyList<string> strings)
		{
			if (strings == null)
			{
				Put(0);
				return this;
			}
			Put(strings.Count);
			foreach (string @string in strings)
			{
				Put(@string);
			}
			return this;
		}

		public DataWriter Put(Dictionary<string, string> dict)
		{
			if (dict == null)
			{
				Put(0);
				return this;
			}
			Put(dict.Count);
			foreach (KeyValuePair<string, string> item in dict)
			{
				Put(item.Key).Put(item.Value);
			}
			return this;
		}

		public DataWriter Put<T>(T obj) where T : INetworkSerializable
		{
			obj.Serialize(this);
			return this;
		}

		public DataWriter PutIn<T>(in T obj) where T : struct, INetworkSerializable
		{
			obj.Serialize(this);
			return this;
		}

		public DataWriter Put<T>(IReadOnlyList<T> list) where T : INetworkSerializable
		{
			if (list == null || list.Count == 0)
			{
				Put(0);
				return this;
			}
			Put(list.Count);
			foreach (T item in list)
			{
				item.Serialize(this);
			}
			return this;
		}

		public void EnsureCapacity(int additional)
		{
			if (_position + additional > _buffer.Length)
			{
				byte[] array = _pool.Rent((_position + additional) * 2);
				Array.Copy(_buffer, 0, array, 0, _position);
				_pool.Return(_buffer);
				_buffer = array;
			}
		}

		public void Dispose()
		{
			if (_buffer != null)
			{
				_pool.Return(_buffer);
				_buffer = null;
				_position = 0;
			}
		}
	}
	public interface INetworkSerializable
	{
		void Serialize(DataWriter writer);

		void Deserialize(DataReader reader);
	}
	[Serializable]
	public struct PlayerData : INetworkSerializable
	{
		[Serializable]
		public struct HandData : INetworkSerializable
		{
			public byte handType;

			public byte interactState;

			public float PosX;

			public float PosY;

			public float PosZ;

			public string itemName;

			public ulong targetId;

			public float desiredPosX;

			public float desiredPosY;

			public float desiredPosZ;

			public Vector3 Position
			{
				get
				{
					//IL_0012: Unknown result type (might be due to invalid IL or missing references)
					return new Vector3(PosX, PosY, PosZ);
				}
				set
				{
					//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_001a: Unknown result type (might be due to invalid IL or missing references)
					PosX = value.x;
					PosY = value.y;
					PosZ = value.z;
				}
			}

			public Vector3 DesiredPosition
			{
				get
				{
					//IL_0012: Unknown result type (might be due to invalid IL or missing references)
					return new Vector3(desiredPosX, desiredPosY, desiredPosZ);
				}
				set
				{
					//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_001a: Unknown result type (might be due to invalid IL or missing references)
					desiredPosX = value.x;
					desiredPosY = value.y;
					desiredPosZ = value.z;
				}
			}

			public void Serialize(DataWriter writer)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				writer.Put(handType);
				writer.Put(interactState);
				writer.Put(Position);
				switch (interactState)
				{
				case 0:
					writer.Put(itemName);
					break;
				case 2:
					writer.Put(targetId);
					writer.Put(DesiredPosition);
					break;
				case 4:
					writer.Put(targetId);
					break;
				case 1:
				case 3:
					break;
				}
			}

			public void Deserialize(DataReader reader)
			{
				//IL_001b: 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)
				handType = reader.GetByte();
				interactState = reader.GetByte();
				Position = reader.GetVector3();
				switch (interactState)
				{
				case 0:
					itemName = reader.GetString();
					break;
				case 2:
					targetId = reader.GetULong();
					DesiredPosition = reader.GetVector3();
					break;
				case 4:
					targetId = reader.GetULong();
					break;
				case 1:
				case 3:
					break;
				}
			}

			public bool IsBeGrabbing(ulong targetPlayerId)
			{
				return interactState == 2 && targetId == targetPlayerId;
			}

			public bool IsBeHanging(ulong targetPlayerId)
			{
				return interactState == 4 && targetId == targetPlayerId;
			}

			public static bool operator ==(HandData left, HandData right)
			{
				if (left.handType != right.handType || left.interactState != right.interactState)
				{
					return false;
				}
				float num = left.PosX - right.PosX;
				float num2 = left.PosY - right.PosY;
				float num3 = left.PosZ - right.PosZ;
				if (num * num + num2 * num2 + num3 * num3 >= 0.0025f)
				{
					return false;
				}
				switch (left.interactState)
				{
				case 0:
					return left.itemName == right.itemName;
				case 2:
				{
					if (left.targetId != right.targetId)
					{
						return false;
					}
					float num4 = left.desiredPosX - right.desiredPosX;
					float num5 = left.desiredPosY - right.desiredPosY;
					float num6 = left.desiredPosZ - right.desiredPosZ;
					return num4 * num4 + num5 * num5 + num6 * num6 < 0.0025f;
				}
				case 4:
					return left.targetId == right.targetId;
				default:
					return true;
				}
			}

			public static bool operator !=(HandData left, HandData right)
			{
				return !(left == right);
			}
		}

		private const float POSITION_CHANGE_THRESHOLD_SQR = 0.0025f;

		private const float ROTATION_CHANGE_THRESHOLD_DEG = 0.5f;

		public ulong playId;

		public long TimestampTicks;

		public float PosX;

		public float PosY;

		public float PosZ;

		public float RotX;

		public float RotY;

		public float RotZ;

		public float RotW;

		public HandData LeftHand;

		public HandData RightHand;

		public bool IsTeleport;

		public Vector3 Position
		{
			get
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				return new Vector3(PosX, PosY, PosZ);
			}
			set
			{
				//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_001a: Unknown result type (might be due to invalid IL or missing references)
				PosX = value.x;
				PosY = value.y;
				PosZ = value.z;
			}
		}

		public Quaternion Rotation
		{
			get
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				return new Quaternion(RotX, RotY, RotZ, RotW);
			}
			set
			{
				//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_001a: 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)
				RotX = value.x;
				RotY = value.y;
				RotZ = value.z;
				RotW = value.w;
			}
		}

		public void Serialize(DataWriter writer)
		{
			//IL_001b: 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)
			writer.Put(playId).Put(TimestampTicks);
			writer.Put(Position).Put(Rotation);
			writer.PutIn(in LeftHand).PutIn(in RightHand);
			writer.Put(IsTeleport);
		}

		public void Deserialize(DataReader reader)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			playId = reader.GetULong();
			TimestampTicks = reader.GetLong();
			Position = reader.GetVector3();
			Rotation = reader.GetQuaternion();
			reader.GetRef(ref LeftHand);
			reader.GetRef(ref RightHand);
			IsTeleport = reader.GetBool();
		}

		public bool UpdateIfChanged(in PlayerData newData, bool forceUpdate = false)
		{
			//IL_0058: 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)
			if (forceUpdate)
			{
				this = newData;
				return true;
			}
			float num = PosX - newData.PosX;
			float num2 = PosY - newData.PosY;
			float num3 = PosZ - newData.PosZ;
			if (num * num + num2 * num2 + num3 * num3 >= 0.0025f || !IsRotationSimilar(Rotation, newData.Rotation, 0.5f) || LeftHand != newData.LeftHand || RightHand != newData.RightHand)
			{
				this = newData;
				return true;
			}
			return false;
		}

		private static bool IsRotationSimilar(Quaternion a, Quaternion b, float thresholdDegrees)
		{
			//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)
			float num = Mathf.Cos(thresholdDegrees * (MathF.PI / 180f) * 0.5f);
			float num2 = Mathf.Abs(Quaternion.Dot(a, b));
			return num2 > num;
		}
	}
}
namespace WKMPMod.Component
{
	public class LookAt : MonoBehaviour
	{
		private Camera? mainCamera;

		[Header("锁定大小")]
		public bool maintainScreenSize = true;

		[Header("初始缩放比例")]
		public float baseScale = 0.1f;

		[Header("用户设置缩放比例")]
		public float userScale = 1f;

		private void LateUpdate()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)mainCamera == (Object)null)
			{
				mainCamera = Camera.main;
				if ((Object)(object)mainCamera == (Object)null)
				{
					return;
				}
			}
			((Component)this).transform.rotation = ((Component)mainCamera).transform.rotation;
			if (maintainScreenSize)
			{
				float num = Vector3.Distance(((Component)this).transform.position, ((Component)mainCamera).transform.position);
				float num2 = ((!(num < 10f)) ? num : (0.8f * num + 2f));
				float num3 = num2 * baseScale * userScale;
				((Component)this).transform.localScale = new Vector3(num3, num3, num3);
			}
		}
	}
	public class RemotePlayer : MonoBehaviour
	{
		public ulong playerId;

		[Header("距离设置")]
		[Tooltip("当当前位置与目标位置超过此距离时直接瞬移")]
		public float teleportThreshold = 50f;

		[Tooltip("平滑移动的最大距离限制")]
		public float maxSmoothDistance = 10f;

		private bool _isTeleporting = false;

		private Vector3 _targetPosition;

		private Vector3 _velocity = Vector3.zero;

		private void LateUpdate()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if (_isTeleporting)
			{
				return;
			}
			float num = Vector3.Distance(((Component)this).transform.position, _targetPosition);
			if (num > teleportThreshold)
			{
				Teleport(_targetPosition);
			}
			else if (((Component)this).transform.position != _targetPosition)
			{
				float num2 = CalculateSmoothTime(num);
				((Component)this).transform.position = Vector3.SmoothDamp(((Component)this).transform.position, _targetPosition, ref _velocity, num2, float.MaxValue, Time.deltaTime);
				if (((Vector3)(ref _velocity)).magnitude < 0.5f && num > 0.05f)
				{
					Vector3 val = _targetPosition - ((Component)this).transform.position;
					Vector3 normalized = ((Vector3)(ref val)).normalized;
					_velocity = normalized * 0.5f;
				}
			}
		}

		private float CalculateSmoothTime(float distance)
		{
			if (distance > maxSmoothDistance)
			{
				return Mathf.Clamp(Mathf.Log(distance) * 0.1f, 0.05f, 0.3f);
			}
			return Mathf.Clamp(distance / 10f, 0.05f, 0.1f);
		}

		public void UpdateFromPlayerData(Vector3 position, Quaternion rotation)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			_isTeleporting = false;
			_targetPosition = position;
			((Component)this).transform.rotation = rotation;
		}

		public void UpdateFromPlayerData(ref PlayerData playerData)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			_isTeleporting = false;
			_targetPosition = playerData.Position;
			((Component)this).transform.rotation = playerData.Rotation;
		}

		public void Teleport(Vector3 position, Quaternion? rotation = null)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			_isTeleporting = true;
			((Component)this).transform.position = position;
			_targetPosition = position;
			_velocity = Vector3.zero;
			if (rotation.HasValue)
			{
				((Component)this).transform.rotation = rotation.Value;
			}
			((MonoBehaviour)this).StartCoroutine(ResetTeleportFlag());
		}

		private IEnumerator ResetTeleportFlag()
		{
			yield return null;
			_isTeleporting = false;
		}
	}
	public class RemoteTag : MonoBehaviour
	{
		private Transform? _cameraTransform;

		private TextMeshPro? _textMeshPro;

		private float _lastUpdateDistance;

		private TickTimer updateTick = new TickTimer(1);

		[Header("Settings")]
		public const float MIN_DISTANCE_LABEL = 10f;

		public const float DISTANCE_CHANGE_THRESHOLD = 1f;

		public const float MESSAGE_TIMEOUT = 15f;

		[Header("Id")]
		public ulong PlayerId;

		[Header("名字")]
		public string PlayerName = "";

		[Header("Message")]
		public string _message = "";

		private Coroutine? _messageTimeoutCoroutine;

		public string Message
		{
			get
			{
				return _message;
			}
			set
			{
				string text = ((value.Length <= 15) ? value : value.Substring(0, 15));
				if (!(_message == text))
				{
					_message = text;
					if (_messageTimeoutCoroutine != null)
					{
						((MonoBehaviour)this).StopCoroutine(_messageTimeoutCoroutine);
					}
					_messageTimeoutCoroutine = ((MonoBehaviour)this).StartCoroutine(MessageTimeoutRoutine());
					RefreshName();
				}
			}
		}

		private void Awake()
		{
			_textMeshPro = ((Component)this).GetComponent<TextMeshPro>();
			if ((Object)(object)Camera.main != (Object)null)
			{
				_cameraTransform = ((Component)Camera.main).transform;
			}
		}

		private void OnDestroy()
		{
			if (_messageTimeoutCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_messageTimeoutCoroutine);
			}
		}

		private void Update()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (!updateTick.TryTick())
			{
				return;
			}
			if ((Object)(object)_cameraTransform == (Object)null)
			{
				if (!((Object)(object)Camera.main != (Object)null))
				{
					Debug.LogError((object)"[MP RemoteTag]No main camera found");
					return;
				}
				_cameraTransform = ((Component)Camera.main).transform;
			}
			float num = Vector3.Distance(((Component)this).transform.position, _cameraTransform.position);
			if (Mathf.Abs(num - _lastUpdateDistance) >= 1f)
			{
				RefreshName(num);
			}
		}

		public void Initialize(ulong playerId, string playerName)
		{
			PlayerId = playerId;
			PlayerName = playerName;
		}

		public void RefreshName()
		{
			//IL_001a: 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)
			if (!((Object)(object)_cameraTransform == (Object)null))
			{
				RefreshName(Vector3.Distance(((Component)this).transform.position, _cameraTransform.position));
			}
		}

		private void RefreshName(float currentDistance)
		{
			_lastUpdateDistance = currentDistance;
			if (!((Object)(object)_textMeshPro == (Object)null))
			{
				string text = currentDistance.ToString("F0");
				if (currentDistance < 10f)
				{
					((TMP_Text)_textMeshPro).text = (string.IsNullOrEmpty(_message) ? PlayerName : (PlayerName + "\n" + _message));
					return;
				}
				((TMP_Text)_textMeshPro).text = (string.IsNullOrEmpty(_message) ? (PlayerName + " (" + text + "m)") : (PlayerName + " (" + text + "m)\n" + _message));
			}
		}

		private IEnumerator MessageTimeoutRoutine()
		{
			yield return (object)new WaitForSeconds(15f);
			_message = "";
			RefreshName();
			_messageTimeoutCoroutine = null;
		}
	}
	public class SimpleArmIK : MonoBehaviour
	{
		[Header("目标设置")]
		public Transform? target;

		public float originalLength = 1f;

		[Header("限制")]
		public float minScale = 0.1f;

		public float maxScale = 10f;

		private void Start()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (originalLength <= 0f && (Object)(object)target != (Object)null)
			{
				originalLength = Vector3.Distance(((Component)this).transform.position, target.position);
			}
		}

		private void LateUpdate()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)target == (Object)null))
			{
				Vector3 val = target.position - ((Component)this).transform.position;
				float magnitude = ((Vector3)(ref val)).magnitude;
				if (!(magnitude < 0.0001f))
				{
					((Component)this).transform.rotation = Quaternion.FromToRotation(Vector3.up, val);
					float num = magnitude / originalLength;
					num = Mathf.Clamp(num, minScale, maxScale);
					((Component)this).transform.localScale = new Vector3(1f, num, 1f);
				}
			}
		}
	}
}