namespace Aeshnidae.Expedition; /// /// The Old Ring of Tenkarrdun: the shared Aerlinthe island's quest (design: the doc "The Old /// Ring of Tenkarrdun", Tom 2026-09-27). This mod holds the island's state and runs its acts; /// the island itself is InstancesNoDat's shared region copy "aerlinthe", reached through /// OverworldCopies' portal. Act 1 (Ashfall) built 2026-09-28: zone meters, /expedition, thinning /// and settlers' camps. Acts 2-4 and the payout come next, one at a time. /// public class Mod : IHarmonyMod { public static readonly string Name = typeof(Mod).Assembly.GetName().Name!; public static readonly string HarmonyId = $"mod.{Name.ToLowerInvariant()}"; public static readonly string ModPath = Path.Combine(ModManager.ModPath, Name); public static ModContainer? Container => ModManager.GetModContainerByPath(ModPath); public static Settings Settings { get; private set; } = new(); private static Harmony? _harmony; private bool _disposed; public void Initialize() { try { Settings = Settings.Load(ModPath); Zones.Build(); Expedition.Load(); Expedition.RefreshFlags(); Island.Refresh(); // Generators already standing in the open island landblocks get the island's density // now; new ones get it as they are added (Density, Patches.PostAddWorldObject). WorldManager.EnqueueAction(new ActionEventDelegate(() => { var n = Density.ApplyToOpen(); if (n > 0) ModManager.Log($"[{Name}] density x{Settings.SpawnMultiplier}: {n} open generator(s) brought to it"); })); _harmony = new Harmony(HarmonyId); // Explicit assembly: the parameterless overload walks the stack and can land on ACE.Server. _harmony.PatchAllUncategorized(typeof(Mod).Assembly); ModManager.Log($"[{Name}] loaded - {(Settings.Enabled ? "ON" : "off")}: {Expedition.LoadStatus}; {Zones.All.Count} zone(s), {Settings.Camps?.Count ?? 0} camp object(s); island {Island.Status}"); } catch (Exception ex) { ModManager.Log($"[{Name}] failed to start: {ex}", ModManager.LogLevel.Error); } } /// Re-reads Settings.json: zones, camps, numbers. The cycle's state is untouched. public static void ReloadSettings() { Settings = Settings.Load(ModPath); Zones.Build(); Island.ReloadLandblocks(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) { try { Expedition.Flush(); } catch (Exception ex) { ModManager.Log($"[{Name}] final save failed: {ex.Message}", ModManager.LogLevel.Warn); } _harmony?.UnpatchAll(HarmonyId); _harmony = null; // With the persist patch gone, InstancesNoDat's Keep would save a standing camp into // the database; take them down on the world thread (a later load adopts or respawns). try { WorldManager.EnqueueAction(new ActionEventDelegate(Camps.RemoveAll)); } catch { /* shutting down */ } // A siege running when the mod unloads ends with nothing burned; its invaders go too. try { WorldManager.EnqueueAction(new ActionEventDelegate(Siege.Shutdown)); } catch { /* shutting down */ } ModManager.Log($"[{Name}] shut down"); } _disposed = true; } }