Decompiled source of FiresEasyBakeMeshes v1.2.15

FiresEasyBakeMeshes.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FiresCore.Async;
using FiresCore.Diagnostics;
using FiresCore.Help;
using FiresCore.Logging;
using FiresEasyBakeMeshes.EasyBake;
using FiresEasyBakeMeshes.Patches;
using FiresEasyBakeMeshes.Utilities;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("FiresEasyBakeMeshes")]
[assembly: AssemblyDescription("Per-zone static mesh batching for invulnerable pieces, plus prefab/material prewarm.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FiresEasyBakeMeshes")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6e5c6655-2d34-4d66-bbb0-be94bb3c5351")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FiresEasyBakeMeshes
{
	[BepInPlugin("com.Fire.FiresEasyBakeMeshes", "FiresEasyBakeMeshes", "1.2.15")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[DefaultExecutionOrder(1000)]
	public class FiresEasyBakeMeshesPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.Fire.FiresEasyBakeMeshes";

		public const string PluginName = "FiresEasyBakeMeshes";

		public const string PluginVersion = "1.2.15";

		public static ConfigEntry<bool> PluginEnabled;

		public static ConfigEntry<bool> VerboseZoneLogging;

		public static ConfigEntry<bool> BatchingEnabled;

		public static ConfigEntry<bool> BatchingRunOnServer;

		public static ConfigEntry<int> BatchingMinPiecesPerZone;

		public static ConfigEntry<int> BatchingMinPiecesPerBatch;

		public static ConfigEntry<float> BatchingSettleDelaySeconds;

		public static ConfigEntry<bool> BatchingFarTierEnabled;

		public static ConfigEntry<float> BatchingFarTierDistance;

		public static ConfigEntry<bool> BatchingInstancingEnabled;

		public static ConfigEntry<bool> BatchingCullOffScreen;

		public static ConfigEntry<bool> BatchingMultiPartPieces;

		public static ConfigEntry<float> BatchingBuildRadius;

		public static ConfigEntry<int> BatchingMinInstancesPerPrefab;

		public static ConfigEntry<bool> BatchingDamageablePieces;

		public static ConfigEntry<bool> BatchingVerbose;

		public static ConfigEntry<bool> BatchingExcludeTransparent;

		public static ConfigEntry<bool> SkipBakedPieceObjects;

		public static ConfigEntry<bool> PrewarmEnabled;

		public static ConfigEntry<bool> PrewarmRunOnServer;

		public static ConfigEntry<int> PrewarmPrefabsPerFrame;

		public static ConfigEntry<bool> PrewarmVerbose;

		public static ConfigEntry<string> PrewarmSkipNameContains;

		public static ConfigEntry<float> PrewarmSlowInstantiateThresholdMs;

		public static ConfigEntry<int> PrewarmMaxTransformCount;

		public static ConfigEntry<float> PrewarmFrameBudgetMs;

		public static ConfigEntry<float> MaterialRegistryFrameBudgetMs;

		public static ConfigEntry<bool> CachePersistEnabled;

		public static ConfigEntry<bool> CreateDestroySkipEnabled;

		public static ConfigEntry<float> CreateDestroySkipMaxSeconds;

		public static ConfigEntry<bool> CreateDestroySkipVerbose;

		public static ConfigEntry<bool> WearShortCircuitEnabled;

		public static ConfigEntry<bool> ZoneKeepaliveEnabled;

		public static ConfigEntry<int> ZoneKeepaliveRadius;

		public static ConfigEntry<float> ZoneKeepaliveSeconds;

		public static ConfigEntry<bool> ZoneKeepaliveVerbose;

		public static ConfigEntry<bool> DestroyTimeSliceEnabled;

		public static ConfigEntry<float> DestroyTimeSliceBudgetMs;

		public static ConfigEntry<bool> DestroyTimeSliceVerbose;

		public static ConfigEntry<bool> SectorMirrorEnabled;

		public static ConfigEntry<float> SectorMirrorRebuildSeconds;

		public static ConfigEntry<bool> SectorMirrorVerbose;

		public static ConfigEntry<bool> LightFlickerLodEnabled;

		public static ConfigEntry<float> LightFlickerLodDistance;

		public static ConfigEntry<float> LightFlickerMidDistance;

		public static ConfigEntry<float> LightFlickerFarDistance;

		public static ConfigEntry<float> LightFlickerMidRate;

		public static ConfigEntry<float> LightFlickerFarRate;

		public static ConfigEntry<float> LightFlickerDistantRate;

		public static ConfigEntry<float> LightFlickerTierCheckRate;

		public static ConfigEntry<bool> ZSFXLodEnabled;

		public static ConfigEntry<float> ZSFXLodDistance;

		public static ConfigEntry<bool> ZSyncStaticSkipEnabled;

		public static ConfigEntry<bool> ZSyncStaticSkipVerbose;

		public static ConfigEntry<bool> ClutterLodEnabled;

		public static ConfigEntry<float> ClutterLodMoveThreshold;

		public static ConfigEntry<float> ClutterLodMaxSeconds;

		public static ConfigEntry<bool> ClutterLodVerbose;

		private Harmony _harmony;

		private bool _patchesApplied;

		private void Awake()
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Expected O, but got Unknown
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Expected O, but got Unknown
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Expected O, but got Unknown
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: 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_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Expected O, but got Unknown
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Expected O, but got Unknown
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Expected O, but got Unknown
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Expected O, but got Unknown
			//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Expected O, but got Unknown
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_0460: Expected O, but got Unknown
			//IL_0493: Unknown result type (might be due to invalid IL or missing references)
			//IL_049d: Expected O, but got Unknown
			//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d6: Expected O, but got Unknown
			//IL_0509: Unknown result type (might be due to invalid IL or missing references)
			//IL_0513: Expected O, but got Unknown
			//IL_0586: Unknown result type (might be due to invalid IL or missing references)
			//IL_0590: Expected O, but got Unknown
			//IL_0619: Unknown result type (might be due to invalid IL or missing references)
			//IL_0623: Expected O, but got Unknown
			//IL_0656: Unknown result type (might be due to invalid IL or missing references)
			//IL_0660: Expected O, but got Unknown
			//IL_06d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06dd: Expected O, but got Unknown
			//IL_0750: Unknown result type (might be due to invalid IL or missing references)
			//IL_075a: Expected O, but got Unknown
			//IL_07cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d7: Expected O, but got Unknown
			//IL_080a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0814: Expected O, but got Unknown
			//IL_0847: Unknown result type (might be due to invalid IL or missing references)
			//IL_0851: Expected O, but got Unknown
			//IL_0884: Unknown result type (might be due to invalid IL or missing references)
			//IL_088e: Expected O, but got Unknown
			//IL_08c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_08cb: Expected O, but got Unknown
			//IL_08fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0908: Expected O, but got Unknown
			//IL_093b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0945: Expected O, but got Unknown
			//IL_0998: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a2: Expected O, but got Unknown
			//IL_0a35: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a3f: Expected O, but got Unknown
			//IL_0a72: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a7c: Expected O, but got Unknown
			//IL_0aac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ab6: Expected O, but got Unknown
			EasyBakeLog.Bind(((BaseUnityPlugin)this).Logger);
			try
			{
				FiresEasyBakeBanner.PrintBig();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Big banner failed: " + ex.Message));
			}
			Probe.Detect();
			PluginEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PluginEnabled", true, "Master kill switch. When off no Harmony patches are applied at all.");
			VerboseZoneLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Verbose Zone Logging", false, "Log the per-zone cache-hit and fresh-bake lines (one line per zone,\n~25-30 at login on a megabase). Off by default — the debounced\nZONES BAKED summary box carries the totals either way.");
			BatchingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Batching", "Enabled", true, "Workstream E.2 v1: at zone load, combine all invulnerable-piece meshes\ninto one batch per material. Per-piece MeshRenderers are disabled but\nGameObjects (and ZNetView, colliders, Piece) stay alive.");
			BatchingRunOnServer = ((BaseUnityPlugin)this).Config.Bind<bool>("Batching", "RunOnServer", false, "Run batching on dedicated server too. Default off — a headless server\ndoesn't render so Mesh.CombineMeshes() output is pure wasted CPU + memory.\nA player-hosted world (host + client in one process) still gets the benefit\nregardless of this setting; this gate only suppresses true dedicated servers.");
			BatchingMinPiecesPerZone = ((BaseUnityPlugin)this).Config.Bind<int>("Batching", "MinPiecesPerZone", 20, new ConfigDescription("Below this many invulnerable pieces in a zone, skip batching entirely.\nTiny invulnerable counts don't pay back the bake cost.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10000), Array.Empty<object>()));
			BatchingMinPiecesPerBatch = ((BaseUnityPlugin)this).Config.Bind<int>("Batching", "MinPiecesPerBatch", 10, new ConfigDescription("Below this many pieces sharing a material, that bucket passes through\nto vanilla rendering rather than getting its own combined mesh.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10000), Array.Empty<object>()));
			BatchingInstancingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Batching", "InstancingEnabled", true, new ConfigDescription("Draw uniform single-mesh prefabs (palisades, floor tiles, stakewalls)\nas GPU instances instead of merging them into a combined mesh. Costs no\nvertex duplication, and a removed piece drops out in O(1) instead of\nforcing the zone to rebake.", (AcceptableValueBase)null, Array.Empty<object>()));
			BatchingCullOffScreen = ((BaseUnityPlugin)this).Config.Bind<bool>("Batching", "SkipInstancesOutOfView", true, new ConfigDescription("Instanced pieces are handed to the graphics card again every frame, for every\nloaded zone, including the ones behind you. With this on, a group of instances\nwhose box is outside the camera is left out of the frame entirely. The box is\nstretched along the sun first, so shadows still land on what you can see.", (AcceptableValueBase)null, Array.Empty<object>()));
			BatchingMultiPartPieces = ((BaseUnityPlugin)this).Config.Bind<bool>("Batching", "MultiPartInstancing", true, new ConfigDescription("Draw pieces built from more than one mesh - vines, log poles, tiled roofs - as GPU\ninstances as well, one draw per mesh and material. Without it only prefabs that come\ndown to a single renderer are instanced and the rest are merged or left to draw\nthemselves. Applies to zones baked after a change.", (AcceptableValueBase)null, Array.Empty<object>()));
			BatchingMinInstancesPerPrefab = ((BaseUnityPlugin)this).Config.Bind<int>("Batching", "MinInstancesPerPrefab", 10, new ConfigDescription("A prefab needs at least this many copies in one zone before it is\ndrawn as instances. Below it the pieces fall through to mesh combining,\nwhere they still batch by material with everything else.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 10000), Array.Empty<object>()));
			BatchingDamageablePieces = ((BaseUnityPlugin)this).Config.Bind<bool>("Batching", "DamageablePieces", true, new ConfigDescription("Also draw building pieces that can take damage as GPU instances. They stay\nin the world, so rain wear, support and raids work as normal, and a piece\ngoes back to drawing itself the moment it is damaged, burns or is\nhighlighted by a hammer. Never skipped. Applies to zones baked after a change.", (AcceptableValueBase)null, Array.Empty<object>()));
			BatchingFarTierEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Batching", "FarTierEnabled", true, new ConfigDescription("Bake a second combined mesh per zone from each piece's LOD1 geometry\nand swap to it once the viewer is far enough away. Without it a baked\nzone draws full LOD0 detail at every distance.", (AcceptableValueBase)null, Array.Empty<object>()));
			BatchingFarTierDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Batching", "FarTierDistanceMeters", 64f, new ConfigDescription("Distance from the zone centre at which a baked zone swaps to its LOD1\nmesh. A zone is 64m across, so its centre is at most ~45m from any\npoint inside it — keep this at or above 64 and the swap can never\nhappen while you are standing in the zone watching it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(48f, 512f), Array.Empty<object>()));
			BatchingSettleDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Batching", "SettleDelaySeconds", 1.5f, new ConfigDescription("Wait this long after the last piece is added or removed in a zone\nbefore baking. Cooperates with VAGhetto's time-sliced instantiation:\npieces arrive across many frames, settle-delay debounces until the\nzone is stable. Each new piece resets the timer.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 30f), Array.Empty<object>()));
			BatchingVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Batching", "VerboseLogging", false, "Log per-zone classification and bake details.");
			BatchingExcludeTransparent = ((BaseUnityPlugin)this).Config.Bind<bool>("Batching", "ExcludeTransparentPieces", true, "Skip pieces with transparent-queue materials (renderQueue >= 2500) and\nFiresGlass windows. Combining transparent geometry into a static batch\nbreaks per-piece depth sorting — stained glass sorts against the world\nper pane, a merged mesh sorts once for the whole batch. Excluded pieces\nstay live and render normally.");
			SkipBakedPieceObjects = ((BaseUnityPlugin)this).Config.Bind<bool>("Batching", "SkipBakedPieceObjects", true, "Multiplayer clients only. Pieces a bake already draws are not created as game objects:\na stand-in collider takes each one's place, so they cost nothing per frame. Only\ninvulnerable, purely structural pieces qualify; anything that crafts, stores, lights,\nprotects, comforts or animates is always created. Real pieces come back while a build\ntool is out nearby, or when a skipped piece is removed, moved or loses invulnerability.\nNever runs on a server, host or single-player world.");
			SkipBakedPieceObjects.SettingChanged += delegate
			{
				if (!SkipBakedPieceObjects.Value)
				{
					ZoneTracker.HandBackAllSkipped();
				}
			};
			BatchingBuildRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Batching", "BuildToolRadiusMeters", 24f, new ConfigDescription("While a build tool is out, the real pieces come back within this many metres of you, so the\nhammer can snap to them, highlight them and take them down. Everything further away stays\nbaked. In a dense base this is the most expensive thing skipping does, so keep it near what\nyou can actually reach.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 256f), Array.Empty<object>()));
			PrewarmEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Prewarm", "Enabled", true, "Workstream B: at ZNetScene.Awake, instantiate every prefab in m_prefabs\nonce at (0, -1000, 0), SetActive(false), then Destroy. Pays the hidden\nfirst-Instantiate shader-compile / asset-bundle cost (5-35ms per heavy\nprefab) once during loading rather than at zone borders during gameplay.");
			PrewarmRunOnServer = ((BaseUnityPlugin)this).Config.Bind<bool>("Prewarm", "RunOnServer", false, "Run prewarm on dedicated server too. Default off — server doesn't render\nso it gains nothing from shader-variant warm-up.");
			PrewarmPrefabsPerFrame = ((BaseUnityPlugin)this).Config.Bind<int>("Prewarm", "PrefabsPerFrame", 25, new ConfigDescription("Batch size of the prewarm coroutine. 25 keeps each loading-screen\nframe under ~50ms even when a batch hits some 5ms heavy prefabs.\nHigher = faster total warm-up but choppier loading screen.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 500), Array.Empty<object>()));
			PrewarmVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Prewarm", "VerboseLogging", false, "Log every prefab + per-prefab ms during warm-up. Off by default; the\nsummary line carries totals + worst-single only.");
			PrewarmSkipNameContains = ((BaseUnityPlugin)this).Config.Bind<string>("Prewarm", "SkipNameContains", "", "Comma-separated list of case-insensitive substrings. Any prefab whose\nname contains one of these tokens is skipped during prewarm. Empty by\ndefault — main-thread responsiveness is preserved by the time-budgeted\nyield pattern (see TimeBudgetMs below), not by skipping. Use this\nconfig only when a specific prefab is misbehaving badly enough that\nyou'd rather pay the first-instantiate cost in-game than at load.");
			PrewarmFrameBudgetMs = ((BaseUnityPlugin)this).Config.Bind<float>("Prewarm", "FrameBudgetMs", 8f, new ConfigDescription("Time-budgeted yield: after each Instantiate, if the elapsed wall\ntime on THIS frame exceeds this many ms, the coroutine yields and\nthe next prefab runs on the next frame. Keeps the main thread\nresponsive (loading screen + any open dialogs stay interactive)\nat the cost of longer total wall time. A single very-slow prefab\n(e.g. ConsMassiveTower's ~30s first-Instantiate) will still freeze\nthe frame it lands on — Unity's shader-variant compile is\nsynchronous and can't be yielded mid-Instantiate — but every\nother prefab around it stops piling on. Lower = smoother but\nlonger. 8ms ≈ half a 16ms frame budget.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			PrewarmSlowInstantiateThresholdMs = ((BaseUnityPlugin)this).Config.Bind<float>("Prewarm", "SlowInstantiateThresholdMs", 5000f, new ConfigDescription("If a single prefab's Instantiate takes longer than this many ms,\nlog a warning naming the prefab AND persist it to\nconfig/FiresEasyBakeMeshes/prewarm_slow_skips.txt, so every future\nsession skips it before instantiating (delete a line from that file\nto give a prefab another chance, e.g. after removing the mod that\nmade it slow). 0 to disable the runtime detector entirely.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60000f), Array.Empty<object>()));
			PrewarmMaxTransformCount = ((BaseUnityPlugin)this).Config.Bind<int>("Prewarm", "MaxTransformCount", 800, new ConfigDescription("Skip any prefab whose transform hierarchy exceeds this many nodes,\nWITHOUT instantiating it. A single Instantiate is atomic on the main\nthread — the frame budget cannot split it — and combined-build\nmega-prefabs (e.g. ConsMassiveTower, ~29s) freeze the whole client\non their first-ever warm-up, which the slow-instantiate detector\nabove can only prevent from the SECOND session on. The node count is\na cheap capped traversal; skipped prefabs warm on first real spawn\ninstead. Normal pieces are tens of nodes; only combined builds reach\nthe hundreds. 0 to disable the gate.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100000), Array.Empty<object>()));
			MaterialRegistryFrameBudgetMs = ((BaseUnityPlugin)this).Config.Bind<float>("Cache", "MaterialRegistryFrameBudgetMs", 4f, new ConfigDescription("Time-budgeted yield for the material-registry build pass that\nruns on ZNetScene.Awake (BEFORE prewarm starts). The build walks\nevery prefab's MeshRenderers to index sharedMaterials by name —\non a 5000+ prefab world this can take seconds synchronously,\nand the freeze lands right around the password-prompt /\nloading-screen-first-frame window. Yielding every Nms keeps the\nmain thread interactive during that build. Lower = smoother but\nmore total wall time. 4ms is roughly a quarter of a 16ms frame.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			CachePersistEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Cache", "PersistToDisk", true, "Save baked meshes to BepInEx/config/FiresEasyBakeMeshes/cache/<worldUid>/\nand reload them on subsequent sessions of the same world. Eliminates the\nper-zone Mesh.CombineMeshes cost on re-entry — disk read + Mesh.SetVertices\nis ~4x faster than rebuilding from source pieces. Disable to always rebake\n(useful when debugging or after admin-removing pieces, which the cache\ncan't detect and would leave as ghost geometry).");
			CreateDestroySkipEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "CreateDestroySkipEnabled", true, "Skip ZNetScene.CreateDestroyObjects when the player hasn't crossed a sector\nboundary AND no zone has loaded/unloaded since the last call. Vanilla does\na full O(loaded ZNetView) walk every 33ms; at a megabase that's ~6 ms/tick\nof pure overhead finding zero things to remove. Skipping reclaims that for\nthe steady-state case (stationary at base). Set false to use pure vanilla.");
			CreateDestroySkipMaxSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "CreateDestroySkipMaxSeconds", 1f, new ConfigDescription("Maximum time to skip CreateDestroyObjects even when nothing has changed.\nForces a vanilla pass at this cadence so server-pushed ZDOs (creature\nspawns, remote player drops) eventually get instantiated on the client.\nLower = more responsive to network events, less optimization gain.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			CreateDestroySkipVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "CreateDestroySkipVerbose", false, "Log a periodic summary of how many CreateDestroyObjects ticks we skipped.");
			WearShortCircuitEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "WearShortCircuitInvulnerable", true, "Skip WearNTear.UpdateWear and UpdateCover for invulnerable pieces.\nInvulnerable pieces (m_health < 0 or all-Immune damage modifiers)\ncan't take damage, so vanilla's per-piece wet/roof/support/biome/lava\ncomputation is wasted work — CanBeRemoved() zeros the accumulated\ndamage at the bottom of the method. At a megabase WearNTearUpdater is\nthe single largest per-frame cost; this short-circuit reclaims roughly\n30 ms/sec. Disable only if a mod conflict requires vanilla behavior.");
			ZoneKeepaliveEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "ZoneKeepaliveEnabled", true, "Pin baked zones in ZNetScene.m_instances when the player walks outside\nthe active ring, instead of letting vanilla destroy and re-Instantiate\nthem on the next zone-cross. Eliminates the multi-hundred-ms hitches\nfrom cache-mesh reconstruction + mass re-Instantiate when moving around\ntown. Memory cost scales with KeepaliveRadius; CPU cost is near zero\nwith the WearNTear short-circuit also enabled.");
			ZoneKeepaliveRadius = ((BaseUnityPlugin)this).Config.Bind<int>("Optimize", "ZoneKeepaliveRadius", 15, new ConfigDescription("Max zone-distance from the player to keep baked zones pinned. Beyond\nthis radius the zone is released and vanilla destroys its instances.\nEach zone is 64m. Default 15 = 960m radius — wide enough to cover\nRender Limits' extended view (typically +12 zones) so zones at the\nedge of the rendered area don't get destroyed when you walk around\nwithin town. With ~30 baked zones at a megabase the memory cost is\nbounded by the bake set, not the radius. Raise to 25-50 for very\nwide cities; drop to 5 for stock-vanilla active area.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
			ZoneKeepaliveSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "ZoneKeepaliveSeconds", 60f, new ConfigDescription("How long a baked zone stays pinned after the player last had it in\nthe keepalive radius. After this, even though it's still tracked,\nthe zone is released and vanilla destroys its instances on the next\nCreateDestroyObjects tick. Prevents stale pins from accumulating\nduring long travel sessions.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 600f), Array.Empty<object>()));
			ZoneKeepaliveVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "ZoneKeepaliveVerbose", false, "Log a periodic summary of how many zones are pinned and the refresh /\nprune deltas. Useful for tuning the radius when paired with the\nFiresDebugginTools profile output.");
			DestroyTimeSliceEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "DestroyTimeSliceEnabled", true, "Replace ZNetScene.RemoveObjects' single-tick destroy loop with a queued,\ntime-budgeted version. Vanilla destroys every unearmarked instance in\none frame; at megabase scale with Render Limits expanding the loaded\nring, a single zone-cross can drop 10k+ pieces and produce a 100+ms\nframe hitch. Time-slicing spreads the destroys across multiple frames\nso the work is paced rather than spiked. Same total CPU cost, far\nsmoother frame distribution. Disable to use vanilla destroy semantics.");
			DestroyTimeSliceBudgetMs = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "DestroyTimeSliceBudgetMs", 3f, new ConfigDescription("Per-frame ms budget for the destroy queue. Higher = drains faster\nbut allows bigger spikes; lower = smoother frames but the queue\ntakes more wall-clock time to drain. Default 3ms keeps a 10k-piece\nunload at ~5ms peak frame impact and drains in ~3 seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>()));
			DestroyTimeSliceVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "DestroyTimeSliceVerbose", false, "Log a periodic summary of destroyed / re-earmark-skipped counts and\ncurrent queue depth. Useful for confirming the slicer is draining at\nthe configured rate and not falling perpetually behind.");
			SectorMirrorEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "SectorMirrorEnabled", true, "Maintain a per-sector instance-count mirror of ZNetScene.m_instances and\nintercept ZNetScene.HaveInstanceInSector with an O(1) dictionary lookup.\nVanilla walks every entry in m_instances (146k+ at megabase) for each\nZoneSystem.UpdateTTL zone check — profile shows ZoneSystem.Update\nspiking to 80+ ms/call during in-town movement. The mirror eliminates\nthat scan. Staleness from instances that move sectors after spawn\n(creatures, ships) is corrected by a periodic full rebuild.");
			SectorMirrorRebuildSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "SectorMirrorRebuildSeconds", 60f, new ConfigDescription("How often to rebuild the sector mirror from scratch. The rebuild\nwalks m_instances once (cost similar to one vanilla HaveInstanceInSector\ncall) and corrects any drift from instances that moved sectors since\ninstantiation. Lower = tighter accuracy, slightly more cost; higher =\nlonger-lived false positives (zones held alive after their creature\nwandered away). 60s is the default sweet spot. Set 0 to disable rebuilds\nentirely (only safe for fully-static worlds).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>()));
			SectorMirrorVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "SectorMirrorVerbose", false, "Log a line each time the sector mirror rebuilds, showing tracked ZDO\nand sector counts. Useful for verifying the mirror is staying populated.");
			LightFlickerLodEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "LightFlickerLodEnabled", true, "Distance-tiered throttling of LightFlicker.CustomUpdate. Vanilla runs\nflicker math (6+ sin/cos calls + position jitter) every frame for every\nlit prefab in the scene; at a megabase with hundreds of torches/braziers\nthis aggregates to 8-10 ms/sec. Distant lights update less often instead\nof being skipped outright — vanilla zeroes a light's intensity when it is\nenabled and only CustomUpdate writes it back, so a light that never ticks\nrenders black. Skipped time is banked and handed to the next real update,\nso flicker and fade still run at the correct speed. Temporary FX lights\n(m_ttl > 0) and lights still fading in always run every frame.");
			LightFlickerLodDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "LightFlickerLodDistance", 30f, new ConfigDescription("Radius in meters within which lights flicker at full vanilla rate.\nBeyond it they step down through the mid / far / distant tiers below.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 200f), Array.Empty<object>()));
			LightFlickerMidDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "LightFlickerMidDistance", 60f, new ConfigDescription("Outer radius of the mid tier. Lights between LightFlickerLodDistance\nand this distance update at LightFlickerMidRate.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 300f), Array.Empty<object>()));
			LightFlickerFarDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "LightFlickerFarDistance", 100f, new ConfigDescription("Outer radius of the far tier. Lights between LightFlickerMidDistance\nand this distance update at LightFlickerFarRate; anything beyond uses\nLightFlickerDistantRate.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 500f), Array.Empty<object>()));
			LightFlickerMidRate = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "LightFlickerMidRate", 10f, new ConfigDescription("Updates per second for lights in the mid distance tier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>()));
			LightFlickerFarRate = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "LightFlickerFarRate", 5f, new ConfigDescription("Updates per second for lights in the far distance tier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			LightFlickerDistantRate = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "LightFlickerDistantRate", 2f, new ConfigDescription("Updates per second for lights beyond LightFlickerFarDistance. Keep\nabove zero so distant lights still receive an intensity write.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			LightFlickerTierCheckRate = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "LightFlickerTierCheckRate", 2f, new ConfigDescription("How often each light re-measures its distance tier. Caching the tier\nis what removes the per-frame distance math; raise it only if lights\nvisibly lag a tier change while you sprint past them.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			ZSFXLodEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "ZSFXLodEnabled", true, "Distance-LOD on ZSFX.CustomUpdate. ZSFX is Valheim's per-sound wrapper\naround Unity's AudioSource — manages fade in/out, pitch/volume modifiers,\nreverb routing, and concurrency suppression. It ticks every frame on every\nactive sfx in the scene; at a megabase with hundreds of torch / brazier /\nfountain loops this aggregates to ~3 ms/sec. Unity's audio engine handles\nspatial attenuation independently of CustomUpdate, so beyond the audible\nfalloff radius the per-frame housekeeping has no perceptible effect on what\nthe player hears. We skip CustomUpdate entirely beyond the configured\ndistance; the AudioSource keeps its last set volume / pitch which already\nattenuates to ~zero at that range.");
			ZSFXLodDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "ZSFXLodDistance", 60f, new ConfigDescription("Distance in meters beyond which ZSFX.CustomUpdate is skipped. 60 m\nis conservative — most ambient sfx have AudioSource.maxDistance under\n50 m so they're inaudible past that even when CustomUpdate is still\nrunning. Music and ambient zones have longer reach; raise this if you\nhear audio pop in/out at the edge of your hearing range. Lower for\nmore aggressive savings.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 200f), Array.Empty<object>()));
			ZSyncStaticSkipEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "ZSyncStaticSkipEnabled", true, "Disable ZSyncTransform on player-built Pieces that never move. ZSyncTransform\nis an IMonoUpdater that ticks every frame on every active instance, even when\nthe piece is a static wall whose position has been settled since placement.\nSetting enabled=false on the component removes it from ZSyncTransform.Instances\nvia OnDisable so the per-frame iteration stops visiting it.\n\nEligibility is narrow and conservative: must be a Piece (player-built), must\nhave no parent transform (rules out ship/cart attachments), no body-velocity\nor character-parent sync flag, no non-kinematic Rigidbody, and no component\nfrom the animated/interactable safelist (Door, Container, Sign, Smelter,\nCookingStation, Fireplace, Pickable, TeleportWorld, Bed, Ship, Vagon,\nMineRock, ShieldGenerator, …) — the same surface as the mesh-bake unsafe\nfilter plus all interactables.\n\nRisk surface: in solo this is essentially free. In multiplayer an admin\nteleport on a static piece won't propagate to other clients until reload.\nDisable this toggle if you hit a sync issue in MP and we'll look at it.");
			ZSyncStaticSkipVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "ZSyncStaticSkipVerbose", false, "Log a periodic summary of how many pieces have had their ZSync disabled and\nhow many prefabs are in the eligibility cache. Useful for verifying the\nfilter is hitting your prefab set as expected after a deploy.");
			ClutterLodEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "ClutterLodEnabled", true, "Skip ClutterSystem.LateUpdate while the player is standing still. Vanilla\nre-walks the full grass-patch ring around the camera TWICE every frame\n(generate + timeout, ~120 patches at default range) even when parked —\nFiresDebugginTools measures this at ~3 ms EVERY frame, the largest steady\ncost on a natural (non-megabase) world. The grass set is identical frame to\nframe while stationary, so we skip the pass until the player moves, with a\nshort TTL (below) keeping it ticking a few times a second and an immediate\nescape when a rebuild is pending (terrain edit, quality change, ResetGrass).\nMoving = full vanilla every frame, so grass-in and the player push effect\nare unchanged. Disable if you see grass not refreshing while standing still.");
			ClutterLodMoveThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "ClutterLodMoveThreshold", 0.25f, new ConfigDescription("How far (meters) the player must move from the last clutter pass before\nClutterSystem.LateUpdate runs again. Below this the player counts as\nparked and the pass is skipped. 0.25 m skips only when genuinely still;\ncamera rotation / mouse-look doesn't move the player so it still skips.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 8f), Array.Empty<object>()));
			ClutterLodMaxSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Optimize", "ClutterLodMaxSeconds", 0.33f, new ConfigDescription("Maximum time ClutterSystem.LateUpdate is skipped while parked before a\nforced vanilla pass. Keeps the grass-push trail decaying and picks up\nasync heightmap-ready transitions. Lower = more responsive, less savings;\nhigher = more savings, longer-lived frozen push trail. 0.33s ≈ 3 Hz.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 5f), Array.Empty<object>()));
			ClutterLodVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimize", "ClutterLodVerbose", false, "Log a one-line summary every ~5 seconds tallying ClutterLod calls: how many were\nskipped vs passed through, and the reason for each passthrough (moved past threshold,\nttl expired, m_forceRebuild pending, no local player, freefly, disabled). Useful when\nClutterSystem.LateUpdate cost in the FiresDebugginTools overlay doesn't drop while\nparked — the line will tell you whether the prefix is even being called, and if so,\nwhat's forcing it to pass through to vanilla.");
			MeshCacheStore.Initialize();
			_harmony = new Harmony("com.Fire.FiresEasyBakeMeshes");
			PluginEnabled.SettingChanged += delegate
			{
				if (PluginEnabled.Value && !_patchesApplied)
				{
					ApplyPatches();
					EasyBakeLog.Info("FiresEasyBakeMeshes re-enabled via config — patches restored.");
				}
				else if (!PluginEnabled.Value && _patchesApplied)
				{
					RemovePatches();
					EasyBakeLog.Info("FiresEasyBakeMeshes disabled via config — patches removed, subsystem state reset.");
				}
			};
			if (PluginEnabled.Value)
			{
				ApplyPatches();
			}
			else
			{
				EasyBakeLog.Info("FiresEasyBakeMeshes v1.2.15 loaded but PluginEnabled=false — no patches applied. Flip PluginEnabled to true in the config manager to enable live (no restart needed).");
			}
			try
			{
				EbmHelpContent.Register();
			}
			catch (Exception ex2)
			{
				EasyBakeLog.Warn("Help registration failed: " + ex2.Message);
			}
			((MonoBehaviour)this).StartCoroutine(EmitCompactBannerWhenZNetReady());
		}

		private IEnumerator EmitCompactBannerWhenZNetReady()
		{
			while ((Object)(object)ZNetScene.instance == (Object)null || ZNetScene.instance.m_prefabs == null || ZNetScene.instance.m_prefabs.Count == 0)
			{
				yield return null;
			}
			yield return (object)new WaitForEndOfFrame();
			try
			{
				FiresEasyBakeBanner.Print();
			}
			catch (Exception ex)
			{
				EasyBakeLog.Info("FiresEasyBakeMeshes v1.2.15 loaded. (banner failed: " + ex.Message + ")");
			}
		}

		private void ApplyPatches()
		{
			if (_patchesApplied)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			Type[] types = typeof(FiresEasyBakeMeshesPlugin).Assembly.GetTypes();
			foreach (Type type in types)
			{
				if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0)
				{
					try
					{
						_harmony.CreateClassProcessor(type).Patch();
						num++;
					}
					catch (Exception ex)
					{
						num2++;
						EasyBakeLog.Error("Patch " + type.Name + " failed: " + ex.Message);
					}
				}
			}
			_patchesApplied = true;
			EasyBakeLog.Info(string.Format("{0} v{1} active — {2} patches registered, {3} skipped. ", "FiresEasyBakeMeshes", "1.2.15", num, num2) + "Batching=" + (BatchingEnabled.Value ? "on" : "off") + ", Prewarm=" + (PrewarmEnabled.Value ? "on" : "off") + ".");
		}

		private void RemovePatches()
		{
			if (!_patchesApplied)
			{
				return;
			}
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch (Exception ex)
			{
				EasyBakeLog.Error("UnpatchSelf failed: " + ex.Message);
			}
			try
			{
				ZoneTracker.Reset();
			}
			catch
			{
			}
			try
			{
				ZNetScene_CreateDestroyObjects_Patch.ResetState();
			}
			catch
			{
			}
			try
			{
				ClutterSystem_LateUpdate_Patch.ResetState();
			}
			catch
			{
			}
			_patchesApplied = false;
		}

		private void OnDestroy()
		{
			RemovePatches();
		}

		private void Update()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			if (CachePersistEnabled.Value)
			{
				long num = MeshCacheStore.TryGetWorldUid();
				if (num != 0L)
				{
					MeshCacheStore.KickPreload(num);
				}
			}
			BakeSummary.Update();
			if (BatchingActive())
			{
				long start = Probe.Start();
				long timestamp = Stopwatch.GetTimestamp();
				ZoneTracker.Update();
				InstancedDraw.NoteZoneTracking(Stopwatch.GetTimestamp() - timestamp);
				Probe.Stop("EasyBake:zoneTrack", start);
				if (ZoneKeepaliveEnabled.Value && (Object)(object)ZNet.instance != (Object)null && (Object)(object)ZoneSystem.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null)
				{
					Vector2s zone = ZoneSystem.GetZone(ZNet.instance.GetReferencePosition());
					SimulationDistance syncedSimulationDistance = ZNet.instance.GetSyncedSimulationDistance();
					int nearSimulationDistance = ((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance;
					long start2 = Probe.Start();
					ZoneKeepalive.Update(zone, nearSimulationDistance);
					Probe.Stop("EasyBake:keepalive", start2);
				}
				if (SectorMirrorEnabled.Value && (Object)(object)ZNetScene.instance != (Object)null)
				{
					long start3 = Probe.Start();
					SectorInstanceMirror.MaybeRebuild(ZNetScene.instance);
					Probe.Stop("EasyBake:sectorMirror", start3);
				}
				StaticPieceZSyncSkip.MaybeReport();
			}
		}

		private void LateUpdate()
		{
			if (BatchingActive())
			{
				ZoneTracker.DrawInstances();
			}
		}

		public static bool BatchingActive()
		{
			if (!PluginEnabled.Value)
			{
				return false;
			}
			if (!BatchingEnabled.Value)
			{
				return false;
			}
			if (BatchingRunOnServer.Value)
			{
				return true;
			}
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				return !ZNet.instance.IsDedicated();
			}
			return true;
		}
	}
	internal static class EasyBakeLog
	{
		private static ManualLogSource _log;

		public static ManualLogSource Source => _log;

		public static void Bind(ManualLogSource log)
		{
			_log = log;
		}

		public static void Info(string msg)
		{
			if (_log != null)
			{
				_log.LogMessage((object)msg);
			}
		}

		public static void Debug(string msg)
		{
			if (_log != null)
			{
				_log.LogInfo((object)msg);
			}
		}

		public static void Warn(string msg)
		{
			if (_log != null)
			{
				_log.LogWarning((object)msg);
			}
		}

		public static void Error(string msg)
		{
			if (_log != null)
			{
				_log.LogError((object)msg);
			}
		}
	}
	internal static class FiresEasyBakeBanner
	{
		private static bool s_compactPrinted;

		private static readonly Segment[][] s_compactLines = new Segment[12][]
		{
			(Segment[])(object)new Segment[1]
			{
				new Segment("                ) ) )", ConsoleColor.Yellow)
			},
			(Segment[])(object)new Segment[1]
			{
				new Segment("               ( ( (", ConsoleColor.DarkYellow)
			},
			(Segment[])(object)new Segment[1]
			{
				new Segment("            ┌───────────┐", ConsoleColor.DarkGray)
			},
			(Segment[])(object)new Segment[3]
			{
				new Segment("            │ ", ConsoleColor.DarkGray),
				new Segment("▌ ▣ ▣ ▣ ▐", ConsoleColor.Red),
				new Segment(" │", ConsoleColor.DarkGray)
			},
			(Segment[])(object)new Segment[1]
			{
				new Segment("            └───────────┘", ConsoleColor.DarkGray)
			},
			(Segment[])(object)new Segment[1]
			{
				new Segment("   ╔══════════════════════════╗", ConsoleColor.DarkGray)
			},
			(Segment[])(object)new Segment[5]
			{
				new Segment("   ║   ", ConsoleColor.DarkGray),
				new Segment("[", ConsoleColor.Gray),
				new Segment("██████████████████", ConsoleColor.Green),
				new Segment("]", ConsoleColor.Gray),
				new Segment("   ║", ConsoleColor.DarkGray)
			},
			(Segment[])(object)new Segment[3]
			{
				new Segment("   ║        ", ConsoleColor.DarkGray),
				new Segment("\ud83e\uddf1 OVEN HOT", ConsoleColor.Yellow),
				new Segment("       ║", ConsoleColor.DarkGray)
			},
			(Segment[])(object)new Segment[1]
			{
				new Segment("   ╚══════════════════════════╝", ConsoleColor.DarkGray)
			},
			(Segment[])(object)new Segment[1]
			{
				new Segment("    FIRES EASY BAKE MESHES", ConsoleColor.Cyan)
			},
			(Segment[])(object)new Segment[0],
			(Segment[])(object)new Segment[1]
			{
				new Segment("   Fires Easy Bake Meshes Loaded", ConsoleColor.Magenta)
			}
		};

		private static readonly (string text, ConsoleColor color)[] s_bigLines = new(string, ConsoleColor)[70]
		{
			("", ConsoleColor.Gray),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Red),
			("%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%++%%%@%%%%%%++%%%%%%%%%%++%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkRed),
			("%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%==+%%%%%%%%%==+%%@@%%%%%==+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Red),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%+=@%%%%%%%%%+=@%%%%%%%%%+=@%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkRed),
			("%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%@%%%+=%%++%%%%%%+=%%++%%%%%%+=%%++%%%%%%@%%%%%%%%%%%%%%@%%%%%%%@%%%", ConsoleColor.Red),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+=%@+==*%%%%+=%%+==*%%%%+=%%+==*%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%", ConsoleColor.DarkRed),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%==+%%=+%%%%%==+%%=+%%%%%==+%%=+%%%%%%%%%%%%@%%%%%%%%%@%%%%%%%%", ConsoleColor.Red),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++%%+=%%%%%%++@%+=%%%%%%++%%+=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkRed),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%==%%%%%%%%%%==%%%%%%%%%%==%%@%%%%%%%%%%%%%%%%%%@%%%%%%%%%", ConsoleColor.Red),
			("%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%++=+%%%%%%%%++=+%%%%%%%%++=+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-:::::::::::::::::::::::::::::::::::::::::::*%%%%%%%%%%%%%%@%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-:::::::::::::::::::::::::::::::::::::::::::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%@@%%%%%%%%%%%%%%%%-:::::::::::::::::::::::::::::::::::::::::::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%@%%%%%%%%-::+*************************************-::*%%%%%%%%%@%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%@%%%%%-::*%%@%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%-::*%%%%%%%@%%%%%%%%%%%%%%%@%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%%%%%%%%%%%@%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%@%%%%%%%%%%@%%%%%%%%%-::*@%%%@%%%%%%--::::::::::--%%%%%%%%%%%%-::*%%%%%%%%@%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%@-::*%%%%%%%%#-:..............:--%%%%%%%%%-::*%%%%%%%%%%%%%@%%%%%%%@%%@%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%%%%-:...::-------::.....-*%%%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%@%%%%%%-::*%@%%%*:...:-%%-:--------:....:-%%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%@%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%%:..:-%%-::--------::-::..:-%%%%%-::*%%@%%%%%%%%%%%@%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("%%@%%%%%%%%%%%%%%@%%%%%%%%%%-::*%%%%-..:-%@%-:--------::%-:@:..:%%%%%-::*%%@%%%%%%%%%%%@%%%%%%%%@%@%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%@%%%%%%%%%%%%-::*%%%%:..-%%%%-:%%%%%%%%-:%-:%-...@%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%:..-%%%%-:%%%%%%%%-:%-:%%:..*%%%%-::*%%%%%%%%%%%%%%%%%@%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%:..-%%%%-:%%%%%%%%-:%-:%-...#%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%-..:-%%%-:%%%%%%%%-:-:-%:..:%%%%%-::*%%%%%%%%%%%%%@%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%%:..:-%%-:---------.:+=:..:-%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%@%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%@-::*%%%%%-:...:-------------=-:..:-%%%%%%-::*%%@%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%%%@-....:---%%%%---:....:-%%%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%@%%%%%%--:...............:-%%%%%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%%%%%%%%--::......:::-*%%%%%%%%%%%-::*%%%%%%%%%%%%@%%%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("@%%%%%%%%%%@%%%%%%%%%%%%%%%%-::*%%%%%%%%%%%%%%%%%**#%%%%%%%%%%%@%%%%@-::*%%%%%%%%%%%%%%%%@%%%%%%%@%%", ConsoleColor.Yellow),
			("%%%%@%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-::*%%%%%%%%%%%%%%@%@%%@%%%%%%%%%%%%%%%%%-::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-:::::::::::::::::::::::::::::::::::::::::::*%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%@%-:::::::::::::::::::::::::::::::::::::::::::*%%%@%%%%%%%%%%%%%%%%%@%%%%%", ConsoleColor.DarkYellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%-:::::::::::::::::::::::::::::::::::::::::::*%%%%%%@%%@%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%@%%%@%%%%%**-::::+*****************************-::::+*#%%%%%%%%%%@%%%%%%%%%%%%%%%%", ConsoleColor.DarkYellow),
			("@%%@%%%%%%%%%%%%%%%%%%%%%%%%%%-::::*%%%%%%%@@@%%%%%%%%%%%%%%%%%%%-::::*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkGray),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*****#%%%%%%%%%@%%%%%%%%%%%%%%%%%%%*****#%%%%%%%%%%%@%%%%%%%%%%%%%%%%%", ConsoleColor.DarkGray),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%", ConsoleColor.DarkGray),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%", ConsoleColor.DarkGray),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkGray),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkGray),
			("%%%%%%%%%%%%%%%%%%@%%%%%%@%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkGray),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.White),
			("%%%%%%%@-:::::::%%:::::::%%#::....:-%-:::-%::::#%%%-::::::::-%%%::::::-%%-::::%::::--:::::::%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%-......:%%......:%%:...::...-#...:-...:%%%%-....:....%%+......:%%:...:-...:%-......:%%%%%%%%", ConsoleColor.White),
			("%%%%%%%%-...:%%%%-...:...=%:...:-:::-%-...:...%%@%%-....%:...%%-.......%%:...:....-%-...:%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%-....::-%:...:...-%-.....:-@%%%:.....-%%%%@-....:...:%%:...-...-%:.......-%%-....::-%%%%%%%%", ConsoleColor.White),
			("%%%%%%%%-......-%:...@...:%%-::.....-%%-....:%%%%%%-....:...:-%....-...:%:.......:%%-......-%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%-...:%%%@....:....%-:::-:...:%%%:...-%@%@%%-....%:...--....:....%:........-%-...:%%%%%%%%%%%", ConsoleColor.White),
			("%%%%%%%%-....::--....:....-:...:-...:%%%:...+%%%%%%-....-....-:....:....-:...::...:%-....::-%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%-.......:...:%:...:-:.......-%%@:...+%%%%%%-.........-:...:%:...::...:=....--......:%%%%%%%%", ConsoleColor.White),
			("%%%%%%@%-------------%-----%%------%%%%%----+%%%%%%---------%%-----%----------%-------------%%%%%%%@", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%", ConsoleColor.White),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%@%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%@%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.White),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%@%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.White),
			("%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.Yellow),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%@%%%%%@@%@%%%%%%%%%%%%%@%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkGray),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkGray),
			("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkGray),
			("@%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", ConsoleColor.DarkGray),
			("@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%", ConsoleColor.DarkGray),
			("", ConsoleColor.Gray)
		};

		public static void PrintBig()
		{
			try
			{
				EmitHeader("Fires Easy Bake Meshes Loading...");
				Banner.Print(ToSegments(s_bigLines));
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[FiresEasyBakeMeshes] Big banner failed: " + ex.Message));
			}
		}

		public static void Print()
		{
			if (s_compactPrinted)
			{
				return;
			}
			s_compactPrinted = true;
			try
			{
				EmitHeader("Fires Easy Bake Meshes Loaded.");
				Banner.Print(s_compactLines);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[FiresEasyBakeMeshes] Compact banner failed: " + ex.Message));
			}
		}

		private static void EmitHeader(string text)
		{
			if (EasyBakeLog.Source != null)
			{
				EasyBakeLog.Source.LogInfo((object)text);
			}
			else
			{
				Debug.Log((object)("[FiresEasyBakeMeshes] " + text));
			}
		}

		private static Segment[][] ToSegments((string text, ConsoleColor color)[] lines)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Segment[][] array = new Segment[lines.Length][];
			for (int i = 0; i < lines.Length; i++)
			{
				array[i] = (Segment[])(object)new Segment[1]
				{
					new Segment(lines[i].text, lines[i].color)
				};
			}
			return array;
		}
	}
	internal static class BakeSummary
	{
		private const float DebounceSeconds = 5f;

		private static readonly TaggedEmitter Emitter = LoadSummary.For("FiresEasyBakeMeshes");

		private static int _zonesFromCache;

		private static int _zonesBakedFresh;

		private static int _batches;

		private static long _totalMs;

		private static float _lastEventUnscaledTime = -1f;

		public static void RecordCacheConstruct(int batches, long elapsedMs)
		{
			_zonesFromCache++;
			_batches += batches;
			_totalMs += elapsedMs;
			_lastEventUnscaledTime = Time.unscaledTime;
		}

		public static void RecordFreshBake(int batches, long elapsedMs)
		{
			_zonesBakedFresh++;
			_batches += batches;
			_totalMs += elapsedMs;
			_lastEventUnscaledTime = Time.unscaledTime;
		}

		public static void Update()
		{
			if (!(_lastEventUnscaledTime < 0f) && !(Time.unscaledTime - _lastEventUnscaledTime < 5f))
			{
				((TaggedEmitter)(ref Emitter)).EmitMiniBox("\ud83e\uddf1 ZONES BAKED", new string[4]
				{
					$"from cache : {_zonesFromCache}",
					$"baked fresh: {_zonesBakedFresh}",
					$"batches    : {_batches}",
					$"total time : {_totalMs}ms"
				});
				_zonesFromCache = 0;
				_zonesBakedFresh = 0;
				_batches = 0;
				_totalMs = 0L;
				_lastEventUnscaledTime = -1f;
			}
		}
	}
}
namespace FiresEasyBakeMeshes.Patches
{
	[HarmonyPatch(typeof(ZNetScene), "CreateObject")]
	public static class ZNetScene_CreateObject_Skip_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix(ZDO zdo, ref GameObject __result, bool __runOriginal)
		{
			if (!__runOriginal)
			{
				return false;
			}
			bool flag;
			try
			{
				flag = ZoneTracker.TrySkipCreation(zdo);
			}
			catch (Exception ex)
			{
				ZoneTracker.LogSkipFailureOnce(ex);
				flag = false;
			}
			if (!flag)
			{
				return true;
			}
			__result = null;
			return false;
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "IsAreaReady")]
	public static class ZNetScene_IsAreaReady_Skip_Patch
	{
		[HarmonyPostfix]
		public static void Postfix(Vector3 point, ref bool __result)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (__result)
			{
				return;
			}
			try
			{
				if (ZoneTracker.IsAreaReadyCountingSkipped(point))
				{
					__result = true;
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(ClutterSystem), "LateUpdate")]
	public static class ClutterSystem_LateUpdate_Patch
	{
		private static Vector3 _lastRunPos = new Vector3(float.MinValue, float.MinValue, float.MinValue);

		private static float _lastRunTime = -1000f;

		private static FieldInfo s_forceRebuildField;

		private static bool s_forceRebuildChecked;

		private static int _ctSkipped;

		private static int _ctPassMoved;

		private static int _ctPassTTL;

		private static int _ctPassForceRebuild;

		private static int _ctPassNoPlayer;

		private static int _ctPassFreefly;

		private static int _ctPassDisabled;

		private static float _lastReportTime;

		[HarmonyPrefix]
		public static bool Prefix(ClutterSystem __instance)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: 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)
			if (!FiresEasyBakeMeshesPlugin.PluginEnabled.Value)
			{
				_ctPassDisabled++;
				MaybeReport();
				return true;
			}
			if (!FiresEasyBakeMeshesPlugin.ClutterLodEnabled.Value)
			{
				_ctPassDisabled++;
				MaybeReport();
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				_ctPassNoPlayer++;
				MaybeReport();
				return true;
			}
			if (GameCamera.InFreeFly())
			{
				_ctPassFreefly++;
				MaybeReport();
				return true;
			}
			if (GetForceRebuild(__instance))
			{
				_ctPassForceRebuild++;
				MaybeReport();
				return true;
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			float unscaledTime = Time.unscaledTime;
			float value = FiresEasyBakeMeshesPlugin.ClutterLodMoveThreshold.Value;
			float value2 = FiresEasyBakeMeshesPlugin.ClutterLodMaxSeconds.Value;
			float num = position.x - _lastRunPos.x;
			float num2 = position.y - _lastRunPos.y;
			float num3 = position.z - _lastRunPos.z;
			bool flag = num * num + num2 * num2 + num3 * num3 >= value * value;
			bool flag2 = unscaledTime - _lastRunTime >= value2;
			if (!flag && !flag2)
			{
				_ctSkipped++;
				MaybeReport();
				return false;
			}
			if (flag)
			{
				_ctPassMoved++;
			}
			else if (flag2)
			{
				_ctPassTTL++;
			}
			_lastRunPos = position;
			_lastRunTime = unscaledTime;
			MaybeReport();
			return true;
		}

		private static void MaybeReport()
		{
			if (!FiresEasyBakeMeshesPlugin.ClutterLodVerbose.Value)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (!(unscaledTime - _lastReportTime < 5f))
			{
				_lastReportTime = unscaledTime;
				int num = _ctSkipped + _ctPassMoved + _ctPassTTL + _ctPassForceRebuild + _ctPassNoPlayer + _ctPassFreefly + _ctPassDisabled;
				if (num != 0)
				{
					int num2 = _ctSkipped * 100 / num;
					EasyBakeLog.Info($"[ClutterLod] {num} calls in last ~5s — skipped {_ctSkipped} ({num2}%), " + $"passed: moved={_ctPassMoved} ttl={_ctPassTTL} forceRebuild={_ctPassForceRebuild} " + $"noPlayer={_ctPassNoPlayer} freefly={_ctPassFreefly} disabled={_ctPassDisabled}");
					_ctSkipped = (_ctPassMoved = (_ctPassTTL = (_ctPassForceRebuild = (_ctPassNoPlayer = (_ctPassFreefly = (_ctPassDisabled = 0))))));
				}
			}
		}

		private static bool GetForceRebuild(ClutterSystem cs)
		{
			if (!s_forceRebuildChecked)
			{
				s_forceRebuildField = typeof(ClutterSystem).GetField("m_forceRebuild", BindingFlags.Instance | BindingFlags.NonPublic);
				s_forceRebuildChecked = true;
				if (s_forceRebuildField == null)
				{
					EasyBakeLog.Warn("[ClutterLod] ClutterSystem.m_forceRebuild not found via reflection — throttle disabled (fail-open: never skips).");
				}
			}
			if (s_forceRebuildField == null)
			{
				return true;
			}
			return (bool)s_forceRebuildField.GetValue(cs);
		}

		public static void ResetState()
		{
			//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)
			_lastRunPos = new Vector3(float.MinValue, float.MinValue, float.MinValue);
			_lastRunTime = -1000f;
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "AddInstance")]
	public static class ZNetScene_AddInstance_Patch
	{
		[HarmonyPostfix]
		public static void Postfix(ZDO zdo, ZNetView nview)
		{
			if (FiresEasyBakeMeshesPlugin.SectorMirrorEnabled.Value)
			{
				SectorInstanceMirror.OnInstanceAdded(zdo, nview);
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "OnZDODestroyed")]
	public static class ZNetScene_OnZDODestroyed_Patch
	{
		[HarmonyPrefix]
		public static void Prefix(ZDO zdo)
		{
			if (FiresEasyBakeMeshesPlugin.SectorMirrorEnabled.Value)
			{
				SectorInstanceMirror.OnInstanceRemoved(zdo);
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Destroy")]
	public static class ZNetScene_Destroy_Patch
	{
		[HarmonyPrefix]
		public static void Prefix(GameObject go)
		{
			if (!FiresEasyBakeMeshesPlugin.SectorMirrorEnabled.Value || (Object)(object)go == (Object)null)
			{
				return;
			}
			ZNetView component = go.GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null))
			{
				ZDO zDO = component.GetZDO();
				if (zDO != null)
				{
					SectorInstanceMirror.OnInstanceRemoved(zDO);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Shutdown")]
	public static class ZNetScene_Shutdown_Patch
	{
		[HarmonyPostfix]
		public static void Postfix()
		{
			SectorInstanceMirror.Reset();
			try
			{
				ZoneTracker.Reset();
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "HaveInstanceInSector")]
	public static class ZNetScene_HaveInstanceInSector_Patch
	{
		private static bool s_standDownLogged;

		[HarmonyPrefix]
		public static bool Prefix(Vector2s sector, ref bool __result, bool __runOriginal)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (!__runOriginal)
			{
				if (!s_standDownLogged)
				{
					s_standDownLogged = true;
					EasyBakeLog.Info("[SectorMirror] Another mod already answers ZNetScene.HaveInstanceInSector; the sector mirror stands down.");
				}
				return false;
			}
			if (!FiresEasyBakeMeshesPlugin.SectorMirrorEnabled.Value)
			{
				return true;
			}
			if (SectorInstanceMirror.TryHasInstance(sector, out var result))
			{
				__result = result;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(LightFlicker), "CustomUpdate")]
	public static class LightFlicker_CustomUpdate_Patch
	{
		private sealed class ThrottleState
		{
			public float NextUpdateTime;

			public float NextTierCheckTime;

			public float TierInterval;

			public float BankedDeltaTime;

			public bool HasTier;
		}

		private const float FullRateInterval = 0f;

		private const float SlowestSupportedRate = 0.01f;

		private const float TierCheckJitterFraction = 0.25f;

		private const int TierCheckPhaseSalt = 14961;

		private const uint PhaseMask = 16777215u;

		private static readonly FieldRef<LightFlicker, Light> LightRef = AccessTools.FieldRefAccess<LightFlicker, Light>("m_light");

		private static readonly FieldRef<LightFlicker, float> ElapsedTimeRef = AccessTools.FieldRefAccess<LightFlicker, float>("m_time");

		private static readonly ConditionalWeakTable<LightFlicker, ThrottleState> ThrottleStates = new ConditionalWeakTable<LightFlicker, ThrottleState>();

		[HarmonyPrefix]
		public static bool Prefix(LightFlicker __instance, ref float deltaTime)
		{
			if (!FiresEasyBakeMeshesPlugin.LightFlickerLodEnabled.Value)
			{
				return true;
			}
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return true;
			}
			Light val = LightRef.Invoke(__instance);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			ThrottleState orCreateValue = ThrottleStates.GetOrCreateValue(__instance);
			if (!((Behaviour)val).enabled)
			{
				ClearSchedule(orCreateValue);
				return false;
			}
			if (NeedsEveryFrame(__instance))
			{
				return ReleaseBankedDeltaTime(orCreateValue, ref deltaTime);
			}
			float time = Time.time;
			RefreshTierInterval(__instance, orCreateValue, time);
			if (orCreateValue.TierInterval <= 0f)
			{
				orCreateValue.NextUpdateTime = 0f;
				return ReleaseBankedDeltaTime(orCreateValue, ref deltaTime);
			}
			if (IsUpdateDue(orCreateValue, time, ((Object)__instance).GetInstanceID()))
			{
				return ReleaseBankedDeltaTime(orCreateValue, ref deltaTime);
			}
			orCreateValue.BankedDeltaTime += deltaTime;
			return false;
		}

		private static bool NeedsEveryFrame(LightFlicker flicker)
		{
			if (flicker.m_ttl > 0f)
			{
				return true;
			}
			if (flicker.m_fadeInDuration > 0f)
			{
				return ElapsedTimeRef.Invoke(flicker) < flicker.m_fadeInDuration;
			}
			return false;
		}

		private static void RefreshTierInterval(LightFlicker flicker, ThrottleState state, float now)
		{
			if (!state.HasTier || !(now < state.NextTierCheckTime))
			{
				state.TierInterval = ResolveTierInterval(flicker);
				state.HasTier = true;
				float num = IntervalFromRate(FiresEasyBakeMeshesPlugin.LightFlickerTierCheckRate.Value);
				state.NextTierCheckTime = now + num * JitterScale(((Object)flicker).GetInstanceID() ^ 0x3A71);
			}
		}

		private static float ResolveTierInterval(LightFlicker flicker)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			float value = FiresEasyBakeMeshesPlugin.LightFlickerLodDistance.Value;
			float num = Mathf.Max(value, FiresEasyBakeMeshesPlugin.LightFlickerMidDistance.Value);
			float num2 = Mathf.Max(num, FiresEasyBakeMeshesPlugin.LightFlickerFarDistance.Value);
			Vector3 val = ((Component)flicker).transform.position - ((Component)Player.m_localPlayer).transform.position;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			if (sqrMagnitude <= value * value)
			{
				return 0f;
			}
			if (sqrMagnitude <= num * num)
			{
				return IntervalFromRate(FiresEasyBakeMeshesPlugin.LightFlickerMidRate.Value);
			}
			if (sqrMagnitude <= num2 * num2)
			{
				return IntervalFromRate(FiresEasyBakeMeshesPlugin.LightFlickerFarRate.Value);
			}
			return IntervalFromRate(FiresEasyBakeMeshesPlugin.LightFlickerDistantRate.Value);
		}

		private static bool IsUpdateDue(ThrottleState state, float now, int phaseSeed)
		{
			if (state.NextUpdateTime <= 0f)
			{
				state.NextUpdateTime = now + state.TierInterval * StablePhase01(phaseSeed);
				return true;
			}
			if (now < state.NextUpdateTime)
			{
				return false;
			}
			state.NextUpdateTime = now + state.TierInterval;
			return true;
		}

		private static bool ReleaseBankedDeltaTime(ThrottleState state, ref float deltaTime)
		{
			if (state.BankedDeltaTime > 0f)
			{
				deltaTime += state.BankedDeltaTime;
				state.BankedDeltaTime = 0f;
			}
			return true;
		}

		private static void ClearSchedule(ThrottleState state)
		{
			state.NextUpdateTime = 0f;
			state.NextTierCheckTime = 0f;
			state.TierInterval = 0f;
			state.BankedDeltaTime = 0f;
			state.HasTier = false;
		}

		private static float IntervalFromRate(float updatesPerSecond)
		{
			return 1f / Mathf.Max(0.01f, updatesPerSecond);
		}

		private static float JitterScale(int seed)
		{
			return 0.75f + 0.25f * StablePhase01(seed);
		}

		private static float StablePhase01(int seed)
		{
			int num = (seed ^ (seed >>> 16)) * -2048144789;
			int num2 = (num ^ (num >>> 13)) * -1028477387;
			return (float)(uint)((num2 ^ (num2 >>> 16)) & 0xFFFFFF) / 16777215f;
		}
	}
	[HarmonyPatch(typeof(ZSFX), "CustomUpdate")]
	public static class ZSFX_CustomUpdate_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix(ZSFX __instance)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (!FiresEasyBakeMeshesPlugin.ZSFXLodEnabled.Value)
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return true;
			}
			float value = FiresEasyBakeMeshesPlugin.ZSFXLodDistance.Value;
			float num = value * value;
			Vector3 position = ((Component)localPlayer).transform.position;
			Vector3 position2 = ((Component)__instance).transform.position;
			float num2 = position.x - position2.x;
			float num3 = position.y - position2.y;
			float num4 = position.z - position2.z;
			if (num2 * num2 + num3 * num3 + num4 * num4 > num)
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	public static class ZNetScene_Awake_Patch
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__1_0;

			internal void <Postfix>b__1_0(ConsoleEventArgs args)
			{
				string text = ZoneTracker.Census();
				EasyBakeLog.Info(text);
				string[] array = text.Split(new char[1] { '\n' });
				foreach (string text2 in array)
				{
					Terminal context = args.Context;
					if (context != null)
					{
						context.AddString(text2);
					}
				}
			}
		}

		private static bool s_censusRegistered;

		[HarmonyPostfix]
		public static void Postfix(ZNetScene __instance)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			if (!FiresEasyBakeMeshesPlugin.PluginEnabled.Value)
			{
				return;
			}
			if (!s_censusRegistered)
			{
				s_censusRegistered = true;
				object obj = <>c.<>9__1_0;
				if (obj == null)
				{
					ConsoleEvent val = delegate(ConsoleEventArgs args)
					{
						string text = ZoneTracker.Census();
						EasyBakeLog.Info(text);
						string[] array = text.Split(new char[1] { '\n' });
						foreach (string text2 in array)
						{
							Terminal context = args.Context;
							if (context != null)
							{
								context.AddString(text2);
							}
						}
					};
					<>c.<>9__1_0 = val;
					obj = (object)val;
				}
				new ConsoleCommand("ebm_census", "FiresEasyBakeMeshes: count every loaded object and why it was created instead of skipped (also written to the log).", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			}
			SkipEligibility.Clear();
			StandInColliders.Clear();
			bool flag = FiresEasyBakeMeshesPlugin.PrewarmEnabled.Value;
			if (flag && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && !FiresEasyBakeMeshesPlugin.PrewarmRunOnServer.Value)
			{
				flag = false;
			}
			((MonoBehaviour)__instance).StartCoroutine(BuildRegistryThenPrewarm(__instance, flag));
		}

		private static IEnumerator BuildRegistryThenPrewarm(ZNetScene scene, bool prewarmAllowed)
		{
			if (prewarmAllowed)
			{
				PrewarmOptions val = BuildPrewarmOptions();
				IEnumerator prewarmEnum = PrewarmCoroutine.Run((IList<GameObject>)scene.m_prefabs, val, (Action<string>)EasyBakeLog.Info, (Action<string>)EasyBakeLog.Warn, (Action<string>)EasyBakeLog.Debug);
				while (prewarmEnum.MoveNext())
				{
					yield return prewarmEnum.Current;
				}
			}
			if (!FiresEasyBakeMeshesPlugin.CachePersistEnabled.Value)
			{
				EasyBakeLog.Info("[Cache] CachePersistEnabled=false — skipping material registry build (saves ~50s of main-thread budget; registry only feeds cache reattach).");
				yield break;
			}
			float waitStart = Time.unscaledTime;
			long worldUid = 0L;
			while (Time.unscaledTime - waitStart < 30f)
			{
				worldUid = MeshCacheStore.TryGetWorldUid();
				if (worldUid != 0L)
				{
					break;
				}
				yield return null;
			}
			if (worldUid == 0L)
			{
				EasyBakeLog.Info("[Cache] Timed out waiting for world UID — skipping material registry. Cache reattach disabled this session; bakes will happen fresh.");
				yield break;
			}
			if (!MeshCacheStore.WorldHasCache(worldUid))
			{
				EasyBakeLog.Info($"[Cache] No on-disk cache for world {worldUid:x16} — skipping material registry. " + "First-bake-from-scratch path is fine without it; next session will have a cache and the registry will build then.");
				yield break;
			}
			EasyBakeLog.Info($"[Cache] World {worldUid:x16} has a cache — building material registry.");
			InstanceDefinitionCache.Clear();
			IEnumerator registryEnum = MeshCacheStore.BuildMaterialRegistryAsync(scene);
			while (registryEnum.MoveNext())
			{
				yield return registryEnum.Current;
			}
		}

		private static PrewarmOptions BuildPrewarmOptions()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_009e: Expected O, but got Unknown
			return new PrewarmOptions
			{
				PrefabsPerFrame = FiresEasyBakeMeshesPlugin.PrewarmPrefabsPerFrame.Value,
				FrameBudgetMs = ((FiresEasyBakeMeshesPlugin.PrewarmFrameBudgetMs != null) ? FiresEasyBakeMeshesPlugin.PrewarmFrameBudgetMs.Value : 8f),
				SlowInstantiateThresholdMs = FiresEasyBakeMeshesPlugin.PrewarmSlowInstantiateThresholdMs.Value,
				MaxTransformCount = FiresEasyBakeMeshesPlugin.PrewarmMaxTransformCount.Value,
				PersistSlowSkipPath = Path.Combine(Paths.ConfigPath, "FiresEasyBakeMeshes", "prewarm_slow_skips.txt"),
				Verbose = FiresEasyBakeMeshesPlugin.PrewarmVerbose.Value,
				SkipNameContains = (FiresEasyBakeMeshesPlugin.PrewarmSkipNameContains.Value ?? string.Empty),
				SkipStatefulComponents = true
			};
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "CreateObject")]
	public static class ZNetScene_CreateObject_Patch
	{
		[HarmonyPostfix]
		public static void Postfix(GameObject __result)
		{
			if (!((Object)(object)__result == (Object)null))
			{
				long start = Probe.Start();
				StaticPieceZSyncSkip.TryDisable(__result);
				if (FiresEasyBakeMeshesPlugin.BatchingActive())
				{
					ZoneTracker.OnInstanceCreated(__result);
				}
				Probe.Stop("EasyBake:hook", start);
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "RemoveObjects")]
	public static class ZNetScene_RemoveObjects_Patch
	{
		private static bool s_standDownLogged;

		[HarmonyPrefix]
		public static bool Prefix(ZNetScene __instance, List<ZDO> currentNearObjects, List<ZDO> currentDistantObjects, bool __runOriginal)
		{
			//IL_0075: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!__runOriginal)
			{
				if (!s_standDownLogged)
				{
					s_standDownLogged = true;
					EasyBakeLog.Info("[DTS] Another mod already replaces ZNetScene.RemoveObjects; destroy time-slicing and zone keepalive stand down.");
				}
				return false;
			}
			if (!FiresEasyBakeMeshesPlugin.BatchingActive())
			{
				return true;
			}
			if (FiresEasyBakeMeshesPlugin.ZoneKeepaliveEnabled.Value)
			{
				ZoneSystem instance = ZoneSystem.instance;
				ZNet instance2 = ZNet.instance;
				if ((Object)(object)instance != (Object)null && (Object)(object)instance2 != (Object)null)
				{
					Vector2s zone = ZoneSystem.GetZone(instance2.GetReferencePosition());
					SimulationDistance syncedSimulationDistance = instance2.GetSyncedSimulationDistance();
					int nearSimulationDistance = ((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance;
					ZoneKeepalive.AppendKeepaliveZDOs(currentNearObjects, zone, nearSimulationDistance);
				}
				else
				{
					ZoneKeepalive.AppendKeepaliveZDOs(currentNearObjects, new Vector2s(0, 0), -1);
				}
			}
			if (FiresEasyBakeMeshesPlugin.DestroyTimeSliceEnabled.Value)
			{
				long start = Probe.Start();
				bool num = DestroyTimeSlicer.Run(__instance, currentNearObjects, currentDistantObjects);
				Probe.Stop("EasyBake:destroy", start);
				if (num)
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(WearNTear), "OnDestroy")]
	public static class WearNTear_OnDestroy_Patch
	{
		[HarmonyPrefix]
		public static void Prefix(WearNTear __instance)
		{
			InvulnerableClassifier.Forget(__instance);
			if (FiresEasyBakeMeshesPlugin.BatchingActive())
			{
				ZoneTracker.OnPieceDestroyed(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(WearNTear), "SetHealthVisual")]
	public static class WearNTear_SetHealthVisual_Patch
	{
		[HarmonyPostfix]
		public static void Postfix(WearNTear __instance, float health)
		{
			if (!(health > 0.75f) && FiresEasyBakeMeshesPlugin.BatchingActive())
			{
				ZoneTracker.HandBackPiece(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(WearNTear), "SetAshlandsMaterialValue")]
	public static class WearNTear_SetAshlandsMaterialValue_Patch
	{
		[HarmonyPostfix]
		public static void Postfix(WearNTear __instance, float v)
		{
			if (!(v <= 0f) && FiresEasyBakeMeshesPlugin.BatchingActive())
			{
				ZoneTracker.HandBackPiece(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(WearNTear), "Highlight")]
	public static class WearNTear_Highlight_Patch
	{
		[HarmonyPrefix]
		public static void Prefix(WearNTear __instance)
		{
			if (FiresEasyBakeMeshesPlugin.BatchingActive())
			{
				ZoneTracker.HandBackPiece(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(WearNTear), "UpdateWear")]
	public static class WearNTear_UpdateWear_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix(WearNTear __instance)
		{
			if (!FiresEasyBakeMeshesPlugin.PluginEnabled.Value)
			{
				return true;
			}
			if (!FiresEasyBakeMeshesPlugin.WearShortCircuitEnabled.Value)
			{
				return true;
			}
			if (!InvulnerableClassifier.IsInvulnerable(__instance))
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(WearNTear), "UpdateCover")]
	public static class WearNTear_UpdateCover_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix(WearNTear __instance)
		{
			if (!FiresEasyBakeMeshesPlugin.PluginEnabled.Value)
			{
				return true;
			}
			if (!FiresEasyBakeMeshesPlugin.WearShortCircuitEnabled.Value)
			{
				return true;
			}
			if (!InvulnerableClassifier.IsInvulnerable(__instance))
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ShieldGenerator), "UpdateShield")]
	public static class ShieldGenerator_UpdateShield_NREGuard
	{
		private static readonly HashSet<int> _silenced = new HashSet<int>();

		private static readonly FieldInfo f_nview = AccessTools.Field(typeof(ShieldGenerator), "m_nview");

		private static readonly FieldInfo f_enabledObject = AccessTools.Field(typeof(ShieldGenerator), "m_enabledObject");

		private static readonly FieldInfo f_disabledObject = AccessTools.Field(typeof(ShieldGenerator), "m_disabledObject");

		private static readonly FieldInfo f_shieldDome = AccessTools.Field(typeof(ShieldGenerator), "m_shieldDome");

		private static readonly FieldInfo f_energyParticles = AccessTools.Field(typeof(ShieldGenerator), "m_energyParticles");

		private static readonly FieldInfo f_energyParticlesFlare = AccessTools.Field(typeof(ShieldGenerator), "m_energyParticlesFlare");

		private static readonly FieldInfo f_coloredLights = AccessTools.Field(typeof(ShieldGenerator), "m_coloredLights");

		private static readonly FieldInfo f_meshRenderers = AccessTools.Field(typeof(ShieldGenerator), "m_meshRenderers");

		private static readonly FieldInfo f_propertyBlock = AccessTools.Field(typeof(ShieldGenerator), "m_propertyBlock");

		[HarmonyFinalizer]
		public static Exception Finalizer(ShieldGenerator __instance, Exception __exception)
		{
			if (__exception == null)
			{
				return null;
			}
			if ((Object)(object)__instance == (Object)null)
			{
				return __exception;
			}
			int instanceID = ((Object)__instance).GetInstanceID();
			if (_silenced.Contains(instanceID))
			{
				return null;
			}
			_silenced.Add(instanceID);
			try
			{
				((MonoBehaviour)__instance).CancelInvoke("UpdateShield");
			}
			catch (Exception ex)
			{
				EasyBakeLog.Warn("[NREGuard] CancelInvoke failed on '" + InstanceLabel(__instance) + "': " + ex.Message);
			}
			EasyBakeLog.Warn(BuildDiagnostic(__instance, __exception));
			return null;
		}

		private static string BuildDiagnostic(ShieldGenerator inst, Exception ex)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("[NREGuard] ShieldGenerator.UpdateShield NRE on '").Append(InstanceLabel(inst)).Append("'. ");
			stringBuilder.Append("Cancelled future ticks for this instance. ");
			stringBuilder.Append("Field state: ");
			AppendFieldState<object>(stringBuilder, "m_nview", f_nview, inst);
			AppendFieldState<object>(stringBuilder, "m_enabledObject", f_enabledObject, inst);
			AppendFieldState<object>(stringBuilder, "m_disabledObject", f_disabledObject, inst);
			AppendFieldState<object>(stringBuilder, "m_shieldDome", f_shieldDome, inst);
			AppendArrayState(stringBuilder, "m_energyParticles", f_energyParticles, inst);
			AppendFieldState<object>(stringBuilder, "m_energyParticlesFlare", f_energyParticlesFlare, inst);
			AppendArrayState(stringBuilder, "m_coloredLights", f_coloredLights, inst);
			AppendArrayState(stringBuilder, "m_meshRenderers", f_meshRenderers, inst);
			AppendFieldState<object>(stringBuilder, "m_propertyBlock", f_propertyBlock, inst);
			stringBuilder.Append("Original: ").Append(ex.GetType().Name).Append(" — ")
				.Append(ex.Message);
			return stringBuilder.ToString();
		}

		private static void AppendFieldState<T>(StringBuilder sb, string label, FieldInfo field, ShieldGenerator inst)
		{
			sb.Append(label).Append('=');
			if (field == null)
			{
				sb.Append("?fieldMissing? ");
				return;
			}
			try
			{
				object value = field.GetValue(inst);
				if (value == null)
				{
					sb.Append("null");
				}
				else
				{
					Object val = (Object)((value is Object) ? value : null);
					if (val != null && !Object.op_Implicit(val))
					{
						sb.Append("Unity-null");
					}
					else
					{
						sb.Append("ok");
					}
				}
			}
			catch (Exception ex)
			{
				sb.Append("?readFailed:").Append(ex.GetType().Name).Append("?");
			}
			sb.Append(' ');
		}

		private static void AppendArrayState(StringBuilder sb, string label, FieldInfo field, ShieldGenerator inst)
		{
			sb.Append(label).Append('=');
			if (field == null)
			{
				sb.Append("?fieldMissing? ");
				return;
			}
			try
			{
				object value = field.GetValue(inst);
				if (value == null)
				{
					sb.Append("null");
				}
				else if (value is Array array)
				{
					sb.Append("len=").Append(array.Length);
					int num = 0;
					for (int i = 0; i < array.Length; i++)
					{
						object value2 = array.GetValue(i);
						if (value2 == null)
						{
							num++;
							continue;
						}
						Object val = (Object)((value2 is Object) ? value2 : null);
						if (val != null && !Object.op_Implicit(val))
						{
							num++;
						}
					}
					if (num > 0)
					{
						sb.Append(",nulls=").Append(num);
					}
				}
				else
				{
					sb.Append("?notArray?");
				}
			}
			catch (Exception ex)
			{
				sb.Append("?readFailed:").Append(ex.GetType().Name).Append("?");
			}
			sb.Append(' ');
		}

		private static string InstanceLabel(ShieldGenerator inst)
		{
			try
			{
				return ((Object)(object)((Component)inst).gameObject != (Object)null) ? ((Object)((Component)inst).gameObject).name : "<destroyed>";
			}
			catch
			{
				return "<unreadable>";
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "CreateDestroyObjects")]
	public static class ZNetScene_CreateDestroyObjects_Patch
	{
		private static Vector2s _lastCenter = new Vector2s(short.MinValue, short.MinValue);

		private static int _lastZoneCount = -1;

		private static int _lastInstanceCount = -1;

		private static int _lastZdoCount = -1;

		private static float _lastVanillaTime = -1000f;

		private static FieldInfo s_zonesField;

		private static bool s_zonesFieldChecked;

		private static FieldInfo s_instancesField;

		private static bool s_instancesFieldChecked;

		private static int _skippedSinceReport;

		private static float _lastReportTime;

		private static bool s_standDownLogged;

		[HarmonyPrefix]
		public static bool Prefix(ZNetScene __instance, bool __runOriginal)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			if (!__runOriginal)
			{
				if (!s_standDownLogged)
				{
					s_standDownLogged = true;
					EasyBakeLog.Info("[CDS] Another mod already replaces ZNetScene.CreateDestroyObjects; the create/destroy skip stands down.");
				}
				return false;
			}
			if (!FiresEasyBakeMeshesPlugin.PluginEnabled.Value)
			{
				return true;
			}
			if (!FiresEasyBakeMeshesPlugin.CreateDestroySkipEnabled.Value)
			{
				return true;
			}
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return true;
			}
			if (ZNet.instance.IsDedicated())
			{
				return true;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return true;
			}
			if (((Character)Player.m_localPlayer).IsTeleporting())
			{
				return true;
			}
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			Vector2s zone = ZoneSystem.GetZone(ZNet.instance.GetReferencePosition());
			int zoneCount = GetZoneCount(instance);
			if (zoneCount < 0)
			{
				return true;
			}
			int instanceCount = GetInstanceCount(__instance);
			if (instanceCount < 0)
			{
				return true;
			}
			ZDOMan instance2 = ZDOMan.instance;
			if (instance2 == null)
			{
				return true;
			}
			int num = instance2.NrOfObjects();
			float unscaledTime = Time.unscaledTime;
			float value = FiresEasyBakeMeshesPlugin.CreateDestroySkipMaxSeconds.Value;
			bool flag = unscaledTime - _lastVanillaTime >= value;
			if (zone.x == _lastCenter.x && zone.y == _lastCenter.y && zoneCount == _lastZoneCount && instanceCount == _lastInstanceCount && num == _lastZdoCount && !flag && _lastZoneCount >= 0)
			{
				_skippedSinceReport++;
				if (FiresEasyBakeMeshesPlugin.CreateDestroySkipVerbose.Value && unscaledTime - _lastReportTime > 5f)
				{
					EasyBakeLog.Info($"[CDS] Skipped {_skippedSinceReport} CreateDestroyObjects ticks " + $"in last {unscaledTime - _lastReportTime:F1}s " + $"(center={zone.x},{zone.y}, zones={zoneCount}, instances={instanceCount}, zdos={num}).");
					_skippedSinceReport = 0;
					_lastReportTime = unscaledTime;
				}
				return false;
			}
			_lastCenter = zone;
			_lastZoneCount = zoneCount;
			_lastInstanceCount = instanceCount;
			_lastZdoCount = num;
			_lastVanillaTime = unscaledTime;
			return true;
		}

		private static int GetZoneCount(ZoneSystem zs)
		{
			if (!s_zonesFieldChecked)
			{
				s_zonesField = typeof(ZoneSystem).GetField("m_zones", BindingFlags.Instance | BindingFlags.NonPublic);
				s_zonesFieldChecked = true;
				if (s_zonesField == null)
				{
					EasyBakeLog.Warn("[CDS] ZoneSystem.m_zones field not found via reflection — CreateDestroyObjects skip optimization disabled (fail-open).");
				}
			}
			if (s_zonesField == null)
			{
				return -1;
			}
			return (s_zonesField.GetValue(zs) as ICollection)?.Count ?? (-1);
		}

		private static int GetInstanceCount(ZNetScene scene)
		{
			if (!s_instancesFieldChecked)
			{
				s_instancesField = typeof(ZNetScene).GetField("m_instances", BindingFlags.Instance | BindingFlags.NonPublic);
				s_instancesFieldChecked = true;
				if (s_instancesField == null)
				{
					EasyBakeLog.Warn("[CDS] ZNetScene.m_instances field not found via reflection — CreateDestroyObjects skip optimization disabled (fail-open).");
				}
			}
			if (s_instancesField == null)
			{
				return -1;
			}
			return (s_instancesField.GetValue(scene) as ICollection)?.Count ?? (-1);
		}

		public static void ResetState()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			_lastCenter = new Vector2s(short.MinValue, short.MinValue);
			_lastZoneCount = -1;
			_lastInstanceCount = -1;
			_lastZdoCount = -1;
			_lastVanillaTime = -1000f;
			_skippedSinceReport = 0;
			_lastReportTime = 0f;
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "OnZDODestroyed")]
	public static class ZNetScene_OnZDODestroyed_BakeInvalidate_Patch
	{
		[HarmonyPrefix]
		public static void Prefix(ZDO zdo)
		{
			if (!FiresEasyBakeMeshesPlugin.BatchingActive())
			{
				return;
			}
			try
			{
				ZoneTracker.OnZdoDestroyed(zdo);
			}
			catch
			{
			}
		}
	}
}
namespace FiresEasyBakeMeshes.EasyBake
{
	internal static class InvulnerableClassifier
	{
		private static readonly Dictionary<WearNTear, bool> _cache = new Dictionary<WearNTear, bool>();

		public static bool IsInvulnerable(WearNTear wnt)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)wnt == (Object)null)
			{
				return false;
			}
			if (_cache.TryGetValue(wnt, out var value))
			{
				return value;
			}
			bool flag = HasNegativeHealth(wnt) || AllImmune(wnt.m_damages);
			_cache[wnt] = flag;
			return flag;
		}

		public static void Forget(WearNTear wnt)
		{
			if ((Object)(object)wnt != (Object)null)
			{
				_cache.Remove(wnt);
			}
		}

		public static void Reset()
		{
			_cache.Clear();
		}

		private static bool HasNegativeHealth(WearNTear wnt)
		{
			if (wnt.m_health < 0f)
			{
				return true;
			}
			ZNetView component = ((Component)wnt).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			ZDO zDO = component.GetZDO();
			if (zDO == null)
			{
				return false;
			}
			return zDO.GetFloat(ZDOVars.s_health, wnt.m_health) < 0f;
		}

		internal static bool AllImmune(DamageModifiers m)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_0024: 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: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Invalid comparison between Unknown and I4
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Invalid comparison between Unknown and I4
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Invalid comparison between Unknown and I4
			if ((int)m.m_blunt == 3 && (int)m.m_slash == 3 && (int)m.m_pierce == 3 && (int)m.m_chop == 3 && (int)m.m_pickaxe == 3 && (int)m.m_fire == 3 && (int)m.m_frost == 3 && (int)m.m_lightning == 3 && (int)m.m_poison == 3)
			{
				return (int)m.m_spirit == 3;
			}
			return false;
		}
	}
	internal static class ZoneTracker
	{
		private class ZoneState
		{
			public Vector2s Coord;

			public HashSet<WearNTear> Pieces = new HashSet<WearNTear>();

			public float LastChangeUnscaledTime;

			public float ConstructedUnscaledTime;

			public bool Baked;

			public bool Dirty;

			public bool ZoneActive = true;

			public MeshBaker.BakeResult Bake;

			public bool NeedsCacheValidation;

			public readonly Dictionary<ZDO, MeshBaker.PieceIdentity> Skipped = new Dictionary<ZDO, MeshBaker.PieceIdentity>();

			public GameObject StandInRoot;

			public readonly Dictionary<MeshBaker.PieceIdentity, GameObject> StandIns = new Dictionary<MeshBaker.PieceIdentity, GameObject>();

			public readonly Queue<MeshBaker.PieceIdentity> StandInQueue = new Queue<MeshBaker.PieceIdentity>();

			public readonly Queue<WearNTear> ConvertQueue = new Queue<WearNTear>();

			public bool HoldReal;

			public float HoldRealUntil;

			public List<ZDO> AwaitingRecreate;

			public List<MeshBaker.PieceIdentity> AwaitingIdentities;

			public float AwaitingSince;

			public bool CacheStale;

			public int PresentPieces => Pieces.Count + Skipped.Count;
		}

		private static readonly Dictionary<Vector2s, ZoneState> _zones = new Dictionary<Vector2s, ZoneState>();

		private static readonly List<Vector2s> _dropScratch = new List<Vector2s>();

		private const float BuildHoldSeconds = 30f;

		private const float RecreateTimeoutSeconds = 20f;

		private const float EmptyZoneGraceSeconds = 10f;

		private const float CacheValidationQuietSeconds = 10f;

		private const double StandInBudgetMs = 4.0;

		private const double LoadingStandInBudgetMs = 12.0;

		private const double ConvertBudgetMs = 2.0;

		private const float SkipReportSeconds = 30f;

		private const int ParkedStandInExtraZones = 8;

		private static bool s_buildingNearby;

		private static float s_nextRangeCheck;

		private static float s_nextWatch;

		private static float s_nextSkipReport;

		private static int s_skippedAtCreation;

		private static int s_convertedLive;

		private static int s_standInColliders;

		private static int s_standInsOnDemand;

		private static int s_standInZonesReused;

		private static int s_handedBackForBuilding;

		private static int s_handedBackForChanges;

		private static int s_handedBackLooks;

		private static int s_joinedLate;

		private static int s_lastReportedTotal;

		private static bool s_skipFailureLogged;

		private static FieldInfo s_instancesField;

		private static readonly List<ZoneState> _zoneScratch = new List<ZoneState>();

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

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

		private static Vector3 s_sortReference;

		private const float FarTierHysteresisMeters = 4f;

		private static readonly Comparison<ZoneState> CompareByDistance = (ZoneState a, ZoneState b) => ZoneDistanceSq(a.Coord).CompareTo(ZoneDistanceSq(b.Coord));

		private static readonly List<KeyValuePair<ZDO, MeshBaker.PieceIdentity>> _changedScratch = new List<KeyValuePair<ZDO, MeshBaker.PieceIdentity>>();

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

		private static readonly Dictionary<string, bool> _transparentByName = new Dictionary<string, bool>(StringComparer.Ordinal);

		public static void OnInstanceCreated(GameObject go)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00