diff --git a/src/GameCult.Geometry/CultGeometryDocuments.cs b/src/GameCult.Geometry/CultGeometryDocuments.cs index 306b5849..1ce73bdb 100644 --- a/src/GameCult.Geometry/CultGeometryDocuments.cs +++ b/src/GameCult.Geometry/CultGeometryDocuments.cs @@ -153,8 +153,8 @@ namespace GameCult.Geometry public string RequestId { get; set; } = string.Empty; [Key(1)] - [CultReference(typeof(CultGeometryDomainDocument))] - public string DomainKey { get; set; } = string.Empty; + [MessagePackFormatter(typeof(CultRecordRefFormatter))] + public CultRecordRef DomainKey { get; set; } [Key(2)] [CultIndex] @@ -200,7 +200,7 @@ namespace GameCult.Geometry { if (request == null) throw new ArgumentNullException(nameof(request)); return new CultRecordKey("geometry:request:" + StableHash( - request.DomainKey, + request.DomainKey.Key.Value, request.WorkerGroup, StableVector(request.CameraPosition), StableVector(request.FrustumMin), @@ -228,8 +228,8 @@ namespace GameCult.Geometry public string CutId { get; set; } = string.Empty; [Key(1)] - [CultReference(typeof(CultGeometryBuildRequest))] - public string RequestKey { get; set; } = string.Empty; + [MessagePackFormatter(typeof(CultRecordRefFormatter))] + public CultRecordRef RequestKey { get; set; } [Key(2)] public string[] SelectedNodes { get; set; } = Array.Empty(); @@ -247,7 +247,7 @@ namespace GameCult.Geometry { if (cut == null) throw new ArgumentNullException(nameof(cut)); return new CultRecordKey("geometry:cut:" + StableHash( - cut.RequestKey, + cut.RequestKey.Key.Value, cut.CutId, StableArray(cut.SelectedNodes), StableArray(cut.DeferredChildRequests), @@ -313,8 +313,8 @@ namespace GameCult.Geometry public string ChunkId { get; set; } = string.Empty; [Key(1)] - [CultReference(typeof(CultGeometrySelectedCutManifest))] - public string CutKey { get; set; } = string.Empty; + [MessagePackFormatter(typeof(CultRecordRefFormatter))] + public CultRecordRef CutKey { get; set; } [Key(2)] [CultIndex] @@ -357,7 +357,7 @@ namespace GameCult.Geometry { if (chunk == null) throw new ArgumentNullException(nameof(chunk)); return new CultRecordKey("geometry:chunk:" + StableHash( - chunk.CutKey, + chunk.CutKey.Key.Value, chunk.ChunkId, chunk.SelectedCutId, StableArray(chunk.SourceDomainKeys), diff --git a/src/GameCult.Geometry/GameCult.Geometry.csproj b/src/GameCult.Geometry/GameCult.Geometry.csproj index c10c2ecf..cc66cba9 100644 --- a/src/GameCult.Geometry/GameCult.Geometry.csproj +++ b/src/GameCult.Geometry/GameCult.Geometry.csproj @@ -10,6 +10,7 @@ + diff --git a/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs b/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs index 8741f891..b5f63775 100644 --- a/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs +++ b/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs @@ -10,6 +10,7 @@ using R3; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text.Json; using System.Threading.Tasks; @@ -104,7 +105,7 @@ namespace GameCult.Geometry.Tests var domainKey = CultGeometryDomainDocument.CreateRecordKey(domain); var request = new CultGeometryBuildRequest { - DomainKey = domainKey.Value, + DomainKey = new CultRecordRef(domainKey), WorkerGroup = "ragnarok-column-workers", CameraPosition = [36f, -42f, 30f], FrustumMin = [-75f, -75f, -30f], @@ -129,6 +130,26 @@ namespace GameCult.Geometry.Tests first.Value.Should().StartWith("geometry:request:"); } + // The geometry documents reference each other by record key. The reference members are + // CultRecordRef so the cache can walk them, and they stay a bare msgpack string on the wire. + [Test] + public void GeometryReferences_AreWalkableByTheCache_AndStayStringsOnTheWire() + { + var cache = new CultCache(); + var descriptor = cache.Registry.GetRequired(); + descriptor.DeclaredMembers.Should().Contain(m => m.MemberName == "DomainKey" && m.IsReference && !m.IsMany); + + var chunk = SampleChunk(); + var references = cache.Registry.GetRequired().ReferencesOf(chunk, "CutKey").ToArray(); + references.Should().ContainSingle().Which.Target.Value.Should().Be("geometry:cut:test"); + + var payload = CultDocumentMessagePackSerialization.SerializeUntyped(chunk, typeof(CultGeometryChunkArtifact)); + var reader = new MessagePackReader(payload); + reader.ReadArrayHeader(); + reader.ReadString().Should().Be(chunk.ChunkId); + reader.ReadString().Should().Be("geometry:cut:test"); + } + [Test] public void ChunkArtifact_RoundTrips_ThroughCultCacheMessagePack() { @@ -382,7 +403,7 @@ namespace GameCult.Geometry.Tests return new CultGeometryChunkArtifact { ChunkId = "chunk/ragnarok-column/column-00", - CutKey = "geometry:cut:test", + CutKey = new CultRecordRef(new CultRecordKey("geometry:cut:test")), SelectedCutId = "cut-test", BoundsMin = [-1f, -1f, 0f], BoundsMax = [1f, 1f, 1f],