Compare commits

...
This repository has been archived on 2026-10-29. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
Author SHA1 Message Date
Meta Vens
e5556c3194 Keep live entity transforms body-owned 2026-07-22 01:02:30 +01:00
Meta Vens
8d0789ba0d Witness the mounted provider cockpit 2026-07-20 05:22:52 +01:00
Meta Vens
c0670fd07c Pin visibly themed Eve cockpit release 2026-07-20 05:06:23 +01:00
9 changed files with 95 additions and 22 deletions

View file

@ -331,15 +331,19 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
provider,
provider);
host.Connect();
var loweredSurface = new EveUiToolkitSurfaceLowerer().Lower(
provider.CurrentDocument.SurfaceDocument,
provider.Submit);
var cockpit = loweredSurface.Q<VisualElement>("aetheria.daemon.game.cockpit");
var mountedOverlay = root.GetComponent<EveUnityUiToolkitOverlay>();
Assert.That(mountedOverlay, Is.Not.Null);
var cockpit = mountedOverlay.Root.Q<VisualElement>("aetheria.daemon.game.cockpit");
Assert.That(cockpit, Is.Not.Null, "The provider did not publish a generic cockpit overlay.");
cockpitProgressCount = cockpit.Query<ProgressBar>().ToList().Count;
Assert.That(cockpitProgressCount, Is.GreaterThanOrEqualTo(7));
Assert.That(loweredSurface.Q<VisualElement>("aetheria.daemon.game.frame").style.display.value,
Is.EqualTo(DisplayStyle.None), "Daemon diagnostics leaked into the pilot UI.");
Assert.That(mountedOverlay.Root.Q<VisualElement>("aetheria.daemon.game.frame").style.display.value,
Is.EqualTo(DisplayStyle.None), "Daemon diagnostics leaked into the mounted pilot UI.");
Assert.That(mountedOverlay.Root.Q<VisualElement>("aetheria.daemon.game.main_menu").style.display.value,
Is.EqualTo(DisplayStyle.None), "The closed main menu leaked into the mounted pilot UI.");
Assert.That(provider.CurrentDocument.SurfaceDocument.Surface.Root.Children
.Single(component => component.Id == "aetheria.daemon.game.frame").Layout["display"],
Is.EqualTo("none"), "Daemon diagnostics leaked into the pilot UI.");
trajectories = root.GetComponent<EveUnityShotTrajectoryRenderer>();
Assert.That(trajectories, Is.Not.Null);
host.ShotAvailable += shot =>
@ -956,6 +960,9 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(captureFieldVolume.CompositeCount - initialCompositeCount,
Is.GreaterThanOrEqualTo(temporalSettlingFrames),
"The pilot capture ran before the advertised temporal reconstruction had settled.");
Assert.That(cockpit.resolvedStyle.display, Is.Not.EqualTo(DisplayStyle.None));
Assert.That(cockpit.worldBound.width, Is.GreaterThan(0),
"The mounted provider cockpit has no visible screen layout.");
Debug.Log($"EveUnity witness phase temporal-settling-128-frames took {temporalSettlingElapsed.Elapsed.TotalMilliseconds:0.###}ms.");
var pilotCaptureElapsed = Stopwatch.StartNew();
yield return null;

View file

