namespace Aeshnidae.Fellowship; /// /// Fellowship size and experience sharing as settings rather than constants. /// /// Size needs no patch - ACE keeps MaxFellows in a public static field. Sharing does, /// because ACE's table is a switch that stops at 9 and falls through to a full share, /// so the two have to move together. See Settings. /// 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 Settings Settings { get; private set; } = new(); /// ACE's own value, kept so unloading puts it back. private static int _originalMaxFellows; private static Harmony? _harmony; private bool _disposed; public void Initialize() { Settings = Settings.Load(ModPath); if (Settings.EnsureSharePercentages()) Settings.Save(ModPath); _originalMaxFellows = AceFellowship.MaxFellows; Apply(); _harmony = new Harmony(HarmonyId); // Explicit assembly: the parameterless overload walks the stack, and an // inlined Initialize() makes it resolve to ACE.Server and patch nothing. _harmony.PatchAllUncategorized(typeof(Mod).Assembly); ModManager.Log($"[{Name}] fellowships up to {AceFellowship.MaxFellows} " + $"(retail {_originalMaxFellows}), share at that size " + $"{Settings.ShareFor(AceFellowship.MaxFellows):P0} each"); } /// Pushes the configured size into ACE. Safe to call again after a reload. public static void Apply() { if (!Settings.Enabled) { AceFellowship.MaxFellows = _originalMaxFellows; return; } if (Settings.MaxFellows < 1) { ModManager.Log($"[{Name}] MaxFellows of {Settings.MaxFellows} makes no sense; " + $"leaving it at {_originalMaxFellows}", ModManager.LogLevel.Warn); return; } AceFellowship.MaxFellows = Settings.MaxFellows; // A size with no share entry would fall to the floor, which is legal but almost // certainly not intended - say so rather than letting it surprise someone. for (var count = 1; count <= Settings.MaxFellows; count++) { if (!Settings.SharePercentages.ContainsKey(count)) { ModManager.Log($"[{Name}] no share configured for {count} member(s); " + $"they will get the {Settings.ShareBeyondTable:P0} floor", ModManager.LogLevel.Warn); } } } /// Re-reads Settings.json and re-applies it, for /fellow reload. public static void Reload() { Settings = Settings.Load(ModPath); Settings.EnsureSharePercentages(); Apply(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) { // Put ACE's constant back; the field is global and outlives this mod. if (_originalMaxFellows > 0) AceFellowship.MaxFellows = _originalMaxFellows; _harmony?.UnpatchAll(HarmonyId); _harmony = null; ModManager.Log($"[{Name}] shut down, fellowship size back to {_originalMaxFellows}"); } _disposed = true; } }