using AcDream.Plugin.Abstractions; using OpenAC.MosswartMassacre.Quests; namespace OpenAC.MosswartMassacre.FlagTracker; /// /// The "Mossy Tracker" window, opened from the main window's Mossy Tracker /// tab: augmentations, luminance auras, recalls, /// cantrips, tracked weapons and quest timers for the character in the world. /// Nothing here reaches the backend. /// /// /// The window exists only on a host that draws one; on a headless host this /// feature registers nothing and does nothing. The pages are read at login /// and whenever the player presses a page's Refresh button, as the original /// read them when its window opened and on Refresh; the quest page follows /// the quest list and redraws its countdowns every five seconds. /// internal sealed class FlagTrackerFeature : IMmFeature { /// The panel's markup file, beside the plugin assembly. public const string MarkupFile = "mosswartmassacre-flagtracker.xml"; /// How often the quest countdowns are redrawn. public static readonly TimeSpan QuestRedrawInterval = TimeSpan.FromSeconds(5); private readonly MmContext _context; private readonly QuestManager _quests; private readonly FlagTrackerData _data; private readonly IDisposable? _panel; private readonly Action? _onQuestsChanged; private IDisposable? _questRedraw; public FlagTrackerFeature(MmContext context, QuestManager quests) { _context = context; _quests = quests; _data = new FlagTrackerData(context.Automation); if (!context.Host.HasUi) return; Panel = new FlagTrackerViewModel(); Panel.RefreshRequested += OnRefreshRequested; _onQuestsChanged = ShowQuests; _quests.QuestsChanged += _onQuestsChanged; string directory = Path.GetDirectoryName(typeof(FlagTrackerFeature).Assembly.Location) ?? "."; _panel = context.Host.Ui.RegisterPanel( new PluginPanelDescriptor("flagtracker", "Mossy Tracker") { // Shown while the binding's IsVisible is set; the host's own // shown state starts true so that flag alone opens it. StartVisible = true, // No bar button: as in the original, the main window's // Mossy Tracker tab opens it. ShowInSidePanel = false, }, Path.Combine(directory, MarkupFile), Panel); } /// /// The window's binding object; set its IsVisible to open the /// window. Null on a host without a window. /// public FlagTrackerViewModel? Panel { get; } internal FlagTrackerData Data => _data; public void OnLogin() { if (Panel is null) return; RefreshAll(); _questRedraw?.Dispose(); _questRedraw = _context.Scheduler.Every(QuestRedrawInterval, ShowQuests); } public void OnLogoff() { _questRedraw?.Dispose(); _questRedraw = null; Panel?.Clear(); } public void Dispose() { OnLogoff(); if (_onQuestsChanged is not null) _quests.QuestsChanged -= _onQuestsChanged; if (Panel is not null) Panel.RefreshRequested -= OnRefreshRequested; _panel?.Dispose(); } /// Reads every page again and redraws it. public void RefreshAll() { if (Panel is null) return; try { _data.RefreshAll(); } catch (Exception ex) { _context.Chat.Write($"[MossyTracker] Data refresh failed: {ex.Message}"); } Panel.ShowData(_data); ShowQuests(); } private void ShowQuests() { if (Panel is null || !_context.IsLoggedIn) return; Panel.ShowQuestRows(_quests.QuestList, _quests.UnixNow); } private void OnRefreshRequested(string button) { if (Panel is null || !_context.IsLoggedIn) return; try { switch (button) { case nameof(FlagTrackerViewModel.RefreshAugs): _data.RefreshAugmentations(); Panel.ShowAugmentations(_data); break; case nameof(FlagTrackerViewModel.RefreshLum): _data.RefreshLuminanceAuras(); Panel.ShowLuminance(_data); break; case nameof(FlagTrackerViewModel.RefreshRecalls): _data.RefreshRecallSpells(); Panel.ShowRecallSpells(_data); break; case nameof(FlagTrackerViewModel.RefreshCantrips): _data.RefreshCantrips(); Panel.ShowCantripRows(_data); break; case nameof(FlagTrackerViewModel.RefreshWeapons): _data.RefreshWeapons(); Panel.ShowWeaponRows(_data); break; case nameof(FlagTrackerViewModel.RefreshQuests): _quests.RefreshQuests(); ShowQuests(); break; } } catch (Exception ex) { _context.Chat.Write($"[MossyTracker] Refresh failed: {ex.Message}"); } } }