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 DaylightSavings v1.0.1
DaylightSavings.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; 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: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("DaylightSavings")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Pauses Valheim fires and lights when they are not needed, preserving fuel until they are.")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+5817ed70128f2f68248451dc0d3e685646c0f69e")] [assembly: AssemblyProduct("DaylightSavings")] [assembly: AssemblyTitle("DaylightSavings")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.0")] [module: UnverifiableCode] [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 DaylightSavings { internal static class AlwaysBurnStore { internal static bool IsAlwaysBurn(Fireplace fireplace) { ZDO zdo = FireplaceAccess.GetZdo(fireplace); if (zdo != null) { return zdo.GetBool("ds_always", false); } return false; } internal static void SetAlwaysBurn(Fireplace fireplace, bool alwaysBurn) { ZNetView nview = FireplaceAccess.GetNview(fireplace); if (!((Object)(object)nview == (Object)null) && nview.IsValid()) { if (!nview.HasOwner()) { nview.ClaimOwnership(); } ZDO zDO = nview.GetZDO(); if (zDO != null) { zDO.Set("ds_always", alwaysBurn); } } } internal static bool ToggleAlwaysBurn(Fireplace fireplace) { bool flag = !IsAlwaysBurn(fireplace); SetAlwaysBurn(fireplace, flag); return flag; } } [BepInPlugin("Hardwire99.DaylightSavings", "DaylightSavings", "1.0.1")] public sealed class DaylightSavingsPlugin : BaseUnityPlugin { private Harmony _harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); _harmony = new Harmony("Hardwire99.DaylightSavings"); _harmony.PatchAll(); Log.LogInfo((object)"DaylightSavings 1.0.1 loaded. Client-side: install on every joining player."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class FireplaceAccess { internal static readonly FieldRef<Fireplace, ZNetView> Nview = AccessTools.FieldRefAccess<Fireplace, ZNetView>("m_nview"); internal static ZNetView GetNview(Fireplace fireplace) { if ((Object)(object)fireplace == (Object)null) { return null; } try { ZNetView val = Nview.Invoke(fireplace); if ((Object)(object)val != (Object)null) { return val; } } catch { } return ((Component)fireplace).GetComponent<ZNetView>(); } internal static ZDO GetZdo(Fireplace fireplace) { ZNetView nview = GetNview(fireplace); if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return null; } return nview.GetZDO(); } internal static bool HasFuel(Fireplace fireplace) { if ((Object)(object)fireplace == (Object)null) { return false; } if (fireplace.m_infiniteFuel) { return true; } ZDO zdo = GetZdo(fireplace); if (zdo != null) { return zdo.GetFloat(ZDOVars.s_fuel, 0f) > 0f; } return false; } } internal enum FireplaceKind { Ignored, Fire, Light } internal static class FireplaceClassifier { private static readonly HashSet<string> DefaultFires = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "fire_pit", "fire_pit_iron", "bonfire", "hearth" }; private static readonly HashSet<string> DefaultLights = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "piece_walltorch", "piece_groundtorch", "piece_groundtorch_wood", "piece_groundtorch_green", "piece_groundtorch_blue", "piece_groundtorch_mist", "piece_brazierfloor01", "piece_brazierfloor02", "piece_brazierceiling01", "piece_jackoturnip", "piece_Lavalantern" }; private static readonly Dictionary<string, FireplaceKind> Cache = new Dictionary<string, FireplaceKind>(StringComparer.OrdinalIgnoreCase); internal static void Invalidate() { Cache.Clear(); } internal static FireplaceKind Classify(Fireplace fireplace) { if ((Object)(object)fireplace == (Object)null) { return FireplaceKind.Ignored; } string prefabName = GetPrefabName(fireplace); if (string.IsNullOrEmpty(prefabName)) { return FireplaceKind.Ignored; } if (Cache.TryGetValue(prefabName, out var value)) { return value; } FireplaceKind fireplaceKind = ClassifyPrefab(prefabName, fireplace); Cache[prefabName] = fireplaceKind; return fireplaceKind; } internal static string GetPrefabName(Fireplace fireplace) { if ((Object)(object)fireplace == (Object)null || (Object)(object)((Component)fireplace).gameObject == (Object)null) { return string.Empty; } try { return Utils.GetPrefabName(((Component)fireplace).gameObject); } catch { return Utils.GetPrefabName(((Object)((Component)fireplace).gameObject).name); } } private static FireplaceKind ClassifyPrefab(string prefab, Fireplace fireplace) { foreach (string item in ModConfig.ParseNames(ModConfig.ExcludePrefabs.Value)) { if (string.Equals(item, prefab, StringComparison.OrdinalIgnoreCase)) { return FireplaceKind.Ignored; } } foreach (string item2 in ModConfig.ParseNames(ModConfig.ExtraFirePrefabs.Value)) { if (string.Equals(item2, prefab, StringComparison.OrdinalIgnoreCase)) { return FireplaceKind.Fire; } } foreach (string item3 in ModConfig.ParseNames(ModConfig.ExtraLightPrefabs.Value)) { if (string.Equals(item3, prefab, StringComparison.OrdinalIgnoreCase)) { return FireplaceKind.Light; } } if (DefaultFires.Contains(prefab)) { return FireplaceKind.Fire; } if (DefaultLights.Contains(prefab)) { return FireplaceKind.Light; } if (!IsWoodFuel(fireplace)) { return FireplaceKind.Light; } return FireplaceKind.Fire; } private static bool IsWoodFuel(Fireplace fireplace) { ItemDrop fuelItem = fireplace.m_fuelItem; if ((Object)(object)fuelItem == (Object)null || fuelItem.m_itemData?.m_shared == null) { return false; } return string.Equals(fuelItem.m_itemData.m_shared.m_name, "$item_wood", StringComparison.OrdinalIgnoreCase); } } internal static class ModConfig { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> ProximityMeters; internal static ConfigEntry<bool> PauseFiresWhenNoPlayerNearby; internal static ConfigEntry<bool> PauseLightsWhenNoPlayerNearby; internal static ConfigEntry<bool> PauseLightsInUsableDaylight; internal static ConfigEntry<float> SealedCoverThreshold; internal static ConfigEntry<string> ExtraFirePrefabs; internal static ConfigEntry<string> ExtraLightPrefabs; internal static ConfigEntry<string> ExcludePrefabs; internal static void Bind(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown Enabled = config.Bind<bool>("General", "Enabled", true, "Enable DaylightSavings. When false, fires and lights behave as vanilla."); ProximityMeters = config.Bind<float>("General", "ProximityMeters", 10f, new ConfigDescription("Player range in meters for fires and for lights that are not in usable daylight.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>())); PauseFiresWhenNoPlayerNearby = config.Bind<bool>("Fires", "PauseFiresWhenNoPlayerNearby", true, "Pause campfires, hearths, and bonfires when no player is within ProximityMeters."); PauseLightsWhenNoPlayerNearby = config.Bind<bool>("Lights", "PauseLightsWhenNoPlayerNearby", true, "Pause torches and other lights when no player is within ProximityMeters, including at night."); PauseLightsInUsableDaylight = config.Bind<bool>("Lights", "PauseLightsInUsableDaylight", true, "Pause lights in windowed or open spaces during daylight, even if a player is standing there."); SealedCoverThreshold = config.Bind<float>("Lights", "SealedCoverThreshold", 0.8f, new ConfigDescription("Cover fraction that counts as a sealed pit (vanilla shelter is 0.8). Windowed halls stay below this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.4f, 1f), Array.Empty<object>())); ExtraFirePrefabs = config.Bind<string>("Classification", "ExtraFirePrefabs", "", "Comma-separated prefab names treated as fires (proximity only). Example: MyMod_Campfire"); ExtraLightPrefabs = config.Bind<string>("Classification", "ExtraLightPrefabs", "", "Comma-separated prefab names treated as lights (proximity + daylight)."); ExcludePrefabs = config.Bind<string>("Classification", "ExcludePrefabs", "", "Comma-separated prefab names DaylightSavings never pauses."); ExtraFirePrefabs.SettingChanged += delegate { FireplaceClassifier.Invalidate(); }; ExtraLightPrefabs.SettingChanged += delegate { FireplaceClassifier.Invalidate(); }; ExcludePrefabs.SettingChanged += delegate { FireplaceClassifier.Invalidate(); }; } internal static IReadOnlyList<string> ParseNames(string raw) { if (string.IsNullOrWhiteSpace(raw)) { return Array.Empty<string>(); } return (from s in raw.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim() into s where s.Length > 0 select s).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); } } internal static class ModConstants { public const string ModGuid = "Hardwire99.DaylightSavings"; public const string ModName = "DaylightSavings"; public const string ModVersion = "1.0.1"; public const string AlwaysBurnZdoKey = "ds_always"; public const float CatchUpMaxSeconds = 4f; public const float EvaluationCacheSeconds = 0.5f; public const float SunSampleHeight = 0.8f; public const float SunSampleInward = 1.5f; public const float SunRayDistance = 200f; public const float MinSunIntensity = 0.05f; } internal enum PauseReason { None, NoPlayerNearby, UsableDaylight } internal static class PauseEvaluator { private struct CacheEntry { public float Time; public PauseReason Reason; } private static readonly Dictionary<int, CacheEntry> Cache = new Dictionary<int, CacheEntry>(); private static int SolidRayMask; internal static bool ShouldPause(Fireplace fireplace) { return Evaluate(fireplace) != PauseReason.None; } internal static PauseReason Evaluate(Fireplace fireplace) { if ((Object)(object)fireplace == (Object)null || ModConfig.Enabled == null || !ModConfig.Enabled.Value) { return PauseReason.None; } if (fireplace.m_infiniteFuel || AlwaysBurnStore.IsAlwaysBurn(fireplace)) { return PauseReason.None; } ZNetView nview = FireplaceAccess.GetNview(fireplace); if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return PauseReason.None; } int instanceID = ((Object)fireplace).GetInstanceID(); float time = Time.time; if (Cache.TryGetValue(instanceID, out var value) && time - value.Time < 0.5f) { return value.Reason; } PauseReason pauseReason = EvaluateUncached(fireplace); Cache[instanceID] = new CacheEntry { Time = time, Reason = pauseReason }; return pauseReason; } internal static void StampLastTime(Fireplace fireplace) { ZDO zdo = FireplaceAccess.GetZdo(fireplace); if (zdo != null && !((Object)(object)ZNet.instance == (Object)null)) { zdo.Set(ZDOVars.s_lastTime, ZNet.instance.GetTime().Ticks); } } internal static bool LastUpdateIsStale(Fireplace fireplace, float maxSeconds) { ZDO zdo = FireplaceAccess.GetZdo(fireplace); if (zdo == null || (Object)(object)ZNet.instance == (Object)null) { return false; } long num = zdo.GetLong(ZDOVars.s_lastTime, 0L); if (num <= 0) { return false; } return (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds > (double)maxSeconds; } private static PauseReason EvaluateUncached(Fireplace fireplace) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) FireplaceKind fireplaceKind = FireplaceClassifier.Classify(fireplace); if (fireplaceKind == FireplaceKind.Ignored) { return PauseReason.None; } bool flag = Player.IsPlayerInRange(((Component)fireplace).transform.position, ModConfig.ProximityMeters.Value); if (fireplaceKind == FireplaceKind.Fire) { if (ModConfig.PauseFiresWhenNoPlayerNearby.Value && !flag) { return PauseReason.NoPlayerNearby; } return PauseReason.None; } if (ModConfig.PauseLightsWhenNoPlayerNearby.Value && !flag) { return PauseReason.NoPlayerNearby; } if (ModConfig.PauseLightsInUsableDaylight.Value && HasUsableDaylight(fireplace)) { return PauseReason.UsableDaylight; } return PauseReason.None; } private static bool HasUsableDaylight(Fireplace fireplace) { //IL_001c: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)EnvMan.instance == (Object)null || !EnvMan.IsDaylight()) { return false; } float num = default(float); bool flag = default(bool); Cover.GetCoverForPoint(((Component)fireplace).transform.position + Vector3.up * fireplace.m_coverCheckOffset, ref num, ref flag, 0.5f); bool num2 = num >= ModConfig.SealedCoverThreshold.Value; bool flag2 = SunReachesSpace(fireplace); return !num2 || flag2; } private static bool SunReachesSpace(Fireplace fireplace) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) Light val = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.m_dirLight : null); if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled || val.intensity < 0.05f) { return false; } EnsureRayMask(); Vector3 toSun = -((Component)val).transform.forward; Transform transform = ((Component)fireplace).transform; Vector3 val2 = transform.position + Vector3.up * 0.8f; float num = 1.5f; Vector3[] array = (Vector3[])(object)new Vector3[5] { val2, val2 + transform.forward * num, val2 - transform.forward * num, val2 + transform.right * num, val2 - transform.right * num }; for (int i = 0; i < array.Length; i++) { if (SunReachesPoint(array[i], toSun)) { return true; } } return false; } private static bool SunReachesPoint(Vector3 point, Vector3 toSun) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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) return !Physics.Raycast(point + toSun * 0.2f, toSun, 200f, SolidRayMask, (QueryTriggerInteraction)1); } private static void EnsureRayMask() { if (SolidRayMask == 0) { SolidRayMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" }); } } } } namespace DaylightSavings.Patches { [HarmonyPatch(typeof(Fireplace))] internal static class FireplacePatches { [HarmonyPostfix] [HarmonyPatch("IsBurning")] [HarmonyPriority(0)] private static void IsBurningPostfix(Fireplace __instance, ref bool __result) { if (__result && PauseEvaluator.ShouldPause(__instance)) { __result = false; } } [HarmonyPrefix] [HarmonyPatch("UpdateFireplace")] private static void UpdateFireplacePrefix(Fireplace __instance) { ZNetView nview = FireplaceAccess.GetNview(__instance); if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner()) { if (PauseEvaluator.ShouldPause(__instance)) { PauseEvaluator.StampLastTime(__instance); } else if (PauseEvaluator.LastUpdateIsStale(__instance, 4f)) { PauseEvaluator.StampLastTime(__instance); } } } [HarmonyPostfix] [HarmonyPatch("CanBeRemoved")] private static void CanBeRemovedPostfix(Fireplace __instance, ref bool __result) { if (__result && PauseEvaluator.ShouldPause(__instance) && FireplaceAccess.HasFuel(__instance)) { __result = false; } } [HarmonyPrefix] [HarmonyPatch("Interact")] private static bool InteractPrefix(Fireplace __instance, Humanoid user, bool hold, bool alt, ref bool __result) { if (ModConfig.Enabled == null || !ModConfig.Enabled.Value || hold || !alt) { return true; } ZNetView nview = FireplaceAccess.GetNview(__instance); if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return true; } if (FireplaceClassifier.Classify(__instance) == FireplaceKind.Ignored) { return true; } bool flag = AlwaysBurnStore.ToggleAlwaysBurn(__instance); if ((Object)(object)user != (Object)null) { string text = (flag ? "Daylight Savings: Always burn" : "Daylight Savings: Managed"); ((Character)user).Message((MessageType)2, text, 0, (Sprite)null, false); } __result = true; return false; } [HarmonyPostfix] [HarmonyPatch("GetHoverText")] private static void GetHoverTextPostfix(Fireplace __instance, ref string __result) { if (ModConfig.Enabled != null && ModConfig.Enabled.Value && !string.IsNullOrEmpty(__result) && FireplaceClassifier.Classify(__instance) != FireplaceKind.Ignored) { bool flag = AlwaysBurnStore.IsAlwaysBurn(__instance); string text = ((!flag) ? PauseEvaluator.Evaluate(__instance) : PauseReason.None) switch { PauseReason.NoPlayerNearby => "\n<color=grey>Paused (no one nearby)</color>", PauseReason.UsableDaylight => "\n<color=grey>Paused (daylight)</color>", _ => string.Empty, }; string text2 = (flag ? "\n<color=orange>Daylight Savings: Always burn</color>" : "\n<color=orange>Daylight Savings: Managed</color>"); string text3 = (flag ? "\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] Use Daylight Savings" : "\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] Always burn"); __result += Localization.instance.Localize(text + text2 + text3); } } } }