fix(vtank): slice 7 fix round C item D2 — /mt refresh now re-syncs the Monsters grid
EnsureDefaultMonsterRule() is a _combatSettings.Rules mutator (it appends a DEFAULT row when the list is empty), but the /mt refresh command handler never called RefreshMonsterEditor() afterward, unlike every other Rules mutator in the plugin (AddMonsterRuleCore, DeleteMonsterRuleAtCore, MoveMonsterRuleAtCore, UpdateMonsterActionsAt, the constructor, and ResetProfileConsumers's own EnsureDefaultMonsterRule call). Audited every _combatSettings.Rules mutation site in the plugin (grep for "_combatSettings.Rules" across all of src/AcDream.Plugins.MossTank): AddMonsterRuleCore, DeleteMonsterRuleAtCore, MoveMonsterRuleAtCore, and UpdateMonsterActionsAt already call RefreshMonsterEditor right after mutating; the constructor and ResetProfileConsumers already pair their own EnsureDefaultMonsterRule call with one. The /mt refresh handler was the only gap. Mutation named: since Rules can never actually be observed empty through the panel's own public surface (delete refuses removing DEFAULT, and every profile-load path already re-adds it via ResetProfileConsumers before this handler could see it), the new pin reaches the private CombatSettings instance via reflection to clear Rules directly, and also pokes the cached _monsterNameColumn field to a "STALE" sentinel first — otherwise EnsureDefaultMonsterRule() re-adding "DEFAULT" would coincide with the grid's already-cached construction-time value and the test would pass even with the fix missing. Confirmed it fails (shows "STALE" instead of "DEFAULT") with the RefreshMonsterEditor() call removed, before restoring the fix. MossTank suite 678 -> 679 (one new pin). Full solution build green; App markup/plugin filter 203/203. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
23d4376cc3
commit
f15667db5f
2 changed files with 53 additions and 0 deletions
|
|
@ -172,7 +172,19 @@ internal sealed partial class MossTankPanel
|
|||
WriteVtank($"Portal space toggle count: {_commandPortalCount}");
|
||||
return;
|
||||
case "refresh":
|
||||
// Fix round C item D2: EnsureDefaultMonsterRule() mutates
|
||||
// _combatSettings.Rules (adds the DEFAULT row when the list
|
||||
// is empty) but this handler never re-materialized the
|
||||
// Monsters grid's cached columns afterward — every OTHER
|
||||
// _combatSettings.Rules mutator (AddMonsterRuleCore,
|
||||
// DeleteMonsterRuleAtCore, MoveMonsterRuleAtCore,
|
||||
// UpdateMonsterActionsAt) already calls RefreshMonsterEditor
|
||||
// right after mutating, as do the constructor and
|
||||
// ResetProfileConsumers's own EnsureDefaultMonsterRule call
|
||||
// — this was the one remaining gap found by auditing every
|
||||
// _combatSettings.Rules mutation site in the plugin.
|
||||
EnsureDefaultMonsterRule();
|
||||
RefreshMonsterEditor();
|
||||
RefreshItemEditors();
|
||||
RefreshLootEditor();
|
||||
RefreshRouteEditor();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Reflection;
|
||||
using AcDream.Plugin.Abstractions;
|
||||
|
||||
namespace AcDream.Plugins.MossTank.Tests;
|
||||
|
|
@ -2126,6 +2127,46 @@ public sealed class MossTankPanelTests
|
|||
Assert.Equal(["DEFAULT", "mosswart"], panel.MonsterNameColumn);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VtankRefreshCommandRepopulatesTheMonstersGridAfterCreatingTheDefaultRule()
|
||||
{
|
||||
// Fix round C item D2: /mt refresh calls EnsureDefaultMonsterRule
|
||||
// (a _combatSettings.Rules mutator) but used to skip
|
||||
// RefreshMonsterEditor afterward — every OTHER Rules mutator in the
|
||||
// panel (AddMonsterRuleCore, DeleteMonsterRuleAtCore,
|
||||
// MoveMonsterRuleAtCore, UpdateMonsterActionsAt, the constructor,
|
||||
// and ResetProfileConsumers's own EnsureDefaultMonsterRule call)
|
||||
// already refreshes the grid right after mutating; this command
|
||||
// handler was the one gap found by auditing every
|
||||
// _combatSettings.Rules mutation site. Rules can never actually go
|
||||
// empty through the panel's own public surface (delete refuses
|
||||
// removing DEFAULT, and every profile-load path re-adds it via
|
||||
// ResetProfileConsumers before this handler could ever observe it
|
||||
// empty) — so this reaches the private CombatSettings instance
|
||||
// directly to reproduce the corrupted/emptied-list precondition
|
||||
// the command's own defensive EnsureDefaultMonsterRule() call
|
||||
// exists to recover from. The cached _monsterNameColumn field is
|
||||
// also poked to a sentinel value first: EnsureDefaultMonsterRule
|
||||
// re-adding "DEFAULT" happens to reproduce the SAME content the
|
||||
// grid already had from construction, so without also corrupting
|
||||
// the cache this test would pass even with the refresh call
|
||||
// missing (the stale cache and the freshly recomputed one would
|
||||
// coincidentally agree).
|
||||
var panel = new MossTankPanel(new FakeHost(new FakeAutomation()));
|
||||
Type panelType = typeof(MossTankPanel);
|
||||
var combatSettings = (CombatSettings)panelType
|
||||
.GetField("_combatSettings", BindingFlags.Instance | BindingFlags.NonPublic)!
|
||||
.GetValue(panel)!;
|
||||
combatSettings.Rules.Clear();
|
||||
FieldInfo monsterNameColumnField = panelType
|
||||
.GetField("_monsterNameColumn", BindingFlags.Instance | BindingFlags.NonPublic)!;
|
||||
monsterNameColumnField.SetValue(panel, new[] { "STALE" });
|
||||
|
||||
panel.ExecuteVtankCommand(new PluginCommand("vt", "refresh", "/vt refresh"));
|
||||
|
||||
Assert.Equal(["DEFAULT"], panel.MonsterNameColumn);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MoveMonsterRuleAtReordersButNeverDisplacesDefault()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue