Decompiled source of VBNetTweaks v0.1.51

VBNetTweaks.dll

Decompiled a day ago
#define DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
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 BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Extensions;
using Microsoft.CodeAnalysis;
using Steamworks;
using UnityEngine;
using VBNetTweaks.Utils;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("VBNetTweaks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VBNetTweaks")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("d9c87954-ce20-459d-81ec-96599caed427")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace VBNetTweaks
{
	public static class AdaptiveThrottler
	{
		private class PeerStats
		{
			public float lastPing;

			public float lastPingTime;

			public int missedPings;
		}

		private static float _lastEvalTime;

		private static float _currentInterval = 0.05f;

		private const float LowPingThreshold = 0.15f;

		private const float HighPingThreshold = 0.6f;

		private const float MinInterval = 0.03f;

		private const float MaxInterval = 0.1f;

		private const float EvalInterval = 1f;

		private static readonly Dictionary<ZNetPeer, PeerStats> _peerStats = new Dictionary<ZNetPeer, PeerStats>();

		public static void Update(ZNet znet, float dt)
		{
			if (!Object.op_Implicit((Object)(object)znet) || !Helper.IsServer())
			{
				return;
			}
			_lastEvalTime += dt;
			if (_lastEvalTime < 1f)
			{
				return;
			}
			_lastEvalTime = 0f;
			List<ZNetPeer> peers = znet.m_peers;
			if (peers == null || peers.Count == 0)
			{
				_currentInterval = VBNetTweaks.SendInterval?.Value ?? 0.05f;
				return;
			}
			float time = Time.time;
			float num = 0f;
			float num2 = 0f;
			int num3 = 0;
			for (int i = 0; i < peers.Count; i++)
			{
				ZNetPeer val = peers[i];
				if (val?.m_rpc == null)
				{
					continue;
				}
				if (!_peerStats.TryGetValue(val, out var value))
				{
					value = new PeerStats();
					_peerStats[val] = value;
				}
				float timeSinceLastPing = val.m_rpc.GetTimeSinceLastPing();
				if (timeSinceLastPing < 10f)
				{
					if (timeSinceLastPing > value.lastPing * 2f)
					{
						value.missedPings++;
					}
					else
					{
						value.missedPings = Mathf.Max(0, value.missedPings - 1);
					}
					value.lastPing = timeSinceLastPing;
					value.lastPingTime = time;
					num3++;
				}
				else if (time - value.lastPingTime > 5f)
				{
					value.missedPings += 2;
				}
				if (time - value.lastPingTime < 3f)
				{
					if (timeSinceLastPing > num)
					{
						num = timeSinceLastPing;
					}
					num2 += (float)value.missedPings;
				}
			}
			if (num3 == 0)
			{
				_currentInterval = VBNetTweaks.SendInterval?.Value ?? 0.05f;
				return;
			}
			num2 /= (float)num3;
			float num4 = VBNetTweaks.SendInterval?.Value ?? 0.05f;
			float num5 = num4;
			if (num < 0.15f)
			{
				num5 = Mathf.Max(0.03f, num4 * 0.7f);
			}
			else if (num > 0.6f)
			{
				num5 = Mathf.Min(0.1f, num4 * 1.5f);
			}
			if (num2 > 2f)
			{
				num5 = Mathf.Min(0.1f, num5 * 1.3f);
			}
			else if (num2 < 0.5f && num < 0.6f)
			{
				num5 = Mathf.Max(0.03f, num5 * 0.9f);
			}
			_currentInterval = num5;
			if (VBNetTweaks.DebugEnabled.Value)
			{
				VBNetTweaks.LogDebug($"AdaptiveThrottler: ping={num:0.000}s loss={num2:F1} " + $"base={num4:0.000}s -> interval={_currentInterval:0.000}s");
			}
		}

		public static void OnPeerDisconnected(ZNetPeer peer)
		{
			_peerStats.Remove(peer);
		}

		public static float GetInterval(float fallback)
		{
			return (_currentInterval > 0f) ? _currentInterval : fallback;
		}
	}
	public interface ICompressor
	{
		byte[] Compress(byte[] data);

		byte[] Decompress(byte[] data);
	}
	public class DeflateCompressor : ICompressor
	{
		public byte[] Compress(byte[] data)
		{
			if (data.Length < 32)
			{
				return data;
			}
			using MemoryStream memoryStream = new MemoryStream();
			using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionLevel.Fastest))
			{
				deflateStream.Write(data, 0, data.Length);
			}
			byte[] array = memoryStream.ToArray();
			return (array.Length < data.Length) ? array : data;
		}

		public byte[] Decompress(byte[] data)
		{
			using MemoryStream stream = new MemoryStream(data);
			using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress);
			using MemoryStream memoryStream = new MemoryStream();
			deflateStream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}
	}
	public class ZstdCompressor : ICompressor
	{
		private dynamic _compressor;

		private dynamic _decompressor;

		public ZstdCompressor()
		{
			try
			{
				Assembly assembly = Assembly.Load("ZstdSharp");
				Type type = assembly.GetType("ZstdSharp.Compressor");
				Type type2 = assembly.GetType("ZstdSharp.Decompressor");
				_compressor = Activator.CreateInstance(type, 1);
				_decompressor = Activator.CreateInstance(type2);
			}
			catch
			{
				throw new Exception("ZstdSharp not available");
			}
		}

		public byte[] Compress(byte[] data)
		{
			if (data.Length < 32)
			{
				return data;
			}
			dynamic val = _compressor.Wrap(data);
			return (val is byte[] array) ? array : val.ToArray();
		}

		public byte[] Decompress(byte[] data)
		{
			dynamic val = _decompressor.Unwrap(data);
			return (val is byte[] array) ? array : val.ToArray();
		}
	}
	[HarmonyPatch]
	public static class PlayerCache
	{
		private static List<Player> _cachedPlayers = new List<Player>();

		private static Dictionary<long, Player> _playersById = new Dictionary<long, Player>();

		private static Dictionary<long, bool> _playerAttachedState = new Dictionary<long, bool>();

		private static Dictionary<long, ZDOID> _playerShipMap = new Dictionary<long, ZDOID>();

		private static int _cachedFrame = -1;

		private static float _cachedTime = -1f;

		public static List<Player> GetAll()
		{
			return GetCached();
		}

		public static List<Player> GetCurrentFrame()
		{
			return GetCached(0f);
		}

		public static List<Player> GetCached(float maxAgeSeconds = 0.5f)
		{
			if (Time.time - _cachedTime > maxAgeSeconds || _cachedFrame != Time.frameCount)
			{
				RefreshCache();
				_cachedTime = Time.time;
				_cachedFrame = Time.frameCount;
			}
			return _cachedPlayers;
		}

		public static Player GetById(long id)
		{
			if (_cachedFrame != Time.frameCount)
			{
				RefreshCache();
			}
			Player value;
			return _playersById.TryGetValue(id, out value) ? value : null;
		}

		public static bool IsPlayerOnShip(long playerId)
		{
			return _playerShipMap.ContainsKey(playerId);
		}

		public static bool IsPlayerAttached(long playerId)
		{
			bool value;
			return _playerAttachedState.TryGetValue(playerId, out value) && value;
		}

		public static ZDOID GetPlayerShip(long playerId)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			ZDOID value;
			return (ZDOID)(_playerShipMap.TryGetValue(playerId, out value) ? value : default(ZDOID));
		}

		public static void UpdatePlayerState(long playerId, bool attached, ZDOID shipId)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			_playerAttachedState[playerId] = attached;
			if (((ZDOID)(ref shipId)).IsNone())
			{
				_playerShipMap.Remove(playerId);
			}
			else
			{
				_playerShipMap[playerId] = shipId;
			}
		}

		public static void RemovePlayer(long playerId)
		{
			_playersById.Remove(playerId);
			_playerAttachedState.Remove(playerId);
			_playerShipMap.Remove(playerId);
		}

		private static void RefreshCache()
		{
			_cachedPlayers.Clear();
			_playersById.Clear();
			List<Player> allPlayers = Player.GetAllPlayers();
			_cachedPlayers.AddRange(allPlayers);
			foreach (Player item in allPlayers)
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					long playerID = item.GetPlayerID();
					_playersById[playerID] = item;
				}
			}
			if (VBNetTweaks.DebugEnabled.Value && VBNetTweaks.VerboseLogging.Value)
			{
				VBNetTweaks.LogVerbose($"PlayerCache refreshed: {_cachedPlayers.Count} players");
			}
		}

		public static void Invalidate()
		{
			_cachedFrame = -1;
			_cachedTime = -1f;
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		[HarmonyPostfix]
		private static void OnNewConnection()
		{
			Invalidate();
		}

		[HarmonyPatch(typeof(ZNet), "Disconnect")]
		[HarmonyPostfix]
		private static void OnDisconnect(ZNetPeer peer)
		{
			Invalidate();
			if (peer != null)
			{
				RemovePlayer(peer.m_uid);
			}
		}
	}
	[HarmonyPatch]
	public static class PlayerSyncSystem
	{
		private class PD
		{
			public Vector3 pos;

			public Quaternion rot;

			public Vector3 vel;

			public float t;

			public bool ok;
		}

		private static readonly Dictionary<long, PD> _playerData = new Dictionary<long, PD>();

		private static readonly Stack<PD> _pdPool = new Stack<PD>();

		private static PD GetOrCreatePD()
		{
			if (_pdPool.Count > 0)
			{
				return _pdPool.Pop();
			}
			return new PD();
		}

		private static void ReturnPD(PD pd)
		{
			pd.ok = false;
			_pdPool.Push(pd);
		}

		public static void CleanupPeer(long uid)
		{
			if (_playerData.TryGetValue(uid, out var value))
			{
				ReturnPD(value);
			}
			_playerData.Remove(uid);
			PlayerCache.RemovePlayer(uid);
		}

		[HarmonyPatch(typeof(ZNetView), "Deserialize")]
		[HarmonyPostfix]
		public static void CapturePlayerState(ZNetView __instance)
		{
			//IL_007c: 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_0083: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: 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_0120: 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)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			if (Helper.IsServer() || !Object.op_Implicit((Object)(object)__instance))
			{
				return;
			}
			Player component = ((Component)__instance).GetComponent<Player>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return;
			}
			ZDO zDO = __instance.GetZDO();
			if (zDO == null || !zDO.IsValid())
			{
				return;
			}
			long owner = zDO.GetOwner();
			if (owner == 0L || owner == ZNet.GetUID())
			{
				return;
			}
			Vector3 position = zDO.GetPosition();
			Quaternion rotation = zDO.GetRotation();
			if (!_playerData.TryGetValue(owner, out var value))
			{
				value = GetOrCreatePD();
				value.pos = position;
				value.rot = rotation;
				value.t = Time.time;
				value.ok = true;
				_playerData[owner] = value;
				return;
			}
			float num = Time.time - value.t;
			if (num > 0f)
			{
				value.vel = (position - value.pos) / num;
			}
			value.pos = position;
			value.rot = rotation;
			value.t = Time.time;
			value.ok = true;
		}

		[HarmonyPatch(typeof(Player), "LateUpdate")]
		[HarmonyPostfix]
		public static void SmoothRemotePlayers(Player __instance)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer || Helper.IsServer())
			{
				return;
			}
			long playerID = __instance.GetPlayerID();
			if (!_playerData.TryGetValue(playerID, out var value) || !value.ok)
			{
				return;
			}
			bool flag = PlayerCache.IsPlayerAttached(playerID);
			bool flag2 = PlayerCache.IsPlayerOnShip(playerID);
			if (!(flag || flag2))
			{
				if (VBNetTweaks.EnablePlayerPrediction.Value)
				{
					float num = Time.deltaTime * 1.5f;
					Vector3 val = value.pos + value.vel * num;
					((Component)__instance).transform.position = Vector3.Lerp(((Component)__instance).transform.position, val, 0.8f);
				}
				if (VBNetTweaks.EnableClientInterpolation.Value)
				{
					float num2 = Mathf.Clamp01(Time.deltaTime * 12f);
					Vector3 val2 = value.pos + value.vel * Time.deltaTime * 0.5f;
					((Component)__instance).transform.position = Vector3.Lerp(((Component)__instance).transform.position, val2, num2);
					((Component)__instance).transform.rotation = Quaternion.Slerp(((Component)__instance).transform.rotation, value.rot, num2);
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "Disconnect")]
		[HarmonyPostfix]
		public static void OnPeerDisconnect(ZNetPeer peer)
		{
			if (peer != null)
			{
				long uid = peer.m_uid;
				CleanupPeer(uid);
				AdaptiveThrottler.OnPeerDisconnected(peer);
			}
		}
	}
	public static class RpcBatcher
	{
		private class RpcEntry
		{
			public string Name;

			public object[] Args;

			public int Priority;
		}

		private static readonly Dictionary<ZNetView, List<RpcEntry>> rpcQueue = new Dictionary<ZNetView, List<RpcEntry>>();

		private static readonly object _lock = new object();

		private static float lastSendTime;

		private const float SendInterval = 0.05f;

		public static void Enqueue(ZNetView nview, string rpcName, int priority, params object[] args)
		{
			if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid())
			{
				return;
			}
			lock (_lock)
			{
				if (!rpcQueue.TryGetValue(nview, out var value))
				{
					value = new List<RpcEntry>();
					rpcQueue[nview] = value;
				}
				value.Add(new RpcEntry
				{
					Name = rpcName,
					Args = args,
					Priority = priority
				});
			}
		}

		public static void Update()
		{
			float time = Time.time;
			if (time - lastSendTime < 0.05f)
			{
				return;
			}
			lastSendTime = time;
			Dictionary<ZNetView, List<RpcEntry>> dictionary;
			lock (_lock)
			{
				if (rpcQueue.Count == 0)
				{
					return;
				}
				dictionary = new Dictionary<ZNetView, List<RpcEntry>>(rpcQueue.Count);
				foreach (KeyValuePair<ZNetView, List<RpcEntry>> item in rpcQueue)
				{
					dictionary[item.Key] = new List<RpcEntry>(item.Value);
					item.Value.Clear();
				}
			}
			foreach (KeyValuePair<ZNetView, List<RpcEntry>> item2 in dictionary)
			{
				ZNetView key = item2.Key;
				List<RpcEntry> value = item2.Value;
				if (!Object.op_Implicit((Object)(object)key) || !key.IsValid() || value.Count == 0)
				{
					continue;
				}
				value.Sort((RpcEntry a, RpcEntry b) => b.Priority.CompareTo(a.Priority));
				ZPackage val = ObjectPool.RentPackage();
				try
				{
					val.Write(value.Count);
					foreach (RpcEntry item3 in value)
					{
						val.Write(item3.Name);
						val.Write(item3.Args.Length);
						for (int i = 0; i < item3.Args.Length; i++)
						{
							RpcSerializer.WriteArg(val, item3.Args[i]);
						}
					}
					key.InvokeRPC("VBNT_RPCBatch", new object[1] { val });
				}
				finally
				{
					ObjectPool.ReturnPackage(val);
				}
			}
		}

		public static void HandleBatch(long sender, ZPackage pkg)
		{
			int num = pkg.ReadInt();
			for (int i = 0; i < num; i++)
			{
				string text = pkg.ReadString();
				int num2 = pkg.ReadInt();
				object[] array = new object[num2];
				for (int j = 0; j < num2; j++)
				{
					array[j] = RpcSerializer.ReadArg(pkg);
				}
				if (VBNetTweaks.DebugEnabled.Value && VBNetTweaks.VerboseLogging.Value)
				{
					VBNetTweaks.LogDebug($"RpcBatcher: executing {text} ({num2} args)");
				}
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, text, array);
			}
		}
	}
	[HarmonyPatch]
	public static class ShipSyncSystem
	{
		private class ShipData
		{
			public Vector3 pos;

			public Quaternion rot;

			public Vector3 vel;

			public float t;

			public bool ok;
		}

		private class PlayerShipState
		{
			public Ship ship;

			public Vector3 localPos;

			public Quaternion localRot;

			public float lastUpdate;

			public bool isAttached;
		}

		private static readonly Dictionary<long, ShipData> _shipData;

		private static readonly Dictionary<long, PlayerShipState> _playerStates;

		private static readonly Dictionary<ZDOID, int> _playersOnShip;

		private static readonly Dictionary<long, ZDOID> _playerShipMap;

		private const string RPC_SYNC_ATTACHMENT = "VBNT.SyncAttachment";

		public static bool ShipHasPlayers(ZDOID shipId)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return _playersOnShip.ContainsKey(shipId);
		}

		public static int GetPlayersOnShipCount(ZDOID shipId)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			int value;
			return _playersOnShip.TryGetValue(shipId, out value) ? value : 0;
		}

		public static bool IsPlayerOnShip(long playerId)
		{
			return PlayerCache.IsPlayerOnShip(playerId);
		}

		public static bool IsPlayerAttached(long playerId)
		{
			return PlayerCache.IsPlayerAttached(playerId);
		}

		static ShipSyncSystem()
		{
			_shipData = new Dictionary<long, ShipData>();
			_playerStates = new Dictionary<long, PlayerShipState>();
			_playersOnShip = new Dictionary<ZDOID, int>();
			_playerShipMap = new Dictionary<long, ZDOID>();
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<long, bool, ZDOID, string>("VBNT.SyncAttachment", (Method<long, bool, ZDOID, string>)RPC_SyncAttachment);
			}
		}

		private static void SyncAttachment(long playerId, bool attached, ZDOID shipId, string attachPointName = "")
		{
			//IL_003d: 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)
			if (Object.op_Implicit((Object)(object)ZNet.instance))
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "VBNT.SyncAttachment", new object[4] { playerId, attached, shipId, attachPointName });
				PlayerCache.UpdatePlayerState(playerId, attached, shipId);
			}
		}

		private static void RPC_SyncAttachment(long sender, long playerId, bool attached, ZDOID shipId, string attachPointName)
		{
			//IL_0044: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			if (sender == ZNet.GetUID())
			{
				return;
			}
			Player byId = PlayerCache.GetById(playerId);
			if (!Object.op_Implicit((Object)(object)byId))
			{
				VBNetTweaks.LogDebug($"RPC_SyncAttachment: player {playerId} not found");
				return;
			}
			PlayerCache.UpdatePlayerState(playerId, attached, shipId);
			if (attached)
			{
				GameObject val = ZNetScene.instance.FindInstance(shipId);
				if (!Object.op_Implicit((Object)(object)val))
				{
					return;
				}
				Ship component = val.GetComponent<Ship>();
				if (Object.op_Implicit((Object)(object)component))
				{
					Transform val2 = FindAttachPoint(component, attachPointName);
					if (Object.op_Implicit((Object)(object)val2) && !((Character)byId).IsAttached())
					{
						((Character)byId).AttachStart(val2, (GameObject)null, false, false, true, "attach_chair", Vector3.zero, (Transform)null);
					}
				}
			}
			else if (((Character)byId).IsAttached())
			{
				((Character)byId).AttachStop();
			}
		}

		public static void CleanupPeer(long uid)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			_shipData.Remove(uid);
			if (_playerShipMap.TryGetValue(uid, out var value))
			{
				if (_playersOnShip.TryGetValue(value, out var value2))
				{
					if (value2 <= 1)
					{
						_playersOnShip.Remove(value);
					}
					else
					{
						_playersOnShip[value] = value2 - 1;
					}
				}
				_playerShipMap.Remove(uid);
			}
			_playerStates.Remove(uid);
			PlayerCache.RemovePlayer(uid);
		}

		private static Transform FindAttachPoint(Ship ship, string pointName)
		{
			if (!Object.op_Implicit((Object)(object)ship))
			{
				return null;
			}
			ShipControlls componentInChildren = ((Component)ship).GetComponentInChildren<ShipControlls>();
			if (Object.op_Implicit((Object)(object)componentInChildren) && Object.op_Implicit((Object)(object)componentInChildren.m_attachPoint))
			{
				return componentInChildren.m_attachPoint;
			}
			Chair[] componentsInChildren = ((Component)ship).GetComponentsInChildren<Chair>();
			Chair[] array = componentsInChildren;
			foreach (Chair val in array)
			{
				if (Object.op_Implicit((Object)(object)val.m_attachPoint))
				{
					return val.m_attachPoint;
				}
			}
			if (!string.IsNullOrEmpty(pointName))
			{
				Transform val2 = ((Component)ship).transform.Find(pointName);
				if (Object.op_Implicit((Object)(object)val2))
				{
					return val2;
				}
			}
			return null;
		}

		private static Ship GetShipUnderPlayer(Player p)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//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)
			Vector3 val = ((Component)p).transform.position + Vector3.up * 0.2f;
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(val, Vector3.down, ref val2, 2f))
			{
				return ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Ship>();
			}
			return null;
		}

		private static bool IsPlayerAttached(Player p)
		{
			return Object.op_Implicit((Object)(object)p) && ((Character)p).IsAttached();
		}

		private static bool IsShipZDO(ZDO zdo)
		{
			int prefab = zdo.GetPrefab();
			return prefab == StringExtensionMethods.GetStableHashCode("Karve") || prefab == StringExtensionMethods.GetStableHashCode("VikingShip") || prefab == StringExtensionMethods.GetStableHashCode("Raft") || prefab == StringExtensionMethods.GetStableHashCode("VikingShip_Ashlands");
		}

		[HarmonyPatch(typeof(ZNetView), "Deserialize")]
		[HarmonyPostfix]
		public static void CaptureShipState(ZNetView __instance)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			if (Helper.IsServer() || !Object.op_Implicit((Object)(object)__instance))
			{
				return;
			}
			Ship component = ((Component)__instance).GetComponent<Ship>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return;
			}
			ZDO zDO = __instance.GetZDO();
			if (zDO == null || !zDO.IsValid())
			{
				return;
			}
			long owner = zDO.GetOwner();
			if (owner == 0 || owner == ZNet.GetUID())
			{
				return;
			}
			Vector3 position = zDO.GetPosition();
			Quaternion rotation = zDO.GetRotation();
			if (!_shipData.TryGetValue(owner, out var value))
			{
				value = new ShipData
				{
					pos = position,
					rot = rotation,
					t = Time.time,
					ok = true
				};
				_shipData[owner] = value;
				return;
			}
			float num = Time.time - value.t;
			if (num > 0f)
			{
				value.vel = (position - value.pos) / num;
			}
			value.pos = position;
			value.rot = rotation;
			value.t = Time.time;
			value.ok = true;
		}

		[HarmonyPatch(typeof(Ship), "CustomFixedUpdate")]
		[HarmonyPostfix]
		public static void SmoothShip(Ship __instance)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			if (Helper.IsServer())
			{
				return;
			}
			ZNetView nview = __instance.m_nview;
			ZDO val = ((nview != null) ? nview.GetZDO() : null);
			if (val != null && IsShipZDO(val))
			{
				long owner = val.GetOwner();
				if (_shipData.TryGetValue(owner, out var value) && value.ok)
				{
					Transform transform = ((Component)__instance).transform;
					Vector3 val2 = value.pos + value.vel * Time.deltaTime;
					transform.position = Vector3.Lerp(transform.position, val2, 0.25f);
					transform.rotation = Quaternion.Slerp(transform.rotation, value.rot, 0.15f);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Update")]
		[HarmonyPostfix]
		public static void TrackLocalPlayer(Player __instance)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			long playerID = __instance.GetPlayerID();
			PlayerShipState value;
			Ship val = (_playerStates.TryGetValue(playerID, out value) ? value.ship : null);
			Ship shipUnderPlayer = GetShipUnderPlayer(__instance);
			bool flag = IsPlayerAttached(__instance);
			if ((Object)(object)val == (Object)(object)shipUnderPlayer && Object.op_Implicit((Object)(object)shipUnderPlayer))
			{
				if (_playerStates.TryGetValue(playerID, out var value2))
				{
					value2.localPos = ((Component)shipUnderPlayer).transform.InverseTransformPoint(((Component)__instance).transform.position);
					value2.localRot = Quaternion.Inverse(((Component)shipUnderPlayer).transform.rotation) * ((Component)__instance).transform.rotation;
					value2.isAttached = flag;
					value2.lastUpdate = Time.time;
				}
				return;
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				ZNetView nview = val.m_nview;
				ZDO val2 = ((nview != null) ? nview.GetZDO() : null);
				if (val2 != null)
				{
					ZDOID uid = val2.m_uid;
					if (_playersOnShip.TryGetValue(uid, out var value3))
					{
						if (value3 <= 1)
						{
							_playersOnShip.Remove(uid);
						}
						else
						{
							_playersOnShip[uid] = value3 - 1;
						}
					}
				}
			}
			if (Object.op_Implicit((Object)(object)shipUnderPlayer))
			{
				ZNetView nview2 = shipUnderPlayer.m_nview;
				ZDO val3 = ((nview2 != null) ? nview2.GetZDO() : null);
				if (val3 != null)
				{
					ZDOID uid2 = val3.m_uid;
					_playersOnShip[uid2] = ((!_playersOnShip.TryGetValue(uid2, out var value4)) ? 1 : (value4 + 1));
					_playerShipMap[playerID] = uid2;
				}
			}
			if (!_playerStates.TryGetValue(playerID, out var value5))
			{
				value5 = new PlayerShipState();
				_playerStates[playerID] = value5;
			}
			bool isAttached = value5.isAttached;
			bool flag2 = (Object)(object)val != (Object)(object)shipUnderPlayer;
			value5.ship = shipUnderPlayer;
			value5.isAttached = flag;
			if (Object.op_Implicit((Object)(object)shipUnderPlayer))
			{
				value5.localPos = ((Component)shipUnderPlayer).transform.InverseTransformPoint(((Component)__instance).transform.position);
				value5.localRot = Quaternion.Inverse(((Component)shipUnderPlayer).transform.rotation) * ((Component)__instance).transform.rotation;
			}
			value5.lastUpdate = Time.time;
			if (flag2 || isAttached != flag)
			{
				ZDOID? obj;
				if (shipUnderPlayer == null)
				{
					obj = null;
				}
				else
				{
					ZNetView nview3 = shipUnderPlayer.m_nview;
					obj = ((nview3 == null) ? null : nview3.GetZDO()?.m_uid);
				}
				ZDOID? val4 = obj;
				ZDOID valueOrDefault = val4.GetValueOrDefault();
				SyncAttachment(playerID, flag, valueOrDefault);
			}
		}

		[HarmonyPatch(typeof(Player), "LateUpdate")]
		[HarmonyPostfix]
		public static void ApplyShipCompensation(Player __instance)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)(object)Player.m_localPlayer))
			{
				long playerID = __instance.GetPlayerID();
				if (_playerStates.TryGetValue(playerID, out var value) && Object.op_Implicit((Object)(object)value.ship))
				{
					float num = 15f;
					Vector3 val = ((Component)value.ship).transform.TransformPoint(value.localPos);
					Quaternion val2 = ((Component)value.ship).transform.rotation * value.localRot;
					((Component)__instance).transform.position = Vector3.Lerp(((Component)__instance).transform.position, val, Time.deltaTime * num);
					((Component)__instance).transform.rotation = Quaternion.Slerp(((Component)__instance).transform.rotation, val2, Time.deltaTime * num);
				}
			}
		}
	}
	[HarmonyPatch]
	public static class ZDONetworkOptimizer
	{
		private class PeerCompressionStatus
		{
			public int Version { get; set; }

			public bool PeerEnabled { get; set; }

			public bool SendingCompressed { get; set; }

			public bool ReceivingCompressed { get; set; }

			public bool IsCompatible => Version == 1;
		}

		private static readonly Dictionary<ZDO, float> _distanceCache = new Dictionary<ZDO, float>();

		private static Vector3 _cachedRefPos;

		private static int _cachedFrame = -1;

		private const int MaxZDOsPerTick = 350;

		private const float MobNearDistance = 40f;

		private const float MobMediumDistance = 100f;

		private const float ImportantObjectDistance = 200f;

		private static readonly int PlayerPrefab = StringExtensionMethods.GetStableHashCode("Player");

		private static readonly HashSet<int> ShipPrefabs = new HashSet<int>
		{
			StringExtensionMethods.GetStableHashCode("Karve"),
			StringExtensionMethods.GetStableHashCode("VikingShip"),
			StringExtensionMethods.GetStableHashCode("Raft"),
			StringExtensionMethods.GetStableHashCode("VikingShip_Ashlands")
		};

		private static readonly HashSet<int> ImportantPrefabs = new HashSet<int>
		{
			StringExtensionMethods.GetStableHashCode("portal_wood"),
			StringExtensionMethods.GetStableHashCode("portal_stone"),
			StringExtensionMethods.GetStableHashCode("piece_workbench"),
			StringExtensionMethods.GetStableHashCode("piece_bed"),
			StringExtensionMethods.GetStableHashCode("piece_chest")
		};

		private static readonly int HashAI = StringExtensionMethods.GetStableHashCode("ai");

		private const int COMPRESSION_VERSION = 1;

		private const string RPC_VERSION = "VBNT.CompressionVersion";

		private const string RPC_ENABLED = "VBNT.CompressionEnabled";

		private const string RPC_STARTED = "VBNT.CompressionStarted";

		private static ICompressor _compressor;

		private static readonly Dictionary<ISocket, PeerCompressionStatus> _peerStatus = new Dictionary<ISocket, PeerCompressionStatus>();

		public static void Initialize()
		{
			if (!VBNetTweaks.EnableNetworkCompression.Value)
			{
				return;
			}
			try
			{
				string value = VBNetTweaks.CompressionAlgorithm.Value;
				if (value.Equals("Zstd", StringComparison.OrdinalIgnoreCase))
				{
					_compressor = new ZstdCompressor();
					VBNetTweaks.LogDebug("Using Zstd compressor");
				}
				else
				{
					_compressor = new DeflateCompressor();
					VBNetTweaks.LogDebug("Using Deflate compressor");
				}
			}
			catch (Exception ex)
			{
				VBNetTweaks.LogDebug("Compression init failed: " + ex.Message + ", using Deflate fallback");
				try
				{
					_compressor = new DeflateCompressor();
				}
				catch
				{
				}
			}
		}

		public static void OptimizedSendZDOToPeers(ZDOMan zdoManager, float dt)
		{
			try
			{
				int count = zdoManager.m_peers.Count;
				if (count <= 0)
				{
					return;
				}
				ZDOMan obj = zdoManager;
				obj.m_sendTimer += dt;
				float effectiveSendInterval = VBNetTweaks.GetEffectiveSendInterval();
				if (zdoManager.m_sendTimer < effectiveSendInterval)
				{
					return;
				}
				zdoManager.m_sendTimer = 0f;
				int num = Mathf.Max(zdoManager.m_nextSendPeer, 0);
				int peersPerUpdate = VBNetTweaks.GetPeersPerUpdate();
				int num2 = 0;
				for (int i = 0; i < Mathf.Min(peersPerUpdate, count); i++)
				{
					int index = (num + i) % count;
					ZDOPeer peer = zdoManager.m_peers[index];
					ZDOPeer obj2 = peer;
					if (obj2 == null)
					{
						continue;
					}
					ZNetPeer peer2 = obj2.m_peer;
					bool? obj3;
					if (peer2 == null)
					{
						obj3 = null;
					}
					else
					{
						ISocket socket = peer2.m_socket;
						obj3 = ((socket != null) ? new bool?(socket.IsConnected()) : null);
					}
					if (obj3 == true)
					{
						if (Helper.IsServer() && VBNetTweaks.EnableZDOThrottling.Value)
						{
							ApplyZDOThrottle(zdoManager, peer);
						}
						PerformanceMonitor.Track("SendZDOs", delegate
						{
							zdoManager.SendZDOs(peer, false);
						});
						num2++;
					}
				}
				zdoManager.m_nextSendPeer = (num + num2) % count;
			}
			catch (Exception ex)
			{
				VBNetTweaks.LogDebug("ERROR in OptimizedSendZDOToPeers: " + ex.Message);
				zdoManager.SendZDOToPeers2(dt);
			}
		}

		private static void ApplyZDOThrottle(ZDOMan zdoManager, ZDOPeer peer)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_00ca: 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)
			List<ZDO> list = null;
			List<ZDO> list2 = null;
			try
			{
				Vector3 refPos = peer.m_peer.GetRefPos();
				Vector2i zone = ZoneSystem.GetZone(refPos);
				list = ObjectPool.RentList<ZDO>();
				list2 = ObjectPool.RentList<ZDO>();
				int num = ZoneSystem.instance?.m_activeArea ?? 3;
				int num2 = ZoneSystem.instance?.m_activeDistantArea ?? 5;
				zdoManager.FindSectorObjects(zone, num, num2, list, list2);
				float value = VBNetTweaks.ZDOThrottleDistance.Value;
				foreach (ZDO item in list)
				{
					float num3 = Vector3.Distance(item.GetPosition(), refPos);
					item.m_tempSortValue = num3 - 150f;
				}
				foreach (ZDO item2 in list2)
				{
					float num4 = Vector3.Distance(item2.GetPosition(), refPos);
					item2.m_tempSortValue = num4 + 150f;
					if (num4 > value * 2f)
					{
						item2.m_tempSortValue += 300f;
					}
				}
			}
			finally
			{
				if (list != null)
				{
					ObjectPool.ReturnList(list);
				}
				if (list2 != null)
				{
					ObjectPool.ReturnList(list2);
				}
			}
		}

		private static float GetDistance(ZDO zdo, Vector3 refPos)
		{
			//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)
			if (_distanceCache.TryGetValue(zdo, out var value))
			{
				return value;
			}
			value = Vector3.Distance(zdo.GetPosition(), refPos);
			_distanceCache[zdo] = value;
			return value;
		}

		private static bool IsMob(ZDO zdo)
		{
			return zdo.GetInt(HashAI, -1) != -1;
		}

		private static void OptimizedRemoveObjects(ZNetScene scene, List<ZDO> near, List<ZDO> distant)
		{
			byte b = (byte)((uint)Time.frameCount & 0xFFu);
			foreach (ZDO item in near)
			{
				if (item != null)
				{
					item.TempRemoveEarmark = b;
				}
			}
			foreach (ZDO item2 in distant)
			{
				if (item2 != null)
				{
					item2.TempRemoveEarmark = b;
				}
			}
			Dictionary<ZDO, ZNetView> instances = scene.m_instances;
			List<ZNetView> tempRemoved = scene.m_tempRemoved;
			tempRemoved.Clear();
			List<ZDO> list = new List<ZDO>(instances.Keys);
			foreach (ZDO item3 in list)
			{
				if (item3 == null || !instances.TryGetValue(item3, out var value) || (Object)(object)value == (Object)null)
				{
					instances.Remove(item3);
				}
				else if (item3.TempRemoveEarmark != b)
				{
					tempRemoved.Add(value);
				}
			}
			foreach (ZNetView item4 in tempRemoved)
			{
				if (Object.op_Implicit((Object)(object)item4))
				{
					ZDO zdo = item4.m_zdo;
					if (zdo != null)
					{
						zdo.Created = false;
						item4.m_zdo = null;
					}
					Object.Destroy((Object)(object)((Component)item4).gameObject);
					instances.Remove(zdo);
				}
			}
		}

		private static void RegisterCompressionRPCs(ZNetPeer peer)
		{
			peer.m_rpc.Register<int>("VBNT.CompressionVersion", (Action<ZRpc, int>)delegate(ZRpc rpc, int version)
			{
				RPC_CompressionVersion(peer, version);
			});
			peer.m_rpc.Register<bool>("VBNT.CompressionEnabled", (Action<ZRpc, bool>)delegate(ZRpc rpc, bool enabled)
			{
				RPC_CompressionEnabled(peer, enabled);
			});
			peer.m_rpc.Register<bool>("VBNT.CompressionStarted", (Action<ZRpc, bool>)delegate(ZRpc rpc, bool started)
			{
				RPC_CompressionStarted(peer, started);
			});
		}

		private static void SendCompressionVersion(ZNetPeer peer)
		{
			peer.m_rpc.Invoke("VBNT.CompressionVersion", new object[1] { 1 });
		}

		private static void RPC_CompressionVersion(ZNetPeer peer, int version)
		{
			if (_peerStatus.TryGetValue(peer.m_socket, out var value))
			{
				value.Version = version;
				if (value.IsCompatible)
				{
					VBNetTweaks.LogDebug("Compression compatible with " + GetPeerName(peer));
					SendCompressionEnabledStatus(peer);
				}
			}
		}

		private static void SendCompressionEnabledStatus(ZNetPeer peer)
		{
			bool value = VBNetTweaks.EnableNetworkCompression.Value;
			peer.m_rpc.Invoke("VBNT.CompressionEnabled", new object[1] { value });
		}

		private static void RPC_CompressionEnabled(ZNetPeer peer, bool enabled)
		{
			if (_peerStatus.TryGetValue(peer.m_socket, out var value))
			{
				value.PeerEnabled = enabled;
				bool started = VBNetTweaks.EnableNetworkCompression.Value && enabled && value.IsCompatible;
				SendCompressionStarted(peer, started);
			}
		}

		private static void SendCompressionStarted(ZNetPeer peer, bool started)
		{
			if (_peerStatus.TryGetValue(peer.m_socket, out var value) && value.SendingCompressed != started)
			{
				peer.m_rpc.Invoke("VBNT.CompressionStarted", new object[1] { started });
				peer.m_socket.Flush();
				value.SendingCompressed = started;
				VBNetTweaks.LogDebug("Compression " + (started ? "started" : "stopped") + " with " + GetPeerName(peer));
			}
		}

		private static void RPC_CompressionStarted(ZNetPeer peer, bool started)
		{
			if (_peerStatus.TryGetValue(peer.m_socket, out var value))
			{
				value.ReceivingCompressed = started;
				VBNetTweaks.LogDebug("Receiving " + (started ? "compressed" : "uncompressed") + " from " + GetPeerName(peer));
			}
		}

		public static bool ShouldCompressSend(ISocket socket)
		{
			PeerCompressionStatus value;
			return _peerStatus.TryGetValue(socket, out value) && value.SendingCompressed && _compressor != null;
		}

		public static bool ShouldCompressReceive(ISocket socket)
		{
			PeerCompressionStatus value;
			return _peerStatus.TryGetValue(socket, out value) && value.ReceivingCompressed && _compressor != null;
		}

		public static byte[] Compress(byte[] data)
		{
			return _compressor?.Compress(data) ?? data;
		}

		public static byte[] Decompress(byte[] data)
		{
			return _compressor?.Decompress(data) ?? data;
		}

		private static string GetPeerName(ZNetPeer peer)
		{
			try
			{
				ISocket socket = peer.m_socket;
				return ((socket != null) ? socket.GetEndPointString() : null) ?? peer.m_uid.ToString();
			}
			catch
			{
				return peer.m_uid.ToString();
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(ZDOMan), "Update")]
		private static IEnumerable<CodeInstruction> ZDOManUpdateTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0003: 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_003e: Expected O, but got Unknown
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).Start();
			val.MatchStartForward((CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(ZDOMan), "SendZDOToPeers2", (Type[])null, (Type[])null), (string)null)
			});
			if (val.IsInvalid)
			{
				VBNetTweaks.LogDebug("WARNING: SendZDOToPeers2 not found");
				return instructions;
			}
			val.SetOperandAndAdvance((object)AccessTools.Method(typeof(ZDONetworkOptimizer), "OptimizedSendZDOToPeers", (Type[])null, (Type[])null));
			return val.InstructionEnumeration();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ZDOMan), "ServerSortSendZDOS")]
		public static void ApplyWeights(List<ZDO> objects, Vector3 refPos)
		{
			//IL_0034: 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)
			//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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			if (!Helper.IsServer() || !VBNetTweaks.EnablePlayerPositionBoost.Value)
			{
				return;
			}
			if (_cachedFrame != Time.frameCount || _cachedRefPos != refPos)
			{
				_distanceCache.Clear();
				_cachedRefPos = refPos;
				_cachedFrame = Time.frameCount;
			}
			foreach (ZDO @object in objects)
			{
				if (@object == null)
				{
					continue;
				}
				int prefab = @object.GetPrefab();
				if (prefab == PlayerPrefab)
				{
					@object.m_tempSortValue -= 500f;
					continue;
				}
				if (ShipPrefabs.Contains(prefab))
				{
					bool flag = ShipSyncSystem.ShipHasPlayers(@object.m_uid);
					@object.m_tempSortValue += (flag ? (-450f) : (-200f));
					continue;
				}
				float distance = GetDistance(@object, refPos);
				if (IsMob(@object))
				{
					if (distance < 40f)
					{
						@object.m_tempSortValue -= 300f;
					}
					else if (distance < 100f)
					{
						@object.m_tempSortValue -= 150f;
					}
					else
					{
						@object.m_tempSortValue += distance;
					}
				}
				else if (ImportantPrefabs.Contains(prefab) && distance < 200f)
				{
					@object.m_tempSortValue -= 150f;
				}
				else
				{
					@object.m_tempSortValue += distance;
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ZDOMan), "ServerSortSendZDOS")]
		public static void LimitZDOs(List<ZDO> objects)
		{
			if (Helper.IsServer() && objects.Count > 350)
			{
				objects.Sort((ZDO a, ZDO b) => a.m_tempSortValue.CompareTo(b.m_tempSortValue));
				int num = objects.Count - 350;
				objects.RemoveRange(350, num);
				if (VBNetTweaks.DebugEnabled.Value)
				{
					VBNetTweaks.LogVerbose($"ZDO limiter: removed {num} objects");
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ZNetScene), "RemoveObjects")]
		private static bool RemoveObjectsPrefix(ZNetScene __instance, List<ZDO> currentNearObjects, List<ZDO> currentDistantObjects)
		{
			try
			{
				PerformanceMonitor.Track("RemoveObjects", delegate
				{
					OptimizedRemoveObjects(__instance, currentNearObjects, currentDistantObjects);
				});
				return false;
			}
			catch
			{
				return true;
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		[HarmonyPostfix]
		private static void OnNewConnection(ZNetPeer peer)
		{
			if (_compressor != null)
			{
				_peerStatus[peer.m_socket] = new PeerCompressionStatus();
				RegisterCompressionRPCs(peer);
				SendCompressionVersion(peer);
			}
		}

		[HarmonyPatch(typeof(ZNet), "Disconnect")]
		[HarmonyPostfix]
		private static void OnDisconnect(ZNetPeer peer)
		{
			_peerStatus.Remove(peer.m_socket);
		}
	}
	[HarmonyPatch]
	public static class AILODPatches
	{
		private static bool ShouldUpdateAI(Character c)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			List<Player> cached = PlayerCache.GetCached();
			float num = float.MaxValue;
			for (int i = 0; i < cached.Count; i++)
			{
				Player val = cached[i];
				if (Object.op_Implicit((Object)(object)val))
				{
					float num2 = Vector3.Distance(((Component)c).transform.position, ((Component)val).transform.position);
					if (num2 < num)
					{
						num = num2;
					}
				}
			}
			if (num <= VBNetTweaks.AILODNearDistance.Value)
			{
				return true;
			}
			if (num > VBNetTweaks.AILODFarDistance.Value)
			{
				float num3 = Mathf.Clamp(VBNetTweaks.AILODThrottleFactor.Value, 0.25f, 0.75f);
				if (Time.time % (1f / num3) > Time.fixedDeltaTime)
				{
					return false;
				}
			}
			return true;
		}

		[HarmonyPrefix]
		public static bool FixedUpdate_Prefix(Character __instance)
		{
			if (Helper.IsServer())
			{
				ConfigEntry<bool> enableAILOD = VBNetTweaks.EnableAILOD;
				if (enableAILOD != null && enableAILOD.Value)
				{
					if (!__instance.IsPlayer())
					{
						Tameable component = ((Component)__instance).GetComponent<Tameable>();
						if (component == null || !component.IsTamed())
						{
							bool result = true;
							PerformanceMonitor.Track("AI.FixedUpdate", delegate
							{
								result = ShouldUpdateAI(__instance);
							});
							return result;
						}
					}
					return true;
				}
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class MonsterAiPatches
	{
		[HarmonyPatch(typeof(RandEventSystem), "FixedUpdate")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> RandEventSystem_FixedUpdate_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null);
			val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[2]
			{
				new CodeMatch((OpCode?)OpCodes.Ldsfld, (object)AccessTools.Field(typeof(Player), "m_localPlayer"), (string)null),
				new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(Object), "op_Implicit", (Type[])null, (Type[])null), (string)null)
			});
			if (val.IsInvalid)
			{
				return instructions;
			}
			val.RemoveInstructions(2);
			val.Insert((CodeInstruction[])(object)new CodeInstruction[2]
			{
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Player), "GetAllPlayers", (Type[])null, (Type[])null)),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(MonsterAiPatches), "HasAnyPlayerNearby", (Type[])null, (Type[])null))
			});
			return val.InstructionEnumeration();
		}

		[HarmonyPatch(typeof(SpawnSystem), "UpdateSpawning")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> SpawnSystem_UpdateSpawning_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null);
			val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[4]
			{
				new CodeMatch((OpCode?)OpCodes.Ldsfld, (object)AccessTools.Field(typeof(Player), "m_localPlayer"), (string)null),
				new CodeMatch((OpCode?)OpCodes.Ldnull, (object)null, (string)null),
				new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Object), "op_Equality", (Type[])null, (Type[])null), (string)null),
				new CodeMatch((OpCode?)OpCodes.Brfalse, (object)null, (string)null)
			});
			if (val.IsInvalid)
			{
				return instructions;
			}
			val.RemoveInstructions(3);
			val.SetInstructionAndAdvance(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Player), "GetAllPlayers", (Type[])null, (Type[])null)));
			val.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(MonsterAiPatches), "HasAnyPlayerNearby", (Type[])null, (Type[])null))
			});
			val.SetOpcodeAndAdvance(OpCodes.Brfalse);
			return val.InstructionEnumeration();
		}

		private static bool HasAnyPlayerNearby(List<Player> all)
		{
			//IL_0051: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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)
			if (all == null || all.Count == 0)
			{
				return false;
			}
			int num = ZoneSystem.instance?.m_activeArea ?? 3;
			for (int i = 0; i < all.Count; i++)
			{
				Player val = all[i];
				if (Object.op_Implicit((Object)(object)val))
				{
					Vector2i zone = ZoneSystem.GetZone(((Component)val).transform.position);
					if (!ZNetScene.OutsideActiveArea(((Component)val).transform.position, zone, num))
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	[HarmonyPatch]
	public static class SteamOptimizations
	{
		[HarmonyTranspiler]
		[HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")]
		private static IEnumerable<CodeInstruction> ZSteamSocket_RegisterGlobalCallbacks_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0016: 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)
			//IL_003f: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			if (!Helper.IsServer())
			{
				return instructions;
			}
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Ldc_I4, (object)153600, (string)null)
			});
			if (val.IsInvalid)
			{
				VBNetTweaks.LogDebug("WARNING: Steam transfer rate limit not found");
				return instructions;
			}
			int num = 50000000;
			val.SetInstructionAndAdvance(new CodeInstruction(OpCodes.Ldc_I4, (object)num));
			if (VBNetTweaks.DebugEnabled.Value)
			{
				VBNetTweaks.LogVerbose("Steam transfer rate patched in transpiler");
			}
			VBNetTweaks.LogVerbose($"Steam transfer rate patched: 153600 -> {num}");
			return val.InstructionEnumeration();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")]
		private static void ZSteamSocket_RegisterGlobalCallbacks_Postfix(ZSteamSocket __instance)
		{
			try
			{
				ConfigEntry<bool> enableSteamSendRate = VBNetTweaks.EnableSteamSendRate;
				if (enableSteamSendRate == null || !enableSteamSendRate.Value)
				{
					return;
				}
				Assembly assembly = typeof(ZSteamSocket).Assembly;
				Type type = assembly.GetType("Steamworks.SteamNetworkingUtils");
				if (type == null)
				{
					VBNetTweaks.LogDebug("SteamNetworkingUtils type not found");
					return;
				}
				MethodInfo setCfg = type.GetMethod("SetConfigValue", new Type[5]
				{
					typeof(ESteamNetworkingConfigValue),
					typeof(ESteamNetworkingConfigScope),
					typeof(IntPtr),
					typeof(ESteamNetworkingConfigDataType),
					typeof(IntPtr)
				});
				if (setCfg == null)
				{
					VBNetTweaks.LogDebug("SetConfigValue method not found");
					return;
				}
				int num = Math.Max(64, VBNetTweaks.SteamSendRateMinKB.Value) * 1024;
				int num2 = Math.Max(num, VBNetTweaks.SteamSendRateMaxKB.Value) * 1024;
				int num3 = Math.Max(8388608, VBNetTweaks.SteamSendBufferSize.Value);
				SetInt((ESteamNetworkingConfigValue)10, num);
				SetInt((ESteamNetworkingConfigValue)11, num2);
				SetInt((ESteamNetworkingConfigValue)9, num3);
				VBNetTweaks.LogVerbose($"Steam send rates applied: min={num / 1024}KB/s max={num2 / 1024}KB/s buffer={num3}");
				void SetInt(ESteamNetworkingConfigValue key, int value)
				{
					//IL_001e: Unknown result type (might be due to invalid IL or missing references)
					GCHandle gCHandle = GCHandle.Alloc(value, GCHandleType.Pinned);
					try
					{
						setCfg.Invoke(null, new object[5]
						{
							key,
							(object)(ESteamNetworkingConfigScope)1,
							IntPtr.Zero,
							(object)(ESteamNetworkingConfigDataType)1,
							gCHandle.AddrOfPinnedObject()
						});
					}
					finally
					{
						gCHandle.Free();
					}
				}
			}
			catch (Exception ex)
			{
				VBNetTweaks.LogDebug("Error applying Steam send rates: " + ex.Message);
			}
		}
	}
	public enum CompressionAlgorithm
	{
		Deflate,
		Zstd
	}
	[BepInPlugin("VitByr.VBNetTweaks", "VBNetTweaks", "0.1.5")]
	public class VBNetTweaks : BaseUnityPlugin
	{
		private const string ModName = "VBNetTweaks";

		private const string ModVersion = "0.1.5";

		private const string ModGUID = "VitByr.VBNetTweaks";

		public static ConfigEntry<bool> EnableAILOD;

		public static ConfigEntry<float> AILODNearDistance;

		public static ConfigEntry<float> AILODFarDistance;

		public static ConfigEntry<float> AILODThrottleFactor;

		public static ConfigEntry<bool> EnableZDOThrottling;

		public static ConfigEntry<float> ZDOThrottleDistance;

		public static ConfigEntry<bool> EnablePlayerPositionBoost;

		public static ConfigEntry<float> PlayerPositionUpdateMultiplier;

		public static ConfigEntry<bool> EnableClientInterpolation;

		public static ConfigEntry<bool> EnablePlayerPrediction;

		public static ConfigEntry<bool> EnableMonsterAiPatches;

		public static ConfigEntry<bool> EnableSteamSendRate;

		public static ConfigEntry<int> SteamSendRateMinKB;

		public static ConfigEntry<int> SteamSendRateMaxKB;

		public static ConfigEntry<int> SteamSendBufferSize;

		public static ConfigEntry<bool> EnableNetworkCompression;

		public static ConfigEntry<string> CompressionAlgorithm;

		public static ConfigEntry<bool> DebugEnabled;

		public static ConfigEntry<bool> VerboseLogging;

		public static ConfigEntry<float> SendInterval;

		public static ConfigEntry<int> PeersPerUpdate;

		public static ConfigEntry<bool> SceneDebugEnabled;

		public static ConfigEntry<bool> EnableNetSync;

		public static double NetTime;

		public static float DeltaTimeFixedPhysics = 0.02f;

		public static float DeltaTimePhysics = 0.01f;

		private Harmony _harmony;

		private static bool _serverConfigsInitialized;

		private void Awake()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			DebugEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - General", "DebugEnabled", false, new ConfigDescription("Включить отладочный вывод", (AcceptableValueBase)null, Array.Empty<object>()));
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - General", "VerboseLogging", false, new ConfigDescription("Включить подробное логирование успешных операций", (AcceptableValueBase)null, Array.Empty<object>()));
			EnableNetworkCompression = ((BaseUnityPlugin)this).Config.Bind<bool>("Network", "EnableCompression", true, "Enable network compression (safe, negotiated between peers)");
			CompressionAlgorithm = ((BaseUnityPlugin)this).Config.Bind<string>("Network", "CompressionAlgorithm", "Deflate", "Deflate (built-in) or Zstd (requires ZstdSharp)");
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<ZPackage>("VBNT_RPCBatch", (Action<long, ZPackage>)RpcBatcher.HandleBatch);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"VBNetTweaks: VBNT_RPCBatch registered");
			}
			if (EnableNetworkCompression.Value)
			{
				ZDONetworkOptimizer.Initialize();
			}
			_harmony = new Harmony("VitByr.VBNetTweaks");
			_harmony.PatchAll(typeof(ZDONetworkOptimizer));
			_harmony.PatchAll(typeof(SteamOptimizations));
			_harmony.PatchAll(typeof(ShipSyncSystem));
			_harmony.PatchAll(typeof(PlayerSyncSystem));
			_harmony.PatchAll(typeof(ObjectPool));
			_harmony.PatchAll(typeof(PlayerCache));
			((MonoBehaviour)this).StartCoroutine(DelayedServerPatchInit());
			((MonoBehaviour)this).StartCoroutine(DelayedServerConfigInit());
			((BaseUnityPlugin)this).Logger.LogInfo((object)"VBNetTweaks загружен!");
			if (DebugEnabled.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Режим отладки включен");
			}
		}

		private IEnumerator DelayedServerPatchInit()
		{
			float timeout = 30f;
			float elapsed = 0f;
			while (!Object.op_Implicit((Object)(object)ZNet.instance) && elapsed < timeout)
			{
				elapsed += Time.deltaTime;
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"ZNet.instance не появился за 30 секунд — серверные патчи не применены.");
			}
			else if (Helper.IsServer())
			{
				if (EnableAILOD?.Value ?? false)
				{
					_harmony.PatchAll(typeof(AILODPatches));
				}
				if (EnableMonsterAiPatches?.Value ?? false)
				{
					_harmony.PatchAll(typeof(MonsterAiPatches));
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"VBNetTweaks: серверные патчи успешно применены.");
			}
		}

		private IEnumerator DelayedServerConfigInit()
		{
			int maxAttempts = 100;
			for (int i = 0; i < maxAttempts; i++)
			{
				if (Object.op_Implicit((Object)(object)ZNet.instance))
				{
					break;
				}
				yield return (object)new WaitForSeconds(0.25f);
			}
			if (EnableNetworkCompression.Value)
			{
				ZDONetworkOptimizer.Initialize();
			}
			if (Helper.IsServer())
			{
				EnableNetSync = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "02 - Network", "EnableNetSync", true, "Включить новую систему синхронизации NetSync", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				SendInterval = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "02 - Network", "SendInterval", 0.05f, "Интервал отправки данных (секунды) - ТОЛЬКО СЕРВЕР", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				PeersPerUpdate = ConfigFileExtensions.BindConfig<int>(((BaseUnityPlugin)this).Config, "02 - Network", "PeersPerUpdate", 20, "Количество пиров для обработки за один апдейт - ТОЛЬКО СЕРВЕР", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				EnableZDOThrottling = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "02 - Network", "EnableZDOThrottling", true, "Снижать частоту обновления для дальних ZDO (только для сервера).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				ZDOThrottleDistance = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "02 - Network", "ZDOThrottleDistance", 500f, "Дистанция (в метрах), за пределами которой ZDO обновляются реже.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				EnableSteamSendRate = ((BaseUnityPlugin)this).Config.Bind<bool>("02 - Network", "EnableSteamSendRateOverride", true, "Применять настройки скорости отправки Steam при запуске.");
				SteamSendRateMinKB = ((BaseUnityPlugin)this).Config.Bind<int>("02 - Network", "SteamSendRateMinKB", 256, "Минимальная скорость отправки (КБ/с).");
				SteamSendRateMaxKB = ((BaseUnityPlugin)this).Config.Bind<int>("02 - Network", "SteamSendRateMaxKB", 1024, "Максимальная скорость отправки (КБ/с).");
				SteamSendBufferSize = ((BaseUnityPlugin)this).Config.Bind<int>("02 - Network", "SteamSendBufferBytes", 100000000, "Размер буфера отправки Steam (в байтах).");
				SceneDebugEnabled = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "03 - Scene Optimizations", "SceneDebugEnabled", false, "Включить отладочный вывод для сцены", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				EnableAILOD = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "04 - AI", "EnableAILOD", true, "Уменьшать частоту обновления AI для дальних существ (только для сервера).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				AILODNearDistance = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "04 - AI", "AILODNearDistance", 100f, "Дистанция (в метрах), в пределах которой AI работает на полной скорости.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				AILODFarDistance = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "04 - AI", "AILODFarDistance", 300f, "Дистанция (в метрах), за пределами которой AI замедляется.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				AILODThrottleFactor = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "04 - AI", "AILODThrottleFactor", 0.5f, "Коэффициент замедления для дальнего AI (0.5 = половинная скорость).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				EnablePlayerPositionBoost = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "05 - Player Sync", "EnableHighFrequencyPositionUpdates", true, "Повысить приоритет обновления позиций игроков на сервере.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				PlayerPositionUpdateMultiplier = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "05 - Player Sync", "PositionUpdateMultiplier", 2.5f, "Множитель приоритета синхронизации игроков (1.0 = стандарт, 2.5 = рекомендовано).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
				EnableClientInterpolation = ((BaseUnityPlugin)this).Config.Bind<bool>("05 - Player Sync", "EnableClientInterpolation", true, "Сглаживать движения других игроков на клиенте (убирает рывки).");
				EnablePlayerPrediction = ((BaseUnityPlugin)this).Config.Bind<bool>("05 - Player Sync", "EnableClientPrediction", true, "Прогнозировать движения других игроков между сетевыми обновлениями (плавность в бою).");
				EnableMonsterAiPatches = ((BaseUnityPlugin)this).Config.Bind<bool>("06 - Gameplay", "EnableMonsterAiPatches", true, "Использовать всех игроков вместо локального для событий и спавна монстров.");
				_serverConfigsInitialized = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Серверные настройки VBNetTweaks инициализированы");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"VBNetTweaks работает в клиентском режиме");
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		public static void LogDebug(string message)
		{
			if (DebugEnabled.Value)
			{
				Debug.Log((object)("[VBNetTweaks] " + message));
			}
		}

		public static void LogVerbose(string message)
		{
			if (DebugEnabled.Value && VerboseLogging.Value)
			{
				Debug.Log((object)("[VBNetTweaks] " + message));
			}
		}

		public static bool GetSceneDebugEnabled()
		{
			try
			{
				return SceneDebugEnabled?.Value ?? false;
			}
			catch
			{
				return false;
			}
		}

		public static float GetEffectiveSendInterval()
		{
			float fallback = ((!_serverConfigsInitialized) ? 0.05f : (SendInterval?.Value ?? 0.05f));
			return AdaptiveThrottler.GetInterval(fallback);
		}

		public static int GetPeersPerUpdate()
		{
			return (!_serverConfigsInitialized) ? 20 : (PeersPerUpdate?.Value ?? 20);
		}
	}
}
namespace VBNetTweaks.Utils
{
	[HarmonyPatch]
	public static class ObjectPool
	{
		private static class Pool<T>
		{
			public static readonly Stack<T> Stack = new Stack<T>();

			public static int MaxSize = 256;
		}

		private static readonly Stack<ZPackage> _pkgPool = new Stack<ZPackage>();

		private const int MaxPkgPoolSize = 128;

		public static List<T> RentList<T>()
		{
			if (Pool<List<T>>.Stack.Count > 0)
			{
				List<T> list = Pool<List<T>>.Stack.Pop();
				list.Clear();
				return list;
			}
			LogAlloc("List<" + typeof(T).Name + ">");
			return new List<T>();
		}

		public static void ReturnList<T>(List<T> list)
		{
			if (list != null)
			{
				list.Clear();
				if (Pool<List<T>>.Stack.Count < Pool<List<T>>.MaxSize)
				{
					Pool<List<T>>.Stack.Push(list);
				}
			}
		}

		public static ZPackage RentPackage()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			if (_pkgPool.Count > 0)
			{
				ZPackage val = _pkgPool.Pop();
				val.Clear();
				LogReuse("ZPackage");
				return val;
			}
			LogAlloc("ZPackage");
			return new ZPackage();
		}

		public static void ReturnPackage(ZPackage pkg)
		{
			if (pkg != null)
			{
				pkg.Clear();
				if (_pkgPool.Count < 128)
				{
					_pkgPool.Push(pkg);
				}
			}
		}

		[Conditional("DEBUG")]
		private static void LogAlloc(string type)
		{
			if (VBNetTweaks.DebugEnabled.Value && VBNetTweaks.VerboseLogging.Value)
			{
				VBNetTweaks.LogVerbose("ObjectPool: allocated new " + type);
			}
		}

		[Conditional("DEBUG")]
		private static void LogReuse(string type)
		{
			if (VBNetTweaks.DebugEnabled.Value && VBNetTweaks.VerboseLogging.Value)
			{
				VBNetTweaks.LogVerbose("ObjectPool: reused " + type);
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[HarmonyPostfix]
		public static void OnSceneAwake()
		{
			_pkgPool.Clear();
			Pool<List<ZDO>>.Stack.Clear();
			Pool<List<Player>>.Stack.Clear();
			VBNetTweaks.LogVerbose("ObjectPool cleared on scene load");
		}
	}
	public static class PerformanceMonitor
	{
		private struct Sample
		{
			public string Name;

			public float TotalTime;

			public int Count;

			public float LastLogTime;
		}

		private static Dictionary<string, Sample> _samples = new Dictionary<string, Sample>();

		private const float LOG_INTERVAL = 5f;

		public static void Track(string name, Action action)
		{
			if (!VBNetTweaks.DebugEnabled.Value)
			{
				action();
				return;
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			action();
			stopwatch.Stop();
			if (!_samples.TryGetValue(name, out var value))
			{
				Sample sample = default(Sample);
				sample.Name = name;
				value = sample;
			}
			value.TotalTime += stopwatch.ElapsedMilliseconds;
			value.Count++;
			float time = Time.time;
			if (time - value.LastLogTime > 5f)
			{
				float num = value.TotalTime / (float)value.Count;
				VBNetTweaks.LogDebug($"{name}: avg={num:F2}ms over {value.Count} samples");
				value.TotalTime = 0f;
				value.Count = 0;
				value.LastLogTime = time;
			}
			_samples[name] = value;
		}
	}
	public static class RpcSerializer
	{
		private const byte Type_None = 0;

		private const byte Type_Int = 1;

		private const byte Type_Float = 2;

		private const byte Type_String = 3;

		private const byte Type_Bool = 4;

		private const byte Type_Vector3 = 5;

		private const byte Type_Quat = 6;

		private const byte Type_Long = 7;

		public static void WriteArg(ZPackage pkg, object arg)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			if (arg is int)
			{
				pkg.Write((byte)1);
				pkg.Write((int)arg);
				return;
			}
			if (arg is float)
			{
				pkg.Write((byte)2);
				pkg.Write((float)arg);
				return;
			}
			if (arg is string)
			{
				pkg.Write((byte)3);
				pkg.Write((string)arg);
				return;
			}
			if (arg is bool)
			{
				pkg.Write((byte)4);
				pkg.Write((bool)arg);
				return;
			}
			if (arg is Vector3)
			{
				pkg.Write((byte)5);
				pkg.Write((Vector3)arg);
				return;
			}
			if (arg is Quaternion)
			{
				pkg.Write((byte)6);
				pkg.Write((Quaternion)arg);
				return;
			}
			if (arg is long)
			{
				pkg.Write((byte)7);
				pkg.Write((long)arg);
				return;
			}
			pkg.Write((byte)0);
			if (VBNetTweaks.DebugEnabled.Value)
			{
				VBNetTweaks.LogDebug("RpcSerializer: unsupported arg type " + arg.GetType());
			}
		}

		public static object ReadArg(ZPackage pkg)
		{
			//IL_0068: 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)
			return pkg.ReadByte() switch
			{
				1 => pkg.ReadInt(), 
				2 => pkg.ReadSingle(), 
				3 => pkg.ReadString(), 
				4 => pkg.ReadBool(), 
				5 => pkg.ReadVector3(), 
				6 => pkg.ReadQuaternion(), 
				7 => pkg.ReadLong(), 
				_ => null, 
			};
		}
	}
	[HarmonyPatch]
	[HarmonyPatch(typeof(ZNet), "Update")]
	public static class ZNetOptimizations
	{
		private static float _lastThrottlerUpdate;

		private const float THROTTLER_INTERVAL = 0.5f;

		[HarmonyPostfix]
		public static void Postfix(ZNet __instance)
		{
			if (Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)ZNet.instance))
			{
				RpcBatcher.Update();
				float time = Time.time;
				if (time - _lastThrottlerUpdate >= 0.5f)
				{
					AdaptiveThrottler.Update(__instance, Time.deltaTime);
					_lastThrottlerUpdate = time;
				}
				PerformanceMonitor.Track("ZNet.Update", delegate
				{
				});
			}
		}
	}
	public static class Helper
	{
		private static int _lastFrame = -1;

		private static bool _cachedIsServer;

		private static bool _cachedIsClient;

		public static bool IsServer()
		{
			if (_lastFrame == Time.frameCount)
			{
				return _cachedIsServer;
			}
			try
			{
				ZNet instance = ZNet.instance;
				_cachedIsServer = Object.op_Implicit((Object)(object)instance) && instance.IsServer();
				_cachedIsClient = Object.op_Implicit((Object)(object)instance) && !instance.IsServer();
				_lastFrame = Time.frameCount;
				return _cachedIsServer;
			}
			catch
			{
				return false;
			}
		}

		public static bool IsClient()
		{
			if (_lastFrame == Time.frameCount)
			{
				return _cachedIsClient;
			}
			IsServer();
			return _cachedIsClient;
		}
	}
}