Add Unity playable world presentation boundary
This commit is contained in:
parent
5f29e2defc
commit
eef8a5b7aa
11 changed files with 346 additions and 82 deletions
|
|
@ -613,11 +613,15 @@ Recently cut:
|
|||
`EveUnitySceneClientSession` now consumes provider surface snapshots and emits
|
||||
movement/focus/target/action intents through the advertised command boundary,
|
||||
while `EveUnitySceneProviderConnection` defines the generic surface source
|
||||
and command sink ports that a CultMesh/CultNet adapter must implement. The
|
||||
Unity client boundary is generic before it learns live transport. The next
|
||||
blocker is the live generic Unity player loop: implement that CultMesh/CultNet
|
||||
adapter, instantiate the projected world in Unity, and wait for provider
|
||||
receipts/next frames rather than renderer-local simulation.
|
||||
and command sink ports that a CultMesh/CultNet adapter must implement.
|
||||
`EveUnityPlayableWorldPresenter` now maps provider-authored entity rows and
|
||||
asset refs into scene sink operations, including removal of entities absent
|
||||
from later provider snapshots, without importing Aetheria entity/prefab
|
||||
classes. The Unity client boundary is generic before it learns live transport.
|
||||
The next blocker is the live generic Unity player loop: implement that
|
||||
CultMesh/CultNet adapter, provide Unity `GameObject`/prefab-backed scene sink
|
||||
and asset resolver implementations, and wait for provider receipts/next frames
|
||||
rather than renderer-local simulation.
|
||||
- EveElectron capture lifecycle now carries the same kind of structured pending
|
||||
capture contract. `captureContract` names the Electron shell runtime, capture
|
||||
kind, PNG artifact pattern, conformance attachment point, required Aetheria
|
||||
|
|
|
|||
|
|
@ -484,9 +484,12 @@ active surface and emits `gamecult.eve.command.v1` intents without Aetheria
|
|||
types. It also declares `providerSurfaceSource` through
|
||||
`EveUnitySceneProviderConnection`, `IEveUnitySceneProviderSurfaceSource`, and
|
||||
`IEveUnitySceneCommandSink`, so the live CultMesh/CultNet adapter has a narrow
|
||||
runtime-owned port to implement. The remaining blocker is that live adapter,
|
||||
Unity player instantiation, and Unity screenshot or frame-capture PNG production
|
||||
from EveUnity.
|
||||
runtime-owned port to implement. The runtime now also declares
|
||||
`playableWorldScenePresentation`: `EveUnityPlayableWorldPresenter` maps
|
||||
provider-authored entity rows and asset refs into scene sink operations while
|
||||
removing entities absent from later provider snapshots. The remaining blocker is
|
||||
that live adapter, Unity `GameObject`/prefab-backed scene sink and asset
|
||||
resolver, and Unity screenshot or frame-capture PNG production from EveUnity.
|
||||
|
||||
Runtime capture probe coverage is exported as `runtimeCaptureProbeCoverage[]`.
|
||||
Each record joins runtime status, capture owner, lifecycle capture contract,
|
||||
|
|
|
|||
|
|
@ -163,14 +163,19 @@ radii, asset refs, controllability, and command affordances. The generic
|
|||
`gamecult.eve.command.v1` intents through the advertised command boundary.
|
||||
`EveUnitySceneProviderConnection` adds the live-source port shape:
|
||||
`IEveUnitySceneProviderSurfaceSource` supplies current and updated snapshots,
|
||||
while `IEveUnitySceneCommandSink` receives command envelopes. Aetheria-specific
|
||||
names appear only as provider-authored data and command ids; the Unity client
|
||||
code does not import Aetheria runtime types or apply movement locally.
|
||||
while `IEveUnitySceneCommandSink` receives command envelopes.
|
||||
`EveUnityPlayableWorldPresenter` maps the provider-authored entity rows and
|
||||
asset refs into scene operations through `IEveUnityPlayableWorldSceneSink` and
|
||||
`IEveUnityPlayableWorldAssetResolver`, including removal of entities that
|
||||
disappear from later provider snapshots. Aetheria-specific names appear only as
|
||||
provider-authored data and command ids; the Unity client code does not import
|
||||
Aetheria runtime types, prefab classes, or apply movement locally.
|
||||
|
||||
This is not yet the final playable client. The remaining cut is a live
|
||||
CultMesh/CultNet provider subscription adapter implementing those source/sink
|
||||
ports, Unity player instantiation of the projected world, and proof that daemon
|
||||
receipts drive the next frame rather than renderer-local state.
|
||||
ports, Unity `GameObject`/prefab-backed implementations of the scene sink and
|
||||
asset resolver, and proof that daemon receipts drive the next frame rather than
|
||||
renderer-local state.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace GameCult.Eve.UnityScene
|
||||
{
|
||||
public interface IEveUnityPlayableWorldSceneSink
|
||||
{
|
||||
void ConfigureWorld(EveUnityPlayableWorldProjection world);
|
||||
|
||||
void UpsertEntity(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset);
|
||||
|
||||
void RemoveEntity(string entityId);
|
||||
}
|
||||
|
||||
public interface IEveUnityPlayableWorldAssetResolver
|
||||
{
|
||||
EveUnityPlayableWorldAssetBinding Resolve(EveUnityPlayableWorldEntity entity);
|
||||
}
|
||||
|
||||
public sealed class EveUnityPlayableWorldPresenter
|
||||
{
|
||||
private readonly IEveUnityPlayableWorldSceneSink _sceneSink;
|
||||
private readonly IEveUnityPlayableWorldAssetResolver _assetResolver;
|
||||
private readonly HashSet<string> _knownEntityIds = new HashSet<string>(StringComparer.Ordinal);
|
||||
|
||||
public EveUnityPlayableWorldPresenter(
|
||||
IEveUnityPlayableWorldSceneSink sceneSink,
|
||||
IEveUnityPlayableWorldAssetResolver assetResolver)
|
||||
{
|
||||
_sceneSink = sceneSink ?? throw new ArgumentNullException(nameof(sceneSink));
|
||||
_assetResolver = assetResolver ?? throw new ArgumentNullException(nameof(assetResolver));
|
||||
}
|
||||
|
||||
public EveUnityPlayableWorldPresentation Apply(EveUnitySceneProjection projection)
|
||||
{
|
||||
if (projection == null) throw new ArgumentNullException(nameof(projection));
|
||||
if (projection.PlayableWorld == null)
|
||||
throw new InvalidOperationException("Unity playable world presentation requires a playableWorld projection.");
|
||||
|
||||
return Apply(projection.PlayableWorld);
|
||||
}
|
||||
|
||||
public EveUnityPlayableWorldPresentation Apply(EveUnityPlayableWorldProjection world)
|
||||
{
|
||||
if (world == null) throw new ArgumentNullException(nameof(world));
|
||||
|
||||
var nextEntityIds = new HashSet<string>(StringComparer.Ordinal);
|
||||
_sceneSink.ConfigureWorld(world);
|
||||
|
||||
var upserted = 0;
|
||||
foreach (var entity in world.Entities)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(entity.EntityId))
|
||||
continue;
|
||||
|
||||
nextEntityIds.Add(entity.EntityId);
|
||||
_sceneSink.UpsertEntity(entity, _assetResolver.Resolve(entity));
|
||||
upserted++;
|
||||
}
|
||||
|
||||
var removed = 0;
|
||||
var previousEntityIds = new List<string>(_knownEntityIds);
|
||||
foreach (var entityId in previousEntityIds)
|
||||
{
|
||||
if (nextEntityIds.Contains(entityId))
|
||||
continue;
|
||||
|
||||
_sceneSink.RemoveEntity(entityId);
|
||||
_knownEntityIds.Remove(entityId);
|
||||
removed++;
|
||||
}
|
||||
|
||||
foreach (var entityId in nextEntityIds)
|
||||
_knownEntityIds.Add(entityId);
|
||||
|
||||
return new EveUnityPlayableWorldPresentation(
|
||||
world.WorldRootId,
|
||||
world.PlayerEntityId,
|
||||
world.InputProfile,
|
||||
world.CameraRig,
|
||||
upserted,
|
||||
removed,
|
||||
_knownEntityIds.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class EveUnityPlayableWorldAssetBinding
|
||||
{
|
||||
public EveUnityPlayableWorldAssetBinding(
|
||||
string assetRef,
|
||||
string entityKind,
|
||||
string presentationKind)
|
||||
{
|
||||
AssetRef = assetRef ?? "";
|
||||
EntityKind = entityKind ?? "";
|
||||
PresentationKind = presentationKind ?? "";
|
||||
}
|
||||
|
||||
public string AssetRef { get; }
|
||||
|
||||
public string EntityKind { get; }
|
||||
|
||||
public string PresentationKind { get; }
|
||||
}
|
||||
|
||||
public sealed class EveUnityPlayableWorldPresentation
|
||||
{
|
||||
public EveUnityPlayableWorldPresentation(
|
||||
string worldRootId,
|
||||
string playerEntityId,
|
||||
string inputProfile,
|
||||
string cameraRig,
|
||||
int upsertedEntities,
|
||||
int removedEntities,
|
||||
int activeEntities)
|
||||
{
|
||||
WorldRootId = worldRootId ?? "";
|
||||
PlayerEntityId = playerEntityId ?? "";
|
||||
InputProfile = inputProfile ?? "";
|
||||
CameraRig = cameraRig ?? "";
|
||||
UpsertedEntities = upsertedEntities;
|
||||
RemovedEntities = removedEntities;
|
||||
ActiveEntities = activeEntities;
|
||||
}
|
||||
|
||||
public string WorldRootId { get; }
|
||||
|
||||
public string PlayerEntityId { get; }
|
||||
|
||||
public string InputProfile { get; }
|
||||
|
||||
public string CameraRig { get; }
|
||||
|
||||
public int UpsertedEntities { get; }
|
||||
|
||||
public int RemovedEntities { get; }
|
||||
|
||||
public int ActiveEntities { get; }
|
||||
}
|
||||
|
||||
public sealed class EveUnityAssetRefResolver : IEveUnityPlayableWorldAssetResolver
|
||||
{
|
||||
public EveUnityPlayableWorldAssetBinding Resolve(EveUnityPlayableWorldEntity entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException(nameof(entity));
|
||||
return new EveUnityPlayableWorldAssetBinding(
|
||||
entity.AssetRef,
|
||||
entity.EntityKind,
|
||||
string.IsNullOrWhiteSpace(entity.AssetRef) ? "unity-generated-placeholder" : "provider-asset-ref");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -198,6 +198,46 @@ namespace GameCult.Eve.UnityScene.Tests
|
|||
Assert.That(projectionUpdates, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities()
|
||||
{
|
||||
var lowerer = new EveUnitySceneSurfaceLowerer();
|
||||
var sink = new FakePlayableWorldSceneSink();
|
||||
var presenter = new EveUnityPlayableWorldPresenter(sink, new EveUnityAssetRefResolver());
|
||||
|
||||
var firstProjection = lowerer.Lower(PlayableArpgDocument(), Advertisement("aetheria.daemon.game"));
|
||||
var firstPresentation = presenter.Apply(firstProjection);
|
||||
|
||||
Assert.That(firstPresentation.WorldRootId, Is.EqualTo("aetheria.daemon.game.playable"));
|
||||
Assert.That(firstPresentation.PlayerEntityId, Is.EqualTo("player-vanguard"));
|
||||
Assert.That(firstPresentation.InputProfile, Is.EqualTo("arpg-third-person"));
|
||||
Assert.That(firstPresentation.CameraRig, Is.EqualTo("third-person-orbit"));
|
||||
Assert.That(firstPresentation.UpsertedEntities, Is.EqualTo(3));
|
||||
Assert.That(firstPresentation.RemovedEntities, Is.EqualTo(0));
|
||||
Assert.That(firstPresentation.ActiveEntities, Is.EqualTo(3));
|
||||
Assert.That(sink.ConfiguredWorlds.Count, Is.EqualTo(1));
|
||||
Assert.That(sink.Upserts.Count, Is.EqualTo(3));
|
||||
Assert.That(sink.Upserts[0].entity.EntityId, Is.EqualTo("player-vanguard"));
|
||||
Assert.That(sink.Upserts[0].entity.PositionX, Is.EqualTo(0f));
|
||||
Assert.That(sink.Upserts[0].asset.AssetRef, Is.EqualTo("cultmesh://aetheria/assets/map/entity/player"));
|
||||
Assert.That(sink.Upserts[0].asset.PresentationKind, Is.EqualTo("provider-asset-ref"));
|
||||
|
||||
var secondProjection = lowerer.Lower(
|
||||
PlayableArpgDocument(includeRaider: false, playerPosition: "5,0,2"),
|
||||
Advertisement("aetheria.daemon.game"));
|
||||
var secondPresentation = presenter.Apply(secondProjection);
|
||||
|
||||
Assert.That(secondPresentation.UpsertedEntities, Is.EqualTo(2));
|
||||
Assert.That(secondPresentation.RemovedEntities, Is.EqualTo(1));
|
||||
Assert.That(secondPresentation.ActiveEntities, Is.EqualTo(2));
|
||||
Assert.That(sink.ConfiguredWorlds.Count, Is.EqualTo(2));
|
||||
Assert.That(sink.RemovedEntityIds.Count, Is.EqualTo(1));
|
||||
Assert.That(sink.RemovedEntityIds[0], Is.EqualTo("raider-scout"));
|
||||
Assert.That(sink.Upserts[3].entity.EntityId, Is.EqualTo("player-vanguard"));
|
||||
Assert.That(sink.Upserts[3].entity.PositionX, Is.EqualTo(5f));
|
||||
Assert.That(sink.Upserts[3].entity.PositionZ, Is.EqualTo(2f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState()
|
||||
{
|
||||
|
|
@ -323,8 +363,79 @@ namespace GameCult.Eve.UnityScene.Tests
|
|||
Array.Empty<EveCommandTemplate>());
|
||||
}
|
||||
|
||||
private static EveSurfaceDocument PlayableArpgDocument()
|
||||
private static EveSurfaceDocument PlayableArpgDocument(
|
||||
bool includeRaider = true,
|
||||
string playerPosition = "0,0,0")
|
||||
{
|
||||
var playableChildren = new List<EveSurfaceComponent>
|
||||
{
|
||||
PlayableEntity(
|
||||
"aetheria.daemon.game.entity.player",
|
||||
"player-vanguard",
|
||||
"player",
|
||||
"Vanguard",
|
||||
"player",
|
||||
"cultmesh://aetheria/assets/map/entity/player",
|
||||
playerPosition,
|
||||
"35",
|
||||
"1.15",
|
||||
true,
|
||||
true,
|
||||
"aetheria.daemon.focus",
|
||||
"aetheria.daemon.move_intent",
|
||||
"",
|
||||
"")
|
||||
};
|
||||
|
||||
if (includeRaider)
|
||||
{
|
||||
playableChildren.Add(PlayableEntity(
|
||||
"aetheria.daemon.game.entity.raider",
|
||||
"raider-scout",
|
||||
"enemy",
|
||||
"Raider Scout",
|
||||
"raider",
|
||||
"cultmesh://aetheria/assets/map/entity/ship",
|
||||
"9,0,14",
|
||||
"220",
|
||||
"0.9",
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"aetheria.daemon.target",
|
||||
""));
|
||||
}
|
||||
|
||||
playableChildren.Add(PlayableEntity(
|
||||
"aetheria.daemon.game.entity.station",
|
||||
"anchor-station",
|
||||
"station",
|
||||
"Anchor Station",
|
||||
"neutral",
|
||||
"cultmesh://aetheria/assets/map/entity/station",
|
||||
"-18,0,6",
|
||||
"0",
|
||||
"3.4",
|
||||
true,
|
||||
false,
|
||||
"aetheria.daemon.focus",
|
||||
"",
|
||||
"",
|
||||
""));
|
||||
|
||||
playableChildren.Add(new EveSurfaceComponent(
|
||||
"aetheria.daemon.game.flow",
|
||||
"field.vector3d",
|
||||
new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["fieldId"] = "aetheria.zone.flow",
|
||||
["bind"] = "aetheria.daemon.soaView.flowField3d",
|
||||
["visualizer"] = "particles",
|
||||
["bounds"] = "-32,0,-32,32,24,32"
|
||||
},
|
||||
Array.Empty<EveSurfaceComponent>()));
|
||||
|
||||
return new EveSurfaceDocument(
|
||||
"aetheria",
|
||||
"game.runtime",
|
||||
|
|
@ -354,68 +465,7 @@ namespace GameCult.Eve.UnityScene.Tests
|
|||
["targetCommand"] = "aetheria.daemon.target",
|
||||
["actionCommand"] = "aetheria.daemon.use_equipment"
|
||||
},
|
||||
new[]
|
||||
{
|
||||
PlayableEntity(
|
||||
"aetheria.daemon.game.entity.player",
|
||||
"player-vanguard",
|
||||
"player",
|
||||
"Vanguard",
|
||||
"player",
|
||||
"cultmesh://aetheria/assets/map/entity/player",
|
||||
"0,0,0",
|
||||
"35",
|
||||
"1.15",
|
||||
true,
|
||||
true,
|
||||
"aetheria.daemon.focus",
|
||||
"aetheria.daemon.move_intent",
|
||||
"",
|
||||
""),
|
||||
PlayableEntity(
|
||||
"aetheria.daemon.game.entity.raider",
|
||||
"raider-scout",
|
||||
"enemy",
|
||||
"Raider Scout",
|
||||
"raider",
|
||||
"cultmesh://aetheria/assets/map/entity/ship",
|
||||
"9,0,14",
|
||||
"220",
|
||||
"0.9",
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"aetheria.daemon.target",
|
||||
""),
|
||||
PlayableEntity(
|
||||
"aetheria.daemon.game.entity.station",
|
||||
"anchor-station",
|
||||
"station",
|
||||
"Anchor Station",
|
||||
"neutral",
|
||||
"cultmesh://aetheria/assets/map/entity/station",
|
||||
"-18,0,6",
|
||||
"0",
|
||||
"3.4",
|
||||
true,
|
||||
false,
|
||||
"aetheria.daemon.focus",
|
||||
"",
|
||||
"",
|
||||
""),
|
||||
new EveSurfaceComponent(
|
||||
"aetheria.daemon.game.flow",
|
||||
"field.vector3d",
|
||||
new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["fieldId"] = "aetheria.zone.flow",
|
||||
["bind"] = "aetheria.daemon.soaView.flowField3d",
|
||||
["visualizer"] = "particles",
|
||||
["bounds"] = "-32,0,-32,32,24,32"
|
||||
},
|
||||
Array.Empty<EveSurfaceComponent>())
|
||||
},
|
||||
playableChildren,
|
||||
new[]
|
||||
{
|
||||
new CultMeshStateBindingDescriptor("run", "cultmesh://aetheria/run/current"),
|
||||
|
|
@ -605,5 +655,30 @@ namespace GameCult.Eve.UnityScene.Tests
|
|||
Submitted.Add(request);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class FakePlayableWorldSceneSink : IEveUnityPlayableWorldSceneSink
|
||||
{
|
||||
public List<EveUnityPlayableWorldProjection> ConfiguredWorlds { get; } = new List<EveUnityPlayableWorldProjection>();
|
||||
|
||||
public List<(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset)> Upserts { get; } =
|
||||
new List<(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset)>();
|
||||
|
||||
public List<string> RemovedEntityIds { get; } = new List<string>();
|
||||
|
||||
public void ConfigureWorld(EveUnityPlayableWorldProjection world)
|
||||
{
|
||||
ConfiguredWorlds.Add(world);
|
||||
}
|
||||
|
||||
public void UpsertEntity(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset)
|
||||
{
|
||||
Upserts.Add((entity, asset));
|
||||
}
|
||||
|
||||
public void RemoveEntity(string entityId)
|
||||
{
|
||||
RemovedEntityIds.Add(entityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
"providerSurfaceSource",
|
||||
"sceneGraphProjection",
|
||||
"playableWorldProjection",
|
||||
"playableWorldScenePresentation",
|
||||
"embeddedDocuments"
|
||||
],
|
||||
"supportedPlugins": [
|
||||
|
|
@ -63,6 +64,7 @@
|
|||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
|
||||
|
|
@ -111,6 +113,7 @@
|
|||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
|
||||
|
|
@ -148,6 +151,7 @@
|
|||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
|
||||
|
|
@ -36,6 +37,7 @@
|
|||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef",
|
||||
"tools/eveunity/eveunity-release-contract.mjs",
|
||||
"tools/eveunity/eveunity-release-contract.test.mjs",
|
||||
|
|
@ -54,6 +56,7 @@
|
|||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
|
||||
|
|
@ -61,7 +64,7 @@
|
|||
"runtimes/incubating/eve-unity-scene/eve-runtime-capability.json"
|
||||
],
|
||||
"destinationOwner": "EveUnity",
|
||||
"replacementProof": "EveUnity claims the provider-advertised unity-scene lowering target with provider-agnostic playable-world projection, scene graph projection, provider snapshot session, and command boundary evidence; live transport and capture remain separate lifecycle proofs."
|
||||
"replacementProof": "EveUnity claims the provider-advertised unity-scene lowering target with provider-agnostic playable-world projection, scene graph projection, provider snapshot session, playable-world scene presentation, and command boundary evidence; live transport and capture remain separate lifecycle proofs."
|
||||
},
|
||||
{
|
||||
"id": "unity-scene-sai-plugin-projection",
|
||||
|
|
@ -150,6 +153,7 @@
|
|||
"EveUnity owns a provider-agnostic scene graph lowerer that consumes advertised worldInteraction boundaries without importing Aetheria internals.",
|
||||
"EveUnity owns a provider-snapshot Unity scene client session that lowers Aetheria's surface and emits command intents without importing Aetheria project code.",
|
||||
"EveUnity owns provider surface source and command sink ports that a live CultMesh/CultNet adapter can implement without changing scene lowering.",
|
||||
"EveUnity owns a playable-world presenter that maps provider-authored entity rows and asset refs into Unity scene operations without importing Aetheria entity or prefab classes.",
|
||||
"EveUnity owns the provider-agnostic playable-world scene lowerer outside Eve incubation.",
|
||||
"EveUnity owns the Unity scene Sai projection adapter outside Eve incubation without importing Sai story state or VN/Ink internals.",
|
||||
"EveUnity owns the Unity scene Norn projection adapter outside Eve incubation without importing Norn implementation state.",
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ if ($manifest.incubation.splitHandoff.manifestPath -ne "runtimes/incubating/eve-
|
|||
throw "EveUnity scene manifest missing split handoff path"
|
||||
}
|
||||
|
||||
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "embeddedDocuments")) {
|
||||
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "embeddedDocuments")) {
|
||||
if (-not (@($manifest.supportedFeatures) -contains $feature)) {
|
||||
throw "EveUnity scene manifest missing provider-shell feature: $feature"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ foreach ($evidencePath in @($worldSurfaceLoweringClaim.evidencePaths)) {
|
|||
}
|
||||
}
|
||||
|
||||
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection")) {
|
||||
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation")) {
|
||||
if (-not (@($manifest.supportedFeatures) -contains $feature)) {
|
||||
throw "EveUnity scene provider shell missing supported feature: $feature"
|
||||
}
|
||||
|
|
@ -66,6 +66,7 @@ $expectedFiles = @(
|
|||
"runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneSurfaceLowerer.cs",
|
||||
"runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneClientSession.cs",
|
||||
"runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneProviderConnection.cs",
|
||||
"runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldPresenter.cs",
|
||||
"runtimes\incubating\eve-unity-scene\Runtime\SaiVisualNovelUnitySceneProjectionAdapter.cs",
|
||||
"runtimes\incubating\eve-unity-scene\Runtime\NornGraphUnitySceneProjectionAdapter.cs",
|
||||
"runtimes\incubating\eve-unity-scene\Runtime\TeXMathUnitySceneProjectionAdapter.cs",
|
||||
|
|
@ -101,6 +102,13 @@ foreach ($symbol in @("IEveUnitySceneProviderSurfaceSource", "IEveUnitySceneComm
|
|||
}
|
||||
}
|
||||
|
||||
$playableWorldPresenterSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldPresenter.cs") -Raw
|
||||
foreach ($symbol in @("IEveUnityPlayableWorldSceneSink", "IEveUnityPlayableWorldAssetResolver", "EveUnityPlayableWorldPresenter", "EveUnityPlayableWorldAssetBinding", "EveUnityPlayableWorldPresentation", "EveUnityAssetRefResolver", "ConfigureWorld", "UpsertEntity", "RemoveEntity", "provider-asset-ref", "unity-generated-placeholder")) {
|
||||
if (-not $playableWorldPresenterSource.Contains($symbol)) {
|
||||
throw "EveUnity playable world presenter missing symbol: $symbol"
|
||||
}
|
||||
}
|
||||
|
||||
$saiAdapterSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\SaiVisualNovelUnitySceneProjectionAdapter.cs") -Raw
|
||||
foreach ($symbol in @("SaiVisualNovelUnitySceneProjectionAdapter", "sai.vn", "vn.stage", "story.choose", "story.continue", "story.jump", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "Sai")) {
|
||||
if (-not $saiAdapterSource.Contains($symbol)) {
|
||||
|
|
@ -123,7 +131,7 @@ foreach ($symbol in @("TeXMathUnitySceneProjectionAdapter", "tex.math", "embed.t
|
|||
}
|
||||
|
||||
$testSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Tests\Editor\EveUnitySceneSurfaceLowererTests.cs") -Raw
|
||||
foreach ($symbol in @("LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "FakeProviderSurfaceSource", "FakeCommandSink", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "playable-world-root", "playable-world-entity", "world-field-3d", "arpg-third-person", "cultmesh://aetheria/assets/manifest", "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", "aetheria.daemon.move_intent", "sai-vn-scene-stage", "norn-graph-scene-projection", "tex-math-scene-projection", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1")) {
|
||||
foreach ($symbol in @("LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "FakeProviderSurfaceSource", "FakeCommandSink", "FakePlayableWorldSceneSink", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "playable-world-root", "playable-world-entity", "world-field-3d", "arpg-third-person", "cultmesh://aetheria/assets/manifest", "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", "aetheria.daemon.move_intent", "sai-vn-scene-stage", "norn-graph-scene-projection", "tex-math-scene-projection", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1")) {
|
||||
if (-not $testSource.Contains($symbol)) {
|
||||
throw "EveUnity scene provider shell tests missing symbol: $symbol"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ node $consumerScript $consumerExport `
|
|||
--expect-runtime-feature unity-scene:providerSurfaceSource `
|
||||
--expect-runtime-feature unity-scene:sceneGraphProjection `
|
||||
--expect-runtime-feature unity-scene:playableWorldProjection `
|
||||
--expect-runtime-feature unity-scene:playableWorldScenePresentation `
|
||||
--expect-runtime-feature electron-shell:providerAdvertisements `
|
||||
--expect-runtime-feature electron-shell:commandTransport `
|
||||
--expect-runtime-feature electron-shell:surfaceTreeProjection `
|
||||
|
|
|
|||
|
|
@ -1040,7 +1040,7 @@
|
|||
"splitHandoffPath": "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json",
|
||||
"requiredFixtures": ["aetheria-world", "eve-world-smoke"],
|
||||
"pluginFixtures": ["sai-vn"],
|
||||
"supportedFeatures": ["providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "embeddedDocuments"],
|
||||
"supportedFeatures": ["providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "embeddedDocuments"],
|
||||
"supportedPlugins": [
|
||||
{
|
||||
"pluginId": "sai.vn",
|
||||
|
|
@ -1070,6 +1070,7 @@
|
|||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
|
||||
|
|
@ -1085,6 +1086,7 @@
|
|||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
|
||||
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
|
||||
|
|
@ -1120,6 +1122,10 @@
|
|||
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
|
||||
"contains": ["IEveUnitySceneProviderSurfaceSource", "IEveUnitySceneCommandSink", "EveUnitySceneProviderConnection", "SnapshotAvailable", "CurrentSnapshot", "Connect", "Refresh", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Disconnect"]
|
||||
},
|
||||
{
|
||||
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
|
||||
"contains": ["IEveUnityPlayableWorldSceneSink", "IEveUnityPlayableWorldAssetResolver", "EveUnityPlayableWorldPresenter", "EveUnityPlayableWorldAssetBinding", "EveUnityPlayableWorldPresentation", "EveUnityAssetRefResolver", "ConfigureWorld", "UpsertEntity", "RemoveEntity", "provider-asset-ref", "unity-generated-placeholder"]
|
||||
},
|
||||
{
|
||||
"path": "runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
|
||||
"contains": ["SaiVisualNovelUnitySceneProjectionAdapter", "sai.vn", "vn.stage", "story.choose", "story.continue", "story.jump", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "Sai"]
|
||||
|
|
@ -1134,7 +1140,7 @@
|
|||
},
|
||||
{
|
||||
"path": "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
|
||||
"contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "FakeProviderSurfaceSource", "FakeCommandSink", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "playable-world-root", "playable-world-entity", "world-field-3d", "arpg-third-person", "cultmesh://aetheria/assets/manifest", "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", "aetheria.daemon.move_intent", "sai-vn-scene-stage", "norn-graph-scene-projection", "tex-math-scene-projection", "norn.map", "cultmesh://aetheria/norn/map", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1"]
|
||||
"contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "FakeProviderSurfaceSource", "FakeCommandSink", "FakePlayableWorldSceneSink", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "playable-world-root", "playable-world-entity", "world-field-3d", "arpg-third-person", "cultmesh://aetheria/assets/manifest", "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", "aetheria.daemon.move_intent", "sai-vn-scene-stage", "norn-graph-scene-projection", "tex-math-scene-projection", "norn.map", "cultmesh://aetheria/norn/map", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1"]
|
||||
},
|
||||
{
|
||||
"path": "tools/eveunity/eveunity-capture-contract.test.mjs",
|
||||
|
|
|
|||
Loading…
Reference in a new issue