Decompiled source of ValheimPerformanceOverhaul v3.0.0

BepInEx/plugins/ValheimPerformanceOverhaul.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.PostProcessing;
using UnityEngine.UI;
using ValheimPerformanceOverhaul.AI;
using ValheimPerformanceOverhaul.Audio;
using ValheimPerformanceOverhaul.Core;
using ValheimPerformanceOverhaul.Network;
using ValheimPerformanceOverhaul.ObjectPooling;
using ValheimPerformanceOverhaul.Pieces;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ValheimPerformanceOverhaul")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ValheimPerformanceOverhaul")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e1d59e72-fa59-450d-94cd-86cc02deca70")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ValheimPerformanceOverhaul
{
	[HarmonyPatch(typeof(Resources), "UnloadUnusedAssets")]
	public static class GCPatches
	{
		private delegate bool InAttackDelegate(Player player);

		private static FieldRef<Character, Vector3> _getMoveDirFast;

		private static InAttackDelegate _inAttackFast;

		private static bool _delegatesInitialized;

		private const float MAX_LOW_LATENCY_SECONDS = 45f;

		private static float _lowLatencyStartTime;

		private static bool _isInLowLatency;

		static GCPatches()
		{
			_lowLatencyStartTime = -1f;
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(Character), "m_moveDir");
				MethodInfo methodInfo = AccessTools.Method(typeof(Player), "InAttack", (Type[])null, (Type[])null);
				if (fieldInfo != null && methodInfo != null)
				{
					_getMoveDirFast = AccessTools.FieldRefAccess<Character, Vector3>(fieldInfo);
					_inAttackFast = (InAttackDelegate)Delegate.CreateDelegate(typeof(InAttackDelegate), methodInfo);
					_delegatesInitialized = true;
					Plugin.Log.LogInfo((object)"[GC] Fast delegates initialized.");
				}
				else
				{
					Plugin.Log.LogWarning((object)"[GC] Private fields not found — GC optimization disabled.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[GC] Failed to initialize delegates: " + ex.Message));
				_delegatesInitialized = false;
			}
		}

		[HarmonyPriority(600)]
		[HarmonyPrefix]
		private static bool PreventUnloadWhenBusy()
		{
			if (!Plugin.GcControlEnabled.Value || !_delegatesInitialized)
			{
				return true;
			}
			return !IsPlayerBusy();
		}

		public static void TickGCMode()
		{
			if (!Plugin.GcControlEnabled.Value || !_delegatesInitialized)
			{
				return;
			}
			bool flag = IsPlayerBusy();
			if (flag && !_isInLowLatency)
			{
				GCSettings.LatencyMode = GCLatencyMode.LowLatency;
				_isInLowLatency = true;
				_lowLatencyStartTime = Time.unscaledTime;
			}
			else if (!flag && _isInLowLatency)
			{
				ExitLowLatency();
			}
			else if (_isInLowLatency && Time.unscaledTime - _lowLatencyStartTime > 45f)
			{
				if (Plugin.DebugLoggingEnabled.Value)
				{
					Plugin.Log.LogInfo((object)"[GC] Safety timeout — forcing collect and resetting mode.");
				}
				ExitLowLatency();
				GC.Collect(0, GCCollectionMode.Optimized);
				if (IsPlayerBusy())
				{
					GCSettings.LatencyMode = GCLatencyMode.LowLatency;
					_isInLowLatency = true;
					_lowLatencyStartTime = Time.unscaledTime;
				}
			}
		}

		private static void ExitLowLatency()
		{
			GCSettings.LatencyMode = GCLatencyMode.Interactive;
			_isInLowLatency = false;
			_lowLatencyStartTime = -1f;
		}

		public static bool IsPlayerBusyProxy()
		{
			if (_delegatesInitialized)
			{
				return IsPlayerBusy();
			}
			return false;
		}

		private static bool IsPlayerBusy()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
			{
				return false;
			}
			try
			{
				if (!((Character)localPlayer).IsOnGround() || ((Character)localPlayer).IsSwimming() || ((Character)localPlayer).IsTeleporting())
				{
					return true;
				}
				if (((Vector3)(ref _getMoveDirFast.Invoke((Character)(object)localPlayer))).sqrMagnitude > 0.01f)
				{
					return true;
				}
				if (_inAttackFast(localPlayer))
				{
					return true;
				}
			}
			catch (Exception ex)
			{
				if (Plugin.DebugLoggingEnabled.Value)
				{
					Plugin.Log.LogWarning((object)("[GC] Error checking player state: " + ex.Message));
				}
				return false;
			}
			return false;
		}
	}
	[HarmonyPatch]
	public static class JitPatches
	{
		private static bool _warmedUp;

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		[HarmonyPostfix]
		private static void WarmupGameMethods(Player __instance)
		{
			if (_warmedUp || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Plugin.JitWarmupEnabled.Value)
			{
				return;
			}
			_warmedUp = true;
			try
			{
				PrepareMethod(typeof(Character), "Damage", "Character.Damage");
				PrepareMethod(typeof(Player), "StartAttack", "Player.StartAttack");
				PrepareMethod(typeof(Attack), "DoMeleeAttack", "Attack.DoMeleeAttack");
				PrepareMethod(typeof(Player), "GetHoverObject", "Player.GetHoverObject");
				PrepareMethod(typeof(Player), "GetHoverCreature", "Player.GetHoverCreature");
				PrepareMethod(typeof(Player), "GetHoveringPiece", "Player.GetHoveringPiece");
				PrepareMethod(typeof(Player), "UpdatePlacement", "Player.UpdatePlacement");
				PrepareMethod(typeof(InventoryGui), "Show", "InventoryGui.Show");
				PrepareMethod(typeof(Minimap), "SetMapMode", "Minimap.SetMapMode");
				PrepareMethod(typeof(EnvMan), "GetCurrentBiome", "EnvMan.GetCurrentBiome");
				Plugin.Log.LogInfo((object)"[JIT] Warm-up complete.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[JIT] Warm-up error: " + ex.Message));
			}
		}

		private static void PrepareMethod(Type type, string methodName, string logLabel)
		{
			if (type == null || string.IsNullOrEmpty(methodName))
			{
				return;
			}
			try
			{
				MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					if (Plugin.DebugLoggingEnabled.Value)
					{
						Plugin.Log.LogWarning((object)("[JIT] Method not found: " + logLabel));
					}
					return;
				}
				RuntimeHelpers.PrepareMethod(methodInfo.MethodHandle);
				if (Plugin.DebugLoggingEnabled.Value)
				{
					Plugin.Log.LogInfo((object)("[JIT] Warmed: " + logLabel));
				}
			}
			catch (Exception ex)
			{
				if (Plugin.DebugLoggingEnabled.Value)
				{
					Plugin.Log.LogWarning((object)("[JIT] Could not prepare " + logLabel + ": " + ex.Message));
				}
			}
		}
	}
	[BepInPlugin("com.Skarif.ValheimPerformanceOverhaul", "Valheim Performance Overhaul", "2.7.0")]
	public class Plugin : BaseUnityPlugin
	{
		private const string PluginGUID = "com.Skarif.ValheimPerformanceOverhaul";

		private const string PluginName = "Valheim Performance Overhaul";

		public const string PluginVersion = "2.7.0";

		private readonly Harmony _harmony = new Harmony("com.Skarif.ValheimPerformanceOverhaul");

		public static ManualLogSource Log;

		public static Plugin Instance;

		public static ConfigEntry<bool> DebugLoggingEnabled;

		public static ConfigEntry<bool> GcControlEnabled;

		public static ConfigEntry<bool> DistanceCullerEnabled;

		public static ConfigEntry<float> CreatureCullDistance;

		public static ConfigEntry<float> PieceCullDistance;

		public static ConfigEntry<bool> AiThrottlingEnabled;

		public static ConfigEntry<string> CullerExclusions;

		public static ConfigEntry<bool> ObjectPoolingEnabled;

		public static ConfigEntry<bool> JitWarmupEnabled;

		public static ConfigEntry<bool> LightCullingEnabled;

		public static ConfigEntry<int> MaxActiveLights;

		public static ConfigEntry<float> LightCullDistance;

		public static ConfigEntry<int> MaxShadowCasters;

		public static ConfigEntry<float> ShadowCullDistance;

		public static ConfigEntry<bool> LightLODEnabled;

		public static ConfigEntry<float> LightLODFullDistance;

		public static ConfigEntry<float> LightLODNoShadowDistance;

		public static ConfigEntry<float> LightLODEmissiveDistance;

		public static ConfigEntry<float> LightLODBillboardDistance;

		public static ConfigEntry<bool> AudioPoolingEnabled;

		public static ConfigEntry<int> AudioPoolSize;

		public static ConfigEntry<bool> GraphicsSettingsEnabled;

		public static ConfigEntry<float> ConfigShadowDistance;

		public static ConfigEntry<int> ConfigShadowResolution;

		public static ConfigEntry<int> ConfigShadowCascades;

		public static ConfigEntry<float> ConfigTerrainQuality;

		public static ConfigEntry<bool> ConfigReflections;

		public static ConfigEntry<bool> ConfigBloom;

		public static ConfigEntry<float> PathCacheDistance;

		public static ConfigEntry<bool> PieceOptimizationEnabled;

		public static ConfigEntry<float> PieceSupportCacheDuration;

		public static ConfigEntry<bool> ParticleOptimizationEnabled;

		public static ConfigEntry<float> ParticleCullDistance;

		public static ConfigEntry<int> MaxActiveParticles;

		public static ConfigEntry<float> TorchParticleLifetime;

		public static ConfigEntry<bool> VegetationOptimizationEnabled;

		public static ConfigEntry<float> GrassRenderDistance;

		public static ConfigEntry<float> GrassDensityMultiplier;

		public static ConfigEntry<float> DetailObjectDistance;

		public static ConfigEntry<float> DetailDensity;

		public static ConfigEntry<int> TerrainMaxLOD;

		public static ConfigEntry<bool> AnimatorOptimizationEnabled;

		public static ConfigEntry<bool> MinimapOptimizationEnabled;

		public static ConfigEntry<bool> TamedIdleOptimizationEnabled;

		public static ConfigEntry<float> TamedIdleDistanceFromCombat;

		public static ConfigEntry<float> TamedIdleBaseDetectionRadius;

		public static ConfigEntry<bool> LightFlickerOptimizationEnabled;

		public static ConfigEntry<bool> SmokeOptimizationEnabled;

		public static ConfigEntry<float> SmokeLiftForce;

		public static ConfigEntry<bool> EngineQualitySettingsEnabled;

		public static ConfigEntry<int> ParticleRaycastBudget;

		public static ConfigEntry<bool> SkipIntroEnabled;

		public static ConfigEntry<bool> FrameBudgetGuardEnabled;

		public static ConfigEntry<float> FrameBudgetThresholdMs;

		public static ConfigEntry<float> FrameBudgetThrottledDelta;

		public static ConfigEntry<float> FrameBudgetNormalDelta;

		public static ConfigEntry<int> ConfigSkinWeights;

		public static ConfigEntry<bool> PieceSupportSmartInvalidation;

		public static ConfigEntry<bool> SmartZoneOwnershipEnabled;

		public static ConfigEntry<int> ZonePingThreshold;

		public static ConfigEntry<int> ZonePingHysteresis;

		public static ConfigEntry<float> ZoneUpdateInterval;

		private float _poolMaintenanceTimer;

		private const float POOL_MAINTENANCE_INTERVAL = 30f;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			HardwareProfiler.Initialize();
			SetupConfig();
			Log.LogInfo((object)"Initializing Valheim Performance Overhaul v2.7.0...");
			if (GraphicsSettingsEnabled.Value)
			{
				ApplyImmediateGraphicsSettings();
			}
			Log.LogInfo((object)"Applying Harmony patches...");
			try
			{
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				Log.LogInfo((object)"All patches applied successfully.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Error applying patches: " + ex.Message + "\n" + ex.StackTrace));
			}
		}

		private void Start()
		{
			//IL_0071: 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_0082: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			if (AiThrottlingEnabled.Value)
			{
				AIOptimizerManager.Initialize();
				Log.LogInfo((object)"[AI] Optimizer manager initialized.");
			}
			if (ObjectPoolingEnabled.Value)
			{
				ObjectPoolManager.Initialize();
				Log.LogInfo((object)"[ObjectPooling] System initialized.");
			}
			if (AudioPoolingEnabled.Value)
			{
				AudioPoolManager.Initialize();
				Log.LogInfo((object)"[AudioPooling] System initialized.");
			}
			if (DistanceCullerEnabled.Value)
			{
				GameObject val = new GameObject("_VPO_DistanceCullerManager");
				val.AddComponent<DistanceCullerManager>();
				Object.DontDestroyOnLoad((Object)val);
				Log.LogInfo((object)"[DistanceCuller] Manager initialized.");
			}
			if (FrameBudgetGuardEnabled.Value)
			{
				GameObject val2 = new GameObject("_VPO_FrameBudgetGuard");
				val2.AddComponent<FrameBudgetGuard>();
				Object.DontDestroyOnLoad((Object)val2);
				Log.LogInfo((object)"[FrameBudgetGuard] Initialized.");
			}
		}

		private void SetupConfig()
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Expected O, but got Unknown
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Expected O, but got Unknown
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Expected O, but got Unknown
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Expected O, but got Unknown
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Expected O, but got Unknown
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Expected O, but got Unknown
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Expected O, but got Unknown
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Expected O, but got Unknown
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Expected O, but got Unknown
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_0420: Expected O, but got Unknown
			//IL_045a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Expected O, but got Unknown
			//IL_048b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0495: Expected O, but got Unknown
			//IL_04c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d2: Expected O, but got Unknown
			//IL_0548: Unknown result type (might be due to invalid IL or missing references)
			//IL_0552: Expected O, but got Unknown
			//IL_0585: Unknown result type (might be due to invalid IL or missing references)
			//IL_058f: Expected O, but got Unknown
			//IL_05e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ec: Expected O, but got Unknown
			//IL_067f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0689: Expected O, but got Unknown
			//IL_06b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06bd: Expected O, but got Unknown
			//IL_06f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fa: Expected O, but got Unknown
			//IL_074d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0757: Expected O, but got Unknown
			//IL_078a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0794: Expected O, but got Unknown
			//IL_07c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d1: Expected O, but got Unknown
			//IL_0804: Unknown result type (might be due to invalid IL or missing references)
			//IL_080e: Expected O, but got Unknown
			//IL_0835: Unknown result type (might be due to invalid IL or missing references)
			//IL_083f: Expected O, but got Unknown
			//IL_08cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_08d6: Expected O, but got Unknown
			//IL_0900: Unknown result type (might be due to invalid IL or missing references)
			//IL_090a: Expected O, but got Unknown
			//IL_093d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0947: Expected O, but got Unknown
			//IL_09a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_09af: Expected O, but got Unknown
			//IL_09e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_09ec: Expected O, but got Unknown
			//IL_0a5f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a69: Expected O, but got Unknown
			//IL_0ab9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ac3: Expected O, but got Unknown
			//IL_0b36: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b40: Expected O, but got Unknown
			//IL_0b73: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b7d: Expected O, but got Unknown
			//IL_0bb0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bba: Expected O, but got Unknown
			DebugLoggingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "Enable Debug Logging", false, "Enables detailed diagnostic logs.");
			GcControlEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("2. GC Control", "Enabled", true, "Prevents garbage collection during combat or movement.");
			DistanceCullerEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Distance Culler", "Enabled", true, "Disables logic for distant objects.");
			CreatureCullDistance = ((BaseUnityPlugin)this).Config.Bind<float>("3. Distance Culler", "Creature Cull Distance", 80f, new ConfigDescription("Distance at which creatures sleep.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(40f, 200f), Array.Empty<object>()));
			PieceCullDistance = ((BaseUnityPlugin)this).Config.Bind<float>("3. Distance Culler", "Piece Cull Distance", 100f, new ConfigDescription("Distance at which build pieces sleep.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(50f, 300f), Array.Empty<object>()));
			AiThrottlingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Distance Culler", "Enable AI Throttling", true, "Reduces how often distant AI updates.");
			CullerExclusions = ((BaseUnityPlugin)this).Config.Bind<string>("3. Distance Culler", "Exclusions", "TombStone,portal_wood", "Comma-separated list of prefab names to never cull. Objects with ZSyncTransform+Rigidbody (doors, torches) are automatically excluded in code and do not need to be listed here.");
			ObjectPoolingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Object Pooling", "Enabled", true, "Reuses ItemDrop objects.");
			JitWarmupEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("5. JIT Warm-up", "Enabled", true, "Pre-compiles critical methods at game start.");
			LightCullingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Light Culling", "Enabled", true, "Disables distant light sources.");
			MaxActiveLights = ((BaseUnityPlugin)this).Config.Bind<int>("6. Light Culling", "Max Active Lights", 15, new ConfigDescription("Max active lights.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 50), Array.Empty<object>()));
			LightCullDistance = ((BaseUnityPlugin)this).Config.Bind<float>("6. Light Culling", "Light Cull Distance", 60f, new ConfigDescription("Max distance for active lights.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 150f), Array.Empty<object>()));
			MaxShadowCasters = ((BaseUnityPlugin)this).Config.Bind<int>("6. Light Culling", "Max Shadow Casters", 5, new ConfigDescription("Max shadow casters.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 15), Array.Empty<object>()));
			ShadowCullDistance = ((BaseUnityPlugin)this).Config.Bind<float>("6. Light Culling", "Shadow Cull Distance", 30f, new ConfigDescription("Distance for shadows.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 80f), Array.Empty<object>()));
			LightLODEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Light Culling", "Enable Light LOD System", true, "Enables Level of Detail system for lights.");
			LightLODFullDistance = ((BaseUnityPlugin)this).Config.Bind<float>("6. Light Culling", "LOD Full Light Distance", 20f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 50f), Array.Empty<object>()));
			LightLODNoShadowDistance = ((BaseUnityPlugin)this).Config.Bind<float>("6. Light Culling", "LOD No Shadow Distance", 40f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 80f), Array.Empty<object>()));
			LightLODEmissiveDistance = ((BaseUnityPlugin)this).Config.Bind<float>("6. Light Culling", "LOD Emissive Distance", 70f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(40f, 120f), Array.Empty<object>()));
			LightLODBillboardDistance = ((BaseUnityPlugin)this).Config.Bind<float>("6. Light Culling", "LOD Billboard Distance", 100f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(60f, 200f), Array.Empty<object>()));
			AudioPoolingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("7. Audio Optimization", "Enabled", true, "Reuses sound effect objects.");
			AudioPoolSize = ((BaseUnityPlugin)this).Config.Bind<int>("7. Audio Optimization", "Total Pool Size", 32, new ConfigDescription("Total pooled sources.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(16, 128), Array.Empty<object>()));
			GraphicsSettingsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("8. Graphics Settings", "Enabled", true, "Enables advanced graphics settings.");
			ConfigShadowDistance = ((BaseUnityPlugin)this).Config.Bind<float>("8. Graphics Settings", "Shadow Distance", 50f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 150f), Array.Empty<object>()));
			ConfigShadowResolution = ((BaseUnityPlugin)this).Config.Bind<int>("8. Graphics Settings", "Shadow Resolution", 512, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[4] { 512, 1024, 2048, 4096 }), Array.Empty<object>()));
			ConfigShadowCascades = ((BaseUnityPlugin)this).Config.Bind<int>("8. Graphics Settings", "Shadow Cascades", 1, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 4), Array.Empty<object>()));
			ConfigTerrainQuality = ((BaseUnityPlugin)this).Config.Bind<float>("8. Graphics Settings", "Terrain Quality Multiplier", 0.7f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>()));
			ConfigReflections = ((BaseUnityPlugin)this).Config.Bind<bool>("8. Graphics Settings", "Enable Reflections", false, "Enables screen-space reflections.");
			ConfigBloom = ((BaseUnityPlugin)this).Config.Bind<bool>("8. Graphics Settings", "Enable Bloom", false, "Enables bloom glow effect.");
			ConfigSkinWeights = ((BaseUnityPlugin)this).Config.Bind<int>("8. Graphics Settings", "Skin Weights (Bones)", 2, new ConfigDescription("Number of bones per vertex for animations. 4 = Vanilla, 2 = Optimal (Recommended), 1 = Max FPS.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[3] { 1, 2, 4 }), Array.Empty<object>()));
			PathCacheDistance = ((BaseUnityPlugin)this).Config.Bind<float>("9. AI Optimization", "Path Cache Distance", 2f, new ConfigDescription("AI path caching distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 8f), Array.Empty<object>()));
			PieceOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("10. Piece Optimization", "Enabled", true, "Optimizes building pieces.");
			PieceSupportCacheDuration = ((BaseUnityPlugin)this).Config.Bind<float>("10. Piece Optimization", "Support Cache Duration (seconds)", 5f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			PieceSupportSmartInvalidation = ((BaseUnityPlugin)this).Config.Bind<bool>("10. Piece Optimization", "Smart Cache Invalidation", false, "Instantly recalculates the stability of adjacent buildings when a chunk is destroyed.");
			RainDamagePatch.DisableRainDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("10. Piece Optimization", "Disable Rain Damage", false, "Completely disables wear and tear of wooden buildings from rain and rotting in water.");
			ParticleOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("11. Particle Optimization", "Enabled", true, "Optimizes particle systems.");
			ParticleCullDistance = ((BaseUnityPlugin)this).Config.Bind<float>("11. Particle Optimization", "Particle Cull Distance", 50f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 100f), Array.Empty<object>()));
			MaxActiveParticles = ((BaseUnityPlugin)this).Config.Bind<int>("11. Particle Optimization", "Max Active Particle Systems", 30, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 100), Array.Empty<object>()));
			TorchParticleLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("11. Particle Optimization", "Torch Particle Lifetime", 0.8f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 2f), Array.Empty<object>()));
			VegetationOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("12. Vegetation Optimization", "Enabled", true, "Optimizes grass and details.");
			GrassRenderDistance = ((BaseUnityPlugin)this).Config.Bind<float>("12. Vegetation Optimization", "Grass Render Distance", 60f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 120f), Array.Empty<object>()));
			GrassDensityMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("12. Vegetation Optimization", "Grass Density Multiplier", 0.7f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 1f), Array.Empty<object>()));
			DetailObjectDistance = ((BaseUnityPlugin)this).Config.Bind<float>("12. Vegetation Optimization", "Detail Object Distance", 80f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(40f, 150f), Array.Empty<object>()));
			DetailDensity = ((BaseUnityPlugin)this).Config.Bind<float>("12. Vegetation Optimization", "Detail Density", 0.7f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 1f), Array.Empty<object>()));
			TerrainMaxLOD = ((BaseUnityPlugin)this).Config.Bind<int>("12. Vegetation Optimization", "Terrain Max LOD", 1, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 2), Array.Empty<object>()));
			AnimatorOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("13. Animator Optimization", "Enabled", true, "Optimizes character animations.");
			MinimapOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("14. Minimap Optimization", "Enabled", true, "Reduces minimap texture updates.");
			SmartZoneOwnershipEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("14. Network Optimization", "Smart Zone Ownership", true, "[Только Сервер] Автоматически передает управление ИИ мобов игроку с наименьшим пингом в зоне.");
			ZonePingThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("14. Network Optimization", "Zone Ping Threshold (ms)", 120, new ConfigDescription("Ping, at which the server will start looking for a new owner for the zone.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 500), Array.Empty<object>()));
			ZonePingHysteresis = ((BaseUnityPlugin)this).Config.Bind<int>("14. Network Optimization", "Zone Ping Hysteresis (ms)", 30, new ConfigDescription("The difference in ping required to transfer possession.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 100), Array.Empty<object>()));
			ZoneUpdateInterval = ((BaseUnityPlugin)this).Config.Bind<float>("14. Network Optimization", "Zone Update Interval (sec)", 5f, new ConfigDescription("How often does the server check pings in zones?", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 20f), Array.Empty<object>()));
			NetworkManager.SetupConfigs(((BaseUnityPlugin)this).Config);
			TamedIdleOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("16. Tamed Mob Idle Optimization", "Enabled", true, "Idle mode for tamed mobs.");
			TamedIdleDistanceFromCombat = ((BaseUnityPlugin)this).Config.Bind<float>("16. Tamed Mob Idle Optimization", "Idle Distance From Combat", 5f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 30f), Array.Empty<object>()));
			TamedIdleBaseDetectionRadius = ((BaseUnityPlugin)this).Config.Bind<float>("16. Tamed Mob Idle Optimization", "Base Detection Radius", 30f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 60f), Array.Empty<object>()));
			LightFlickerOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("17. Light Flicker Optimization", "Enabled", true, "Fixes light intensity to base value.");
			SmokeOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("18. Smoke Physics Optimization", "Enabled", true, "Simplified smoke aerodynamics.");
			SmokeLiftForce = ((BaseUnityPlugin)this).Config.Bind<float>("18. Smoke Physics Optimization", "Smoke Lift Force", 3.5f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			EngineQualitySettingsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("19. Engine Quality Settings", "Enabled", true, "Low-level Unity tweaks.");
			ParticleRaycastBudget = ((BaseUnityPlugin)this).Config.Bind<int>("19. Engine Quality Settings", "Particle Raycast Budget", 1024, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<int>(64, 4096), Array.Empty<object>()));
			SkipIntroEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("20. Skip Intro", "Enabled", true, "Skips logos.");
			FrameBudgetGuardEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("21. Frame Budget Guard", "Enabled", true, "Limits maximumDeltaTime on frame spikes.");
			FrameBudgetThresholdMs = ((BaseUnityPlugin)this).Config.Bind<float>("21. Frame Budget Guard", "Freeze Threshold (ms)", 28f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(16f, 100f), Array.Empty<object>()));
			FrameBudgetThrottledDelta = ((BaseUnityPlugin)this).Config.Bind<float>("21. Frame Budget Guard", "Throttled MaxDeltaTime", 0.045f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 0.1f), Array.Empty<object>()));
			FrameBudgetNormalDelta = ((BaseUnityPlugin)this).Config.Bind<float>("21. Frame Budget Guard", "Normal MaxDeltaTime", 0.07f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.03f, 0.2f), Array.Empty<object>()));
		}

		private void ApplyImmediateGraphicsSettings()
		{
			try
			{
				QualitySettings.shadowDistance = ConfigShadowDistance.Value;
				switch (ConfigShadowResolution.Value)
				{
				case 512:
					QualitySettings.shadowResolution = (ShadowResolution)0;
					break;
				case 1024:
					QualitySettings.shadowResolution = (ShadowResolution)1;
					break;
				case 2048:
					QualitySettings.shadowResolution = (ShadowResolution)2;
					break;
				case 4096:
					QualitySettings.shadowResolution = (ShadowResolution)3;
					break;
				default:
					QualitySettings.shadowResolution = (ShadowResolution)0;
					break;
				}
				QualitySettings.shadowCascades = ConfigShadowCascades.Value;
				Log.LogInfo((object)"[Graphics] Applied immediate graphics settings.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[Graphics] Failed to apply settings: " + ex.Message));
			}
		}

		private void OnDestroy()
		{
			Log.LogInfo((object)"Unpatching all Valheim Performance Overhaul methods.");
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
			if (GcControlEnabled != null && GcControlEnabled.Value)
			{
				GCPatches.TickGCMode();
			}
			if (ObjectPoolingEnabled == null || !ObjectPoolingEnabled.Value)
			{
				return;
			}
			_poolMaintenanceTimer += Time.deltaTime;
			if (_poolMaintenanceTimer >= 30f)
			{
				_poolMaintenanceTimer = 0f;
				ObjectPoolManager.PerformMaintenance();
				if (DebugLoggingEnabled.Value)
				{
					ObjectPoolManager.LogPoolStats();
				}
			}
		}
	}
	public class DistanceCuller : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <RegisterNextFrame>d__10 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public DistanceCuller <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				int num = <>1__state;
				DistanceCuller distanceCuller = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if ((Object)(object)distanceCuller == (Object)null || (Object)(object)distanceCuller._zNetView == (Object)null || !distanceCuller._zNetView.IsValid())
					{
						return false;
					}
					DistanceCullerManager.Instance?.RegisterCuller(distanceCuller);
					return false;
				}
			}

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

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

		private readonly List<MonoBehaviour> _culledComponents = new List<MonoBehaviour>();

		private ZNetView _zNetView;

		private bool _isCulled;

		private bool _isCharacter;

		private Transform _transform;

		public float CullDistance = 80f;

		private float _cullDistanceSqr;

		private float _wakeUpDistanceSqr;

		private const float HYSTERESIS = 15f;

		private void Awake()
		{
			_transform = ((Component)this).transform;
			_zNetView = ((Component)this).GetComponent<ZNetView>();
			if ((Object)(object)_zNetView == (Object)null || !_zNetView.IsValid())
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			_isCharacter = (Object)(object)((Component)this).GetComponent<Character>() != (Object)null;
			try
			{
				_cullDistanceSqr = (CullDistance + 15f) * (CullDistance + 15f);
				_wakeUpDistanceSqr = (CullDistance - 15f) * (CullDistance - 15f);
				if (!_isCharacter)
				{
					CollectComponents();
				}
				((MonoBehaviour)this).StartCoroutine(RegisterNextFrame());
			}
			catch (Exception ex)
			{
				if (Plugin.DebugLoggingEnabled.Value)
				{
					Plugin.Log.LogError((object)("[DistanceCuller] Error in Awake: " + ex.Message));
				}
				Object.Destroy((Object)(object)this);
			}
		}

		[IteratorStateMachine(typeof(<RegisterNextFrame>d__10))]
		private IEnumerator RegisterNextFrame()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RegisterNextFrame>d__10(0)
			{
				<>4__this = this
			};
		}

		private void CollectComponents()
		{
			MonoBehaviour[] componentsInChildren = ((Component)this).GetComponentsInChildren<MonoBehaviour>(true);
			if (componentsInChildren == null)
			{
				return;
			}
			MonoBehaviour[] array = componentsInChildren;
			foreach (MonoBehaviour val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)this) && !(val is ZNetView) && !(val is ZSyncTransform) && !(val is DistanceCuller) && !(val is Character) && !(val is Humanoid) && (!Plugin.AiThrottlingEnabled.Value || !(val is BaseAI)))
				{
					_culledComponents.Add(val);
				}
			}
			if (Plugin.DebugLoggingEnabled.Value && _culledComponents.Count > 0)
			{
				Plugin.Log.LogInfo((object)$"[DistanceCuller] Collected {_culledComponents.Count} components on {((Object)((Component)this).gameObject).name}");
			}
		}

		public void ManagerUpdate(IReadOnlyList<Player> players)
		{
			if (players == null || players.Count == 0)
			{
				if (_isCulled)
				{
					SetComponentsEnabled(enabled: true);
				}
			}
			else
			{
				float minPlayerDistanceSqr = GetMinPlayerDistanceSqr(players);
				bool shouldCull = DetermineCullingState(minPlayerDistanceSqr);
				ApplyOwnershipLogic(shouldCull);
			}
		}

		private float GetMinPlayerDistanceSqr(IReadOnlyList<Player> players)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			float num = float.MaxValue;
			Vector3 position = _transform.position;
			for (int i = 0; i < players.Count; i++)
			{
				Player val = players[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).transform == (Object)null))
				{
					Vector3 val2 = ((Component)val).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
					}
				}
			}
			return num;
		}

		private bool DetermineCullingState(float distSqr)
		{
			if (!_isCulled)
			{
				return distSqr > _cullDistanceSqr;
			}
			return distSqr > _wakeUpDistanceSqr;
		}

		private void ApplyOwnershipLogic(bool shouldCull)
		{
			if ((Object)(object)_zNetView == (Object)null)
			{
				return;
			}
			if (_zNetView.IsOwner())
			{
				if (_isCulled != shouldCull)
				{
					SetComponentsEnabled(!shouldCull);
				}
			}
			else if (_isCulled)
			{
				SetComponentsEnabled(enabled: true);
			}
		}

		private void SetComponentsEnabled(bool enabled)
		{
			if (_isCulled == !enabled)
			{
				return;
			}
			_isCulled = !enabled;
			if (!_isCharacter)
			{
				if (enabled)
				{
					EnableComponents();
				}
				else
				{
					DisableComponents();
				}
			}
		}

		private void EnableComponents()
		{
			for (int num = _culledComponents.Count - 1; num >= 0; num--)
			{
				MonoBehaviour val = _culledComponents[num];
				if ((Object)(object)val == (Object)null)
				{
					_culledComponents.RemoveAt(num);
				}
				else if (!((Behaviour)val).enabled)
				{
					try
					{
						((Behaviour)val).enabled = true;
					}
					catch (Exception ex)
					{
						if (Plugin.DebugLoggingEnabled.Value)
						{
							Plugin.Log.LogWarning((object)("[DistanceCuller] Failed to enable " + ((object)val).GetType().Name + ": " + ex.Message));
						}
					}
				}
			}
		}

		private void DisableComponents()
		{
			for (int num = _culledComponents.Count - 1; num >= 0; num--)
			{
				MonoBehaviour val = _culledComponents[num];
				if ((Object)(object)val == (Object)null)
				{
					_culledComponents.RemoveAt(num);
				}
				else if (((Behaviour)val).enabled)
				{
					try
					{
						((Behaviour)val).enabled = false;
					}
					catch (Exception ex)
					{
						if (Plugin.DebugLoggingEnabled.Value)
						{
							Plugin.Log.LogWarning((object)("[DistanceCuller] Failed to disable " + ((object)val).GetType().Name + ": " + ex.Message));
						}
					}
				}
			}
		}

		private void OnDestroy()
		{
			try
			{
				DistanceCullerManager.Instance?.UnregisterCuller(this);
				_culledComponents.Clear();
			}
			catch (Exception ex)
			{
				if (Plugin.DebugLoggingEnabled.Value)
				{
					Plugin.Log.LogError((object)("[DistanceCuller] OnDestroy error: " + ex.Message));
				}
			}
		}
	}
	public class DistanceCullerManager : MonoBehaviour
	{
		private static readonly List<Player> _globalPlayerCache = new List<Player>();

		private readonly List<DistanceCuller> _cullers = new List<DistanceCuller>(1024);

		private readonly HashSet<DistanceCuller> _cullerSet = new HashSet<DistanceCuller>();

		private float _playerUpdateTimer;

		private float _sliceTimer;

		private int _currentIndex;

		private const float PLAYER_UPDATE_INTERVAL = 1f;

		private const int MAX_CHECKS_PER_FRAME = 100;

		private Vector3 _lastPlayerPos;

		public static DistanceCullerManager Instance { get; private set; }

		public static IReadOnlyList<Player> Players => _globalPlayerCache;

		private void Awake()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			Instance = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			Plugin.Log.LogInfo((object)"[DistanceCullerManager] Initialized with Time-Slicing.");
		}

		public void RegisterCuller(DistanceCuller culler)
		{
			if ((Object)(object)culler != (Object)null && _cullerSet.Add(culler))
			{
				_cullers.Add(culler);
			}
		}

		public void UnregisterCuller(DistanceCuller culler)
		{
			if (!((Object)(object)culler == (Object)null) && _cullerSet.Remove(culler))
			{
				int num = _cullers.IndexOf(culler);
				if (num >= 0)
				{
					int index = _cullers.Count - 1;
					_cullers[num] = _cullers[index];
					_cullers.RemoveAt(index);
				}
			}
		}

		private void Update()
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			_playerUpdateTimer += Time.deltaTime;
			_sliceTimer += Time.deltaTime;
			if (_playerUpdateTimer >= 1f)
			{
				_playerUpdateTimer = 0f;
				_globalPlayerCache.Clear();
				List<Player> allPlayers = Player.GetAllPlayers();
				if (allPlayers != null)
				{
					_globalPlayerCache.AddRange(allPlayers);
				}
			}
			if (_sliceTimer < 0.1f)
			{
				return;
			}
			_sliceTimer = 0f;
			if (!Plugin.DistanceCullerEnabled.Value || _globalPlayerCache.Count == 0 || _cullers.Count == 0)
			{
				return;
			}
			if (_globalPlayerCache.Count == 1)
			{
				Player val = _globalPlayerCache[0];
				if ((Object)(object)val != (Object)null)
				{
					if (Vector3.SqrMagnitude(((Component)val).transform.position - _lastPlayerPos) < 1f)
					{
						return;
					}
					_lastPlayerPos = ((Component)val).transform.position;
				}
			}
			int num = _cullers.Count;
			int num2 = 0;
			while (num2 < 100 && num > 0)
			{
				if (_currentIndex >= num)
				{
					_currentIndex = 0;
				}
				DistanceCuller distanceCuller = _cullers[_currentIndex];
				if ((Object)(object)distanceCuller == (Object)null)
				{
					_cullerSet.Remove(distanceCuller);
					_cullers.RemoveAt(_currentIndex);
					num--;
				}
				else
				{
					distanceCuller.ManagerUpdate(_globalPlayerCache);
					_currentIndex++;
					num2++;
				}
			}
		}

		private void OnDestroy()
		{
			_cullers.Clear();
			_cullerSet.Clear();
			Instance = null;
		}
	}
	[HarmonyPatch]
	public static class GraphicsPatches
	{
		private static readonly FieldInfo _heightmapsListField = AccessTools.Field(typeof(Heightmap), "s_heightmaps");

		[HarmonyPatch(typeof(GameCamera), "Awake")]
		[HarmonyPostfix]
		private static void ApplyPostProcessingSettings(GameCamera __instance)
		{
			if (!Plugin.GraphicsSettingsEnabled.Value)
			{
				return;
			}
			PostProcessingBehaviour component = ((Component)__instance).GetComponent<PostProcessingBehaviour>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component.profile == (Object)null))
			{
				PostProcessingProfile profile = component.profile;
				((PostProcessingModel)profile.bloom).enabled = Plugin.ConfigBloom.Value;
				((PostProcessingModel)profile.screenSpaceReflection).enabled = Plugin.ConfigReflections.Value;
				if (Plugin.DebugLoggingEnabled.Value)
				{
					Plugin.Log.LogInfo((object)"[Graphics] Applied post-processing settings.");
				}
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		[HarmonyPostfix]
		private static void ApplyInitialTerrainSettings()
		{
			if (!Plugin.GraphicsSettingsEnabled.Value || _heightmapsListField == null || !(_heightmapsListField.GetValue(null) is List<Heightmap> list))
			{
				return;
			}
			if (Plugin.DebugLoggingEnabled.Value)
			{
				Plugin.Log.LogInfo((object)$"[Graphics] Applying terrain quality to {list.Count} existing heightmaps...");
			}
			float num = Mathf.Clamp(Plugin.ConfigTerrainQuality.Value, 0.1f, 2f);
			float heightmapPixelError = 5f / num;
			foreach (Heightmap item in list)
			{
				if ((Object)(object)item != (Object)null)
				{
					Terrain component = ((Component)item).GetComponent<Terrain>();
					if ((Object)(object)component != (Object)null)
					{
						component.heightmapPixelError = heightmapPixelError;
					}
				}
			}
		}
	}
	public static class AnimatorOptimizer
	{
		[HarmonyPatch(typeof(Character), "Awake")]
		public static class Character_Awake_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Character __instance)
			{
				if (!((Object)(object)__instance == (Object)null) && Plugin.AnimatorOptimizationEnabled.Value && (Object)(object)((Component)__instance).GetComponent<CharacterAnimatorOptimizer>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<CharacterAnimatorOptimizer>();
				}
			}
		}
	}
	public class CharacterAnimatorOptimizer : MonoBehaviour
	{
		private Character _character;

		private Animator _animator;

		private ZNetView _nview;

		private MonsterAI _monsterAI;

		private float _checkTimer;

		private const float CHECK_INTERVAL = 1f;

		private const float CULL_DIST_SQR = 3600f;

		private const float FAR_CULL_DIST_SQR = 10000f;

		private bool _isFullyCulled;

		private bool _isPartiallyCulled;

		private void Awake()
		{
			_character = ((Component)this).GetComponent<Character>();
			_animator = ((Component)this).GetComponent<Animator>();
			_nview = ((Component)this).GetComponent<ZNetView>();
			_monsterAI = ((Component)this).GetComponent<MonsterAI>();
			_checkTimer = Random.Range(0f, 1f);
		}

		private void FixedUpdate()
		{
			_checkTimer += Time.fixedDeltaTime;
			if (!(_checkTimer < 1f))
			{
				_checkTimer = 0f;
				Optimize();
			}
		}

		private void Optimize()
		{
			//IL_0066: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_character == (Object)null || (Object)(object)_animator == (Object)null)
			{
				Object.Destroy((Object)(object)this);
			}
			else
			{
				if (_character.IsPlayer() || ((Object)(object)_nview != (Object)null && !_nview.IsValid()) || (Object)(object)Player.m_localPlayer == (Object)null)
				{
					return;
				}
				Vector3 val = ((Component)_character).transform.position - ((Component)Player.m_localPlayer).transform.position;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude > 10000f)
				{
					bool flag = (Object)(object)_monsterAI != (Object)null && (Object)(object)((BaseAI)_monsterAI).GetTargetCreature() == (Object)(object)Player.m_localPlayer;
					if (!_isFullyCulled && !flag)
					{
						((Behaviour)_animator).enabled = false;
						_isFullyCulled = true;
						_isPartiallyCulled = false;
						if (Plugin.DebugLoggingEnabled.Value)
						{
							Plugin.Log.LogInfo((object)("[Animator] Fully disabled: " + ((Object)_character).name + " " + $"at {Mathf.Sqrt(sqrMagnitude):F1}m"));
						}
					}
				}
				else if (sqrMagnitude > 3600f)
				{
					if (!_isPartiallyCulled || _isFullyCulled)
					{
						((Behaviour)_animator).enabled = true;
						_animator.cullingMode = (AnimatorCullingMode)2;
						_isPartiallyCulled = true;
						_isFullyCulled = false;
						if (Plugin.DebugLoggingEnabled.Value)
						{
							Plugin.Log.LogInfo((object)("[Animator] CullCompletely: " + ((Object)_character).name + " " + $"at {Mathf.Sqrt(sqrMagnitude):F1}m"));
						}
					}
				}
				else if (_isPartiallyCulled || _isFullyCulled)
				{
					((Behaviour)_animator).enabled = true;
					_animator.cullingMode = (AnimatorCullingMode)0;
					_isPartiallyCulled = false;
					_isFullyCulled = false;
					if (Plugin.DebugLoggingEnabled.Value)
					{
						Plugin.Log.LogInfo((object)("[Animator] Full animation: " + ((Object)_character).name + " " + $"at {Mathf.Sqrt(sqrMagnitude):F1}m"));
					}
				}
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_animator != (Object)null)
			{
				((Behaviour)_animator).enabled = true;
				_animator.cullingMode = (AnimatorCullingMode)0;
			}
		}
	}
	[HarmonyPatch]
	public static class MinimapOptimizer
	{
		private static FieldInfo _smallRootField;

		private static FieldInfo _largeRootField;

		private static bool _fieldsReady;

		private const int PIN_UPDATE_INTERVAL = 4;

		static MinimapOptimizer()
		{
			_smallRootField = AccessTools.Field(typeof(Minimap), "m_smallRoot") ?? AccessTools.Field(typeof(Minimap), "m_smallMapPanel");
			_largeRootField = AccessTools.Field(typeof(Minimap), "m_largeRoot") ?? AccessTools.Field(typeof(Minimap), "m_largeMapPanel");
			_fieldsReady = _smallRootField != null && _largeRootField != null;
			if (!_fieldsReady)
			{
				Plugin.Log.LogWarning((object)"[MinimapOptimizer] Minimap root fields not found — minimap update optimization disabled.");
			}
		}

		[HarmonyPatch(typeof(Minimap), "Update")]
		[HarmonyPrefix]
		private static bool Minimap_Update_Prefix(Minimap __instance)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			//IL_0032: 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_0042: Invalid comparison between Unknown and I4
			if (!Plugin.MinimapOptimizationEnabled.Value)
			{
				return true;
			}
			if (!_fieldsReady)
			{
				return true;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return true;
			}
			if ((int)__instance.m_mode == 2)
			{
				return true;
			}
			if ((int)__instance.m_mode == 0)
			{
				return false;
			}
			if ((int)__instance.m_mode == 1)
			{
				object? value = _smallRootField.GetValue(__instance);
				GameObject val = (GameObject)((value is GameObject) ? value : null);
				if ((Object)(object)val != (Object)null && !val.activeInHierarchy)
				{
					return false;
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(Minimap), "UpdateDynamicPins")]
		[HarmonyPrefix]
		private static bool UpdateDynamicPins_Prefix(Minimap __instance)
		{
			//IL_000f: 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: Invalid comparison between Unknown and I4
			if (!Plugin.MinimapOptimizationEnabled.Value)
			{
				return true;
			}
			if ((int)__instance.m_mode == 0)
			{
				return false;
			}
			if ((int)__instance.m_mode == 2)
			{
				return true;
			}
			return Time.frameCount % 4 == 0;
		}
	}
}
namespace ValheimPerformanceOverhaul.UI
{
	[HarmonyPatch]
	public static class VPOSettingsMenu
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__4_0;

