Add typed catalog snapshot queries
This commit is contained in:
parent
1c592b10e9
commit
6272408db2
148 changed files with 363 additions and 229 deletions
Binary file not shown.
|
|
@ -240,7 +240,7 @@ internal static class LegacyCatalogReader
|
|||
Description = description,
|
||||
Mass = GetDouble(payload, 4),
|
||||
Volume = shape.OccupiedCells,
|
||||
ManufacturerLegacyId = GetGuid(payload, 3),
|
||||
ManufacturerLegacyId = GetOptionalGuid(payload, 3),
|
||||
Price = GetInt(payload, 8),
|
||||
ShapeWidth = shape.Width,
|
||||
ShapeHeight = shape.Height,
|
||||
|
|
@ -255,8 +255,8 @@ internal static class LegacyCatalogReader
|
|||
LegacyId = legacyId,
|
||||
ShortName = GetString(payload, 2),
|
||||
Description = GetString(payload, 3),
|
||||
GeonameFileLegacyId = GetGuid(payload, 9),
|
||||
BossHullLegacyId = GetGuid(payload, 10),
|
||||
GeonameFileLegacyId = GetOptionalGuid(payload, 9),
|
||||
BossHullLegacyId = GetOptionalGuid(payload, 10),
|
||||
InfluenceDistance = GetInt(payload, 11),
|
||||
AllegianceCount = GetMapCount(payload, 12),
|
||||
OverworldMusic = GetUInt(payload, 13),
|
||||
|
|
@ -374,6 +374,12 @@ internal static class LegacyCatalogReader
|
|||
: "";
|
||||
}
|
||||
|
||||
private static string GetOptionalGuid(IReadOnlyDictionary<int, object?> payload, int key)
|
||||
{
|
||||
var legacyId = GetGuid(payload, key);
|
||||
return Guid.TryParse(legacyId, out var guid) && guid == Guid.Empty ? "" : legacyId;
|
||||
}
|
||||
|
||||
private static string GetString(IReadOnlyDictionary<int, object?> payload, int key)
|
||||
{
|
||||
return payload.TryGetValue(key, out var value) ? value as string ?? "" : "";
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ var quarantine = await node.GetLegacyCatalogQuarantineAsync()
|
|||
var items = node.Cache.GetAll<AetheriaItemDefinition>().ToArray();
|
||||
var corporations = node.Cache.GetAll<AetheriaCorporation>().ToArray();
|
||||
var nameFiles = node.Cache.GetAll<AetheriaNameFile>().ToArray();
|
||||
var catalog = node.ReadCatalogSnapshot();
|
||||
|
||||
RequireCount(ledger, "aetheria.item_definition.v1", items.Length);
|
||||
RequireCount(ledger, "aetheria.corporation.v1", corporations.Length);
|
||||
|
|
@ -67,6 +68,30 @@ if (corporationNameLinks == 0)
|
|||
throw new InvalidOperationException("Typed corporations did not import geoname file legacy IDs.");
|
||||
}
|
||||
|
||||
var tradeItems = catalog.TradeItems.ToArray();
|
||||
if (tradeItems.Length != pricedItems)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Typed catalog trade item query mismatch: query={tradeItems.Length}, priced={pricedItems}.");
|
||||
}
|
||||
|
||||
var manufacturedItem = items.FirstOrDefault(item => !string.IsNullOrWhiteSpace(item.ManufacturerLegacyId))
|
||||
?? throw new InvalidOperationException("Cannot verify typed catalog manufacturer lookup: no manufactured item.");
|
||||
if (catalog.GetManufacturer(manufacturedItem) == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Typed catalog manufacturer lookup failed for item {manufacturedItem.Name}.");
|
||||
}
|
||||
|
||||
var corporationWithNames = corporations.FirstOrDefault(corporation =>
|
||||
!string.IsNullOrWhiteSpace(corporation.GeonameFileLegacyId))
|
||||
?? throw new InvalidOperationException("Cannot verify typed catalog name-file lookup: no linked corporation.");
|
||||
if (catalog.GetNameFile(corporationWithNames) == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Typed catalog name-file lookup failed for corporation {corporationWithNames.Name}.");
|
||||
}
|
||||
|
||||
await RequireLegacyLookupAsync(
|
||||
items[0].LegacyId,
|
||||
() => node.GetItemDefinitionByLegacyIdAsync(items[0].LegacyId),
|
||||
|
|
@ -89,6 +114,7 @@ Console.WriteLine($"Aetheria typed state verify passed: {statePath}");
|
|||
Console.WriteLine($"Catalog fingerprint: {quarantine.CatalogFingerprint}");
|
||||
Console.WriteLine($"Item definitions: {items.Length}");
|
||||
Console.WriteLine($"Priced/manufactured/shaped items: {pricedItems}/{manufacturedItems}/{shapedItems}");
|
||||
Console.WriteLine($"Typed catalog trade items: {tradeItems.Length}");
|
||||
Console.WriteLine($"Corporations: {corporations.Length}");
|
||||
Console.WriteLine($"Described/geoname-linked corporations: {describedCorporations}/{corporationNameLinks}");
|
||||
Console.WriteLine($"Name files: {nameFiles.Length}");
|
||||
|
|
|
|||
80
Aetheria.State/AetheriaCatalogSnapshot.cs
Normal file
80
Aetheria.State/AetheriaCatalogSnapshot.cs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Aetheria.State.Documents;
|
||||
|
||||
namespace Aetheria.State;
|
||||
|
||||
public sealed class AetheriaCatalogSnapshot
|
||||
{
|
||||
private readonly Dictionary<string, AetheriaItemDefinition> _itemsByLegacyId;
|
||||
private readonly Dictionary<string, AetheriaCorporation> _corporationsByLegacyId;
|
||||
private readonly Dictionary<string, AetheriaNameFile> _nameFilesByLegacyId;
|
||||
|
||||
public AetheriaCatalogSnapshot(
|
||||
IEnumerable<AetheriaItemDefinition> items,
|
||||
IEnumerable<AetheriaCorporation> corporations,
|
||||
IEnumerable<AetheriaNameFile> nameFiles)
|
||||
{
|
||||
Items = items.OrderBy(item => item.Name, StringComparer.OrdinalIgnoreCase).ToArray();
|
||||
Corporations = corporations.OrderBy(corporation => corporation.Name, StringComparer.OrdinalIgnoreCase).ToArray();
|
||||
NameFiles = nameFiles.OrderBy(nameFile => nameFile.Name, StringComparer.OrdinalIgnoreCase).ToArray();
|
||||
|
||||
_itemsByLegacyId = Items
|
||||
.Where(item => !string.IsNullOrWhiteSpace(item.LegacyId))
|
||||
.ToDictionary(item => item.LegacyId, StringComparer.OrdinalIgnoreCase);
|
||||
_corporationsByLegacyId = Corporations
|
||||
.Where(corporation => !string.IsNullOrWhiteSpace(corporation.LegacyId))
|
||||
.ToDictionary(corporation => corporation.LegacyId, StringComparer.OrdinalIgnoreCase);
|
||||
_nameFilesByLegacyId = NameFiles
|
||||
.Where(nameFile => !string.IsNullOrWhiteSpace(nameFile.LegacyId))
|
||||
.ToDictionary(nameFile => nameFile.LegacyId, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public IReadOnlyList<AetheriaItemDefinition> Items { get; }
|
||||
|
||||
public IReadOnlyList<AetheriaCorporation> Corporations { get; }
|
||||
|
||||
public IReadOnlyList<AetheriaNameFile> NameFiles { get; }
|
||||
|
||||
public IEnumerable<AetheriaItemDefinition> TradeItems =>
|
||||
Items.Where(item => item.Price > 0).OrderBy(item => item.Name, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public AetheriaItemDefinition? FindItemByLegacyId(string legacyId)
|
||||
{
|
||||
return TryGet(_itemsByLegacyId, legacyId);
|
||||
}
|
||||
|
||||
public AetheriaCorporation? FindCorporationByLegacyId(string legacyId)
|
||||
{
|
||||
return TryGet(_corporationsByLegacyId, legacyId);
|
||||
}
|
||||
|
||||
public AetheriaNameFile? FindNameFileByLegacyId(string legacyId)
|
||||
{
|
||||
return TryGet(_nameFilesByLegacyId, legacyId);
|
||||
}
|
||||
|
||||
public AetheriaCorporation? FindCorporationByNamePrefix(string namePrefix)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(namePrefix)
|
||||
? null
|
||||
: Corporations.FirstOrDefault(corporation =>
|
||||
corporation.Name.StartsWith(namePrefix, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
public AetheriaCorporation? GetManufacturer(AetheriaItemDefinition item)
|
||||
{
|
||||
return FindCorporationByLegacyId(item.ManufacturerLegacyId);
|
||||
}
|
||||
|
||||
public AetheriaNameFile? GetNameFile(AetheriaCorporation corporation)
|
||||
{
|
||||
return FindNameFileByLegacyId(corporation.GeonameFileLegacyId);
|
||||
}
|
||||
|
||||
private static T? TryGet<T>(IReadOnlyDictionary<string, T> dictionary, string key) where T : class
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(key) ? null : dictionary.TryGetValue(key, out var value) ? value : null;
|
||||
}
|
||||
}
|
||||
|
|
@ -155,6 +155,14 @@ public sealed class AetheriaStateNode : IAsyncDisposable, IDisposable
|
|||
return GetNameFileAsync(AetheriaCatalogKeys.NameFileFromLegacyId(legacyId));
|
||||
}
|
||||
|
||||
public AetheriaCatalogSnapshot ReadCatalogSnapshot()
|
||||
{
|
||||
return new AetheriaCatalogSnapshot(
|
||||
Cache.GetAll<AetheriaItemDefinition>(),
|
||||
Cache.GetAll<AetheriaCorporation>(),
|
||||
Cache.GetAll<AetheriaNameFile>());
|
||||
}
|
||||
|
||||
public Task<CultRecordHandle<AetheriaPlayerSettings>> PutPlayerSettingsAsync(AetheriaPlayerSettings settings)
|
||||
{
|
||||
return Database.PutAsync(new CultRecordKey("global:aetheria.player_settings.v1"), settings);
|
||||
|
|
|
|||
|
|
@ -52,12 +52,20 @@ field from key 3, name-file and boss-hull legacy IDs, influence distance,
|
|||
allegiance count, and music bank IDs. Runtime object graphs, behaviors, full
|
||||
Unity shape masks, and simulation state remain legacy until dedicated typed
|
||||
documents exist.
|
||||
Legacy GUID references that are `Guid.Empty` are imported as absent references,
|
||||
not as resolvable catalog links.
|
||||
|
||||
`AetheriaCatalogSnapshot` is the typed read surface over materialized catalog
|
||||
documents. It exposes trade items, legacy-ID lookup, manufacturer lookup,
|
||||
corporation prefix lookup, and corporation name-file lookup without reading
|
||||
`DatabaseEntry` objects.
|
||||
|
||||
`Aetheria.State.Verify` opens a materialized state file and checks that the
|
||||
typed migration ledger matches the actual item, corporation, and name-file
|
||||
records in the `.cc` store. It also verifies the canonical legacy-ID lookup API
|
||||
for one migrated record of each catalog kind and checks that expanded item and
|
||||
corporation catalog facts survived materialization. Use it after import when
|
||||
corporation catalog facts survived materialization. The verifier also exercises
|
||||
the typed catalog snapshot query surface. Use it after import when
|
||||
`GameData/aetheria-world.cc` changes.
|
||||
|
||||
Current rebuild notes:
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue