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 BloodMoon v1.0.0
plugins/BloodMoon.dll
Decompiled 3 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BloodMoon")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BloodMoon")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("fe84a512-87e1-4358-a19c-f1a2a6dba47c")] [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 BloodMoon; internal static class BloodMoonVisualState { internal static bool BaselineValid; internal static Color BaseFog; internal static Color BaseAmbient; internal static float BaseFogDensity; internal static Color BaseSkyTint; internal static Color BaseMoonColor; internal static bool StarsCached; internal static List<Renderer> StarRenderers = new List<Renderer>(); internal static Dictionary<int, bool> StarWasEnabled = new Dictionary<int, bool>(); } internal class BloodMoonVisualController : MonoBehaviour { private float _nextScan; private void LateUpdate() { if (Time.time >= _nextScan) { _nextScan = Time.time + 10f; BloodMoonVisualState.StarsCached = false; } ApplyOrRestore(); } internal static void ApplyOrRestore() { if (!BloodMoonPlugin.IsBloodMoon) { CaptureBaselineFromCurrent(); EnsureStarsCached(); RestoreStars(); return; } if (!BloodMoonVisualState.BaselineValid) { CaptureBaselineFromCurrent(); } EnsureStarsCached(); HideStars(); ApplyBloodMoonBrightRed(); } private static void CaptureBaselineFromCurrent() { //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_000b: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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) BloodMoonVisualState.BaseFog = RenderSettings.fogColor; BloodMoonVisualState.BaseAmbient = RenderSettings.ambientLight; BloodMoonVisualState.BaseFogDensity = RenderSettings.fogDensity; if ((Object)(object)RenderSettings.skybox != (Object)null) { if (RenderSettings.skybox.HasProperty("_SkyTint")) { BloodMoonVisualState.BaseSkyTint = RenderSettings.skybox.GetColor("_SkyTint"); } if (RenderSettings.skybox.HasProperty("_MoonColor")) { BloodMoonVisualState.BaseMoonColor = RenderSettings.skybox.GetColor("_MoonColor"); } } BloodMoonVisualState.BaselineValid = true; } private static void ApplyBloodMoonBrightRed() { //IL_0085: 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_008d: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(BloodMoonPlugin.Redness); float num2 = 0.75f * num; float num3 = 0.7f * num; float num4 = 0.75f * num; float num5 = 1f * num; Color val = default(Color); ((Color)(ref val))..ctor(0.7f, 0.06f, 0.08f); Color val2 = default(Color); ((Color)(ref val2))..ctor(0.55f, 0.16f, 0.16f); Color val3 = default(Color); ((Color)(ref val3))..ctor(0.95f, 0.12f, 0.14f); Color val4 = default(Color); ((Color)(ref val4))..ctor(1f, 0.02f, 0.06f); RenderSettings.fogColor = Color.Lerp(BloodMoonVisualState.BaseFog, val, num2); RenderSettings.ambientLight = Color.Lerp(BloodMoonVisualState.BaseAmbient, val2, num3); float num6 = Mathf.Lerp(1f, 1.18f, 0.75f * num); RenderSettings.fogDensity = Mathf.Lerp(BloodMoonVisualState.BaseFogDensity, BloodMoonVisualState.BaseFogDensity * num6, 0.65f * num); Material skybox = RenderSettings.skybox; if (!((Object)(object)skybox == (Object)null)) { if (skybox.HasProperty("_SkyTint")) { skybox.SetColor("_SkyTint", Color.Lerp(BloodMoonVisualState.BaseSkyTint, val3, num4)); } if (skybox.HasProperty("_MoonColor")) { skybox.SetColor("_MoonColor", Color.Lerp(BloodMoonVisualState.BaseMoonColor, val4, num5)); } TintPropLerp(skybox, "_HorizonColor", new Color(0.85f, 0.1f, 0.12f), 0.85f * num); TintPropLerp(skybox, "_AtmosphereColor", new Color(0.75f, 0.08f, 0.1f), 0.75f * num); TintPropLerp(skybox, "_CloudColor", new Color(0.65f, 0.06f, 0.08f), 0.8f * num); TintPropLerp(skybox, "_CloudTint", new Color(0.65f, 0.06f, 0.08f), 0.8f * num); TintPropLerp(skybox, "_Tint", new Color(0.85f, 0.1f, 0.12f), 0.55f * num); TintPropLerp(skybox, "_Color", new Color(0.85f, 0.1f, 0.12f), 0.45f * num); if (skybox.HasProperty("_Exposure")) { float @float = skybox.GetFloat("_Exposure"); skybox.SetFloat("_Exposure", Mathf.Lerp(@float, @float * 0.95f, 0.25f * num)); } if (skybox.HasProperty("_EmissionColor")) { Color color = skybox.GetColor("_EmissionColor"); skybox.SetColor("_EmissionColor", Color.Lerp(color, new Color(0.6f, 0.05f, 0.07f), 0.4f * num)); } } } private static void TintPropLerp(Material m, string prop, Color target, float t) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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) if (!((Object)(object)m == (Object)null) && m.HasProperty(prop)) { Color color = m.GetColor(prop); m.SetColor(prop, Color.Lerp(color, target, Mathf.Clamp01(t))); } } private static void EnsureStarsCached() { if (BloodMoonVisualState.StarsCached) { return; } BloodMoonVisualState.StarsCached = true; BloodMoonVisualState.StarRenderers.Clear(); BloodMoonVisualState.StarWasEnabled.Clear(); Renderer[] array = Object.FindObjectsOfType<Renderer>(); foreach (Renderer val in array) { if ((Object)(object)val == (Object)null) { continue; } Material sharedMaterial = val.sharedMaterial; if (!((Object)(object)sharedMaterial == (Object)null) && !((Object)(object)sharedMaterial.shader == (Object)null)) { string text = (((Object)val).name ?? "").ToLowerInvariant(); string text2 = ((Object)sharedMaterial.shader).name.ToLowerInvariant(); if (text.Contains("star") || text.Contains("stars") || text.Contains("stardome") || text.Contains("starfield") || text.Contains("milky") || text2.Contains("star") || text2.Contains("stardome") || text2.Contains("starfield")) { BloodMoonVisualState.StarRenderers.Add(val); BloodMoonVisualState.StarWasEnabled[((Object)val).GetInstanceID()] = val.enabled; } } } } private static void HideStars() { for (int i = 0; i < BloodMoonVisualState.StarRenderers.Count; i++) { Renderer val = BloodMoonVisualState.StarRenderers[i]; if ((Object)(object)val != (Object)null) { val.enabled = false; } } } private static void RestoreStars() { for (int i = 0; i < BloodMoonVisualState.StarRenderers.Count; i++) { Renderer val = BloodMoonVisualState.StarRenderers[i]; if (!((Object)(object)val == (Object)null)) { if (BloodMoonVisualState.StarWasEnabled.TryGetValue(((Object)val).GetInstanceID(), out var value)) { val.enabled = value; } else { val.enabled = true; } } } } } [HarmonyPatch(typeof(EnvMan), "SetEnv")] internal static class BloodMoonSetEnvVisualPatch { private static void Postfix() { BloodMoonVisualController.ApplyOrRestore(); } } [HarmonyPatch(typeof(EnvMan), "OnMorning")] internal static class BloodMoonMorningVisualPatch { private static void Postfix() { BloodMoonVisualState.BaselineValid = false; BloodMoonVisualState.StarsCached = false; } } [HarmonyPatch(typeof(EnvMan), "UpdateTriggers")] internal static class BloodMoonSchedulePatch { private static void Postfix() { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)EnvMan.instance == (Object)null) { return; } int currentDaySafe = GetCurrentDaySafe(EnvMan.instance); bool flag = IsNightSafe(EnvMan.instance); bool flag2 = flag && currentDaySafe > 1 && currentDaySafe % BloodMoonPlugin.PeriodDays == 0; bool flag3 = false; if (BloodMoonPlugin.IsBloodMoon != flag2 || BloodMoonPlugin.IsBloodWarning != flag3) { BloodMoonPlugin.IsBloodMoon = flag2; BloodMoonPlugin.IsBloodWarning = flag3; BloodMoonNet.BroadcastState(flag2, flag3); if (BloodMoonPlugin.Log != null) { BloodMoonPlugin.Log.LogInfo((object)("[BloodMoon] state moon=" + flag2 + " day=" + currentDaySafe + " night=" + flag)); } } } private static int GetCurrentDaySafe(EnvMan env) { try { MethodInfo methodInfo = AccessTools.Method(((object)env).GetType(), "GetCurrentDay", (Type[])null, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(env, null); if (obj is int) { return (int)obj; } } } catch { } if ((Object)(object)ZNet.instance == (Object)null) { return 1; } double timeSeconds = ZNet.instance.GetTimeSeconds(); int num = (int)(timeSeconds / 1800.0) + 1; return (num < 1) ? 1 : num; } private static bool IsNightSafe(EnvMan env) { try { MethodInfo methodInfo = AccessTools.Method(((object)env).GetType(), "IsNight", (Type[])null, (Type[])null); if (methodInfo != null && methodInfo.ReturnType == typeof(bool)) { object obj = methodInfo.Invoke(env, null); if (obj is bool) { return (bool)obj; } } } catch { } try { FieldInfo fieldInfo = AccessTools.Field(((object)env).GetType(), "m_smoothDayFraction"); if (fieldInfo != null && fieldInfo.FieldType == typeof(float)) { float num = (float)fieldInfo.GetValue(env); return num >= 0.25f && num <= 0.75f; } } catch { } return false; } } [HarmonyPatch(typeof(Character), "Awake")] internal static class BloodMoonCharacterAwakePatch { private const string ZdoStarTemp = "bm_star_temp"; private const string ZdoBaseLevel = "bm_base_level"; private const string ZdoDupApplied = "bm_dup_applied"; private static readonly HashSet<string> NoStarNoDup = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Lox", "Deathsquito", "Hen", "Chicken", "Wolf", "Boar" }; private static void Postfix(Character __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || __instance.IsPlayer() || (Object)(object)((Component)__instance).GetComponent<BaseAI>() == (Object)null) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || component.GetZDO() == null) { return; } if (!BloodMoonPlugin.IsBloodMoon) { TryRevertTempStarIfNeeded(__instance, component); return; } string prefabNameFast = GetPrefabNameFast(((Component)__instance).gameObject); if (!ShouldExclude(__instance, prefabNameFast)) { TryAddTempStar(__instance, component); TrySpawnDuplicateOnce(__instance, component, prefabNameFast); } } private static bool ShouldExclude(Character ch, string prefab) { if (NoStarNoDup.Contains(prefab)) { return true; } if (string.Equals(prefab, "Wolf_cub", StringComparison.OrdinalIgnoreCase)) { Tameable component = ((Component)ch).GetComponent<Tameable>(); if ((Object)(object)component != (Object)null && component.IsTamed()) { return true; } } Tameable component2 = ((Component)ch).GetComponent<Tameable>(); if ((Object)(object)component2 != (Object)null && component2.IsTamed()) { return true; } return false; } private static void TryAddTempStar(Character ch, ZNetView nview) { try { if (!nview.GetZDO().GetBool("bm_star_temp", false)) { int level = ch.GetLevel(); nview.GetZDO().Set("bm_base_level", level); int num = level + BloodMoonPlugin.ExtraStars; if (num > BloodMoonPlugin.MaxLevel) { num = BloodMoonPlugin.MaxLevel; } if (num < 1) { num = 1; } if (num != level) { ch.SetLevel(num); } nview.GetZDO().Set("bm_star_temp", true); } } catch (Exception ex) { if (BloodMoonPlugin.Log != null) { BloodMoonPlugin.Log.LogWarning((object)("[BloodMoon] TryAddTempStar failed: " + ex)); } } } private static void TrySpawnDuplicateOnce(Character ch, ZNetView nview, string prefab) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) try { int num = Math.Max(0, (int)Math.Round(BloodMoonPlugin.SpawnMultiplier) - 1); if (num <= 0 || nview.GetZDO().GetBool("bm_dup_applied", false)) { return; } nview.GetZDO().Set("bm_dup_applied", true); if ((Object)(object)ZNetScene.instance == (Object)null) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(ZNetScene), "Instantiate", new Type[3] { typeof(string), typeof(Vector3), typeof(Quaternion) }, (Type[])null); if (methodInfo == null) { if (BloodMoonPlugin.Log != null) { BloodMoonPlugin.Log.LogWarning((object)"[BloodMoon] ZNetScene.Instantiate(string,Vector3,Quaternion) not found. Cannot duplicate mobs."); } return; } for (int i = 0; i < num; i++) { Vector3 val = ((Component)ch).transform.position + Random.insideUnitSphere * 3f; val.y = ((Component)ch).transform.position.y; object obj = methodInfo.Invoke(ZNetScene.instance, new object[3] { prefab, val, ((Component)ch).transform.rotation }); GameObject val2 = (GameObject)((obj is GameObject) ? obj : null); if (!((Object)(object)val2 == (Object)null)) { ZNetView component = val2.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.GetZDO() != null) { component.GetZDO().Set("bm_dup_applied", true); } } } } catch (Exception ex) { if (BloodMoonPlugin.Log != null) { BloodMoonPlugin.Log.LogWarning((object)("[BloodMoon] TrySpawnDuplicateOnce failed: " + ex)); } } } private static void TryRevertTempStarIfNeeded(Character ch, ZNetView nview) { try { if (nview.GetZDO().GetBool("bm_star_temp", false)) { int num = nview.GetZDO().GetInt("bm_base_level", ch.GetLevel()); if (num < 1) { num = 1; } if (ch.GetLevel() != num) { ch.SetLevel(num); } nview.GetZDO().Set("bm_star_temp", false); nview.GetZDO().Set("bm_base_level", 0); } } catch (Exception ex) { if (BloodMoonPlugin.Log != null) { BloodMoonPlugin.Log.LogWarning((object)("[BloodMoon] TryRevertTempStarIfNeeded failed: " + ex)); } } } private static string GetPrefabNameFast(GameObject go) { string text = ((Object)go).name; if (text == null) { return ""; } int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num); } return text.Trim(); } } [HarmonyPatch(typeof(EnvMan), "OnMorning")] internal static class BloodMoonMorningRevertPatch { private const string ZdoStarTemp = "bm_star_temp"; private const string ZdoBaseLevel = "bm_base_level"; private static void Postfix() { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } try { BloodMoonPlugin.IsBloodMoon = false; BloodMoonPlugin.IsBloodWarning = false; List<Character> allCharacters = Character.GetAllCharacters(); for (int i = 0; i < allCharacters.Count; i++) { Character val = allCharacters[i]; if ((Object)(object)val == (Object)null || val.IsPlayer()) { continue; } ZNetView component = ((Component)val).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.GetZDO() != null && component.GetZDO().GetBool("bm_star_temp", false)) { int num = component.GetZDO().GetInt("bm_base_level", val.GetLevel()); if (num < 1) { num = 1; } if (val.GetLevel() != num) { val.SetLevel(num); } component.GetZDO().Set("bm_star_temp", false); component.GetZDO().Set("bm_base_level", 0); } } if (BloodMoonPlugin.Log != null) { BloodMoonPlugin.Log.LogInfo((object)"[BloodMoon] Morning revert done (loaded mobs)."); } } catch (Exception ex) { if (BloodMoonPlugin.Log != null) { BloodMoonPlugin.Log.LogWarning((object)("[BloodMoon] Morning revert failed: " + ex)); } } } } internal static class BloodMoonNet { internal const string RpcName = "BM_SetState"; private static bool _registered; internal static void Register(ZRoutedRpc rpc) { if (!_registered && rpc != null) { _registered = true; rpc.Register<bool, bool>("BM_SetState", (Action<long, bool, bool>)delegate(long sender, bool active, bool warning) { BloodMoonPlugin.IsBloodMoon = active; BloodMoonPlugin.IsBloodWarning = warning; }); } } internal static void BroadcastState(bool active, bool warning) { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "BM_SetState", new object[2] { active, warning }); } } } [BepInPlugin("com.yourname.valheim.bloodmoon", "BloodMoon", "1.0.0")] public class BloodMoonPlugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <RegisterRpcWhenReady>d__13 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public BloodMoonPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RegisterRpcWhenReady>d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if (ZRoutedRpc.instance == null) { <>2__current = null; <>1__state = 1; return true; } BloodMoonNet.Register(ZRoutedRpc.instance); if (Log != null) { Log.LogInfo((object)"[BloodMoon] RPC registered (no Harmony patch)."); } 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(); } } public const string ModGUID = "com.yourname.valheim.bloodmoon"; public const string ModName = "BloodMoon"; public const string ModVersion = "1.0.0"; internal static ManualLogSource Log; internal static int PeriodDays = 5; internal static int ExtraStars = 1; internal static int MaxLevel = 3; internal static float SpawnMultiplier = 2f; internal static float Redness = 0.8f; internal static bool IsBloodMoon; internal static bool IsBloodWarning; private Harmony _harmony; private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("com.yourname.valheim.bloodmoon"); _harmony.PatchAll(); ((Component)this).gameObject.AddComponent<BloodMoonVisualController>(); ((MonoBehaviour)this).StartCoroutine(RegisterRpcWhenReady()); Log.LogInfo((object)"BloodMoon loaded"); } [IteratorStateMachine(typeof(<RegisterRpcWhenReady>d__13))] private IEnumerator RegisterRpcWhenReady() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RegisterRpcWhenReady>d__13(0) { <>4__this = this }; } }