feat(runtime): define borrowed views commands and ordered events

Establish the J1 presentation-independent contract with instance-scoped clocks and generations, immutable borrowed views, typed generation-gated commands, normalized ordered diagnostics, and teardown acknowledgements. Route graphical startup plus press-time selection, movement, and combat through focused App adapters over the exact existing owners without adding a queue or mirrored world.

Validated by the Release solution build, 13 Runtime tests, 3,838 App tests with three existing skips, and the complete 8,424-test Release suite with five existing skips.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-25 19:08:42 +02:00
parent afebbe3eca
commit 854d9e9cd1
21 changed files with 2594 additions and 44 deletions

View file

@ -3,6 +3,7 @@ using AcDream.App.Input;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Scene;
using AcDream.App.Rendering.Vfx;
using AcDream.App.Runtime;
using AcDream.App.Settings;
using AcDream.App.Update;
using AcDream.App.World;
@ -58,7 +59,8 @@ internal sealed record FrameRootResult(
RenderFrameOrchestrator Render,
FrameRootRuntimeBindings RuntimeBindings,
IDisposable FrameGraphPublication,
AcDream.App.Net.LiveSessionHost SessionHost);
AcDream.App.Net.LiveSessionHost SessionHost,
CurrentGameRuntimeAdapter GameRuntime);
internal interface IGameWindowFrameRootPublication
{
@ -566,7 +568,8 @@ internal sealed class FrameRootCompositionPhase
renderFrame,
bindings,
frameGraphPublication,
session.SessionHost);
session.SessionHost,
session.GameRuntime);
_publication.PublishFrameRoots(result);
graphLease.Transfer();
bindingsLease.Transfer();

View file

@ -8,6 +8,7 @@ using AcDream.App.Rendering;
using AcDream.App.Rendering.Scene;
using AcDream.App.Rendering.Vfx;
using AcDream.App.Rendering.Wb;
using AcDream.App.Runtime;
using AcDream.App.Settings;
using AcDream.App.Streaming;
using AcDream.App.Update;
@ -115,6 +116,7 @@ internal sealed record SessionPlayerResult(
PlayerModeAutoEntry PlayerModeAutoEntry,
LocalPlayerTeleportController LocalTeleport,
LiveSessionHost SessionHost,
CurrentGameRuntimeAdapter GameRuntime,
GameplayInputActionRouter? GameplayActions,
SessionPlayerRuntimeBindings RuntimeBindings);
@ -864,6 +866,22 @@ internal sealed class SessionPlayerCompositionPhase
bindings.Adopt(
"live combat-mode commands",
d.CombatModeCommands.BindOwned(combatCommand));
var gameRuntime = new CurrentGameRuntimeAdapter(
d.Options,
liveSession,
sessionHost,
d.PlayerIdentity,
live.LiveEntities,
d.Objects,
d.Chat,
d.PlayerController,
worldReveal,
d.UpdateClock,
d.Selection,
live.SelectionInteractions,
gameplayInput,
combatCommand);
bindings.Adopt("current game runtime adapter", gameRuntime);
var nearbyDiagnostics = new NearbyWorldDiagnosticDumper(
new RuntimeNearbyWorldDiagnosticSource(
@ -903,13 +921,17 @@ internal sealed class SessionPlayerCompositionPhase
playerMode),
new ItemTargetModeCommands(interaction.ItemInteraction),
new GameplayCameraModeCommands(host.CameraController),
combatCommand,
gameRuntime,
gameRuntime.Combat,
new GameplayWindowCommands(d.Window.Close));
var targets = new RuntimeGameplayInputPriorityTargets(
gameplayInput,
pointer,
interaction.RetainedUi?.Runtime,
live.SelectionInteractions,
gameRuntime,
gameRuntime.Selection,
gameRuntime.MovementCommands,
commands);
GameplayInputActionRouter gameplayActions =
GameplayInputActionRouter.Create(
@ -954,6 +976,7 @@ internal sealed class SessionPlayerCompositionPhase
playerModeAutoEntry,
teleportLease.Resource,
sessionHost,
gameRuntime,
gameplayActionsLease?.Resource,
bindings);
_publication.PublishSessionPlayer(result);

View file

@ -1,9 +1,8 @@
using AcDream.App.Net;
using AcDream.Runtime;
namespace AcDream.App.Composition;
internal sealed record SessionStartDependencies(
RuntimeOptions Options,
Action<string> Log);
/// <summary>
@ -22,24 +21,23 @@ internal sealed class SessionStartCompositionPhase
public void Start(FrameRootResult frame)
{
ArgumentNullException.ThrowIfNull(frame);
LiveSessionStartResult result =
frame.SessionHost.Start(_dependencies.Options);
RuntimeSessionStartResult result =
frame.GameRuntime.Session.Start(frame.GameRuntime.Generation);
Report(result, _dependencies.Log);
}
internal static void Report(
LiveSessionStartResult result,
RuntimeSessionStartResult result,
Action<string> log)
{
ArgumentNullException.ThrowIfNull(result);
ArgumentNullException.ThrowIfNull(log);
switch (result.Status)
{
case LiveSessionStartStatus.MissingCredentials:
case RuntimeSessionStartStatus.MissingCredentials:
log(
"live: ACDREAM_LIVE set but TEST_USER/TEST_PASS missing; skipping");
break;
case LiveSessionStartStatus.Failed:
case RuntimeSessionStartStatus.Failed:
log($"live: session failed: {result.Error}");
break;
}