VTank's own Meta tab (docs/research/vtank-kb/08-ui-views.md §1 "Tab: Meta")
is only 5 controls: the lstMetaRules grid, cmdMetaCreate ("Create"), a bold
"Current State:" caption, and a SETTABLE cmbMetaCurrentState choice — no
profile toolbar, no "Enable Meta" checkbox, no inline editor at all.
- Removed from the Meta tab entirely: the profile menu/name-draft field/
New/CopyTo/Clear/Delete row (Profiles already carries the Meta combo/
CopyTo/Delete) and the "Enable Meta" toggle (already on Options) — same
accepted-regression shape as fix round A's Macro/Nav CopyTo-name-field
loss (no Profiles-tab equivalent exists for these, and VTank's own tab
has none either).
- Moved the inline State/Condition/Action editor (fields, condition/action
menus, numeric steppers, Apply/Remove/MoveUp/MoveDown) into a new popup,
mosstank-metaeditor.xml, registered the same StartVisible=true/
ShowInSidePanel=false way as the buff picker. Opened by a grid text-cell
click (SelectMetaRule, still populating the draft via SelectMetaRuleCore)
or the tab's own "Create" button (CreateMetaRule — new, distinct from the
still-existing AddMetaRule the tests call directly); Apply and Cancel
(HideMetaEditor) both close it. DeleteMetaRuleAt/MoveMetaRuleUpAt/
MoveMetaRuleDownAt call SelectMetaRuleCore directly and do NOT open the
popup.
- "Add" -> "Create": CreateMetaRule adds a default rule (delegating to the
existing AddMetaRuleCore) and opens the editor so it isn't left silently
default-valued.
- Added the settable current-state menu: MetaCurrentStateNames/
SelectedMetaCurrentState/SetMetaCurrentState expose MetaEngine's own
already-public States/Transition(string) — choosing a state here forces
the live engine into it, matching VTank's own manual override.
- The grid returns to VTank's full-width 856x116 proportion (848x116 here)
now nothing else shares the tab.
- Bold text isn't representable in the plain retail UI font (0x40000000 has
no bold face); "Current State:" uses the same bright caption color other
tab headers use instead — documented in mosstank.xml's own comment, not
silently dropped.
New tests: MetaEditorPopupOpensOnCellClickOrCreateAndClosesOnApplyOrCancel,
MetaCurrentStateMenuForcesTheLiveEngineIntoTheChosenState. Both mutation-
checked: commenting out SelectMetaRule's `_metaEditorVisible = true` turned
the first red ("Expected: True, Actual: False"); commenting out
SetMetaCurrentState's `_meta.Transition(value)` turned the second red
("Expected: Hunt, Actual: Default"). Restoring both turns them green.
EveryInteractiveControlDeclaresARealHandlerBinding's pinned control count:
186 -> 166 (-7 controls removed for good, -14 moved into the new popup file
this scan doesn't cover, +1 the new current-state menu).
SecondaryPopupPanelsFitTheirOwnBoundsAndEveryBindingResolves gained
mosstank-metaeditor.xml (630x236... — 630x160, corrected below).
tests/AcDream.Plugins.MossTank.Tests: 665/665 (was 663/663, +2 new tests).
tests/AcDream.App.Tests --filter Markup|Plugin|UiMenu|Slider: 276/3 skipped/279 (unchanged).
Screenshot with at least two rules (item 17) is owed with the round's other
live captures.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
152 lines
6.5 KiB
C#
152 lines
6.5 KiB
C#
using AcDream.Plugin.Abstractions;
|
|
|
|
namespace AcDream.Plugins.MossTank;
|
|
|
|
/// <summary>
|
|
/// MossTank — a self-buffing plugin, and the first consumer of acdream's
|
|
/// plugin automation surface.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Named for the mosswart, and for the Virindi Tank lineage this milestone is
|
|
/// modelled on. The buff policy lives here rather than in the host on purpose:
|
|
/// the host publishes spell data and a cast primitive, the plugin decides what
|
|
/// to cast. See <c>docs/research/2026-07-29-vtank-plugin-automation-requirements.md</c>.
|
|
/// </remarks>
|
|
public sealed class MossTankPlugin : IAcDreamPlugin
|
|
{
|
|
private IPluginHost? _host;
|
|
private MossTankPanel? _panel;
|
|
private Action<double>? _tick;
|
|
private IDisposable? _commandRegistration;
|
|
|
|
public void Initialize(IPluginHost host)
|
|
{
|
|
_host = host;
|
|
_panel = new MossTankPanel(host);
|
|
host.Log.Info("MossTank initialized");
|
|
}
|
|
|
|
public void Enable()
|
|
{
|
|
if (_host is null || _panel is null)
|
|
return;
|
|
|
|
// Markup ships beside the plugin assembly, so it is found relative to
|
|
// this DLL rather than the host's working directory -- plugins are
|
|
// loaded from their own directory and the two are not the same.
|
|
string directory =
|
|
Path.GetDirectoryName(typeof(MossTankPlugin).Assembly.Location) ?? ".";
|
|
|
|
_host.Ui.AddPanel(
|
|
new PluginPanelDescriptor("main", "MossTank")
|
|
{
|
|
IconText = "MT",
|
|
// A real installed portal.dat RenderSurface — see
|
|
// MossTankIconInstalledDatTests for the DAT-presence proof.
|
|
// IconText remains the fallback if this id is ever absent
|
|
// from an install.
|
|
IconSurfaceId = 0x06002C41u,
|
|
StartVisible = true,
|
|
ShowInSidePanel = true,
|
|
},
|
|
Path.Combine(directory, "mosstank.xml"),
|
|
_panel);
|
|
|
|
// Fix round A (2026-09-07): Advanced Options / Loot Editor were
|
|
// in-panel groups sharing the main window (forcing it to 350px
|
|
// tall with dead space under the nine normal tabs); they are now
|
|
// their own plugin panels, matching VTank's own separate popup
|
|
// windows (docs/research/vtank-kb/08-ui-views.md §1's secondary-
|
|
// view table). ShowInSidePanel=false — VTank's popups have no
|
|
// independent shelf/taskbar entry, they only exist while opened
|
|
// from the Options/Profiles tab checkbox
|
|
// (AdvancedOptionsVisible/LootEditorVisible). Each popup's own
|
|
// <panel visible="{...}"> binding is the SAME flag the checkbox
|
|
// flips and the popup's own "Back" button clears, so closing the
|
|
// popup unchecks the box for free — no new IUiRegistry show/hide
|
|
// API needed.
|
|
//
|
|
// StartVisible=true (NOT false) here — confirmed against a live
|
|
// build after StartVisible=false left both popups permanently
|
|
// invisible despite AdvancedOptionsVisible/LootEditorVisible
|
|
// reading true. RetailUiRuntime.MountPlugins wraps every plugin
|
|
// window's markup-level visible={Prop} ("availability") in a
|
|
// PluginWindowVisibilityController that ANDs it with a SEPARATE
|
|
// "requested visible" axis seeded from StartVisible and only ever
|
|
// flipped back to true by OnShown() (the shelf's un-minimize
|
|
// click). A ShowInSidePanel=false window has no shelf entry to
|
|
// click, so StartVisible=false would leave "requested visible"
|
|
// permanently false and availability's AND can never rescue it.
|
|
// StartVisible=true keeps "requested visible" true from the start
|
|
// (and PluginWindowVisibilityController.OnHidden only ever latches
|
|
// it back to false on a genuine minimize — it explicitly no-ops
|
|
// when hidden because availability itself went false, which is
|
|
// exactly what closing via "Back" does), leaving availability
|
|
// (AdvancedOptionsVisible/LootEditorVisible) as the sole effective
|
|
// gate, same as the main panel's own always-true
|
|
// ShowInSidePanel=true default.
|
|
_host.Ui.AddPanel(
|
|
new PluginPanelDescriptor("advanced-options", "MossTank Advanced Options")
|
|
{
|
|
StartVisible = true,
|
|
ShowInSidePanel = false,
|
|
},
|
|
Path.Combine(directory, "mosstank-advanced.xml"),
|
|
_panel);
|
|
_host.Ui.AddPanel(
|
|
new PluginPanelDescriptor("loot-editor", "MossTank Loot Editor")
|
|
{
|
|
StartVisible = true,
|
|
ShowInSidePanel = false,
|
|
},
|
|
Path.Combine(directory, "mosstank-loot-editor.xml"),
|
|
_panel);
|
|
// Campaign VT S7.4: the Buffs tab's "Add..." picker (VTank's own
|
|
// SelfBuffChoiceView), same StartVisible=true/ShowInSidePanel=false
|
|
// popup pattern as the two panels above — see their own comments
|
|
// for why StartVisible must be true.
|
|
_host.Ui.AddPanel(
|
|
new PluginPanelDescriptor("buff-picker", "MossTank Add Buff")
|
|
{
|
|
StartVisible = true,
|
|
ShowInSidePanel = false,
|
|
},
|
|
Path.Combine(directory, "mosstank-buffpicker.xml"),
|
|
_panel);
|
|
// Fix round B item 5: the Meta tab's inline rule editor moved to its
|
|
// own popup, same StartVisible=true/ShowInSidePanel=false pattern
|
|
// as the three panels above.
|
|
_host.Ui.AddPanel(
|
|
new PluginPanelDescriptor("meta-editor", "MossTank Meta Rule Editor")
|
|
{
|
|
StartVisible = true,
|
|
ShowInSidePanel = false,
|
|
},
|
|
Path.Combine(directory, "mosstank-metaeditor.xml"),
|
|
_panel);
|
|
|
|
_commandRegistration = _host.Commands.Register(
|
|
"vt",
|
|
_panel.ExecuteVtankCommand);
|
|
|
|
_tick = _panel.OnTick;
|
|
_host.Events.Tick += _tick;
|
|
|
|
_host.Log.Info(
|
|
_host.Automation.IsAvailable
|
|
? "MossTank enabled"
|
|
: "MossTank enabled (no live session yet; the Buff button will "
|
|
+ "report 'Not in world' until one is up)");
|
|
}
|
|
|
|
public void Disable()
|
|
{
|
|
if (_host is not null && _tick is not null)
|
|
_host.Events.Tick -= _tick;
|
|
_commandRegistration?.Dispose();
|
|
_commandRegistration = null;
|
|
_tick = null;
|
|
_panel?.Disable();
|
|
_host?.Log.Info("MossTank disabled");
|
|
}
|
|
}
|