Resolve CultMesh network body fallback

This commit is contained in:
Meta Vens 2026-07-13 20:27:00 +01:00
commit 61a255a4d5
3 changed files with 80 additions and 3 deletions

View file

@ -31,6 +31,7 @@ namespace GameCult.Eve.UnityScene
typeof(EveAssetCatalogDocument),
typeof(EveEntitySoaViewDocument),
typeof(CultMeshBodyPublicationDocument),
typeof(CultMeshNetworkBodyDocument),
typeof(CultMeshCdnArtifactManifest),
typeof(CultMeshCdnArtifactChunk)
};
@ -291,12 +292,56 @@ namespace GameCult.Eve.UnityScene
{
new CultMeshSharedMemoryBodyAdapter(),
new CultMeshMappedBodyAdapter(mappedRoot),
new CultMeshNetworkBodyAdapter(_ => throw new NotSupportedException(
"The connected Verse does not expose a CultMesh network body byte reader."))
new CultMeshNetworkBodyAdapter(ReadNetworkBody)
},
(producerId, _) => string.Equals(producerId, _providerId, StringComparison.Ordinal)));
}
private byte[] ReadNetworkBody(CultMeshBodyDescriptor descriptor)
{
var binding = _snapshot!
.FetchDocumentsAsync<CultMeshNetworkBodyDocument>(
recordKeys: new[] { CultMeshNetworkBodyDocument.CreateRecordKey(descriptor.CapabilityToken).Value },
schemaIds: new[] { CultMeshBodyPublicationSchemaVersions.NetworkBody })
.GetAwaiter().GetResult().SingleOrDefault()
?? throw new FileNotFoundException("Provider network body capability is missing.", descriptor.CapabilityToken);
var manifest = _snapshot
.FetchDocumentsAsync<CultMeshCdnArtifactManifest>(
recordKeys: new[] { binding.ManifestRecordKey },
schemaIds: new[] { CultMeshCdnSchemaVersions.ArtifactManifest })
.GetAwaiter().GetResult().SingleOrDefault()
?? throw new FileNotFoundException("Provider network body manifest is missing.", binding.ManifestRecordKey);
var chunks = _snapshot
.FetchDocumentsAsync<CultMeshCdnArtifactChunk>(
recordKeys: manifest.Chunks.Select(chunk => chunk.RecordKey).ToArray(),
schemaIds: new[] { CultMeshCdnSchemaVersions.ArtifactChunk })
.GetAwaiter().GetResult();
return ResolveNetworkBody(descriptor, binding, manifest, chunks);
}
private static byte[] ResolveNetworkBody(
CultMeshBodyDescriptor descriptor,
CultMeshNetworkBodyDocument binding,
CultMeshCdnArtifactManifest manifest,
IReadOnlyList<CultMeshCdnArtifactChunk> chunks)
{
var registry = CultMesh.CreateCultCacheDocumentRegistry(
typeof(CultMeshNetworkBodyDocument),
typeof(CultMeshCdnArtifactManifest),
typeof(CultMeshCdnArtifactChunk));
var cache = new CultCache(registry);
cache.UpsertAsync(binding, new CultRecordHandle<CultMeshNetworkBodyDocument>(binding.RecordKey))
.GetAwaiter().GetResult();
cache.UpsertAsync(manifest, new CultRecordHandle<CultMeshCdnArtifactManifest>(
CultMeshCdnArtifactManifest.CreateRecordKey(manifest)))
.GetAwaiter().GetResult();
foreach (var chunk in chunks)
cache.UpsertAsync(chunk, new CultRecordHandle<CultMeshCdnArtifactChunk>(
CultMeshCdnArtifactChunk.CreateRecordKey(chunk)))
.GetAwaiter().GetResult();
return new CultMeshNetworkBodyResolver(cache).Fetch(descriptor);
}
private void PublishEntityView(EveEntitySoaViewDocument document)
{
ResolveAdvertisement();

View file

@ -57,6 +57,38 @@ namespace GameCult.Eve.UnityScene.Tests
new CultMeshBodyPublicationHandle(view.Buffers[0].BufferId, view.ProducerEpoch, view.Sequence).RecordKey));
}
[Test]
public async System.Threading.Tasks.Task LiveTransportResolvesExactNetworkBodyThroughVerseDocuments()
{
var view = EntityLeaseDocument();
var bytes = Enumerable.Range(0, 32).Select(value => (byte)value).ToArray();
var source = new CultCache();
var generation = new CultMeshBodyGeneration
{
BodyId = view.Buffers[0].BufferId,
ProducerId = view.ProviderId,
SchemaId = view.BodySchemaId,
LayoutVersion = view.LayoutVersion,
Capacity = view.Capacity,
ProducerEpoch = view.ProducerEpoch,
Sequence = view.Sequence,
Synchronization = CultMeshBodySynchronization.TripleBuffer,
LeaseExpiresAtUnixMs = DateTimeOffset.UtcNow.AddMinutes(1).ToUnixTimeMilliseconds()
};
var descriptor = await new CultMeshNetworkBodyPublisher(source, _ => true).PublishAsync(generation, bytes);
var binding = source.Get<CultMeshNetworkBodyDocument>(
CultMeshNetworkBodyDocument.CreateRecordKey(descriptor.CapabilityToken))!;
var manifest = source.Get<CultMeshCdnArtifactManifest>(new CultRecordKey(binding.ManifestRecordKey))!;
var chunks = manifest.Chunks.Select(reference =>
source.Get<CultMeshCdnArtifactChunk>(new CultRecordKey(reference.RecordKey))!).ToArray();
var method = typeof(EveUnityCultMeshLiveProviderTransport)
.GetMethod("ResolveNetworkBody", BindingFlags.NonPublic | BindingFlags.Static)!;
var resolved = (byte[])method.Invoke(null, new object[] { descriptor, binding, manifest, chunks })!;
Assert.That(resolved, Is.EqualTo(bytes));
}
[Test]
public void EntitySoaViewReadsGenericSemanticColumnsFromInjectedLease()
{

View file

@ -1,7 +1,7 @@
{
"name": "org.gamecult.eve.unity-scene",
"displayName": "Eve Unity Scene Lowering",
"version": "0.2.2",
"version": "0.2.3",
"unity": "2021.3",
"description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.",
"dependencies": {