diff --git a/src/GameCult.Geometry/CultGeometryDocuments.cs b/src/GameCult.Geometry/CultGeometryDocuments.cs
index 7a1677b3..306b5849 100644
--- a/src/GameCult.Geometry/CultGeometryDocuments.cs
+++ b/src/GameCult.Geometry/CultGeometryDocuments.cs
@@ -411,7 +411,13 @@ namespace GameCult.Geometry
public static string StableVector(float[] values)
{
- return string.Join(",", values.Select(value => value.ToString("R", CultureInfo.InvariantCulture)));
+ return string.Join(",", values.Select(StableFloat));
+ }
+
+ public static string StableFloat(float value)
+ {
+ return BitConverter.ToUInt32(BitConverter.GetBytes(value), 0)
+ .ToString("x8", CultureInfo.InvariantCulture);
}
public static string StableArray(string[] values)
diff --git a/tests/GameCult.Geometry.Tests/Fixtures/vg-csg-ragnarok/ragnarok-domain.msgpack b/tests/GameCult.Geometry.Tests/Fixtures/vg-csg-ragnarok/ragnarok-domain.msgpack
new file mode 100644
index 00000000..79c5f5b6
Binary files /dev/null and b/tests/GameCult.Geometry.Tests/Fixtures/vg-csg-ragnarok/ragnarok-domain.msgpack differ
diff --git a/tests/GameCult.Geometry.Tests/Fixtures/vg-csg-ragnarok/ragnarok-first-chunk.msgpack b/tests/GameCult.Geometry.Tests/Fixtures/vg-csg-ragnarok/ragnarok-first-chunk.msgpack
new file mode 100644
index 00000000..4cfcf493
Binary files /dev/null and b/tests/GameCult.Geometry.Tests/Fixtures/vg-csg-ragnarok/ragnarok-first-chunk.msgpack differ
diff --git a/tests/GameCult.Geometry.Tests/GameCult.Geometry.Tests.csproj b/tests/GameCult.Geometry.Tests/GameCult.Geometry.Tests.csproj
index fe7fd8c1..407f5305 100644
--- a/tests/GameCult.Geometry.Tests/GameCult.Geometry.Tests.csproj
+++ b/tests/GameCult.Geometry.Tests/GameCult.Geometry.Tests.csproj
@@ -12,6 +12,10 @@
+
+
+
+
diff --git a/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs b/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs
index e3938284..1723b852 100644
--- a/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs
+++ b/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs
@@ -82,15 +82,41 @@ namespace GameCult.Geometry.Tests
claim.StableFingerprint().Should().Be(string.Join('\u001e',
"column-support-shell",
- "0,0,0",
- "0,0,0,1",
- "0,0,45",
- "18,18,96",
+ "00000000,00000000,00000000",
+ "00000000,00000000,00000000,3f800000",
+ "00000000,00000000,42340000",
+ "41900000,41900000,42c00000",
"SupportShell",
"10",
"RenderAndCollider"));
}
+ [Test]
+ public void RustExportedDomainDocument_DecodesWithStableCultCacheKey()
+ {
+ var payload = File.ReadAllBytes(FixturePath("ragnarok-domain.msgpack"));
+ var domain = CultDocumentMessagePackSerialization.Deserialize(payload);
+
+ domain.DomainId.Should().Be("ragnarok-column");
+ domain.Root.Children.Should().NotBeEmpty();
+ domain.Root.Children[0].Name.Should().Be("stellarator-column-00");
+ CultGeometryDomainDocument.CreateRecordKey(domain).Value
+ .Should().Be("geometry:domain:02c9b5810977406b0c206f3a3494327a423abb9448192be1b9a1863cd0f2ed95");
+ }
+
+ [Test]
+ public void RustExportedChunkArtifact_DecodesWithStableCultCacheKey()
+ {
+ var payload = File.ReadAllBytes(FixturePath("ragnarok-first-chunk.msgpack"));
+ var chunk = CultDocumentMessagePackSerialization.Deserialize(payload);
+
+ chunk.ChunkId.Should().StartWith("chunk/");
+ chunk.RenderMesh.TriangleCount.Should().BeGreaterThan(0);
+ chunk.SourceDomainKeys.Should().NotBeEmpty();
+ CultGeometryChunkArtifact.CreateRecordKey(chunk).Value
+ .Should().Be("geometry:chunk:b94dcd7d6776df15d0fa5fcf7f4b24f1384876b13b2d38cc57c4468136521af5");
+ }
+
[Test]
public async Task ChunkArtifact_Replicates_ThroughCultNetRawDocumentLane()
{
@@ -273,6 +299,15 @@ namespace GameCult.Geometry.Tests
};
}
+ private static string FixturePath(string fileName)
+ {
+ return Path.Combine(
+ TestContext.CurrentContext.TestDirectory,
+ "Fixtures",
+ "vg-csg-ragnarok",
+ fileName);
+ }
+
private static CultGeometryChunkArtifact SampleChunk()
{
return new CultGeometryChunkArtifact