using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Obelisk.ValheimOptimizer")] [assembly: AssemblyDescription("Lightweight Valheim performance fixes with SkyAlpha caching and optional weather controls")] [assembly: AssemblyCompany("Obelisk")] [assembly: AssemblyProduct("Obelisk.ValheimOptimizer")] [assembly: AssemblyFileVersion("0.1.2.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.1.2.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Obelisk.ValheimOptimizer { [HarmonyPatch(typeof(LightFlicker), "ApplySettings")] internal static class PersistentLightFlickerPatch { private static void Postfix(LightFlicker __instance, Light ___m_light, float ___m_baseIntensity, Vector3 ___m_basePosition) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (OptimizerPlugin.DisablePersistentLightFlicker.Value && !(__instance.m_ttl > 0f) && !Settings.ReduceFlashingLights) { if ((Object)(object)___m_light != (Object)null) { ___m_light.intensity = ___m_baseIntensity; } ((Component)__instance).transform.localPosition = ___m_basePosition; LightFlicker.Instances.Remove((IMonoUpdater)(object)__instance); } } } [HarmonyPatch(typeof(LightLod), "OnEnable")] internal static class LightLodDistancePatch { private static void Prefix(LightLod __instance) { if (OptimizerPlugin.LightDistance.Value > 0f) { __instance.m_lightDistance = Math.Min(__instance.m_lightDistance, OptimizerPlugin.LightDistance.Value); } if (OptimizerPlugin.ShadowDistance.Value > 0f) { __instance.m_shadowDistance = Math.Min(__instance.m_shadowDistance, OptimizerPlugin.ShadowDistance.Value); } } } [HarmonyPatch(typeof(GraphicsSettingsManager), "ApplyLightLod")] internal static class LightLimitPatch { private static void Postfix() { LightLod.m_lightLimit = ClampVanillaLimit(LightLod.m_lightLimit, OptimizerPlugin.PointLightLimit.Value); LightLod.m_shadowLimit = ClampVanillaLimit(LightLod.m_shadowLimit, OptimizerPlugin.PointLightShadowLimit.Value); } private static int ClampVanillaLimit(int vanilla, int configured) { if (configured < 0) { return vanilla; } if (vanilla >= 0) { return Math.Min(vanilla, configured); } return configured; } } [HarmonyPatch(typeof(SmokeSpawner), "Awake")] internal static class SmokeSpawnerPatch { private static void Prefix(SmokeSpawner __instance) { float value = OptimizerPlugin.MinimumSmokeInterval.Value; if (value > 0f && __instance.m_interval < value) { __instance.m_interval = value; } } } [HarmonyPatch(typeof(Smoke), "Awake")] internal static class SmokeLifetimePatch { private static void Prefix(Smoke __instance) { float value = OptimizerPlugin.MaximumSmokeLifetime.Value; if (value > 0f && __instance.m_ttl > value) { __instance.m_ttl = value; } float value2 = OptimizerPlugin.MaximumSmokeFadeTime.Value; if (value2 > 0f && __instance.m_fadetime > value2) { __instance.m_fadetime = value2; } } } [HarmonyPatch(typeof(ItemDrop), "AutoStackItems")] internal static class GroundLootAutoStackPatch { private static readonly Collider[] NearbyItems = (Collider[])(object)new Collider[256]; private static readonly FieldRef HaveAutoStacked = AccessTools.FieldRefAccess("m_haveAutoStacked"); private static readonly FieldRef NetworkView = AccessTools.FieldRefAccess("m_nview"); private static readonly MethodInfo SaveMethod = AccessTools.Method(typeof(ItemDrop), "Save", (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeof(ItemDrop).FullName, "Save"); private static readonly int ItemMask = LayerMask.GetMask(new string[1] { "item" }); private static bool Prefix(ItemDrop __instance) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (!OptimizerPlugin.OptimizeGroundLootAutoStack.Value) { return true; } ItemData itemData = __instance.m_itemData; ref bool reference = ref HaveAutoStacked.Invoke(__instance); if ((itemData.m_shared.m_maxStackSize <= 1 || itemData.m_stack >= itemData.m_shared.m_maxStackSize) | reference) { return false; } reference = true; bool flag = false; int num = Physics.OverlapSphereNonAlloc(((Component)__instance).transform.position, 4f, NearbyItems, ItemMask); try { for (int i = 0; i < num; i++) { Collider val = NearbyItems[i]; Rigidbody val2 = (((Object)(object)val != (Object)null) ? val.attachedRigidbody : null); ItemDrop val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent() : null); if ((Object)(object)val3 == (Object)null || (Object)(object)val3 == (Object)(object)__instance) { continue; } ZNetView val4 = NetworkView.Invoke(val3); ItemData itemData2 = val3.m_itemData; if (itemData2.m_shared.m_autoStack && !((Object)(object)val4 == (Object)null) && val4.IsValid() && val4.IsOwner() && !(itemData2.m_shared.m_name != itemData.m_shared.m_name) && itemData2.m_quality == itemData.m_quality) { int num2 = itemData.m_shared.m_maxStackSize - itemData.m_stack; if (num2 == 0) { break; } if (itemData2.m_stack <= num2) { itemData.m_stack += itemData2.m_stack; val4.Destroy(); flag = true; } } } } finally { Array.Clear(NearbyItems, 0, num); } if (flag) { SaveMethod.Invoke(__instance, null); } return false; } } [BepInPlugin("obelisk.valheimoptimizer", "Obelisk Valheim Optimizer", "0.1.2")] [BepInProcess("valheim.exe")] [BepInProcess("valheim_server.exe")] public sealed class OptimizerPlugin : BaseUnityPlugin { public const string PluginGuid = "obelisk.valheimoptimizer"; public const string PluginName = "Obelisk Valheim Optimizer"; public const string PluginVersion = "0.1.2"; internal static ConfigEntry DisablePersistentLightFlicker; internal static ConfigEntry LightDistance; internal static ConfigEntry ShadowDistance; internal static ConfigEntry PointLightLimit; internal static ConfigEntry PointLightShadowLimit; internal static ConfigEntry MinimumSmokeInterval; internal static ConfigEntry MaximumSmokeLifetime; internal static ConfigEntry MaximumSmokeFadeTime; internal static ConfigEntry OptimizeFireParticles; internal static ConfigEntry FireParticleEmissionMultiplier; internal static ConfigEntry FireParticleLimit; internal static ConfigEntry CleanupOrphanedParticleEffects; internal static ConfigEntry OptimizeGroundLootAutoStack; internal static ConfigEntry EnableSkyAlphaOptimizer; internal static ConfigEntry DisableRainWear; internal static ConfigEntry DisablePieceRoofWetChecks; internal static ManualLogSource Log; private Harmony _harmony; internal static bool IsGraphicalClient => string.Equals(Paths.ProcessName, "valheim", StringComparison.OrdinalIgnoreCase); private void Awake() { //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; DisablePersistentLightFlicker = ((BaseUnityPlugin)this).Config.Bind("Light", "DisablePersistentFlicker", true, "Stops per-frame flicker and transform motion on persistent lights. TTL-driven lights are never disabled."); LightDistance = ((BaseUnityPlugin)this).Config.Bind("Light", "MaximumLightDistance", 32f, "Maximum LightLod distance. Lower vanilla values are preserved."); ShadowDistance = ((BaseUnityPlugin)this).Config.Bind("Light", "MaximumShadowDistance", 16f, "Maximum LightLod shadow distance. Lower vanilla values are preserved."); PointLightLimit = ((BaseUnityPlugin)this).Config.Bind("Light", "MaximumPointLights", 32, "Client-side cap applied after the vanilla graphics preset. Set to -1 to keep vanilla."); PointLightShadowLimit = ((BaseUnityPlugin)this).Config.Bind("Light", "MaximumShadowedPointLights", 2, "Client-side cap applied after the vanilla graphics preset. Set to -1 to keep vanilla."); MinimumSmokeInterval = ((BaseUnityPlugin)this).Config.Bind("Smoke", "MinimumSpawnInterval", 0.75f, "Minimum interval between visual smoke balls. Ventilation/blockage checks are not bypassed."); MaximumSmokeLifetime = ((BaseUnityPlugin)this).Config.Bind("Smoke", "MaximumLifetime", 8f, "Maximum active lifetime of a visual smoke Rigidbody."); MaximumSmokeFadeTime = ((BaseUnityPlugin)this).Config.Bind("Smoke", "MaximumFadeTime", 2.5f, "Maximum fade time after a visual smoke Rigidbody expires."); OptimizeFireParticles = ((BaseUnityPlugin)this).Config.Bind("Particles", "OptimizeFireParticles", true, "Pauses off-screen looping fireplace particles and applies conservative emission limits."); FireParticleEmissionMultiplier = ((BaseUnityPlugin)this).Config.Bind("Particles", "FireEmissionMultiplier", 0.75f, "Multiplier for looping particle emission owned by fireplaces."); FireParticleLimit = ((BaseUnityPlugin)this).Config.Bind("Particles", "FireMaxParticlesPerSystem", 256, "Maximum particles in each looping particle system owned by a fireplace."); CleanupOrphanedParticleEffects = ((BaseUnityPlugin)this).Config.Bind("Particles", "CleanupOrphanedEffects", true, "Destroys local, non-looping EffectList results that have no vanilla lifetime owner."); OptimizeGroundLootAutoStack = ((BaseUnityPlugin)this).Config.Bind("Loot", "AllocationFreeAutoStack", true, "Uses a fixed non-allocating physics buffer for vanilla owner-only ground-item auto stacking."); EnableSkyAlphaOptimizer = ((BaseUnityPlugin)this).Config.Bind("Rendering", "EnableSkyAlphaOptimizer", true, "Caches the 100 m SkyAlpha mask until the player moves 10 m or relevant world geometry changes. No per-frame tracking is added."); DisableRainWear = ((BaseUnityPlugin)this).Config.Bind("Weather", "DisableRainWear", false, "Disables rain-only structure wear. Requires a world restart and the same value on every potential multiplayer ZDO owner."); DisablePieceRoofWetChecks = ((BaseUnityPlugin)this).Config.Bind("Weather", "DisableRoofWetChecks", false, "Skips normal rain roof casts and piece wet VFX while preserving Ashlands roof checks and underwater wetness. Requires a world restart."); EnableSkyAlphaOptimizer.SettingChanged += OnSkyAlphaSettingChanged; _harmony = new Harmony("obelisk.valheimoptimizer"); _harmony.PatchAll(typeof(OptimizerPlugin).Assembly); if (DisableRainWear.Value || DisablePieceRoofWetChecks.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Weather gameplay options are enabled. Use the same values on every client/server that can own piece ZDOs."); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Obelisk Valheim Optimizer 0.1.2 loaded."); } private static void OnSkyAlphaSettingChanged(object sender, EventArgs args) { SkyAlphaOptimizerPatch.MarkDirty(); } private void OnDestroy() { if (EnableSkyAlphaOptimizer != null) { EnableSkyAlphaOptimizer.SettingChanged -= OnSkyAlphaSettingChanged; } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(Fireplace), "Awake")] internal static class FireplaceParticlePatch { private static void Postfix(Fireplace __instance) { if (OptimizerPlugin.OptimizeFireParticles.Value) { HashSet seenRoots = new HashSet(); HashSet seenSystems = new HashSet(); OptimizeRoot(__instance.m_enabledObject, seenRoots, seenSystems); OptimizeRoot(__instance.m_enabledObjectLow, seenRoots, seenSystems); OptimizeRoot(__instance.m_enabledObjectHigh, seenRoots, seenSystems); OptimizeRoot(__instance.m_fullObject, seenRoots, seenSystems); OptimizeRoot(__instance.m_halfObject, seenRoots, seenSystems); } } private static void OptimizeRoot(GameObject root, HashSet seenRoots, HashSet seenSystems) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)root == (Object)null || !seenRoots.Add(((Object)root).GetInstanceID())) { return; } ParticleSystem[] componentsInChildren = root.GetComponentsInChildren(true); foreach (ParticleSystem val in componentsInChildren) { if ((Object)(object)val == (Object)null || !seenSystems.Add(((Object)val).GetInstanceID())) { continue; } MainModule main = val.main; if (((MainModule)(ref main)).loop) { ((MainModule)(ref main)).cullingMode = (ParticleSystemCullingMode)2; int value = OptimizerPlugin.FireParticleLimit.Value; if (value > 0 && ((MainModule)(ref main)).maxParticles > value) { ((MainModule)(ref main)).maxParticles = value; } float num = Mathf.Clamp01(OptimizerPlugin.FireParticleEmissionMultiplier.Value); if (num < 1f) { EmissionModule emission = val.emission; ((EmissionModule)(ref emission)).rateOverTimeMultiplier = ((EmissionModule)(ref emission)).rateOverTimeMultiplier * num; } } } } } [HarmonyPatch(typeof(EffectList), "Create", new Type[] { typeof(Vector3), typeof(Quaternion), typeof(Transform), typeof(float), typeof(int) })] internal static class OrphanedParticleCleanupPatch { private const float CleanupPadding = 3f; private const float MaximumCleanupDelay = 60f; private static readonly HashSet AuditedOrphanNames = new HashSet(StringComparer.Ordinal) { "fx_Fader_Ragdoll", "vfx_charredcross_spawner_destroyed", "vfx_ashland_ruin_wall_windows_broken_4x6_destruction", "fx_altar_charred_destruction", "fx_altar_crystal_destruction", "vfx_Ash_Arch2_Broken1_destroyed", "vfx_Ash_Arch2_Broken2_destroyed", "vfx_Ashpiece_roof_destroyed", "vfx_Ashruin_steepstair_destroyed", "vfx_Ashruin_wall3_destroyed", "vfx_Ashruin_wall4_destroyed", "vfx_Ashruin_wall5_destroyed", "vfx_Ashruin_window2_destroyed", "vfx_Ashruin_window3_destroyed", "vfx_Ashruin_window4_destroyed", "vfx_Ashruin_window5_destroyed", "vfx_Ashruin_window6_destroyed", "vfx_Destroyed_AshlandsShip", "vfx_Destroyed_Karve", "vfx_Destroyed_Raft", "vfx_Destroyed_VikingShip", "vfx_CharredBanner1_destroyed", "vfx_CharredBanner2_destroyed", "vfx_CharredBanner3_destroyed", "vfx_creep_hangingdetroyed", "vfx_crypt_skeleton_chest_destroyed" }; private static void Postfix(GameObject[] __result) { if (OptimizerPlugin.CleanupOrphanedParticleEffects.Value && __result != null) { for (int i = 0; i < __result.Length; i++) { ScheduleIfOrphaned(__result[i]); } } } private static void ScheduleIfOrphaned(GameObject effect) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)effect == (Object)null || !AuditedOrphanNames.Contains(StripCloneSuffix(((Object)effect).name)) || (Object)(object)effect.GetComponentInChildren(true) != (Object)null || (Object)(object)effect.GetComponentInChildren(true) != (Object)null) { return; } ParticleSystem[] componentsInChildren = effect.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { return; } float num = 0f; ParticleSystem[] array = componentsInChildren; foreach (ParticleSystem val in array) { if (!((Object)(object)val == (Object)null)) { MainModule main = val.main; if (((MainModule)(ref main)).loop) { return; } float val2 = num; MinMaxCurve val3 = ((MainModule)(ref main)).startDelay; float num2 = ((MinMaxCurve)(ref val3)).constantMax + ((MainModule)(ref main)).duration; val3 = ((MainModule)(ref main)).startLifetime; num = Math.Max(val2, num2 + ((MinMaxCurve)(ref val3)).constantMax); } } LightFlicker[] componentsInChildren2 = effect.GetComponentsInChildren(true); foreach (LightFlicker val4 in componentsInChildren2) { if ((Object)(object)val4 != (Object)null && val4.m_ttl > 0f) { return; } } float num3 = Mathf.Clamp(num + 3f, 3f, 60f); Object.Destroy((Object)(object)effect, num3); } private static string StripCloneSuffix(string name) { if (!name.EndsWith("(Clone)", StringComparison.Ordinal)) { return name; } return name.Substring(0, name.Length - "(Clone)".Length); } } [HarmonyPatch(typeof(DepthCamera), "RenderDepth")] internal static class SkyAlphaOptimizerPatch { private sealed class CameraState { internal bool Initialized; internal Vector3 Anchor; internal int DirtyVersion; } private struct PendingRender { internal bool Commit; internal CameraState State; internal Vector3 Anchor; internal int DirtyVersion; } private const float RecenterDistance = 10f; private const float RecenterDistanceSquared = 100f; private const float VerticalRecenterDistance = 5f; private const float MaximumMaskLodBias = 2.5f; private static readonly ConditionalWeakTable States = new ConditionalWeakTable(); private static readonly MethodInfo GetMaskLodBiasMethod = AccessTools.Method(typeof(SkyAlphaOptimizerPatch), "GetMaskLodBias", (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeof(SkyAlphaOptimizerPatch).FullName, "GetMaskLodBias"); private static int _dirtyVersion; [HarmonyPrepare] private static bool Prepare() { return OptimizerPlugin.IsGraphicalClient; } internal static void MarkDirty() { Interlocked.Increment(ref _dirtyVersion); } private static bool Prefix(DepthCamera __instance, ref PendingRender __state) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_00a4: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) if (!OptimizerPlugin.EnableSkyAlphaOptimizer.Value) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return true; } if ((Object)(object)Utils.GetMainCamera() == (Object)null) { return true; } CameraState value = States.GetValue(__instance, (DepthCamera _) => new CameraState()); if (((Character)localPlayer).IsTeleporting()) { MarkDirty(); if (value.Initialized) { return false; } } Vector3 position = ((Component)localPlayer).transform.position; int num = Volatile.Read(in _dirtyVersion); Vector3 val = position - value.Anchor; bool flag = val.x * val.x + val.z * val.z >= 100f || Mathf.Abs(val.y) >= 5f; if (value.Initialized && !flag && value.DirtyVersion == num) { return false; } __state = new PendingRender { Commit = true, State = value, Anchor = position, DirtyVersion = num }; return true; } private static void Postfix(PendingRender __state) { //IL_0010: 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) if (__state.Commit) { __state.State.Anchor = __state.Anchor; __state.State.DirtyVersion = __state.DirtyVersion; __state.State.Initialized = true; } } private static IEnumerable Transpiler(IEnumerable instructions) { List list = new List(instructions); List list2 = new List(); for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Ldc_R4 && val.operand is float num && num.Equals(10f)) { list2.Add(i); } } if (list2.Count != 1) { ManualLogSource log = OptimizerPlugin.Log; if (log != null) { log.LogWarning((object)$"SkyAlpha lodBias patch disabled: expected one constant in DepthCamera.RenderDepth, found {list2.Count}."); } return list; } CodeInstruction obj = list[list2[0]]; obj.opcode = OpCodes.Call; obj.operand = GetMaskLodBiasMethod; return list; } private static float GetMaskLodBias() { if (!OptimizerPlugin.EnableSkyAlphaOptimizer.Value || !((Object)(object)Player.m_localPlayer != (Object)null)) { return 10f; } return Mathf.Min(QualitySettings.lodBias, 2.5f); } } [HarmonyPatch(typeof(Piece), "Awake")] internal static class SkyAlphaPieceCreatedPatch { [HarmonyPrepare] private static bool Prepare() { return OptimizerPlugin.IsGraphicalClient; } private static void Postfix(Piece __instance) { if (!ZNetView.m_forceDisableInit) { SkyAlphaOccluderLifecycle.MarkIfRelevant(((Object)(object)__instance != (Object)null) ? ((Component)__instance).gameObject : null); } } } [HarmonyPatch(typeof(Piece), "OnDestroy")] internal static class SkyAlphaPieceDestroyedPatch { [HarmonyPrepare] private static bool Prepare() { return OptimizerPlugin.IsGraphicalClient; } private static void Prefix(Piece __instance) { SkyAlphaOccluderLifecycle.MarkIfRelevant(((Object)(object)__instance != (Object)null) ? ((Component)__instance).gameObject : null); } } [HarmonyPatch(typeof(ZNetScene), "CreateObject")] internal static class SkyAlphaNetworkObjectCreatedPatch { [HarmonyPrepare] private static bool Prepare() { return OptimizerPlugin.IsGraphicalClient; } private static void Postfix(GameObject __result) { SkyAlphaOccluderLifecycle.MarkIfRelevant(__result); } } [HarmonyPatch(typeof(ZNetView), "OnDestroy")] internal static class SkyAlphaNetworkObjectDestroyedPatch { [HarmonyPrepare] private static bool Prepare() { return OptimizerPlugin.IsGraphicalClient; } private static void Prefix(ZNetView __instance) { SkyAlphaOccluderLifecycle.MarkIfRelevant(((Object)(object)__instance != (Object)null) ? ((Component)__instance).gameObject : null); } } [HarmonyPatch(typeof(Door), "SetState")] internal static class SkyAlphaDoorStatePatch { [HarmonyPrepare] private static bool Prepare() { return OptimizerPlugin.IsGraphicalClient; } private static void Postfix(Door __instance) { SkyAlphaOccluderLifecycle.MarkIfRelevant(((Object)(object)__instance != (Object)null) ? ((Component)__instance).gameObject : null); } } [HarmonyPatch(typeof(MineRock5), "UpdateMesh")] internal static class SkyAlphaMineRockMeshPatch { [HarmonyPrepare] private static bool Prepare() { return OptimizerPlugin.IsGraphicalClient; } private static void Postfix(MineRock5 __instance) { SkyAlphaOccluderLifecycle.MarkIfRelevant(((Object)(object)__instance != (Object)null) ? ((Component)__instance).gameObject : null); } } internal static class SkyAlphaOccluderLifecycle { private static readonly int PieceLayer = LayerMask.NameToLayer("piece"); private static readonly int StaticSolidLayer = LayerMask.NameToLayer("static_solid"); internal static void MarkIfRelevant(GameObject gameObject) { if (OptimizerPlugin.EnableSkyAlphaOptimizer.Value && !((Object)(object)gameObject == (Object)null) && ContainsRelevantLayer(gameObject.transform)) { SkyAlphaOptimizerPatch.MarkDirty(); } } private static bool ContainsRelevantLayer(Transform transform) { int layer = ((Component)transform).gameObject.layer; if (layer == PieceLayer || layer == StaticSolidLayer) { return true; } for (int i = 0; i < transform.childCount; i++) { if (ContainsRelevantLayer(transform.GetChild(i))) { return true; } } return false; } } [HarmonyPatch(typeof(WearNTear), "Awake")] internal static class PieceWeatherDefaultsPatch { [HarmonyPrepare] private static bool Prepare() { return OptimizerPlugin.DisableRainWear.Value; } private static void Prefix(WearNTear __instance) { __instance.m_noRoofWear = false; } } [HarmonyPatch(typeof(WearNTear), "UpdateCover")] internal static class PieceCoverUpdatePatch { [HarmonyPrepare] private static bool Prepare() { return OptimizerPlugin.DisablePieceRoofWetChecks.Value; } private static bool Prefix(WearNTear __instance, bool ___m_inAshlands, ref bool ___m_haveRoof) { ___m_haveRoof = true; if ((Object)(object)__instance.m_wet != (Object)null && __instance.m_wet.activeSelf) { __instance.m_wet.SetActive(false); } return ___m_inAshlands; } } [HarmonyPatch(typeof(WearNTear), "HaveRoof")] internal static class PieceNormalRoofCheckPatch { [HarmonyPrepare] private static bool Prepare() { return OptimizerPlugin.DisablePieceRoofWetChecks.Value; } private static bool Prefix(ref bool __result) { __result = true; return false; } } }