fix(vt): round 3 item 12 — cleanup pass (stale refs, silent swallows, comments)
Five small fixes bundled per the round's cleanup item:
- VtankNavRouteSerializer.cs's doc comment cited a "WriteBinaryNavBlob"
method that no longer exists anywhere in the codebase (MetaEngine's
embedded-navigation contract moved to the typed MetaAction.EmbeddedRoute
NavigationSettings, saved/loaded through MetafSerializer.SaveNav/
TryLoadNav, back at round 2 step B) — corrected to name the real
mechanism.
- MossTankCommands.cs:274's comment referenced an "exports/nav/" mirror
directory that stopped existing when route profiles cut over to writing
their real .af file directly (round 2 steps 2-3) — corrected.
- docs/research/vtank-kb/07-meta-and-expressions.md section 5.2 row 6
described the pre-cutover "MossTankMetaProfileStore.WriteLegacyExport
convenience mirror" design; .af is now the SOLE authoritative Meta
store, so a disabled rule's save refusal now blocks the profile itself
— the row now says a disabled rule makes the profile file genuinely
unsaveable, not that a mirror goes stale.
- The two bare `catch (FormatException) { }` blocks that silently dropped
a corrupt monster-rule expression (one in SideCarDocument.Apply, reached
from a corrupt side-car; one in LegacyCombatProfileDocument.Apply,
reached during legacy-JSON migration) now log a warning via the host's
IPluginLogger, threaded through as an optional parameter from every call
site.
- VtankDatabase.Render()'s table-sort doc comment now states explicitly
that StringComparer.Ordinal matching .NET Framework's SortedDictionary
default order is confirmed only for the plain-ASCII table names VTank
ships (AntiExtraBuffSpells, MyMonsters, Settings, …), not as a general
claim for any string — comment only, no behavior change.
Added CorruptSideCarMonsterRuleIsLoggedNotSilentlySwallowed (FakeLogger
now captures Warn() calls via a new FakeHost.Logger property) pinning the
swallow-to-log fix.
Mutation: reverted MossTankProfileStore.cs to HEAD (keeping only the new
test) and ran it — failed with an empty Warnings collection, confirming
the silent-swallow bug before the fix.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
55010f92c7
commit
f58e997b19
6 changed files with 95 additions and 24 deletions
|
|
@ -271,9 +271,13 @@ internal sealed partial class MossTankPanel
|
|||
// Item J (slice-1 fix round): .af is the only VTank-compatible
|
||||
// storage format now (Campaign VT slice 1 Part A); ".nav" is
|
||||
// stripped for legacy-typed names, ".af" for names copy-pasted
|
||||
// from the exports/nav/ directory or a real VTank profile folder —
|
||||
// without both, "/vt nav save Foo.af" would have produced a
|
||||
// doubled "Foo.af.af" export.
|
||||
// from a real .af file (the VtankProfiles directory, or an
|
||||
// imports/ drop-in for TryImportLegacy below) — without both,
|
||||
// "/vt nav save Foo.af" would have produced a doubled "Foo.af.af"
|
||||
// file. Round 3 item 12: this comment previously cited an
|
||||
// "exports/nav/" mirror directory that no longer exists — route
|
||||
// profiles have written directly to their real .af file since the
|
||||
// round 2 step 2-3 cutover, with no separate export copy.
|
||||
name = StripExtension(name, ".nav", ".af");
|
||||
if (operation == "save")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ internal sealed class MossTankProfileStore
|
|||
database = VtankDefaultSettingsDatabase.Parse();
|
||||
ApplyFromDatabase(database, settings);
|
||||
sidecar = SideCarDocument.CreateDefaults();
|
||||
sidecar.Apply(settings, noBuffItemNames);
|
||||
sidecar.Apply(settings, noBuffItemNames, _host.Log);
|
||||
}
|
||||
WriteUsdText(fileName, database.Render());
|
||||
WriteJson(SideCarKey(fileName), sidecar);
|
||||
|
|
@ -268,7 +268,7 @@ internal sealed class MossTankProfileStore
|
|||
// template/defaults rather than leaving the live settings alone.
|
||||
VtankDatabase fresh = VtankDefaultSettingsDatabase.Parse();
|
||||
ApplyFromDatabase(fresh, settings);
|
||||
SideCarDocument.CreateDefaults().Apply(settings, noBuffItemNames);
|
||||
SideCarDocument.CreateDefaults().Apply(settings, noBuffItemNames, _host.Log);
|
||||
_currentDatabase = fresh;
|
||||
_currentDatabaseFileName = fileName;
|
||||
return;
|
||||
|
|
@ -286,7 +286,7 @@ internal sealed class MossTankProfileStore
|
|||
_host.Log.Warn(RecoveryNotice);
|
||||
VtankDatabase fresh = VtankDefaultSettingsDatabase.Parse();
|
||||
ApplyFromDatabase(fresh, settings);
|
||||
SideCarDocument.CreateDefaults().Apply(settings, noBuffItemNames);
|
||||
SideCarDocument.CreateDefaults().Apply(settings, noBuffItemNames, _host.Log);
|
||||
_currentDatabase = fresh;
|
||||
_currentDatabaseFileName = fileName;
|
||||
return;
|
||||
|
|
@ -294,7 +294,7 @@ internal sealed class MossTankProfileStore
|
|||
_currentDatabase = database;
|
||||
_currentDatabaseFileName = fileName;
|
||||
(ReadJson<SideCarDocument>(SideCarKey(fileName)) ?? SideCarDocument.CreateDefaults())
|
||||
.Apply(settings, noBuffItemNames);
|
||||
.Apply(settings, noBuffItemNames, _host.Log);
|
||||
}
|
||||
|
||||
public void SaveCurrent(
|
||||
|
|
@ -319,7 +319,7 @@ internal sealed class MossTankProfileStore
|
|||
{
|
||||
VtankDatabase database = VtankDefaultSettingsDatabase.Parse();
|
||||
ApplyFromDatabase(database, settings);
|
||||
SideCarDocument.CreateDefaults().Apply(settings, noBuffItemNames);
|
||||
SideCarDocument.CreateDefaults().Apply(settings, noBuffItemNames, _host.Log);
|
||||
string fileName = CurrentFileName();
|
||||
WriteUsdText(fileName, database.Render());
|
||||
WriteJson(SideCarKey(fileName), SideCarDocument.CreateDefaults());
|
||||
|
|
@ -499,7 +499,8 @@ internal sealed class MossTankProfileStore
|
|||
};
|
||||
var noBuffItemNames = new HashSet<string>(StringComparer.Ordinal);
|
||||
legacy.Apply(
|
||||
settings.Combat, settings.Buffs, settings.Vitals, settings.Inventory, noBuffItemNames);
|
||||
settings.Combat, settings.Buffs, settings.Vitals, settings.Inventory,
|
||||
noBuffItemNames, _host.Log);
|
||||
VtankDatabase database = VtankSettingsProfileSerializer.CreateNew(settings);
|
||||
WriteUsdText(fileName, database.Render());
|
||||
WriteJson(SideCarKey(fileName), SideCarDocument.Capture(settings, noBuffItemNames));
|
||||
|
|
@ -563,7 +564,7 @@ internal sealed class MossTankProfileStore
|
|||
return;
|
||||
}
|
||||
|
||||
legacy.Apply(settings.Combat, settings.Buffs, settings.Vitals, settings.Inventory, noBuffItemNames);
|
||||
legacy.Apply(settings.Combat, settings.Buffs, settings.Vitals, settings.Inventory, noBuffItemNames, _host.Log);
|
||||
VtankDatabase database = VtankSettingsProfileSerializer.CreateNew(settings);
|
||||
WriteUsdText(fileName, database.Render());
|
||||
WriteJson(SideCarKey(fileName), SideCarDocument.Capture(settings, noBuffItemNames));
|
||||
|
|
@ -823,7 +824,8 @@ internal sealed class MossTankProfileStore
|
|||
|
||||
public void Apply(
|
||||
VtankSettingsProfileSerializer.AllSettings settings,
|
||||
ISet<string> noBuffItemNames)
|
||||
ISet<string> noBuffItemNames,
|
||||
IPluginLogger? logger = null)
|
||||
{
|
||||
Replace(settings.Combat.CombatItemNames, ItemNames);
|
||||
settings.Combat.CombatItemObjectIds.Clear();
|
||||
|
|
@ -851,7 +853,12 @@ internal sealed class MossTankProfileStore
|
|||
foreach (MonsterRuleDocument rule in CombatRules ?? [])
|
||||
{
|
||||
try { settings.Combat.Rules.Add(rule.ToRule()); }
|
||||
catch (FormatException) { }
|
||||
catch (FormatException error)
|
||||
{
|
||||
// Round 3 item 12: log rather than silently drop a
|
||||
// corrupt side-car monster rule.
|
||||
logger?.Warn($"MossTank could not restore a monster rule: {error.Message}");
|
||||
}
|
||||
}
|
||||
if (!settings.Combat.Rules.Any(static rule => rule.IsDefault))
|
||||
settings.Combat.Rules.Add(new MonsterRule("DEFAULT", 0));
|
||||
|
|
@ -1014,9 +1021,10 @@ internal sealed class MossTankProfileStore
|
|||
BuffSettings buffs,
|
||||
VitalSettings vitals,
|
||||
InventorySettings inventory,
|
||||
ISet<string> noBuffItemNames)
|
||||
ISet<string> noBuffItemNames,
|
||||
IPluginLogger? logger = null)
|
||||
{
|
||||
(Combat ?? LegacyCombatProfileDocument.Capture(new CombatSettings())).Apply(combat);
|
||||
(Combat ?? LegacyCombatProfileDocument.Capture(new CombatSettings())).Apply(combat, logger);
|
||||
(Buffs ?? LegacyBuffProfileDocument.Capture(new BuffSettings())).Apply(buffs);
|
||||
(Vitals ?? LegacyVitalProfileDocument.Capture(new VitalSettings())).Apply(vitals);
|
||||
(Inventory ?? LegacyInventoryProfileDocument.Capture(new InventorySettings())).Apply(inventory);
|
||||
|
|
@ -1237,7 +1245,7 @@ internal sealed class MossTankProfileStore
|
|||
Rules = value.Rules.Select(MonsterRuleDocument.From).ToArray(),
|
||||
};
|
||||
|
||||
public void Apply(CombatSettings value)
|
||||
public void Apply(CombatSettings value, IPluginLogger? logger = null)
|
||||
{
|
||||
value.Enabled = Enabled;
|
||||
value.MaximumRange = Math.Clamp(MaximumRange, 2f, 100f);
|
||||
|
|
@ -1282,7 +1290,12 @@ internal sealed class MossTankProfileStore
|
|||
foreach (MonsterRuleDocument rule in Rules ?? [])
|
||||
{
|
||||
try { value.Rules.Add(rule.ToRule()); }
|
||||
catch (FormatException) { }
|
||||
catch (FormatException error)
|
||||
{
|
||||
// Round 3 item 12: log rather than silently drop a
|
||||
// corrupt legacy-JSON monster rule during migration.
|
||||
logger?.Warn($"MossTank could not restore a legacy monster rule: {error.Message}");
|
||||
}
|
||||
}
|
||||
if (!value.Rules.Any(static rule => rule.IsDefault))
|
||||
value.Rules.Add(new MonsterRule("DEFAULT", 0));
|
||||
|
|
|
|||
|
|
@ -8,11 +8,17 @@ namespace AcDream.Plugins.MossTank;
|
|||
/// import path only. Per the owner's 2026-09-06 "MossTank does not author
|
||||
/// <c>.nav</c>" direction (Campaign VT slice 1 Part A), the writer that
|
||||
/// used to live here was deleted: <c>.af</c> (<see cref="MetafSerializer"/>)
|
||||
/// is the only storage/authoring format for navigation routes now. The
|
||||
/// small binary-blob writer <see cref="MetaEngine"/>'s embedded-navigation
|
||||
/// contract still needs lives in <see cref="MetafSerializer"/> itself
|
||||
/// (<c>WriteBinaryNavBlob</c>) rather than here, since that shape is a
|
||||
/// MossTank runtime contract, not a VTank file on disk.
|
||||
/// is the only storage/authoring format for navigation routes now.
|
||||
/// <see cref="MetaEngine"/>'s embedded-navigation contract (a Meta rule's
|
||||
/// <see cref="MetaActionKind.LoadEmbeddedNavigationRoute"/> action,
|
||||
/// <c>.af</c> tag <c>EmbedNav</c>) is a typed
|
||||
/// <see cref="MetaAction.EmbeddedRoute"/> <see cref="NavigationSettings"/>
|
||||
/// now (round 2 step B, replacing an earlier binary-blob shape), saved and
|
||||
/// loaded through the SAME <see cref="MetafSerializer.SaveNav"/>/
|
||||
/// <see cref="MetafSerializer.TryLoadNav"/> grammar this class no longer
|
||||
/// owns any writer for — round 3 item 12 cleanup: this doc comment
|
||||
/// previously cited a "<c>WriteBinaryNavBlob</c>" method that does not
|
||||
/// exist anywhere in the codebase.
|
||||
/// </summary>
|
||||
internal static class VtankNavRouteSerializer
|
||||
{
|
||||
|
|
|
|||
|
|
@ -268,6 +268,17 @@ internal sealed class VtankDatabase
|
|||
/// accident of whatever order the source data happened to arrive in
|
||||
/// (no observable behavior change for any fixture today; it only
|
||||
/// matters the day a future code path adds or reorders a table).
|
||||
///
|
||||
/// Round 3 item 12: <see cref="StringComparer.Ordinal"/> is used here
|
||||
/// as a stand-in for .NET Framework's <c>SortedDictionary<string, bd></c>
|
||||
/// default key order — that equivalence is confirmed only for the
|
||||
/// plain-ASCII, single-case table names VTank itself ships
|
||||
/// (AntiExtraBuffSpells, MyMonsters, Settings, …), not as a general
|
||||
/// claim that ordinal and .NET's culture-aware default string
|
||||
/// comparer agree for every possible string; a hypothetical future
|
||||
/// table name using non-ASCII characters or mixed-width comparisons
|
||||
/// could sort differently under the two. No behavior change is
|
||||
/// implied or made by this note.
|
||||
/// </summary>
|
||||
public string Render()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue