Centralize typed catalog legacy keys
This commit is contained in:
parent
3b7956f7a2
commit
af1247ce68
5 changed files with 82 additions and 20 deletions
|
|
@ -2,7 +2,6 @@ using System.Security.Cryptography;
|
|||
using Aetheria.State;
|
||||
using Aetheria.State.Documents;
|
||||
using Aetheria.State.Migration;
|
||||
using GameCult.Caching;
|
||||
using MessagePack;
|
||||
|
||||
var root = args.Length > 0 ? Path.GetFullPath(args[0]) : Directory.GetCurrentDirectory();
|
||||
|
|
@ -110,17 +109,17 @@ await node.PutMigrationLedgerAsync(new AetheriaMigrationLedger
|
|||
|
||||
foreach (var item in itemDefinitions)
|
||||
{
|
||||
await node.PutItemDefinitionAsync(new CultRecordKey($"legacy:item:{item.LegacyId}"), item);
|
||||
await node.PutLegacyItemDefinitionAsync(item);
|
||||
}
|
||||
|
||||
foreach (var corporation in corporations)
|
||||
{
|
||||
await node.PutCorporationAsync(new CultRecordKey($"legacy:faction:{corporation.LegacyId}"), corporation);
|
||||
await node.PutLegacyCorporationAsync(corporation);
|
||||
}
|
||||
|
||||
foreach (var nameFile in parsedNameFiles)
|
||||
{
|
||||
await node.PutNameFileAsync(new CultRecordKey($"legacy:name-file:{nameFile.LegacyId}"), nameFile);
|
||||
await node.PutLegacyNameFileAsync(nameFile);
|
||||
}
|
||||
|
||||
await node.FlushAsync();
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ using GameCult.Caching;
|
|||
var root = args.Length > 0 ? args[0] : Directory.GetCurrentDirectory();
|
||||
var statePath = AetheriaStatePaths.ResolveDefaultStatePath(root);
|
||||
var now = DateTimeOffset.UtcNow.ToString("O");
|
||||
var itemKey = new CultRecordKey("item:smoke-aether-drive");
|
||||
var factionKey = new CultRecordKey("faction:smoke");
|
||||
var nameFileKey = new CultRecordKey("name-file:smoke");
|
||||
var itemLegacyId = "smoke:aether-drive";
|
||||
var factionLegacyId = "smoke:faction";
|
||||
var nameFileLegacyId = "smoke:name-file";
|
||||
var runKey = new CultRecordKey("run:smoke");
|
||||
|
||||
await using (var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-state-smoke"))
|
||||
|
|
@ -22,13 +22,12 @@ await using (var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-s
|
|||
UpdatedAtUtc = now
|
||||
});
|
||||
|
||||
await node.PutItemDefinitionAsync(
|
||||
itemKey,
|
||||
await node.PutLegacyItemDefinitionAsync(
|
||||
new AetheriaItemDefinition
|
||||
{
|
||||
Name = "Smoke Aether Drive",
|
||||
Category = "ship-module",
|
||||
LegacyId = "smoke:aether-drive",
|
||||
LegacyId = itemLegacyId,
|
||||
Description = "Typed CultCache smoke document for the rebuild spine.",
|
||||
Mass = 12.5,
|
||||
Volume = 4.0,
|
||||
|
|
@ -70,17 +69,17 @@ await using (var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-s
|
|||
Notes = ["Smoke proves legacy catalog quarantine state is typed and durable."]
|
||||
});
|
||||
|
||||
await node.PutCorporationAsync(factionKey, new AetheriaCorporation
|
||||
await node.PutLegacyCorporationAsync(new AetheriaCorporation
|
||||
{
|
||||
Name = "Smoke Faction",
|
||||
LegacyId = "smoke:faction",
|
||||
LegacyId = factionLegacyId,
|
||||
Description = "Typed faction/corporation document for legacy catalog migration smoke."
|
||||
});
|
||||
|
||||
await node.PutNameFileAsync(nameFileKey, new AetheriaNameFile
|
||||
await node.PutLegacyNameFileAsync(new AetheriaNameFile
|
||||
{
|
||||
Name = "Smoke Names",
|
||||
LegacyId = "smoke:name-file",
|
||||
LegacyId = nameFileLegacyId,
|
||||
NameCount = 2,
|
||||
SampleNames = ["Ada", "Grace"]
|
||||
});
|
||||
|
|
@ -117,9 +116,9 @@ await using (var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-s
|
|||
await using (var reopened = await AetheriaStateNode.OpenAsync(statePath, "aetheria-state-smoke-reopen"))
|
||||
{
|
||||
var world = await reopened.GetWorldAsync();
|
||||
var item = await reopened.GetItemDefinitionAsync(itemKey);
|
||||
var faction = await reopened.GetCorporationAsync(factionKey);
|
||||
var nameFile = await reopened.GetNameFileAsync(nameFileKey);
|
||||
var item = await reopened.GetItemDefinitionByLegacyIdAsync(itemLegacyId);
|
||||
var faction = await reopened.GetCorporationByLegacyIdAsync(factionLegacyId);
|
||||
var nameFile = await reopened.GetNameFileByLegacyIdAsync(nameFileLegacyId);
|
||||
var quarantine = await reopened.GetLegacyCatalogQuarantineAsync();
|
||||
var playerSettings = await reopened.GetPlayerSettingsAsync();
|
||||
var runState = await reopened.GetRunStateAsync(runKey);
|
||||
|
|
@ -134,7 +133,7 @@ await using (var reopened = await AetheriaStateNode.OpenAsync(statePath, "aether
|
|||
throw new InvalidOperationException("Item definition did not survive flush/reopen.");
|
||||
}
|
||||
|
||||
if (faction?.LegacyId != "smoke:faction")
|
||||
if (faction?.LegacyId != factionLegacyId)
|
||||
{
|
||||
throw new InvalidOperationException("Faction/corporation document did not survive flush/reopen.");
|
||||
}
|
||||
|
|
|
|||
31
Aetheria.State/AetheriaCatalogKeys.cs
Normal file
31
Aetheria.State/AetheriaCatalogKeys.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
using GameCult.Caching;
|
||||
|
||||
namespace Aetheria.State;
|
||||
|
||||
public static class AetheriaCatalogKeys
|
||||
{
|
||||
public static CultRecordKey ItemDefinitionFromLegacyId(string legacyId)
|
||||
{
|
||||
return CreateLegacyKey("item", legacyId);
|
||||
}
|
||||
|
||||
public static CultRecordKey CorporationFromLegacyId(string legacyId)
|
||||
{
|
||||
return CreateLegacyKey("faction", legacyId);
|
||||
}
|
||||
|
||||
public static CultRecordKey NameFileFromLegacyId(string legacyId)
|
||||
{
|
||||
return CreateLegacyKey("name-file", legacyId);
|
||||
}
|
||||
|
||||
private static CultRecordKey CreateLegacyKey(string catalogKind, string legacyId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(legacyId))
|
||||
{
|
||||
throw new ArgumentException("Legacy catalog id must be non-empty.", nameof(legacyId));
|
||||
}
|
||||
|
||||
return new CultRecordKey($"legacy:{catalogKind}:{legacyId.Trim()}");
|
||||
}
|
||||
}
|
||||
|
|
@ -95,31 +95,61 @@ public sealed class AetheriaStateNode : IAsyncDisposable, IDisposable
|
|||
return Database.PutAsync(key, item);
|
||||
}
|
||||
|
||||
public Task<CultRecordHandle<AetheriaItemDefinition>> PutLegacyItemDefinitionAsync(AetheriaItemDefinition item)
|
||||
{
|
||||
return PutItemDefinitionAsync(AetheriaCatalogKeys.ItemDefinitionFromLegacyId(item.LegacyId), item);
|
||||
}
|
||||
|
||||
public Task<AetheriaItemDefinition?> GetItemDefinitionAsync(CultRecordKey key)
|
||||
{
|
||||
return Database.GetAsync<AetheriaItemDefinition>(key);
|
||||
}
|
||||
|
||||
public Task<AetheriaItemDefinition?> GetItemDefinitionByLegacyIdAsync(string legacyId)
|
||||
{
|
||||
return GetItemDefinitionAsync(AetheriaCatalogKeys.ItemDefinitionFromLegacyId(legacyId));
|
||||
}
|
||||
|
||||
public Task<CultRecordHandle<AetheriaCorporation>> PutCorporationAsync(CultRecordKey key, AetheriaCorporation corporation)
|
||||
{
|
||||
return Database.PutAsync(key, corporation);
|
||||
}
|
||||
|
||||
public Task<CultRecordHandle<AetheriaCorporation>> PutLegacyCorporationAsync(AetheriaCorporation corporation)
|
||||
{
|
||||
return PutCorporationAsync(AetheriaCatalogKeys.CorporationFromLegacyId(corporation.LegacyId), corporation);
|
||||
}
|
||||
|
||||
public Task<AetheriaCorporation?> GetCorporationAsync(CultRecordKey key)
|
||||
{
|
||||
return Database.GetAsync<AetheriaCorporation>(key);
|
||||
}
|
||||
|
||||
public Task<AetheriaCorporation?> GetCorporationByLegacyIdAsync(string legacyId)
|
||||
{
|
||||
return GetCorporationAsync(AetheriaCatalogKeys.CorporationFromLegacyId(legacyId));
|
||||
}
|
||||
|
||||
public Task<CultRecordHandle<AetheriaNameFile>> PutNameFileAsync(CultRecordKey key, AetheriaNameFile nameFile)
|
||||
{
|
||||
return Database.PutAsync(key, nameFile);
|
||||
}
|
||||
|
||||
public Task<CultRecordHandle<AetheriaNameFile>> PutLegacyNameFileAsync(AetheriaNameFile nameFile)
|
||||
{
|
||||
return PutNameFileAsync(AetheriaCatalogKeys.NameFileFromLegacyId(nameFile.LegacyId), nameFile);
|
||||
}
|
||||
|
||||
public Task<AetheriaNameFile?> GetNameFileAsync(CultRecordKey key)
|
||||
{
|
||||
return Database.GetAsync<AetheriaNameFile>(key);
|
||||
}
|
||||
|
||||
public Task<AetheriaNameFile?> GetNameFileByLegacyIdAsync(string legacyId)
|
||||
{
|
||||
return GetNameFileAsync(AetheriaCatalogKeys.NameFileFromLegacyId(legacyId));
|
||||
}
|
||||
|
||||
public Task<CultRecordHandle<AetheriaPlayerSettings>> PutPlayerSettingsAsync(AetheriaPlayerSettings settings)
|
||||
{
|
||||
return Database.PutAsync(new CultRecordKey("global:aetheria.player_settings.v1"), settings);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
|
|||
MessagePack union fields into typed item/faction/name-file documents without
|
||||
compiling the old Unity domain model into `Aetheria.State`. The current
|
||||
checked-in catalog maps to 115 item definitions, 12 factions, and 12 name
|
||||
files.
|
||||
files. `Aetheria.State` now owns the canonical legacy-ID record key mapping
|
||||
for migrated item, corporation, and name-file documents.
|
||||
- `GameData/aetheria-world.cc` is now materialized from the importer as the
|
||||
project-local typed state file for the checked-in catalog. The importer stores
|
||||
relative provenance in the state document, not machine-local absolute paths.
|
||||
|
|
@ -100,7 +101,9 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
|
|||
CultMesh server state.
|
||||
- Outputs: `Aetheria.State` emits `.cc` state and CultMesh documents. Legacy
|
||||
catalog reads emit in-memory domain objects only; the old local save and
|
||||
editor catalog write paths have been cut.
|
||||
editor catalog write paths have been cut. Migrated catalog documents are
|
||||
addressed through `AetheriaCatalogKeys` and `AetheriaStateNode` legacy-ID
|
||||
methods, not importer-local string concatenation.
|
||||
- Derived state: UI panels, generated keyboard layouts, editor rows, and
|
||||
serialized legacy payloads are projections, migration inputs, or disabled
|
||||
session-local DTOs, not durable authority.
|
||||
|
|
|
|||
Loading…
Reference in a new issue