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 Ashlands Fire Particle Fix v1.1.1
BepInEx/plugins/AshlandsFireParticleFix/AshlandsFireGuard.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: InternalsVisibleTo("NativeGuardProbe")] [assembly: AssemblyVersion("1.1.1.0")] [BepInPlugin("local.sadge.ashlandsfireguard", "Ashlands Fire & Particle Fix", "1.1.1")] public sealed class AshlandsFireGuard : BaseUnityPlugin { private sealed class Entry { public ZDO Record; public ZDOID Id; public float Created; public long Sequence; public bool PendingDelete; } [HarmonyPatch(typeof(ZDO), "SetPrefab")] private static class PrefabPatch { private static void Postfix(ZDO __instance) { Track(__instance); } } [HarmonyPatch(typeof(ZDO), "Deserialize")] private static class ReceivePatch { private static void Postfix(ZDO __instance) { Track(__instance); } } [HarmonyPatch(typeof(ZDOMan), "LoadChunks")] private static class LoadPatch { private static void Postfix(ZDOMan __instance, Dictionary<ZDOID, ZDO> ___m_objectsByID) { tracked.Clear(); SweepCount = 0; sequence = 0L; if (!ScopeAllowsServer()) { return; } foreach (ZDO value in ___m_objectsByID.Values) { if (value.GetPrefab() == 1730843282 || value.GetPrefab() == -837447586) { Track(value); } } log.LogInfo((object)("Saved Ashlands wildfires tracked: " + tracked.Count)); if (current.startupCleanup.Value) { Check(__instance); } current.Schedule(); } } public const string PluginGuid = "local.sadge.ashlandsfireguard"; internal const int HouseFireHash = 1730843282; internal const int FireHash = -837447586; internal static int SweepCount; private static AshlandsFireGuard current; private static ManualLogSource log; private Harmony patches; private ConfigEntry<bool> guardEnabled; private ConfigEntry<int> interval; private ConfigEntry<int> perSector; private ConfigEntry<int> total; private ConfigEntry<int> lifetime; private ConfigEntry<bool> deduplicate; private ConfigEntry<int> cellSize; private ConfigEntry<bool> startupCleanup; private ConfigEntry<bool> logSummary; private HashSet<string> allowedWorlds; private static long sequence; private static readonly Dictionary<ZDOID, Entry> tracked = new Dictionary<ZDOID, Entry>(); private void Awake() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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 //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Expected O, but got Unknown current = this; log = ((BaseUnityPlugin)this).Logger; guardEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable the server-side wildfire guard. Restart the host after changing settings."); interval = ((BaseUnityPlugin)this).Config.Bind<int>("Cleanup", "CheckIntervalSeconds", 60, new ConfigDescription("Seconds between cleanup passes. Counts can exceed limits between passes.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 3600), new object[0])); perSector = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "MaxFiresPerSector", 8, new ConfigDescription("Maximum retained Fire/HouseFire objects per 64x64m sector at each pass.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10000), new object[0])); total = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "MaxFiresInAshlands", 128, new ConfigDescription("Maximum retained Fire/HouseFire objects across the entire Ashlands biome at each pass.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100000), new object[0])); lifetime = ((BaseUnityPlugin)this).Config.Bind<int>("Cleanup", "MaxLifetimeSeconds", 60, new ConfigDescription("Remove tracked fires at or beyond this age. Zero disables age-based removal. Actual removal may wait one cleanup interval; age resets on world load.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 86400), new object[0])); deduplicate = ((BaseUnityPlugin)this).Config.Bind<bool>("Limits", "SuppressOverlappingFires", true, "Retain at most one wildfire in each spatial cell."); cellSize = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "CellSizeMeters", 2, new ConfigDescription("Width, height and depth of the deduplication cells.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 16), new object[0])); startupCleanup = ((BaseUnityPlugin)this).Config.Bind<bool>("Cleanup", "CleanupOnWorldLoad", true, "Run a quota/overlap pass once after loading the saved world. Saved fires start with age zero; the lifetime rule still waits for the configured age."); logSummary = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogCleanupSummary", true, "Log one aggregate line when a pass removes fires."); string value = ((BaseUnityPlugin)this).Config.Bind<string>("General", "AllowedWorldNames", "", "Optional comma-separated world names, case-sensitive. Empty means all worlds. Restart the host after changing this setting.").Value; allowedWorlds = new HashSet<string>(StringComparer.Ordinal); string[] array = value.Split(new char[1] { ',' }); foreach (string text in array) { if (!string.IsNullOrWhiteSpace(text)) { allowedWorlds.Add(text.Trim()); } } patches = new Harmony("local.sadge.ashlandsfireguard"); patches.PatchAll(typeof(AshlandsFireGuard).Assembly); Schedule(); ((BaseUnityPlugin)this).Logger.LogInfo((object)(guardEnabled.Value ? ("Wildfire guard ready: Ashlands only; cleanup interval " + interval.Value + "s; limits " + perSector.Value + "/sector and " + total.Value + "/biome; age threshold " + lifetime.Value + "s.") : "Wildfire guard disabled by configuration.")); } private void Schedule() { ((MonoBehaviour)this).CancelInvoke("PeriodicCheck"); if (guardEnabled.Value) { ((MonoBehaviour)this).InvokeRepeating("PeriodicCheck", (float)interval.Value, (float)interval.Value); } } private void OnDestroy() { ((MonoBehaviour)this).CancelInvoke("PeriodicCheck"); if (patches != null) { patches.UnpatchSelf(); } tracked.Clear(); if (object.ReferenceEquals(current, this)) { current = null; } } private static bool ScopeAllowsServer() { if ((Object)(object)current == (Object)null || !current.guardEnabled.Value) { return false; } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer()) { return false; } if (current.allowedWorlds.Count != 0) { if (instance.GetWorld() != null) { return current.allowedWorlds.Contains(instance.GetWorldName()); } return false; } return true; } internal static bool IsTarget(int prefab, Vector3 position) { //IL_0074: 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_007c: Invalid comparison between Unknown and I4 if (prefab != 1730843282 && prefab != -837447586) { return false; } if (float.IsNaN(position.x) || float.IsNaN(position.y) || float.IsNaN(position.z) || float.IsInfinity(position.x) || float.IsInfinity(position.y) || float.IsInfinity(position.z)) { return false; } if (WorldGenerator.instance != null) { return (int)WorldGenerator.instance.GetBiome(position) == 32; } return false; } internal static void Track(ZDO record) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (record != null) { int prefab = record.GetPrefab(); if ((prefab == 1730843282 || prefab == -837447586) && ScopeAllowsServer() && IsTarget(prefab, record.GetPosition()) && (!tracked.TryGetValue(record.m_uid, out var value) || !object.ReferenceEquals(value.Record, record))) { tracked[record.m_uid] = new Entry { Record = record, Id = record.m_uid, Created = Time.realtimeSinceStartup, Sequence = ++sequence }; } } } internal static void Check(ZDOMan manager) { //IL_0054: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_0156: Unknown result type (might be due to invalid IL or missing references) if (tracked.Count == 0 || !ScopeAllowsServer()) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; SweepCount++; List<Entry> list = new List<Entry>(); List<ZDOID> list2 = new List<ZDOID>(); foreach (KeyValuePair<ZDOID, Entry> item2 in tracked) { Entry value = item2.Value; if (!object.ReferenceEquals(manager.GetZDO(value.Id), value.Record) || !IsTarget(value.Record.GetPrefab(), value.Record.GetPosition())) { list2.Add(item2.Key); } else if (!value.PendingDelete) { list.Add(value); } } foreach (ZDOID item3 in list2) { tracked.Remove(item3); } list.Sort((Entry a, Entry b) => b.Sequence.CompareTo(a.Sequence)); Dictionary<string, int> dictionary = new Dictionary<string, int>(); HashSet<string> hashSet = new HashSet<string>(); int num = 0; int num2 = 0; foreach (Entry item4 in list) { Vector3 position = item4.Record.GetPosition(); string key2 = Math.Floor((position.x + 32f) / 64f) + ":" + Math.Floor((position.z + 32f) / 64f); string item = Math.Floor(position.x / (float)current.cellSize.Value) + ":" + Math.Floor(position.y / (float)current.cellSize.Value) + ":" + Math.Floor(position.z / (float)current.cellSize.Value); dictionary.TryGetValue(key2, out var value2); bool flag = current.lifetime.Value > 0 && realtimeSinceStartup - item4.Created >= (float)current.lifetime.Value; bool flag2 = current.deduplicate.Value && hashSet.Contains(item); if (flag || num >= current.total.Value || value2 >= current.perSector.Value || flag2) { item4.Record.SetOwner(ZDOMan.GetSessionID()); manager.DestroyZDO(item4.Record); item4.PendingDelete = true; num2++; } else { num++; dictionary[key2] = value2 + 1; hashSet.Add(item); } } if (num2 > 0 && current.logSummary.Value) { log.LogInfo((object)("Ashlands wildfire cleanup: removed " + num2 + "; retained " + num + ".")); } } private void PeriodicCheck() { if (tracked.Count != 0) { ZDOMan instance = ZDOMan.instance; if (instance != null) { Check(instance); } } } }