@ -9,7 +9,7 @@
"org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.43",
"org.gamecult.eve.plugin-fields": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.3",
"org.gamecult.eve.surface": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.4",
"org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.102",
"org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.103",
"org.gamecult.eve.unity-uitoolkit": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-uitoolkit#eveunity-uitoolkit-v0.1.2"
},
"testables": [

View file

@ -144,7 +144,7 @@
"hash": "e08fa08335f99e9edddeb706912eecfad07cb281"
},
"org.gamecult.eve.unity-scene": {
"version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.102",
"version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.103",
"depth": 0,
"source": "git",
"dependencies": {
@ -156,7 +156,7 @@
"com.unity.render-pipelines.universal": "17.4.0",
"com.unity.modules.particlesystem": "1.0.0"
},
"hash": "ddd2c5871f935978a0640d43cb58e18579523125"
"hash": "050b2019bd6faa4275013516870d1ded245ee391"
},
"org.gamecult.eve.unity-uitoolkit": {
"version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-uitoolkit#eveunity-uitoolkit-v0.1.2",

View file

@ -331,15 +331,19 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
provider,
provider);
host.Connect();
var loweredSurface = new EveUiToolkitSurfaceLowerer().Lower(
provider.CurrentDocument.SurfaceDocument,
provider.Submit);
var cockpit = loweredSurface.Q<VisualElement>("aetheria.daemon.game.cockpit");
var mountedOverlay = root.GetComponent<EveUnityUiToolkitOverlay>();
Assert.That(mountedOverlay, Is.Not.Null);
var cockpit = mountedOverlay.Root.Q<VisualElement>("aetheria.daemon.game.cockpit");
Assert.That(cockpit, Is.Not.Null, "The provider did not publish a generic cockpit overlay.");
cockpitProgressCount = cockpit.Query<ProgressBar>().ToList().Count;
Assert.That(cockpitProgressCount, Is.GreaterThanOrEqualTo(7));
Assert.That(loweredSurface.Q<VisualElement>("aetheria.daemon.game.frame").style.display.value,
Is.EqualTo(DisplayStyle.None), "Daemon diagnostics leaked into the pilot UI.");
Assert.That(mountedOverlay.Root.Q<VisualElement>("aetheria.daemon.game.frame").style.display.value,
Is.EqualTo(DisplayStyle.None), "Daemon diagnostics leaked into the mounted pilot UI.");
Assert.That(mountedOverlay.Root.Q<VisualElement>("aetheria.daemon.game.main_menu").style.display.value,
Is.EqualTo(DisplayStyle.None), "The closed main menu leaked into the mounted pilot UI.");
Assert.That(provider.CurrentDocument.SurfaceDocument.Surface.Root.Children
.Single(component => component.Id == "aetheria.daemon.game.frame").Layout["display"],
Is.EqualTo("none"), "Daemon diagnostics leaked into the pilot UI.");
trajectories = root.GetComponent<EveUnityShotTrajectoryRenderer>();
Assert.That(trajectories, Is.Not.Null);
host.ShotAvailable += shot =>
@ -956,6 +960,9 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(captureFieldVolume.CompositeCount - initialCompositeCount,
Is.GreaterThanOrEqualTo(temporalSettlingFrames),
"The pilot capture ran before the advertised temporal reconstruction had settled.");
Assert.That(cockpit.resolvedStyle.display, Is.Not.EqualTo(DisplayStyle.None));
Assert.That(cockpit.worldBound.width, Is.GreaterThan(0),
"The mounted provider cockpit has no visible screen layout.");
Debug.Log($"EveUnity witness phase temporal-settling-128-frames took {temporalSettlingElapsed.Elapsed.TotalMilliseconds:0.###}ms.");
var pilotCaptureElapsed = Stopwatch.StartNew();
yield return null;

View file

