diff --git a/src/AcDream.Plugins.MossTank/MossTankMetaProfileStore.cs b/src/AcDream.Plugins.MossTank/MossTankMetaProfileStore.cs
index 676aa1396..8ba153b50 100644
--- a/src/AcDream.Plugins.MossTank/MossTankMetaProfileStore.cs
+++ b/src/AcDream.Plugins.MossTank/MossTankMetaProfileStore.cs
@@ -195,7 +195,12 @@ internal sealed class MossTankMetaProfileStore
/// .af is the only VTank-compatible export format now (Campaign
/// VT slice 1 Part A — MossTank no longer authors the binary
/// .met format at all, matching 's
- /// demotion to a one-shot import).
+ /// demotion to a one-shot import). Exports live under
+ /// exports/meta/ — a distinct subdirectory from
+ /// 's exports/nav/ — so a
+ /// Meta profile and a route (Navigation) profile sharing the same name
+ /// cannot silently overwrite each other's .af file (both stores
+ /// used to write into the same flat exports/ root).
///
private void WriteLegacyExport(string name, MetaProfile profile)
{
@@ -204,7 +209,7 @@ internal sealed class MossTankMetaProfileStore
try
{
_host.Storage.WriteText(
- $"exports/{LegacyFileName(name)}.af",
+ $"exports/meta/{LegacyFileName(name)}.af",
MetafSerializer.SaveMeta(profile));
}
catch (Exception error)
diff --git a/src/AcDream.Plugins.MossTank/MossTankRouteProfileStore.cs b/src/AcDream.Plugins.MossTank/MossTankRouteProfileStore.cs
index d6af35d8a..49c4ae7af 100644
--- a/src/AcDream.Plugins.MossTank/MossTankRouteProfileStore.cs
+++ b/src/AcDream.Plugins.MossTank/MossTankRouteProfileStore.cs
@@ -264,7 +264,12 @@ internal sealed class MossTankRouteProfileStore
/// .af is the only VTank-compatible export format now (Campaign
/// VT slice 1 Part A — MossTank no longer authors the binary
/// .nav format at all, matching 's
- /// demotion to a one-shot import).
+ /// demotion to a one-shot import). Exports live under
+ /// exports/nav/ — a distinct subdirectory from
+ /// 's exports/meta/ — so a
+ /// route (Navigation) profile and a Meta profile sharing the same name
+ /// cannot silently overwrite each other's .af file (both stores
+ /// used to write into the same flat exports/ root).
///
private void WriteLegacyExport(string name, NavigationSettings settings)
{
@@ -273,7 +278,7 @@ internal sealed class MossTankRouteProfileStore
try
{
_host.Storage.WriteText(
- $"exports/{LegacyFileName(name)}.af",
+ $"exports/nav/{LegacyFileName(name)}.af",
MetafSerializer.SaveNav(settings));
}
catch (Exception error)
diff --git a/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs b/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs
index 2fab57bd8..8a506f9b5 100644
--- a/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs
+++ b/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs
@@ -678,7 +678,39 @@ public sealed class MossTankPanelTests
Command(panel, "nav save Exported.nav");
Assert.StartsWith(
"NAV: ",
- storage.Text["exports/Exported.af"],
+ storage.Text["exports/nav/Exported.af"],
+ StringComparison.Ordinal);
+ }
+
+ // Item C (Campaign VT slice-1 fix round): a Meta profile and a route
+ // (Navigation) profile named identically used to write into the SAME
+ // flat "exports/" directory — "Same.af" from one silently clobbered
+ // "Same.af" from the other. exports/meta/ and exports/nav/ are
+ // separate subdirectories so both coexist.
+ [Fact]
+ public void MetaAndRouteExportsWithTheSameNameDoNotCollide()
+ {
+ var storage = new MemoryStorage();
+ storage.Text["imports/Same.met"] =
+ "1\r\nCondAct\r\n5\r\nCType\r\nAType\r\nCData\r\nAData\r\nState\r\n"
+ + "n\r\nn\r\nn\r\nn\r\nn\r\n1\r\n"
+ + "i\r\n1\r\ni\r\n2\r\ni\r\n0\r\ns\r\n/say imported\r\n"
+ + "s\r\nDefault\r\n";
+ var panel = new MossTankPanel(new FakeHost(new FakeAutomation(), storage));
+
+ Command(panel, "meta load Same.met");
+ Command(panel, "meta save Same.met");
+ Command(panel, "nav save Same.nav");
+
+ Assert.True(storage.Text.ContainsKey("exports/meta/Same.af"));
+ Assert.True(storage.Text.ContainsKey("exports/nav/Same.af"));
+ Assert.StartsWith(
+ "STATE: ",
+ storage.Text["exports/meta/Same.af"],
+ StringComparison.Ordinal);
+ Assert.StartsWith(
+ "NAV: ",
+ storage.Text["exports/nav/Same.af"],
StringComparison.Ordinal);
}
@@ -712,10 +744,10 @@ public sealed class MossTankPanelTests
Command(panel, "meta save Exported.met");
Assert.StartsWith(
"STATE: ",
- storage.Text["exports/Exported.af"],
+ storage.Text["exports/meta/Exported.af"],
StringComparison.Ordinal);
Assert.True(MetafSerializer.TryLoadMeta(
- storage.Text["exports/Exported.af"],
+ storage.Text["exports/meta/Exported.af"],
NoOpSpellCatalogForExport.Instance,
out MetaProfile exported,
out string error), error);