Decompiled source of ValheimScalability v1.0.0

plugins\ValheimScalability.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using ValheimScalability.BepInExConfig;
using ValheimScalability.Patches;
using ValheimScalability.Rendering.Clustering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ValheimScalability")]
[assembly: AssemblyDescription("Valheim Mod for rapid world startup and server joining without UI interaction")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("zolantris")]
[assembly: AssemblyProduct("ValheimScalability")]
[assembly: AssemblyCopyright("Copyright © 2026, GNU-v3 licensed")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimVehicles.SharedScripts
{
	internal static class BuildInfo
	{
		public const string Version = "1.0.0";

		public const string AssemblyVersion = "1.0.0.0";

		public const string FileVersion = "1.0.0.0";

		public const string PackageVersion = "1.0.0";
	}
}
namespace ValheimScalability
{
	[BepInPlugin("zolantris.ValheimScalability", "ValheimScalability", "1.0.0")]
	public class ValheimScalabilityPlugin : BaseUnityPlugin
	{
		public const string Author = "zolantris";

		public const string Version = "1.0.0";

		public const string ModName = "ValheimScalability";

		public const string BepInGuid = "zolantris.ValheimScalability";

		private static Harmony _harmony;

		public const string ModDescription = "Valheim Mod meant to unlock performance and scalability of your machine";

		public const string CopyRight = "Copyright © 2026, GNU-v3 licensed";

		public static string HarmonyGuid => "zolantris.ValheimScalability";

		public void Awake()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			ValheimScalabilityConfig.Bind(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony(HarmonyGuid);
			_harmony.PatchAll(typeof(SectorMeshClusterPatches));
			_harmony.PatchAll(typeof(SectorMeshClusterDamagePatch));
		}
	}
}
namespace ValheimScalability.Rendering.Clustering
{
	public static class ClusterBatchFilter
	{
		private static readonly object Sync = new object();

		private static bool _dirty = true;

		private static HashSet<int> _includedLayers = new HashSet<int>();

		private static HashSet<int> _excludedLayers = new HashSet<int>();

		private static string[] _includedObjectNames = Array.Empty<string>();

		private static string[] _excludedObjectNames = Array.Empty<string>();

		private static Regex[] _includedObjectRegex = Array.Empty<Regex>();

		private static Regex[] _excludedObjectRegex = Array.Empty<Regex>();

		private static string[] _excludedMaterialNames = Array.Empty<string>();

		private static Regex[] _excludedMaterialRegex = Array.Empty<Regex>();

		private static string[] _excludedShaderNames = Array.Empty<string>();

		private static Regex[] _excludedShaderRegex = Array.Empty<Regex>();

		private static string[] _instancedObjectHints = Array.Empty<string>();

		private static string[] _instancedMaterialHints = Array.Empty<string>();

		private static string[] _instancedShaderHints = Array.Empty<string>();

		private static Regex[] _instancedCandidateRegex = Array.Empty<Regex>();

		private static string[] _windPropertyNames = Array.Empty<string>();

		private static bool _hasObjectIncludeFilter;

		public static void Invalidate()
		{
			lock (Sync)
			{
				_dirty = true;
			}
		}

		public static bool IsLayerAllowed(int layer)
		{
			EnsureParsed();
			if (_excludedLayers.Contains(layer))
			{
				return false;
			}
			if (_includedLayers.Count != 0)
			{
				return _includedLayers.Contains(layer);
			}
			return true;
		}

		public static bool IsObjectAllowed(string rootName, string rendererName)
		{
			EnsureParsed();
			if (MatchesSubstring(rootName, _excludedObjectNames) || MatchesSubstring(rendererName, _excludedObjectNames) || MatchesRegex(rootName, _excludedObjectRegex) || MatchesRegex(rendererName, _excludedObjectRegex))
			{
				return false;
			}
			if (!_hasObjectIncludeFilter)
			{
				return true;
			}
			if (!MatchesSubstring(rootName, _includedObjectNames) && !MatchesSubstring(rendererName, _includedObjectNames) && !MatchesRegex(rootName, _includedObjectRegex))
			{
				return MatchesRegex(rendererName, _includedObjectRegex);
			}
			return true;
		}

		public static bool IsMaterialAllowed(Material material)
		{
			EnsureParsed();
			if (!Object.op_Implicit((Object)(object)material))
			{
				return false;
			}
			if (!MatchesSubstring(((Object)material).name, _excludedMaterialNames))
			{
				return !MatchesRegex(((Object)material).name, _excludedMaterialRegex);
			}
			return false;
		}

		public static bool IsShaderAllowed(Shader shader)
		{
			EnsureParsed();
			if (!Object.op_Implicit((Object)(object)shader))
			{
				return false;
			}
			if (!MatchesSubstring(((Object)shader).name, _excludedShaderNames))
			{
				return !MatchesRegex(((Object)shader).name, _excludedShaderRegex);
			}
			return false;
		}

		public static bool IsInstancingCandidate(string rootName, string rendererName, Material[] materials)
		{
			EnsureParsed();
			if (MatchesSubstring(rootName, _instancedObjectHints) || MatchesSubstring(rendererName, _instancedObjectHints))
			{
				return true;
			}
			string text = rootName + "|" + rendererName;
			foreach (Material val in materials)
			{
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				text = text + "|" + ((Object)val).name;
				if (MatchesSubstring(((Object)val).name, _instancedMaterialHints))
				{
					return true;
				}
				if (Object.op_Implicit((Object)(object)val.shader))
				{
					text = text + "|" + ((Object)val.shader).name;
					if (MatchesSubstring(((Object)val.shader).name, _instancedShaderHints))
					{
						return true;
					}
				}
				string[] windPropertyNames = _windPropertyNames;
				foreach (string text2 in windPropertyNames)
				{
					if (!string.IsNullOrWhiteSpace(text2) && val.HasProperty(text2))
					{
						return true;
					}
				}
			}
			return MatchesRegex(text, _instancedCandidateRegex);
		}

		private static void EnsureParsed()
		{
			if (!_dirty)
			{
				return;
			}
			lock (Sync)
			{
				if (_dirty)
				{
					_includedLayers = ParseLayers(ValheimScalabilityConfig.IncludedLayers?.Value);
					_excludedLayers = ParseLayers(ValheimScalabilityConfig.ExcludedLayers?.Value);
					_includedObjectNames = ParseCsv(ValheimScalabilityConfig.IncludedObjectNames?.Value);
					_excludedObjectNames = ParseCsv(ValheimScalabilityConfig.ExcludedObjectNames?.Value);
					_includedObjectRegex = ParseRegexList(ValheimScalabilityConfig.IncludedObjectRegexList?.Value, "IncludedObjectRegexList");
					_excludedObjectRegex = ParseRegexList(ValheimScalabilityConfig.ExcludedObjectRegexList?.Value, "ExcludedObjectRegexList");
					_excludedMaterialNames = ParseCsv(ValheimScalabilityConfig.ExcludedMaterialNames?.Value);
					_excludedMaterialRegex = ParseRegexList(ValheimScalabilityConfig.ExcludedMaterialRegexList?.Value, "ExcludedMaterialRegexList");
					_excludedShaderNames = ParseCsv(ValheimScalabilityConfig.ExcludedShaderNames?.Value);
					_excludedShaderRegex = ParseRegexList(ValheimScalabilityConfig.ExcludedShaderRegexList?.Value, "ExcludedShaderRegexList");
					_instancedObjectHints = ParseCsv(ValheimScalabilityConfig.InstancedObjectNameHints?.Value);
					_instancedMaterialHints = ParseCsv(ValheimScalabilityConfig.InstancedMaterialNameHints?.Value);
					_instancedShaderHints = ParseCsv(ValheimScalabilityConfig.InstancedShaderNameHints?.Value);
					_instancedCandidateRegex = ParseRegexList(ValheimScalabilityConfig.InstancedCandidateRegexList?.Value, "InstancedCandidateRegexList");
					_windPropertyNames = ParseCsv(ValheimScalabilityConfig.WindShaderPropertyNames?.Value);
					_hasObjectIncludeFilter = _includedObjectNames.Length != 0 || _includedObjectRegex.Length != 0;
					_dirty = false;
				}
			}
		}

		private static string[] ParseCsv(string value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return Array.Empty<string>();
			}
			string[] array = value.Split(',');
			List<string> list = new List<string>(array.Length);
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				string text = array2[i].Trim();
				if (!string.IsNullOrWhiteSpace(text))
				{
					list.Add(text);
				}
			}
			return list.ToArray();
		}

		private static Regex[] ParseRegexList(string value, string settingName)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return Array.Empty<Regex>();
			}
			string[] array = value.Split(new char[3] { ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			List<Regex> list = new List<Regex>(array.Length);
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				string text = array2[i].Trim();
				if (!string.IsNullOrWhiteSpace(text))
				{
					try
					{
						list.Add(new Regex(text, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant));
					}
					catch (ArgumentException ex)
					{
						Debug.LogWarning((object)("[ValheimScalability] Ignoring invalid regex in " + settingName + ": '" + text + "'. " + ex.Message));
					}
				}
			}
			return list.ToArray();
		}

		private static HashSet<int> ParseLayers(string value)
		{
			HashSet<int> hashSet = new HashSet<int>();
			if (string.IsNullOrWhiteSpace(value))
			{
				return hashSet;
			}
			string[] array = value.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (string.IsNullOrWhiteSpace(text))
				{
					continue;
				}
				if (int.TryParse(text, out var result))
				{
					if (result >= 0 && result <= 31)
					{
						hashSet.Add(result);
					}
					continue;
				}
				int num = LayerMask.NameToLayer(text);
				if (num >= 0)
				{
					hashSet.Add(num);
				}
				else
				{
					Debug.LogWarning((object)("[ValheimScalability] Unknown layer '" + text + "' in clustering filter."));
				}
			}
			return hashSet;
		}

		private static bool MatchesSubstring(string value, string[] patterns)
		{
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			foreach (string value2 in patterns)
			{
				if (value.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private static bool MatchesRegex(string value, Regex[] regexes)
		{
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			for (int i = 0; i < regexes.Length; i++)
			{
				if (regexes[i].IsMatch(value))
				{
					return true;
				}
			}
			return false;
		}
	}
	public enum ClusterPresentationMode
	{
		Off,
		FullCluster,
		Adaptive
	}
	public enum ClusterRenderStrategy
	{
		Original,
		CombinedMesh,
		Instanced
	}
	internal static class DynamicHierarchyBatchExclusion
	{
		private const string MBParentIdKey = "MBParentId";

		private const string SwivelParentIdKey = "SwivelParentId";

		private static readonly int MBParentIdHash = StringExtensionMethods.GetStableHashCode("MBParentId");

		public static bool HasPersistedMovingParent(ZDO zdo)
		{
			if (zdo == null)
			{
				return false;
			}
			if (zdo.GetInt(MBParentIdHash, 0) == 0)
			{
				return zdo.GetInt("SwivelParentId", 0) != 0;
			}
			return true;
		}

		public static bool ShouldExclude(GameObject root)
		{
			if (!Object.op_Implicit((Object)(object)root))
			{
				return true;
			}
			ZNetView val = root.GetComponent<ZNetView>() ?? root.GetComponentInParent<ZNetView>();
			if (Object.op_Implicit((Object)(object)val) && HasPersistedMovingParent(val.GetZDO()))
			{
				return true;
			}
			return (Object)(object)root.GetComponentInParent<Rigidbody>() != (Object)null;
		}

		public static bool ShouldExclude(ZDO zdo, GameObject root)
		{
			if (HasPersistedMovingParent(zdo))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)root))
			{
				return (Object)(object)root.GetComponentInParent<Rigidbody>() != (Object)null;
			}
			return false;
		}

		public static bool ShouldExcludeRenderer(MeshRenderer renderer)
		{
			if (Object.op_Implicit((Object)(object)renderer))
			{
				return (Object)(object)((Component)renderer).GetComponentInParent<Rigidbody>() != (Object)null;
			}
			return false;
		}
	}
	public sealed class InstancedClusterBatch
	{
		private readonly Matrix4x4[][] _matrixChunks;

		public Mesh Mesh { get; }

		public int SubMeshIndex { get; }

		public Material SourceMaterial { get; }

		public Material InstancedMaterial { get; }

		public int Layer { get; }

		public ShadowCastingMode ShadowCastingMode { get; }

		public bool ReceiveShadows { get; }

		public LightProbeUsage LightProbeUsage { get; }

		public int DrawCallCount => _matrixChunks.Length;

		public long EstimatedMemoryBytes
		{
			get
			{
				long num = 0L;
				Matrix4x4[][] matrixChunks = _matrixChunks;
				foreach (Matrix4x4[] array in matrixChunks)
				{
					if (array != null)
					{
						num += (long)array.Length * 4L * 16;
					}
				}
				return num;
			}
		}

		public InstancedClusterBatch(Mesh mesh, int subMeshIndex, Material sourceMaterial, Material instancedMaterial, int layer, ShadowCastingMode shadowCastingMode, bool receiveShadows, LightProbeUsage lightProbeUsage, List<Matrix4x4> matrices)
		{
			//IL_002c: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			Mesh = mesh;
			SubMeshIndex = subMeshIndex;
			SourceMaterial = sourceMaterial;
			InstancedMaterial = instancedMaterial;
			Layer = layer;
			ShadowCastingMode = shadowCastingMode;
			ReceiveShadows = receiveShadows;
			LightProbeUsage = lightProbeUsage;
			int num = Mathf.CeilToInt((float)matrices.Count / 1023f);
			_matrixChunks = new Matrix4x4[num][];
			for (int i = 0; i < num; i++)
			{
				int num2 = i * 1023;
				int num3 = Mathf.Min(1023, matrices.Count - num2);
				Matrix4x4[] array = (Matrix4x4[])(object)new Matrix4x4[num3];
				for (int j = 0; j < num3; j++)
				{
					array[j] = matrices[num2 + j];
				}
				_matrixChunks[i] = array;
			}
		}

		public bool Draw()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Mesh) || !Object.op_Implicit((Object)(object)InstancedMaterial) || _matrixChunks.Length == 0)
			{
				return false;
			}
			try
			{
				Matrix4x4[][] matrixChunks = _matrixChunks;
				foreach (Matrix4x4[] array in matrixChunks)
				{
					Graphics.DrawMeshInstanced(Mesh, SubMeshIndex, InstancedMaterial, array, array.Length, (MaterialPropertyBlock)null, ShadowCastingMode, ReceiveShadows, Layer, (Camera)null, LightProbeUsage, (LightProbeProxyVolume)null);
				}
				return true;
			}
			catch (Exception ex)
			{
				string[] obj = new string[6]
				{
					"[ValheimScalability] GPU instancing failed for mesh '",
					((Object)Mesh).name,
					"', material '",
					null,
					null,
					null
				};
				Material sourceMaterial = SourceMaterial;
				obj[3] = ((sourceMaterial != null) ? ((Object)sourceMaterial).name : null);
				obj[4] = "'. Falling back to original renderers. ";
				obj[5] = ex.Message;
				Debug.LogWarning((object)string.Concat(obj));
				return false;
			}
		}
	}
	public static class InstancedMaterialCache
	{
		private static readonly Dictionary<int, Material> Cache = new Dictionary<int, Material>();

		private static readonly HashSet<int> Unsupported = new HashSet<int>();

		public static Material GetOrCreate(Material source)
		{
			//IL_003b: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)source) || !SystemInfo.supportsInstancing)
			{
				return null;
			}
			int instanceID = ((Object)source).GetInstanceID();
			if (Unsupported.Contains(instanceID))
			{
				return null;
			}
			if (Cache.TryGetValue(instanceID, out Material value))
			{
				return value;
			}
			Material val = null;
			try
			{
				val = new Material(source)
				{
					name = ((Object)source).name + "_ValheimScalability_Instanced",
					hideFlags = (HideFlags)52
				};
				val.enableInstancing = true;
				if (!val.enableInstancing)
				{
					Object.Destroy((Object)(object)val);
					Unsupported.Add(instanceID);
					return null;
				}
				Cache[instanceID] = val;
				return val;
			}
			catch
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					Object.Destroy((Object)(object)val);
				}
				Unsupported.Add(instanceID);
				return null;
			}
		}

		public static void MarkUnsupported(Material source)
		{
			if (!Object.op_Implicit((Object)(object)source))
			{
				return;
			}
			int instanceID = ((Object)source).GetInstanceID();
			Unsupported.Add(instanceID);
			if (Cache.TryGetValue(instanceID, out Material value))
			{
				if (Object.op_Implicit((Object)(object)value))
				{
					Object.Destroy((Object)(object)value);
				}
				Cache.Remove(instanceID);
			}
		}

		public static void Clear()
		{
			foreach (Material value in Cache.Values)
			{
				if (Object.op_Implicit((Object)(object)value))
				{
					Object.Destroy((Object)(object)value);
				}
			}
			Cache.Clear();
			Unsupported.Clear();
		}
	}
	public readonly struct MaterialBatchIdentity : IEquatable<MaterialBatchIdentity>
	{
		private static readonly MethodInfo ComputeCrcMethod = typeof(Material).GetMethod("ComputeCRC", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);

		public readonly int ShaderId;

		public readonly int MaterialContentId;

		public readonly int RenderQueue;

		public readonly bool UsesContentCrc;

		public MaterialBatchIdentity(int shaderId, int materialContentId, int renderQueue, bool usesContentCrc)
		{
			ShaderId = shaderId;
			MaterialContentId = materialContentId;
			RenderQueue = renderQueue;
			UsesContentCrc = usesContentCrc;
		}

		public static MaterialBatchIdentity From(Material material)
		{
			if (!Object.op_Implicit((Object)(object)material))
			{
				return default(MaterialBatchIdentity);
			}
			int shaderId = (Object.op_Implicit((Object)(object)material.shader) ? ((Object)material.shader).GetInstanceID() : 0);
			if (TryComputeContentCrc(material, out var crc))
			{
				return new MaterialBatchIdentity(shaderId, crc, material.renderQueue, usesContentCrc: true);
			}
			return new MaterialBatchIdentity(shaderId, ((Object)material).GetInstanceID(), material.renderQueue, usesContentCrc: false);
		}

		private static bool TryComputeContentCrc(Material material, out int crc)
		{
			crc = 0;
			if (ComputeCrcMethod == null)
			{
				return false;
			}
			try
			{
				object obj = ComputeCrcMethod.Invoke(material, null);
				if (obj == null)
				{
					return false;
				}
				crc = (int)Convert.ToUInt32(obj);
				return true;
			}
			catch
			{
				return false;
			}
		}

		public bool Equals(MaterialBatchIdentity other)
		{
			if (ShaderId == other.ShaderId && MaterialContentId == other.MaterialContentId)
			{
				return RenderQueue == other.RenderQueue;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is MaterialBatchIdentity other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((ShaderId * 397) ^ MaterialContentId) * 397) ^ RenderQueue;
		}

		public override string ToString()
		{
			return $"{ShaderId:X8}:{MaterialContentId:X8}:Q{RenderQueue}";
		}
	}
	public sealed class PlayerClusterProximityTracker : MonoBehaviour
	{
		private Player _player;

		private Coroutine _coroutine;

		private void Awake()
		{
			_player = ((Component)this).GetComponent<Player>();
		}

		private void OnEnable()
		{
			if (_coroutine == null)
			{
				_coroutine = ((MonoBehaviour)this).StartCoroutine(ProximityCoroutine());
			}
		}

		private IEnumerator ProximityCoroutine()
		{
			while (Object.op_Implicit((Object)(object)this) && Object.op_Implicit((Object)(object)_player) && (Object)(object)Player.m_localPlayer != (Object)(object)_player)
			{
				yield return null;
			}
			while (Object.op_Implicit((Object)(object)this) && Object.op_Implicit((Object)(object)_player))
			{
				if ((Object)(object)Player.m_localPlayer == (Object)(object)_player && !Application.isBatchMode && ValheimScalabilityConfig.Mode == ClusterPresentationMode.Adaptive)
				{
					SectorMeshClusterManager.EnsureAttached()?.UpdateLocalPlayerProximity(((Component)_player).transform.position, Camera.main);
				}
				yield return (object)new WaitForSecondsRealtime(Mathf.Max(0.05f, ValheimScalabilityConfig.ProximityPollInterval));
			}
		}

		private void OnDisable()
		{
			if (_coroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_coroutine);
				_coroutine = null;
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)Player.m_localPlayer == (Object)(object)_player)
			{
				SectorMeshClusterManager.Instance?.ClearLocalPlayerProximity();
			}
		}
	}
	public sealed class SectorMeshClusterController : MonoBehaviour
	{
		private enum OptimizedPresentation
		{
			Uninitialized = -1,
			None,
			All,
			PieceLayerOnly
		}

		private sealed class ClusterCellState
		{
			public readonly int Index;

			public readonly Bounds WorldBounds;

			public readonly HashSet<GameObject> RegisteredRoots = new HashSet<GameObject>();

			public readonly HashSet<GameObject> DamagedRoots = new HashSet<GameObject>();

			public readonly Dictionary<GameObject, List<MeshRenderer>> SourceRenderersByRoot = new Dictionary<GameObject, List<MeshRenderer>>();

			public readonly Dictionary<GameObject, List<MeshRenderer>> CurrentlyHiddenRenderersByRoot = new Dictionary<GameObject, List<MeshRenderer>>();

			public readonly List<GeneratedRenderer> GeneratedRenderers = new List<GeneratedRenderer>();

			public readonly List<Mesh> GeneratedMeshes = new List<Mesh>();

			public readonly List<GameObject> GeneratedObjects = new List<GameObject>();

			public readonly List<InstancedClusterBatch> InstancedBatches = new List<InstancedClusterBatch>();

			public long EstimatedGeneratedMemoryBytes;

			public bool ClusterBuilt;

			public bool Dirty = true;

			public bool ContainsStaleGeometry;

			public bool NearLocalPlayer;

			public bool VisibleToLocalPlayer;

			public float NextBuildTime;

			public float SuspendedUntil;

			public OptimizedPresentation InstancedPresentation;

			public OptimizedPresentation CurrentPresentation = OptimizedPresentation.Uninitialized;

			public ClusterCellState(int index, Bounds worldBounds, float nextBuildTime)
			{
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				Index = index;
				WorldBounds = worldBounds;
				NextBuildTime = nextBuildTime;
			}
		}

		private readonly struct GeneratedRenderer
		{
			public readonly MeshRenderer Renderer;

			public readonly int Layer;

			public GeneratedRenderer(MeshRenderer renderer, int layer)
			{
				Renderer = renderer;
				Layer = layer;
			}
		}

		private sealed class CombinedBucket
		{
			public readonly Material Material;

			public readonly List<CombineInstance> Instances = new List<CombineInstance>();

			public CombinedBucket(Material material)
			{
				Material = material;
			}
		}

		private sealed class InstancedBucket
		{
			public readonly List<Matrix4x4> Matrices = new List<Matrix4x4>();
		}

		private readonly struct CombinedBucketKey : IEquatable<CombinedBucketKey>
		{
			public readonly MaterialBatchIdentity MaterialIdentity;

			public readonly int Layer;

			public readonly int LightmapIndex;

			public readonly ShadowCastingMode ShadowCastingMode;

			public readonly bool ReceiveShadows;

			public readonly LightProbeUsage LightProbeUsage;

			public readonly ReflectionProbeUsage ReflectionProbeUsage;

			public readonly uint RenderingLayerMask;

			public readonly int SortingLayerId;

			public readonly int SortingOrder;

			public CombinedBucketKey(Material material, int layer, int lightmapIndex, ShadowCastingMode shadowCastingMode, bool receiveShadows, LightProbeUsage lightProbeUsage, ReflectionProbeUsage reflectionProbeUsage, uint renderingLayerMask, int sortingLayerId, int sortingOrder)
			{
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				MaterialIdentity = MaterialBatchIdentity.From(material);
				Layer = layer;
				LightmapIndex = lightmapIndex;
				ShadowCastingMode = shadowCastingMode;
				ReceiveShadows = receiveShadows;
				LightProbeUsage = lightProbeUsage;
				ReflectionProbeUsage = reflectionProbeUsage;
				RenderingLayerMask = renderingLayerMask;
				SortingLayerId = sortingLayerId;
				SortingOrder = sortingOrder;
			}

			public bool Equals(CombinedBucketKey other)
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: 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_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				if (MaterialIdentity.Equals(other.MaterialIdentity) && Layer == other.Layer && LightmapIndex == other.LightmapIndex && ShadowCastingMode == other.ShadowCastingMode && ReceiveShadows == other.ReceiveShadows && LightProbeUsage == other.LightProbeUsage && ReflectionProbeUsage == other.ReflectionProbeUsage && RenderingLayerMask == other.RenderingLayerMask && SortingLayerId == other.SortingLayerId)
				{
					return SortingOrder == other.SortingOrder;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is CombinedBucketKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				//IL_0032: 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: 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: 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_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0076: 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_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Expected I4, but got Unknown
				return (int)((((((((((((((((((MaterialIdentity.GetHashCode() * 397) ^ Layer) * 397) ^ LightmapIndex) * 397) ^ ShadowCastingMode) * 397) ^ ReceiveShadows.GetHashCode()) * 397) ^ LightProbeUsage) * 397) ^ ReflectionProbeUsage) * 397) ^ RenderingLayerMask) * 397) ^ SortingLayerId) * 397) ^ SortingOrder);
			}
		}

		private readonly struct InstancedBucketKey : IEquatable<InstancedBucketKey>
		{
			public readonly Mesh Mesh;

			public readonly int SubMeshIndex;

			public readonly Material SourceMaterial;

			public readonly Material InstancedMaterial;

			public readonly int Layer;

			public readonly ShadowCastingMode ShadowCastingMode;

			public readonly bool ReceiveShadows;

			public readonly LightProbeUsage LightProbeUsage;

			public InstancedBucketKey(Mesh mesh, int subMeshIndex, Material sourceMaterial, Material instancedMaterial, int layer, ShadowCastingMode shadowCastingMode, bool receiveShadows, LightProbeUsage lightProbeUsage)
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: 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)
				Mesh = mesh;
				SubMeshIndex = subMeshIndex;
				SourceMaterial = sourceMaterial;
				InstancedMaterial = instancedMaterial;
				Layer = layer;
				ShadowCastingMode = shadowCastingMode;
				ReceiveShadows = receiveShadows;
				LightProbeUsage = lightProbeUsage;
			}

			public bool Equals(InstancedBucketKey other)
			{
				//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_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)Mesh == (Object)(object)other.Mesh && SubMeshIndex == other.SubMeshIndex && (Object)(object)SourceMaterial == (Object)(object)other.SourceMaterial && Layer == other.Layer && ShadowCastingMode == other.ShadowCastingMode && ReceiveShadows == other.ReceiveShadows)
				{
					return LightProbeUsage == other.LightProbeUsage;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is InstancedBucketKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: 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_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_0084: Expected I4, but got Unknown
				return ((((((((((((Object.op_Implicit((Object)(object)Mesh) ? ((Object)Mesh).GetInstanceID() : 0) * 397) ^ SubMeshIndex) * 397) ^ (Object.op_Implicit((Object)(object)SourceMaterial) ? ((Object)SourceMaterial).GetInstanceID() : 0)) * 397) ^ Layer) * 397) ^ ShadowCastingMode) * 397) ^ ReceiveShadows.GetHashCode()) * 397) ^ LightProbeUsage;
			}
		}

		private readonly Dictionary<GameObject, int> _rootToCell = new Dictionary<GameObject, int>();

		private readonly Dictionary<int, ClusterCellState> _cells = new Dictionary<int, ClusterCellState>();

		private readonly HashSet<GameObject> _hierarchyCandidateBuffer = new HashSet<GameObject>();

		private readonly List<GameObject> _deadRootBuffer = new List<GameObject>();

		private Vector2s _sector;

		private bool _initialized;

		private int _cellDivisions;

		private float _zoneSize;

		private float _cellSize;

		private float _nextDestroyedRootCleanupTime;

		private bool _isWarmCached;

		public Vector2s Sector => _sector;

		public bool HasRegisteredObjects => _rootToCell.Count > 0;

		public bool IsWarmCached => _isWarmCached;

		public long EstimatedGeneratedMemoryBytes
		{
			get
			{
				long num = 0L;
				foreach (ClusterCellState value in _cells.Values)
				{
					num += value.EstimatedGeneratedMemoryBytes;
				}
				return num;
			}
		}

		public void Initialize(Vector2s sector)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (!_initialized)
			{
				_initialized = true;
				_sector = sector;
				((Component)this).transform.SetPositionAndRotation(ZoneSystem.GetZonePos(sector), Quaternion.identity);
				((Component)this).transform.localScale = Vector3.one;
				RefreshCellDimensions();
			}
		}

		public bool Register(GameObject root)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)root) || !_initialized || _rootToCell.ContainsKey(root) || !CanRegisterRoot(root))
			{
				return false;
			}
			int cellIndex = GetCellIndex(root.transform.position);
			ClusterCellState orCreateCell = GetOrCreateCell(cellIndex);
			orCreateCell.RegisteredRoots.Add(root);
			orCreateCell.Dirty = true;
			orCreateCell.NextBuildTime = Mathf.Max(orCreateCell.NextBuildTime, Time.unscaledTime + ValheimScalabilityConfig.RegistrationSettleDelay);
			_rootToCell.Add(root, cellIndex);
			return true;
		}

		public void RegisterHierarchy(GameObject hierarchyRoot)
		{
			if (!Object.op_Implicit((Object)(object)hierarchyRoot))
			{
				return;
			}
			_hierarchyCandidateBuffer.Clear();
			MeshRenderer[] componentsInChildren = hierarchyRoot.GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val in componentsInChildren)
			{
				if (Object.op_Implicit((Object)(object)val) && !Object.op_Implicit((Object)(object)((Component)val).GetComponentInParent<ZNetView>()))
				{
					Transform val2 = FindTopLevelChild(hierarchyRoot.transform, ((Component)val).transform);
					if (Object.op_Implicit((Object)(object)val2))
					{
						_hierarchyCandidateBuffer.Add(((Component)val2).gameObject);
					}
				}
			}
			foreach (GameObject item in _hierarchyCandidateBuffer)
			{
				Register(item);
			}
			_hierarchyCandidateBuffer.Clear();
		}

		public void Unregister(GameObject root)
		{
			if (Object.op_Implicit((Object)(object)root) && _rootToCell.TryGetValue(root, out var value) && _cells.TryGetValue(value, out ClusterCellState value2))
			{
				_rootToCell.Remove(root);
				value2.RegisteredRoots.Remove(root);
				value2.DamagedRoots.Remove(root);
				value2.SourceRenderersByRoot.Remove(root);
				if (value2.CurrentlyHiddenRenderersByRoot.TryGetValue(root, out List<MeshRenderer> value3))
				{
					RestoreRendererList(value3);
					value2.CurrentlyHiddenRenderersByRoot.Remove(root);
				}
				InvalidateCellForRemovedGeometry(value2);
			}
		}

		public bool NotifyDamage(GameObject damagedObject)
		{
			if (!Object.op_Implicit((Object)(object)damagedObject))
			{
				return false;
			}
			GameObject val = FindRegisteredRoot(damagedObject.transform);
			if (!Object.op_Implicit((Object)(object)val) || !_rootToCell.TryGetValue(val, out var value) || !_cells.TryGetValue(value, out ClusterCellState value2))
			{
				return false;
			}
			value2.DamagedRoots.Add(val);
			value2.Dirty = true;
			value2.ContainsStaleGeometry = value2.ClusterBuilt;
			value2.SuspendedUntil = Mathf.Max(value2.SuspendedUntil, Time.unscaledTime + ValheimScalabilityConfig.DamageCooldown);
			TransitionPresentation(value2, OptimizedPresentation.None);
			if (_isWarmCached)
			{
				DestroyOptimizedRepresentations(value2);
				value2.ClusterBuilt = false;
			}
			return true;
		}

		public void UpdateLocalPlayerProximity(Vector3 playerPosition, Camera camera)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if (_isWarmCached)
			{
				return;
			}
			ClusterPresentationMode mode = ValheimScalabilityConfig.Mode;
			Plane[] array = null;
			if (mode == ClusterPresentationMode.Adaptive && ValheimScalabilityConfig.OnlyUnclusterVisibleCells && Object.op_Implicit((Object)(object)camera))
			{
				array = GeometryUtility.CalculateFrustumPlanes(camera);
			}
			foreach (ClusterCellState value in _cells.Values)
			{
				if (mode != ClusterPresentationMode.Adaptive)
				{
					value.NearLocalPlayer = false;
					value.VisibleToLocalPlayer = false;
					ApplyPresentation(value);
					continue;
				}
				value.NearLocalPlayer = GetCardinalDistanceToBounds(playerPosition, value.WorldBounds) <= ValheimScalabilityConfig.UnclusterRadius;
				if (!value.NearLocalPlayer)
				{
					value.VisibleToLocalPlayer = false;
				}
				else if (!ValheimScalabilityConfig.OnlyUnclusterVisibleCells || !Object.op_Implicit((Object)(object)camera) || array == null)
				{
					value.VisibleToLocalPlayer = true;
				}
				else
				{
					value.VisibleToLocalPlayer = GeometryUtility.TestPlanesAABB(array, value.WorldBounds);
				}
				ApplyPresentation(value);
			}
		}

		public void ClearLocalPlayerProximity()
		{
			foreach (ClusterCellState value in _cells.Values)
			{
				value.NearLocalPlayer = false;
				value.VisibleToLocalPlayer = false;
				ApplyPresentation(value);
			}
		}

		public void EnterWarmCache()
		{
			if (_isWarmCached)
			{
				return;
			}
			_isWarmCached = true;
			CleanupDestroyedRoots();
			foreach (ClusterCellState value in _cells.Values)
			{
				if (value.CurrentPresentation != OptimizedPresentation.None)
				{
					TransitionPresentation(value, OptimizedPresentation.None);
				}
				if (value.ContainsStaleGeometry)
				{
					DestroyOptimizedRepresentations(value);
					value.ClusterBuilt = false;
				}
				value.NearLocalPlayer = false;
				value.VisibleToLocalPlayer = false;
			}
		}

		public void ExitWarmCache()
		{
			if (!_isWarmCached)
			{
				return;
			}
			_isWarmCached = false;
			foreach (ClusterCellState value in _cells.Values)
			{
				value.CurrentPresentation = OptimizedPresentation.Uninitialized;
			}
		}

		public void RebuildForConfigurationChange()
		{
			List<GameObject> list = new List<GameObject>(_rootToCell.Count);
			HashSet<GameObject> hashSet = new HashSet<GameObject>();
			foreach (KeyValuePair<GameObject, int> item in _rootToCell)
			{
				if (Object.op_Implicit((Object)(object)item.Key))
				{
					list.Add(item.Key);
				}
			}
			foreach (ClusterCellState value3 in _cells.Values)
			{
				foreach (GameObject damagedRoot in value3.DamagedRoots)
				{
					if (Object.op_Implicit((Object)(object)damagedRoot))
					{
						hashSet.Add(damagedRoot);
					}
				}
				RestoreOriginalRenderers(value3);
				value3.CurrentPresentation = OptimizedPresentation.Uninitialized;
				DestroyOptimizedRepresentations(value3);
			}
			_rootToCell.Clear();
			_cells.Clear();
			RefreshCellDimensions();
			foreach (GameObject item2 in list)
			{
				Register(item2);
				if (hashSet.Contains(item2) && _rootToCell.TryGetValue(item2, out var value) && _cells.TryGetValue(value, out ClusterCellState value2))
				{
					value2.DamagedRoots.Add(item2);
				}
			}
		}

		public void Tick()
		{
			if (!_initialized || _isWarmCached)
			{
				return;
			}
			if (Time.unscaledTime >= _nextDestroyedRootCleanupTime)
			{
				_nextDestroyedRootCleanupTime = Time.unscaledTime + 2f;
				CleanupDestroyedRoots();
			}
			foreach (ClusterCellState value in _cells.Values)
			{
				if (ValheimScalabilityConfig.Mode == ClusterPresentationMode.Off)
				{
					if (value.CurrentPresentation != OptimizedPresentation.None)
					{
						TransitionPresentation(value, OptimizedPresentation.None);
					}
				}
				else if (value.RegisteredRoots.Count == 0)
				{
					RestoreOriginalRenderers(value);
					value.CurrentPresentation = OptimizedPresentation.Uninitialized;
					DestroyOptimizedRepresentations(value);
					value.ClusterBuilt = false;
					value.Dirty = true;
					value.ContainsStaleGeometry = false;
				}
				else
				{
					if (CanBuildCell(value))
					{
						BuildCluster(value);
					}
					ApplyPresentation(value);
				}
			}
		}

		private void LateUpdate()
		{
			if (_isWarmCached || ValheimScalabilityConfig.Mode == ClusterPresentationMode.Off || !ValheimScalabilityConfig.IsGpuInstancingEnabled)
			{
				return;
			}
			foreach (ClusterCellState value in _cells.Values)
			{
				if (value.InstancedPresentation == OptimizedPresentation.None)
				{
					continue;
				}
				foreach (InstancedClusterBatch instancedBatch in value.InstancedBatches)
				{
					if ((value.InstancedPresentation != OptimizedPresentation.PieceLayerOnly || instancedBatch.Layer == SectorMeshClusterSettings.PieceLayer) && !instancedBatch.Draw())
					{
						HandleInstancingFailure(value, instancedBatch.SourceMaterial);
						break;
					}
				}
			}
		}

		private bool CanBuildCell(ClusterCellState cell)
		{
			if (!cell.Dirty || Time.unscaledTime < cell.NextBuildTime || Time.unscaledTime < cell.SuspendedUntil)
			{
				return false;
			}
			if (ValheimScalabilityConfig.Mode == ClusterPresentationMode.Off)
			{
				return false;
			}
			if (ValheimScalabilityConfig.Mode == ClusterPresentationMode.Adaptive && cell.NearLocalPlayer && cell.VisibleToLocalPlayer)
			{
				return false;
			}
			return true;
		}

		private bool ShouldForceOriginals(ClusterCellState cell)
		{
			if (ValheimScalabilityConfig.Mode == ClusterPresentationMode.Off)
			{
				return true;
			}
			if (Time.unscaledTime < cell.SuspendedUntil)
			{
				return true;
			}
			if (cell.Dirty)
			{
				return cell.ContainsStaleGeometry;
			}
			return false;
		}

		private void ApplyPresentation(ClusterCellState cell)
		{
			OptimizedPresentation optimizedPresentation = DeterminePresentation(cell);
			if (cell.CurrentPresentation != optimizedPresentation)
			{
				TransitionPresentation(cell, optimizedPresentation);
			}
		}

		private OptimizedPresentation DeterminePresentation(ClusterCellState cell)
		{
			if (ValheimScalabilityConfig.Mode == ClusterPresentationMode.Off || !cell.ClusterBuilt || ShouldForceOriginals(cell))
			{
				return OptimizedPresentation.None;
			}
			if (ValheimScalabilityConfig.Mode != ClusterPresentationMode.Adaptive || !cell.NearLocalPlayer || !cell.VisibleToLocalPlayer)
			{
				return OptimizedPresentation.All;
			}
			if (!ValheimScalabilityConfig.KeepPieceLayerClusteredNearPlayer)
			{
				return OptimizedPresentation.None;
			}
			return OptimizedPresentation.PieceLayerOnly;
		}

		private void TransitionPresentation(ClusterCellState cell, OptimizedPresentation desired)
		{
			if (cell.CurrentPresentation != OptimizedPresentation.None)
			{
				RestoreOriginalRenderers(cell);
			}
			SetOptimizedPresentation(cell, desired);
			switch (desired)
			{
			case OptimizedPresentation.All:
				HideSourceRenderers(cell, null);
				break;
			case OptimizedPresentation.PieceLayerOnly:
				HideSourceRenderers(cell, SectorMeshClusterSettings.PieceLayer);
				break;
			default:
				RestoreOriginalRenderers(cell);
				break;
			}
			cell.CurrentPresentation = desired;
			if (ValheimScalabilityConfig.IsBatchDiagnosticsEnabled)
			{
				Debug.Log((object)$"[ValheimScalability] Presentation sector={_sector.x},{_sector.y} cell={cell.Index} -> {desired}; roots={cell.RegisteredRoots.Count}; optimizedSources={cell.SourceRenderersByRoot.Count}; hiddenRenderers={CountHiddenRenderers(cell)}; generatedRenderers={cell.GeneratedRenderers.Count}; instancedBatches={cell.InstancedBatches.Count}");
			}
		}

		private static int CountHiddenRenderers(ClusterCellState cell)
		{
			int num = 0;
			foreach (List<MeshRenderer> value in cell.CurrentlyHiddenRenderersByRoot.Values)
			{
				num += value.Count;
			}
			return num;
		}

		private void BuildCluster(ClusterCellState cell)
		{
			RestoreOriginalRenderers(cell);
			SetOptimizedPresentation(cell, OptimizedPresentation.None);
			cell.CurrentPresentation = OptimizedPresentation.Uninitialized;
			DestroyOptimizedRepresentations(cell);
			cell.SourceRenderersByRoot.Clear();
			Dictionary<CombinedBucketKey, CombinedBucket> dictionary = new Dictionary<CombinedBucketKey, CombinedBucket>();
			Dictionary<InstancedBucketKey, InstancedBucket> dictionary2 = new Dictionary<InstancedBucketKey, InstancedBucket>();
			int num = 0;
			foreach (GameObject registeredRoot in cell.RegisteredRoots)
			{
				if (Object.op_Implicit((Object)(object)registeredRoot) && !cell.DamagedRoots.Contains(registeredRoot) && CanRegisterRoot(registeredRoot))
				{
					num += CollectRootGeometry(registeredRoot, cell, dictionary, dictionary2);
				}
			}
			int num2 = CountCombinedDrawCalls(dictionary) + CountInstancedDrawCalls(dictionary2);
			if (num - num2 < ValheimScalabilityConfig.MinimumEstimatedDrawCallSavings)
			{
				cell.SourceRenderersByRoot.Clear();
				cell.ClusterBuilt = false;
				cell.Dirty = false;
				cell.ContainsStaleGeometry = false;
			}
			else
			{
				BuildCombinedMeshes(cell, dictionary);
				BuildInstancedBatches(cell, dictionary2);
				cell.ClusterBuilt = cell.GeneratedRenderers.Count > 0 || cell.InstancedBatches.Count > 0;
				UpdateEstimatedGeneratedMemory(cell);
				cell.Dirty = false;
				cell.ContainsStaleGeometry = false;
			}
		}

		private int CollectRootGeometry(GameObject root, ClusterCellState cell, Dictionary<CombinedBucketKey, CombinedBucket> combinedBuckets, Dictionary<InstancedBucketKey, InstancedBucket> instancedBuckets)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			HashSet<MeshRenderer> hashSet = new HashSet<MeshRenderer>();
			ZNetView component = root.GetComponent<ZNetView>();
			MeshRenderer[] componentsInChildren = root.GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val in componentsInChildren)
			{
				if (!TryGetRendererStrategy(root, component, val, out ClusterRenderStrategy strategy, out LODGroup selectedLodGroup, out Mesh mesh, out Material[] materials, out Material[] instancedMaterials))
				{
					continue;
				}
				bool flag = false;
				switch (strategy)
				{
				case ClusterRenderStrategy.CombinedMesh:
				{
					Matrix4x4 transform = ((Component)this).transform.worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
					for (int k = 0; k < mesh.subMeshCount; k++)
					{
						Material material = materials[k];
						CombinedBucketKey key2 = new CombinedBucketKey(material, ((Component)val).gameObject.layer, ((Renderer)val).lightmapIndex, ((Renderer)val).shadowCastingMode, ((Renderer)val).receiveShadows, ((Renderer)val).lightProbeUsage, ((Renderer)val).reflectionProbeUsage, ((Renderer)val).renderingLayerMask, ((Renderer)val).sortingLayerID, ((Renderer)val).sortingOrder);
						if (!combinedBuckets.TryGetValue(key2, out CombinedBucket value2))
						{
							value2 = new CombinedBucket(material);
							combinedBuckets.Add(key2, value2);
						}
						List<CombineInstance> instances = value2.Instances;
						CombineInstance item = default(CombineInstance);
						((CombineInstance)(ref item)).mesh = mesh;
						((CombineInstance)(ref item)).subMeshIndex = k;
						((CombineInstance)(ref item)).transform = transform;
						((CombineInstance)(ref item)).lightmapScaleOffset = ((Renderer)val).lightmapScaleOffset;
						instances.Add(item);
					}
					flag = true;
					break;
				}
				case ClusterRenderStrategy.Instanced:
				{
					Matrix4x4 localToWorldMatrix = ((Component)val).transform.localToWorldMatrix;
					for (int j = 0; j < mesh.subMeshCount; j++)
					{
						Material sourceMaterial = materials[j];
						Material instancedMaterial = instancedMaterials[j];
						InstancedBucketKey key = new InstancedBucketKey(mesh, j, sourceMaterial, instancedMaterial, ((Component)val).gameObject.layer, ((Renderer)val).shadowCastingMode, ((Renderer)val).receiveShadows, ((Renderer)val).lightProbeUsage);
						if (!instancedBuckets.TryGetValue(key, out InstancedBucket value))
						{
							value = new InstancedBucket();
							instancedBuckets.Add(key, value);
						}
						value.Matrices.Add(localToWorldMatrix);
					}
					flag = true;
					break;
				}
				}
				if (flag)
				{
					num += mesh.subMeshCount;
					hashSet.Add(val);
					if (Object.op_Implicit((Object)(object)selectedLodGroup))
					{
						AddAllLodRenderers(selectedLodGroup, hashSet);
					}
				}
			}
			if (hashSet.Count == 0)
			{
				return 0;
			}
			List<MeshRenderer> list = new List<MeshRenderer>(hashSet.Count);
			foreach (MeshRenderer item2 in hashSet)
			{
				if (Object.op_Implicit((Object)(object)item2))
				{
					list.Add(item2);
				}
			}
			if (list.Count > 0)
			{
				cell.SourceRenderersByRoot[root] = list;
			}
			return num;
		}

		private bool TryGetRendererStrategy(GameObject root, ZNetView rootNetView, MeshRenderer renderer, out ClusterRenderStrategy strategy, out LODGroup selectedLodGroup, out Mesh mesh, out Material[] materials, out Material[] instancedMaterials)
		{
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Invalid comparison between Unknown and I4
			strategy = ClusterRenderStrategy.Original;
			selectedLodGroup = null;
			mesh = null;
			materials = null;
			instancedMaterials = null;
			if (!Object.op_Implicit((Object)(object)renderer) || !((Renderer)renderer).enabled || !((Component)renderer).gameObject.activeInHierarchy || ((Renderer)renderer).forceRenderingOff)
			{
				return false;
			}
			if (DynamicHierarchyBatchExclusion.ShouldExcludeRenderer(renderer) || HasUnsafeDynamicRendering(((Component)renderer).gameObject))
			{
				return false;
			}
			if (!ClusterBatchFilter.IsLayerAllowed(((Component)renderer).gameObject.layer))
			{
				return false;
			}
			if (!ClusterBatchFilter.IsObjectAllowed(((Object)root).name, ((Object)((Component)renderer).gameObject).name))
			{
				return false;
			}
			if (ValheimScalabilityConfig.SkipPropertyBlockRenderers && ((Renderer)renderer).HasPropertyBlock())
			{
				return false;
			}
			if (HasAnimatorBetween(((Component)renderer).transform, root.transform))
			{
				return false;
			}
			ZNetView componentInParent = ((Component)renderer).GetComponentInParent<ZNetView>();
			if (Object.op_Implicit((Object)(object)rootNetView))
			{
				if (Object.op_Implicit((Object)(object)componentInParent) && (Object)(object)componentInParent != (Object)(object)rootNetView)
				{
					return false;
				}
			}
			else if (Object.op_Implicit((Object)(object)componentInParent))
			{
				return false;
			}
			if (!IsSelectedLodRenderer(renderer, root.transform, out selectedLodGroup))
			{
				return false;
			}
			MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>();
			if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.sharedMesh))
			{
				return false;
			}
			mesh = component.sharedMesh;
			materials = ((Renderer)renderer).sharedMaterials;
			if (mesh.subMeshCount <= 0 || materials.Length < mesh.subMeshCount)
			{
				return false;
			}
			for (int i = 0; i < mesh.subMeshCount; i++)
			{
				Material val = materials[i];
				if (!Object.op_Implicit((Object)(object)val) || !ClusterBatchFilter.IsMaterialAllowed(val) || !ClusterBatchFilter.IsShaderAllowed(val.shader))
				{
					return false;
				}
			}
			if (ClusterBatchFilter.IsInstancingCandidate(((Object)root).name, ((Object)((Component)renderer).gameObject).name, materials))
			{
				if (!ValheimScalabilityConfig.IsGpuInstancingEnabled || !SystemInfo.supportsInstancing || IsLightmapped(renderer) || (int)((Renderer)renderer).lightProbeUsage == 2 || ((Renderer)renderer).sortingLayerID != 0 || ((Renderer)renderer).sortingOrder != 0)
				{
					return false;
				}
				instancedMaterials = (Material[])(object)new Material[mesh.subMeshCount];
				for (int j = 0; j < mesh.subMeshCount; j++)
				{
					Material orCreate = InstancedMaterialCache.GetOrCreate(materials[j]);
					if (!Object.op_Implicit((Object)(object)orCreate))
					{
						return false;
					}
					instancedMaterials[j] = orCreate;
				}
				strategy = ClusterRenderStrategy.Instanced;
				return true;
			}
			if (!mesh.isReadable)
			{
				return false;
			}
			strategy = ClusterRenderStrategy.CombinedMesh;
			return true;
		}

		private static bool IsLightmapped(MeshRenderer renderer)
		{
			if (((Renderer)renderer).lightmapIndex >= 0)
			{
				return ((Renderer)renderer).lightmapIndex < 65534;
			}
			return false;
		}

		private static int CountCombinedDrawCalls(Dictionary<CombinedBucketKey, CombinedBucket> buckets)
		{
			int num = 0;
			foreach (KeyValuePair<CombinedBucketKey, CombinedBucket> bucket in buckets)
			{
				if (Object.op_Implicit((Object)(object)bucket.Value.Material) && bucket.Value.Instances.Count > 0)
				{
					num++;
				}
			}
			return num;
		}

		private static int CountInstancedDrawCalls(Dictionary<InstancedBucketKey, InstancedBucket> buckets)
		{
			int num = 0;
			foreach (InstancedBucket value in buckets.Values)
			{
				if (value.Matrices.Count != 0)
				{
					num += Mathf.CeilToInt((float)value.Matrices.Count / 1023f);
				}
			}
			return num;
		}

		private void BuildCombinedMeshes(ClusterCellState cell, Dictionary<CombinedBucketKey, CombinedBucket> buckets)
		{
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Expected O, but got Unknown
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<CombinedBucketKey, CombinedBucket> bucket in buckets)
			{
				CombinedBucketKey key = bucket.Key;
				CombinedBucket value = bucket.Value;
				Material material = value.Material;
				if (Object.op_Implicit((Object)(object)material) && value.Instances.Count != 0)
				{
					if (ValheimScalabilityConfig.IsBatchDiagnosticsEnabled)
					{
						Debug.Log((object)$"[ValheimScalability] Combined batch sector={_sector.x},{_sector.y} cell={cell.Index} material='{((Object)material).name}' materialKey={key.MaterialIdentity} instances={value.Instances.Count} layer={key.Layer} lightmap={key.LightmapIndex} shadows={key.ShadowCastingMode} receiveShadows={key.ReceiveShadows} lightProbes={key.LightProbeUsage} reflectionProbes={key.ReflectionProbeUsage} renderingLayerMask={key.RenderingLayerMask} sortingLayer={key.SortingLayerId} sortingOrder={key.SortingOrder}");
					}
					Mesh val = new Mesh();
					((Object)val).name = $"ValheimScalability_Sector_{_sector.x}_{_sector.y}_Cell_{cell.Index}_{((Object)material).name}";
					val.indexFormat = (IndexFormat)1;
					Mesh val2 = val;
					bool flag = key.LightmapIndex >= 0 && key.LightmapIndex < 65534;
					val2.CombineMeshes(value.Instances.ToArray(), true, true, flag);
					val2.RecalculateBounds();
					GameObject val3 = new GameObject($"Combined_{_sector.x}_{_sector.y}_Cell_{cell.Index}_{((Object)material).name}_x{value.Instances.Count}");
					val3.layer = key.Layer;
					val3.transform.SetParent(((Component)this).transform, false);
					val3.transform.localPosition = Vector3.zero;
					val3.transform.localRotation = Quaternion.identity;
					val3.transform.localScale = Vector3.one;
					val3.AddComponent<MeshFilter>().sharedMesh = val2;
					MeshRenderer val4 = val3.AddComponent<MeshRenderer>();
					((Renderer)val4).sharedMaterial = material;
					((Renderer)val4).shadowCastingMode = key.ShadowCastingMode;
					((Renderer)val4).receiveShadows = key.ReceiveShadows;
					((Renderer)val4).lightProbeUsage = key.LightProbeUsage;
					((Renderer)val4).reflectionProbeUsage = key.ReflectionProbeUsage;
					((Renderer)val4).renderingLayerMask = key.RenderingLayerMask;
					((Renderer)val4).sortingLayerID = key.SortingLayerId;
					((Renderer)val4).sortingOrder = key.SortingOrder;
					if (flag)
					{
						((Renderer)val4).lightmapIndex = key.LightmapIndex;
					}
					((Renderer)val4).enabled = false;
					cell.GeneratedMeshes.Add(val2);
					cell.GeneratedObjects.Add(val3);
					cell.GeneratedRenderers.Add(new GeneratedRenderer(val4, key.Layer));
				}
			}
		}

		private static void BuildInstancedBatches(ClusterCellState cell, Dictionary<InstancedBucketKey, InstancedBucket> buckets)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<InstancedBucketKey, InstancedBucket> bucket in buckets)
			{
				InstancedBucketKey key = bucket.Key;
				InstancedBucket value = bucket.Value;
				if (Object.op_Implicit((Object)(object)key.Mesh) && Object.op_Implicit((Object)(object)key.SourceMaterial) && Object.op_Implicit((Object)(object)key.InstancedMaterial) && value.Matrices.Count != 0)
				{
					cell.InstancedBatches.Add(new InstancedClusterBatch(key.Mesh, key.SubMeshIndex, key.SourceMaterial, key.InstancedMaterial, key.Layer, key.ShadowCastingMode, key.ReceiveShadows, key.LightProbeUsage, value.Matrices));
				}
			}
		}

		private void HandleInstancingFailure(ClusterCellState cell, Material sourceMaterial)
		{
			InstancedMaterialCache.MarkUnsupported(sourceMaterial);
			TransitionPresentation(cell, OptimizedPresentation.None);
			cell.Dirty = true;
			cell.ContainsStaleGeometry = true;
			cell.NextBuildTime = Time.unscaledTime + ValheimScalabilityConfig.RemovalRebuildDelay;
		}

		private bool CanRegisterRoot(GameObject root)
		{
			if (!Object.op_Implicit((Object)(object)root) || Object.op_Implicit((Object)(object)root.GetComponentInParent<Character>()) || DynamicHierarchyBatchExclusion.ShouldExclude(root) || HasUnsafeDynamicRendering(root))
			{
				return false;
			}
			MeshRenderer[] componentsInChildren = root.GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val in componentsInChildren)
			{
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)((Component)val).GetComponent<MeshFilter>()))
				{
					return true;
				}
			}
			return false;
		}

		private void InvalidateCellForRemovedGeometry(ClusterCellState cell)
		{
			cell.Dirty = true;
			cell.ContainsStaleGeometry = cell.ClusterBuilt;
			cell.NextBuildTime = Mathf.Max(cell.NextBuildTime, Time.unscaledTime + ValheimScalabilityConfig.RemovalRebuildDelay);
			if (cell.ContainsStaleGeometry)
			{
				TransitionPresentation(cell, OptimizedPresentation.None);
				if (_isWarmCached)
				{
					DestroyOptimizedRepresentations(cell);
					cell.ClusterBuilt = false;
				}
			}
		}

		private void RefreshCellDimensions()
		{
			_zoneSize = (Object.op_Implicit((Object)(object)ZoneSystem.instance) ? ZoneSystem.instance.m_zoneSize : 64f);
			_cellDivisions = ((ValheimScalabilityConfig.Mode == ClusterPresentationMode.FullCluster && ValheimScalabilityConfig.UseSingleCellInFullCluster) ? 1 : Mathf.Clamp(ValheimScalabilityConfig.CellDivisions, 1, 8));
			_cellSize = _zoneSize / (float)_cellDivisions;
		}

		private ClusterCellState GetOrCreateCell(int cellIndex)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (_cells.TryGetValue(cellIndex, out ClusterCellState value))
			{
				return value;
			}
			ClusterCellState clusterCellState = new ClusterCellState(cellIndex, GetCellBounds(cellIndex), Time.unscaledTime + ValheimScalabilityConfig.InitialBuildDelay);
			_cells.Add(cellIndex, clusterCellState);
			return clusterCellState;
		}

		private int GetCellIndex(Vector3 worldPosition)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			Vector3 zonePos = ZoneSystem.GetZonePos(_sector);
			float num = _zoneSize * 0.5f;
			float num2 = Mathf.Clamp(worldPosition.x - (zonePos.x - num), 0f, _zoneSize - 0.001f);
			float num3 = Mathf.Clamp(worldPosition.z - (zonePos.z - num), 0f, _zoneSize - 0.001f);
			int num4 = Mathf.Clamp(Mathf.FloorToInt(num2 / _cellSize), 0, _cellDivisions - 1);
			return Mathf.Clamp(Mathf.FloorToInt(num3 / _cellSize), 0, _cellDivisions - 1) * _cellDivisions + num4;
		}

		private Bounds GetCellBounds(int cellIndex)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0077: 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)
			int num = cellIndex % _cellDivisions;
			int num2 = cellIndex / _cellDivisions;
			Vector3 zonePos = ZoneSystem.GetZonePos(_sector);
			float num3 = _zoneSize * 0.5f;
			float num4 = zonePos.x - num3 + (float)num * _cellSize;
			float num5 = zonePos.z - num3 + (float)num2 * _cellSize;
			return new Bounds(new Vector3(num4 + _cellSize * 0.5f, zonePos.y, num5 + _cellSize * 0.5f), new Vector3(_cellSize, ValheimScalabilityConfig.VisibilityHeight, _cellSize));
		}

		private static float GetCardinalDistanceToBounds(Vector3 point, Bounds bounds)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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)
			Vector3 min = ((Bounds)(ref bounds)).min;
			Vector3 max = ((Bounds)(ref bounds)).max;
			float num = ((point.x < min.x) ? (min.x - point.x) : ((point.x > max.x) ? (point.x - max.x) : 0f));
			float num2 = ((point.z < min.z) ? (min.z - point.z) : ((point.z > max.z) ? (point.z - max.z) : 0f));
			return num + num2;
		}

		private GameObject FindRegisteredRoot(Transform start)
		{
			Transform val = start;
			while (Object.op_Implicit((Object)(object)val))
			{
				if (_rootToCell.ContainsKey(((Component)val).gameObject))
				{
					return ((Component)val).gameObject;
				}
				val = val.parent;
			}
			return null;
		}

		private static Transform FindTopLevelChild(Transform hierarchyRoot, Transform item)
		{
			if (!Object.op_Implicit((Object)(object)hierarchyRoot) || !Object.op_Implicit((Object)(object)item))
			{
				return null;
			}
			if ((Object)(object)item == (Object)(object)hierarchyRoot)
			{
				return item;
			}
			Transform val = item;
			while (Object.op_Implicit((Object)(object)val.parent) && (Object)(object)val.parent != (Object)(object)hierarchyRoot)
			{
				val = val.parent;
			}
			if (!((Object)(object)val.parent == (Object)(object)hierarchyRoot))
			{
				return null;
			}
			return val;
		}

		private static bool IsSelectedLodRenderer(MeshRenderer renderer, Transform root, out LODGroup lodGroup)
		{
			lodGroup = FindNearestLodGroup(((Component)renderer).transform, root);
			if (!Object.op_Implicit((Object)(object)lodGroup))
			{
				return true;
			}
			LOD[] lODs = lodGroup.GetLODs();
			if (lODs.Length == 0)
			{
				return true;
			}
			int num = 0;
			if (ValheimScalabilityConfig.UseLowestLod)
			{
				for (int num2 = lODs.Length - 1; num2 >= 0; num2--)
				{
					if (lODs[num2].renderers != null && lODs[num2].renderers.Length != 0)
					{
						num = num2;
						break;
					}
				}
			}
			Renderer[] renderers = lODs[num].renderers;
			for (int i = 0; i < renderers.Length; i++)
			{
				if ((Object)(object)renderers[i] == (Object)(object)renderer)
				{
					return true;
				}
			}
			return false;
		}

		private static LODGroup FindNearestLodGroup(Transform start, Transform root)
		{
			Transform val = start;
			while (Object.op_Implicit((Object)(object)val))
			{
				LODGroup component = ((Component)val).GetComponent<LODGroup>();
				if (Object.op_Implicit((Object)(object)component))
				{
					return component;
				}
				if ((Object)(object)val == (Object)(object)root)
				{
					break;
				}
				val = val.parent;
			}
			return null;
		}

		private static void AddAllLodRenderers(LODGroup lodGroup, HashSet<MeshRenderer> target)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			LOD[] lODs = lodGroup.GetLODs();
			foreach (LOD val in lODs)
			{
				if (val.renderers == null)
				{
					continue;
				}
				Renderer[] renderers = val.renderers;
				foreach (Renderer obj in renderers)
				{
					MeshRenderer val2 = (MeshRenderer)(object)((obj is MeshRenderer) ? obj : null);
					if (val2 != null && Object.op_Implicit((Object)(object)val2))
					{
						target.Add(val2);
					}
				}
			}
		}

		private static bool HasUnsafeDynamicRendering(GameObject root)
		{
			if (!Object.op_Implicit((Object)(object)root))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)root.GetComponentInChildren<Cloth>(true)))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)root.GetComponentInChildren<SkinnedMeshRenderer>(true)))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)root.GetComponentInChildren<Animator>(true)))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)root.GetComponentInChildren<Animation>(true)))
			{
				return true;
			}
			return false;
		}

		private static bool HasAnimatorBetween(Transform start, Transform root)
		{
			Transform val = start;
			while (Object.op_Implicit((Object)(object)val))
			{
				if (Object.op_Implicit((Object)(object)((Component)val).GetComponent<Animator>()))
				{
					return true;
				}
				if ((Object)(object)val == (Object)(object)root)
				{
					break;
				}
				val = val.parent;
			}
			return false;
		}

		private static void HideSourceRenderers(ClusterCellState cell, int? onlyLayer)
		{
			foreach (KeyValuePair<GameObject, List<MeshRenderer>> item in cell.SourceRenderersByRoot)
			{
				GameObject key = item.Key;
				if (!Object.op_Implicit((Object)(object)key) || cell.DamagedRoots.Contains(key))
				{
					continue;
				}
				if (!cell.CurrentlyHiddenRenderersByRoot.TryGetValue(key, out List<MeshRenderer> value))
				{
					value = new List<MeshRenderer>();
					cell.CurrentlyHiddenRenderersByRoot.Add(key, value);
				}
				foreach (MeshRenderer item2 in item.Value)
				{
					if (Object.op_Implicit((Object)(object)item2) && ((Renderer)item2).enabled && ((Component)item2).gameObject.activeInHierarchy && (!onlyLayer.HasValue || ((Component)item2).gameObject.layer == onlyLayer.Value))
					{
						((Renderer)item2).enabled = false;
						if (!value.Contains(item2))
						{
							value.Add(item2);
						}
					}
				}
			}
		}

		private static void RestoreOriginalRenderers(ClusterCellState cell)
		{
			foreach (KeyValuePair<GameObject, List<MeshRenderer>> item in cell.CurrentlyHiddenRenderersByRoot)
			{
				RestoreRendererList(item.Value);
			}
			cell.CurrentlyHiddenRenderersByRoot.Clear();
		}

		private static void RestoreRendererList(List<MeshRenderer> renderers)
		{
			foreach (MeshRenderer renderer in renderers)
			{
				if (Object.op_Implicit((Object)(object)renderer))
				{
					((Renderer)renderer).enabled = true;
				}
			}
			renderers.Clear();
		}

		private static void SetOptimizedPresentation(ClusterCellState cell, OptimizedPresentation presentation)
		{
			cell.InstancedPresentation = presentation;
			foreach (GeneratedRenderer generatedRenderer in cell.GeneratedRenderers)
			{
				if (Object.op_Implicit((Object)(object)generatedRenderer.Renderer))
				{
					((Renderer)generatedRenderer.Renderer).enabled = presentation switch
					{
						OptimizedPresentation.PieceLayerOnly => generatedRenderer.Layer == SectorMeshClusterSettings.PieceLayer, 
						OptimizedPresentation.All => true, 
						_ => false, 
					};
				}
			}
		}

		private static void DestroyOptimizedRepresentations(ClusterCellState cell)
		{
			SetOptimizedPresentation(cell, OptimizedPresentation.None);
			foreach (GameObject generatedObject in cell.GeneratedObjects)
			{
				if (Object.op_Implicit((Object)(object)generatedObject))
				{
					Object.Destroy((Object)(object)generatedObject);
				}
			}
			foreach (Mesh generatedMesh in cell.GeneratedMeshes)
			{
				if (Object.op_Implicit((Object)(object)generatedMesh))
				{
					Object.Destroy((Object)(object)generatedMesh);
				}
			}
			cell.GeneratedObjects.Clear();
			cell.GeneratedRenderers.Clear();
			cell.GeneratedMeshes.Clear();
			cell.InstancedBatches.Clear();
			cell.EstimatedGeneratedMemoryBytes = 0L;
		}

		private static void UpdateEstimatedGeneratedMemory(ClusterCellState cell)
		{
			long num = 0L;
			foreach (Mesh generatedMesh in cell.GeneratedMeshes)
			{
				if (Object.op_Implicit((Object)(object)generatedMesh))
				{
					try
					{
						num += Profiler.GetRuntimeMemorySizeLong((Object)(object)generatedMesh);
					}
					catch
					{
						num += (long)generatedMesh.vertexCount * 64L;
					}
				}
			}
			foreach (InstancedClusterBatch instancedBatch in cell.InstancedBatches)
			{
				if (instancedBatch != null)
				{
					num += instancedBatch.EstimatedMemoryBytes;
				}
			}
			num += (long)cell.GeneratedObjects.Count * 2048L;
			cell.EstimatedGeneratedMemoryBytes = num;
		}

		private void CleanupDestroyedRoots()
		{
			_deadRootBuffer.Clear();
			foreach (KeyValuePair<GameObject, int> item in _rootToCell)
			{
				if (!Object.op_Implicit((Object)(object)item.Key))
				{
					_deadRootBuffer.Add(item.Key);
				}
			}
			foreach (GameObject item2 in _deadRootBuffer)
			{
				if (_rootToCell.TryGetValue(item2, out var value))
				{
					_rootToCell.Remove(item2);
					if (_cells.TryGetValue(value, out ClusterCellState value2))
					{
						value2.RegisteredRoots.Remove(item2);
						value2.DamagedRoots.Remove(item2);
						value2.SourceRenderersByRoot.Remove(item2);
						value2.CurrentlyHiddenRenderersByRoot.Remove(item2);
						InvalidateCellForRemovedGeometry(value2);
					}
				}
			}
			_deadRootBuffer.Clear();
		}

		private void OnDisable()
		{
			foreach (ClusterCellState value in _cells.Values)
			{
				SetOptimizedPresentation(value, OptimizedPresentation.None);
				RestoreOriginalRenderers(value);
				value.CurrentPresentation = OptimizedPresentation.Uninitialized;
			}
		}

		private void OnDestroy()
		{
			foreach (ClusterCellState value in _cells.Values)
			{
				RestoreOriginalRenderers(value);
				DestroyOptimizedRepresentations(value);
			}
			_rootToCell.Clear();
			_cells.Clear();
		}
	}
	public sealed class SectorMeshClusterManager : MonoBehaviour
	{
		private sealed class SectorCacheState
		{
			public bool IsActive;

			public int VisitCount;

			public float LastVisitCountTime;

			public float LastTouchTime;

			public float LastActiveTime;

			public float WarmSince;
		}

		private sealed class WarmCacheCandidate
		{
			public readonly Vector2s Sector;

			public readonly SectorMeshClusterController Controller;

			public readonly SectorCacheState State;

			public readonly long Bytes;

			public readonly bool IsFrequent;

			public bool Evicted;

			public WarmCacheCandidate(Vector2s sector, SectorMeshClusterController controller, SectorCacheState state, long bytes, bool isFrequent)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				Sector = sector;
				Controller = controller;
				State = state;
				Bytes = bytes;
				IsFrequent = isFrequent;
			}

			public static int CompareFrequentEvictionOrder(WarmCacheCandidate left, WarmCacheCandidate right)
			{
				if (left.IsFrequent != right.IsFrequent)
				{
					if (!left.IsFrequent)
					{
						return 1;
					}
					return -1;
				}
				int num = left.State.LastActiveTime.CompareTo(right.State.LastActiveTime);
				if (num != 0)
				{
					return num;
				}
				return right.Bytes.CompareTo(left.Bytes);
			}

			public static int CompareGlobalEvictionOrder(WarmCacheCandidate left, WarmCacheCandidate right)
			{
				if (left.IsFrequent != right.IsFrequent)
				{
					if (!left.IsFrequent)
					{
						return -1;
					}
					return 1;
				}
				int num = left.State.LastActiveTime.CompareTo(right.State.LastActiveTime);
				if (num != 0)
				{
					return num;
				}
				return right.Bytes.CompareTo(left.Bytes);
			}
		}

		private const float ActiveTouchGraceSeconds = 3f;

		private const float MinimumVisitCountIntervalSeconds = 30f;

		private const int MaxColdHistoryEntries = 4096;

		private readonly Dictionary<Vector2s, SectorMeshClusterController> _sectorControllers = new Dictionary<Vector2s, SectorMeshClusterController>();

		private readonly Dictionary<Vector2s, SectorCacheState> _sectorCacheStates = new Dictionary<Vector2s, SectorCacheState>();

		private readonly Dictionary<int, Vector2s> _networkObjectSectors = new Dictionary<int, Vector2s>();

		private readonly List<Vector2s> _deadSectorBuffer = new List<Vector2s>();

		private readonly List<int> _networkIdBuffer = new List<int>();

		private readonly List<WarmCacheCandidate> _warmCandidateBuffer = new List<WarmCacheCandidate>();

		private readonly List<Vector2s> _historyPruneBuffer = new List<Vector2s>();

		private float _nextMaintenanceTime;

		public static SectorMeshClusterManager Instance { get; private set; }

		public static SectorMeshClusterManager EnsureAttached()
		{
			if (Object.op_Implicit((Object)(object)Instance))
			{
				return Instance;
			}
			if (Application.isBatchMode || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return null;
			}
			SectorMeshClusterManager component = ((Component)ZNetScene.instance).GetComponent<SectorMeshClusterManager>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return ((Component)ZNetScene.instance).gameObject.AddComponent<SectorMeshClusterManager>();
			}
			return component;
		}

		private void Awake()
		{
			if (Object.op_Implicit((Object)(object)Instance) && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)this);
			}
			else
			{
				Instance = this;
			}
		}

		public void RegisterNetworkObject(ZDO zdo, ZNetView nview)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (zdo != null && Object.op_Implicit((Object)(object)nview) && !Application.isBatchMode && !DynamicHierarchyBatchExclusion.ShouldExclude(zdo, ((Component)nview).gameObject))
			{
				Vector2s sector = zdo.GetSector();
				SectorMeshClusterController orCreateController = GetOrCreateController(sector);
				ActivateSector(sector, orCreateController, countVisit: true);
				if (orCreateController.Register(((Component)nview).gameObject))
				{
					_networkObjectSectors[((Object)((Component)nview).gameObject).GetInstanceID()] = sector;
				}
			}
		}

		public void UnregisterNetworkObject(ZNetView nview)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)nview))
			{
				return;
			}
			int instanceID = ((Object)((Component)nview).gameObject).GetInstanceID();
			if (_networkObjectSectors.TryGetValue(instanceID, out var value))
			{
				if (_sectorControllers.TryGetValue(value, out SectorMeshClusterController value2) && Object.op_Implicit((Object)(object)value2))
				{
					value2.Unregister(((Component)nview).gameObject);
				}
				_networkObjectSectors.Remove(instanceID);
				return;
			}
			ZDO zDO = nview.GetZDO();
			value = ((zDO != null) ? zDO.GetSector() : ZoneSystem.GetZone(((Component)nview).transform.position));
			if (_sectorControllers.TryGetValue(value, out SectorMeshClusterController value3) && Object.op_Implicit((Object)(object)value3))
			{
				value3.Unregister(((Component)nview).gameObject);
			}
		}

		public void RegisterZoneHierarchy(Vector2s sector, GameObject hierarchyRoot)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)hierarchyRoot) && !Application.isBatchMode)
			{
				SectorMeshClusterController orCreateController = GetOrCreateController(sector);
				ActivateSector(sector, orCreateController, countVisit: true);
				orCreateController.RegisterHierarchy(hierarchyRoot);
				RegisterExistingNetworkObjectsInSector(sector, orCreateController);
			}
		}

		public void RegisterLocationHierarchy(GameObject locationRoot)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)locationRoot) && !Application.isBatchMode)
			{
				Vector2s zone = ZoneSystem.GetZone(locationRoot.transform.position);
				SectorMeshClusterController orCreateController = GetOrCreateController(zone);
				ActivateSector(zone, orCreateController, countVisit: true);
				orCreateController.RegisterHierarchy(locationRoot);
			}
		}

		public void NotifyDamage(GameObject damagedObject)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0085: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)damagedObject) && !Application.isBatchMode)
			{
				ZNetView componentInParent = damagedObject.GetComponentInParent<ZNetView>();
				Vector2s value;
				Vector2s val = ((Object.op_Implicit((Object)(object)componentInParent) && _networkObjectSectors.TryGetValue(((Object)((Component)componentInParent).gameObject).GetInstanceID(), out value)) ? value : ((!Object.op_Implicit((Object)(object)componentInParent) || componentInParent.GetZDO() == null) ? ZoneSystem.GetZone(damagedObject.transform.position) : componentInParent.GetZDO().GetSector()));
				if (_sectorControllers.TryGetValue(val, out SectorMeshClusterController value2) && Object.op_Implicit((Object)(object)value2))
				{
					ActivateSector(val, value2, countVisit: false);
					value2.NotifyDamage(damagedObject);
				}
			}
		}

		public void UpdateLocalPlayerProximity(Vector3 playerPosition, Camera camera)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (ValheimScalabilityConfig.Mode != ClusterPresentationMode.Adaptive)
			{
				return;
			}
			foreach (KeyValuePair<Vector2s, SectorMeshClusterController> sectorController in _sectorControllers)
			{
				SectorMeshClusterController value = sectorController.Value;
				if (Object.op_Implicit((Object)(object)value) && !value.IsWarmCached)
				{
					value.UpdateLocalPlayerProximity(playerPosition, camera);
				}
			}
		}

		public void ClearLocalPlayerProximity()
		{
			foreach (SectorMeshClusterController value in _sectorControllers.Values)
			{
				if (Object.op_Implicit((Object)(object)value) && !value.IsWarmCached)
				{
					value.ClearLocalPlayerProximity();
				}
			}
		}

		public void RebuildAllForConfigurationChange()
		{
			ClusterBatchFilter.Invalidate();
			SectorMeshClusterSettings.InvalidateLayerCache();
			foreach (SectorMeshClusterController value in _sectorControllers.Values)
			{
				if (Object.op_Implicit((Object)(object)value))
				{
					value.RebuildForConfigurationChange();
				}
			}
		}

		private SectorMeshClusterController GetOrCreateController(Vector2s sector)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (_sectorControllers.TryGetValue(sector, out SectorMeshClusterController value) && Object.op_Implicit((Object)(object)value))
			{
				return value;
			}
			GameObject val = new GameObject($"ValheimScalability_SectorMeshCluster_{sector.x}_{sector.y}");
			val.transform.SetParent(((Component)this).transform, true);
			val.transform.SetPositionAndRotation(ZoneSystem.GetZonePos(sector), Quaternion.identity);
			val.transform.localScale = Vector3.one;
			SectorMeshClusterController sectorMeshClusterController = val.AddComponent<SectorMeshClusterController>();
			sectorMeshClusterController.Initialize(sector);
			_sectorControllers[sector] = sectorMeshClusterController;
			SectorCacheState orCreateCacheState = GetOrCreateCacheState(sector);
			float num = (orCreateCacheState.LastActiveTime = (orCreateCacheState.LastTouchTime = Time.unscaledTime));
			if (orCreateCacheState.VisitCount <= 0)
			{
				orCreateCacheState.VisitCount = 1;
				orCreateCacheState.LastVisitCountTime = num;
			}
			else if (!orCreateCacheState.IsActive && num - orCreateCacheState.LastVisitCountTime >= 30f)
			{
				orCreateCacheState.VisitCount++;
				orCreateCacheState.LastVisitCountTime = num;
			}
			orCreateCacheState.IsActive = true;
			return sectorMeshClusterController;
		}

		private SectorCacheState GetOrCreateCacheState(Vector2s sector)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (_sectorCacheStates.TryGetValue(sector, out SectorCacheState value))
			{
				return value;
			}
			SectorCacheState sectorCacheState = new SectorCacheState();
			_sectorCacheStates.Add(sector, sectorCacheState);
			return sectorCacheState;
		}

		private void ActivateSector(Vector2s sector, SectorMeshClusterController controller, bool countVisit)
		{
			//IL_000a: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)controller))
			{
				return;
			}
			SectorCacheState orCreateCacheState = GetOrCreateCacheState(sector);
			float num = (orCreateCacheState.LastActiveTime = (orCreateCacheState.LastTouchTime = Time.unscaledTime));
			if (!orCreateCacheState.IsActive)
			{
				orCreateCacheState.IsActive = true;
				if (countVisit && num - orCreateCacheState.LastVisitCountTime >= 30f)
				{
					orCreateCacheState.VisitCount++;
					orCreateCacheState.LastVisitCountTime = num;
				}
				controller.ExitWarmCache();
				if (ValheimScalabilityConfig.IsCacheDiagnosticsEnabled)
				{
					Debug.Log((object)$"[ValheimScalability] Warm-cache hit/reactivation sector={sector.x},{sector.y} visits={orCreateCacheState.VisitCount} retained={FormatMegabytes(controller.EstimatedGeneratedMemoryBytes)} MB");
				}
			}
			else if (controller.IsWarmCached)
			{
				controller.ExitWarmCache();
			}
		}

		private void RegisterExistingNetworkObjectsInSector(Vector2s sector, SectorMeshClusterController controller)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)controller) || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return;
			}
			foreach (KeyValuePair<ZDO, ZNetView> instance in ZNetScene.instance.m_instances)
			{
				ZDO key = instance.Key;
				ZNetView value = instance.Value;
				if (key != null && Object.op_Implicit((Object)(object)value) && !(key.GetSector() != sector) && controller.Register(((Component)value).gameObject))
				{
					_networkObjectSectors[((Object)((Component)value).gameObject).GetInstanceID()] = sector;
				}
			}
		}

		private void Update()
		{
			//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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			if (Application.isBatchMode || Time.unscaledTime < _nextMaintenanceTime)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			_nextMaintenanceTime = unscaledTime + ValheimScalabilityConfig.MaintenanceInterval;
			_deadSectorBuffer.Clear();
			foreach (KeyValuePair<Vector2s, SectorMeshClusterController> sectorController in _sectorControllers)
			{
				Vector2s key = sectorController.Key;
				SectorMeshClusterController value = sectorController.Value;
				if (!Object.op_Implicit((Object)(object)value))
				{
					_deadSectorBuffer.Add(key);
					continue;
				}
				SectorCacheState orCreateCacheState = GetOrCreateCacheState(key);
				bool flag = Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.m_zones.ContainsKey(key);
				bool flag2 = unscaledTime - orCreateCacheState.LastTouchTime <= 3f;
				if (flag || flag2)
				{
					if (!orCreateCacheState.IsActive || value.IsWarmCached)
					{
						ActivateSector(key, value, flag);
					}
					orCreateCacheState.LastActiveTime = unscaledTime;
					value.Tick();
				}
				else if (orCreateCacheState.IsActive)
				{
					orCreateCacheState.IsActive = false;
					orCreateCacheState.WarmSince = unscaledTime;
					value.EnterWarmCache();
					if (ValheimScalabilityConfig.IsCacheDiagnosticsEnabled)
					{
						Debug.Log((object)$"[ValheimScalability] Sector entered warm cache sector={key.x},{key.y} visits={orCreateCacheState.VisitCount} retained={FormatMegabytes(value.EstimatedGeneratedMemoryBytes)} MB");
					}
				}
			}
			RemoveDeadControllerEntries();
			EnforceWarmCacheLimits(unscaledTime);
			PruneColdHistory();
		}

		private void EnforceWarmCacheLimits(float now)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			_warmCandidateBuffer.Clear();
			long totalWarmBytes = 0L;
			int totalWarmZones = 0;
			int frequentWarmZones = 0;
			foreach (KeyValuePair<Vector2s, SectorMeshClusterController> sectorController in _sectorControllers)
			{
				Vector2s key = sectorController.Key;
				SectorMeshClusterController value = sectorController.Value;
				if (Object.op_Implicit((Object)(object)value) && _sectorCacheStates.TryGetValue(key, out SectorCacheState value2) && !value2.IsActive)
				{
					long estimatedGeneratedMemoryBytes = value.EstimatedGeneratedMemoryBytes;
					bool flag = value2.VisitCount >= ValheimScalabilityConfig.FrequentZoneVisitThreshold;
					WarmCacheCandidate item = new WarmCacheCandidate(key, value, value2, estimatedGeneratedMemoryBytes, flag);
					_warmCandidateBuffer.Add(item);
					totalWarmBytes += estimatedGeneratedMemoryBytes;
					totalWarmZones++;
					if (flag)
					{
						frequentWarmZones++;
					}
				}
			}
			if (_warmCandidateBuffer.Count == 0)
			{
				return;
			}
			if (!ValheimScalabilityConfig.IsWarmCacheEnabled)
			{
				foreach (WarmCacheCandidate item2 in _warmCandidateBuffer)
				{
					EvictSector(item2.Sector, "warm cache disabled");
				}
				return;
			}
			long singleWarmZoneMemoryLimitBytes = ValheimScalabilityConfig.SingleWarmZoneMemoryLimitBytes;
			foreach (WarmCacheCandidate item3 in _warmCandidateBuffer)
			{
				if (!item3.Evicted)
				{
					float num = (item3.IsFrequent ? ValheimScalabilityConfig.FrequentWarmRetentionSeconds : ValheimScalabilityConfig.WarmRetentionSeconds);
					float num2 = Mathf.Max(0f, now - item3.State.WarmSince);
					if (num >= 0f && num2 > num)
					{
						MarkEvicted(item3, ref totalWarmZones, ref frequentWarmZones, ref totalWarmBytes);
						EvictSector(item3.Sector, item3.IsFrequent ? "frequent-zone TTL expired" : "warm-zone TTL expired");
					}
					else if (singleWarmZoneMemoryLimitBytes > 0 && item3.Bytes > singleWarmZoneMemoryLimitBytes)
					{
						MarkEvicted(item3, ref totalWarmZones, ref frequentWarmZones, ref totalWarmBytes);
						EvictSector(item3.Sector, "single-zone warm memory limit exceeded");
					}
				}
			}
			int frequentWarmZoneLimit = ValheimScalabilityConfig.FrequentWarmZoneLimit;
			if (frequentWarmZoneLimit >= 0 && frequentWarmZones > frequentWarmZoneLimit)
			{
				_warmCandidateBuffer.Sort(WarmCacheCandidate.CompareFrequentEvictionOrder);
				foreach (WarmCacheCandidate item4 in _warmCandidateBuffer)
				{
					if (frequentWarmZones <= frequentWarmZoneLimit)
					{
						break;
					}
					if (!item4.Evicted && item4.IsFrequent)
					{
						MarkEvicted(item4, ref totalWarmZones, ref frequentWarmZones, ref totalWarmBytes);
						EvictSector(item4.Sector, "frequent warm-zone limit exceeded");
					}
				}
			}
			int warmZoneLimit = ValheimScalabilityConfig.WarmZoneLimit;
			long warmMeshMemoryLimitBytes = ValheimScalabilityConfig.WarmMeshMemoryLimitBytes;
			bool num3 = warmZoneLimit > 0 && totalWarmZones > warmZoneLimit;
			bool flag2 = warmMeshMemoryLimitBytes > 0 && totalWarmBytes > warmMeshMemoryLimitBytes;
			if (!num3 && !flag2)
			{
				return;
			}
			_warmCandidateBuffer.Sort(WarmCacheCandidate.CompareGlobalEvictionOrder);
			foreach (WarmCacheCandidate item5 in _warmCandidateBuffer)
			{
				bool num4 = warmZoneLimit > 0 && totalWarmZones > warmZoneLimit;
				flag2 = warmMeshMemoryLimitBytes > 0 && totalWarmBytes > warmMeshMemoryLimitBytes;
				if (!num4 && !flag2)
				{
					break;
				}
				if (!item5.Evicted)
				{
					MarkEvicted(item5, ref totalWarmZones, ref frequentWarmZones, ref totalWarmBytes);
					EvictSector(item5.Sector, flag2 ? "warm mesh-memory budget exceeded" : "warm-zone count limit exceeded");
				}
			}
		}

		private static void MarkEvicted(WarmCacheCandidate candidate, ref int totalWarmZones, ref int frequentWarmZones, ref long totalWarmBytes)
		{
			if (!candidate.Evicted)
			{
				candidate.Evicted = true;
				totalWarmZones = Mathf.Max(0, totalWarmZones - 1);
				if (candidate.IsFrequent)
				{
					frequentWarmZones = Mathf.Max(0, frequentWarmZones - 1);
				}
				totalWarmBytes = Math.Max(0L, totalWarmBytes - candidate.Bytes);
			}
		}

		private void EvictSector(Vector2s sector, string reason)
		{
			//IL_0006: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if (_sectorControllers.TryGetValue(sector, out SectorMeshClusterController value))
			{
				long bytes = (Object.op_Implicit((Object)(object)value) ? value.EstimatedGeneratedMemoryBytes : 0);
				if (ValheimScalabilityConfig.IsCacheDiagnosticsEnabled)
				{
					Debug.Log((object)$"[ValheimScalability] Cold-evict sector={sector.x},{sector.y} reason='{reason}' releasing≈{FormatMegabytes(bytes)} MB");
				}
				if (Object.op_Implicit((Object)(object)value))
				{
					Object.Destroy((Object)(object)((Component)value).gameObject);
				}
				_sectorControllers.Remove(sector);
				if (_sectorCacheStates.TryGetValue(sector, out SectorCacheState value2))
				{
					va