Subscribe Unity clients to negotiated hot bodies

This commit is contained in:
Meta Vens 2026-07-19 03:18:35 +01:00
commit b2dd92af02
4 changed files with 37 additions and 13 deletions

View file

@ -612,14 +612,10 @@ namespace GameCult.Eve.UnityScene
if (document.Buffers == null || document.Buffers.Length == 0)
throw new InvalidOperationException("Entity layout does not name a primary logical buffer.");
var handle = BodyPublicationHandle(document);
var publication = _node!.Database.Cache.Get<CultMeshBodyPublicationDocument>(handle.RecordKey)
?? _snapshot!
.FetchDocumentsAsync<CultMeshBodyPublicationDocument>(
recordKeys: new[] { handle.RecordKey.Value },
schemaIds: new[] { CultMeshBodyPublicationSchemaVersions.Publication })
.GetAwaiter().GetResult().FirstOrDefault()
var publicationKey = CultMeshBodyPublicationDocument.CreateLatestRecordKey(handle.BodyId);
var publication = _node!.Database.Cache.Get<CultMeshBodyPublicationDocument>(publicationKey)
?? throw new InvalidOperationException(
$"Provider did not publish CultMesh body generation '{handle.RecordKey.Value}'.");
$"Subscribed CultMesh body publication '{publicationKey.Value}' is missing for generation {handle.Sequence}.");
handle.Validate(publication);
var now = DateTimeOffset.UtcNow;
if (!IsPublicationLive(publication, now))
@ -718,12 +714,34 @@ namespace GameCult.Eve.UnityScene
string entityViewPointer = lowered.PlayableWorld == null
? ""
: lowered.PlayableWorld.EntityViewPointerId;
string entityBodyId = lowered.PlayableWorld == null
? ""
: lowered.PlayableWorld.EntityBodyId;
if (!string.IsNullOrWhiteSpace(entityViewPointer))
{
if (string.IsNullOrWhiteSpace(entityBodyId))
throw new InvalidOperationException(
"The playable world advertises an entity-view pointer without its logical body id.");
_entitySubscriptions.SubscribeAsync(
"eve-unity-entity-view",
recordKeys: new[] { entityViewPointer },
schemaIds: new[] { EveEntitySoaViewDocument.SchemaId })
recordKeys: new[]
{
entityViewPointer,
CultMeshBodyPublicationDocument.CreateLatestRecordKey(
entityBodyId).Value
},
schemaIds: new[]
{
EveEntitySoaViewDocument.SchemaId,
CultMeshBodyPublicationSchemaVersions.Publication
},
consumerRuntimeId: _runtimeId,
bodyIds: new[] { entityBodyId },
supportedBodyTransports: new[]
{
CultMeshBodyTransportKind.SharedMemory.ToString(),
CultMeshBodyTransportKind.Network.ToString()
})
.GetAwaiter().GetResult();
var current = _node!.Database.Cache.Get(new CultRecordKey(entityViewPointer)) as EveEntitySoaViewDocument
?? _snapshot!

View file

@ -131,6 +131,7 @@ namespace GameCult.Eve.UnityScene
entities,
worldRoot.GetProp("entityViewPointerId"),
worldRoot.GetProp("entityViewSchema"),
worldRoot.GetProp("entityBodyId"),
worldRoot.GetProp("zoneRenderPointerId"),
worldRoot.GetProp("zoneRenderSchema"),
ParseStringList(worldRoot.GetProp("excludedRenderChannels")),
@ -401,6 +402,7 @@ namespace GameCult.Eve.UnityScene
IReadOnlyList<EveUnityPlayableWorldEntity> entities,
string entityViewPointerId = "",
string entityViewSchema = "",
string entityBodyId = "",
string zoneRenderPointerId = "",
string zoneRenderSchema = "",
IReadOnlyList<string>? excludedRenderChannels = null,
@ -457,6 +459,7 @@ namespace GameCult.Eve.UnityScene
Entities = entities ?? Array.Empty<EveUnityPlayableWorldEntity>();
EntityViewPointerId = entityViewPointerId ?? "";
EntityViewSchema = entityViewSchema ?? "";
EntityBodyId = entityBodyId ?? "";
ZoneRenderPointerId = zoneRenderPointerId ?? "";
ZoneRenderSchema = zoneRenderSchema ?? "";
ExcludedRenderChannels = excludedRenderChannels ?? Array.Empty<string>();
@ -514,6 +517,8 @@ namespace GameCult.Eve.UnityScene
public string EntityViewSchema { get; }
public string EntityBodyId { get; }
public string ZoneRenderPointerId { get; }
public string ZoneRenderSchema { get; }

View file

@ -424,6 +424,7 @@ namespace GameCult.Eve.UnityScene.Tests
Assert.That(projection.PlayableWorld.StatePointerId, Is.EqualTo("cultmesh://aetheria/run/current"));
Assert.That(projection.PlayableWorld.EntityViewPointerId, Is.EqualTo("cultmesh://aetheria/world/entities.soa"));
Assert.That(projection.PlayableWorld.EntityViewSchema, Is.EqualTo(EveEntitySoaViewDocument.SchemaId));
Assert.That(projection.PlayableWorld.EntityBodyId, Is.EqualTo("eve:entity-soa:aetheria.daemon:pilot"));
Assert.That(projection.PlayableWorld.ZoneRenderPointerId, Is.EqualTo("cultmesh://aetheria/world/zone-render"));
Assert.That(projection.PlayableWorld.AssetManifest, Is.EqualTo("cultmesh://aetheria/assets/manifest"));
Assert.That(projection.PlayableWorld.InputProfile, Is.EqualTo("arpg-third-person"));
@ -2324,6 +2325,7 @@ namespace GameCult.Eve.UnityScene.Tests
["statePointerId"] = "cultmesh://aetheria/run/current",
["entityViewPointerId"] = "cultmesh://aetheria/world/entities.soa",
["entityViewSchema"] = EveEntitySoaViewDocument.SchemaId,
["entityBodyId"] = "eve:entity-soa:aetheria.daemon:pilot",
["zoneRenderPointerId"] = "cultmesh://aetheria/world/zone-render",
["zoneRenderSchema"] = "gamecult.aetheria.zone_render.v1",
["assetManifest"] = "cultmesh://aetheria/assets/manifest",
@ -2849,8 +2851,7 @@ namespace GameCult.Eve.UnityScene.Tests
Sequence = sequence,
Synchronization = descriptor.Synchronization,
LivenessExpiresAtUnixMs = descriptor.LeaseExpiresAtUnixMs,
PreferredLocal = descriptor,
NetworkFallback = network
Representations = new[] { descriptor, network }
};
}

View file

@ -1,11 +1,11 @@
{
"name": "org.gamecult.eve.unity-scene",
"displayName": "Eve Unity Scene Lowering",
"version": "0.3.72",
"version": "0.3.73",
"unity": "6000.0",
"description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.",
"dependencies": {
"org.gamecult.cultlib": "1.0.18",
"org.gamecult.cultlib": "1.0.20",
"org.gamecult.eve.plugin-fields": "0.2.3",
"org.gamecult.eve.surface": "0.2.4",
"com.unity.mathematics": "1.3.2",