Decompiled source of FiresGhettoNetworking v1.3.2

VAGhettoNetworking.dll

Decompiled 2 weeks 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.2")]
	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__65 : 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__65(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.2";

		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;

		public static ConfigEntry<bool> ConfigEnableServerOwnership;

		public static ConfigEntry<bool> ConfigShowAILODInServerStatus;

		public static ConfigEntry<bool> ConfigEnableBootPatchVerification;

		public static ConfigEntry<bool> ConfigEnableLargeZdoDiagnostics;

		public static ConfigEntry<int> ConfigClientMaxDestroysPerFrame;

		public static ConfigEntry<string> ConfigDediFellOutRescueLayers;

		public static ConfigEntry<float> ConfigDiagnosticIntervalSec;

		public static ConfigEntry<bool> ConfigEnableBulkTransferBoost;

		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.2 — Running on DEDICATED SERVER, enabling server-side features.");
			}
			else
			{
				LoggerOptions.LogMessage("FiresGhettoNetworkMod v1.3.2 — 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(BulkTransferGatePatches));
			Harmony.PatchAll(typeof(BigZdoDiagnostic));
			WackyDatabaseCompatibilityPatch.Init(Harmony);
			Harmony.PatchAll(typeof(PlayerPositionSyncPatches));
			Harmony.PatchAll(typeof(WearNTearClientSupportPatches));
			Harmony.PatchAll(typeof(ClientCleanupThrottle));
			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(ServerStabilityPatches));
				Harmony.PatchAll(typeof(MonsterAIPatches));
				if (ConfigEnableServerOwnership.Value)
				{
					Harmony.PatchAll(typeof(ServerOwnershipPatches));
					LoggerOptions.LogMessage("Server ZDO ownership transfer ENABLED — every persistent ZDO in any peer's active area will be claimed by the server.");
				}
				else
				{
					LoggerOptions.LogInfo("Server ZDO ownership transfer disabled (ConfigEnableServerOwnership = false). Vanilla peer ownership in effect.");
				}
				Harmony.PatchAll(typeof(ZDOThrottlingPatches));
				Harmony.PatchAll(typeof(AILODPatches));
				if (ConfigEnableBootPatchVerification.Value)
				{
					DumpPatchInfo(typeof(BaseAI), "UpdateAI");
					DumpPatchInfo(typeof(BaseAI), "Awake");
					DumpPatchInfo(typeof(MonsterAI), "UpdateAI");
					DumpPatchInfo(typeof(Character), "CustomFixedUpdate");
					DumpPatchInfo(typeof(MonoUpdaters), "FixedUpdate");
					DumpPatchInfo(typeof(ZNetScene), "CreateDestroyObjects");
					DumpPatchInfo(typeof(ZNetScene), "CreateObject");
					DumpPatchInfo(typeof(ZoneSystem), "IsActiveAreaLoaded");
					DumpPatchInfo(typeof(SpawnSystem), "UpdateSpawning");
					DumpPatchInfo(typeof(ShieldDomeImageEffect), "Awake");
					DumpPatchInfo(typeof(TerrainComp), "Update");
				}
				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.2 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 static void DumpPatchInfo(Type type, string methodName)
		{
			MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				LoggerOptions.LogMessage("[PatchVerify] " + type.FullName + "." + methodName + " → method NOT FOUND by AccessTools.");
				return;
			}
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo == null)
			{
				LoggerOptions.LogMessage("[PatchVerify] " + type.FullName + "." + methodName + " → NO patches attached (info=null).");
				return;
			}
			int num = (patchInfo.Prefixes?.Count ?? 0) + (patchInfo.Postfixes?.Count ?? 0) + (patchInfo.Transpilers?.Count ?? 0) + (patchInfo.Finalizers?.Count ?? 0);
			LoggerOptions.LogMessage($"[PatchVerify] {type.FullName}.{methodName} → total={num} (prefixes={patchInfo.Prefixes?.Count ?? 0}, postfixes={patchInfo.Postfixes?.Count ?? 0}, transpilers={patchInfo.Transpilers?.Count ?? 0}, finalizers={patchInfo.Finalizers?.Count ?? 0}).");
			DumpList("Prefix", patchInfo.Prefixes);
			DumpList("Postfix", patchInfo.Postfixes);
			DumpList("Transpiler", patchInfo.Transpilers);
			DumpList("Finalizer", patchInfo.Finalizers);
			static void DumpList(string kind, IEnumerable<Patch> ps)
			{
				if (ps == null)
				{
					return;
				}
				foreach (Patch p in ps)
				{
					LoggerOptions.LogMessage($"[PatchVerify]   [{kind}] owner='{p.owner}' method={p.PatchMethod.DeclaringType?.FullName}.{p.PatchMethod.Name} prio={p.priority}");
				}
			}
		}

		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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Expected O, but got Unknown
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Expected O, but got Unknown
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Expected O, but got Unknown
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Expected O, but got Unknown
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Expected O, but got Unknown
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_039e: Expected O, but got Unknown
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d7: Expected O, but got Unknown
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Expected O, but got Unknown
			//IL_0459: Unknown result type (might be due to invalid IL or missing references)
			//IL_0463: Expected O, but got Unknown
			//IL_0484: Unknown result type (might be due to invalid IL or missing references)
			//IL_048e: Expected O, but got Unknown
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b9: Expected O, but got Unknown
			//IL_04da: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e4: Expected O, but got Unknown
			//IL_050b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0515: Expected O, but got Unknown
			//IL_0568: Unknown result type (might be due to invalid IL or missing references)
			//IL_0572: Expected O, but got Unknown
			//IL_05a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05af: Expected O, but got Unknown
			//IL_05d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e2: Expected O, but got Unknown
			//IL_0635: Unknown result type (might be due to invalid IL or missing references)
			//IL_063f: Expected O, but got Unknown
			//IL_0692: Unknown result type (might be due to invalid IL or missing references)
			//IL_069c: Expected O, but got Unknown
			//IL_06cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d9: Expected O, but got Unknown
			//IL_070c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0716: Expected O, but got Unknown
			//IL_0745: Unknown result type (might be due to invalid IL or missing references)
			//IL_074f: Expected O, but got Unknown
			//IL_0770: Unknown result type (might be due to invalid IL or missing references)
			//IL_077a: Expected O, but got Unknown
			//IL_079b: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a5: Expected O, but got Unknown
			ConfigLogLevel = ((BaseUnityPlugin)this).Config.Bind<LogLevel>("01 - General", "Log Level", LogLevel.Message, "Controls verbosity in BepInEx log.");
			ConfigZoneLoadBatchSize = ((BaseUnityPlugin)this).Config.Bind<int>("02 - 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>()));
			PlayerPositionSyncPatches.Init(((BaseUnityPlugin)this).Config);
			ConfigEnableCompression = ((BaseUnityPlugin)this).Config.Bind<bool>("04 - Networking", "Enable Compression", true, "Enable ZSTD network compression (highly recommended).");
			ConfigUpdateRate = ((BaseUnityPlugin)this).Config.Bind<UpdateRateOptions>("04 - 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>("05 - Networking - Steamworks", "Send Rate Min", SendRateMinOptions._256KB, "Minimum send rate Steam will attempt.");
			ConfigSendRateMax = ((BaseUnityPlugin)this).Config.Bind<SendRateMaxOptions>("05 - Networking - Steamworks", "Send Rate Max", SendRateMaxOptions._512KB, "Maximum send rate Steam will attempt.");
			AutoTuneConfig.Init(((BaseUnityPlugin)this).Config);
			ConfigQueueSize = ((BaseUnityPlugin)this).Config.Bind<QueueSizeOptions>("04 - Networking", "Queue Size", QueueSizeOptions._32KB, "Send queue size. Higher helps high-player servers.");
			ConfigForceCrossplay = ((BaseUnityPlugin)this).Config.Bind<ForceCrossplayOptions>("09 - 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>("09 - 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>("09 - 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>("02 - 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>("02 - 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>("02 - 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>("02 - 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>("02 - 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>("02 - 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>("02 - 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>()));
			ConfigEnableRpcRouter = ((BaseUnityPlugin)this).Config.Bind<bool>("10 - 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.");
			ConfigEnableShipFixes = ((BaseUnityPlugin)this).Config.Bind<bool>("11 - Ship Fixes", "Enable Universal Ship Fixes", true, "Apply permanent autopilot + jitter fixes to ALL ships.");
			ConfigEnableServerSideShipSimulation = ((BaseUnityPlugin)this).Config.Bind<bool>("11 - 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.");
			ConfigEnableRpcAoI = ((BaseUnityPlugin)this).Config.Bind<bool>("10 - 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>("10 - 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>()));
			ConfigClientMaxDestroysPerFrame = ((BaseUnityPlugin)this).Config.Bind<int>("02 - Client Performance", "Max Destroys Per Frame", 200, new ConfigDescription("Maximum ZNetScene instances the client destroys per CreateDestroyObjects pass.\nVanilla destroys every out-of-area instance in a single frame, producing a\nmulti-second hitch when leaving a heavily-loaded zone (e.g. ~150k instances\non a megabase). The throttle defers the surplus to subsequent frames so the\ndeparture cost spreads out smoothly.\n0 = no throttle (vanilla single-frame destruction).\n200 = ~12s to clear a 150k-instance backlog at 60 fps, with each frame's\ndestroy cost roughly equal to instantiating 200 objects.\nCLIENT-ONLY — no effect on dedicated server.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 5000), Array.Empty<object>()));
			ConfigDediFellOutRescueLayers = ((BaseUnityPlugin)this).Config.Bind<string>("10 - Server Authority", "Dedi Fell-Out Rescue Layers", "Default,static_solid,Default_small,piece,terrain,vehicle", new ConfigDescription("Comma-separated Unity layer names the dedi raycasts against when rescuing a mob\nthat fell below the kill plane (y < -5000). Default mirrors vanilla BaseAI's\nsolid-ray mask so any vanilla collider catches the mob. If your modlist ships\ncustom terrain on a non-vanilla layer (RPGmaker overlay, etc.) and you see mobs\npermanently parked instead of recovering, add that layer name here. The cache\nrefreshes when this value changes; no restart needed.", (AcceptableValueBase)null, Array.Empty<object>()));
			ConfigShowAILODInServerStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - General", "Show AILOD in ServerStatus", true, "When ON, appends the AILOD throttle's per-window stats (mobs examined,\nnear/mid/far decision counts, nearest-peer distance range) to the\nconsolidated [ServerStatus] line. Useful for tuning the near/far gates.\nTurn OFF once tuning is validated and you want a quieter log.\nHas no effect when Enable AI LOD Throttling is OFF — there's nothing to report.");
			ConfigDiagnosticIntervalSec = ((BaseUnityPlugin)this).Config.Bind<float>("01 - General", "Diagnostic Rollup Interval (sec)", 60f, new ConfigDescription("How often the consolidated [ServerStatus] line is logged on a dedicated server.\nSummarises MonoUpdaters tick rate, AI list sizes, BaseAI/MonsterAI tick counts,\nZNetScene instantiation, our CreateDestroyObjects / IsActiveAreaLoaded gate\nbehavior, and ServerOwnership transfer/release churn in a single line.\nLower = more visibility, more log spam. Higher = quieter. Change takes effect on the next window.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 3600f), Array.Empty<object>()));
			ConfigEnableBulkTransferBoost = ((BaseUnityPlugin)this).Config.Bind<bool>("04 - Networking", "Enable Bulk Transfer Queue Boost", true, new ConfigDescription("When ON, reflectively patches the 20 KB GetSendQueueSize gate inside every loaded ServerSync.ConfigSync (AzuEPI, Marketplace, EpicLoot, Wizardry, EW Data, etc.) AND ServerCharacters.Shared copy so their fragment loops keep up with our raised ZDOMan cap.\nReplaces the old BulkTransferGuard which suppressed ZDOMan.SendZDOs during bulk bursts and incidentally starved player position ZDOs (the source of 'players flying / teleporting / hits from across the map' complaints).\nDisable as a kill switch if you suspect the scan is causing freezes or false-positive patching.\nBoth sides — applies on client and dedicated server.", (AcceptableValueBase)null, Array.Empty<object>()));
			ConfigEnableServerAuthority = ((BaseUnityPlugin)this).Config.Bind<bool>("10 - 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>()));
			ConfigEnableServerOwnership = ((BaseUnityPlugin)this).Config.Bind<bool>("10 - Server Authority", "Enable Server ZDO Ownership Transfer (EXPERIMENTAL)", false, new ConfigDescription("EXPERIMENTAL — defaults OFF. Direct port of the original Serverside Simulations mod's\nZDOMan.ReleaseNearbyZDOS prefix. When enabled, the server takes ownership of EVERY\npersistent ZDO in any peer's active area (mobs, ships, terrain, structures, items, doors,\nthe whole world). Peers no longer own anything.\n\nWHEN TO ENABLE: you've validated the rest of your modlist plays nicely with broad\nserver ownership and you want maximum server-side simulation (offloads client CPU,\nflips the bandwidth pattern so server send dominates).\n\nWHEN TO LEAVE OFF: you're running a heavy modpack, you've seen mob freezes or\ninteraction issues after a previous attempt, or you don't know yet. Leaving this off\npreserves vanilla peer ownership — every other server-authority feature (zones,\nspawning, raids, throttling) still works without it.\n\nREQUIRES: ConfigEnableServerAuthority = true AND running on a dedicated server.\nTOGGLE IS INDEPENDENT — flip this without touching ConfigEnableServerAuthority.", (AcceptableValueBase)null, Array.Empty<object>()));
			ConfigExtendedZoneRadius = ((BaseUnityPlugin)this).Config.Bind<int>("10 - 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>("10 - 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>("10 - 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>("10 - 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>("10 - 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>("10 - 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>("10 - 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>("10 - 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>("10 - 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>("10 - 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>("10 - 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>("12 - 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>()));
			ConfigEnableBootPatchVerification = ((BaseUnityPlugin)this).Config.Bind<bool>("12 - Advanced", "Enable Boot Patch Verification", false, new ConfigDescription("OFF by default. When ON, logs every Harmony patch attached to the AI tick,\ninstantiation, and zone-gate methods this mod cares about — useful when\ntroubleshooting mod-conflict scenarios (another mod's transpiler stomping our\nprefix, etc.) or when bringing up a new feature.\n\nThe runtime [ServerStatus] rollup is the ongoing health indicator; this toggle\nis only useful when you suspect Harmony itself didn't attach something.", (AcceptableValueBase)null, Array.Empty<object>()));
			ConfigEnableLargeZdoDiagnostics = ((BaseUnityPlugin)this).Config.Bind<bool>("12 - Advanced", "Enable Large ZDO Diagnostics", false, new ConfigDescription("OFF by default. When ON, adds enriched [BigZdoDiag] log lines next to vanilla's\nexisting 'Writing a lot of data; X items, is not optimal' warning so you can see\nwhich ZDO is bloating its extra-data buckets (uid, prefab name, world position,\nowner peer id, bucket type and count).\n\nNOTE: the underlying warning is emitted by vanilla Valheim, not by this mod.\nThis toggle only controls whether we ATTACH context to it. Turn this on when you\nsee the vanilla warning and want to track down the offending entity; leave it off\notherwise so the log stays quiet.", (AcceptableValueBase)null, Array.Empty<object>()));
			ConfigEnableZDODelta = ((BaseUnityPlugin)this).Config.Bind<bool>("12 - 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>("12 - 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>("12 - 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[42]
			{
				(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)ConfigShowAILODInServerStatus,
				(ConfigEntryBase)ConfigEnableBootPatchVerification,
				(ConfigEntryBase)ConfigEnableLargeZdoDiagnostics,
				(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)ConfigEnableBulkTransferBoost,
				(ConfigEntryBase)ConfigEnableServerOwnership
			};
			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__65))]
		private IEnumerator RegisterDummyRpcWhenReady()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RegisterDummyRpcWhenReady>d__65(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
	{
		private const float MillisecondsPerSecondNoise = 0.001f;

		[HarmonyPatch(typeof(Character), "CustomFixedUpdate")]
		[HarmonyPrefix]
		public static bool CustomFixedUpdate_Prefix(Character __instance, float dt)
		{
			//IL_0073: 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;
			}
			ServerStatusDiagnostics.s_ailod_examined++;
			if (__instance.IsPlayer() || __instance.IsTamed())
			{
				ServerStatusDiagnostics.s_ailod_playerOrTamed++;
				return true;
			}
			int peerCount;
			float num = ComputeDistanceToNearestPeer(((Component)__instance).transform.position, out peerCount);
			ServerStatusDiagnostics.s_ailod_peersLastSeen = peerCount;
			UpdateNearestDistanceObservedRange(num);
			float value = FiresGhettoNetworkMod.ConfigAILODNearDistance.Value;
			float value2 = FiresGhettoNetworkMod.ConfigAILODFarDistance.Value;
			if (num <= value)
			{
				ServerStatusDiagnostics.s_ailod_decidedNear++;
				return true;
			}
			if (num > value2)
			{
				return DecideFarBand(__instance, dt);
			}
			ServerStatusDiagnostics.s_ailod_decidedMidBand++;
			return true;
		}

		private static float ComputeDistanceToNearestPeer(Vector3 origin, out int peerCount)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			float num = float.MaxValue;
			peerCount = 0;
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer != null)
				{
					peerCount++;
					Vector3 refPos = peer.GetRefPos();
					float num2 = origin.x - refPos.x;
					float num3 = origin.y - refPos.y;
					float num4 = origin.z - refPos.z;
					float num5 = num2 * num2 + num3 * num3 + num4 * num4;
					if (num5 < num)
					{
						num = num5;
					}
				}
			}
			return (num < float.MaxValue) ? Mathf.Sqrt(num) : float.MaxValue;
		}

		private static void UpdateNearestDistanceObservedRange(float nearestDist)
		{
			if (nearestDist < ServerStatusDiagnostics.s_ailod_minNearestDist)
			{
				ServerStatusDiagnostics.s_ailod_minNearestDist = nearestDist;
			}
			if (nearestDist > ServerStatusDiagnostics.s_ailod_maxNearestDist && nearestDist < float.MaxValue)
			{
				ServerStatusDiagnostics.s_ailod_maxNearestDist = nearestDist;
			}
		}

		private static bool DecideFarBand(Character mob, float dt)
		{
			int hashCode = ((object)mob).GetHashCode();
			float num = 1f / FiresGhettoNetworkMod.ConfigAILODThrottleFactor.Value;
			if ((Time.time + (float)hashCode * 0.001f) % num > dt)
			{
				ServerStatusDiagnostics.s_ailod_decidedFarSkipped++;
				return false;
			}
			ServerStatusDiagnostics.s_ailod_decidedFarRan++;
			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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (__instance == null || !IsDiagnosticEnabled())
			{
				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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (__instance == null || !IsDiagnosticEnabled())
			{
				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 bool IsDiagnosticEnabled()
		{
			return FiresGhettoNetworkMod.ConfigEnableLargeZdoDiagnostics?.Value ?? false;
		}

		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 BulkTransferGatePatches
	{
		private readonly struct Target
		{
			public readonly string TypeName;

			public readonly string GateMethodName;

			public readonly int VanillaConstant;

			public Target(string typeName, string gateMethodName, int vanillaConstant)
			{
				TypeName = typeName;
				GateMethodName = gateMethodName;
				VanillaConstant = vanillaConstant;
			}
		}

		[CompilerGenerated]
		private sealed class <WalkAllNestedTypes>d__6 : IEnumerable<Type>, IEnumerable, IEnumerator<Type>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private Type <>2__current;

			private int <>l__initialThreadId;

			private Type root;

			public Type <>3__root;

			private Type[] <nested>5__1;

			private Type[] <>s__2;

			private int <>s__3;

			private Type <nt>5__4;

			private IEnumerator<Type> <>s__5;

			private Type <sub>5__6;

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

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

			[DebuggerHidden]
			public <WalkAllNestedTypes>d__6(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 2)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<nested>5__1 = null;
				<>s__2 = null;
				<nt>5__4 = null;
				<>s__5 = null;
				<sub>5__6 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>2__current = root;
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -1;
						try
						{
							<nested>5__1 = root.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);
						}
						catch
						{
							return false;
						}
						<>s__2 = <nested>5__1;
						<>s__3 = 0;
						goto IL_0128;
					case 2:
						{
							<>1__state = -3;
							<sub>5__6 = null;
							goto IL_00f8;
						}
						IL_00f8:
						if (<>s__5.MoveNext())
						{
							<sub>5__6 = <>s__5.Current;
							<>2__current = <sub>5__6;
							<>1__state = 2;
							return true;
						}
						<>m__Finally1();
						<>s__5 = null;
						<nt>5__4 = null;
						<>s__3++;
						goto IL_0128;
						IL_0128:
						if (<>s__3 < <>s__2.Length)
						{
							<nt>5__4 = <>s__2[<>s__3];
							<>s__5 = WalkAllNestedTypes(<nt>5__4).GetEnumerator();
							<>1__state = -3;
							goto IL_00f8;
						}
						<>s__2 = null;
						return false;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>s__5 != null)
				{
					<>s__5.Dispose();
				}
			}

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

			[DebuggerHidden]
			IEnumerator<Type> IEnumerable<Type>.GetEnumerator()
			{
				<WalkAllNestedTypes>d__6 <WalkAllNestedTypes>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<WalkAllNestedTypes>d__ = this;
				}
				else
				{
					<WalkAllNestedTypes>d__ = new <WalkAllNestedTypes>d__6(0);
				}
				<WalkAllNestedTypes>d__.root = <>3__root;
				return <WalkAllNestedTypes>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<Type>)this).GetEnumerator();
			}
		}

		private static readonly Target[] Targets = new Target[2]
		{
			new Target("ServerSync.ConfigSync", "GetSendQueueSize", 20000),
			new Target("ServerCharacters.Shared", "GetSendQueueSize", 20000)
		};

		private static int s_currentVanillaConstant;

		private static bool s_applied;

		[HarmonyPatch(typeof(ZNet), "Start")]
		[HarmonyPostfix]
		private static void ApplyOnZNetStart()
		{
			if (s_applied)
			{
				return;
			}
			s_applied = true;
			ConfigEntry<bool> configEnableBulkTransferBoost = FiresGhettoNetworkMod.ConfigEnableBulkTransferBoost;
			if (configEnableBulkTransferBoost != null && !configEnableBulkTransferBoost.Value)
			{
				LoggerOptions.LogMessage("Bulk-transfer gate scan skipped — ConfigEnableBulkTransferBoost = false.");
				return;
			}
			try
			{
				ApplyAll(FiresGhettoNetworkMod.Harmony);
			}
			catch (Exception ex)
			{
				LoggerOptions.LogWarning("Bulk-transfer gate scan threw: " + ex.Message);
			}
		}

		private static void ApplyAll(Harmony harmony)
		{
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Expected O, but got Unknown
			int targetQueueSize = GetTargetQueueSize();
			int num = 0;
			int num2 = 0;
			Target[] targets = Targets;
			for (int i = 0; i < targets.Length; i++)
			{
				Target target = targets[i];
				if (targetQueueSize <= target.VanillaConstant)
				{
					LoggerOptions.LogInfo("Bulk-transfer gate scan for " + target.TypeName + " skipped — " + $"our queue cap ({targetQueueSize} bytes) is at/below the vanilla {target.VanillaConstant} default.");
					continue;
				}
				int num3 = 0;
				int num4 = 0;
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					Type type = null;
					try
					{
						type = assembly.GetType(target.TypeName, throwOnError: false);
					}
					catch
					{
						continue;
					}
					if (type == null)
					{
						continue;
					}
					num3++;
					foreach (Type item in WalkAllNestedTypes(type))
					{
						MethodInfo[] methods = item.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
						foreach (MethodInfo methodInfo in methods)
						{
							if (!methodInfo.IsAbstract && !methodInfo.ContainsGenericParameters && MentionsBoth(methodInfo, target.GateMethodName, target.VanillaConstant))
							{
								try
								{
									s_currentVanillaConstant = target.VanillaConstant;
									harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(BulkTransferGatePatches), "BumpQueueGate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
									num4++;
									LoggerOptions.LogMessage("Bulk-transfer gate patched: " + assembly.GetName().Name + " → " + item.FullName + "." + methodInfo.Name + " " + $"({target.VanillaConstant} → {targetQueueSize} bytes).");
								}
								catch (Exception ex)
								{
									LoggerOptions.LogWarning("Failed to patch bulk-transfer gate at " + assembly.GetName().Name + "." + item.FullName + "." + methodInfo.Name + ": " + ex.Message);
								}
							}
						}
					}
				}
				num += num3;
				num2 += num4;
				LoggerOptions.LogMessage($"Bulk-transfer gate scan for {target.TypeName}: {num3} copies found, {num4} gate sites patched.");
			}
			LoggerOptions.LogMessage($"Bulk-transfer gate scan complete: {num} third-party copies found across loaded assemblies, " + $"{num2} queue-gate sites patched (target {targetQueueSize} bytes).");
		}

		[IteratorStateMachine(typeof(<WalkAllNestedTypes>d__6))]
		private static IEnumerable<Type> WalkAllNestedTypes(Type root)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WalkAllNestedTypes>d__6(-2)
			{
				<>3__root = root
			};
		}

		private static bool MentionsBoth(MethodBase m, string callName, int needsConstant)
		{
			List<CodeInstruction> currentInstructions;
			try
			{
				currentInstructions = PatchProcessor.GetCurrentInstructions(m, int.MaxValue, (ILGenerator)null);
			}
			catch
			{
				return false;
			}
			bool flag = false;
			bool flag2 = false;
			foreach (CodeInstruction item in currentInstructions)
			{
				if (!flag && (item.opcode == OpCodes.Ldc_I4 || item.opcode == OpCodes.Ldc_I4_S) && item.operand is int num && num == needsConstant)
				{
					flag = true;
				}
				if (!flag2 && (item.opcode == OpCodes.Call || item.opcode == OpCodes.Callvirt) && item.operand is MethodInfo methodInfo && methodInfo.Name == callName)
				{
					flag2 = true;
				}
				if (flag && flag2)
				{
					return true;
				}
			}
			return false;
		}

		public static IEnumerable<CodeInstruction> BumpQueueGate(IEnumerable<CodeInstruction> instructions)
		{
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			int num = s_currentVanillaConstant;
			int targetQueueSize = GetTargetQueueSize();
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			List<int> list2 = new List<int>();
			for (int i = 0; i < list.Count; i++)
			{
				if ((list[i].opcode == OpCodes.Call || list[i].opcode == OpCodes.Callvirt) && list[i].operand is MethodInfo methodInfo && methodInfo.Name == "GetSendQueueSize")
				{
					list2.Add(i);
				}
			}
			if (list2.Count == 0)
			{
				return list;
			}
			for (int j = 0; j < list.Count; j++)
			{
				if ((!(list[j].opcode == OpCodes.Ldc_I4) && !(list[j].opcode == OpCodes.Ldc_I4_S)) || !(list[j].operand is int num2) || num2 != num)
				{
					continue;
				}
				bool flag = false;
				foreach (int item in list2)
				{
					if (Math.Abs(item - j) <= 8)
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					list[j] = new CodeInstruction(OpCodes.Ldc_I4, (object)targetQueueSize);
				}
			}
			return list;
		}

		private static int GetTargetQueueSize()
		{
			QueueSizeOptions queueSizeOptions = EffectiveConfig.QueueSize();
			if (1 == 0)
			{
			}
			int result = queueSizeOptions switch
			{
				QueueSizeOptions._80KB => 81920, 
				QueueSizeOptions._64KB => 65536, 
				QueueSizeOptions._48KB => 49152, 
				QueueSizeOptions._32KB => 32768, 
				_ => 20000, 
			};
			if (1 == 0)
			{
			}
			return result;
		}
	}
	[HarmonyPatch]
	public static class ClientCleanupThrottle
	{
		private static readonly HashSet<ZNetView> _pendingDestroySet = new HashSet<ZNetView>();

		private static readonly Queue<ZNetView> _pendingDestroyQueue = new Queue<ZNetView>();

		private static readonly List<ZDO> _zdosToUnregisterScratch = new List<ZDO>(256);

		[HarmonyPatch(typeof(ZNetScene), "RemoveObjects")]
		[HarmonyPrefix]
		public static bool RemoveObjects_ClientThrottle_Prefix(ZNetScene __instance, List<ZDO> currentNearObjects, List<ZDO> currentDistantObjects)
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated())
			{
				return true;
			}
			int num = FiresGhettoNetworkMod.ConfigClientMaxDestroysPerFrame?.Value ?? 0;
			if (num <= 0)
			{
				return true;
			}
			MarkInAreaZdosWithCurrentFrameEarmark(currentNearObjects, currentDistantObjects, out var frameEarmark);
			EnqueueOutOfAreaInstancesForDeferredDestroy(__instance, frameEarmark);
			DestroyUpToBudget(__instance, frameEarmark, num);
			return false;
		}

		private static void MarkInAreaZdosWithCurrentFrameEarmark(List<ZDO> near, List<ZDO> distant, out byte frameEarmark)
		{
			frameEarmark = (byte)((uint)Time.frameCount & 0xFFu);
			ApplyEarmark(near, frameEarmark);
			ApplyEarmark(distant, frameEarmark);
		}

		private static void ApplyEarmark(List<ZDO> zdos, byte mark)
		{
			if (zdos == null)
			{
				return;
			}
			for (int i = 0; i < zdos.Count; i++)
			{
				ZDO val = zdos[i];
				if (val != null)
				{
					val.TempRemoveEarmark = mark;
				}
			}
		}

		private static void EnqueueOutOfAreaInstancesForDeferredDestroy(ZNetScene scene, byte frameEarmark)
		{
			foreach (KeyValuePair<ZDO, ZNetView> instance in scene.m_instances)
			{
				ZNetView value = instance.Value;
				if (!((Object)(object)value == (Object)null))
				{
					ZDO zDO = value.GetZDO();
					if (zDO != null && zDO.TempRemoveEarmark != frameEarmark && _pendingDestroySet.Add(value))
					{
						_pendingDestroyQueue.Enqueue(value);
					}
				}
			}
		}

		private static void DestroyUpToBudget(ZNetScene scene, byte frameEarmark, int budget)
		{
			_zdosToUnregisterScratch.Clear();
			int num = 0;
			while (_pendingDestroyQueue.Count > 0 && num < budget)
			{
				ZNetView val = _pendingDestroyQueue.Dequeue();
				_pendingDestroySet.Remove(val);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				ZDO zDO = val.GetZDO();
				if (zDO != null && zDO.TempRemoveEarmark != frameEarmark)
				{
					val.ResetZDO();
					_zdosToUnregisterScratch.Add(zDO);
					if (!zDO.Persistent && zDO.IsOwner())
					{
						ZDOMan.instance.DestroyZDO(zDO);
					}
					Object.Destroy((Object)(object)((Component)val).gameObject);
					num++;
				}
			}
			for (int i = 0; i < _zdosToUnregisterScratch.Count; i++)
			{
				scene.m_instances.Remove(_zdosToUnregisterScratch[i]);
			}
			_zdosToUnregisterScratch.Clear();
		}
	}
	[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 = 7;

			public static readonly SocketStatus ourStatus = new SocketStatus
			{
				version = 7,
				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 static readonly byte[] CompressionMagic = new byte[4] { 70, 71, 90, 55 };

		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;
			}
			if (HasCompressionHeader(data))
			{
				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[] compressed)
			{
				return AddCompressionHeaderIfUseful(data, compressed);
			}
			MethodInfo methodInfo2 = obj?.GetType().GetMethod("ToArray", Type.EmptyTypes);
			if (methodInfo2 != null)
			{
				return AddCompressionHeaderIfUseful(data, (byte[])methodInfo2.Invoke(obj, null));
			}
			return data;
		}

		internal static byte[] Decompress(byte[] data)
		{
			if (!HasCompressionHeader(data))
			{
				return 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");
			byte[] array = StripCompressionHeader(data);
			object obj = methodInfo.Invoke(decompressor, new object[1] { array });
			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");
		}

		private static bool HasCompressionHeader(byte[] data)
		{
			if (data == null || data.Length < CompressionMagic.Length)
			{
				return false;
			}
			for (int i = 0; i < CompressionMagic.Length; i++)
			{
				if (data[i] != CompressionMagic[i])
				{
					return false;
				}
			}
			return true;
		}

		private static byte[] AddCompressionHeaderIfUseful(byte[] original, byte[] compressed)
		{
			if (compressed == null || original == null)
			{
				return original;
			}
			if (compressed.Length + CompressionMagic.Length >= original.Length)
			{
				return original;
			}
			byte[] array = new byte[compressed.Length + CompressionMagic.Length];
			Buffer.BlockCopy(CompressionMagic, 0, array, 0, CompressionMagic.Length);
			Buffer.BlockCopy(compressed, 0, array, CompressionMagic.Length, compressed.Length);
			return array;
		}

		private static byte[] StripCompressionHeader(byte[] data)
		{
			byte[] array = new byte[data.Length - CompressionMagic.Length];
			Buffer.BlockCopy(data, CompressionMagic.Length, array, 0, array.Length);
			return array;
		}

		[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 HashSet<string> s_seenAwakeNames = new HashSet<string>();

		private static int s_awakeLogsRemaining = 10;

		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_spawnsystem_heightmap = AccessTools.Field(typeof(SpawnSystem), "m_heightmap");

		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)
		{
			ServerStatusDiagnostics.s_uai_examined++;
			if ((Object)(object)__instance.m_nview == (Object)null)
			{
				ServerStatusDiagnostics.s_uai_bail_nviewNull++;
				return false;
			}
			if (!__instance.m_nview.IsValid())
			{
				ServerStatusDiagnostics.s_uai_bail_nviewInvalid++;
				return false;
			}
			if (__instance.m_nview.GetZDO() == null)
			{
				ServerStatusDiagnostics.s_uai_bail_zdoNull++;
				return false;
			}
			if ((Object)(object)__instance.m_character == (Object)null)
			{
				ServerStatusDiagnostics.s_uai_bail_charNull++;
				return false;
			}
			if (__instance.m_nview.IsOwner())
			{
				ServerStatusDiagnostics.s_uai_passThrough_isOwner++;
			}
			else
			{
				ServerStatusDiagnostics.s_uai_passThrough_notOwner++;
			}
			return true;
		}

		[HarmonyPatch(typeof(MonoUpdaters), "FixedUpdate")]
		[HarmonyPostfix]
		public static void MonoUpdaters_FixedUpdate_RollupDriver_Postfix()
		{
			ServerStatusDiagnostics.TryEmit();
		}

		[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
		[HarmonyPrefix]
		public static void MonsterAI_UpdateAI_Counter_Prefix()
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsDedicated())
			{
				ServerStatusDiagnostics.s_mai_examined++;
			}
		}

		[HarmonyPatch(typeof(BaseAI), "Awake")]
		[HarmonyPostfix]
		public static void BaseAI_Awake_Diagnostic_Postfix(BaseAI __instance)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsDedicated() && s_awakeLogsRemaining > 0)
			{
				string text = (((Object)(object)((Component)__instance).gameObject != (Object)null) ? ((Object)((Component)__instance).gameObject).name : "<null-go>");
				if (s_seenAwakeNames.Add(text))
				{
					s_awakeLogsRemaining--;
					LoggerOptions.LogMessage("[BaseAI.Awake] First-time mob '" + text + "' awoke server-side. " + $"Post-Awake BaseAI.Instances.Count={BaseAI.Instances.Count}, " + $"BaseAI.BaseAIInstances.Count={BaseAI.BaseAIInstances.Count}. " + $"(Remaining log budget: {s_awakeLogsRemaining}.)");
				}
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "CreateObject")]
		[HarmonyPostfix]
		public static void ZNetScene_CreateObject_Diagnostic_Postfix(GameObject __result)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsDedicated())
			{
				ServerStatusDiagnostics.s_co_calls++;
				if ((Object)(object)__result == (Object)null)
				{
					ServerStatusDiagnostics.s_co_nullReturns++;
				}
			}
		}

		[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_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: 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();
			if (!TryEnsureSpawnSystemHeightmap(__instance))
			{
				return false;
			}
			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;
		}

		private static bool TryEnsureSpawnSystemHeightmap(SpawnSystem ss)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ss == (Object)null || _f_spawnsystem_heightmap == null)
			{
				return false;
			}
			object? value = _f_spawnsystem_heightmap.GetValue(ss);
			Heightmap val = (Heightmap)((value is Heightmap) ? value : null);
			if ((Object)(object)val != (Object)null)
			{
				return true;
			}
			val = Heightmap.FindHeightmap(((Component)ss).transform.position);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			_f_spawnsystem_heightmap.SetValue(ss, val);
			return true;
		}

		[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