@ -23,14 +23,17 @@ namespace GameCult.Eve.UnityScene
{
private readonly IEveUnityPlayableWorldSceneSink _sceneSink;
private readonly IEveUnityPlayableWorldAssetResolver _assetResolver;
private readonly bool _liveEntityBodyOwner;
private readonly HashSet<string> _knownEntityIds = new HashSet<string>(StringComparer.Ordinal);
public EveUnityPlayableWorldPresenter(
IEveUnityPlayableWorldSceneSink sceneSink,
IEveUnityPlayableWorldAssetResolver assetResolver)
IEveUnityPlayableWorldAssetResolver assetResolver,
bool liveEntityBodyOwner = false)
{
_sceneSink = sceneSink ?? throw new ArgumentNullException(nameof(sceneSink));
_assetResolver = assetResolver ?? throw new ArgumentNullException(nameof(assetResolver));
_liveEntityBodyOwner = liveEntityBodyOwner;
}
public EveUnityPlayableWorldPresentation Apply(EveUnitySceneProjection projection)
@ -46,9 +49,26 @@ namespace GameCult.Eve.UnityScene
{
if (world == null) throw new ArgumentNullException(nameof(world));
var nextEntityIds = new HashSet<string>(StringComparer.Ordinal);
_sceneSink.ConfigureWorld(world);
// A world that advertises a live entity body has one transform and
// membership owner: the SoA generation presenter. The durable Eve
// surface remains configuration/topology and must not periodically
// overwrite realtime body state.
if (_liveEntityBodyOwner &&
(!string.IsNullOrWhiteSpace(world.EntityViewPointerId) ||
!string.IsNullOrWhiteSpace(world.EntityBodyId)))
return new EveUnityPlayableWorldPresentation(
world.WorldRootId,
world.PlayerEntityId,
world.InputProfile,
world.CameraRig,
0,
0,
_knownEntityIds.Count);
var nextEntityIds = new HashSet<string>(StringComparer.Ordinal);
var upserted = 0;
foreach (var entity in world.Entities)
{

View file

@ -41,7 +41,10 @@ namespace GameCult.Eve.UnityScene
_connection = new EveUnitySceneProviderConnection(_surfaceSource, commandSink);
_client = new EveUnityPlayableWorldLiveClient(
_connection,
new EveUnityPlayableWorldPresenter(sceneSink, assetResolver ?? new EveUnityAssetRefResolver()),
new EveUnityPlayableWorldPresenter(
sceneSink,
assetResolver ?? new EveUnityAssetRefResolver(),
liveEntityBodyOwner: _entityViews != null),
receiptSource);
if (assetManifestDocuments != null)

View file

@ -1856,7 +1856,7 @@ namespace GameCult.Eve.UnityScene.Tests
var presenter = new EveUnityPlayableWorldPresenter(sink, new EveUnityAssetRefResolver());
var firstProjection = lowerer.Lower(PlayableArpgDocument(), Advertisement("aetheria.daemon.game"));
var firstPresentation = presenter.Apply(firstProjection);
var firstPresentation = presenter.Apply(SnapshotWorld(firstProjection.PlayableWorld!));
Assert.That(firstPresentation.WorldRootId, Is.EqualTo("aetheria.daemon.game.playable"));
Assert.That(firstPresentation.PlayerEntityId, Is.EqualTo("player-vanguard"));
@ -1875,7 +1875,7 @@ namespace GameCult.Eve.UnityScene.Tests
var secondProjection = lowerer.Lower(
PlayableArpgDocument(includeRaider: false, playerPosition: "5,0,2"),
Advertisement("aetheria.daemon.game"));
var secondPresentation = presenter.Apply(secondProjection);
var secondPresentation = presenter.Apply(SnapshotWorld(secondProjection.PlayableWorld!));
Assert.That(secondPresentation.UpsertedEntities, Is.EqualTo(2));
Assert.That(secondPresentation.RemovedEntities, Is.EqualTo(1));
@ -1888,6 +1888,27 @@ namespace GameCult.Eve.UnityScene.Tests
Assert.That(sink.Upserts[3].entity.PositionZ, Is.EqualTo(2f));
}
[Test]
public void PlayableWorldSurfaceCannotOverwriteLiveBodyEntities()
{
var projection = new EveUnitySceneSurfaceLowerer()
.Lower(PlayableArpgDocument(), Advertisement("aetheria.daemon.game"));
var sink = new FakePlayableWorldSceneSink();
var presenter = new EveUnityPlayableWorldPresenter(
sink,
new EveUnityAssetRefResolver(),
liveEntityBodyOwner: true);
var presentation = presenter.Apply(projection);
Assert.That(projection.PlayableWorld!.EntityBodyId, Is.Not.Empty);
Assert.That(sink.ConfiguredWorlds.Count, Is.EqualTo(1));
Assert.That(sink.Upserts, Is.Empty);
Assert.That(sink.RemovedEntityIds, Is.Empty);
Assert.That(presentation.UpsertedEntities, Is.Zero);
Assert.That(presentation.RemovedEntities, Is.Zero);
}
[Test]
public void LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned()
{
@ -2950,6 +2971,21 @@ namespace GameCult.Eve.UnityScene.Tests
}
}
private static EveUnityPlayableWorldProjection SnapshotWorld(EveUnityPlayableWorldProjection source) =>
new EveUnityPlayableWorldProjection(
source.WorldRootId,
source.StatePointerId,
source.AssetManifest,
source.InputProfile,
source.CameraRig,
source.ViewId,
source.PlayerEntityId,
source.MovementCommand,
source.FocusCommand,
source.TargetCommand,
source.ActionCommand,
source.Entities);
private static EveUnityPlayableWorldEntity PlayableEntityModel(
string entityId,
string assetRef,

View file

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

View file

@ -17,7 +17,7 @@ param(
)
$ErrorActionPreference = "Stop"
$expectedEveUnityCommit = "ddd2c5871f935978a0640d43cb58e18579523125"
$expectedEveUnityCommit = "050b2019bd6faa4275013516870d1ded245ee391"
$expectedEveFieldsCommit = "c5a4a75c1b727499b16c2dae1895f29e2a9f72f0"
$expectedEveUnityUiToolkitCommit = "44390549775ec535ee31fc60a5bc594f372f4147"
$expectedCultLibCommit = "f67f5122ed1bd11da016e7b820ed60145ccd0299"