using System.Buffers.Binary;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Net;
using System.Numerics;
using System.Reflection;
using System.Text.Json;
using AcDream.Core.Net;
using AcDream.Core.Net.Messages;
using AcDream.Core.Physics;
using AcDream.Headless.Configuration;
using AcDream.Headless.Credentials;
using AcDream.Headless.Diagnostics;
using AcDream.Headless.Hosting;
using AcDream.Headless.Platform;
using AcDream.Runtime;
using AcDream.Runtime.Entities;
using AcDream.Runtime.Gameplay;
using AcDream.Runtime.Physics;
using AcDream.Runtime.Session;
using AcDream.Runtime.World;
namespace AcDream.Headless.Tests;
public sealed class HeadlessSessionHostTests
{
[Fact]
public void SingleSessionStartsReconnectsAndConvergesWithoutPresentation()
{
var operations = new FixtureSessionOperations();
using var diagnosticsOutput = new StringWriter();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(diagnosticsOutput),
operations);
RuntimeSessionStartResult first = host.Start();
ulong firstGeneration = host.Runtime.Generation.Value;
host.Tick(0.015d);
RuntimeSessionStartResult second = host.Reconnect();
Assert.Equal(RuntimeSessionStartStatus.Connected, first.Status);
Assert.Equal(RuntimeSessionStartStatus.Connected, second.Status);
Assert.Equal(0x50000002u, first.CharacterId);
Assert.Equal("Headless", host.ActiveCharacterName);
Assert.True(host.Runtime.Session.IsInWorld);
Assert.True(host.Runtime.Generation.Value > firstGeneration);
Assert.Equal(2, operations.CreatedSessionCount);
Assert.Equal(1, operations.DisposedSessionCount);
host.Dispose();
Assert.Equal(2, operations.DisposedSessionCount);
Assert.True(host.Runtime.CaptureOwnership().IsConverged);
Assert.True(credential.IsDisposed);
string diagnostics = diagnosticsOutput.ToString();
Assert.Contains("\"state\":\"start-result\"", diagnostics);
Assert.DoesNotContain("password", diagnostics);
Assert.DoesNotContain("AcDream.App", diagnostics);
}
///
/// Campaign LA slice LA1: proves the status-event writer fires the
/// pinned lifecycle vocabulary — started/connected/characterList/
/// enteredWorld/disconnected/exited — in order, from a real
/// start+dispose cycle, and that the
/// roster surfaced matches
/// exactly (before selection has happened — the roster is reported for
/// BOTH candidates, not just the selected one).
///
[Fact]
public void StatusFileReceivesThePinnedLifecycleEventsInOrder()
{
string statusPath = Path.Combine(
Path.GetTempPath(),
$"acdream-headless-status-{Guid.NewGuid():N}.jsonl");
try
{
var operations = new FixtureSessionOperations();
using var diagnosticsOutput = new StringWriter();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(statusFile: statusPath),
credential,
new HeadlessDiagnosticWriter(diagnosticsOutput),
operations);
RuntimeSessionStartResult started = host.Start();
Assert.Equal(RuntimeSessionStartStatus.Connected, started.Status);
host.Dispose();
string[] lines = File.ReadAllLines(statusPath);
string[] eventNames = lines
.Select(line => JsonDocument.Parse(line)
.RootElement.GetProperty("e").GetString()!)
.ToArray();
Assert.Equal(
[
"started", "connected", "characterList", "enteredWorld",
"disconnected", "exited",
],
eventNames);
using JsonDocument characterListDoc = JsonDocument.Parse(
lines[Array.IndexOf(eventNames, "characterList")]);
JsonElement characterList = characterListDoc.RootElement;
Assert.Equal("account", characterList.GetProperty("accountName").GetString());
Assert.Equal(2, characterList.GetProperty("characters").GetArrayLength());
using JsonDocument enteredWorldDoc = JsonDocument.Parse(
lines[Array.IndexOf(eventNames, "enteredWorld")]);
Assert.Equal(
0x50000002u,
enteredWorldDoc.RootElement.GetProperty("characterId").GetUInt32());
using JsonDocument exitedDoc = JsonDocument.Parse(
lines[Array.IndexOf(eventNames, "exited")]);
Assert.Equal(0, exitedDoc.RootElement.GetProperty("code").GetInt32());
string contents = File.ReadAllText(statusPath);
Assert.DoesNotContain("password", contents, StringComparison.Ordinal);
}
finally
{
if (File.Exists(statusPath))
File.Delete(statusPath);
}
}
[Fact]
public void AbsentStatusFileConstructsANoOpWriter()
{
var operations = new FixtureSessionOperations();
using var diagnosticsOutput = new StringWriter();
using var credential = new HeadlessCredentialSecret("fixture", "password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(diagnosticsOutput),
operations);
RuntimeSessionStartResult started = host.Start();
Assert.Equal(RuntimeSessionStartStatus.Connected, started.Status);
// No exception, and (implicitly) no file was ever touched — the
// writer is a permanent no-op with no configured path.
}
///
/// Campaign LA slice LA2: a probe-mode session's status stream reports
/// started/connected/characterList and then converges straight to
/// exited(reason:"probe", code:0) — never enteredWorld — and the
/// underlying operations fake proves EnterWorld was literally never
/// called (not merely that no wire message happened to arrive).
///
[Fact]
public void ProbeSessionEmitsRosterThenExitsSuccessfullyWithoutEnteringWorld()
{
string statusPath = Path.Combine(
Path.GetTempPath(),
$"acdream-headless-probe-status-{Guid.NewGuid():N}.jsonl");
try
{
var operations = new FixtureSessionOperations();
using var diagnosticsOutput = new StringWriter();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
ProbeDescriptor(statusFile: statusPath),
credential,
new HeadlessDiagnosticWriter(diagnosticsOutput),
operations);
RuntimeSessionStartResult started = host.Start();
Assert.Equal(RuntimeSessionStartStatus.ProbeComplete, started.Status);
Assert.Equal(0, operations.EnterWorldCallCount);
Assert.False(host.Runtime.Session.IsInWorld);
host.Dispose();
Assert.Equal(0, operations.EnterWorldCallCount);
Assert.True(host.Runtime.CaptureOwnership().IsConverged);
string[] lines = File.ReadAllLines(statusPath);
string[] eventNames = lines
.Select(line => JsonDocument.Parse(line)
.RootElement.GetProperty("e").GetString()!)
.ToArray();
Assert.DoesNotContain("enteredWorld", eventNames);
Assert.Contains("characterList", eventNames);
Assert.Contains("exited", eventNames);
Assert.True(
Array.IndexOf(eventNames, "characterList")
< Array.IndexOf(eventNames, "exited"),
"characterList must land before the terminal exited event.");
using JsonDocument exitedDoc = JsonDocument.Parse(
lines[Array.IndexOf(eventNames, "exited")]);
Assert.Equal(0, exitedDoc.RootElement.GetProperty("code").GetInt32());
Assert.Equal(
"probe",
exitedDoc.RootElement.GetProperty("reason").GetString());
string contents = File.ReadAllText(statusPath);
Assert.DoesNotContain("password", contents, StringComparison.Ordinal);
}
finally
{
if (File.Exists(statusPath))
File.Delete(statusPath);
}
}
///
/// Campaign LA slice LA2:
/// maps a ProbeComplete start to
/// (0) rather than — a
/// single-session probe-only process must exit cleanly and promptly
/// without ever needing SIGINT/cancellation, because
/// ProbeHeadlessBotPolicy reports IsComplete immediately.
///
[Fact]
public async Task ProcessHostMapsProbeCompleteStartToSuccessExitCode()
{
var configuration = new HeadlessConfiguration
{
Version = 1,
Sessions =
[
ProbeDescriptor(
provider: HeadlessCredentialProviderKind.StandardInput,
credentialReference: "probe-password"),
],
};
HeadlessPathSet paths = HeadlessPathSet.Resolve(
new HeadlessPathOverrides());
using var diagnostics = new StringWriter();
var operations = new FixtureSessionOperations();
using var host = new HeadlessProcessHost(
configuration,
paths,
new System.IO.StringReader("probe-password" + Environment.NewLine),
diagnostics,
operations);
// Deliberately NOT cancelled — a probe-only process must return on
// its own; a hang here would mean the scheduler never recognized
// the probe session as already complete.
using var cancellation = new CancellationTokenSource(
TimeSpan.FromSeconds(10));
HeadlessExitCode result = await host.RunAsync(cancellation.Token);
Assert.Equal(HeadlessExitCode.Success, result);
Assert.Equal(0, operations.EnterWorldCallCount);
Assert.False(cancellation.IsCancellationRequested);
}
///
/// Campaign LA slice LA2: a probe session completing must not tear down
/// a sibling play session sharing the same process — the process exit
/// code is 0 only once every configured session has succeeded (the
/// probe counts as success the instant it completes; the play session
/// keeps running until cancellation).
///
[Fact]
public async Task ProbeSessionSharingAProcessDoesNotTearDownASiblingPlaySession()
{
var configuration = new HeadlessConfiguration
{
Version = 1,
Sessions =
[
ProbeDescriptor(
"probe-sibling",
provider: HeadlessCredentialProviderKind.StandardInput,
credentialReference: "probe-password"),
Descriptor(
HeadlessCredentialProviderKind.StandardInput,
"play-password"),
],
};
HeadlessPathSet paths = HeadlessPathSet.Resolve(
new HeadlessPathOverrides());
using var diagnostics = new StringWriter();
var operations = new FixtureSessionOperations();
using var host = new HeadlessProcessHost(
configuration,
paths,
new System.IO.StringReader(
"probe-password" + Environment.NewLine
+ "play-password" + Environment.NewLine),
diagnostics,
operations);
using var cancellation = new CancellationTokenSource();
cancellation.Cancel();
HeadlessExitCode result = await host.RunAsync(cancellation.Token);
Assert.Equal(HeadlessExitCode.Success, result);
Assert.Equal(2, host.Sessions.Count);
HeadlessSessionHost probeSession = Assert.Single(
host.Sessions,
s => s.SessionId == "probe-sibling");
HeadlessSessionHost playSession = Assert.Single(
host.Sessions,
s => s.SessionId == "bot");
Assert.False(probeSession.Runtime.Session.IsInWorld);
Assert.True(playSession.Runtime.Session.IsInWorld);
Assert.False(playSession.IsFaulted);
}
///
/// Campaign LA slice LA2: the configured idle policy follows the
/// normal play shape (selector + policy, mode absent), enters world, and
/// remains non-terminal through real scheduler turns until cancellation.
/// Cancellation stops the process loop; the owning host's ordinary
/// disposal transaction then performs graceful session teardown. Status
/// events must describe those boundaries truthfully and remain exactly
/// once even when disposal is repeated.
///
[Fact]
public async Task IdlePolicyEntersWorldRunsUntilCancellationAndConvergesExactlyOnce()
{
string statusPath = Path.Combine(
Path.GetTempPath(),
$"acdream-headless-idle-status-{Guid.NewGuid():N}.jsonl");
try
{
var configuration = new HeadlessConfiguration
{
Version = 1,
Sessions =
[
Descriptor(
HeadlessCredentialProviderKind.StandardInput,
"stdin-bot",
statusFile: statusPath),
],
};
HeadlessPathSet paths = HeadlessPathSet.Resolve(
new HeadlessPathOverrides());
using var diagnostics = new StringWriter();
var operations = new FixtureSessionOperations();
using var host = new HeadlessProcessHost(
configuration,
paths,
new System.IO.StringReader(
"process-password" + Environment.NewLine),
diagnostics,
operations);
using var cancellation = new CancellationTokenSource();
Task run = host.RunAsync(cancellation.Token);
var timeout = Stopwatch.StartNew();
while (operations.TickCallCount < 3
&& !run.IsCompleted
&& timeout.Elapsed < TimeSpan.FromSeconds(10))
{
await Task.Delay(5);
}
Assert.True(
operations.TickCallCount >= 3,
$"Expected at least 3 idle scheduler turns, observed {operations.TickCallCount}.");
Assert.False(run.IsCompleted);
Assert.Equal(1, operations.EnterWorldCallCount);
Assert.Equal("Headless", host.Session.ActiveCharacterName);
Assert.True(host.Session.Runtime.Session.IsInWorld);
Assert.False(host.Session.IsPolicyComplete);
Assert.Equal(
["started", "connected", "characterList", "enteredWorld"],
ReadStatusEventNames(statusPath));
cancellation.Cancel();
HeadlessExitCode result = await run.WaitAsync(
TimeSpan.FromSeconds(10));
Assert.Equal(HeadlessExitCode.Success, result);
// RunAsync owns scheduling, not the host lifetime. The session
// remains honestly connected until its owner disposes it.
Assert.True(host.Session.Runtime.Session.IsInWorld);
Assert.Equal(
["started", "connected", "characterList", "enteredWorld"],
ReadStatusEventNames(statusPath));
host.Dispose();
host.Dispose();
Assert.True(host.Session.Runtime.CaptureOwnership().IsConverged);
Assert.Equal(1, operations.DisposedSessionCount);
string[] lines = File.ReadAllLines(statusPath);
string[] eventNames = ReadStatusEventNames(statusPath);
Assert.Equal(
[
"started", "connected", "characterList", "enteredWorld",
"disconnected", "exited",
],
eventNames);
using JsonDocument disconnected = JsonDocument.Parse(
lines[Array.IndexOf(eventNames, "disconnected")]);
Assert.Equal(
"stopped",
disconnected.RootElement.GetProperty("reason").GetString());
using JsonDocument exited = JsonDocument.Parse(
lines[Array.IndexOf(eventNames, "exited")]);
JsonElement exit = exited.RootElement;
Assert.Equal(0, exit.GetProperty("code").GetInt32());
string? exitReason = exit.GetProperty("reason").GetString();
Assert.False(string.IsNullOrWhiteSpace(exitReason));
Assert.NotEqual("fault", exitReason);
Assert.NotEqual("probe", exitReason);
Assert.DoesNotContain(
"process-password",
File.ReadAllText(statusPath),
StringComparison.Ordinal);
Assert.DoesNotContain(
"process-password",
diagnostics.ToString(),
StringComparison.Ordinal);
}
finally
{
if (File.Exists(statusPath))
File.Delete(statusPath);
}
}
[Fact]
public async Task DirectCredentialsOverrideSingleConfiguredSession()
{
var configuration = new HeadlessConfiguration
{
Version = 1,
Sessions = [Descriptor()],
};
HeadlessPathSet paths = HeadlessPathSet.Resolve(
new HeadlessPathOverrides());
using var diagnostics = new StringWriter();
var operations = new FixtureSessionOperations();
using var host = new HeadlessProcessHost(
configuration,
paths,
TextReader.Null,
diagnostics,
operations,
directCredentials: new HeadlessDirectCredentials(
"direct-account",
"direct-secret"));
using var cancellation = new CancellationTokenSource();
cancellation.Cancel();
HeadlessExitCode result =
await host.RunAsync(cancellation.Token);
Assert.Equal(HeadlessExitCode.Success, result);
Assert.Equal("direct-account", operations.LastUser);
Assert.Equal("direct-secret", operations.LastPassword);
Assert.DoesNotContain(
"direct-secret",
diagnostics.ToString());
}
[Fact]
public async Task DirectCredentialsPreserveDeclaredCharacterOptions()
{
// MF-1 (Campaign OP OP7 review fix, 2026-08-11): the K3 direct-CLI
// launch mode (--user/--password) rebuilds the configured session
// descriptor via HeadlessProcessHost.WithAccount before constructing
// HeadlessSessionHost. A hand-copied clone that forgets a property
// silently drops that feature for this launch mode with no error —
// exactly what happened to CharacterOptions. Assert the declared
// block survives the direct-credential path by checking the
// constructed session's seeder actually saw it.
var configuration = new HeadlessConfiguration
{
Version = 1,
Sessions =
[
Descriptor(characterOptions: new Dictionary
{
["AutoRepeatAttack"] = true,
}),
],
};
HeadlessPathSet paths = HeadlessPathSet.Resolve(
new HeadlessPathOverrides());
using var diagnostics = new StringWriter();
var operations = new FixtureSessionOperations();
using var host = new HeadlessProcessHost(
configuration,
paths,
TextReader.Null,
diagnostics,
operations,
directCredentials: new HeadlessDirectCredentials(
"direct-account",
"direct-secret"));
using var cancellation = new CancellationTokenSource();
cancellation.Cancel();
HeadlessExitCode result =
await host.RunAsync(cancellation.Token);
Assert.Equal(HeadlessExitCode.Success, result);
Assert.Equal("direct-account", operations.LastUser);
Assert.NotNull(host.Session.OptionsSeeder);
Assert.True(host.Session.OptionsSeeder!.HasDeclaredOptions);
}
[Fact]
public void DirectFirstEntryCompletion_InvokesOnLoginCompleteSentHookThroughProductionWiring()
{
// SF-4 (Campaign OP OP7 review fix, 2026-08-11): the THIRD
// production LoginComplete->seeder hook lives entirely inside
// HeadlessSessionHost.CreateEventRoute's own closure (the direct,
// non-portal first-entry completion callback wired to
// RuntimeFirstEntryDriveController via HeadlessSessionEventRoute's
// localPlayerCompleted parameter) — driving it end-to-end would
// need a real DAT-backed collision fixture this test project does
// not have. Reflection reaches the SAME closure instance
// HeadlessSessionHost actually constructed during Start() (not a
// hand-rolled reconstruction of it) and invokes it exactly as
// RuntimeFirstEntryDriveController would on residence completion,
// then proves the seeder reacted through the real wire — the same
// "declared option actually sends" proof
// HeadlessCharacterOptionsSeederWiringTests uses for the other two
// sites.
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(characterOptions: new Dictionary
{
["IgnoreAllegianceRequests"] = true,
}),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
Assert.NotNull(host.OptionsSeeder);
WorldSession session = operations.Sessions[^1];
var sent = new List();
session.GameActionCapture = body => sent.Add(body);
object eventRoute = typeof(HeadlessSessionHost)
.GetField(
"_eventRoute",
BindingFlags.NonPublic | BindingFlags.Instance)!
.GetValue(host)
?? throw new InvalidOperationException(
"HeadlessSessionHost constructed no event route.");
var localPlayerCompleted =
(Action?)typeof(HeadlessSessionEventRoute)
.GetField(
"_localPlayerCompleted",
BindingFlags.NonPublic | BindingFlags.Instance)!
.GetValue(eventRoute);
Assert.NotNull(localPlayerCompleted);
const uint playerGuid = 0x50000009u;
host.Runtime.PlayerIdentity.ServerGuid = playerGuid;
RuntimeEntityRecord record = host.Runtime.EntityObjects
.RegisterEntity(Spawn(playerGuid))
.Canonical!;
// Invoke the PRODUCTION closure directly — proves
// HeadlessSessionHost really wires _optionsSeeder?.NoteLoginCompleteSent()
// into this callback, not merely that some test double does.
localPlayerCompleted!(record);
Assert.Contains(
sent,
body => body.SequenceEqual(GameActionLoginComplete.Build()));
// No PlayerDescription has landed yet — HasServerSeed is still
// false, so nothing beyond LoginComplete can have sent.
Assert.DoesNotContain(
sent,
body => ActionOpcode(body)
== SocialActions.SetSingleCharacterOptionOpcode);
session.GameEvents.Dispatch(
GameEventEnvelope.TryParse(
WrapPlayerDescriptionEnvelope(options1: 0u, options2: 0u))!
.Value);
Assert.Contains(
sent,
body => ActionOpcode(body)
== SocialActions.SetSingleCharacterOptionOpcode);
}
[Fact]
public void DirectFrameUsesSharedRetailOrderAndMovementCadence()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
HydrateGroundedPlayer(host.Runtime);
var sent = new List<(byte[] Body, double Time)>();
var trace = new RuntimeTraceRecorder();
using IDisposable subscription =
host.Runtime.Subscribe(trace);
operations.Sessions[^1].GameActionCapture =
body => sent.Add((
body,
host.Runtime.Clock.SimulationTimeSeconds));
RuntimeCommandResult intent = host.Commands.Movement.SetIntent(
host.Runtime.Generation,
new MovementInput(Forward: true, Run: true));
host.Tick(0.015d);
Assert.True(intent.Accepted);
Assert.Contains(
trace.Entries,
static entry =>
entry.Kind == RuntimeTraceKind.Movement);
Assert.Equal(
[
MoveToState.MoveToStateAction,
AutonomousPosition.AutonomousPositionAction,
],
sent.Select(static entry =>
ActionOpcode(entry.Body)).ToArray());
sent.Clear();
for (int index = 0; index < 70; index++)
host.Tick(0.015d);
(byte[] Body, double Time)[] positions = sent
.Where(static entry =>
ActionOpcode(entry.Body)
== AutonomousPosition.AutonomousPositionAction)
.ToArray();
Assert.InRange(positions.Length, 1, 2);
Assert.True(positions[^1].Time >= 1d);
if (positions.Length == 2)
{
Assert.True(
positions[1].Time - positions[0].Time >= 0.99d);
}
Assert.DoesNotContain(
sent,
entry => ActionOpcode(entry.Body)
== MoveToState.MoveToStateAction);
}
[Fact]
public void TeardownRetriesOnlyTheUnfinishedSuffix()
{
var operations = new FixtureSessionOperations();
var writer = new FailOnceTextWriter();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(writer),
operations);
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
writer.FailNextWrite = true;
Assert.Throws(host.Dispose);
Assert.Equal(1, operations.DisposedSessionCount);
host.Dispose();
Assert.Equal(1, operations.DisposedSessionCount);
Assert.True(host.Runtime.CaptureOwnership().IsConverged);
}
///
/// B5(a) review fix:
/// proved the underlying re-offer MECHANISM works, but hand-constructed
/// directly and called
/// route.RetryPending() itself — it never touches
/// 's own
/// _eventRoute?.RetryPending() call. This test drives Tick
/// itself (via the placementSinkOverride test seam added for this
/// fix, mirroring the existing policyOverride parameter) so a
/// regression that deletes or reorders that exact line would fail HERE,
/// not just in the lower-level subscription test.
///
[Fact]
public void TickRetriesAPreviouslyDeclinedPlacementThroughTheRealEventRoute()
{
const uint remote = 0x70004301u;
const uint landblock = 0xA9B40000u;
const uint cell = landblock | 0x0001u;
const float height = 6f;
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
var sink = new DecliningThenAcceptingPlacementSink();
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations,
placementSinkOverride: sink);
GameRuntime runtime = host.Runtime;
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
runtime.EntityObjects.Physics.ObserveLocalWorldFrame(
cell, teleportAdvanced: false);
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
landblock, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
landblock, 1UL, ready: true);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntity(Spawn(remote, cell))
.Canonical!;
runtime.EntityObjects.Entities.SetFinalPhysicsState(
record, PhysicsStateFlags.Gravity);
runtime.EntityObjects.Entities.SetFullCell(
record, cell, landblock);
var body = new PhysicsBody
{
Position = new Vector3(10f, 10f, height),
Orientation = Quaternion.Identity,
LastUpdateTime = 1d,
State = PhysicsStateFlags.Gravity,
TransientState = TransientStateFlags.Active,
};
body.SnapToCell(cell, body.Position, body.Position);
runtime.EntityObjects.Entities.SetPhysicsBody(record, body);
record.ObjectClock.Activate();
runtime.EntityObjects.Physics.AcknowledgeSpatialProjection(
record, spatial: true);
RuntimeEntityPlacementToken token = runtime.EntityObjects.Physics
.SetPosition.TryBeginExclusiveAuthoredPlacement(
record,
record.PositionAuthorityVersion,
RuntimeSetPositionOperationKind.RemoteAuthoritative);
Assert.True(token.IsValid);
RuntimeSetPositionMoverPreparationStatus status = runtime.EntityObjects
.Physics.SetPosition.TryPrepareAndSubmitAuthoredPlacement(
record,
token,
RuntimeSetPositionOperationKind.RemoteAuthoritative,
PhysicsSetPositionFlags.Teleport | PhysicsSetPositionFlags.Slide,
new LoadedSetupCollisionSource(),
gameTime: runtime.Clock.SimulationTimeSeconds,
out RuntimeSetPositionOutcome outcome,
resolveWorldOffsetFromRuntimeFrame: true);
Assert.Equal(RuntimeSetPositionMoverPreparationStatus.Prepared, status);
Assert.Equal(
RuntimeSetPositionStatus.CommittedHostAcknowledgementPending,
outcome.Status);
// The production HeadlessSessionEventRoute's subscription attached
// during host.Start() already observed this Place synchronously —
// the fake sink is still declining, so it must remain unacknowledged.
Assert.Equal(1, sink.CallCount);
Assert.True(
runtime.EntityObjects.Physics.SetPosition.TryPeekProjection(
out _));
// The sink starts accepting (mirrors a landblock finishing streaming
// in) — driving ONE real host tick is what must re-offer the head,
// through Tick's own wiring, not a hand-built route.
sink.Accept = true;
host.Tick(0.015d);
Assert.Equal(2, sink.CallCount);
Assert.False(
runtime.EntityObjects.Physics.SetPosition.TryPeekProjection(
out _));
}
private sealed class DecliningThenAcceptingPlacementSink
: IRuntimePlacementProjectionSink
{
internal int CallCount { get; private set; }
internal bool Accept { get; set; }
public bool TryApply(in RuntimePlacementProjectionSnapshot projection)
{
CallCount++;
return Accept;
}
}
[Fact]
public void WorldProjectionHydratesCanonicalMovementAndTeleportState()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
// C3c: conductor-driven flow — a live generation admits the initial
// residence, the flat landblock's collision generation commits, and
// the world projection's pump drives the local first-entry conductor
// to completion (the deleted SynchronizeLocalPlayer hand-copy's
// replacement).
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
const uint player = 0x50000002u;
runtime.PlayerIdentity.ServerGuid = player;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
0xA9B40000u, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
0xA9B40000u, 1UL, ready: true);
AcDream.Runtime.Session.RuntimeFirstEntryDriveController firstEntry =
CreateFirstEntryDrive(runtime);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntityWithInitialResidence(Spawn(player), isLocalPlayer: true)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var collision = new FixtureCollisionNeighborhood();
// R5/A7 review fix (2026-08-05): the drive controller is now wired
// (was omitted in the first pass, leaving the canonical portal arm
// a no-op by construction here and dual-host parity with zero
// coverage). Mirrors production composition
// (HeadlessSessionHost.cs's own construction order): the SAME
// RuntimeAcceptedPositionDriveController drives both hosts through
// the identical TryExecuteAcceptedPortalArrival entry point.
RuntimeAcceptedPositionDriveController acceptedPositionDrive =
CreateAcceptedPositionDrive(runtime);
var projection = new HeadlessSessionWorldProjection(
runtime,
collision,
firstEntry,
acceptedPositionDrive);
projection.ProjectSpawn(record, isLocalPlayer: true);
PlayerMovementController controller =
Assert.IsType(
runtime.MovementOwner.Controller);
controller.SeedPlacementForTest(
new Vector3(48f, 49f, 50f),
0xA9B40001u, new Vector3(48f, 49f, 50f));
projection.ProjectPosition(
record,
isLocalPlayer: true,
PositionTimestampDisposition.Apply);
Assert.Same(controller, runtime.MovementOwner.Controller);
Assert.Equal(record.LocalEntityId, controller.LocalEntityId);
Assert.Equal(new Vector3(48f, 49f, 50f), controller.Position);
Assert.Equal(
0xA9B40000u,
controller.CellId & 0xFFFF0000u);
Assert.True((controller.CellId & 0xFFFFu) < 0x0100u);
projection.BeginTeleport();
Assert.Equal(PlayerState.PortalSpace, controller.State);
// R5/A7: the destination cell 0xA9B40001 is in the SAME landblock
// (0xA9B40000) whose collision generation the test already
// committed above, so the canonical portal arm resolves
// Committed synchronously - no DeferredCell park needed to exercise
// the real headless placement path. A1's headless retry loop
// (RuntimeLiveEntitySessionController.PumpPortalCompletion) is
// covered separately by
// HeadlessPortalDeferredCellCommitsOnPumpAfterCollisionGenerationWake
// below.
RuntimeDestinationReadiness readiness =
projection.PrepareDestination(
revealGeneration: 7,
new RuntimeTeleportDestination(
player,
InstanceSequence: 1,
PositionSequence: 2,
TeleportSequence: 1,
ForcePositionSequence: 0,
new Position(
0xA9B40001u,
new Vector3(96f, 97f, 50f),
Quaternion.Identity)),
// R5/A7: a real, valid token - `default` was fine for the
// old no-op arm but RuntimePortalPlacementAuthority.IsValid
// now genuinely gates TryExecuteAcceptedPortalArrival on it.
new RuntimeWorldHostProjectionToken(7, 0xA9B40001u));
Assert.True(readiness.IsCollisionReady);
Assert.False(readiness.IsUnhydratable);
Assert.Equal(PlayerState.InWorld, controller.State);
Assert.Equal(2, collision.CenterCount);
Assert.Equal(0xA9B40001u, collision.LastCell);
// A4/dual-host parity: the canonical placement actually committed -
// the body moved to the destination Position, not just the
// collision-neighborhood bookkeeping that CenterCount/LastCell
// alone would have proven even with the earlier no-op arm. Z
// settles 0.005 above the wire value (the foot sphere's bottom
// sits at origin + 0.475 - 0.48, LoadedSetupCollisionSource's own
// doc comment, ISSUES.md #285) - X/Y are exact, Z is asserted
// within that settle tolerance.
Assert.Equal(96f, controller.Position.X);
Assert.Equal(97f, controller.Position.Y);
Assert.Equal(50f, controller.Position.Z, 0.01f);
// The resolved outdoor sub-cell index is derived from X/Y within
// the landblock (not the wire placeholder 0xA9B40001), same as the
// FIRST ProjectPosition assertion above (":406-409") only checks
// landblock+indoor-vs-outdoor, not the exact sub-cell.
Assert.Equal(0xA9B40000u, controller.CellId & 0xFFFF0000u);
Assert.True((controller.CellId & 0xFFFFu) < 0x0100u);
}
///
/// A1/R5/A7 review fix (2026-08-05): headless has no per-frame anim
/// sequencer the way the graphical host does, so its OWN equivalent of
/// A1's "hold until committed" mechanism is
/// HeadlessSessionWorldProjection.PrepareDestination's
/// _awaitingPortalWake polling. This proves it end to end: a
/// destination in a landblock whose collision generation is NOT yet
/// committed parks (IsCollisionReady: false, body unmoved, no
/// throw — DeferredCell is a normal headless outcome per
/// PrepareDestination's own doc), and once the destination
/// landblock's collision generation commits, the SAME park resolves on
/// a later attempt WITHOUT a second concurrent Begin (Runtime's own
/// Begin would refuse that with Contention if this class re-attempted
/// blindly instead of polling PendingCount).
///
[Fact]
public void HeadlessPortalPrepareDestinationParksThenCommitsOnCollisionGenerationWake()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
const uint player = 0x50000009u;
const uint destinationLandblock = 0xAAB40000u;
runtime.PlayerIdentity.ServerGuid = player;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
0xA9B40000u, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
0xA9B40000u, 1UL, ready: true);
AcDream.Runtime.Session.RuntimeFirstEntryDriveController firstEntry =
CreateFirstEntryDrive(runtime);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntityWithInitialResidence(Spawn(player), isLocalPlayer: true)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var collision = new FixtureCollisionNeighborhood();
RuntimeAcceptedPositionDriveController acceptedPositionDrive =
CreateAcceptedPositionDrive(runtime);
var projection = new HeadlessSessionWorldProjection(
runtime,
collision,
firstEntry,
acceptedPositionDrive);
projection.ProjectSpawn(record, isLocalPlayer: true);
PlayerMovementController controller =
Assert.IsType(
runtime.MovementOwner.Controller);
controller.SeedPlacementForTest(
new Vector3(48f, 49f, 50f),
0xA9B40001u, new Vector3(48f, 49f, 50f));
projection.ProjectPosition(
record,
isLocalPlayer: true,
PositionTimestampDisposition.Apply);
projection.BeginTeleport();
var destination = new RuntimeTeleportDestination(
player,
InstanceSequence: 1,
PositionSequence: 2,
TeleportSequence: 1,
ForcePositionSequence: 0,
new Position(
destinationLandblock | 0x0001u,
new Vector3(10f, 10f, 50f),
Quaternion.Identity));
var projectionToken = new RuntimeWorldHostProjectionToken(
7, destinationLandblock | 0x0001u);
// Begin's own portal-vs-latest-cell gate (D-T5) requires the
// destination's landblock to match the record's LATEST MERGED
// Position, not just the transit's retained destination - mirror
// what the real inbound Position handler already does before
// TryCompletePortal ever runs (LiveEntityNetworkUpdateController's
// App-side equivalent).
Assert.True(runtime.EntityObjects.TryApplyPosition(
new WorldSession.EntityPositionUpdate(
player,
new CreateObject.ServerPosition(
destination.Position.ObjCellId,
destination.Position.Frame.Origin.X,
destination.Position.Frame.Origin.Y,
destination.Position.Frame.Origin.Z,
destination.Position.Frame.Orientation.W,
destination.Position.Frame.Orientation.X,
destination.Position.Frame.Orientation.Y,
destination.Position.Frame.Orientation.Z),
Velocity: null,
PlacementId: null,
IsGrounded: true,
InstanceSequence: 1,
PositionSequence: 3,
TeleportSequence: destination.TeleportSequence,
ForcePositionSequence: 0),
isLocalPlayer: true,
forcePositionRotation: Quaternion.Identity,
currentLocalVelocity: Vector3.Zero,
acknowledgeProjection: null,
out _,
out _,
out _));
// First attempt: destinationLandblock's collision generation was
// never begun/committed, so the canonical arm parks DeferredCell.
// Must NOT throw (a park is normal, not an error). The dormant
// stage (RuntimeSetPositionState's SubmitPreparedPlacementCore
// deferred-commit path) already stages the body's Position/CellId
// at the destination while it waits (StageDormantCellFrame,
// body.InWorld=false) - the reader-visible Position moving early is
// that mechanism, not evidence the placement committed; only
// PlayerState/IsCollisionReady distinguish "staged" from
// "committed" here.
RuntimeDestinationReadiness parked = projection.PrepareDestination(
revealGeneration: 7, destination, projectionToken);
Assert.False(parked.IsCollisionReady);
Assert.Equal(PlayerState.PortalSpace, controller.State);
// A SECOND attempt while still parked must not double-Begin -
// Runtime's own Begin would refuse a genuine second attempt with
// Contention, but PrepareDestination's _awaitingPortalWake polls
// PendingCount instead of re-attempting, so this must also report
// not-ready without throwing.
RuntimeDestinationReadiness stillParked =
projection.PrepareDestination(
revealGeneration: 7, destination, projectionToken);
Assert.False(stillParked.IsCollisionReady);
// Commit the destination landblock's collision generation and pump
// the drive's wake (mirrors HeadlessSessionHost.Tick's own
// PumpFirstEntry -> _acceptedPositionDrive.Advance() ordering).
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
destinationLandblock, 1UL);
var heights = new byte[81];
Array.Fill(heights, (byte)50);
var heightTable = new float[256];
for (int index = 0; index < heightTable.Length; index++)
heightTable[index] = index;
runtime.EntityObjects.Physics.Engine.AddLandblock(
destinationLandblock,
new TerrainSurface(heights, heightTable),
[],
[],
worldOffsetX: 0f,
worldOffsetY: 0f);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
destinationLandblock, 1UL, ready: true);
// RuntimeAcceptedPositionDriveControllerTests.CommitLandblockCollision's
// exact proven-working shape: the wake path's
// resolveWorldOffsetFromRuntimeFrame requires the destination
// landblock's world-frame offset to already be resolvable.
runtime.EntityObjects.Physics.ObserveLocalWorldFrame(
destinationLandblock | 0x0001u,
teleportAdvanced: false);
// Drain the placement projection FIFO AFTER committing (exact order
// from RuntimeAcceptedPositionDriveControllerTests.DrainPlacementFifo's
// call site: commit collision -> drain FIFO -> Advance) - the
// deferred park's Withdraw notification is published as part of the
// collision-generation commit, not before it.
while (runtime.EntityObjects.Physics.SetPosition.TryPeekProjection(
out RuntimePlacementProjectionSnapshot head))
{
if (!runtime.EntityObjects.Physics.SetPosition
.AcknowledgeProjection(head.Token))
{
break;
}
}
acceptedPositionDrive.Advance();
RuntimeDestinationReadiness committed =
projection.PrepareDestination(
revealGeneration: 7, destination, projectionToken);
Assert.True(committed.IsCollisionReady);
Assert.Equal(PlayerState.InWorld, controller.State);
Assert.Equal(10f, controller.Position.X);
Assert.Equal(10f, controller.Position.Y);
Assert.Equal(destinationLandblock, controller.CellId & 0xFFFF0000u);
}
///
/// B1 review fix (2026-08-05): headless's required test #2 — the same
/// unsound-commit-inference defect
///
/// proves the HAPPY path for, exercised on the FORGOTTEN path instead. A
/// DeferredCell park killed by an ordinary, unrelated accepted Position
/// merge (exactly the ACE 5-10 Hz broadcast RuntimeSetPositionState's
/// own doc names as the expected way a far-destination park resolves
/// without committing) must leave PrepareDestination reporting
/// NOT ready, unchanged, and the
/// body never moved to the destination - before the fix,
/// PendingCount hitting 0 made PrepareDestination infer
/// "committed" and run the full readiness/materialize/LoginComplete
/// sequence against an unmoved body.
///
[Fact]
public void HeadlessPortalPrepareDestinationForgottenByOrdinaryMergeDoesNotLatchAsCommitted()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
const uint player = 0x50000009u;
const uint destinationLandblock = 0xAAB40000u;
runtime.PlayerIdentity.ServerGuid = player;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
0xA9B40000u, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
0xA9B40000u, 1UL, ready: true);
AcDream.Runtime.Session.RuntimeFirstEntryDriveController firstEntry =
CreateFirstEntryDrive(runtime);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntityWithInitialResidence(Spawn(player), isLocalPlayer: true)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var collision = new FixtureCollisionNeighborhood();
RuntimeAcceptedPositionDriveController acceptedPositionDrive =
CreateAcceptedPositionDrive(runtime);
var projection = new HeadlessSessionWorldProjection(
runtime,
collision,
firstEntry,
acceptedPositionDrive);
projection.ProjectSpawn(record, isLocalPlayer: true);
PlayerMovementController controller =
Assert.IsType(
runtime.MovementOwner.Controller);
controller.SeedPlacementForTest(
new Vector3(48f, 49f, 50f),
0xA9B40001u, new Vector3(48f, 49f, 50f));
projection.ProjectPosition(
record,
isLocalPlayer: true,
PositionTimestampDisposition.Apply);
projection.BeginTeleport();
var destination = new RuntimeTeleportDestination(
player,
InstanceSequence: 1,
PositionSequence: 2,
TeleportSequence: 1,
ForcePositionSequence: 0,
new Position(
destinationLandblock | 0x0001u,
new Vector3(10f, 10f, 50f),
Quaternion.Identity));
var projectionToken = new RuntimeWorldHostProjectionToken(
7, destinationLandblock | 0x0001u);
Assert.True(runtime.EntityObjects.TryApplyPosition(
new WorldSession.EntityPositionUpdate(
player,
new CreateObject.ServerPosition(
destination.Position.ObjCellId,
destination.Position.Frame.Origin.X,
destination.Position.Frame.Origin.Y,
destination.Position.Frame.Origin.Z,
destination.Position.Frame.Orientation.W,
destination.Position.Frame.Orientation.X,
destination.Position.Frame.Orientation.Y,
destination.Position.Frame.Orientation.Z),
Velocity: null,
PlacementId: null,
IsGrounded: true,
InstanceSequence: 1,
PositionSequence: 3,
TeleportSequence: destination.TeleportSequence,
ForcePositionSequence: 0),
isLocalPlayer: true,
forcePositionRotation: Quaternion.Identity,
currentLocalVelocity: Vector3.Zero,
acknowledgeProjection: null,
out _,
out _,
out _));
// First attempt: destinationLandblock's collision generation was
// never begun/committed, so the canonical arm parks DeferredCell.
RuntimeDestinationReadiness parked = projection.PrepareDestination(
revealGeneration: 7, destination, projectionToken);
Assert.False(parked.IsCollisionReady);
Assert.Equal(PlayerState.PortalSpace, controller.State);
Assert.Equal(1, acceptedPositionDrive.PendingCount);
// An ordinary, UNRELATED accepted Position for the same entity - no
// new teleport, just a normal broadcast at the SAME already-accepted
// teleport sequence - Forgets the parked operation the same way
// ACE's 5-10 Hz cadence would (RuntimeSetPositionState.Forget, called
// from TryApplyPosition for every accepted, non-Rejected Position).
Assert.True(runtime.EntityObjects.TryApplyPosition(
new WorldSession.EntityPositionUpdate(
player,
new CreateObject.ServerPosition(
0x20210001u, 48f, 49f, 50f, 1f, 0f, 0f, 0f),
Velocity: null,
PlacementId: null,
IsGrounded: true,
InstanceSequence: 1,
PositionSequence: 4,
TeleportSequence: destination.TeleportSequence,
ForcePositionSequence: 0),
isLocalPlayer: true,
forcePositionRotation: Quaternion.Identity,
currentLocalVelocity: Vector3.Zero,
acknowledgeProjection: null,
out _,
out _,
out _));
// Forget (inside TryApplyPosition) cancels the underlying
// RuntimeSetPositionState operation immediately, but the drive's OWN
// _pending cache only notices on its next Advance() pump - the real
// host does this every HeadlessSessionHost.Tick via PumpFirstEntry;
// the test drives it explicitly, same as the App-level equivalent.
acceptedPositionDrive.Advance();
Assert.Equal(0, acceptedPositionDrive.PendingCount);
// Drive well past where the pre-fix inference would have latched
// "committed" on the very next PrepareDestination call and then
// marched to the full readiness/materialize/LoginComplete sequence.
for (int i = 0; i < 10; i++)
{
RuntimeDestinationReadiness stillNotReady =
projection.PrepareDestination(
revealGeneration: 7, destination, projectionToken);
Assert.False(stillNotReady.IsCollisionReady);
}
Assert.Equal(PlayerState.PortalSpace, controller.State);
}
[Fact]
public void WorldProjectionIgnoresNormalEchoButBlipsForcePosition()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
// C3c: conductor-driven flow — a live generation admits the initial
// residence, the flat landblock's collision generation commits, and
// the world projection's pump drives the local first-entry conductor
// to completion (the deleted SynchronizeLocalPlayer hand-copy's
// replacement).
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
const uint player = 0x50000003u;
runtime.PlayerIdentity.ServerGuid = player;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
0xA9B40000u, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
0xA9B40000u, 1UL, ready: true);
AcDream.Runtime.Session.RuntimeFirstEntryDriveController firstEntry =
CreateFirstEntryDrive(runtime);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntityWithInitialResidence(Spawn(player), isLocalPlayer: true)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var collision = new FixtureCollisionNeighborhood();
var projection = new HeadlessSessionWorldProjection(
runtime,
collision,
firstEntry);
projection.ProjectSpawn(record, isLocalPlayer: true);
PlayerMovementController controller =
Assert.IsType(
runtime.MovementOwner.Controller);
controller.SeedPlacementForTest(
new Vector3(48f, 49f, 50f),
0xA9B40001u, new Vector3(48f, 49f, 50f));
projection.ProjectPosition(
record,
isLocalPlayer: true,
PositionTimestampDisposition.Apply);
Assert.Equal(new Vector3(48f, 49f, 50f), controller.Position);
var force = new WorldSession.EntityPositionUpdate(
player,
record.Snapshot.Position!.Value with
{
PositionX = 72f,
PositionY = 73f,
},
Velocity: null,
PlacementId: null,
IsGrounded: true,
InstanceSequence: 1,
PositionSequence: 2,
TeleportSequence: 0,
ForcePositionSequence: 1);
Assert.True(runtime.EntityObjects.TryApplyPosition(
force,
isLocalPlayer: true,
forcePositionRotation: Quaternion.Identity,
currentLocalVelocity: controller.BodyVelocity,
acknowledgeProjection: null,
out PositionTimestampDisposition disposition,
out _,
out AcceptedPhysicsTimestamps timestamps));
Assert.Equal(
PositionTimestampDisposition.ForcePosition,
disposition);
// C4 route 2 (2026-08-03): a ForcePosition on the local player no
// longer routes through HeadlessSessionWorldProjection.ProjectPosition
// at all — RuntimeLiveEntitySessionController.OnPositionUpdated
// dispatches it directly to RuntimeAcceptedPositionDriveController
// instead (the deleted BlipLocalPlayer's replacement), but R2 review
// fix (2026-08-03): it re-centers the collision neighborhood on the
// destination FIRST — the deleted BlipLocalPlayer's own CenterOn
// side effect, restored via CenterOnAcceptedForcePosition, because a
// DeferredCell park this neighborhood's window can never publish is
// a dead end, not a real park
// (RuntimeAcceptedPositionDriveController.Advance's R1 doc comment).
projection.CenterOnAcceptedForcePosition(record);
RuntimeAcceptedPositionDriveController acceptedPositionDrive =
CreateAcceptedPositionDrive(runtime);
RuntimeAcceptedPositionExecutionStatus forceStatus =
acceptedPositionDrive.TryExecuteAcceptedLocalPosition(
record,
force,
disposition,
timestamps,
timestamps.PreviousTeleport);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.Committed,
forceStatus);
// R7 review fix (2026-08-03): Z is 50.005f — within 5 mm of the
// wire's bare 50f — NOT 50.48f. The dat-exact human Setup's foot
// sphere is (0,0,0.475) r=.48 (LoadedSetupCollisionSource above);
// its bottom sits at origin + 0.475 − 0.48 = origin − 0.005, so a
// settled origin lands 0.005 m ABOVE the floor it rests on (measured
// empirically against this exact fixture), not a full sphere RADIUS
// above it. Retail's BlipPlayer (CPhysicsObj::SetPositionSimple
// @0x005162B0, called from SmartBox::BlipPlayer @0x00453940) has
// never lifted the origin by a sphere radius — the C4-route-2 FIRST
// implementation pass (uncommitted; this file asserts a bare 50f at
// HEAD, never 50.48f) had fitted a 50.48f assertion to a dummy
// fixture sphere whose offset happened to equal its own radius, not
// to retail behavior. The comment it carried described the sphere's
// CENTRE, then wrongly asserted that description about
// controller.Position, which is the body's ORIGIN
// (PlayerMovementController.cs -> PhysicsBody.cs Position), not the
// sphere centre.
Assert.Equal(new Vector3(72f, 73f, 50.005f), controller.Position);
// CenterCount is 2: ProjectSpawn's initial centering plus the
// ForcePosition's own re-centering above (R2's restored mechanism).
Assert.Equal(2, collision.CenterCount);
}
///
/// C3c-R1 review F7: a remote Create whose landblock lies outside the
/// bounded collision neighborhood's service window can never see its
/// deferred placement's collision-generation wake — left alone it would
/// pin its residence (and the drive's pending entry) for the whole
/// session. The host converts it to the celless completion route before
/// the pump: the residence completes with FullCell 0, the accepted wire
/// frame stays on the canonical snapshot (the exact pre-flip
/// accepted-frame behavior for far remotes), and every ledger converges.
///
[Fact]
public void FarRemoteCreateCompletesCelllessWithoutPinningItsResidence()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
const uint player = 0x5000000Bu;
runtime.PlayerIdentity.ServerGuid = player;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
0xA9B40000u, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
0xA9B40000u, 1UL, ready: true);
AcDream.Runtime.Session.RuntimeFirstEntryDriveController firstEntry =
CreateFirstEntryDrive(runtime);
var collision = new FixtureCollisionNeighborhood();
var projection = new HeadlessSessionWorldProjection(
runtime,
collision,
firstEntry);
RuntimeEntityRecord playerRecord = runtime.EntityObjects
.RegisterEntityWithInitialResidence(Spawn(player), isLocalPlayer: true)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
playerRecord,
playerRecord.CreateIntegrationVersion,
playerRecord.Snapshot,
replaceGeneration: false));
projection.ProjectSpawn(playerRecord, isLocalPlayer: true);
const uint farRemote = 0x70000010u;
const uint farCell = 0x00010001u;
Assert.False(collision.IsWithinServiceWindow(farCell));
RuntimeEntityRecord remote = runtime.EntityObjects
.RegisterEntityWithInitialResidence(
Spawn(farRemote, farCell),
isLocalPlayer: false)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
remote,
remote.CreateIntegrationVersion,
remote.Snapshot,
replaceGeneration: false));
projection.ProjectSpawn(remote, isLocalPlayer: false);
// Celless completion: no pinned residence, FullCell stays 0, the
// accepted wire frame survives on the canonical snapshot.
Assert.False(runtime.EntityObjects.TryGetInitialCreateResidence(
remote,
out _));
Assert.Equal(0u, remote.FullCellId);
Assert.Equal(
farCell,
remote.Snapshot.Position!.Value.LandblockId);
RuntimeEntityObjectOwnershipSnapshot ownership =
runtime.EntityObjects.CaptureOwnership();
Assert.Equal(0, ownership.InitialCreateResidenceLeaseCount);
Assert.Equal(0, ownership.FirstEntryDrivePendingCount);
Assert.Equal(0, firstEntry.PendingCount);
// Draining the placement FIFO the way the host subscription would
// converges the completion-receipt ledger too.
while (runtime.EntityObjects.Physics.SetPosition.TryPeekProjection(
out RuntimePlacementProjectionSnapshot head))
{
if (!runtime.EntityObjects.Physics.SetPosition
.AcknowledgeProjection(head.Token))
{
break;
}
}
Assert.Equal(
0,
runtime.EntityObjects.CaptureOwnership()
.PendingCompletionReceiptCount);
}
[Fact]
public void PlacementReceiptValidationDoesNotRegainMovementOrPhysicsAuthority()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
// C3c: conductor-driven flow — a live generation admits the initial
// residence, the flat landblock's collision generation commits, and
// the world projection's pump drives the local first-entry conductor
// to completion (the deleted SynchronizeLocalPlayer hand-copy's
// replacement).
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
const uint player = 0x50000004u;
runtime.PlayerIdentity.ServerGuid = player;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
0xA9B40000u, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
0xA9B40000u, 1UL, ready: true);
AcDream.Runtime.Session.RuntimeFirstEntryDriveController firstEntry =
CreateFirstEntryDrive(runtime);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntityWithInitialResidence(Spawn(player), isLocalPlayer: true)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var directProjection = new HeadlessSessionWorldProjection(
runtime,
new FixtureCollisionNeighborhood(),
firstEntry);
directProjection.ProjectSpawn(record, isLocalPlayer: true);
PlayerMovementController controller = Assert.IsType<
PlayerMovementController>(runtime.MovementOwner.Controller);
Vector3 positionBefore = controller.Position;
Quaternion orientationBefore = controller.BodyOrientation;
RuntimePhysicsOwnershipSnapshot physicsBefore =
runtime.EntityObjects.Physics.CaptureOwnership();
RuntimePlacementProjectionSnapshot receipt = Placement(
runtime,
record,
RuntimePlacementProjectionKind.Place,
new Vector3(600f, 601f, 602f),
Quaternion.CreateFromAxisAngle(Vector3.UnitY, 1.2f));
var receiptSink = new HeadlessRuntimePlacementProjectionSink(runtime);
Assert.True(receiptSink.TryApply(in receipt));
Assert.Equal(positionBefore, controller.Position);
Assert.Equal(orientationBefore, controller.BodyOrientation);
Assert.Equal(
physicsBefore,
runtime.EntityObjects.Physics.CaptureOwnership());
}
[Fact]
public void PlacementReceiptUsesExactIncarnationAndDiscardIsAckOnly()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntity(Spawn(0x50000005u))
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var projection = new HeadlessRuntimePlacementProjectionSink(runtime);
RuntimePlacementProjectionSnapshot place = Placement(
runtime,
record,
RuntimePlacementProjectionKind.Place,
Vector3.One,
Quaternion.Identity);
RuntimePlacementProjectionSnapshot stale = place with
{
Token = place.Token with
{
Entity = place.Token.Entity with
{
Incarnation = unchecked((ushort)(
place.Token.Entity.Incarnation + 1)),
},
},
};
RuntimePlacementProjectionSnapshot discard = stale with
{
Kind = RuntimePlacementProjectionKind.Discard,
Token = stale.Token with
{
SessionLifetimeVersion = ulong.MaxValue,
},
};
Assert.False(projection.TryApply(in stale));
Assert.True(projection.TryApply(in discard));
}
[Fact]
public void ExecutorCompletedReceiptIsAcknowledgeOnlyRegardlessOfRecordValidity()
{
// F1: mirrors PlacementReceiptUsesExactIncarnationAndDiscardIsAckOnly's
// stale-token half - proves ExecutorCompleted is acknowledged
// unconditionally (never gated by the record-lookup/portal-shape
// checks Place/Withdraw depend on), so a genuinely stale/mismatched
// token can never wedge the FIFO behind it.
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntity(Spawn(0x50000006u))
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var sink = new HeadlessRuntimePlacementProjectionSink(runtime);
RuntimePlacementProjectionSnapshot completion = Placement(
runtime,
record,
RuntimePlacementProjectionKind.ExecutorCompleted,
Vector3.One,
Quaternion.Identity);
RuntimePlacementProjectionSnapshot stale = completion with
{
Token = completion.Token with
{
Entity = completion.Token.Entity with
{
Incarnation = unchecked((ushort)(
completion.Token.Entity.Incarnation + 1)),
},
SessionLifetimeVersion = ulong.MaxValue,
},
};
Assert.True(sink.TryApply(in completion));
Assert.True(sink.TryApply(in stale));
}
[Fact]
public void SessionEventRouteOwnsOneObserverAndUnsubscribesBeforeNetworkDetach()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
int subscriberCountDuringDetach = -1;
var inner = new FixtureEventRoute(
onDispose: () => subscriberCountDuringDetach =
runtime.EntityObjects.Events.PlacementSubscriberCount);
var placements = new HeadlessRuntimePlacementProjectionSink(runtime);
var route = new HeadlessSessionEventRoute(
inner,
runtime,
placements);
Assert.Equal(
0,
runtime.EntityObjects.Events.PlacementSubscriberCount);
route.Attach();
route.Attach();
Assert.Equal(
1,
runtime.EntityObjects.Events.PlacementSubscriberCount);
Assert.Equal(1, inner.AttachCount);
route.Dispose();
route.Dispose();
Assert.Equal(0, subscriberCountDuringDetach);
Assert.Equal(
0,
runtime.EntityObjects.Events.PlacementSubscriberCount);
Assert.Equal(1, inner.DisposeCount);
}
[Fact]
public void ReplacementSessionEventRouteGetsOneFreshObserver()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
var placements = new HeadlessRuntimePlacementProjectionSink(runtime);
var first = new HeadlessSessionEventRoute(
new FixtureEventRoute(),
runtime,
placements);
first.Attach();
Assert.Equal(
1,
runtime.EntityObjects.Events.PlacementSubscriberCount);
first.Dispose();
Assert.Equal(
0,
runtime.EntityObjects.Events.PlacementSubscriberCount);
var replacement = new HeadlessSessionEventRoute(
new FixtureEventRoute(),
runtime,
placements);
replacement.Attach();
Assert.Equal(
1,
runtime.EntityObjects.Events.PlacementSubscriberCount);
replacement.Dispose();
Assert.Equal(
0,
runtime.EntityObjects.Events.PlacementSubscriberCount);
}
[Fact]
public void SessionEventRouteRetryDoesNotRestorePlacementObserver()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
var inner = new FixtureEventRoute
{
DisposeFailuresRemaining = 1,
};
var route = new HeadlessSessionEventRoute(
inner,
runtime,
new HeadlessRuntimePlacementProjectionSink(runtime));
route.Attach();
Assert.Throws(route.Dispose);
Assert.Equal(
0,
runtime.EntityObjects.Events.PlacementSubscriberCount);
Assert.Equal(1, inner.DisposeCount);
route.Dispose();
Assert.Equal(2, inner.DisposeCount);
Assert.Equal(
0,
runtime.EntityObjects.Events.PlacementSubscriberCount);
}
[Fact]
public void CollisionTransactionCancelsPostAdmissionFaultWithoutWithdrawingActiveWorld()
{
using var lifetime = new RuntimeEntityObjectLifetime();
RuntimePhysicsState physics = lifetime.Physics;
const uint landblockId = 0xA9B4FFFFu;
CompleteCollisionGeneration(
physics,
landblockId,
afterAdmission: null,
(admission, prepared) =>
physics.StageCollisionAssets(
admission,
prepared,
CollisionAssets(landblockId, 10f)));
Assert.Throws(() =>
CompleteCollisionGeneration(
physics,
landblockId,
_ => throw new FixtureCollisionPublicationException(),
(_, _) => throw new InvalidOperationException(
"Staging must not run after the injected admission fault.")));
Assert.Equal(10f, physics.Engine.SampleTerrainZ(1f, 1f));
RuntimePhysicsOwnershipSnapshot ownership = physics.CaptureOwnership();
Assert.Equal(1, ownership.LandblockCount);
Assert.Equal(0, ownership.CollisionAdmissionCount);
}
[Fact]
public void CollisionTransactionYieldsTheFirstNonterminalRuntimePoll()
{
using var lifetime = new RuntimeEntityObjectLifetime();
RuntimePhysicsState physics = lifetime.Physics;
const uint landblockId = 0xA9B4FFFFu;
HeadlessCollisionGenerationTransaction transaction =
HeadlessCollisionGenerationTransaction.Begin(
physics,
landblockId,
afterAdmission: null,
(admission, prepared) =>
physics.StageCollisionAssets(
admission,
prepared,
CollisionAssets(landblockId, 10f)));
HeadlessCollisionGenerationAdvance advance;
do
{
advance = transaction.Advance();
Assert.True(advance.Progressed);
}
while (!advance.YieldToCaller);
Assert.False(advance.Completed);
Assert.False(advance.WaitingForProjectionAcknowledgement);
Assert.False(transaction.CompletionCommitted);
do
{
advance = transaction.Advance();
Assert.True(advance.Progressed);
}
while (!advance.Completed && !advance.YieldToCaller);
if (!advance.Completed)
advance = transaction.Advance();
Assert.True(advance.Completed);
Assert.True(transaction.EngineMutationCommitted);
Assert.True(transaction.CompletionCommitted);
Assert.Equal(0, physics.CaptureOwnership().CollisionAdmissionCount);
}
[Fact]
public void CollisionTransactionRetainsPostEngineCancellationUntilPlaceAck()
{
using var lifetime = new RuntimeEntityObjectLifetime();
RuntimePhysicsState physics = lifetime.Physics;
const uint landblockId = 0xA9B4FFFFu;
CompleteCollisionGeneration(
physics,
landblockId,
afterAdmission: null,
(admission, prepared) =>
physics.StageCollisionAssets(
admission,
prepared,
CollisionAssets(landblockId, 10f)));
const uint guid = 0x70004201u;
const uint cell = 0xA9B40001u;
Vector3 position = new(10f, 10f, 0f);
RuntimeEntityRecord record = lifetime.RegisterEntity(
Spawn(guid)).Canonical!;
lifetime.Entities.SetFinalPhysicsState(record, PhysicsStateFlags.Gravity);
lifetime.Entities.SetFullCell(record, cell, landblockId);
var body = new PhysicsBody
{
Position = position,
Orientation = Quaternion.Identity,
LastUpdateTime = 1d,
State = PhysicsStateFlags.Gravity,
TransientState = TransientStateFlags.Active,
};
body.SnapToCell(cell, position, position);
lifetime.Entities.SetPhysicsBody(record, body);
record.ObjectClock.Activate();
physics.AcknowledgeSpatialProjection(record, spatial: true);
RuntimePlacementProjectionToken seeded = SeedRuntimePlacement(
physics,
record,
cell,
position);
Assert.True(physics.SetPosition.AcknowledgeProjection(seeded));
HeadlessCollisionGenerationTransaction transaction =
HeadlessCollisionGenerationTransaction.Begin(
physics,
landblockId,
afterAdmission: null,
(admission, prepared) =>
physics.StageCollisionAssets(
admission,
prepared,
CollisionAssets(landblockId, 20f)));
HeadlessCollisionGenerationAdvance advance;
do
{
advance = transaction.Advance();
}
while (!advance.WaitingForProjectionAcknowledgement);
Assert.False(transaction.EngineMutationCommitted);
Assert.True(physics.SetPosition.TryPeekProjection(
out RuntimePlacementProjectionSnapshot withdrawal));
Assert.True(physics.SetPosition.AcknowledgeProjection(withdrawal.Token));
do
{
advance = transaction.Advance();
}
while (!advance.WaitingForProjectionAcknowledgement);
Assert.True(transaction.EngineMutationCommitted);
Assert.True(physics.SetPosition.TryPeekProjection(
out RuntimePlacementProjectionSnapshot placement));
Assert.False(transaction.TryCancel());
Assert.True(physics.SetPosition.AcknowledgeProjection(placement.Token));
Assert.True(transaction.TryCancel());
RuntimePhysicsOwnershipSnapshot ownership = physics.CaptureOwnership();
Assert.Equal(0, ownership.CollisionPrefixMutationCount);
Assert.Equal(0, ownership.CollisionAdmissionCount);
}
[Fact]
public void CollisionTransactionCancelsStagingFaultWithoutWithdrawingActiveWorld()
{
using var lifetime = new RuntimeEntityObjectLifetime();
RuntimePhysicsState physics = lifetime.Physics;
const uint landblockId = 0xA9B4FFFFu;
CompleteCollisionGeneration(
physics,
landblockId,
afterAdmission: null,
(admission, prepared) =>
physics.StageCollisionAssets(
admission,
prepared,
CollisionAssets(landblockId, 10f)));
Assert.Throws(() =>
CompleteCollisionGeneration(
physics,
landblockId,
afterAdmission: null,
(admission, prepared) =>
{
physics.StageCollisionAssets(
admission,
prepared,
CollisionAssets(landblockId, 25f));
throw new FixtureCollisionPublicationException();
}));
Assert.Equal(10f, physics.Engine.SampleTerrainZ(1f, 1f));
RuntimePhysicsOwnershipSnapshot ownership = physics.CaptureOwnership();
Assert.Equal(1, ownership.LandblockCount);
Assert.Equal(0, ownership.CollisionAdmissionCount);
}
///
/// #365 test 3 — the coverage gap the diagnosis doc's Q4 names
/// (HeadlessSessionHostTests.cs:347-475's existing
///
/// uses , which is trivially
/// ready and never opens a real admission — the production
/// HeadlessCollisionNeighborhood has never been exercised against
/// the first-entry conductor while an admission was genuinely open).
/// The player's OWN landblock is prepared the same proven way every
/// other test in this file does (AddFlatLandblock +
/// SetPosition.BeginCollisionGeneration/
/// CommitCollisionGeneration) so it is unconditionally resident —
/// instead
/// holds a SEPARATE REAL open on
/// a DIFFERENT landblock, the same shape as one of the OTHER eight
/// landblocks in production's real 3x3 publication plan — proving Step
/// 3a's gate covers "an admission is open ANYWHERE in the plan", not
/// just the center.
///
///
/// Consolidated-review round (2026-08-10), NIT (c): what THIS bounded
/// xunit test proves is the GATE, not the #365 hydration stall's
/// closure — that broader claim's evidence is the separate live-ACE
/// end-to-end run recorded in
/// docs/research/2026-08-10-365-headless-hydration-diagnosis.md
/// §8 ("hydration now succeeds ... entityCount reaches 136"). This
/// test's own scope is narrower and fully mechanical: the conductor
/// stays undriven (runtime.MovementOwner.Controller stays null)
/// for as long as the unrelated admission is held open, and drives and
/// reaches IsRuntimePublished within a bounded tick budget once
/// it releases. Temporarily reverting the three IsQuiescent
/// gates in HeadlessSessionWorldProjection.ProjectSpawn/
/// ProjectPosition/PumpFirstEntry (never committed — see
/// §8's "Verification that the new test... actually discriminates")
/// makes this test fail the SAME way §8 itself observed: the
/// Assert.Null(runtime.MovementOwner.Controller) checks below
/// fail because the controller is ALREADY built AND published
/// (CanExecuteLiveMovement = True) while the unrelated admission
/// is still open — not merely "reached PublicationCommitted,
/// still dormant" as an earlier draft of this comment claimed; that
/// wording described a weaker intermediate state than what reverting
/// the gate actually produces.
///
[Fact]
public void RealAdmissionNeverDrivesTheConductorWhileOpenAndHydratesOnceReleased()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
const uint player = 0x50000012u;
const uint neighborLandblockId = 0xAAB4FFFFu;
runtime.PlayerIdentity.ServerGuid = player;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
0xA9B40000u, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
0xA9B40000u, 1UL, ready: true);
AcDream.Runtime.Session.RuntimeFirstEntryDriveController firstEntry =
CreateFirstEntryDrive(runtime);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntityWithInitialResidence(
Spawn(player),
isLocalPlayer: true)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var collision = new NeighborAdmissionHeldOpenCollisionNeighborhood(
runtime.EntityObjects.Physics,
neighborLandblockId);
collision.OpenHeldAdmission();
var projection = new HeadlessSessionWorldProjection(
runtime,
collision,
firstEntry);
projection.ProjectSpawn(record, isLocalPlayer: true);
Assert.False(collision.IsQuiescent);
Assert.Null(runtime.MovementOwner.Controller);
// Hold the SEPARATE admission open across many pumps — far longer
// than the conductor needs to reach mover-prep/placement/
// PublicationCommitted on the ALREADY-READY player landblock, so a
// pre-fix conductor being undriven only by luck of a short window
// cannot slip through.
for (int tick = 0; tick < 50; tick++)
{
projection.PumpFirstEntry();
Assert.False(collision.IsQuiescent);
Assert.Null(runtime.MovementOwner.Controller);
}
collision.ReleaseHeldAdmission();
Assert.True(collision.IsQuiescent);
const int boundedTicks = 200;
bool published = false;
for (int tick = 0; tick < boundedTicks; tick++)
{
projection.PumpFirstEntry();
if (runtime.MovementOwner.Controller is { IsRuntimePublished: true })
{
published = true;
break;
}
}
Assert.True(
published,
"the local player never reached RuntimePublished within the "
+ "bounded tick budget after the unrelated admission cleared.");
PlayerMovementController controller = Assert.IsType<
PlayerMovementController>(runtime.MovementOwner.Controller);
Assert.True(controller.IsRuntimePublished);
Assert.Equal(0, firstEntry.PendingCount);
}
///
/// #365 test 4: PumpFirstEntry must not call DriveAll while
/// the collision neighborhood reports non-quiescent, and must call it on
/// the first tick after quiescence — the exact Step 3a gate, isolated
/// from the admission machinery itself via a directly-controllable fake.
///
[Fact]
public void PumpFirstEntryWithholdsDriveAllUntilQuiescentThenDrivesImmediately()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
const uint player = 0x50000013u;
runtime.PlayerIdentity.ServerGuid = player;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
0xA9B40000u, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
0xA9B40000u, 1UL, ready: true);
AcDream.Runtime.Session.RuntimeFirstEntryDriveController firstEntry =
CreateFirstEntryDrive(runtime);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntityWithInitialResidence(Spawn(player), isLocalPlayer: true)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var collision = new GateControllableCollisionNeighborhood
{
QuiescentOverride = false,
};
var projection = new HeadlessSessionWorldProjection(
runtime,
collision,
firstEntry);
projection.ProjectSpawn(record, isLocalPlayer: true);
Assert.Null(runtime.MovementOwner.Controller);
Assert.Equal(1, firstEntry.PendingCount);
projection.PumpFirstEntry();
Assert.Null(runtime.MovementOwner.Controller);
Assert.Equal(1, firstEntry.PendingCount);
collision.QuiescentOverride = true;
projection.PumpFirstEntry();
Assert.NotNull(runtime.MovementOwner.Controller);
}
///
/// #365 test 5: HeadlessLocalPlayerFrameHost.CanAdvancePlayer
/// tracks the controller's exact publication lifecycle — false while
/// dormant (the crash bug's shape), true once published, false again
/// once retired (the #356 lifecycle-caller idiom).
///
[Fact]
public void CanAdvancePlayerReflectsControllerPublicationLifecycle()
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
Assert.True(runtime.Session.IsInWorld);
var inertSession = CreateInertLiveSessionHost();
var frameHost = new HeadlessLocalPlayerFrameHost(runtime, inertSession);
PlayerMovementController candidate =
PlayerMovementController.CreatePublicationCandidate(
new PhysicsEngine(),
PlayerMovementConstructionOptions.Fallback);
candidate.SealPublicationCandidate();
candidate.CommitRuntimeOwnership(new RetailObjectQuantumClock());
runtime.MovementOwner.Controller = candidate;
Assert.True(candidate.IsRuntimeOwnedDormant);
Assert.False(frameHost.CanAdvancePlayer);
candidate.ActivateRuntimePublication();
Assert.True(candidate.IsRuntimePublished);
Assert.True(frameHost.CanAdvancePlayer);
candidate.RetireRuntimePublication();
Assert.False(frameHost.CanAdvancePlayer);
}
private static LiveSessionHost CreateInertLiveSessionHost()
{
var controller = new LiveSessionController(
new ThrowingLiveSessionOperations());
return new LiveSessionHost(
controller,
new LiveSessionHostBindings(
new LiveSessionRoutingFactories(
_ => throw new NotSupportedException(),
_ => throw new NotSupportedException()),
_ => { },
new LiveSessionSelectionBindings(
_ => { },
_ => { },
_ => { },
_ => { },
_ => { },
() => { }),
new LiveSessionEnteredWorldBindings(
_ => { },
() => { },
() => { },
_ => { },
() => { }),
(_, _, _) => { },
() => { },
_ => { },
_ => { }));
}
private sealed class ThrowingLiveSessionOperations : ILiveSessionOperations
{
public IPEndPoint ResolveEndpoint(string host, int port) =>
throw new NotSupportedException();
public WorldSession CreateSession(IPEndPoint endpoint) =>
throw new NotSupportedException();
public void Connect(
WorldSession session,
string user,
string password) =>
throw new NotSupportedException();
public CharacterList.Parsed? GetCharacters(WorldSession session) =>
throw new NotSupportedException();
public void EnterWorld(
WorldSession session,
int activeCharacterIndex) =>
throw new NotSupportedException();
public void Tick(WorldSession session) =>
throw new NotSupportedException();
public void DisposeSession(WorldSession session) =>
throw new NotSupportedException();
}
private static HeadlessSessionDescriptor Descriptor(
HeadlessCredentialProviderKind provider =
HeadlessCredentialProviderKind.Environment,
string credentialReference = "BOT_PASSWORD",
Dictionary? characterOptions = null,
string? statusFile = null) => new()
{
Id = "bot",
Endpoint = new HeadlessEndpointDescriptor
{
Host = "127.0.0.1",
Port = 9000,
},
Account = "account",
Character = new HeadlessCharacterSelector
{
Name = "headless",
},
Policy = new HeadlessBotPolicyDescriptor
{
Id = "idle",
},
Credential = new HeadlessCredentialReference
{
Provider = provider,
Reference = credentialReference,
},
CharacterOptions = characterOptions,
StatusFile = statusFile,
};
/// Campaign LA slice LA2: a probe-mode descriptor — mode
/// "probe", Character/Policy both omitted per the pinned
/// contract shape enforces.
private static HeadlessSessionDescriptor ProbeDescriptor(
string id = "probe-bot",
HeadlessCredentialProviderKind provider =
HeadlessCredentialProviderKind.Environment,
string credentialReference = "PROBE_PASSWORD",
string? statusFile = null) => new()
{
Id = id,
Endpoint = new HeadlessEndpointDescriptor
{
Host = "127.0.0.1",
Port = 9000,
},
Account = "account",
Mode = HeadlessSessionMode.Probe,
Credential = new HeadlessCredentialReference
{
Provider = provider,
Reference = credentialReference,
},
StatusFile = statusFile,
};
private static string[] ReadStatusEventNames(string path) =>
File.ReadAllLines(path)
.Select(static line =>
{
using JsonDocument document = JsonDocument.Parse(line);
return document.RootElement.GetProperty("e").GetString()!;
})
.ToArray();
private static void HydrateGroundedPlayer(GameRuntime runtime)
{
const uint player = 0x50000002u;
PhysicsEngine engine = runtime.EntityObjects.Physics.Engine;
AddFlatLandblock(engine);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntity(Spawn(player))
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var controller = new PlayerMovementController(engine);
controller.SeedPlacementForTest(
new Vector3(96f, 97f, 50f),
0xA9B40001u,
new Vector3(96f, 97f, 50f));
runtime.MovementOwner.Controller = controller;
}
private static void CompleteCollisionGeneration(
RuntimePhysicsState physics,
uint landblockId,
Action? afterAdmission,
Action stage)
{
HeadlessCollisionGenerationTransaction transaction =
HeadlessCollisionGenerationTransaction.Begin(
physics,
landblockId,
afterAdmission,
stage);
while (true)
{
HeadlessCollisionGenerationAdvance advance = transaction.Advance();
if (advance.Completed)
return;
Assert.True(advance.Progressed);
Assert.False(advance.WaitingForProjectionAcknowledgement);
}
}
private static RuntimePlacementProjectionToken SeedRuntimePlacement(
RuntimePhysicsState physics,
RuntimeEntityRecord record,
uint cell,
Vector3 position)
{
Type coreMarker = typeof(PhysicsEngine);
Type requestType = coreMarker.Assembly.GetType(
"AcDream.Core.Physics.PhysicsSetPositionRequest",
throwOnError: true)!;
Type flagsType = coreMarker.Assembly.GetType(
"AcDream.Core.Physics.PhysicsSetPositionFlags",
throwOnError: true)!;
Type placementClassType = coreMarker.Assembly.GetType(
"AcDream.Core.Physics.PhysicsPlacementClass",
throwOnError: true)!;
object request = Activator.CreateInstance(
requestType,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
binder: null,
args:
[
position,
Quaternion.Identity,
cell,
position,
ImmutableArray.Empty,
1f,
0.4f,
0.4f,
PhysicsStateFlags.None,
ObjectInfoState.None,
0u,
Enum.ToObject(placementClassType, 0),
Enum.ToObject(flagsType, 0x011u),
Vector3.Zero,
0f,
0f,
0u,
cell,
],
culture: null)!;
Type runtimeMarker = typeof(RuntimePhysicsState);
Type commandType = runtimeMarker.Assembly.GetType(
"AcDream.Runtime.Physics.RuntimeSetPositionCommand",
throwOnError: true)!;
Type kindType = runtimeMarker.Assembly.GetType(
"AcDream.Runtime.Physics.RuntimeSetPositionOperationKind",
throwOnError: true)!;
object command = Activator.CreateInstance(
commandType,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
binder: null,
args:
[
request,
Enum.ToObject(kindType, 2),
10d,
0UL,
0f,
0f,
default(RuntimePortalPlacementAuthority),
],
culture: null)!;
MethodInfo apply = physics.SetPosition.GetType().GetMethod(
"Apply",
BindingFlags.Instance | BindingFlags.NonPublic)
?? throw new MissingMethodException("Runtime SetPosition.Apply");
object outcome = apply.Invoke(
physics.SetPosition,
[record, record.PositionAuthorityVersion, command])!;
return (RuntimePlacementProjectionToken)(outcome.GetType().GetProperty(
"Projection",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
?.GetValue(outcome)
?? throw new MissingMemberException("Runtime placement projection"));
}
private static RuntimeLandblockCollisionAssets CollisionAssets(
uint landblockId,
float terrainHeight)
{
var heights = new byte[81];
var table = new float[256];
table[0] = terrainHeight;
return new RuntimeLandblockCollisionAssets(
landblockId,
new TerrainSurface(heights, table),
Array.Empty(),
Array.Empty(),
0f,
0f,
0u);
}
private sealed class FixtureCollisionPublicationException : Exception;
[Fact]
public void MissingPreparedCollisionYieldsTypedRetryAndCompletesWhenAvailable()
{
// C3c contract: the prepared-collision read failure is the
// conductor's typed AwaitingCollisionSource retry — no
// InvalidDataException (or any exception) escapes the host wiring,
// the entity stays a tracked, re-drivable first entry, and the same
// sequence completes once the source can serve the Setup.
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
const uint player = 0x50000021u;
runtime.PlayerIdentity.ServerGuid = player;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
0xA9B40000u, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
0xA9B40000u, 1UL, ready: true);
var source = new FlakySetupCollisionSource();
var firstEntry = new AcDream.Runtime.Session
.RuntimeFirstEntryDriveController(
runtime.EntityObjects,
runtime.Clock,
source,
() => PlayerMovementConstructionOptions.From(
runtime.CharacterOwner.MovementSkills.Snapshot),
static _ => new RuntimeLocalPlayerPhysicsActivationPreparation(
Radius: 0.48f,
Height: 1.835f,
RuntimeLocalPlayerShadowDisposition.ProvenShapeless));
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntityWithInitialResidence(Spawn(player), isLocalPlayer: true)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var collision = new FixtureCollisionNeighborhood();
var projection = new HeadlessSessionWorldProjection(
runtime,
collision,
firstEntry);
projection.ProjectSpawn(record, isLocalPlayer: true);
Assert.True(source.SetupReadAttempts >= 1);
Assert.Null(runtime.MovementOwner.Controller);
Assert.Equal(1, firstEntry.PendingCount);
Assert.Equal(0u, record.FullCellId);
source.Available = true;
// The session tick's retry pump.
firstEntry.DriveAll();
Assert.IsType(
runtime.MovementOwner.Controller);
Assert.Equal(0, firstEntry.PendingCount);
Assert.Equal(0xA9B40000u, record.FullCellId & 0xFFFF0000u);
Assert.NotEqual(0u, record.FullCellId);
}
private sealed class FlakySetupCollisionSource
: AcDream.Content.IPreparedCollisionSource
{
internal bool Available { get; set; }
internal int SetupReadAttempts { get; private set; }
public AcDream.Content.PreparedAssetPresence ProbeCollision(
AcDream.Content.Pak.PakAssetType type,
uint sourceFileId) =>
AcDream.Content.PreparedAssetPresence.Available;
public AcDream.Content.PreparedCollisionReadResult
ReadSetupCollision(
uint sourceFileId,
CancellationToken cancellationToken = default)
{
SetupReadAttempts++;
if (!Available)
{
return AcDream.Content.PreparedCollisionReadResult<
FlatSetupCollision>.Missing;
}
return AcDream.Content.PreparedCollisionReadResult<
FlatSetupCollision>.Loaded(new FlatSetupCollision(
System.Collections.Immutable.ImmutableArray<
FlatCollisionCylinder>.Empty,
[new FlatCollisionSphere(Vector3.Zero, 0.48f)],
height: 0f,
radius: 0f,
stepUpHeight: 0.4f,
stepDownHeight: 0.4f));
}
public AcDream.Content.PreparedCollisionReadResult<
FlatGfxObjCollisionAsset> ReadGfxObjCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionReadResult<
FlatCellStructureCollisionAsset> ReadCellStructureCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionReadResult
ReadEnvCellTopology(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionSourceStats CollisionStats =>
default;
public void Dispose()
{
}
}
private static AcDream.Runtime.Session.RuntimeFirstEntryDriveController
CreateFirstEntryDrive(GameRuntime runtime) => new(
runtime.EntityObjects,
runtime.Clock,
new LoadedSetupCollisionSource(),
() => PlayerMovementConstructionOptions.From(
runtime.CharacterOwner.MovementSkills.Snapshot),
static _ => new RuntimeLocalPlayerPhysicsActivationPreparation(
Radius: 0.48f,
Height: 1.835f,
RuntimeLocalPlayerShadowDisposition.ProvenShapeless));
///
/// C4 route 2 (2026-08-03): mirrors 's
/// construction pattern for the accepted-Position drive controller. No
/// real WorldSession is needed for these fixture tests —
/// LocalPlayerOutboundController.SendImmediatePosition no-ops on a null
/// session.
///
private static RuntimeAcceptedPositionDriveController
CreateAcceptedPositionDrive(GameRuntime runtime) => new(
runtime.EntityObjects,
runtime.Clock,
new LoadedSetupCollisionSource(),
new LocalPlayerOutboundController((_, _, _, _, _, _) => { }),
() => runtime.Generation,
() => runtime.PlayerIdentity.ServerGuid,
() => runtime.MovementOwner.Controller,
() => runtime.CharacterOwner.UsePositionFromServer,
() => null);
private sealed class LoadedSetupCollisionSource
: AcDream.Content.IPreparedCollisionSource
{
public AcDream.Content.PreparedAssetPresence ProbeCollision(
AcDream.Content.Pak.PakAssetType type,
uint sourceFileId) =>
AcDream.Content.PreparedAssetPresence.Available;
public AcDream.Content.PreparedCollisionReadResult
ReadSetupCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
AcDream.Content.PreparedCollisionReadResult
.Loaded(new FlatSetupCollision(
System.Collections.Immutable.ImmutableArray<
FlatCollisionCylinder>.Empty,
// R7 review fix (2026-08-03): the dat-exact human Setup
// 0x02000001 spheres (Ts46SphereListConformanceTests.cs
// :35-39) — foot (0,0,0.475) r=.48, head/torso
// (0,0,1.350) r=.48. The PREVIOUS single dummy sphere at
// (0,0,0) r=.48 (offset == radius) made a settled origin
// rest a FULL radius above the floor; the real foot
// sphere's bottom is origin + 0.475 − 0.48 = origin −
// 0.005, so a settled origin lands ON the floor within
// 5 mm. Retail's BlipPlayer has never lifted the origin
// by a sphere radius — that was a fixture artifact, not
// a retail-fidelity gain (docs/ISSUES.md #285 correction).
[
new FlatCollisionSphere(
new Vector3(0f, 0f, 0.475f), 0.48f),
new FlatCollisionSphere(
new Vector3(0f, 0f, 1.350f), 0.48f),
],
height: 0f,
radius: 0f,
stepUpHeight: 0.4f,
stepDownHeight: 0.4f));
public AcDream.Content.PreparedCollisionReadResult<
FlatGfxObjCollisionAsset> ReadGfxObjCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionReadResult<
FlatCellStructureCollisionAsset> ReadCellStructureCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionReadResult
ReadEnvCellTopology(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionSourceStats CollisionStats =>
default;
public void Dispose()
{
}
}
///
/// D1 (C5b architecture review), the local-player FORCE arm — both
/// directions of the reachability rule, driven through the real
/// sink.
///
///
/// The graphical OnPosition route returns ahead of AD-60's W2
/// for every force status EXCEPT NotApplicable, and falls
/// through to it on that one. So: a force the drive HANDLED
/// (Committed here) is placement-receipt-authoritative and this
/// route must leave residency at the cell the placement RESOLVED, not
/// re-stamp the wire cell over it; a force the drive did NOT handle
/// (no drive at all — the login-window / route-1 shape) must still
/// refresh the cell, because nothing else will.
///
///
[Theory]
[InlineData(true)]
[InlineData(false)]
public void LocalForcePosition_CommitsTheWireCellOnlyWhenTheDriveDeclined(
bool driveHandlesIt)
{
var operations = new FixtureSessionOperations();
using var credential = new HeadlessCredentialSecret(
"fixture",
"password");
using var host = new HeadlessSessionHost(
Descriptor(),
credential,
new HeadlessDiagnosticWriter(TextWriter.Null),
operations);
GameRuntime runtime = host.Runtime;
Assert.Equal(
RuntimeSessionStartStatus.Connected,
host.Start().Status);
const uint player = 0x50000004u;
runtime.PlayerIdentity.ServerGuid = player;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
0xA9B40000u, 1UL);
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
0xA9B40000u, 1UL, ready: true);
RuntimeFirstEntryDriveController firstEntry =
CreateFirstEntryDrive(runtime);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntityWithInitialResidence(
Spawn(player),
isLocalPlayer: true)
.Canonical!;
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
record,
record.CreateIntegrationVersion,
record.Snapshot,
replaceGeneration: false));
var collision = new FixtureCollisionNeighborhood();
var projection = new HeadlessSessionWorldProjection(
runtime,
collision,
firstEntry);
projection.ProjectSpawn(record, isLocalPlayer: true);
PlayerMovementController controller =
Assert.IsType(
runtime.MovementOwner.Controller);
controller.SeedPlacementForTest(
new Vector3(48f, 49f, 50f),
0xA9B40001u,
new Vector3(48f, 49f, 50f));
// The residence must be closed before the ordinary post-residence
// rules apply at all (the conductor is the sole cell authority
// while it is open — asserted separately in the Runtime suite).
Assert.False(runtime.EntityObjects.TryGetInitialCreateResidence(
record,
out _));
using var session = new WorldSession(
new IPEndPoint(IPAddress.Loopback, 9000));
var entities = new RuntimeLiveEntitySessionController(
runtime,
session,
log: null,
projection,
driveHandlesIt ? CreateAcceptedPositionDrive(runtime) : null);
LiveEntitySessionSink sink = entities.CreateSink();
// A wire cell that is NOT the cell a placement at (72,73) resolves
// to, so "committed the wire cell" and "kept the placement's own
// resolved cell" are distinguishable values rather than the same
// number arrived at two ways.
const uint wireCell = 0xA9B40002u;
sink.PositionUpdated(new WorldSession.EntityPositionUpdate(
player,
new CreateObject.ServerPosition(
wireCell, 72f, 73f, 50f, 1f, 0f, 0f, 0f),
Velocity: null,
PlacementId: null,
IsGrounded: true,
InstanceSequence: 1,
PositionSequence: 2,
TeleportSequence: 0,
ForcePositionSequence: 1));
if (driveHandlesIt)
{
// The placement committed and resolved its OWN cell — measured
// 0xA9B4001C, the outdoor landcell that actually contains
// (72, 73) in this flat landblock, which is neither the wire
// cell nor the spawn cell. This route added nothing on top of
// it.
Assert.Equal(new Vector3(72f, 73f, 50.005f), controller.Position);
Assert.Equal(0xA9B4001Cu, record.FullCellId);
Assert.NotEqual(wireCell, record.FullCellId);
}
else
{
Assert.Equal(wireCell, record.FullCellId);
Assert.Equal(0xA9B4FFFFu, record.CanonicalLandblockId);
}
}
private static void AddFlatLandblock(PhysicsEngine engine)
{
var heights = new byte[81];
Array.Fill(heights, (byte)50);
var heightTable = new float[256];
for (int index = 0; index < heightTable.Length; index++)
heightTable[index] = index;
engine.AddLandblock(
0xA9B4FFFFu,
new TerrainSurface(heights, heightTable),
[],
[],
worldOffsetX: 0f,
worldOffsetY: 0f);
}
private static WorldSession.EntitySpawn Spawn(
uint guid,
uint cellId = 0xA9B40001u)
{
var position = new CreateObject.ServerPosition(
cellId,
96f,
97f,
50f,
1f,
0f,
0f,
0f);
var timestamps = new PhysicsTimestamps(
Position: 1,
Movement: 1,
State: 1,
Vector: 1,
Teleport: 0,
ServerControlledMove: 1,
ForcePosition: 0,
ObjDesc: 1,
Instance: 1);
var physics = new PhysicsSpawnData(
RawState: (uint)PhysicsStateFlags.ReportCollisions,
Position: position,
Movement: null,
AnimationFrame: null,
SetupTableId: 0x02000001u,
MotionTableId: null,
SoundTableId: null,
PhysicsScriptTableId: null,
Parent: null,
Children: null,
Scale: null,
Friction: null,
Elasticity: null,
Translucency: null,
Velocity: null,
Acceleration: null,
AngularVelocity: null,
DefaultScriptType: null,
DefaultScriptIntensity: null,
Timestamps: timestamps);
return new WorldSession.EntitySpawn(
guid,
position,
0x02000001u,
[],
[],
[],
null,
null,
"Headless",
null,
null,
null,
PhysicsState: physics.RawState,
InstanceSequence: 1,
MovementSequence: 1,
ServerControlSequence: 1,
PositionSequence: 1,
Physics: physics);
}
private static RuntimePlacementProjectionSnapshot Placement(
GameRuntime runtime,
RuntimeEntityRecord record,
RuntimePlacementProjectionKind kind,
Vector3 position,
Quaternion orientation)
{
RuntimeEntityKey key = Assert.IsType(record.Key);
var token = new RuntimePlacementProjectionToken(
Sequence: 1,
Revision: 1,
Entity: key,
PositionAuthorityVersion: record.PositionAuthorityVersion,
SpatialAuthorityVersion: record.SpatialAuthorityVersion,
PlacementCommitVersion: record.PlacementCommitVersion,
SessionLifetimeVersion:
runtime.EntityObjects.Entities.SessionLifetimeVersion,
ExactCellId: record.FullCellId,
CollisionGeneration: 1,
Portal: default);
return new RuntimePlacementProjectionSnapshot(
token,
kind,
position,
orientation,
CellLocalPosition: position,
InContact: false,
OnWalkable: false);
}
private static uint ActionOpcode(byte[] body) =>
BinaryPrimitives.ReadUInt32LittleEndian(
body.AsSpan(8, sizeof(uint)));
// SF-4 fixture: minimal PlayerDescription (0x0013) body carrying only
// the CharacterOptions1/2 trailer fields — copied from
// HeadlessCharacterOptionsSeederWiringTests.WrapPlayerDescriptionEnvelope
// (mirrors GameEventWiringTests.WireAll_PlayerDescription_PublishesCharacterOptions's
// fixture layout).
private static byte[] WrapPlayerDescriptionEnvelope(
uint options1,
uint options2)
{
var stream = new MemoryStream();
using (var writer = new BinaryWriter(
stream, System.Text.Encoding.UTF8, leaveOpen: true))
{
writer.Write(0u); // property flags
writer.Write(0x52u); // player weenie type
writer.Write(0u); // vector flags
writer.Write(0u); // has health
writer.Write(0x40u); // option flags: CharacterOptions2
writer.Write(options1);
writer.Write(0u); // legacy hotbar count
writer.Write(0u); // spellbook filters
writer.Write(options2);
writer.Write(0u); // inventory count
writer.Write(0u); // equipped count
}
byte[] payload = stream.ToArray();
byte[] body = new byte[GameEventEnvelope.HeaderSize + payload.Length];
BinaryPrimitives.WriteUInt32LittleEndian(body, GameEventEnvelope.Opcode);
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(4), 0u);
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(8), 0u);
BinaryPrimitives.WriteUInt32LittleEndian(
body.AsSpan(12), (uint)GameEventType.PlayerDescription);
Array.Copy(payload, 0, body, GameEventEnvelope.HeaderSize, payload.Length);
return body;
}
private sealed class FixtureSessionOperations : ILiveSessionOperations
{
private int _enterWorldCallCount;
private int _tickCallCount;
public List Sessions { get; } = [];
public int CreatedSessionCount { get; private set; }
public int DisposedSessionCount { get; private set; }
public string? LastUser { get; private set; }
public string? LastPassword { get; private set; }
public int EnterWorldCallCount =>
Volatile.Read(ref _enterWorldCallCount);
public int TickCallCount => Volatile.Read(ref _tickCallCount);
public IPEndPoint ResolveEndpoint(string host, int port) =>
new(IPAddress.Loopback, port);
public WorldSession CreateSession(IPEndPoint endpoint)
{
CreatedSessionCount++;
var session = new WorldSession(endpoint);
Sessions.Add(session);
return session;
}
public void Connect(
WorldSession session,
string user,
string password)
{
LastUser = user;
LastPassword = password;
}
public CharacterList.Parsed GetCharacters(
WorldSession session) =>
new(
0u,
[
new CharacterList.Character(
0x50000001u,
"Other",
0u),
new CharacterList.Character(
0x50000002u,
"Headless",
0u),
],
[],
11,
"account",
true,
true);
public void EnterWorld(
WorldSession session,
int activeCharacterIndex)
{
Interlocked.Increment(ref _enterWorldCallCount);
}
public void Tick(WorldSession session)
{
Interlocked.Increment(ref _tickCallCount);
}
public void DisposeSession(WorldSession session)
{
DisposedSessionCount++;
session.Dispose();
}
}
private sealed class FailOnceTextWriter : StringWriter
{
public bool FailNextWrite { get; set; }
public override void WriteLine(string? value)
{
if (FailNextWrite)
{
FailNextWrite = false;
throw new IOException("fixture write failure");
}
base.WriteLine(value);
}
}
private sealed class FixtureCollisionNeighborhood
: IHeadlessCollisionNeighborhood
{
public int CenterCount { get; private set; }
public uint LastCell { get; private set; }
public void CenterOn(uint fullCellId)
{
CenterCount++;
LastCell = fullCellId;
}
public bool IsReady(uint fullCellId) =>
fullCellId == LastCell;
// #365 Step 3a: this fixture has no real admission/publication
// machinery to hold open — every CenterOn/IsReady call is a
// synchronous no-op, so it is quiescent by construction. A fake
// that ever wants to exercise the gate should override this.
public bool IsQuiescent => true;
// C3c-R1 review F7: the fixture window mirrors production's 3x3
// membership around the last requested center; no center yet means
// "within" (never convert before the first CenterOn).
public bool IsWithinServiceWindow(uint fullCellId)
{
if (LastCell == 0u)
return true;
int dx = Math.Abs(
(int)((fullCellId >> 24) & 0xFFu)
- (int)((LastCell >> 24) & 0xFFu));
int dy = Math.Abs(
(int)((fullCellId >> 16) & 0xFFu)
- (int)((LastCell >> 16) & 0xFFu));
return dx <= 1 && dy <= 1;
}
}
///
/// #365 test 3 support: unlike
/// (trivially ready, never opens a real admission),
///
/// needs a fake that holds an ACTUAL
/// open on a landblock the local player does NOT target — the same
/// per-landblock admission primitive production's
/// HeadlessCollisionNeighborhood.CreatePublication opens for every
/// entry in its 3x3 plan. Cancelling (never committing) sidesteps
/// CommitCollisionGeneration's own multi-tick
/// TryAcquireCollisionPrefixMutationPermission settlement — this
/// fake only needs to prove the SEAL sees an open admission, not drive a
/// second full commit cycle to completion.
///
private sealed class NeighborAdmissionHeldOpenCollisionNeighborhood(
RuntimePhysicsState physics,
uint heldLandblockId) : IHeadlessCollisionNeighborhood
{
private RuntimeCollisionAdmission? _admission;
private PreparedLandblockCollisionGeneration? _prepared;
internal void OpenHeldAdmission()
{
_admission = physics.BeginCollisionAdmission(heldLandblockId);
_prepared = physics.PrepareCollisionGeneration(_admission);
}
internal void ReleaseHeldAdmission()
{
if (_admission is null)
return;
bool cancelled = physics.CancelCollisionGeneration(
_admission,
_prepared);
Assert.True(
cancelled,
"the held-open neighbor admission did not cancel in one call.");
_admission = null;
_prepared = null;
}
public bool IsQuiescent => _admission is null;
public void CenterOn(uint fullCellId)
{
}
public bool IsReady(uint fullCellId) => true;
public bool IsWithinServiceWindow(uint fullCellId) => true;
}
///
/// #365 test 4 support: a fake whose the test
/// flips directly, isolating PumpFirstEntry's gate from any real
/// admission machinery.
///
private sealed class GateControllableCollisionNeighborhood
: IHeadlessCollisionNeighborhood
{
private uint _lastCell;
internal bool QuiescentOverride { get; set; } = true;
public void CenterOn(uint fullCellId) => _lastCell = fullCellId;
public bool IsReady(uint fullCellId) => fullCellId == _lastCell;
public bool IsWithinServiceWindow(uint fullCellId) => true;
public bool IsQuiescent => QuiescentOverride;
}
private sealed class FixtureEventRoute(
Action? onDispose = null) : ILiveSessionEventRouting
{
public int AttachCount { get; private set; }
public int DisposeCount { get; private set; }
public int DisposeFailuresRemaining { get; set; }
public void Attach() => AttachCount++;
public void Dispose()
{
DisposeCount++;
onDispose?.Invoke();
if (DisposeFailuresRemaining > 0)
{
DisposeFailuresRemaining--;
throw new IOException("fixture route detach failure");
}
}
}
}