Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ValheimPerformanceOverhaul v3.0.0
BepInEx/plugins/ValheimPerformanceOverhaul.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
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;