			public static Func<KeyValuePair<ConfigDefinition, ConfigEntryBase>, ConfigEntryBase> <>9__5_0;

			public static Func<ConfigEntryBase, string> <>9__5_1;

			public static Func<IGrouping<string, ConfigEntryBase>, int> <>9__5_2;

			public static Func<IGrouping<string, ConfigEntryBase>, string> <>9__5_3;

			internal void <OpenMenu>b__4_0()
			{
				((BaseUnityPlugin)Plugin.Instance).Config.Save();
				ToggleSettingsMenu();
			}

			internal ConfigEntryBase <GenerateConfigUI>b__5_0(KeyValuePair<ConfigDefinition, ConfigEntryBase> kvp)
			{
				return kvp.Value;
			}

			internal string <GenerateConfigUI>b__5_1(ConfigEntryBase x)
			{
				return x.Definition.Section;
			}

			internal int <GenerateConfigUI>b__5_2(IGrouping<string, ConfigEntryBase> x)
			{
				Match match = Regex.Match(x.Key, "^\\d+");
				if (!match.Success)
				{
					return 999;
				}
				return int.Parse(match.Value);
			}

			internal string <GenerateConfigUI>b__5_3(IGrouping<string, ConfigEntryBase> x)
			{
				return x.Key;
			}
		}

		private static GameObject _settingsCanvas;

		private static bool _isMenuOpen;

		[HarmonyPatch(typeof(FejdStartup), "Start")]
		[HarmonyPostfix]
		public static void AddMainMenuButton(FejdStartup __instance)
		{
			//IL_0061: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			Transform val = Utils.FindChild(((Component)__instance).transform, "Menu", (IterativeSearchType)0);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform val2 = Utils.FindChild(val, "Settings", (IterativeSearchType)0);
			if (!((Object)(object)val2 == (Object)null))
			{
				GameObject obj = Object.Instantiate<GameObject>(((Component)val2).gameObject, ((Component)__instance).transform);
				((Object)obj).name = "Button_VPOSettings";
				RectTransform component = obj.GetComponent<RectTransform>();
				component.anchorMin = new Vector2(1f, 1f);
				component.anchorMax = new Vector2(1f, 1f);
				component.pivot = new Vector2(1f, 1f);
				component.sizeDelta = new Vector2(350f, component.sizeDelta.y);
				component.anchoredPosition = new Vector2(-20f, -20f);
				Text componentInChildren = obj.GetComponentInChildren<Text>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.text = "ValheimPerformanceOverhaul";
					componentInChildren.fontSize = 18;
					componentInChildren.horizontalOverflow = (HorizontalWrapMode)1;
				}
				Button component2 = obj.GetComponent<Button>();
				component2.onClick = new ButtonClickedEvent();
				((UnityEvent)component2.onClick).AddListener(new UnityAction(ToggleSettingsMenu));
				if (Plugin.DebugLoggingEnabled.Value)
				{
					Plugin.Log.LogInfo((object)"[VPOSettingsMenu] Top-Right button injected successfully.");
				}
			}
		}

		public static void ToggleSettingsMenu()
		{
			_isMenuOpen = !_isMenuOpen;
			if (_isMenuOpen)
			{
				OpenMenu();
			}
			else
			{
				CloseMenu();
			}
		}

		private static void OpenMenu()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: 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_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			//IL_0427: Unknown result type (might be due to invalid IL or missing references)
			//IL_043d: Unknown result type (might be due to invalid IL or missing references)
			//IL_047c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0486: Expected O, but got Unknown
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Expected O, but got Unknown
			if ((Object)(object)_settingsCanvas != (Object)null)
			{
				return;
			}
			_settingsCanvas = new GameObject("VPOSettingsCanvas");
			_settingsCanvas.layer = 5;
			Object.DontDestroyOnLoad((Object)(object)_settingsCanvas);
			Canvas obj = _settingsCanvas.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 10000;
			_settingsCanvas.AddComponent<CanvasScaler>();
			_settingsCanvas.AddComponent<GraphicRaycaster>();
			GameObject val = MakeRect("Background", _settingsCanvas.transform, new Color(0.05f, 0.05f, 0.05f, 0.98f));
			SetRect(val, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(800f, 650f), Vector2.zero);
			Outline obj2 = val.AddComponent<Outline>();
			((Shadow)obj2).effectColor = new Color(0.3f, 0.3f, 0.3f, 1f);
			((Shadow)obj2).effectDistance = new Vector2(2f, -2f);
			SetRect(((Component)MakeText("Header", val.transform, "VPO CONFIGURATION", 26, new Color(1f, 0.7f, 0.2f), (FontStyle)1)).gameObject, new Vector2(0f, 0.9f), new Vector2(1f, 1f), Vector2.zero, new Vector2(0f, -10f));
			GameObject val2 = MakeRect("CloseBtn", val.transform, new Color(0.7f, 0.2f, 0.2f, 1f));
			SetRect(val2, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(250f, 45f), new Vector2(0f, 35f));
			MakeText("CloseTxt", val2.transform, "CLOSE & SAVE", 18, Color.white, (FontStyle)1);
			ButtonClickedEvent onClick = val2.AddComponent<Button>().onClick;
			object obj3 = <>c.<>9__4_0;
			if (obj3 == null)
			{
				UnityAction val3 = delegate
				{
					((BaseUnityPlugin)Plugin.Instance).Config.Save();
					ToggleSettingsMenu();
				};
				<>c.<>9__4_0 = val3;
				obj3 = (object)val3;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj3);
			GameObject val4 = MakeRect("ScrollArea", val.transform, new Color(0f, 0f, 0f, 0.6f));
			SetRect(val4, new Vector2(0.02f, 0.15f), new Vector2(0.98f, 0.88f), Vector2.zero, Vector2.zero);
			GameObject val5 = MakeRect("Scrollbar", val4.transform, new Color(0.1f, 0.1f, 0.1f, 1f));
			SetRect(val5, new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(15f, 0f), new Vector2(-5f, 0f));
			val5.GetComponent<RectTransform>().pivot = new Vector2(1f, 0.5f);
			GameObject val6 = MakeRect("Handle", val5.transform, new Color(0.4f, 0.4f, 0.4f, 1f));
			SetRect(val6, Vector2.zero, Vector2.one, new Vector2(-4f, -4f), Vector2.zero);
			Scrollbar val7 = val5.AddComponent<Scrollbar>();
			val7.handleRect = val6.GetComponent<RectTransform>();
			val7.direction = (Direction)2;
			GameObject val8 = MakeRect("Viewport", val4.transform, new Color(1f, 1f, 1f, 0.01f));
			SetRect(val8, Vector2.zero, Vector2.one, new Vector2(-25f, 0f), new Vector2(-12.5f, 0f));
			val8.AddComponent<RectMask2D>();
			GameObject obj4 = MakeRect("Content", val8.transform, Color.clear);
			RectTransform component = obj4.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.sizeDelta = new Vector2(0f, 0f);
			VerticalLayoutGroup obj5 = obj4.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj5).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj5).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj5).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj5).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj5).spacing = 8f;
			((LayoutGroup)obj5).padding = new RectOffset(15, 15, 15, 15);
			obj4.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			ScrollRect obj6 = val4.AddComponent<ScrollRect>();
			obj6.content = component;
			obj6.viewport = val8.GetComponent<RectTransform>();
			obj6.horizontal = false;
			obj6.vertical = true;
			obj6.movementType = (MovementType)2;
			obj6.scrollSensitivity = 120f;
			obj6.verticalScrollbar = val7;
			obj6.verticalScrollbarVisibility = (ScrollbarVisibility)0;
			GenerateConfigUI(obj4.transform);
		}

		private static void GenerateConfigUI(Transform contentParent)
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			foreach (IGrouping<string, ConfigEntryBase> item in (from kvp in (IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)((BaseUnityPlugin)Plugin.Instance).Config
				select kvp.Value into x
				group x by x.Definition.Section).OrderBy(delegate(IGrouping<string, ConfigEntryBase> x)
			{
				Match match = Regex.Match(x.Key, "^\\d+");
				return (!match.Success) ? 999 : int.Parse(match.Value);
			}).ThenBy((IGrouping<string, ConfigEntryBase> x) => x.Key))
			{
				Text obj = MakeText("Cat_" + item.Key, contentParent, "  " + item.Key.ToUpper(), 18, new Color(0.4f, 0.8f, 1f), (FontStyle)1);
				obj.alignment = (TextAnchor)3;
				LayoutElement obj2 = ((Component)obj).gameObject.AddComponent<LayoutElement>();
				obj2.minHeight = 35f;
				obj2.preferredHeight = 35f;
				foreach (ConfigEntryBase item2 in item)
				{
					GameObject val = MakeRect("Row_" + item2.Definition.Key, contentParent, new Color(1f, 1f, 1f, 0.05f));
					LayoutElement obj3 = val.AddComponent<LayoutElement>();
					obj3.minHeight = 40f;
					obj3.preferredHeight = 40f;
					HorizontalLayoutGroup obj4 = val.AddComponent<HorizontalLayoutGroup>();
					((HorizontalOrVerticalLayoutGroup)obj4).childControlWidth = true;
					((HorizontalOrVerticalLayoutGroup)obj4).childControlHeight = true;
					((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandWidth = false;
					((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandHeight = true;
					((HorizontalOrVerticalLayoutGroup)obj4).spacing = 15f;
					((LayoutGroup)obj4).padding = new RectOffset(15, 15, 5, 5);
					Text obj5 = MakeText("Label", val.transform, item2.Definition.Key, 15, Color.white, (FontStyle)0);
					obj5.alignment = (TextAnchor)3;
					((Component)obj5).gameObject.AddComponent<LayoutElement>().flexibleWidth = 1f;
					string text = "";
					if (item2.DefaultValue != null)
					{
						text = ((!(item2.SettingType == typeof(bool))) ? item2.DefaultValue.ToString() : (((bool)item2.DefaultValue) ? "ENABLED" : "DISABLED"));
					}
					Text obj6 = MakeText("DefLabel", val.transform, "(Def: " + text + ")", 13, new Color(0.5f, 0.5f, 0.5f, 1f), (FontStyle)0);
					obj6.alignment = (TextAnchor)5;
					LayoutElement obj7 = ((Component)obj6).gameObject.AddComponent<LayoutElement>();
					obj7.minWidth = 100f;
					obj7.preferredWidth = 120f;
					obj7.flexibleWidth = 0f;
					if (item2.SettingType == typeof(bool))
					{
						CreateBoolToggle(val.transform, (ConfigEntry<bool>)(object)item2);
					}
					else if (item2.SettingType == typeof(float) || item2.SettingType == typeof(int) || item2.SettingType == typeof(string))
					{
						CreateInputField(val.transform, item2);
					}
					else
					{
						((Component)MakeText("Unsupported", val.transform, "-", 15, Color.gray, (FontStyle)0)).gameObject.AddComponent<LayoutElement>().minWidth = 150f;
					}
				}
			}
		}

		private static void CreateBoolToggle(Transform parent, ConfigEntry<bool> entry)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			GameObject btnGo = MakeRect("ToggleBtn", parent, entry.Value ? new Color(0.2f, 0.6f, 0.2f) : new Color(0.6f, 0.2f, 0.2f));
			LayoutElement obj = btnGo.AddComponent<LayoutElement>();
			obj.minWidth = 150f;
			obj.preferredWidth = 150f;
			obj.flexibleWidth = 0f;
			Text txt = MakeText("Txt", btnGo.transform, entry.Value ? "ENABLED" : "DISABLED", 15, Color.white, (FontStyle)1);
			((UnityEvent)btnGo.AddComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				//IL_0056: 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)
				entry.Value = !entry.Value;
				((Graphic)btnGo.GetComponent<Image>()).color = (entry.Value ? new Color(0.2f, 0.6f, 0.2f) : new Color(0.6f, 0.2f, 0.2f));
				txt.text = (entry.Value ? "ENABLED" : "DISABLED");
			});
		}

		private static void CreateInputField(Transform parent, ConfigEntryBase entry)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val2 = MakeRect("InputBg", parent, new Color(0f, 0f, 0f, 0.8f));
			LayoutElement obj = val2.AddComponent<LayoutElement>();
			obj.minWidth = 150f;
			obj.preferredWidth = 150f;
			obj.flexibleWidth = 0f;
			string text = ((entry.BoxedValue != null) ? entry.BoxedValue.ToString() : "");
			Text textComponent = MakeText("Text", val2.transform, text, 15, Color.white, (FontStyle)0);
			InputField inputField = val2.AddComponent<InputField>();
			inputField.textComponent = textComponent;
			inputField.text = text;
			if (entry.SettingType == typeof(int))
			{
				inputField.contentType = (ContentType)2;
			}
			else if (entry.SettingType == typeof(float))
			{
				inputField.contentType = (ContentType)3;
			}
			else
			{
				inputField.contentType = (ContentType)0;
			}
			((UnityEvent<string>)(object)inputField.onEndEdit).AddListener((UnityAction<string>)delegate(string val)
			{
				float result2;
				if (entry.SettingType == typeof(int) && int.TryParse(val, out var result))
				{
					entry.BoxedValue = result;
				}
				else if (entry.SettingType == typeof(float) && float.TryParse(val, NumberStyles.Any, CultureInfo.InvariantCulture, out result2))
				{
					entry.BoxedValue = result2;
				}
				else if (entry.SettingType == typeof(string))
				{
					entry.BoxedValue = val;
				}
				else
				{
					inputField.text = entry.BoxedValue?.ToString() ?? "";
				}
			});
		}

		private static void CloseMenu()
		{
			if ((Object)(object)_settingsCanvas != (Object)null)
			{
				Object.Destroy((Object)(object)_settingsCanvas);
				_settingsCanvas = null;
			}
			_isMenuOpen = false;
		}

		private static GameObject MakeRect(string name, Transform parent, Color color)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_0027: Expected O, but got Unknown
			GameObject val = new GameObject(name)
			{
				layer = 5
			};
			val.transform.SetParent(parent, false);
			((Graphic)val.AddComponent<Image>()).color = color;
			return val;
		}

		private static Text MakeText(string name, Transform parent, string text, int size, Color color, FontStyle style = 0)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_006e: 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)
			GameObject val = new GameObject(name);
			val.layer = 5;
			val.transform.SetParent(parent, false);
			Text obj = val.AddComponent<Text>();
			obj.text = text;
			obj.font = GetValheimFont();
			obj.fontSize = size;
			((Graphic)obj).color = color;
			obj.fontStyle = style;
			obj.alignment = (TextAnchor)4;
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.sizeDelta = Vector2.zero;
			component.anchoredPosition = Vector2.zero;
			return obj;
		}

		private static void SetRect(GameObject go, Vector2 anchorMin, Vector2 anchorMax, Vector2 sizeDelta, Vector2 anchoredPos)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = go.GetComponent<RectTransform>();
			component.anchorMin = anchorMin;
			component.anchorMax = anchorMax;
			component.sizeDelta = sizeDelta;
			component.anchoredPosition = anchoredPos;
		}

		private static Font GetValheimFont()
		{
			Font[] array = Object.FindObjectsByType<Font>((FindObjectsSortMode)0);
			foreach (Font val in array)
			{
				if ((Object)(object)val != (Object)null && ((Object)val).name.Contains("Averia"))
				{
					return val;
				}
			}
			return Resources.GetBuiltinResource<Font>("Arial.ttf");
		}
	}
	public static class WelcomeMessage
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__2_0;

			internal void <ShowWelcomePanel>b__2_0()
			{
				Application.OpenURL("https://discord.com/users/1084209564653727804");
			}
		}

		private static bool _shown = false;

		private static readonly string PREFS_KEY = "VPO_HideWelcome_v2.7.0";

		[HarmonyPatch(typeof(FejdStartup), "Start")]
		[HarmonyPostfix]
		public static void ShowWelcomePanel()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			//IL_0420: Unknown result type (might be due to invalid IL or missing references)
			//IL_044d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0479: Unknown result type (might be due to invalid IL or missing references)
			//IL_048e: Unknown result type (might be due to invalid IL or missing references)
			//IL_049d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0502: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Expected O, but got Unknown
			//IL_052b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0543: Unknown result type (might be due to invalid IL or missing references)
			//IL_0552: Unknown result type (might be due to invalid IL or missing references)
			//IL_0561: Unknown result type (might be due to invalid IL or missing references)
			//IL_057e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d6: Expected O, but got Unknown
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Expected O, but got Unknown
			if (_shown || PlayerPrefs.GetInt(PREFS_KEY, 0) == 1)
			{
				return;
			}
			_shown = true;
			GameObject canvasGO = new GameObject("WelcomeCanvas_VPO");
			canvasGO.layer = 5;
			Canvas obj = canvasGO.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 9999;
			canvasGO.AddComponent<CanvasScaler>();
			canvasGO.AddComponent<GraphicRaycaster>();
			Object.DontDestroyOnLoad((Object)(object)canvasGO);
			GameObject val = MakeRect("Background", canvasGO.transform, new Color(0.05f, 0.05f, 0.05f, 0.96f));
			RectTransform component = val.GetComponent<RectTransform>();
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			component.anchorMax = val2;
			component.anchorMin = val2;
			component.sizeDelta = new Vector2(550f, 480f);
			component.anchoredPosition = Vector2.zero;
			GameObject val3 = MakeRect("Header", val.transform, new Color(0.1f, 0.1f, 0.1f, 1f));
			Stretch(val3, new Vector2(0f, 0.86f), Vector2.one);
			MakeText("Title", val3.transform, "ValheimPerformanceOverhaul", 22, new Color(1f, 0.85f, 0.4f), (FontStyle)1);
			Text obj2 = MakeText("Body", val.transform, "Hi! Thank you for using my mod.\nThe mod is in beta, so I'd love to hear any feedback:\nbugs, suggestions, logs - anything.\n\nПривет! Спасибо за использование моего мода.\nМод находится в бете, поэтому я буду рад любым отзывам:\nбагам, предложениям, логам - чему угодно.\n\nMy Discord account / Мой аккаунт Discord:", 15, Color.white, (FontStyle)0);
			obj2.lineSpacing = 1.2f;
			obj2.alignment = (TextAnchor)1;
			SetAnchors(((Component)obj2).gameObject, new Vector2(0f, 0.35f), new Vector2(1f, 0.86f), new Vector2(20f, 0f), new Vector2(-20f, -15f));
			GameObject val4 = MakeRect("Link", val.transform, Color.clear);
			SetAnchors(val4, new Vector2(0f, 0.25f), new Vector2(1f, 0.35f), new Vector2(20f, 0f), new Vector2(-20f, 0f));
			MakeText("LinkText", val4.transform, "https://discord.com/users/1084209564653727804 (skarif_q)", 15, new Color(0.35f, 0.7f, 1f), (FontStyle)0);
			RectTransform component2 = MakeRect("Underline", val4.transform, new Color(0.35f, 0.7f, 1f)).GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0.05f, 0f);
			component2.anchorMax = new Vector2(0.95f, 0f);
			component2.sizeDelta = new Vector2(0f, 1.5f);
			component2.anchoredPosition = new Vector2(0f, 3f);
			Image component3 = val4.GetComponent<Image>();
			Color highlight = new Color(0.35f, 0.7f, 1f, 0.15f);
			Color pressed = new Color(0.35f, 0.7f, 1f, 0.3f);
			object obj3 = <>c.<>9__2_0;
			if (obj3 == null)
			{
				UnityAction val5 = delegate
				{
					Application.OpenURL("https://discord.com/users/1084209564653727804");
				};
				<>c.<>9__2_0 = val5;
				obj3 = (object)val5;
			}
			MakeButton(val4, component3, highlight, pressed, (UnityAction)obj3);
			MakeSeparator("Sep1", val.transform, 0.22f);
			MakeSeparator("Sep2", val.transform, 0.14f);
			bool dontShow = false;
			SetPivotAnchor(((Component)MakeText("Label", val.transform, "Don't show anymore / Больше не показывать", 13, new Color(0.75f, 0.75f, 0.75f), (FontStyle)0)).gameObject, new Vector2(0.5f, 0f), new Vector2(280f, 30f), new Vector2(20f, 85f));
			GameObject val6 = MakeRect("Box", val.transform, new Color(0.25f, 0.25f, 0.25f, 1f));
			SetPivotAnchor(val6, new Vector2(0.5f, 0f), new Vector2(18f, 18f), new Vector2(-135f, 85f));
			GameObject tickGO = ((Component)MakeText("Tick", val6.transform, "v", 13, new Color(0.35f, 0.7f, 1f), (FontStyle)1)).gameObject;
			tickGO.SetActive(false);
			GameObject obj4 = MakeRect("CheckHit", val.transform, Color.clear);
			SetPivotAnchor(obj4, new Vector2(0.5f, 0f), new Vector2(320f, 30f), new Vector2(0f, 85f));
			Image boxImg = val6.GetComponent<Image>();
			MakeButton(obj4, obj4.GetComponent<Image>(), new Color(1f, 1f, 1f, 0.05f), new Color(1f, 1f, 1f, 0.1f), (UnityAction)delegate
			{
				//IL_005d: 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)
				dontShow = !dontShow;
				tickGO.SetActive(dontShow);
				((Graphic)boxImg).color = (dontShow ? new Color(0.1f, 0.25f, 0.45f, 1f) : new Color(0.25f, 0.25f, 0.25f, 1f));
			});
			GameObject val7 = MakeRect("Close", val.transform, new Color(0.65f, 0.15f, 0.15f, 1f));
			SetPivotAnchor(val7, new Vector2(0.5f, 0f), new Vector2(140f, 34f), new Vector2(0f, 20f));
			MakeText("CloseText", val7.transform, "Close / Закрыть", 15, Color.white, (FontStyle)0);
			MakeButton(val7, val7.GetComponent<Image>(), new Color(0.85f, 0.25f, 0.25f, 1f), new Color(0.45f, 0.08f, 0.08f, 1f), (UnityAction)delegate
			{
				if (dontShow)
				{
					PlayerPrefs.SetInt(PREFS_KEY, 1);
				}
				Object.Destroy((Object)(object)canvasGO);
			});
		}

		private static GameObject MakeRect(string name, Transform parent, Color color)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			GameObject val = new GameObject(name)
			{
				layer = 5
			};
			val.transform.SetParent(parent, false);
			val.AddComponent<RectTransform>();
			((Graphic)val.AddComponent<Image>()).color = color;
			return val;
		}

		private static Text MakeText(string name, Transform parent, string text, int size, Color color, FontStyle style = 0)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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)
			GameObject val = new GameObject(name);
			val.layer = 5;
			val.transform.SetParent(parent, false);
			val.AddComponent<RectTransform>();
			Text obj = val.AddComponent<Text>();
			obj.text = text;
			obj.font = GetFont();
			obj.fontSize = size;
			((Graphic)obj).color = color;
			obj.fontStyle = style;
			obj.alignment = (TextAnchor)4;
			Stretch(val, Vector2.zero, Vector2.one);
			return obj;
		}

		private static void MakeButton(GameObject go, Image target, Color highlight, Color pressed, UnityAction action)
		{
			//IL_000e: 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_0017: 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_002b: 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)
			Button obj = go.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)target;
			ColorBlock colors = ((Selectable)obj).colors;
			((ColorBlock)(ref colors)).normalColor = ((Graphic)target).color;
			((ColorBlock)(ref colors)).highlightedColor = highlight;
			((ColorBlock)(ref colors)).pressedColor = pressed;
			((Selectable)obj).colors = colors;
			((UnityEvent)obj.onClick).AddListener(action);
		}

		private static void MakeSeparator(string name, Transform parent, float anchorY)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0052: 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)
			RectTransform component = MakeRect(name, parent, new Color(1f, 1f, 1f, 0.12f)).GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, anchorY);
			component.anchorMax = new Vector2(1f, anchorY);
			component.sizeDelta = new Vector2(0f, 1f);
			component.anchoredPosition = Vector2.zero;
		}

		private static void Stretch(GameObject go, Vector2 min, Vector2 max)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = go.GetComponent<RectTransform>();
			component.anchorMin = min;
			component.anchorMax = max;
			Vector2 offsetMin = (component.offsetMax = Vector2.zero);
			component.offsetMin = offsetMin;
		}

		private static void SetAnchors(GameObject go, Vector2 min, Vector2 max, Vector2 offsetMin, Vector2 offsetMax)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = go.GetComponent<RectTransform>();
			component.anchorMin = min;
			component.anchorMax = max;
			component.offsetMin = offsetMin;
			component.offsetMax = offsetMax;
		}

		private static void SetPivotAnchor(GameObject go, Vector2 anchor, Vector2 size, Vector2 pos)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0017: 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)
			RectTransform component = go.GetComponent<RectTransform>();
			Vector2 anchorMin = (component.anchorMax = anchor);
			component.anchorMin = anchorMin;
			component.sizeDelta = size;
			component.anchoredPosition = pos;
		}

		private static Font GetFont()
		{
			Font[] array = Object.FindObjectsByType<Font>((FindObjectsSortMode)0);
			foreach (Font val in array)
			{
				if ((Object)(object)val != (Object)null && ((Object)val).name.Contains("Averia"))
				{
					return val;
				}
			}
			return Resources.GetBuiltinResource<Font>("Arial.ttf");
		}
	}
}
namespace ValheimPerformanceOverhaul.ObjectPooling
{
	[HarmonyPatch]
	public static class ObjectPoolingPatches
	{
		[CompilerGenerated]
		private sealed class <PatchInstantiate>d__14 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private CodeInstruction <>2__current;

