feat(app): observe canonical placement receipts

This commit is contained in:
Erik 2026-08-01 15:22:52 +02:00
parent 378ca95a67
commit f05ed5c3cd
14 changed files with 545 additions and 31 deletions

View file

@ -585,7 +585,8 @@ internal sealed class FrameRootCompositionPhase
session.LocalPlayerFrame,
session.LiveSpatialReconciler,
live.WorldAvailability,
live.RenderSceneShadow?.LiveProjections);
live.RenderSceneShadow?.LiveProjections,
session.PlacementProjectionRetry);
var cameraFrame = new CameraFrameController(
host.CameraController,
d.InputCapture,

View file

@ -96,6 +96,7 @@ internal sealed record LivePresentationResult(
GpuWorldState WorldState,
RenderSceneShadowRuntime? RenderSceneShadow,
LiveEntityRuntime LiveEntities,
RuntimePlacementPresentationSink PlacementProjection,
ProjectileController ProjectileController,
LiveEntityProjectionWithdrawalController ProjectionWithdrawal,
LiveEntityLightController Lights,
@ -451,6 +452,35 @@ internal sealed class LivePresentationCompositionPhase
liveEntities,
particleVisibility,
"particle projection visibility");
var placementVisibilitySinks = new List<
Action<LiveEntityRecord, bool>>(3)
{
wbVisibility,
};
if (liveRenderProjections is not null)
{
placementVisibilitySinks.Add(
liveRenderProjections.OnProjectionVisibilityChanged);
}
placementVisibilitySinks.Add(particleVisibility);
var placementProjection = new RuntimePlacementPresentationSink(
liveEntities,
worldTransit,
d.WorldGameState,
d.WorldEvents,
d.EffectPoses,
d.LocalPlayerShadow,
() => d.PlayerIdentity.ServerGuid,
guid =>
{
if (d.Selection.SelectedObjectId == guid)
{
d.Selection.Clear(
SelectionChangeSource.System,
SelectionChangeReason.SelectedObjectRemoved);
}
},
placementVisibilitySinks);
Fault(LivePresentationCompositionPoint.ProjectionVisibilityBound);
var projectileController = new ProjectileController(
@ -619,6 +649,7 @@ internal sealed class LivePresentationCompositionPhase
renderSceneShadow,
renderSceneShadowLease,
liveEntities,
placementProjection,
projectileController,
projectionWithdrawal,
lightsLease,
@ -668,6 +699,7 @@ internal sealed class LivePresentationCompositionPhase
CompositionAcquisitionScope.CompositionAcquisitionLease<
RenderSceneShadowRuntime>? renderSceneShadowLease,
LiveEntityRuntime liveEntities,
RuntimePlacementPresentationSink placementProjection,
ProjectileController projectileController,
LiveEntityProjectionWithdrawalController projectionWithdrawal,
CompositionAcquisitionScope.CompositionAcquisitionLease<LiveEntityLightController> lightsLease,
@ -1147,6 +1179,7 @@ internal sealed class LivePresentationCompositionPhase
worldState,
renderSceneShadow,
liveEntities,
placementProjection,
projectileController,
projectionWithdrawal,
lightsLease.Resource,

View file

@ -122,6 +122,7 @@ internal sealed record SessionPlayerResult(
PlayerModeAutoEntry PlayerModeAutoEntry,
LocalPlayerTeleportController LocalTeleport,
LiveSessionHost SessionHost,
RuntimePlacementProjectionRetrySlot PlacementProjectionRetry,
CurrentGameRuntimeAdapter GameRuntime,
GameplayInputActionRouter? GameplayActions,
SessionPlayerRuntimeBindings RuntimeBindings);
@ -832,6 +833,9 @@ internal sealed class SessionPlayerCompositionPhase
AcDream.UI.Abstractions.Panels.Vitals.VitalsVM? vitals =
interaction.RetainedUi?.Vitals;
var placementProjectionRetry =
new RuntimePlacementProjectionRetrySlot(
() => d.Runtime.Generation);
var sessionRuntimeFactory = new LiveSessionRuntimeFactory(
new LiveSessionPlayerRuntime(
d.PlayerIdentity,
@ -878,7 +882,9 @@ internal sealed class SessionPlayerCompositionPhase
content.AnimationHookFrames,
live.Presentation,
d.RemoteMovementObservations,
live.RenderSceneShadow),
live.RenderSceneShadow,
live.PlacementProjection,
placementProjectionRetry),
liveSessionCommands,
d.Log);
LiveSessionHost sessionHost = sessionRuntimeFactory.Create(
@ -1015,6 +1021,7 @@ internal sealed class SessionPlayerCompositionPhase
playerModeAutoEntry,
teleportLease.Resource,
sessionHost,
placementProjectionRetry,
gameRuntime,
gameplayActionsLease?.Resource,
bindings);