From b2dd92af02595d3938a1deba1d67b01bba5ef527 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 19 Jul 2026 03:18:35 +0100 Subject: [PATCH] Subscribe Unity clients to negotiated hot bodies --- .../EveUnityCultMeshLiveProviderTransport.cs | 36 ++++++++++++++----- .../Runtime/EveUnitySceneSurfaceLowerer.cs | 5 +++ .../EveUnitySceneSurfaceLowererTests.cs | 5 +-- .../org.gamecult.eve.unity-scene/package.json | 4 +-- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/packages/org.gamecult.eve.unity-scene/Runtime/CultMesh/EveUnityCultMeshLiveProviderTransport.cs b/packages/org.gamecult.eve.unity-scene/Runtime/CultMesh/EveUnityCultMeshLiveProviderTransport.cs index e085b14..d3a7716 100644 --- a/packages/org.gamecult.eve.unity-scene/Runtime/CultMesh/EveUnityCultMeshLiveProviderTransport.cs +++ b/packages/org.gamecult.eve.unity-scene/Runtime/CultMesh/EveUnityCultMeshLiveProviderTransport.cs @@ -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(handle.RecordKey) - ?? _snapshot! - .FetchDocumentsAsync( - recordKeys: new[] { handle.RecordKey.Value }, - schemaIds: new[] { CultMeshBodyPublicationSchemaVersions.Publication }) - .GetAwaiter().GetResult().FirstOrDefault() + var publicationKey = CultMeshBodyPublicationDocument.CreateLatestRecordKey(handle.BodyId); + var publication = _node!.Database.Cache.Get(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! diff --git a/packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs b/packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs index 713085d..77b9d1f 100644 --- a/packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs +++ b/packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs @@ -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 entities, string entityViewPointerId = "", string entityViewSchema = "", + string entityBodyId = "", string zoneRenderPointerId = "", string zoneRenderSchema = "", IReadOnlyList? excludedRenderChannels = null, @@ -457,6 +459,7 @@ namespace GameCult.Eve.UnityScene Entities = entities ?? Array.Empty(); EntityViewPointerId = entityViewPointerId ?? ""; EntityViewSchema = entityViewSchema ?? ""; + EntityBodyId = entityBodyId ?? ""; ZoneRenderPointerId = zoneRenderPointerId ?? ""; ZoneRenderSchema = zoneRenderSchema ?? ""; ExcludedRenderChannels = excludedRenderChannels ?? Array.Empty(); @@ -514,6 +517,8 @@ namespace GameCult.Eve.UnityScene public string EntityViewSchema { get; } + public string EntityBodyId { get; } + public string ZoneRenderPointerId { get; } public string ZoneRenderSchema { get; } diff --git a/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs b/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs index 3d0d373..566a61f 100644 --- a/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs +++ b/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs @@ -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 } }; } diff --git a/packages/org.gamecult.eve.unity-scene/package.json b/packages/org.gamecult.eve.unity-scene/package.json index 2781bdf..322ad99 100644 --- a/packages/org.gamecult.eve.unity-scene/package.json +++ b/packages/org.gamecult.eve.unity-scene/package.json @@ -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",