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;
}
}