			private int <>l__initialThreadId;

			private IEnumerable<CodeInstruction> instructions;

			public IEnumerable<CodeInstruction> <>3__instructions;

			private string methodName;

			public string <>3__methodName;

			private MethodInfo <poolMethod>5__2;

			private int <patched>5__3;

			private IEnumerator<CodeInstruction> <>7__wrap3;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 1) <= 1u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<poolMethod>5__2 = null;
				<>7__wrap3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e9: Expected O, but got Unknown
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<poolMethod>5__2 = AccessTools.Method(typeof(ObjectPoolManager), "InstantiateFromPool", (Type[])null, (Type[])null);
						<patched>5__3 = 0;
						<>7__wrap3 = instructions.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					case 2:
						<>1__state = -3;
						break;
					}
					if (<>7__wrap3.MoveNext())
					{
						CodeInstruction current = <>7__wrap3.Current;
						if ((current.opcode == OpCodes.Call || current.opcode == OpCodes.Callvirt) && current.operand is MethodInfo methodInfo && methodInfo.Name == "Instantiate" && IsGameObjectInstantiate(methodInfo))
						{
							<patched>5__3++;
							<>2__current = new CodeInstruction(OpCodes.Call, (object)<poolMethod>5__2);
							<>1__state = 1;
							return true;
						}
						<>2__current = current;
						<>1__state = 2;
						return true;
					}
					<>m__Finally1();
					<>7__wrap3 = null;
					if (<patched>5__3 > 0)
					{
						Plugin.Log.LogInfo((object)$"[ObjectPooling] Transpiler OK: {<patched>5__3} Instantiate(s) patched in {methodName}");
					}
					else
					{
						Plugin.Log.LogWarning((object)("[ObjectPooling] Transpiler MISS: Instantiate not found in " + methodName));
					}
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

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

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

			[DebuggerHidden]
			IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator()
			{
				<PatchInstantiate>d__14 <PatchInstantiate>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<PatchInstantiate>d__ = this;
				}
				else
				{
					<PatchInstantiate>d__ = new <PatchInstantiate>d__14(0);
				}
				<PatchInstantiate>d__.instructions = <>3__instructions;
				<PatchInstantiate>d__.methodName = <>3__methodName;
				return <PatchInstantiate>d__;
			}

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

		private static readonly HashSet<string> _projectileWhitelist;

		private static readonly HashSet<int> _whitelistHashes;

		private const string CloneSuffix = "(Clone)";

		public static IEnumerable<string> Whitelist => _projectileWhitelist;

		static ObjectPoolingPatches()
		{
			_projectileWhitelist = new HashSet<string> { "bow_projectile", "bow_projectile_fire", "bow_projectile_frost", "bow_projectile_poison", "bow_projectile_needle", "arbalest_projectile_iron", "bow_projectile_carapace", "vfx_arrowhit", "vfx_BloodHit", "vfx_HitSparks" };
			_whitelistHashes = new HashSet<int>(_projectileWhitelist.Count);
			foreach (string item in _projectileWhitelist)
			{
				_whitelistHashes.Add(StringExtensionMethods.GetStableHashCode(item));
			}
		}

		public static bool IsInWhitelist(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(name);
			if (_whitelistHashes.Contains(stableHashCode))
			{
				return true;
			}
			int num = name.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num < 0)
			{
				return false;
			}
			string text = name.Substring(0, num).Trim();
			return _whitelistHashes.Contains(StringExtensionMethods.GetStableHashCode(text));
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[HarmonyPostfix]
		private static void OnZNetSceneAwake()
		{
			if (Plugin.ObjectPoolingEnabled.Value)
			{
				ObjectPoolManager.Initialize();
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		[HarmonyPostfix]
		private static void PrewarmOnSpawn(Player __instance)
		{
			if (Plugin.ObjectPoolingEnabled.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				ObjectPoolManager.PrewarmPool("bow_projectile", 20);
				ObjectPoolManager.PrewarmPool("bow_projectile_fire", 8);
				ObjectPoolManager.PrewarmPool("bow_projectile_frost", 8);
				ObjectPoolManager.PrewarmPool("bow_projectile_poison", 8);
				ObjectPoolManager.PrewarmPool("arbalest_projectile_iron", 10);
				ObjectPoolManager.PrewarmPool("bow_projectile_needle", 5);
				ObjectPoolManager.PrewarmPool("bow_projectile_carapace", 5);
				ObjectPoolManager.PrewarmPool("vfx_arrowhit", 15);
				ObjectPoolManager.PrewarmPool("vfx_BloodHit", 15);
				ObjectPoolManager.PrewarmPool("vfx_HitSparks", 10);
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Destroy")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool ZNetDestroyPrefix(GameObject go)
		{
			if (!Plugin.ObjectPoolingEnabled.Value || (Object)(object)go == (Object)null)
			{
				return true;
			}
			if (!ObjectPoolManager.IsPooled(go))
			{
				return true;
			}
			if (ObjectPoolManager.IsTracked(go))
			{
				ObjectPoolManager.ReturnObject(go);
			}
			return false;
		}

		[HarmonyPatch(typeof(Object), "Destroy", new Type[] { typeof(Object) })]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool ObjectDestroyPrefix(Object obj)
		{
			if (!Plugin.ObjectPoolingEnabled.Value || obj == (Object)null)
			{
				return true;
			}
			GameObject val = (GameObject)(object)((obj is GameObject) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			if (!ObjectPoolManager.IsPooled(val))
			{
				return true;
			}
			if (ObjectPoolManager.IsTracked(val))
			{
				ObjectPoolManager.ReturnObject(val);
			}
			return false;
		}

		[HarmonyPatch(typeof(Object), "Destroy", new Type[]
		{
			typeof(Object),
			typeof(float)
		})]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool ObjectDestroyDelayPrefix(Object obj, float t)
		{
			if (!Plugin.ObjectPoolingEnabled.Value || obj == (Object)null)
			{
				return true;
			}
			if (t > 0f)
			{
				return true;
			}
			GameObject val = (GameObject)(object)((obj is GameObject) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			if (!ObjectPoolManager.IsPooled(val))
			{
				return true;
			}
			if (ObjectPoolManager.IsTracked(val))
			{
				ObjectPoolManager.ReturnObject(val);
			}
			return false;
		}

		[HarmonyPatch(typeof(Projectile), "SpawnOnHit")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpile_Projectile_SpawnOnHit(IEnumerable<CodeInstruction> instructions)
		{
			return PatchInstantiate(instructions, "Projectile.SpawnOnHit");
		}

		[HarmonyPatch(typeof(Attack), "FireProjectileBurst")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpile_Attack_FireProjectile(IEnumerable<CodeInstruction> instructions)
		{
			return PatchInstantiate(instructions, "Attack.FireProjectileBurst");
		}

		[IteratorStateMachine(typeof(<PatchInstantiate>d__14))]
		private static IEnumerable<CodeInstruction> PatchInstantiate(IEnumerable<CodeInstruction> instructions, string methodName)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PatchInstantiate>d__14(-2)
			{
				<>3__instructions = instructions,
				<>3__methodName = methodName
			};
		}

		private static bool IsGameObjectInstantiate(MethodInfo mi)
		{
			if (mi.GetParameters().Length != 3)
			{
				return false;
			}
			if (mi.ReturnType == typeof(GameObject))
			{
				return true;
			}
			Type[] genericArguments = mi.GetGenericArguments();
			if (genericArguments.Length != 0)
			{
				return genericArguments[0] == typeof(GameObject);
			}
			return false;
		}

		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		[HarmonyPostfix]
		private static void ClearPoolOnShutdown()
		{
			ObjectPoolManager.Clear();
		}
	}
	public static class ObjectPoolManager
	{
		private static readonly Dictionary<int, Queue<GameObject>> _pools;

		private static readonly HashSet<GameObject> _objectsInUse;

		private static readonly HashSet<GameObject> _allPooledObjects;

		private static Transform _poolParent;

		private const int MAX_POOL_SIZE = 50;

		private static readonly FieldInfo _fldDidHit;

		private static readonly FieldInfo _fldVel;

		private static readonly FieldInfo _fldDidBounce;

		private static readonly FieldInfo _fldBounceCount;

		private static readonly FieldInfo _fldHaveStartPoint;

		private static readonly FieldInfo _fldStartPoint;

		private static readonly FieldInfo _fldChangedVisual;

		private static readonly FieldInfo _fldAttachParent;

		private static readonly FieldInfo _fldHasLeftShields;

		private static readonly FieldInfo _fldOwner;

		private static readonly FieldInfo _fldSkill;

		private static readonly FieldInfo _fldDamage;

		private static readonly FieldInfo _fldTtl;

		private static readonly FieldInfo _fldRaiseSkill;

		private static readonly FieldInfo _fldWeapon;

		private static readonly FieldInfo _fldAmmo;

		private static readonly FieldInfo _fldOrigHitData;