Decompiled source of FiresGhettoNetworking v1.3.0

VAGhettoNetworking.dll

Decompiled 20 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FiresGhettoNetworkMod.AutoTune;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("VAGhettoNetworking")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VAGhettoNetworking")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f234bd11-429c-45e2-b280-1fb9121d050d")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.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 FiresGhettoNetworkMod
{
	[BepInPlugin("com.Fire.FiresGhettoNetworkMod", "FiresGhettoNetworkMod", "1.3.0")]
	public class FiresGhettoNetworkMod : BaseUnityPlugin
	{
		[HarmonyPatch]
		public static class WackyDatabaseCompatibilityPatch
		{
			public static void Init(Harmony harmony)
			{
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Expected O, but got Unknown
				Type type = Type.GetType("wackydatabase.Util.Functions, WackysDatabase");
				if (type == null)
				{
					LoggerOptions.LogInfo("WackyDatabase not detected — skipping compatibility patch.");
					return;
				}
				MethodInfo method = type.GetMethod("SnapshotItem", BindingFlags.Static | BindingFlags.Public);
				if (method == null)
				{
					LoggerOptions.LogWarning("WackyDatabase detected but SnapshotItem method not found — patch skipped.");
					return;
				}
				harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(WackyDatabaseCompatibilityPatch), "SnapshotItem_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				LoggerOptions.LogInfo("WackyDatabase compatibility patch applied — will skip snapshots for invalid/broken clones.");
			}

			[HarmonyPrefix]
			public static bool SnapshotItem_Prefix(ref ItemDrop item)
			{
				if ((Object)(object)item == (Object)null)
				{
					LoggerOptions.LogWarning("WDB: Skipping snapshot for null ItemDrop (likely broken clone).");
					return false;
				}
				if ((Object)(object)((Component)item).gameObject == (Object)null)
				{
					LoggerOptions.LogWarning("WDB: Skipping snapshot for " + ((Object)item).name + " — gameObject is null (missing prefab from removed mod).");
					return false;
				}
				bool flag = ((Component)item).GetComponentsInChildren<Renderer>(true).Length != 0;
				bool flag2 = ((Component)item).GetComponentsInChildren<MeshFilter>(true).Length != 0;
				if (!flag && !flag2)
				{
					LoggerOptions.LogWarning("WDB: Skipping snapshot for " + ((Object)item).name + " — no renderers or meshes (broken model).");
					return false;
				}
				return true;
			}
		}

		[CompilerGenerated]
		private sealed class <RegisterDummyRpcWhenReady>d__56 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public FiresGhettoNetworkMod <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RegisterDummyRpcWhenReady>d__56(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (ZRoutedRpc.instance == null)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				if (_dummyRpcRegistered)
				{
					((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Dummy ForceUpdateZDO RPC already registered — skipping.");
					return false;
				}
				ZRoutedRpc.instance.Register("ForceUpdateZDO", (Action<long>)delegate
				{
				});
				_dummyRpcRegistered = true;
				((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Dummy ForceUpdateZDO RPC registered.");
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string PluginGUID = "com.Fire.FiresGhettoNetworkMod";

		public const string PluginName = "FiresGhettoNetworkMod";

		public const string PluginVersion = "1.3.0";

		public static ConfigEntry<LogLevel> ConfigLogLevel;

		public static ConfigEntry<bool> ConfigEnableCompression;

		public static ConfigEntry<UpdateRateOptions> ConfigUpdateRate;

		public static ConfigEntry<SendRateMinOptions> ConfigSendRateMin;

		public static ConfigEntry<SendRateMaxOptions> ConfigSendRateMax;

		public static ConfigEntry<QueueSizeOptions> ConfigQueueSize;

		public static ConfigEntry<ForceCrossplayOptions> ConfigForceCrossplay;

		public static ConfigEntry<int> ConfigPlayerLimit;

		public static ConfigEntry<int> ConfigAdvertisedPlayerLimit;

		public static ConfigEntry<bool> ConfigEnableShipFixes;

		public static ConfigEntry<bool> ConfigEnableServerSideShipSimulation;

		public static ConfigEntry<int> ConfigExtendedZoneRadius;

		public static ConfigEntry<bool> ConfigEnableZDOThrottling;

		public static ConfigEntry<float> ConfigZDOThrottleDistance;

		public static ConfigEntry<bool> ConfigEnableAILOD;

		public static ConfigEntry<float> ConfigAILODNearDistance;

		public static ConfigEntry<float> ConfigAILODFarDistance;

		public static ConfigEntry<float> ConfigAILODThrottleFactor;

		public static ConfigEntry<int> ConfigZoneLoadBatchSize;

		public static ConfigEntry<int> ConfigZPackageReceiveBufferSize;

		public static ConfigEntry<bool> ConfigEnableTimeSliceInstantiation;

		public static ConfigEntry<int> ConfigInstantiationBudgetMs;

		public static ConfigEntry<int> ConfigMaxInstancesPerFrame;

		public static ConfigEntry<bool> ConfigSafetyFallbackEnabled;

		public static ConfigEntry<int> ConfigSafetyFallbackThreshold;

		public static ConfigEntry<bool> ConfigEnablePredictiveZoneStreaming;

		public static ConfigEntry<float> ConfigPredictionLookaheadSec;

		public static ConfigEntry<float> ConfigPredictionMinVelocity;

		public static ConfigEntry<int> ConfigPredictionMaxLookaheadZones;

		public static ConfigEntry<bool> ConfigEnableInvulnerableSupportSkip;

		public static ConfigEntry<bool> ConfigEnableRpcRouter;

		public static ConfigEntry<bool> ConfigEnableRpcAoI;

		public static ConfigEntry<float> ConfigRpcAoIRadius;

		public static ConfigEntry<bool> ConfigEnableZDODelta;

		public static ConfigEntry<bool> ConfigEnableWNTServerOptimization;

		public static ConfigEntry<bool> ConfigEnableServerAuthority;

		private static bool _dummyRpcRegistered;

		private bool _delayedInitDone = false;

		internal static Harmony Harmony { get; private set; }

		public static FiresGhettoNetworkMod Instance { get; private set; }

		private void Awake()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Instance = this;
			Harmony = new Harmony("com.Fire.FiresGhettoNetworkMod");
			BindConfigs();
			try
			{
				((BaseUnityPlugin)this).Config.Save();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to save config file immediately: " + ex.Message));
			}
			LoggerOptions.Init(((BaseUnityPlugin)this).Logger);
			ServerClientUtils.Detect(((BaseUnityPlugin)this).Logger);
			bool isDedicatedServerDetected = ServerClientUtils.IsDedicatedServerDetected;
			if (isDedicatedServerDetected)
			{
				LoggerOptions.LogMessage("FiresGhettoNetworkMod v1.3.0 — Running on DEDICATED SERVER, enabling server-side features.");
			}
			else
			{
				LoggerOptions.LogMessage("FiresGhettoNetworkMod v1.3.0 — Running on CLIENT or SINGLE-PLAYER/LISTEN SERVER, only client-safe features will be applied.");
			}
			SafeInvokeInit("FiresGhettoNetworkMod.CompressionGroup", "InitConfig", new object[1] { ((BaseUnityPlugin)this).Config });
			SafeInvokeInit("FiresGhettoNetworkMod.NetworkingRatesGroup", "Init", new object[1] { ((BaseUnityPlugin)this).Config });
			SafeInvokeInit("FiresGhettoNetworkMod.DedicatedServerGroup", "Init", new object[1] { ((BaseUnityPlugin)this).Config });
			Harmony.PatchAll(typeof(CompressionGroup));
			Harmony.PatchAll(typeof(NetworkingRatesGroup));
			Harmony.PatchAll(typeof(DedicatedServerGroup));
			Harmony.PatchAll(typeof(BigZdoDiagnostic));
			WackyDatabaseCompatibilityPatch.Init(Harmony);
			PlayerPositionSyncPatches.Init(((BaseUnityPlugin)this).Config);
			Harmony.PatchAll(typeof(PlayerPositionSyncPatches));
			Harmony.PatchAll(typeof(WearNTearClientSupportPatches));
			AutoTuneConfig.Init(((BaseUnityPlugin)this).Config);
			Harmony.PatchAll(typeof(AutoTuneProbeHooks));
			Harmony.PatchAll(typeof(ZoneLoadPatches));
			ServerAutoTune.InitServerSide();
			if (isDedicatedServerDetected && ConfigEnableServerAuthority.Value)
			{
				Harmony.PatchAll(typeof(ShipFixesGroup));
				Harmony.PatchAll(typeof(ZDOMemoryManager));
				Harmony.PatchAll(typeof(ServerAuthorityPatches));
				Harmony.PatchAll(typeof(MonsterAIPatches));
				Harmony.PatchAll(typeof(ZDOThrottlingPatches));
				Harmony.PatchAll(typeof(AILODPatches));
				if (ConfigEnableRpcRouter.Value)
				{
					Harmony.PatchAll(typeof(RpcRouterPatches));
					DamageTextHandler.Register();
					HealthChangedHandler.Register();
					WNTHealthChangedHandler.Register();
					SetTargetHandler.Register();
					AddNoiseHandler.Register();
					TriggerAnimationHandler.Register();
					TriggerOnDeathHandler.Register();
					TalkerSayHandler.Register();
					SpawnedZoneHandler.Register();
					LoggerOptions.LogInfo("RPC Router enabled — DamageText, HealthChanged, WNTHealthChanged, SetTarget, AddNoise, TriggerAnimation, TriggerOnDeath, TalkerSay, SpawnedZone handlers registered.");
				}
				if (ConfigEnableZDODelta.Value)
				{
					Harmony.PatchAll(typeof(ZDODeltaPatches));
					LoggerOptions.LogInfo("ZDO delta compression enabled.");
				}
				if (ConfigEnableWNTServerOptimization.Value)
				{
					Harmony.PatchAll(typeof(WearNTearServerPatches));
					LoggerOptions.LogInfo("WearNTear server optimization enabled.");
				}
				LoggerOptions.LogInfo("All server-side features and authority patches enabled.");
			}
			else if (!isDedicatedServerDetected)
			{
				LoggerOptions.LogInfo("Server-side features skipped — not running on a dedicated server.");
			}
			else
			{
				LoggerOptions.LogInfo("Server-side features disabled via ConfigEnableServerAuthority = false.");
			}
			((MonoBehaviour)this).StartCoroutine(RegisterDummyRpcWhenReady());
			((BaseUnityPlugin)this).Logger.LogInfo((object)"FiresGhettoNetworkMod v1.3.0 loaded.");
		}

		private void OnApplicationQuit()
		{
		}

		private void TryPatchAll(Type type)
		{
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Tried to patch a null type!");
			}
			else
			{
				Harmony.PatchAll(type);
			}
		}

		private void SafeInvokeInit(string typeName, string methodName, object[] args)
		{
			try
			{
				Type type = Type.GetType(typeName);
				if (type == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Type " + typeName + " not found; skipping " + methodName + "."));
					return;
				}
				MethodInfo method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Method " + methodName + " not found on " + typeName + "."));
				}
				else
				{
					method.Invoke(null, args);
				}
			}
			catch (TypeLoadException arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"TypeLoadException while invoking {typeName}.{methodName}: {arg}");
			}
			catch (Exception arg2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Exception while invoking {typeName}.{methodName}: {arg2}");
			}
		}

		private void BindConfigs()
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Expected O, but got Unknown
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Expected O, but got Unknown
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Expected O, but got Unknown
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Expected O, but got Unknown
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Expected O, but got Unknown
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Expected O, but got Unknown
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Expected O, but got Unknown
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Expected O, but got Unknown
			//IL_0441: Unknown result type (might be due to invalid IL or missing references)
			//IL_044b: Expected O, but got Unknown
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Expected O, but got Unknown
			//IL_04d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04db: Expected O, but got Unknown
			//IL_052e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0538: Expected O, but got Unknown
			//IL_056b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0575: Expected O, but got Unknown
			//IL_05a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b2: Expected O, but got Unknown
			//IL_05e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05eb: Expected O, but got Unknown
			ConfigLogLevel = ((BaseUnityPlugin)this).Config.Bind<LogLevel>("General", "Log Level", LogLevel.Message, "Controls verbosity in BepInEx log.");
			ConfigEnableCompression = ((BaseUnityPlugin)this).Config.Bind<bool>("Networking", "Enable Compression", true, "Enable ZSTD network compression (highly recommended).");
			ConfigUpdateRate = ((BaseUnityPlugin)this).Config.Bind<UpdateRateOptions>("Networking", "Update Rate", UpdateRateOptions._100, "Server ZDO update frequency. Higher = smoother player movement, more bandwidth.\n100% (20Hz) matches vanilla and is the safe default; 150% (30Hz) is recommended\nfor high-pop servers with bandwidth headroom.");
			ConfigSendRateMin = ((BaseUnityPlugin)this).Config.Bind<SendRateMinOptions>("Networking.Steamworks", "Send Rate Min", SendRateMinOptions._256KB, "Minimum send rate Steam will attempt.");
			ConfigSendRateMax = ((BaseUnityPlugin)this).Config.Bind<SendRateMaxOptions>("Networking.Steamworks", "Send Rate Max", SendRateMaxOptions._512KB, "Maximum send rate Steam will attempt.");
			ConfigQueueSize = ((BaseUnityPlugin)this).Config.Bind<QueueSizeOptions>("Networking", "Queue Size", QueueSizeOptions._32KB, "Send queue size. Higher helps high-player servers.");
			ConfigForceCrossplay = ((BaseUnityPlugin)this).Config.Bind<ForceCrossplayOptions>("Dedicated Server", "Force Crossplay", ForceCrossplayOptions.steamworks, "Requires restart.\nsteamworks = Force crossplay DISABLED (Steam friends only)\nplayfab = Force crossplay ENABLED (PlayFab matchmaking)\nvanilla = Respect command-line -crossplay flag (default Valheim behavior)");
			ConfigPlayerLimit = ((BaseUnityPlugin)this).Config.Bind<int>("Dedicated Server", "Player Limit", 10, new ConfigDescription("Max players on dedicated server. Requires restart.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 999), Array.Empty<object>()));
			ConfigAdvertisedPlayerLimit = ((BaseUnityPlugin)this).Config.Bind<int>("Dedicated Server", "Advertised Player Limit", 0, new ConfigDescription("Max players advertised to matchmaking (Steam server browser → BattleMetrics, PlayFab session/Party). Independent of the actual in-game limit set by 'Player Limit' — useful when an operator wants their server listed as '/500' for marketing while running a real 30-slot cap. 0 = mirror 'Player Limit' (advertised matches reality). Requires restart.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 9999), Array.Empty<object>()));
			ConfigZoneLoadBatchSize = ((BaseUnityPlugin)this).Config.Bind<int>("Client Performance", "Zone Load Batch Size", 1, new ConfigDescription("How aggressively the client consumes incoming zone-stream backlog per frame.\n1 = vanilla (one CreateObjects pass per frame, capped by Valheim).\n2 = double the per-frame cap (faster zone load, bigger frame hitches).\n4 = quadruple (zone-cross stutter masking on capable machines).\nAuto-Tune may override this on the client based on measured frame time.\nCLIENT-ONLY — no effect on server.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), Array.Empty<object>()));
			ConfigZPackageReceiveBufferSize = ((BaseUnityPlugin)this).Config.Bind<int>("Client Performance", "ZPackage Receive Buffer Bytes", 262144, new ConfigDescription("Steam recv-buffer size for inbound network packages. Bigger = fewer dropped packets\nif the client briefly stalls (GC pause, disk hitch), but uses more RAM.\nAuto-Tune may override this on the client based on measured tier.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(65536, 4194304), Array.Empty<object>()));
			ConfigEnableTimeSliceInstantiation = ((BaseUnityPlugin)this).Config.Bind<bool>("Client Performance", "Enable Time-Slice Instantiation", true, "Replace vanilla's fixed 10/100 per-frame ZDO instantiation cap with a per-frame ms\nbudget that drains incoming objects across multiple ticks. Eliminates the big spike\nwhen crossing into a heavy zone. Disable to fall back to the cap-bump transpiler\n(set 'Zone Load Batch Size' to control its multiplier).\nCLIENT-ONLY — no effect on dedicated server.");
			ConfigInstantiationBudgetMs = ((BaseUnityPlugin)this).Config.Bind<int>("Client Performance", "Instantiation Budget Ms", 3, new ConfigDescription("Per-frame millisecond budget for ZDO → GameObject instantiation when time-slicing\nis enabled. Lower = smoother frame times during zone load (longer ramp-in); higher\n= zone loads finish faster (bigger spikes). 3 ms keeps 60-fps clients comfortable.\nAuto-Tune overrides this with tier-specific values when active.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 16), Array.Empty<object>()));
			ConfigMaxInstancesPerFrame = ((BaseUnityPlugin)this).Config.Bind<int>("Client Performance", "Max Instances Per Frame", 100, new ConfigDescription("Hard ceiling on instantiations per frame regardless of how much budget remains.\nBelt-and-suspenders against a runaway pending list.\nAuto-Tune overrides this with tier-specific values when active.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 500), Array.Empty<object>()));
			ConfigSafetyFallbackEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Client Performance", "Safety Fallback Enabled", true, "When the pending instantiation list grows past 'Safety Fallback Threshold' items\n(teleport into megabase, freshly-loaded zones), widen the per-frame budget so we\ndon't bleed across many seconds. Capped at 16 ms so we never burn an entire frame.");
			ConfigSafetyFallbackThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("Client Performance", "Safety Fallback Threshold", 5000, new ConfigDescription("Pending-ZDO count at which the safety fallback widens the instantiation budget.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 50000), Array.Empty<object>()));
			ConfigEnableShipFixes = ((BaseUnityPlugin)this).Config.Bind<bool>("Ship Fixes", "Enable Universal Ship Fixes", true, "Apply permanent autopilot + jitter fixes to ALL ships.");
			ConfigEnableServerSideShipSimulation = ((BaseUnityPlugin)this).Config.Bind<bool>("Ship Fixes", "Server-Side Ship Simulation", false, "Server authoritatively simulates ship physics.\nDisabled by default — enable manually if you want the server to drive ship physics.");
			ConfigEnableRpcRouter = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable RPC Router", true, "Server-side RPC filtering — drops unnecessary DamageText/HealthChanged RPCs before routing\nand prevents SetTarget exploits (targeting players/tamed creatures).\nSaves bandwidth and hardens server security.\nSERVER-ONLY — no effect on client.");
			ConfigEnableRpcAoI = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable RPC Area-of-Interest", true, "When enabled, broadcast RPCs targeting a specific ZDO are only forwarded to peers\nwithin the configured radius of that ZDO. Massively reduces bandwidth on busy servers.\nRPCs without a target ZDO (global RPCs) are always broadcast to all peers.\nRequires Enable RPC Router = true. SERVER-ONLY.");
			ConfigRpcAoIRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "RPC AoI Radius", 256f, new ConfigDescription("Distance (meters) from the target ZDO within which peers will receive the RPC.\nVanilla active area is ~7 zones × 64m = ~448m. Default 256m covers nearby players.\nSet higher if players report missing interactions at distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(64f, 1024f), Array.Empty<object>()));
			ConfigEnableServerAuthority = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable Server-Side Simulation", false, new ConfigDescription("Makes the server fully authoritative over zones, ZDO ownership, monster AI, events, etc. (does NOT override your existing ship fixes).\n\nDisabled by default — enable manually on your DEDICATED SERVER if desired.\n\nWARNING: THIS IS A SERVER-ONLY FEATURE!\nEnabling this on a CLIENT will cause INFINITE LOADING SCREEN.\nThe mod automatically disables it on clients regardless of this setting.", (AcceptableValueBase)null, Array.Empty<object>()));
			ConfigExtendedZoneRadius = ((BaseUnityPlugin)this).Config.Bind<int>("Server Authority", "Extended Zone Radius", 1, new ConfigDescription("Additional zone layers the server pre-loads around players for smoother zone transitions.\n0 = vanilla (no extra pre-load)\n1 = +1 layer (recommended, ~7x7 zones total)\n2 = +2 layers (~9x9 zones)\n3 = +3 layers (~11x11 zones)\n\nHigher values reduce stutter when crossing zone borders but increase server CPU/RAM usage.\nSERVER-ONLY — clients ignore this setting.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3), Array.Empty<object>()));
			ConfigEnablePredictiveZoneStreaming = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable Predictive Zone Streaming", true, "Bias each peer's active-area center forward along their velocity vector so the\nserver starts loading zones BEFORE the peer crosses the boundary. Composes with\n'Extended Zone Radius' — the symmetric ring still expands, the center just slides\nforward. By the time the peer arrives, the predicted zones are already loaded.\nSERVER-ONLY — clients ignore this setting.");
			ConfigPredictionLookaheadSec = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "Prediction Lookahead Sec", 3f, new ConfigDescription("How many seconds ahead the server projects each peer's position when deciding\nwhich zones to pre-load. 3 s gives one zone of headroom at running speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			ConfigPredictionMinVelocity = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "Prediction Min Velocity", 2f, new ConfigDescription("Minimum smoothed speed (m/s) below which prediction is suppressed and the peer's\nreal position is used. Stops idle / slow-walking peers from triggering pre-load.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>()));
			ConfigPredictionMaxLookaheadZones = ((BaseUnityPlugin)this).Config.Bind<int>("Server Authority", "Prediction Max Lookahead Zones", 9, new ConfigDescription("Hard cap on prediction distance, expressed in zones (64 m each). Stops a\nteleporting / glitching peer from subscribing to zones across the world.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 25), Array.Empty<object>()));
			ConfigEnableZDOThrottling = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable ZDO Throttling", true, "Reduce update frequency for distant ZDOs (creatures/structures far away) to save bandwidth.\nSERVER-ONLY — no effect on client.");
			ConfigZDOThrottleDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "ZDO Throttle Distance", 500f, new ConfigDescription("Distance (meters) beyond which ZDOs are throttled (lower update rate).\n0 = disable throttling.\nRecommended: 400-600m.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), Array.Empty<object>()));
			ConfigEnableAILOD = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable AI LOD Throttling", true, "Reduce FixedUpdate frequency for distant AI (saves server CPU).\nNearby AI stays full speed for smooth combat.\nSERVER-ONLY — no effect on client.");
			ConfigAILODNearDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "AI LOD Near Distance", 100f, new ConfigDescription("Full-speed AI within this range (meters).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(50f, 200f), Array.Empty<object>()));
			ConfigAILODFarDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "AI LOD Far Distance", 300f, new ConfigDescription("Beyond this distance, AI is throttled (meters).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(200f, 600f), Array.Empty<object>()));
			ConfigAILODThrottleFactor = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "AI LOD Throttle Factor", 0.5f, new ConfigDescription("Update multiplier for throttled AI (0.5 = half speed, 0.25 = quarter). Lower = more savings.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 0.75f), Array.Empty<object>()));
			ZDOMemoryManager.ConfigMaxZDOs = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "Max Active ZDOs", 500000, new ConfigDescription("If the number of active ZDOs exceeds this value, the mod will force cleanup of orphan non-persistent ZDOs and run garbage collection.\nSet to 0 to disable. Useful on very long-running servers with high entity counts.\nDefault: 500000 (vanilla rarely goes above ~200k).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000000), Array.Empty<object>()));
			ConfigEnableZDODelta = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Enable ZDO Delta Compression", true, "On re-syncs, only send ZDO fields that changed since last send to each peer.\nInitial sync always sends full ZDO state. Re-syncs only send the diff.\nSignificant bandwidth reduction for high-field ZDOs (creatures, players) where\nonly 1-2 fields change per tick (e.g. health, position).\nSERVER-ONLY — no effect on client.");
			ConfigEnableWNTServerOptimization = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Enable WearNTear Server Optimization", true, "Skips structural support recalculation for building pieces that are at full health,\nnot wet, and not in the Ashlands. Support cannot change for intact static pieces,\nso this is a safe CPU saving on servers with large player bases.\nAlso short-circuits damaged-but-invulnerable pieces (Infinity Hammer, admin-flagged)\nsince their support state can't change either.\nSERVER-ONLY — no effect on client.");
			ConfigEnableInvulnerableSupportSkip = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Enable Invulnerable Support Skip", true, "CLIENT-side counterpart to the WearNTear server optimization. Short-circuits the\nexpensive WearNTear.UpdateSupport call (Physics.OverlapBoxNonAlloc per piece) for\npieces whose damage modifiers are all Immune/Ignore — e.g. Infinity Hammer pieces.\nPins m_support at the material's max value so neighbouring mortal pieces still\nsee full support when querying. Massive steady-state CPU saving in megabases\ndominated by invulnerable pieces.");
			ConfigEntryBase[] array = (ConfigEntryBase[])(object)new ConfigEntryBase[37]
			{
				(ConfigEntryBase)ConfigLogLevel,
				(ConfigEntryBase)ConfigEnableCompression,
				(ConfigEntryBase)ConfigUpdateRate,
				(ConfigEntryBase)ConfigSendRateMin,
				(ConfigEntryBase)ConfigSendRateMax,
				(ConfigEntryBase)ConfigQueueSize,
				(ConfigEntryBase)ConfigForceCrossplay,
				(ConfigEntryBase)ConfigPlayerLimit,
				(ConfigEntryBase)ConfigAdvertisedPlayerLimit,
				(ConfigEntryBase)ConfigEnableShipFixes,
				(ConfigEntryBase)ConfigEnableServerSideShipSimulation,
				(ConfigEntryBase)ConfigEnableRpcRouter,
				(ConfigEntryBase)ConfigEnableRpcAoI,
				(ConfigEntryBase)ConfigRpcAoIRadius,
				(ConfigEntryBase)ConfigEnableServerAuthority,
				(ConfigEntryBase)ConfigExtendedZoneRadius,
				(ConfigEntryBase)ConfigEnableZDOThrottling,
				(ConfigEntryBase)ConfigZDOThrottleDistance,
				(ConfigEntryBase)ConfigEnableAILOD,
				(ConfigEntryBase)ConfigAILODNearDistance,
				(ConfigEntryBase)ConfigAILODFarDistance,
				(ConfigEntryBase)ConfigAILODThrottleFactor,
				(ConfigEntryBase)ZDOMemoryManager.ConfigMaxZDOs,
				(ConfigEntryBase)ConfigEnableZDODelta,
				(ConfigEntryBase)ConfigEnableWNTServerOptimization,
				(ConfigEntryBase)ConfigZoneLoadBatchSize,
				(ConfigEntryBase)ConfigZPackageReceiveBufferSize,
				(ConfigEntryBase)ConfigEnableTimeSliceInstantiation,
				(ConfigEntryBase)ConfigInstantiationBudgetMs,
				(ConfigEntryBase)ConfigMaxInstancesPerFrame,
				(ConfigEntryBase)ConfigSafetyFallbackEnabled,
				(ConfigEntryBase)ConfigSafetyFallbackThreshold,
				(ConfigEntryBase)ConfigEnablePredictiveZoneStreaming,
				(ConfigEntryBase)ConfigPredictionLookaheadSec,
				(ConfigEntryBase)ConfigPredictionMinVelocity,
				(ConfigEntryBase)ConfigPredictionMaxLookaheadZones,
				(ConfigEntryBase)ConfigEnableInvulnerableSupportSkip
			};
			ConfigEntryBase[] array2 = array;
			foreach (ConfigEntryBase val in array2)
			{
				Type type = ((object)val).GetType();
				EventInfo @event = type.GetEvent("SettingChanged");
				if (@event != null)
				{
					EventHandler handler = delegate(object sender, EventArgs __)
					{
						//IL_0028: Unknown result type (might be due to invalid IL or missing references)
						//IL_002e: Expected O, but got Unknown
						string text = (((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) ? "SERVER" : "CLIENT");
						ConfigEntryBase val2 = (ConfigEntryBase)sender;
						LoggerOptions.LogInfo($"[{text}] Config changed: {val2.Definition.Section} → {val2.Definition.Key} = {val2.BoxedValue}");
					};
					@event.AddEventHandler(val, handler);
				}
			}
			if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
			{
				ConfigEnableServerAuthority.Value = false;
			}
		}

		private void Start()
		{
			((MonoBehaviour)this).StartCoroutine(RegisterDummyRpcWhenReady());
		}

		[IteratorStateMachine(typeof(<RegisterDummyRpcWhenReady>d__56))]
		private IEnumerator RegisterDummyRpcWhenReady()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RegisterDummyRpcWhenReady>d__56(0)
			{
				<>4__this = this
			};
		}
	}
	public enum LogLevel
	{
		[Description("Errors/Warnings only")]
		Warning,
		[Description("Errors/Warnings/Messages [default]")]
		Message,
		[Description("Everything including Info")]
		Info
	}
	public enum UpdateRateOptions
	{
		[Description("150% - 30 updates/sec [recommended for high-pop]")]
		_150,
		[Description("100% - 20 updates/sec [default, vanilla]")]
		_100,
		[Description("75% - 15 updates/sec")]
		_75,
		[Description("50% - 10 updates/sec")]
		_50
	}
	public enum SendRateMinOptions
	{
		[Description("1024 KB/s | 8 Mbit/s")]
		_1024KB,
		[Description("768 KB/s | 6 Mbit/s")]
		_768KB,
		[Description("512 KB/s | 4 Mbit/s")]
		_512KB,
		[Description("256 KB/s | 2 Mbit/s [default]")]
		_256KB,
		[Description("150 KB/s | 1.2 Mbit/s [vanilla]")]
		_150KB
	}
	public enum SendRateMaxOptions
	{
		[Description("1024 KB/s | 8 Mbit/s")]
		_1024KB,
		[Description("768 KB/s | 6 Mbit/s")]
		_768KB,
		[Description("512 KB/s | 4 Mbit/s [default]")]
		_512KB,
		[Description("256 KB/s | 2 Mbit/s")]
		_256KB,
		[Description("150 KB/s | 1.2 Mbit/s [vanilla]")]
		_150KB
	}
	public enum QueueSizeOptions
	{
		[Description("80 KB")]
		_80KB,
		[Description("64 KB")]
		_64KB,
		[Description("48 KB")]
		_48KB,
		[Description("32 KB [default]")]
		_32KB,
		[Description("Vanilla (~10 KB)")]
		_vanilla
	}
	public enum ForceCrossplayOptions
	{
		[Description("Vanilla behaviour - respect -crossplay flag [default]")]
		vanilla,
		[Description("Force crossplay ENABLED (use PlayFab backend)")]
		playfab,
		[Description("Force crossplay DISABLED (use Steamworks backend)")]
		steamworks
	}
	[HarmonyPatch]
	public static class AILODPatches
	{
		[HarmonyPatch(typeof(Character), "CustomFixedUpdate")]
		[HarmonyPrefix]
		public static bool CustomFixedUpdate_Prefix(Character __instance, float dt)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated() || !FiresGhettoNetworkMod.ConfigEnableAILOD.Value)
			{
				return true;
			}
			if (__instance.IsPlayer() || __instance.IsTamed())
			{
				return true;
			}
			float num = float.MaxValue;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer != (Object)null)
				{
					float num2 = Vector3.Distance(((Component)__instance).transform.position, ((Component)allPlayer).transform.position);
					if (num2 < num)
					{
						num = num2;
					}
				}
			}
			if (num <= FiresGhettoNetworkMod.ConfigAILODNearDistance.Value)
			{
				return true;
			}
			if (num > FiresGhettoNetworkMod.ConfigAILODFarDistance.Value)
			{
				int hashCode = ((object)__instance).GetHashCode();
				float num3 = 1f / FiresGhettoNetworkMod.ConfigAILODThrottleFactor.Value;
				if ((Time.time + (float)hashCode * 0.001f) % num3 > dt)
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class BigZdoDiagnostic
	{
		private const int Threshold = 100;

		private const int SerializeTruncationCeiling = 255;

		[HarmonyPatch(typeof(ZDO), "Save")]
		[HarmonyPrefix]
		public static void ZDO_Save_Prefix(ZDO __instance)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_004a: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			if (__instance == null)
			{
				return;
			}
			try
			{
				ZDOID uid = __instance.m_uid;
				InspectBuckets(__instance, "Save", canTruncate: false, ZDOExtraData.GetSaveFloats(uid).Count, ZDOExtraData.GetSaveVec3s(uid).Count, ZDOExtraData.GetSaveQuaternions(uid).Count, ZDOExtraData.GetSaveInts(uid).Count, ZDOExtraData.GetSaveLongs(uid).Count, ZDOExtraData.GetSaveStrings(uid).Count, ZDOExtraData.GetSaveByteArrays(uid).Count);
			}
			catch (Exception ex)
			{
				LoggerOptions.LogWarning("[BigZdoDiag] Save prefix threw: " + ex.Message);
			}
		}

		[HarmonyPatch(typeof(ZDO), "Serialize")]
		[HarmonyPrefix]
		public static void ZDO_Serialize_Prefix(ZDO __instance)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_004a: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			if (__instance == null)
			{
				return;
			}
			try
			{
				ZDOID uid = __instance.m_uid;
				InspectBuckets(__instance, "Serialize", canTruncate: true, ZDOExtraData.GetFloats(uid).Count, ZDOExtraData.GetVec3s(uid).Count, ZDOExtraData.GetQuaternions(uid).Count, ZDOExtraData.GetInts(uid).Count, ZDOExtraData.GetLongs(uid).Count, ZDOExtraData.GetStrings(uid).Count, ZDOExtraData.GetByteArrays(uid).Count);
			}
			catch (Exception ex)
			{
				LoggerOptions.LogWarning("[BigZdoDiag] Serialize prefix threw: " + ex.Message);
			}
		}

		private static void InspectBuckets(ZDO zdo, string source, bool canTruncate, int fl, int ve, int qu, int ii, int lo, int st, int by)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_00a4: 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)
			if (fl > 100 || ve > 100 || qu > 100 || ii > 100 || lo > 100 || st > 100 || by > 100)
			{
				string text = ResolvePrefabName(zdo.GetPrefab());
				Vector3 position = zdo.GetPosition();
				long owner = zdo.GetOwner();
				string ctx = $"src={source} uid={zdo.m_uid} prefab='{text}'({zdo.GetPrefab()}) " + $"pos=({position.x:F1},{position.z:F1},{position.y:F1}) owner={owner}";
				LogBucket(ctx, "float", fl, canTruncate);
				LogBucket(ctx, "Vector3", ve, canTruncate);
				LogBucket(ctx, "Quaternion", qu, canTruncate);
				LogBucket(ctx, "int", ii, canTruncate);
				LogBucket(ctx, "long", lo, canTruncate);
				LogBucket(ctx, "string", st, canTruncate);
				LogBucket(ctx, "byte[]", by, canTruncate);
			}
		}

		private static void LogBucket(string ctx, string bucket, int count, bool canTruncate)
		{
			if (count > 100)
			{
				if (canTruncate && count > 255)
				{
					LoggerOptions.LogWarning($"[BigZdoDiag TRUNCATING] {ctx} bucket={bucket,-10} count={count} " + $"(>{255} — receiver will read wrapped count, payload corrupt)");
				}
				else
				{
					LoggerOptions.LogWarning($"[BigZdoDiag] {ctx} bucket={bucket,-10} count={count}");
				}
			}
		}

		private static string ResolvePrefabName(int prefabHash)
		{
			try
			{
				ZNetScene instance = ZNetScene.instance;
				if ((Object)(object)instance != (Object)null)
				{
					GameObject prefab = instance.GetPrefab(prefabHash);
					if ((Object)(object)prefab != (Object)null)
					{
						return ((Object)prefab).name;
					}
				}
			}
			catch
			{
			}
			return "<unresolved>";
		}
	}
	[HarmonyPatch]
	public static class CompressionGroup
	{
		internal static class CompressionStatus
		{
			public class SocketStatus
			{
				public int version = 0;

				public bool compressionEnabled = false;

				public bool sendingCompressed = false;

				public bool receivingCompressed = false;
			}

			private const int COMPRESSION_VERSION = 6;

			public static readonly SocketStatus ourStatus = new SocketStatus
			{
				version = 6,
				compressionEnabled = false
			};

			private static readonly Dictionary<ISocket, SocketStatus> peerStatus = new Dictionary<ISocket, SocketStatus>();

			public static void AddPeer(ISocket socket)
			{
				if (socket != null)
				{
					if (peerStatus.ContainsKey(socket))
					{
						peerStatus.Remove(socket);
					}
					peerStatus[socket] = new SocketStatus();
					LoggerOptions.LogMessage("Compression: New peer connected " + socket.GetEndPointString());
				}
			}

			public static void RemovePeer(ISocket socket)
			{
				peerStatus.Remove(socket);
			}

			public static SocketStatus GetStatus(ISocket socket)
			{
				SocketStatus value;
				return peerStatus.TryGetValue(socket, out value) ? value : null;
			}

			public static bool IsCompatible(ISocket socket)
			{
				SocketStatus status = GetStatus(socket);
				return status != null && status.version == ourStatus.version;
			}

			public static bool GetSendCompressionStarted(ISocket socket)
			{
				return GetStatus(socket)?.sendingCompressed ?? false;
			}

			public static bool GetReceiveCompressionStarted(ISocket socket)
			{
				return GetStatus(socket)?.receivingCompressed ?? false;
			}

			public static void SetSendCompressionStarted(ISocket socket, bool started)
			{
				GetStatus(socket).sendingCompressed = started;
			}

			public static void SetReceiveCompressionStarted(ISocket socket, bool started)
			{
				GetStatus(socket).receivingCompressed = started;
			}
		}

		private static string ZSTD_DICT_RESOURCE_NAME = "FiresGhettoNetworkMod.dict.small";

		private static int ZSTD_LEVEL = 1;

		private static object compressor;

		private static object decompressor;

		public static ConfigEntry<bool> ConfigCompressionEnabled;

		private const string RPC_COMPRESSION_VERSION = "FiresGhetto.CompressionVersion";

		private const string RPC_COMPRESSION_ENABLED = "FiresGhetto.CompressionEnabled";

		private const string RPC_COMPRESSION_STARTED = "FiresGhetto.CompressedStarted";

		public static void InitConfig(ConfigFile config)
		{
			ConfigCompressionEnabled = FiresGhettoNetworkMod.ConfigEnableCompression;
			ConfigCompressionEnabled.SettingChanged += delegate
			{
				SetCompressionEnabledFromConfig();
			};
			CompressionStatus.ourStatus.compressionEnabled = ConfigCompressionEnabled?.Value ?? false;
		}

		public static void InitCompressor()
		{
			try
			{
				Type type = Type.GetType("ZstdSharp.Compressor, ZstdSharp");
				Type type2 = Type.GetType("ZstdSharp.Decompressor, ZstdSharp");
				if (type == null || type2 == null)
				{
					LoggerOptions.LogWarning("ZstdSharp assembly not found - compression disabled.");
					return;
				}
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				byte[] array;
				using (Stream stream = executingAssembly.GetManifestResourceStream(ZSTD_DICT_RESOURCE_NAME))
				{
					if (stream == null)
					{
						LoggerOptions.LogError("Compression dictionary resource not found. Compression disabled.");
						return;
					}
					array = new byte[stream.Length];
					stream.Read(array, 0, array.Length);
				}
				compressor = Activator.CreateInstance(type, ZSTD_LEVEL);
				type.GetMethod("LoadDictionary")?.Invoke(compressor, new object[1] { array });
				decompressor = Activator.CreateInstance(type2);
				type2.GetMethod("LoadDictionary")?.Invoke(decompressor, new object[1] { array });
				LoggerOptions.LogInfo("ZSTD compression dictionary loaded successfully.");
			}
			catch (Exception arg)
			{
				LoggerOptions.LogError($"Failed to initialize compressor: {arg}");
			}
		}

		private static void SetCompressionEnabledFromConfig()
		{
			bool value = ConfigCompressionEnabled.Value;
			CompressionStatus.ourStatus.compressionEnabled = value;
			LoggerOptions.LogMessage("Network compression: " + (value ? "Enabled" : "Disabled"));
			SendCompressionEnabledStatusToAll();
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		[HarmonyPostfix]
		private static void OnNewConnection(ZNetPeer peer)
		{
			if (compressor != null)
			{
				CompressionStatus.AddPeer(peer.m_socket);
				RegisterRPCs(peer);
				SendCompressionVersion(peer);
			}
		}

		[HarmonyPatch(typeof(ZNet), "Disconnect")]
		[HarmonyPostfix]
		private static void OnDisconnect(ZNetPeer peer)
		{
			CompressionStatus.RemovePeer(peer.m_socket);
		}

		private static void RegisterRPCs(ZNetPeer peer)
		{
			peer.m_rpc.Register<int>("FiresGhetto.CompressionVersion", (Action<ZRpc, int>)RPC_CompressionVersion);
			peer.m_rpc.Register<bool>("FiresGhetto.CompressionEnabled", (Action<ZRpc, bool>)RPC_CompressionEnabled);
			peer.m_rpc.Register<bool>("FiresGhetto.CompressedStarted", (Action<ZRpc, bool>)RPC_CompressionStarted);
		}

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

		private static void RPC_CompressionVersion(ZRpc rpc, int version)
		{
			ZNetPeer val = FindPeerByRpc(rpc);
			if (val != null)
			{
				CompressionStatus.SocketStatus status = CompressionStatus.GetStatus(val.m_socket);
				if (status != null)
				{
					status.version = version;
				}
				if (version == CompressionStatus.ourStatus.version)
				{
					LoggerOptions.LogMessage("Compression compatible with " + GetPeerName(val));
				}
				else
				{
					LoggerOptions.LogWarning($"Compression version mismatch with {GetPeerName(val)} (them: {version}, us: {CompressionStatus.ourStatus.version})");
				}
				if (CompressionStatus.IsCompatible(val.m_socket))
				{
					SendCompressionEnabledStatus(val);
				}
			}
		}

		private static void SendCompressionEnabledStatusToAll()
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (CompressionStatus.IsCompatible(peer.m_socket))
				{
					SendCompressionEnabledStatus(peer);
				}
			}
		}

		private static void SendCompressionEnabledStatus(ZNetPeer peer)
		{
			peer.m_rpc.Invoke("FiresGhetto.CompressionEnabled", new object[1] { CompressionStatus.ourStatus.compressionEnabled });
			bool started = CompressionStatus.ourStatus.compressionEnabled && (CompressionStatus.GetStatus(peer.m_socket)?.compressionEnabled ?? false);
			SendCompressionStarted(peer, started);
		}

		private static void RPC_CompressionEnabled(ZRpc rpc, bool enabled)
		{
			ZNetPeer val = FindPeerByRpc(rpc);
			if (val != null)
			{
				CompressionStatus.SocketStatus status = CompressionStatus.GetStatus(val.m_socket);
				if (status != null)
				{
					status.compressionEnabled = enabled;
				}
				bool started = CompressionStatus.ourStatus.compressionEnabled && enabled;
				SendCompressionStarted(val, started);
			}
		}

		private static void SendCompressionStarted(ZNetPeer peer, bool started)
		{
			CompressionStatus.SocketStatus status = CompressionStatus.GetStatus(peer.m_socket);
			if (status != null && status.sendingCompressed != started)
			{
				peer.m_rpc.Invoke("FiresGhetto.CompressedStarted", new object[1] { started });
				Flush(peer);
				status.sendingCompressed = started;
				LoggerOptions.LogMessage("Compression " + (started ? "started" : "stopped") + " with " + GetPeerName(peer));
			}
		}

		private static void Flush(ZNetPeer peer)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			OnlineBackendType onlineBackend = ZNet.m_onlineBackend;
			OnlineBackendType val = onlineBackend;
			if ((int)val != 0)
			{
				if ((int)val == 1)
				{
				}
			}
			else
			{
				peer.m_socket.Flush();
			}
		}

		private static void RPC_CompressionStarted(ZRpc rpc, bool started)
		{
			ZNetPeer val = FindPeerByRpc(rpc);
			if (val != null)
			{
				CompressionStatus.SocketStatus status = CompressionStatus.GetStatus(val.m_socket);
				if (status != null)
				{
					status.receivingCompressed = started;
				}
				LoggerOptions.LogMessage("Receiving " + (started ? "compressed" : "uncompressed") + " data from " + GetPeerName(val));
			}
		}

		internal static byte[] Compress(byte[] data)
		{
			if (compressor == null)
			{
				return data;
			}
			Type type = compressor.GetType();
			MethodInfo methodInfo = type.GetMethod("Wrap", new Type[1] { typeof(byte[]) }) ?? type.GetMethod("Wrap");
			object obj = methodInfo.Invoke(compressor, new object[1] { data });
			if (obj is byte[] result)
			{
				return result;
			}
			MethodInfo methodInfo2 = obj?.GetType().GetMethod("ToArray", Type.EmptyTypes);
			if (methodInfo2 != null)
			{
				return (byte[])methodInfo2.Invoke(obj, null);
			}
			return data;
		}

		internal static byte[] Decompress(byte[] data)
		{
			if (decompressor == null)
			{
				throw new Exception("Decompressor not initialized");
			}
			Type type = decompressor.GetType();
			MethodInfo methodInfo = type.GetMethod("Unwrap", new Type[1] { typeof(byte[]) }) ?? type.GetMethod("Unwrap");
			object obj = methodInfo.Invoke(decompressor, new object[1] { data });
			if (obj is byte[] result)
			{
				return result;
			}
			MethodInfo methodInfo2 = obj?.GetType().GetMethod("ToArray", Type.EmptyTypes);
			if (methodInfo2 != null)
			{
				return (byte[])methodInfo2.Invoke(obj, null);
			}
			throw new Exception("Failed to decompress data");
		}

		[HarmonyPatch(typeof(ZSteamSocket), "SendQueuedPackages")]
		[HarmonyPrefix]
		private static bool Steam_SendCompressed(ref Queue<byte[]> ___m_sendQueue, ZSteamSocket __instance)
		{
			if (compressor == null || !CompressionStatus.GetSendCompressionStarted((ISocket)(object)__instance))
			{
				return true;
			}
			___m_sendQueue = new Queue<byte[]>(___m_sendQueue.Select((byte[] p) => Compress(p)));
			return true;
		}

		[HarmonyPatch(typeof(ZSteamSocket), "Recv")]
		[HarmonyPostfix]
		private static void Steam_RecvCompressed(ref ZPackage __result, ZSteamSocket __instance)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			if (__result == null || decompressor == null)
			{
				return;
			}
			CompressionStatus.SocketStatus status = CompressionStatus.GetStatus((ISocket)(object)__instance);
			if (status == null || !status.receivingCompressed)
			{
				return;
			}
			try
			{
				__result = new ZPackage(Decompress(__result.GetArray()));
			}
			catch
			{
				LoggerOptions.LogWarning("Failed to decompress incoming Steamworks package - falling back to uncompressed");
				status.receivingCompressed = false;
			}
		}

		private static ZNetPeer FindPeerByRpc(ZRpc rpc)
		{
			try
			{
				if (rpc == null || ZRoutedRpc.instance == null)
				{
					return null;
				}
				return ((List<ZNetPeer>)AccessTools.Field(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance))?.FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => p.m_rpc == rpc));
			}
			catch
			{
				return null;
			}
		}

		private static string GetPeerName(ZNetPeer peer)
		{
			if (peer == null)
			{
				return "unknown";
			}
			try
			{
				if (peer.m_socket != null)
				{
					return peer.m_socket.GetEndPointString();
				}
			}
			catch
			{
			}
			return peer.m_uid.ToString();
		}
	}
	[HarmonyPatch]
	public static class DedicatedServerGroup
	{
		private static bool isDedicatedDetected;

		public static void Init(ConfigFile config)
		{
			LoggerOptions.LogInfo("Dedicated server features initialized.");
			isDedicatedDetected = ServerClientUtils.IsDedicatedServerDetected;
			if (isDedicatedDetected)
			{
				LoggerOptions.LogInfo("Running as dedicated server (ServerClientUtils).");
			}
			else
			{
				LoggerOptions.LogInfo("Running as client/listen-server (ServerClientUtils).");
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "ParseServerArguments")]
		[HarmonyPostfix]
		private static void ApplyForceCrossplay()
		{
			//IL_0029: 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)
			if (isDedicatedDetected)
			{
				switch (FiresGhettoNetworkMod.ConfigForceCrossplay.Value)
				{
				case ForceCrossplayOptions.playfab:
					ZNet.m_onlineBackend = (OnlineBackendType)1;
					LoggerOptions.LogInfo("Forcing crossplay ENABLED (PlayFab backend).");
					break;
				case ForceCrossplayOptions.steamworks:
					ZNet.m_onlineBackend = (OnlineBackendType)0;
					LoggerOptions.LogInfo("Forcing crossplay DISABLED (Steamworks backend).");
					break;
				default:
					LoggerOptions.LogInfo("Crossplay mode: vanilla (respecting command line).");
					break;
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OverridePlayerLimit(IEnumerable<CodeInstruction> instructions)
		{
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Invalid comparison between Unknown and I4
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Expected O, but got Unknown
			if (!isDedicatedDetected)
			{
				return instructions;
			}
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				if (!(list[i].opcode == OpCodes.Call) || !(list[i].operand is MethodInfo methodInfo) || !(methodInfo.Name == "GetNrOfPlayers"))
				{
					continue;
				}
				for (int j = i + 1; j < list.Count; j++)
				{
					if (list[j].opcode == OpCodes.Ldc_I4_S || list[j].opcode == OpCodes.Ldc_I4 || list[j].opcode == OpCodes.Ldc_I4_0 || list[j].opcode == OpCodes.Ldc_I4_1 || list[j].opcode == OpCodes.Ldc_I4_2 || list[j].opcode == OpCodes.Ldc_I4_3 || list[j].opcode == OpCodes.Ldc_I4_4 || list[j].opcode == OpCodes.Ldc_I4_5 || list[j].opcode == OpCodes.Ldc_I4_6 || list[j].opcode == OpCodes.Ldc_I4_7 || list[j].opcode == OpCodes.Ldc_I4_8)
					{
						int num = FiresGhettoNetworkMod.ConfigPlayerLimit.Value;
						if ((int)ZNet.m_onlineBackend == 1)
						{
							num++;
							LoggerOptions.LogInfo("Applied +1 player limit for PlayFab backend.");
						}
						LoggerOptions.LogInfo($"Overriding player limit constant → {num}");
						list[j] = new CodeInstruction(OpCodes.Ldc_I4, (object)num);
						flag = true;
						break;
					}
				}
				if (flag)
				{
					break;
				}
			}
			if (!flag)
			{
				LoggerOptions.LogWarning("Player limit constant not found in ZNet.RPC_PeerInfo. Patch skipped – possible game update or conflicting mod.");
			}
			return list;
		}

		private static int ResolveAdvertisedLimit(bool addPlayFabHostSlot)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			int num = FiresGhettoNetworkMod.ConfigAdvertisedPlayerLimit?.Value ?? 0;
			int num2 = ((num > 0) ? num : FiresGhettoNetworkMod.ConfigPlayerLimit.Value);
			if (addPlayFabHostSlot && (int)ZNet.m_onlineBackend == 1)
			{
				num2++;
			}
			return num2;
		}

		private static bool IsIntConstantLoad(CodeInstruction ins)
		{
			OpCode opcode = ins.opcode;
			return opcode == OpCodes.Ldc_I4 || opcode == OpCodes.Ldc_I4_S || opcode == OpCodes.Ldc_I4_0 || opcode == OpCodes.Ldc_I4_1 || opcode == OpCodes.Ldc_I4_2 || opcode == OpCodes.Ldc_I4_3 || opcode == OpCodes.Ldc_I4_4 || opcode == OpCodes.Ldc_I4_5 || opcode == OpCodes.Ldc_I4_6 || opcode == OpCodes.Ldc_I4_7 || opcode == OpCodes.Ldc_I4_8;
		}

		[HarmonyPatch(typeof(SteamMatchmaking), "CreateLobby")]
		[HarmonyPrefix]
		private static void OverrideSteamLobbyMaxMembers(ELobbyType eLobbyType, ref int cMaxMembers)
		{
			if (isDedicatedDetected)
			{
				int num = ResolveAdvertisedLimit(addPlayFabHostSlot: false);
				if (num > 0 && cMaxMembers != num)
				{
					LoggerOptions.LogInfo($"Overriding SteamMatchmaking.CreateLobby cMaxMembers: {cMaxMembers} → {num}");
					cMaxMembers = num;
				}
			}
		}

		[HarmonyPatch(typeof(SteamGameServer), "SetMaxPlayerCount")]
		[HarmonyPrefix]
		private static void OverrideSteamGameServerMaxPlayers(ref int cPlayersMax)
		{
			if (isDedicatedDetected)
			{
				int num = ResolveAdvertisedLimit(addPlayFabHostSlot: false);
				if (num > 0 && cPlayersMax != num)
				{
					LoggerOptions.LogInfo($"Overriding SteamGameServer.SetMaxPlayerCount cPlayersMax: {cPlayersMax} → {num}");
					cPlayersMax = num;
				}
			}
		}

		private static List<CodeInstruction> RewriteConstBeforeFieldStore(IEnumerable<CodeInstruction> instructions, string fieldName, string methodLabel, bool addPlayFabHostSlot, bool silentIfNotFound = false)
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			List<CodeInstruction> list = (instructions as List<CodeInstruction>) ?? new List<CodeInstruction>(instructions);
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				CodeInstruction val = list[i];
				if (!(val.opcode != OpCodes.Stfld) && val.operand is FieldInfo fieldInfo && !(fieldInfo.Name != fieldName) && i != 0 && IsIntConstantLoad(list[i - 1]))
				{
					int num = ResolveAdvertisedLimit(addPlayFabHostSlot);
					LoggerOptions.LogInfo($"Overriding {methodLabel} {fieldName} → {num}");
					list[i - 1] = new CodeInstruction(OpCodes.Ldc_I4, (object)num);
					flag = true;
					break;
				}
			}
			if (!flag && !silentIfNotFound)
			{
				LoggerOptions.LogWarning(fieldName + " constant not found in " + methodLabel + ". Patch skipped.");
			}
			return list;
		}

		private static List<CodeInstruction> RewriteConstBeforePropertySet(List<CodeInstruction> list, string propertyName, string methodLabel, bool addPlayFabHostSlot)
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			string text = "set_" + propertyName;
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				CodeInstruction val = list[i];
				if ((!(val.opcode != OpCodes.Callvirt) || !(val.opcode != OpCodes.Call)) && val.operand is MethodInfo methodInfo && !(methodInfo.Name != text) && i != 0 && IsIntConstantLoad(list[i - 1]))
				{
					int num = ResolveAdvertisedLimit(addPlayFabHostSlot);
					LoggerOptions.LogInfo($"Overriding {methodLabel} {propertyName} → {num}");
					list[i - 1] = new CodeInstruction(OpCodes.Ldc_I4, (object)num);
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				LoggerOptions.LogWarning(propertyName + " constant not found in " + methodLabel + ". Patch skipped.");
			}
			return list;
		}
	}
	public static class LoggerOptions
	{
		private static ManualLogSource logger;

		public static void Init(ManualLogSource source)
		{
			logger = source;
		}

		public static void LogError(object data)
		{
			logger.LogError(data);
		}

		public static void LogWarning(object data)
		{
			logger.LogWarning(data);
		}

		public static void LogMessage(object data)
		{
			if (FiresGhettoNetworkMod.ConfigLogLevel != null && FiresGhettoNetworkMod.ConfigLogLevel.Value >= LogLevel.Message)
			{
				logger.LogMessage(data);
			}
		}

		public static void LogInfo(object data)
		{
			if (FiresGhettoNetworkMod.ConfigLogLevel != null && FiresGhettoNetworkMod.ConfigLogLevel.Value >= LogLevel.Info)
			{
				logger.LogInfo(data);
			}
		}
	}
	[HarmonyPatch]
	public static class MonsterAIPatches
	{
		private static readonly int PlayerPrefabHash = StringExtensionMethods.GetStableHashCode("Player");

		private static readonly List<Player> s_tempPlayers = new List<Player>();

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

		private const float EVENT_DIAG_INTERVAL = 30f;

		private const float ZONE_PLAYER_EXTRA = 32f;

		private static readonly FieldInfo _f_randomEvent = AccessTools.Field(typeof(RandEventSystem), "m_randomEvent");

		private static readonly FieldInfo _f_forcedEvent = AccessTools.Field(typeof(RandEventSystem), "m_forcedEvent");

		private static readonly FieldInfo _f_activeEvent = AccessTools.Field(typeof(RandEventSystem), "m_activeEvent");

		private static readonly MethodInfo _m_setActiveEvent = AccessTools.Method(typeof(RandEventSystem), "SetActiveEvent", new Type[2]
		{
			typeof(RandomEvent),
			typeof(bool)
		}, (Type[])null);

		private static readonly MethodInfo _m_isAnyPlayerIn = AccessTools.Method(typeof(RandEventSystem), "IsAnyPlayerInEventArea", new Type[1] { typeof(RandomEvent) }, (Type[])null);

		[HarmonyPatch(typeof(BaseAI), "UpdateAI")]
		[HarmonyPrefix]
		public static bool BaseAI_UpdateAI_Prefix(BaseAI __instance)
		{
			if ((Object)(object)__instance.m_nview == (Object)null)
			{
				return false;
			}
			if (!__instance.m_nview.IsValid())
			{
				return false;
			}
			if (__instance.m_nview.GetZDO() == null)
			{
				return false;
			}
			if ((Object)(object)__instance.m_character == (Object)null)
			{
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(SpawnSystem), "UpdateSpawning")]
		[HarmonyPrefix]
		private static bool UpdateSpawning_Prefix(SpawnSystem __instance, ZNetView ___m_nview, List<SpawnSystemList> ___m_spawnLists)
		{
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated())
			{
				return true;
			}
			if ((Object)(object)___m_nview == (Object)null || !___m_nview.IsValid() || !___m_nview.IsOwner())
			{
				return false;
			}
			RandomEvent val = (RandomEvent)(((Object)(object)RandEventSystem.instance != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			RandomEvent val2 = (RandomEvent)(((Object)(object)RandEventSystem.instance != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			bool flag = val != null || val2 != null;
			bool flag2 = false;
			if (flag)
			{
				int instanceID = ((Object)__instance).GetInstanceID();
				float time = Time.time;
				if (!s_eventDiagLastLogTime.TryGetValue(instanceID, out var value) || time - value >= 30f)
				{
					s_eventDiagLastLogTime[instanceID] = time;
					flag2 = true;
				}
			}
			s_tempPlayers.Clear();
			GetPlayersInZone(__instance, s_tempPlayers);
			if (s_tempPlayers.Count == 0)
			{
				if (flag2)
				{
					Vector3 position = ((Component)__instance).transform.position;
					LoggerOptions.LogInfo($"[EventDiag] SpawnSystem@({position.x:F0},{position.z:F0}) SKIPPED: no players in zone. " + "ActiveEvent='" + ((val != null) ? val.m_name : "null") + "' RunningEvent='" + ((val2 != null) ? val2.m_name : "null") + "' " + $"TotalPlayers={Player.GetAllPlayers().Count} Peers={ZNet.instance.GetConnectedPeers().Count}");
				}
				return false;
			}
			SpawnSystem.m_tempNearPlayers.Clear();
			SpawnSystem.m_tempNearPlayers.AddRange(s_tempPlayers);
			DateTime time2 = ZNet.instance.GetTime();
			foreach (SpawnSystemList ___m_spawnList in ___m_spawnLists)
			{
				if (___m_spawnList?.m_spawners != null)
				{
					__instance.UpdateSpawnList(___m_spawnList.m_spawners, time2, false);
				}
			}
			if ((Object)(object)RandEventSystem.instance != (Object)null)
			{
				List<SpawnData> currentSpawners = RandEventSystem.instance.GetCurrentSpawners();
				if (flag2)
				{
					Vector3 position2 = ((Component)__instance).transform.position;
					int num = currentSpawners?.Count ?? (-1);
					LoggerOptions.LogInfo($"[EventDiag] SpawnSystem@({position2.x:F0},{position2.z:F0}) RAN event path. " + "ActiveEvent='" + ((val != null) ? val.m_name : "null") + "' RunningEvent='" + ((val2 != null) ? val2.m_name : "null") + "' " + $"GetCurrentSpawners.Count={num} Players={s_tempPlayers.Count}");
				}
				if (currentSpawners != null)
				{
					__instance.UpdateSpawnList(currentSpawners, time2, true);
				}
			}
			return false;
		}

		private static void GetPlayersInZone(SpawnSystem spawnSystem, List<Player> players)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer != (Object)null && InsideZone(spawnSystem, ((Component)allPlayer).transform.position, 32f))
				{
					players.Add(allPlayer);
				}
			}
		}

		private static bool InsideZone(SpawnSystem spawnSystem, Vector3 point, float extra = 0f)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_003b: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			float num = 32f + extra;
			Vector3 position = ((Component)spawnSystem).transform.position;
			return point.x >= position.x - num && point.x <= position.x + num && point.z >= position.z - num && point.z <= position.z + num;
		}

		[HarmonyPatch(typeof(RandEventSystem), "FixedUpdate")]
		[HarmonyPrefix]
		private static void RandEventSystem_FixedUpdate_Prefix(RandEventSystem __instance)
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated())
			{
				return;
			}
			object? value = _f_forcedEvent.GetValue(__instance);
			RandomEvent val = (RandomEvent)((value is RandomEvent) ? value : null);
			if (val == null)
			{
				object? value2 = _f_randomEvent.GetValue(__instance);
				RandomEvent val2 = (RandomEvent)((value2 is RandomEvent) ? value2 : null);
				if (val2 != null && (bool)_m_isAnyPlayerIn.Invoke(__instance, new object[1] { val2 }))
				{
					_f_activeEvent.SetValue(__instance, val2);
				}
			}
		}

		[HarmonyPatch(typeof(RandEventSystem), "SetActiveEvent")]
		[HarmonyPrefix]
		private static bool RandEventSystem_SetActiveEvent_Prefix(RandEventSystem __instance, RandomEvent ev)
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated())
			{
				return true;
			}
			if (ev != null)
			{
				return true;
			}
			object? value = _f_forcedEvent.GetValue(__instance);
			RandomEvent val = (RandomEvent)((value is RandomEvent) ? value : null);
			if (val != null)
			{
				return true;
			}
			object? value2 = _f_randomEvent.GetValue(__instance);
			RandomEvent val2 = (RandomEvent)((value2 is RandomEvent) ? value2 : null);
			if (val2 == null)
			{
				return true;
			}
			return false;
		}

		[HarmonyPatch(typeof(RandEventSystem), "FixedUpdate")]
		[HarmonyPostfix]
		private static void RandEventSystem_FixedUpdate_Postfix(RandEventSystem __instance)
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated())
			{
				return;
			}
			object? value = _f_forcedEvent.GetValue(__instance);
			RandomEvent val = (RandomEvent)((value is RandomEvent) ? value : null);
			if (val == null)
			{
				object? value2 = _f_randomEvent.GetValue(__instance);
				RandomEvent val2 = (RandomEvent)((value2 is RandomEvent) ? value2 : null);
				if (val2 != null)
				{
					bool flag = (bool)_m_isAnyPlayerIn.Invoke(__instance, new object[1] { val2 });
					_m_setActiveEvent.Invoke(__instance, new object[2]
					{
						flag ? val2 : null,
						false
					});
				}
				else
				{
					_m_setActiveEvent.Invoke(__instance, new object[2] { null, false });
				}
			}
		}

		public static Player GetNearestPlayer(Vector3 position)
		{
			//IL_002e: 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)
			Player result = null;
			float num = float.MaxValue;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer != (Object)null)
				{
					float num2 = Vector3.Distance(position, ((Component)allPlayer).transform.position);
					if (num2 < num)
					{
						num = num2;
						result = allPlayer;
					}
				}
			}
			return result;
		}

		public static bool IsAnyPlayerInActiveArea(Vector3 position)
		{
			//IL_0022: 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_0028: 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)
			//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_0064: 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)
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			int activeArea = ZoneSystem.instance.m_activeArea;
			Vector2i zone = ZoneSystem.GetZone(position);
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer != (Object)null)
				{
					Vector2i zone2 = ZoneSystem.GetZone(((Component)allPlayer).transform.position);
					if (ZNetScene.InActiveArea(zone, zone2, activeArea))
					{
						return true;
					}
				}
			}
			return false;
		}

		public static Player GetClosestPlayerInRange(Vector3 position, float maxDistance)
		{
			//IL_0038: 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)
			Player result = null;
			float num = maxDistance;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer != (Object)null && !((Character)allPlayer).IsDead())
				{
					float num2 = Vector3.Distance(position, ((Component)allPlayer).transform.position);
					if (num2 < num)
					{
						num = num2;
						result = allPlayer;
					}
				}
			}
			return result;
		}

		public static bool IsPlayerZDO(ZDO zdo)
		{
			return zdo != null && zdo.m_prefab == PlayerPrefabHash;
		}
	}
	[HarmonyPatch]
	public static class NetworkingRatesGroup
	{
		private static bool _recvBufferProbed;

		private static bool _recvBufferSupported;

		private static bool _recvMaxMessageProbed;

		private static bool _recvMaxMessageSupported;

		private static bool _sendBufferProbed;

		private static bool _sendBufferSupported;

		public static void Init(ConfigFile config)
		{
			FiresGhettoNetworkMod.ConfigUpdateRate.SettingChanged += delegate
			{
				ApplyUpdateRate();
			};
			FiresGhettoNetworkMod.ConfigSendRateMin.SettingChanged += delegate
			{
				ApplySendRates();
			};
			FiresGhettoNetworkMod.ConfigSendRateMax.SettingChanged += delegate
			{
				ApplySendRates();
			};
			FiresGhettoNetworkMod.ConfigQueueSize.SettingChanged += delegate
			{
				LoggerOptions.LogInfo("Queue size changed - restart recommended.");
			};
			ApplyUpdateRate();
			ApplySendRates();
		}

		private static void ApplyUpdateRate()
		{
			LoggerOptions.LogMessage($"Update rate set to {FiresGhettoNetworkMod.ConfigUpdateRate.Value}");
		}

		public static void ApplySendRates()
		{
			if (!((Object)(object)ZNet.instance == (Object)null))
			{
				int num = EffectiveConfig.SteamSendRateMin();
				int num2 = EffectiveConfig.SteamSendRateMax();
				SetSteamConfig("k_ESteamNetworkingConfig_SendRateMin", num);
				SetSteamConfig("k_ESteamNetworkingConfig_SendRateMax", num2);
				LoggerOptions.LogMessage($"Steam send rates applied: Min {num / 1024} KB/s, Max {num2 / 1024} KB/s");
			}
		}

		public static void ApplySendBufferSize()
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			if (!_sendBufferProbed)
			{
				_sendBufferProbed = true;
				_sendBufferSupported = HasSteamConfigMember("k_ESteamNetworkingConfig_SendBufferSize");
				if (!_sendBufferSupported)
				{
					LoggerOptions.LogInfo("Steam ESteamNetworkingConfigValue does not expose SendBufferSize in this game build; AutoTune buffer scaling has no effect.");
				}
			}
			if (_sendBufferSupported)
			{
				int num = EffectiveConfig.SteamSendBufferBytes();
				SetSteamConfig("k_ESteamNetworkingConfig_SendBufferSize", num);
				LoggerOptions.LogMessage($"Steam send buffer applied: {num / 1024} KB");
			}
		}

		public static void ApplyRecvBufferSize()
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			if (!_recvBufferProbed)
			{
				_recvBufferProbed = true;
				_recvBufferSupported = HasSteamConfigMember("k_ESteamNetworkingConfig_RecvBufferSize");
				if (!_recvBufferSupported)
				{
					LoggerOptions.LogInfo("Steam ESteamNetworkingConfigValue does not expose RecvBufferSize in this game build; 'ZPackage Receive Buffer Bytes' setting has no effect (Valheim ships an older Steamworks SDK).");
				}
			}
			if (_recvBufferSupported)
			{
				int num = EffectiveConfig.SteamRecvBufferBytes();
				SetSteamConfig("k_ESteamNetworkingConfig_RecvBufferSize", num);
				LoggerOptions.LogMessage($"Steam recv buffer applied: {num / 1024} KB");
			}
		}

		public static void ApplyRecvMaxMessageSize()
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			if (!_recvMaxMessageProbed)
			{
				_recvMaxMessageProbed = true;
				_recvMaxMessageSupported = HasSteamConfigMember("k_ESteamNetworkingConfig_RecvMaxMessageSize");
				if (!_recvMaxMessageSupported)
				{
					LoggerOptions.LogInfo("Steam ESteamNetworkingConfigValue does not expose RecvMaxMessageSize in this game build; per-message cap stays at Steam's 512 KB default (install FiresSteamworksPatcher on the server to enable).");
				}
			}
			if (_recvMaxMessageSupported)
			{
				int num = EffectiveConfig.SteamRecvMaxMessageBytes();
				SetSteamConfig("k_ESteamNetworkingConfig_RecvMaxMessageSize", num);
				LoggerOptions.LogMessage($"Steam recv-max-message applied: {num / 1024} KB");
			}
		}

		private static bool HasSteamConfigMember(string memberName)
		{
			try
			{
				IEnumerable<Type> source = AppDomain.CurrentDomain.GetAssemblies().SelectMany(delegate(Assembly a)
				{
					try
					{
						return a.GetTypes();
					}
					catch
					{
						return Array.Empty<Type>();
					}
				});
				Type type = source.FirstOrDefault((Type t) => t.FullName == "Steamworks.ESteamNetworkingConfigValue");
				if (type == null)
				{
					return false;
				}
				string[] names = Enum.GetNames(type);
				foreach (string text in names)
				{
					if (text == memberName)
					{
						return true;
					}
				}
				return false;
			}
			catch
			{
				return false;
			}
		}

		private static int GetSendRateValue(object option)
		{
			string text = option.ToString();
			if (1 == 0)
			{
			}
			int result = text switch
			{
				"_1024KB" => 1048576, 
				"_768KB" => 786432, 
				"_512KB" => 524288, 
				"_256KB" => 262144, 
				_ => 153600, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		[HarmonyPatch(typeof(ZDOMan), "SendZDOToPeers2")]
		[HarmonyPrefix]
		private static void AdjustUpdateInterval(ref float dt)
		{
			switch (EffectiveConfig.UpdateRate())
			{
			case UpdateRateOptions._150:
				dt *= 1.5f;
				break;
			case UpdateRateOptions._75:
				dt *= 0.75f;
				break;
			case UpdateRateOptions._50:
				dt *= 0.5f;
				break;
			case UpdateRateOptions._100:
				break;
			}
		}

		[HarmonyPatch(typeof(ZNet), "Start")]
		[HarmonyPostfix]
		private static void EnsureRatesOnStart()
		{
			ApplySendRates();
			ApplySendBufferSize();
			ApplyRecvBufferSize();
			ApplyRecvMaxMessageSize();
		}

		private static void SetSteamConfig(string enumMemberName, int value)
		{
			IntPtr intPtr = IntPtr.Zero;
			try
			{
				IEnumerable<Type> source = AppDomain.CurrentDomain.GetAssemblies().SelectMany(delegate(Assembly a)
				{
					try
					{
						return a.GetTypes();
					}
					catch
					{
						return Array.Empty<Type>();
					}
				});
				Type type = source.FirstOrDefault((Type t) => t.FullName == "Steamworks.ESteamNetworkingConfigValue");
				Type type2 = source.FirstOrDefault((Type t) => t.FullName == "Steamworks.ESteamNetworkingConfigScope");
				Type type3 = source.FirstOrDefault((Type t) => t.FullName == "Steamworks.ESteamNetworkingConfigDataType");
				if (type == null || type2 == null || type3 == null)
				{
					LoggerOptions.LogWarning("Steamworks.NET types not found - send rate config skipped.");
					return;
				}
				object obj = Enum.Parse(type, enumMemberName);
				object obj2 = Enum.Parse(type2, "k_ESteamNetworkingConfig_Global");
				object obj3 = Enum.Parse(type3, "k_ESteamNetworkingConfig_Int32");
				intPtr = Marshal.AllocHGlobal(4);
				Marshal.WriteInt32(intPtr, value);
				Type type4 = ((Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsDedicated()) ? source.FirstOrDefault((Type t) => t.FullName == "Steamworks.SteamGameServerNetworkingUtils") : source.FirstOrDefault((Type t) => t.FullName == "Steamworks.SteamNetworkingUtils"));
				if (type4 == null)
				{
					LoggerOptions.LogWarning("Steamworks utils type not found - send rate config skipped.");
					return;
				}
				MethodInfo method = type4.GetMethod("SetConfigValue", BindingFlags.Static | BindingFlags.Public);
				if (method == null)
				{
					LoggerOptions.LogWarning("SetConfigValue method not found - send rate config skipped.");
					return;
				}
				method.Invoke(null, new object[5]
				{
					obj,
					obj2,
					IntPtr.Zero,
					obj3,
					intPtr
				});
			}
			catch (Exception ex)
			{
				LoggerOptions.LogWarning("Failed to set Steam config " + enumMemberName + ": " + ex.Message);
			}
			finally
			{
				if (intPtr != IntPtr.Zero)
				{
					Marshal.FreeHGlobal(intPtr);
				}
			}
		}

		[HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")]
		[HarmonyPostfix]
		private static void ApplySendRatesOnConnect()
		{
			ApplySendRates();
			ApplySendBufferSize();
			ApplyRecvBufferSize();
			ApplyRecvMaxMessageSize();
		}

		[HarmonyPatch(typeof(ZDOMan), "SendZDOs")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> SendZDOs_QueueLimitTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			int num = 0;
			int configuredQueueLimit = GetConfiguredQueueLimit();
			for (int i = 0; i < list.Count; i++)
			{
				if ((!(list[i].opcode == OpCodes.Ldc_I4) && !(list[i].opcode == OpCodes.Ldc_I4_S)) || !(list[i].operand is int num2) || num2 < 10240)
				{
					continue;
				}
				bool flag = false;
				for (int j = Math.Max(0, i - 15); j < Math.Min(list.Count, i + 15); j++)
				{
					if (list[j].opcode == OpCodes.Callvirt && list[j].operand is MethodInfo methodInfo && methodInfo.Name == "GetSendQueueSize")
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					LoggerOptions.LogInfo($"Overriding ZDOMan.SendZDOs queue limit #{num + 1}: original {num2} → {configuredQueueLimit} bytes");
					list[i].opcode = OpCodes.Ldc_I4;
					list[i].operand = configuredQueueLimit;
					num++;
				}
			}
			if (num == 0)
			{
				LoggerOptions.LogWarning("No queue limit constants found in ZDOMan.SendZDOs — queue size config not applied (game update may have changed IL).");
			}
			else
			{
				LoggerOptions.LogInfo($"Successfully patched {num} queue limit constant(s).");
			}
			return list.AsEnumerable();
		}

		private static int GetConfiguredQueueLimit()
		{
			QueueSizeOptions queueSizeOptions = EffectiveConfig.QueueSize();
			if (1 == 0)
			{
			}
			int result = queueSizeOptions switch
			{
				QueueSizeOptions._80KB => 81920, 
				QueueSizeOptions._64KB => 65536, 
				QueueSizeOptions._48KB => 49152, 
				QueueSizeOptions._32KB => 32768, 
				_ => 10240, 
			};
			if (1 == 0)
			{
			}
			return result;
		}
	}
	[HarmonyPatch]
	public static class PlayerPositionSyncPatches
	{
		private sealed class PlayerSyncData
		{
			public Vector3 networkPos;

			public Vector3 prevNetworkPos;

			public Quaternion networkRot;

			public Quaternion prevNetworkRot;

			public Vector3 velocity;

			public Vector3 smoothedVelocity;

			public float lastNetworkUpdateTime;

			public float networkUpdateInterval;

			public bool hasData;

			public Vector3 renderPos;

			public Quaternion renderRot;

			public float lastFrameTime;

			public Vector3 acceleration;
		}

		public static ConfigEntry<bool> ConfigEnablePlayerPositionBoost;

		public static ConfigEntry<float> ConfigPlayerPositionUpdateMultiplier;

		public static ConfigEntry<bool> ConfigEnableClientInterpolation;

		public static ConfigEntry<bool> ConfigEnablePlayerPrediction;

		public static ConfigEntry<float> ConfigSmoothingMinInterval;

		public static ConfigEntry<float> ConfigSmoothingMaxInterval;

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

		private static readonly Dictionary<long, PlayerSyncData> _syncData = new Dictionary<long, PlayerSyncData>();

		public static void Init(ConfigFile config)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			ConfigEnablePlayerPositionBoost = config.Bind<bool>("Player Sync", "Enable High-Frequency Position Updates", true, "Boosts server send priority for player ZDOs so they sync before terrain/object ZDOs.\nReduces the floaty delayed movement you see on other players.\nSERVER-ONLY — no effect on client.");
			ConfigPlayerPositionUpdateMultiplier = config.Bind<float>("Player Sync", "Position Update Multiplier", 2.5f, new ConfigDescription("How aggressively player ZDOs are prioritized over other ZDOs (1.0 = vanilla, 2.5 = recommended).\nHigher values push player positions to the front of the send queue more strongly.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>()));
			ConfigEnableClientInterpolation = config.Bind<bool>("Player Sync", "Enable Client-Side Interpolation", false, "Smooths other players' movement on your client by interpolating between received network positions.\nEliminates the snapping/teleporting caused by discrete 50ms network updates.\nDisabled by default — the rest of the mod's networking improvements (higher update rate, server\nZDO priority boost, larger Steam buffers) usually deliver positions smoothly enough on their own,\nand interpolation adds a small render-lag that some players prefer to avoid. Turn ON if you still\nsee other players snap/teleport even on a healthy connection.\nCLIENT-ONLY — no server impact.");
			ConfigEnablePlayerPrediction = config.Bind<bool>("Player Sync", "Enable Client-Side Prediction", false, "Extrapolates other players' positions forward between network updates using their last known velocity.\nCan help on high latency (>100ms) but may cause overshooting at low ping.\nDisabled by default — only enable if interpolation alone feels laggy.\nCLIENT-ONLY — no server impact.");
			ConfigSmoothingMinInterval = config.Bind<float>("Player Sync", "Smoothing Min Interval (s)", 0f, new ConfigDescription("When a remote player's packets arrive faster than this interval (seconds),\nsmoothing is disabled entirely and vanilla movement renders directly.\nDefault 0 = always smooth (recommended). The earlier default of 0.05\n(vanilla 20Hz) collapsed the smoothing-strength formula to ~0 under\nhealthy traffic, which made BOTH this slider and Smoothing Max feel\nlike no-ops and produced visible snaps every time inter-packet jitter\ncrossed the threshold. Raise above 0 only if you specifically want\nfast packets to bypass smoothing (LAN / very low-latency servers).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.2f), Array.Empty<object>()));
			ConfigSmoothingMaxInterval = config.Bind<float>("Player Sync", "Smoothing Max Interval (s)", 0.2f, new ConfigDescription("When a remote player's packets arrive slower than this interval (seconds),\nsmoothing runs at full strength. Between Min and Max the strength fades\nin linearly so the handoff is invisible. Raise it for a more aggressive\nfade-in (less smoothing on borderline-laggy connections); lower it for a\nsnappier ramp to full smoothing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 0.5f), Array.Empty<object>()));
		}

		private static bool IsPlayerZDO(ZDO zdo)
		{
			return zdo != null && zdo.m_prefab == PlayerPrefabHash;
		}

		[HarmonyPatch(typeof(ZDO), "Deserialize")]
		[HarmonyPostfix]
		public static void ZDO_Deserialize_Postfix(ZDO __instance)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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_00a6: 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_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_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_00e1: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: 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)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			if (ConfigEnableClientInterpolation == null || ConfigEnablePlayerPrediction == null || (!ConfigEnableClientInterpolation.Value && !EffectiveConfig.EnablePlayerPrediction()) || (Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || __instance == null || !IsPlayerZDO(__instance))
			{
				return;
			}
			long owner = __instance.GetOwner();
			if (owner == ZNet.GetUID())
			{
				return;
			}
			Vector3 position = __instance.GetPosition();
			Quaternion rotation = __instance.GetRotation();
			rotation = Quaternion.Normalize(rotation);
			float time = Time.time;
			if (!_syncData.TryGetValue(owner, out var value))
			{
				_syncData[owner] = new PlayerSyncData
				{
					networkPos = position,
					prevNetworkPos = position,
					networkRot = rotation,
					prevNetworkRot = rotation,
					renderPos = position,
					renderRot = rotation,
					velocity = Vector3.zero,
					smoothedVelocity = Vector3.zero,
					acceleration = Vector3.zero,
					networkUpdateInterval = 0.05f,
					lastNetworkUpdateTime = time,
					lastFrameTime = time,
					hasData = true
				};
				return;
			}
			float num = time - value.lastNetworkUpdateTime;
			if (position == value.networkPos)
			{
				value.velocity = Vector3.Lerp(value.velocity, Vector3.zero, 0.9f);
				value.acceleration = Vector3.Lerp(value.acceleration, Vector3.zero, 0.9f);
				if (((Vector3)(ref value.velocity)).magnitude < 0.05f)
				{
					value.velocity = Vector3.zero;
					value.acceleration = Vector3.zero;
				}
			}
			else if (num >= 0.005f && num <= 0.5f)
			{
				value.networkUpdateInterval = Mathf.Lerp(value.networkUpdateInterval, num, 0.15f);
				Vector3 val = (position - value.networkPos) / num;
				if (((Vector3)(ref val)).magnitude <= 30f)
				{
					Vector3 val2 = (val - value.velocity) / num;
					value.acceleration = Vector3.Lerp(value.acceleration, val2, 0.25f);
					Vector3 val3 = Vector3.Lerp(value.velocity, val, 0.5f);
					value.velocity = Vector3.Lerp(value.velocity, val3, 0.7f);
					value.smoothedVelocity = Vector3.Lerp(value.smoothedVelocity, value.velocity, 0.6f);
				}
				else
				{
					value.velocity = Vector3.zero;
					value.smoothedVelocity = Vector3.zero;
					value.acceleration = Vector3.zero;
				}
			}
			value.prevNetworkPos = value.networkPos;
			value.prevNetworkRot = value.networkRot;
			value.networkPos = position;
			value.networkRot = rotation;
			value.lastNetworkUpdateTime = time;
			value.hasData = true;
		}

		[HarmonyPatch(typeof(Player), "LateUpdate")]
		[HarmonyPostfix]
		public static void Player_LateUpdate_Postfix(Player __instance)
		{
			//IL_012f: 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_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0427: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_0446: Unknown result type (might be due to invalid IL or missing references)
			//IL_044b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0451: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_0415: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance == (Object)(object)Player.m_localPlayer || (Object)(object)ZNet.inst