using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; 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 System.Threading.Tasks; 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.Graphics; using ValheimPerformanceOverhaul.Network; using ValheimPerformanceOverhaul.ObjectPooling; using ValheimPerformanceOverhaul.Optimizations; 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 _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(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; } } 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 DebugLoggingEnabled; public static ConfigEntry GcControlEnabled; public static ConfigEntry DistanceCullerEnabled; public static ConfigEntry CreatureCullDistance; public static ConfigEntry PieceCullDistance; public static ConfigEntry AiThrottlingEnabled; public static ConfigEntry CullerExclusions; public static ConfigEntry ObjectPoolingEnabled; public static ConfigEntry JitWarmupEnabled; public static ConfigEntry LightCullingEnabled; public static ConfigEntry MaxActiveLights; public static ConfigEntry LightCullDistance; public static ConfigEntry MaxShadowCasters; public static ConfigEntry ShadowCullDistance; public static ConfigEntry LightLODEnabled; public static ConfigEntry LightLODFullDistance; public static ConfigEntry LightLODNoShadowDistance; public static ConfigEntry LightLODEmissiveDistance; public static ConfigEntry LightLODBillboardDistance; public static ConfigEntry AudioPoolingEnabled; public static ConfigEntry AudioPoolSize; public static ConfigEntry GraphicsSettingsEnabled; public static ConfigEntry ConfigShadowDistance; public static ConfigEntry ConfigShadowResolution; public static ConfigEntry ConfigShadowCascades; public static ConfigEntry ConfigTerrainQuality; public static ConfigEntry ConfigReflections; public static ConfigEntry ConfigBloom; public static ConfigEntry PathCacheDistance; public static ConfigEntry PieceOptimizationEnabled; public static ConfigEntry PieceSupportCacheDuration; public static ConfigEntry ParticleOptimizationEnabled; public static ConfigEntry ParticleCullDistance; public static ConfigEntry MaxActiveParticles; public static ConfigEntry TorchParticleLifetime; public static ConfigEntry VegetationOptimizationEnabled; public static ConfigEntry GrassRenderDistance; public static ConfigEntry GrassDensityMultiplier; public static ConfigEntry DetailObjectDistance; public static ConfigEntry DetailDensity; public static ConfigEntry TerrainMaxLOD; public static ConfigEntry AnimatorOptimizationEnabled; public static ConfigEntry MinimapOptimizationEnabled; public static ConfigEntry TamedIdleOptimizationEnabled; public static ConfigEntry TamedIdleDistanceFromCombat; public static ConfigEntry TamedIdleBaseDetectionRadius; public static ConfigEntry LightFlickerOptimizationEnabled; public static ConfigEntry SmokeOptimizationEnabled; public static ConfigEntry SmokeLiftForce; public static ConfigEntry EngineQualitySettingsEnabled; public static ConfigEntry ParticleRaycastBudget; public static ConfigEntry SkipIntroEnabled; public static ConfigEntry FrameBudgetGuardEnabled; public static ConfigEntry FrameBudgetThresholdMs; public static ConfigEntry FrameBudgetThrottledDelta; public static ConfigEntry FrameBudgetNormalDelta; public static ConfigEntry ConfigSkinWeights; public static ConfigEntry PieceSupportSmartInvalidation; public static ConfigEntry SmartZoneOwnershipEnabled; public static ConfigEntry ZonePingThreshold; public static ConfigEntry ZonePingHysteresis; public static ConfigEntry ZoneUpdateInterval; public static ConfigEntry GPUInstancingEnabled; public static ConfigEntry GPUInstancingDeduplicateMaterials; public static ConfigEntry LODGenerationEnabled; public static ConfigEntry LOD1Quality; public static ConfigEntry LOD2Quality; public static ConfigEntry LODMinVertexCount; public static ConfigEntry StaticBatchingEnabled; public static ConfigEntry StaticBatchingSettleCooldown; public static ConfigEntry TextureOptimizationEnabled; public static ConfigEntry TextureDownscaleMultiplier; public static ConfigEntry TextureMinSize; 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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown if (StaticBatchingEnabled.Value && (Object)(object)StaticBatchingManager.Instance == (Object)null) { new GameObject("_VPO_StaticBatchingManager").AddComponent(); Log.LogInfo((object)"[StaticBatching] System initialized at startup."); } if (LODGenerationEnabled.Value) { LODGenerator.SetupManager(); Log.LogInfo((object)"[LODGenerator] Persistent manager initialized at startup."); } if (GPUInstancingEnabled.Value) { OptimizationTierResolver.Initialize(); } 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(); Object.DontDestroyOnLoad((Object)val); Log.LogInfo((object)"[DistanceCuller] Manager initialized."); } if (FrameBudgetGuardEnabled.Value) { GameObject val2 = new GameObject("_VPO_FrameBudgetGuard"); val2.AddComponent(); 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 //IL_0c4d: Unknown result type (might be due to invalid IL or missing references) //IL_0c57: Expected O, but got Unknown //IL_0c8a: Unknown result type (might be due to invalid IL or missing references) //IL_0c94: Expected O, but got Unknown //IL_0cc7: Unknown result type (might be due to invalid IL or missing references) //IL_0cd1: Expected O, but got Unknown //IL_0d24: Unknown result type (might be due to invalid IL or missing references) //IL_0d2e: Expected O, but got Unknown //IL_0d81: Unknown result type (might be due to invalid IL or missing references) //IL_0d8b: Expected O, but got Unknown //IL_0dbe: Unknown result type (might be due to invalid IL or missing references) //IL_0dc8: Expected O, but got Unknown DebugLoggingEnabled = ((BaseUnityPlugin)this).Config.Bind("1. General", "Enable Debug Logging", false, "Enables detailed diagnostic logs."); GcControlEnabled = ((BaseUnityPlugin)this).Config.Bind("2. GC Control", "Enabled", true, "Prevents garbage collection during combat or movement."); DistanceCullerEnabled = ((BaseUnityPlugin)this).Config.Bind("3. Distance Culler", "Enabled", true, "Disables logic for distant objects."); CreatureCullDistance = ((BaseUnityPlugin)this).Config.Bind("3. Distance Culler", "Creature Cull Distance", 80f, new ConfigDescription("Distance at which creatures sleep.", (AcceptableValueBase)(object)new AcceptableValueRange(40f, 200f), Array.Empty())); PieceCullDistance = ((BaseUnityPlugin)this).Config.Bind("3. Distance Culler", "Piece Cull Distance", 100f, new ConfigDescription("Distance at which build pieces sleep.", (AcceptableValueBase)(object)new AcceptableValueRange(50f, 300f), Array.Empty())); AiThrottlingEnabled = ((BaseUnityPlugin)this).Config.Bind("3. Distance Culler", "Enable AI Throttling", true, "Reduces how often distant AI updates."); CullerExclusions = ((BaseUnityPlugin)this).Config.Bind("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("4. Object Pooling", "Enabled", true, "Reuses ItemDrop objects."); JitWarmupEnabled = ((BaseUnityPlugin)this).Config.Bind("5. JIT Warm-up", "Enabled", true, "Pre-compiles critical methods at game start."); LightCullingEnabled = ((BaseUnityPlugin)this).Config.Bind("6. Light Culling", "Enabled", true, "Disables distant light sources."); MaxActiveLights = ((BaseUnityPlugin)this).Config.Bind("6. Light Culling", "Max Active Lights", 15, new ConfigDescription("Max active lights.", (AcceptableValueBase)(object)new AcceptableValueRange(5, 50), Array.Empty())); LightCullDistance = ((BaseUnityPlugin)this).Config.Bind("6. Light Culling", "Light Cull Distance", 60f, new ConfigDescription("Max distance for active lights.", (AcceptableValueBase)(object)new AcceptableValueRange(20f, 150f), Array.Empty())); MaxShadowCasters = ((BaseUnityPlugin)this).Config.Bind("6. Light Culling", "Max Shadow Casters", 5, new ConfigDescription("Max shadow casters.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 15), Array.Empty())); ShadowCullDistance = ((BaseUnityPlugin)this).Config.Bind("6. Light Culling", "Shadow Cull Distance", 30f, new ConfigDescription("Distance for shadows.", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 80f), Array.Empty())); LightLODEnabled = ((BaseUnityPlugin)this).Config.Bind("6. Light Culling", "Enable Light LOD System", true, "Enables Level of Detail system for lights."); LightLODFullDistance = ((BaseUnityPlugin)this).Config.Bind("6. Light Culling", "LOD Full Light Distance", 20f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 50f), Array.Empty())); LightLODNoShadowDistance = ((BaseUnityPlugin)this).Config.Bind("6. Light Culling", "LOD No Shadow Distance", 40f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(20f, 80f), Array.Empty())); LightLODEmissiveDistance = ((BaseUnityPlugin)this).Config.Bind("6. Light Culling", "LOD Emissive Distance", 70f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(40f, 120f), Array.Empty())); LightLODBillboardDistance = ((BaseUnityPlugin)this).Config.Bind("6. Light Culling", "LOD Billboard Distance", 100f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(60f, 200f), Array.Empty())); AudioPoolingEnabled = ((BaseUnityPlugin)this).Config.Bind("7. Audio Optimization", "Enabled", true, "Reuses sound effect objects."); AudioPoolSize = ((BaseUnityPlugin)this).Config.Bind("7. Audio Optimization", "Total Pool Size", 32, new ConfigDescription("Total pooled sources.", (AcceptableValueBase)(object)new AcceptableValueRange(16, 128), Array.Empty())); GraphicsSettingsEnabled = ((BaseUnityPlugin)this).Config.Bind("8. Graphics Settings", "Enabled", true, "Enables advanced graphics settings."); ConfigShadowDistance = ((BaseUnityPlugin)this).Config.Bind("8. Graphics Settings", "Shadow Distance", 50f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(20f, 150f), Array.Empty())); ConfigShadowResolution = ((BaseUnityPlugin)this).Config.Bind("8. Graphics Settings", "Shadow Resolution", 512, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueList(new int[4] { 512, 1024, 2048, 4096 }), Array.Empty())); ConfigShadowCascades = ((BaseUnityPlugin)this).Config.Bind("8. Graphics Settings", "Shadow Cascades", 1, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(0, 4), Array.Empty())); ConfigTerrainQuality = ((BaseUnityPlugin)this).Config.Bind("8. Graphics Settings", "Terrain Quality Multiplier", 0.7f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 2f), Array.Empty())); ConfigReflections = ((BaseUnityPlugin)this).Config.Bind("8. Graphics Settings", "Enable Reflections", false, "Enables screen-space reflections."); ConfigBloom = ((BaseUnityPlugin)this).Config.Bind("8. Graphics Settings", "Enable Bloom", false, "Enables bloom glow effect."); ConfigSkinWeights = ((BaseUnityPlugin)this).Config.Bind("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(new int[3] { 1, 2, 4 }), Array.Empty())); PathCacheDistance = ((BaseUnityPlugin)this).Config.Bind("9. AI Optimization", "Path Cache Distance", 2f, new ConfigDescription("AI path caching distance.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 8f), Array.Empty())); PieceOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind("10. Piece Optimization", "Enabled", true, "Optimizes building pieces."); PieceSupportCacheDuration = ((BaseUnityPlugin)this).Config.Bind("10. Piece Optimization", "Support Cache Duration (seconds)", 5f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 30f), Array.Empty())); PieceSupportSmartInvalidation = ((BaseUnityPlugin)this).Config.Bind("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("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("11. Particle Optimization", "Enabled", true, "Optimizes particle systems."); ParticleCullDistance = ((BaseUnityPlugin)this).Config.Bind("11. Particle Optimization", "Particle Cull Distance", 50f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(20f, 100f), Array.Empty())); MaxActiveParticles = ((BaseUnityPlugin)this).Config.Bind("11. Particle Optimization", "Max Active Particle Systems", 30, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(10, 100), Array.Empty())); TorchParticleLifetime = ((BaseUnityPlugin)this).Config.Bind("11. Particle Optimization", "Torch Particle Lifetime", 0.8f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 2f), Array.Empty())); VegetationOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind("12. Vegetation Optimization", "Enabled", true, "Optimizes grass and details."); GrassRenderDistance = ((BaseUnityPlugin)this).Config.Bind("12. Vegetation Optimization", "Grass Render Distance", 60f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(30f, 120f), Array.Empty())); GrassDensityMultiplier = ((BaseUnityPlugin)this).Config.Bind("12. Vegetation Optimization", "Grass Density Multiplier", 0.7f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 1f), Array.Empty())); DetailObjectDistance = ((BaseUnityPlugin)this).Config.Bind("12. Vegetation Optimization", "Detail Object Distance", 80f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(40f, 150f), Array.Empty())); DetailDensity = ((BaseUnityPlugin)this).Config.Bind("12. Vegetation Optimization", "Detail Density", 0.7f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 1f), Array.Empty())); TerrainMaxLOD = ((BaseUnityPlugin)this).Config.Bind("12. Vegetation Optimization", "Terrain Max LOD", 1, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(0, 2), Array.Empty())); AnimatorOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind("13. Animator Optimization", "Enabled", true, "Optimizes character animations."); MinimapOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind("14. Minimap Optimization", "Enabled", true, "Reduces minimap texture updates."); SmartZoneOwnershipEnabled = ((BaseUnityPlugin)this).Config.Bind("14. Network Optimization", "Smart Zone Ownership", false, "[Только Сервер] Автоматически передает управление ИИ мобов игроку с наименьшим пингом в зоне."); ZonePingThreshold = ((BaseUnityPlugin)this).Config.Bind("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(50, 500), Array.Empty())); ZonePingHysteresis = ((BaseUnityPlugin)this).Config.Bind("14. Network Optimization", "Zone Ping Hysteresis (ms)", 30, new ConfigDescription("The difference in ping required to transfer possession.", (AcceptableValueBase)(object)new AcceptableValueRange(10, 100), Array.Empty())); ZoneUpdateInterval = ((BaseUnityPlugin)this).Config.Bind("14. Network Optimization", "Zone Update Interval (sec)", 5f, new ConfigDescription("How often does the server check pings in zones?", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 20f), Array.Empty())); NetworkManager.SetupConfigs(((BaseUnityPlugin)this).Config); TamedIdleOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind("16. Tamed Mob Idle Optimization", "Enabled", true, "Idle mode for tamed mobs."); TamedIdleDistanceFromCombat = ((BaseUnityPlugin)this).Config.Bind("16. Tamed Mob Idle Optimization", "Idle Distance From Combat", 5f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(3f, 30f), Array.Empty())); TamedIdleBaseDetectionRadius = ((BaseUnityPlugin)this).Config.Bind("16. Tamed Mob Idle Optimization", "Base Detection Radius", 30f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(15f, 60f), Array.Empty())); LightFlickerOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind("17. Light Flicker Optimization", "Enabled", true, "Fixes light intensity to base value."); SmokeOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind("18. Smoke Physics Optimization", "Enabled", true, "Simplified smoke aerodynamics."); SmokeLiftForce = ((BaseUnityPlugin)this).Config.Bind("18. Smoke Physics Optimization", "Smoke Lift Force", 3.5f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); EngineQualitySettingsEnabled = ((BaseUnityPlugin)this).Config.Bind("19. Engine Quality Settings", "Enabled", true, "Low-level Unity tweaks."); ParticleRaycastBudget = ((BaseUnityPlugin)this).Config.Bind("19. Engine Quality Settings", "Particle Raycast Budget", 1024, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(64, 4096), Array.Empty())); SkipIntroEnabled = ((BaseUnityPlugin)this).Config.Bind("20. Skip Intro", "Enabled", true, "Skips logos."); FrameBudgetGuardEnabled = ((BaseUnityPlugin)this).Config.Bind("21. Frame Budget Guard", "Enabled", true, "Limits maximumDeltaTime on frame spikes."); FrameBudgetThresholdMs = ((BaseUnityPlugin)this).Config.Bind("21. Frame Budget Guard", "Freeze Threshold (ms)", 28f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(16f, 100f), Array.Empty())); FrameBudgetThrottledDelta = ((BaseUnityPlugin)this).Config.Bind("21. Frame Budget Guard", "Throttled MaxDeltaTime", 0.045f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(0.02f, 0.1f), Array.Empty())); FrameBudgetNormalDelta = ((BaseUnityPlugin)this).Config.Bind("21. Frame Budget Guard", "Normal MaxDeltaTime", 0.07f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange(0.03f, 0.2f), Array.Empty())); GPUInstancingEnabled = ((BaseUnityPlugin)this).Config.Bind("22. GPU Instancing", "Enabled", true, "Enables GPU Instancing on highly repetitive world objects (flora, rocks, pieces)."); GPUInstancingDeduplicateMaterials = ((BaseUnityPlugin)this).Config.Bind("22. GPU Instancing", "Deduplicate Materials", true, "Merges duplicate material instances to maximize instancing batch sizes."); LODGenerationEnabled = ((BaseUnityPlugin)this).Config.Bind("23. LOD Generation", "Enabled", true, "Enables asynchronous runtime generation of Level of Detail (LOD) groups for static world objects."); LOD1Quality = ((BaseUnityPlugin)this).Config.Bind("23. LOD Generation", "LOD1 Mesh Quality", 0.5f, new ConfigDescription("Vertex reduction target for LOD1 (50% target).", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 0.9f), Array.Empty())); LOD2Quality = ((BaseUnityPlugin)this).Config.Bind("23. LOD Generation", "LOD2 Mesh Quality", 0.15f, new ConfigDescription("Vertex reduction target for LOD2 (15% target).", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 0.5f), Array.Empty())); LODMinVertexCount = ((BaseUnityPlugin)this).Config.Bind("23. LOD Generation", "Min Vertex Count", 300, new ConfigDescription("Minimum vertex count of a mesh to qualify for LOD generation. Higher values target only high-poly meshes, reducing CPU overhead.", (AcceptableValueBase)(object)new AcceptableValueRange(150, 5000), Array.Empty())); StaticBatchingEnabled = ((BaseUnityPlugin)this).Config.Bind("24. Static Batching", "Enabled", true, "Combines unique static geometry (dungeons, ruins, pillars, cliffs) per sector in runtime using Unity's StaticBatchingUtility."); StaticBatchingSettleCooldown = ((BaseUnityPlugin)this).Config.Bind("24. Static Batching", "Settle Cooldown (seconds)", 2f, new ConfigDescription("Time to wait after the last object spawns in a sector before combining them into a static batch.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 10f), Array.Empty())); TextureOptimizationEnabled = ((BaseUnityPlugin)this).Config.Bind("27. Texture Optimization", "Enabled", false, "Enables runtime background downscaling and GPU compression of secondary object textures to save VRAM."); TextureDownscaleMultiplier = ((BaseUnityPlugin)this).Config.Bind("27. Texture Optimization", "Downscale Multiplier", 0.5f, new ConfigDescription("Texture scale factor (0.5 means halving width and height, reducing memory footprint by 75%).", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 1f), Array.Empty())); TextureMinSize = ((BaseUnityPlugin)this).Config.Bind("27. Texture Optimization", "Min Texture Size to Process", 512, new ConfigDescription("Minimum texture size (width or height) to qualify for optimization. Smaller textures/icons are ignored.", (AcceptableValueBase)(object)new AcceptableValueRange(128, 2048), Array.Empty())); } 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 { private readonly List _culledComponents = new List(); 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(); if ((Object)(object)_zNetView == (Object)null || !_zNetView.IsValid()) { Object.Destroy((Object)(object)this); return; } _isCharacter = (Object)(object)((Component)this).GetComponent() != (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); } } private IEnumerator RegisterNextFrame() { yield return null; if (!((Object)(object)this == (Object)null) && !((Object)(object)_zNetView == (Object)null) && _zNetView.IsValid()) { DistanceCullerManager.Instance?.RegisterCuller(this); } } private void CollectComponents() { MonoBehaviour[] componentsInChildren = ((Component)this).GetComponentsInChildren(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)) && !(val is Fireplace) && !(val is Hoverable) && !(val is Interactable)) { _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 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 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 _globalPlayerCache = new List(); private readonly List _cullers = new List(1024); private readonly HashSet _cullerSet = new HashSet(); 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 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 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(); 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 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(); 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() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } } 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(); _animator = ((Component)this).GetComponent(); _nview = ((Component)this).GetComponent(); _monsterAI = ((Component)this).GetComponent(); _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, ConfigEntryBase> <>9__5_0; public static Func <>9__5_1; public static Func, int> <>9__5_2; public static Func, string> <>9__5_3; internal void b__4_0() { ((BaseUnityPlugin)Plugin.Instance).Config.Save(); ToggleSettingsMenu(); } internal ConfigEntryBase b__5_0(KeyValuePair kvp) { return kvp.Value; } internal string b__5_1(ConfigEntryBase x) { return x.Definition.Section; } internal int b__5_2(IGrouping x) { Match match = Regex.Match(x.Key, "^\\d+"); if (!match.Success) { return 999; } return int.Parse(match.Value); } internal string b__5_3(IGrouping 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(((Component)val2).gameObject, ((Component)__instance).transform); ((Object)obj).name = "Button_VPOSettings"; RectTransform component = obj.GetComponent(); 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(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = "ValheimPerformanceOverhaul"; componentInChildren.fontSize = 18; componentInChildren.horizontalOverflow = (HorizontalWrapMode)1; } Button component2 = obj.GetComponent