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 QuietNights v0.1.0
QuietNights.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using MushroomMods; using MushroomSync; 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("QuietNights")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Turns off the extra night-time creature spawns that killing a boss unlocks.")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+7757ccc54aeca6be4b442e05fcdfb2495dea3f50")] [assembly: AssemblyProduct("Quiet Nights")] [assembly: AssemblyTitle("QuietNights")] [assembly: AssemblyVersion("0.1.0.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 MushroomMods { internal static class PatchIsolation { internal static int PatchAllIsolated(Harmony harmony, Assembly assembly, ManualLogSource log) { int num = 0; Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(assembly); foreach (Type type in typesFromAssembly) { try { harmony.CreateClassProcessor(type).Patch(); } catch (Exception ex) { num++; log.LogError((object)("Harmony patch class " + type.FullName + " was skipped and the rest of " + harmony.Id + " is still active. " + ex)); } } return num; } } } namespace QuietNights { internal static class DumpCommand { internal static void Run(ConsoleEventArgs args) { if (args.Length < 2 || !string.Equals(args[1], "dump", StringComparison.OrdinalIgnoreCase)) { Terminal context = args.Context; if (context != null) { context.AddString("Usage: quietnights dump"); } return; } if ((Object)(object)ZoneSystem.instance == (Object)null) { Terminal context2 = args.Context; if (context2 != null) { context2.AddString("Quiet Nights: load a world first - the spawn table belongs to it."); } return; } int covered; int edited; string text = Build(out covered, out edited); string text2 = Path.Combine(Paths.ConfigPath, "QuietNights.dump.txt"); try { File.WriteAllText(text2, text); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not write " + text2 + ": " + ex.Message)); text2 = "the BepInEx log only"; } Plugin.Log.LogInfo((object)("Spawn table dump:" + Environment.NewLine + text)); Terminal context3 = args.Context; if (context3 != null) { context3.AddString("Quiet Nights: " + covered + " boss-gated entries for covered creatures, " + edited + " currently suppressed. Written to " + text2); } } private static string Build(out int covered, out int edited) { covered = 0; edited = 0; Rules rules = Plugin.CurrentRules(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Quiet Nights 0.1.0 spawn table dump"); stringBuilder.AppendLine("Enabled = " + Plugin.Enabled.Value); stringBuilder.AppendLine("Creatures = " + Plugin.Creatures.Value); stringBuilder.AppendLine("BossKeys = " + Plugin.BossKeys.Value); string text = default(string); stringBuilder.AppendLine("Host values = " + (Plugin.Sync.TryGetSyncedValue<string>(Plugin.Creatures, ref text) ? "yes, following the server" : "no, local config")); stringBuilder.AppendLine("World keys = " + string.Join(", ", ZoneSystem.instance.GetGlobalKeys())); stringBuilder.AppendLine("Spawn lists = " + DescribeSharing()); stringBuilder.AppendLine(); stringBuilder.AppendLine("Listed: every entry gated on a global key, plus every entry for a covered creature."); stringBuilder.AppendLine("biome= is the mask as shipped; now= appears when Quiet Nights has changed it."); stringBuilder.AppendLine(); IReadOnlyList<SpawnSystemList> knownPrefabLists = SpawnSuppressor.KnownPrefabLists; for (int i = 0; i < knownPrefabLists.Count; i++) { if ((Object)(object)knownPrefabLists[i] != (Object)null) { Append(stringBuilder, "list" + i + ":" + ((Object)knownPrefabLists[i]).name, knownPrefabLists[i].m_spawners, rules, ref covered, ref edited); } } foreach (AltBiome altBiome in AltBiomeList.m_altBiomes) { if (altBiome != null) { Append(stringBuilder, "alt:" + altBiome.m_name, altBiome.m_spawn, rules, ref covered, ref edited); } } return stringBuilder.ToString(); } private static void Append(StringBuilder text, string source, List<SpawnData> entries, Rules rules, ref int covered, ref int edited) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) if (entries == null) { return; } for (int i = 0; i < entries.Count; i++) { SpawnData val = entries[i]; if (val == null || (Object)(object)val.m_prefab == (Object)null) { continue; } bool flag = !string.IsNullOrEmpty(val.m_requiredGlobalKey); bool flag2 = rules.Find(((Object)val.m_prefab).name) != null; if (flag || flag2) { Biome kept; Verdict verdict = SpawnSuppressor.Classify(val, rules, out kept); if (verdict != Verdict.NotCovered) { covered++; } bool flag3 = SpawnSuppressor.IsEdited(val); if (flag3) { edited++; } text.Append(source).Append(" idx=").Append(i + 1) .Append(" name=\"") .Append(val.m_name) .Append('"') .Append(" prefab=") .Append(((Object)val.m_prefab).name) .Append(" biome=") .Append(SpawnSuppressor.OriginalBiome(val)); if (flag3) { text.Append(" now=").Append(val.m_biome); } text.Append(" key=").Append(flag ? val.m_requiredGlobalKey : "-").Append(" night=") .Append(val.m_spawnAtNight ? 1 : 0) .Append(" day=") .Append(val.m_spawnAtDay ? 1 : 0) .Append(" enabled=") .Append(val.m_enabled ? 1 : 0) .Append(" max=") .Append(val.m_maxSpawned) .Append(" interval=") .Append(val.m_spawnInterval.ToString(CultureInfo.InvariantCulture)) .Append(" chance=") .Append(val.m_spawnChance.ToString(CultureInfo.InvariantCulture)) .Append(" hunt=") .Append(val.m_huntPlayer ? 1 : 0) .Append(" [") .Append(verdict) .Append(flag3 ? ", APPLIED" : "") .AppendLine("]"); } } } private static string DescribeSharing() { IReadOnlyList<SpawnSystemList> knownPrefabLists = SpawnSuppressor.KnownPrefabLists; if (knownPrefabLists.Count == 0) { return "none found on the zone control prefab"; } foreach (SpawnSystem item in SpawnSuppressor.LiveSpawnSystems()) { if (!((Object)(object)item == (Object)null) && item.m_spawnLists.Count != 0 && !((Object)(object)item.m_spawnLists[0] == (Object)null)) { return (item.m_spawnLists[0] == knownPrefabLists[0]) ? "SHARED - live zones use the prefab's own list objects" : "CLONED - each zone has its own copy (handled per zone from SpawnSystem.Awake)"; } } return "unknown - no zone is loaded to compare against"; } } [HarmonyPatch(typeof(ZoneSystem), "Start")] internal static class ZoneSystem_Start_Patch { private static void Postfix(ZoneSystem __instance) { SpawnSuppressor.OnWorldStart(__instance); } } [HarmonyPatch(typeof(SpawnSystem), "Awake")] internal static class SpawnSystem_Awake_Patch { private static void Postfix(SpawnSystem __instance) { SpawnSuppressor.OnZoneAwake(__instance); } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class Terminal_InitTerminal_Patch { [CompilerGenerated] private static class <>O { public static ConsoleEvent <0>__Run; } private static bool _registered; private static void Postfix() { //IL_003d: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown if (_registered) { return; } _registered = true; try { object obj = <>O.<0>__Run; if (obj == null) { ConsoleEvent val = DumpCommand.Run; <>O.<0>__Run = val; obj = (object)val; } new ConsoleCommand("quietnights", "dump - write every boss-gated spawn entry, and what Quiet Nights does to it, to the log and config folder", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } catch (Exception ex) { Plugin.Log.LogError((object)("Could not register the quietnights console command: " + ex)); } } } [BepInPlugin("mushroom.quietnights", "QuietNights", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("valheim.exe")] [BepInProcess("valheim_server.exe")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "mushroom.quietnights"; public const string PluginName = "QuietNights"; public const string PluginVersion = "0.1.0"; internal static ManualLogSource Log; internal static ConfigSync Sync; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<string> Creatures; internal static ConfigEntry<string> BossKeys; private Harmony _harmony; private static Rules _rules; private static string _rulesSource; internal static Rules CurrentRules() { string text = Creatures.Value + "\n" + BossKeys.Value; if (_rules == null || text != _rulesSource) { _rules = Rules.Parse(Creatures.Value, BossKeys.Value); _rulesSource = text; } return _rules; } private void Awake() { //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Sync = ConfigSync.Create("mushroom.quietnights", "0.1.0", Log).Protecting(((BaseUnityPlugin)this).Config).OnApplied((Action)SpawnSuppressor.Apply); Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When off, every night spawn behaves as in the unmodded game. Set on the server; connected clients follow it."); Creatures = ((BaseUnityPlugin)this).Config.Bind<string>("Rules", "Creatures", "Goblin*:Plains, Seeker*:Mistlands, Charred*:AshLands", "Creatures whose boss-unlocked night spawns are removed everywhere except at home. Comma-separated Prefab:Biome pairs. A trailing * matches a family of prefabs (Goblin* covers Goblin, GoblinArcher, GoblinShaman, GoblinBrute). Join several home biomes with +, as in Plains+Meadows. Run 'quietnights dump' in the console to see the real prefab names and what each rule catches."); BossKeys = ((BaseUnityPlugin)this).Config.Bind<string>("Rules", "BossKeys", "defeated_*", "Global keys that count as a boss kill. Only spawn entries requiring one of these are touched. Comma-separated; a trailing * matches a prefix."); Sync.Register((ConfigEntryBase[])(object)new ConfigEntryBase[3] { (ConfigEntryBase)Enabled, (ConfigEntryBase)Creatures, (ConfigEntryBase)BossKeys }); Enabled.SettingChanged += delegate { SpawnSuppressor.Apply(); }; Creatures.SettingChanged += delegate { SpawnSuppressor.Apply(); }; BossKeys.SettingChanged += delegate { SpawnSuppressor.Apply(); }; Sync.WatchForChanges(((BaseUnityPlugin)this).Config).Start(); _harmony = new Harmony("mushroom.quietnights"); int num = PatchIsolation.PatchAllIsolated(_harmony, typeof(Plugin).Assembly, Log); Log.LogInfo((object)("QuietNights 0.1.0 loaded." + ((num > 0) ? (" " + num + " patch class(es) skipped - see the errors above.") : ""))); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal sealed class Rules { internal sealed class Creature { internal string Pattern; internal Biome Native; } internal readonly List<Creature> Creatures = new List<Creature>(); internal readonly List<string> BossKeys = new List<string>(); internal static Rules Parse(string creatures, string bossKeys) { //IL_00b8: 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) Rules rules = new Rules(); foreach (string item in Split(creatures)) { int num = item.LastIndexOf(':'); if (num <= 0 || num == item.Length - 1) { Plugin.Log.LogWarning((object)("Rules.Creatures: '" + item + "' is not Prefab:Biome - ignored.")); continue; } if (!TryParseBiomes(item.Substring(num + 1), out var biomes)) { Plugin.Log.LogWarning((object)("Rules.Creatures: '" + item + "' names no biome the game knows - ignored. Valid: " + string.Join(", ", Enum.GetNames(typeof(Biome))))); continue; } rules.Creatures.Add(new Creature { Pattern = item.Substring(0, num).Trim(), Native = biomes }); } rules.BossKeys.AddRange(Split(bossKeys)); return rules; } internal Creature Find(string prefabName) { foreach (Creature creature in Creatures) { if (Matches(creature.Pattern, prefabName)) { return creature; } } return null; } internal bool IsBossKey(string key) { foreach (string bossKey in BossKeys) { if (Matches(bossKey, key)) { return true; } } return false; } private static bool Matches(string pattern, string value) { if (string.IsNullOrEmpty(value)) { return false; } if (pattern.EndsWith("*", StringComparison.Ordinal)) { return value.StartsWith(pattern.Substring(0, pattern.Length - 1), StringComparison.OrdinalIgnoreCase); } return string.Equals(pattern, value, StringComparison.OrdinalIgnoreCase); } private static bool TryParseBiomes(string text, out Biome biomes) { //IL_0035: 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) //IL_004a: 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_004d: Expected I4, but got Unknown biomes = (Biome)0; string[] array = text.Split(new char[1] { '+' }); for (int i = 0; i < array.Length; i++) { if (!Enum.TryParse<Biome>(array[i].Trim(), ignoreCase: true, out Biome result) || !Enum.IsDefined(typeof(Biome), result) || (int)result == 0) { return false; } biomes |= result; } return true; } private static IEnumerable<string> Split(string list) { string[] array = (list ?? "").Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { yield return text; } } } } internal enum Verdict { NotCovered, DayOnly, SpawnsByDayToo, NativeOnly, Narrowed, Disabled } internal static class SpawnSuppressor { private sealed class Original { internal Biome Biome; } private static readonly ConditionalWeakTable<SpawnData, Original> Originals = new ConditionalWeakTable<SpawnData, Original>(); private static readonly List<SpawnSystemList> PrefabLists = new List<SpawnSystemList>(); private static readonly FieldInfo InstancesField = AccessTools.Field(typeof(SpawnSystem), "m_instances"); internal static IReadOnlyList<SpawnSystemList> KnownPrefabLists => PrefabLists; internal static void OnWorldStart(ZoneSystem zoneSystem) { PrefabLists.Clear(); SpawnSystem val = (((Object)(object)zoneSystem.m_zoneCtrlPrefab != (Object)null) ? zoneSystem.m_zoneCtrlPrefab.GetComponent<SpawnSystem>() : null); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"The zone control prefab has no SpawnSystem; nothing to suppress."); } else { foreach (SpawnSystemList spawnList in val.m_spawnLists) { if ((Object)(object)spawnList != (Object)null) { PrefabLists.Add(spawnList); } } } Apply(); } internal static void OnZoneAwake(SpawnSystem spawnSystem) { if (!Plugin.Enabled.Value) { return; } Rules rules = null; foreach (SpawnSystemList spawnList in spawnSystem.m_spawnLists) { if (!((Object)(object)spawnList == (Object)null) && !PrefabLists.Contains(spawnList)) { rules = rules ?? Plugin.CurrentRules(); Suppress(spawnList.m_spawners, rules); } } } internal static void Apply() { int num = 0; int num2 = 0; foreach (List<SpawnData> item in ReachableLists()) { num += Restore(item); } if (Plugin.Enabled.Value) { Rules rules = Plugin.CurrentRules(); foreach (List<SpawnData> item2 in ReachableLists()) { num2 += Suppress(item2, rules); } } if (num > 0 || num2 > 0) { Plugin.Log.LogInfo((object)("Night spawns: " + num2 + " entr" + ((num2 == 1) ? "y" : "ies") + " suppressed away from home (" + num + " restored first).")); } } internal static Verdict Classify(SpawnData entry, Rules rules, out Biome kept) { //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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected I4, but got Unknown //IL_0061: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected I4, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Invalid comparison between I4 and Unknown Biome val = OriginalBiome(entry); kept = (Biome)(int)val; if ((Object)(object)entry.m_prefab == (Object)null || string.IsNullOrEmpty(entry.m_requiredGlobalKey) || !rules.IsBossKey(entry.m_requiredGlobalKey)) { return Verdict.NotCovered; } Rules.Creature creature = rules.Find(((Object)entry.m_prefab).name); if (creature == null) { return Verdict.NotCovered; } if (!entry.m_spawnAtNight) { return Verdict.DayOnly; } if (entry.m_spawnAtDay) { return Verdict.SpawnsByDayToo; } kept = (Biome)(val & creature.Native); if ((int)kept == (int)val) { return Verdict.NativeOnly; } if (kept) { return Verdict.Narrowed; } return Verdict.Disabled; } internal static Biome OriginalBiome(SpawnData entry) { //IL_0017: 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) if (!Originals.TryGetValue(entry, out var value)) { return entry.m_biome; } return value.Biome; } internal static bool IsEdited(SpawnData entry) { Original value; return Originals.TryGetValue(entry, out value); } private static int Suppress(List<SpawnData> entries, Rules rules) { //IL_0045: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (SpawnData entry in entries) { if (entry != null && entry.m_enabled && !IsEdited(entry)) { Biome kept; Verdict verdict = Classify(entry, rules, out kept); if (verdict == Verdict.Disabled || verdict == Verdict.Narrowed) { Originals.Add(entry, new Original { Biome = entry.m_biome }); entry.m_biome = kept; num++; } } } return num; } private static int Restore(List<SpawnData> entries) { //IL_0027: 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) int num = 0; foreach (SpawnData entry in entries) { if (entry != null && Originals.TryGetValue(entry, out var value)) { entry.m_biome = value.Biome; Originals.Remove(entry); num++; } } return num; } internal static List<List<SpawnData>> ReachableLists() { List<List<SpawnData>> lists = new List<List<SpawnData>>(); foreach (SpawnSystemList prefabList in PrefabLists) { if ((Object)(object)prefabList != (Object)null) { Add(prefabList.m_spawners); } } foreach (AltBiome altBiome in AltBiomeList.m_altBiomes) { if (altBiome != null) { Add(altBiome.m_spawn); } } foreach (SpawnSystem item in LiveSpawnSystems()) { if ((Object)(object)item == (Object)null) { continue; } foreach (SpawnSystemList spawnList in item.m_spawnLists) { if ((Object)(object)spawnList != (Object)null) { Add(spawnList.m_spawners); } } } return lists; void Add(List<SpawnData> entries) { if (entries != null && !lists.Contains(entries)) { lists.Add(entries); } } } internal static List<SpawnSystem> LiveSpawnSystems() { return (InstancesField?.GetValue(null) as List<SpawnSystem>) ?? new List<SpawnSystem>(); } } }