feat(runtime): C3c - production placement cutover: both hosts on the residence conductors (routes 1+8)
Campaign P remaining-physics-divergence, placement cutover slice C3c
(docs/plans/2026-08-02-placement-cutover.md). Both production hosts now
register every initial Create through the residence + continuation-
executor + first-entry-conductor machinery (C0-C3b):
- Graphical (route 1): RegisterEntityWithInitialResidence at Create; the
shared RuntimeFirstEntryDriveController pumps both conductors from the
placement-receipt flow; MaterializeProjection and RebucketLiveEntity
are presentation-only while a residence is ACTIVE (ExecutorCompleted is
the presentation-binding receipt); post-residence entities take the
full legacy path including the prepare_to_enter_world clock edges.
PlayerModeController attaches presentation to the Runtime-published
controller; its legacy resolve/step-heights/host-construction path is
deleted; presentation-only rollback (retail has no entry-flow rollback).
- Headless (route 8): OnSpawned registers with residence when a drive
exists; content-less sessions keep the pre-flip direct registration;
SynchronizeLocalPlayer/CreateController/ApplySetupStepHeights deleted;
prepared-collision read failure is a typed AwaitingCollisionSource
retry; far remotes outside the service window complete celless.
- RuntimeLocalPlayerMovementState.Controller setter sealed internal; all
controller mutation flows through the publication lifecycle.
Fix slices landed within this cutover, each dual-gated:
- F1: live movement-stat/server-physics application routed through the
Runtime ownership seam (post-logout ingest crash on the retired
controller eliminated; RuntimeMovementSkillProjection deleted).
- F2: login activation wedge - collision-admission prefix gate factored
out of the seal (reentrant-commit RejectedAuthority), rearm generation
identity corrected, PlayerModeAutoEntry requires the Runtime-published
controller (world reveal can no longer seal unmaterialized).
- F3: landblock-prefix 0-sentinel replaced by explicit absent-id guards;
map-corner landblocks (grid row/col 0) fully legal through admission,
park/rearm/retire, quiescence, and outdoor shadow seeds.
- F5: local-player first-entry ground contact seeded by the shared
SpawnPlacementSettler (moved App->Core) at FinalizeActivation - the
retail first-gravity-frame touch (enter_world 0x00516170 carries no
seed); the legacy unconditional force-seed is overwritten by a real
floor-found contact; airborne spawns stay airborne; outbound contact
bit verified end-to-end. Fixes the standing-cast 'You can't do that
while in the air!' rejections.
- R1 (dual-review round): login constraint leash armed at the committed
placement (HandleReceivedPosition 0x00453FD0 analog); register rows
AD-61 (settle-timing compression now covering the local player) and
AD-42 (repointed off the deleted resolve split) in this commit;
residence-conversion owner API; wire-landblock guards; drive-pending
ledger in IsConverged; route attach/detach latch; executor-drain drift
model documented + source-pinned.
Gates: Runtime 1,003, App 4,039/3 skips, Headless 79, complete solution
10,816/0 failed/4 skips (Release, -m:1); connected lifecycle/reconnect
gate PASS (logs/connected-world-gate-20260802-175401; graceful exits,
world-visible, zero airborne rejections). The nine-stop soak remains red
for the pre-existing 6b28ff99 whole-world collision-clone throughput
regression (attributed with evidence; scheduled as its own slice before
C5). Dual Opus reviews (retail-conformance + adversarial): delta PASS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
78f1eb1896
commit
529e0e9d88
68 changed files with 5977 additions and 831 deletions
|
|
@ -500,6 +500,79 @@ internal sealed class SessionPlayerCompositionPhase
|
|||
d.PlayerIdentity,
|
||||
dormantLiveEntities,
|
||||
d.Options.DumpLiveSpawns ? d.Log : null);
|
||||
// C3c: the graphical first-entry drive controller — walks every
|
||||
// initial-Create residence through its Runtime conductor with the
|
||||
// production prepared-collision source, the live movement-skill
|
||||
// options, and the truthful local-player activation preparation
|
||||
// (authored-cylinder radius/height with the legacy fallbacks, and
|
||||
// the shadow disposition read from the exact shadow registry the
|
||||
// activation commit validates against).
|
||||
IPreparedCollisionSource firstEntryCollision =
|
||||
content.PreparedAssets as IPreparedCollisionSource
|
||||
?? throw new NotSupportedException(
|
||||
"Production prepared assets must expose the matching "
|
||||
+ "prepared-collision catalog.");
|
||||
// C3c-R1 review F9: the provider runs on EVERY drive pump while the
|
||||
// entity's conductor is still yielding, and the Setup cylinder per
|
||||
// incarnation is immutable (SourceGfxObjOrSetupId and the spawn
|
||||
// record's ObjScale are fixed at Create) — cache the resolved
|
||||
// world-entity lookup + GetSetupCylinder per pending incarnation
|
||||
// (keyed by the incarnation-unique local id; an unresolved/default
|
||||
// result is NOT cached so late hydration still upgrades it). The
|
||||
// shadow disposition deliberately stays live: shadow registration
|
||||
// can land between pumps and the activation commit validates the
|
||||
// disposition against the exact registry.
|
||||
uint firstEntryCylinderLocalId = 0u;
|
||||
float firstEntryCylinderRadius = 0f;
|
||||
float firstEntryCylinderHeight = 0f;
|
||||
var firstEntryDrive = new RuntimeFirstEntryDriveController(
|
||||
d.EntityObjects,
|
||||
d.Runtime.Clock,
|
||||
firstEntryCollision,
|
||||
() => PlayerMovementConstructionOptions.From(
|
||||
d.Runtime.CharacterOwner.MovementSkills.Snapshot),
|
||||
record =>
|
||||
{
|
||||
float radius = 0.48f;
|
||||
float height = 1.835f;
|
||||
uint localId = record.Key?.LocalEntityId ?? 0u;
|
||||
if (localId != 0u && localId == firstEntryCylinderLocalId)
|
||||
{
|
||||
radius = firstEntryCylinderRadius;
|
||||
height = firstEntryCylinderHeight;
|
||||
}
|
||||
else if (live.LiveEntities.TryGetWorldEntity(
|
||||
record.ServerGuid,
|
||||
out WorldEntity? playerEntity)
|
||||
&& playerEntity is not null)
|
||||
{
|
||||
(float setupRadius, float setupHeight) =
|
||||
d.MotionBindings.GetSetupCylinder(
|
||||
record.ServerGuid,
|
||||
playerEntity);
|
||||
if (setupRadius >= 0.05f)
|
||||
{
|
||||
radius = setupRadius;
|
||||
height = setupHeight;
|
||||
if (localId != 0u)
|
||||
{
|
||||
firstEntryCylinderLocalId = localId;
|
||||
firstEntryCylinderRadius = radius;
|
||||
firstEntryCylinderHeight = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool hasAuthoredShadow = record.Key is { } key
|
||||
&& d.PhysicsEngine.ShadowObjects.HasLogicalOwner(
|
||||
key.LocalEntityId);
|
||||
return new RuntimeLocalPlayerPhysicsActivationPreparation(
|
||||
radius,
|
||||
height,
|
||||
hasAuthoredShadow
|
||||
? RuntimeLocalPlayerShadowDisposition
|
||||
.RegisteredAuthoredPayload
|
||||
: RuntimeLocalPlayerShadowDisposition.ProvenShapeless);
|
||||
});
|
||||
var hydration = new LiveEntityHydrationController(
|
||||
live.LiveEntities,
|
||||
d.EntityObjects,
|
||||
|
|
@ -517,7 +590,8 @@ internal sealed class SessionPlayerCompositionPhase
|
|||
d.PlayerIdentity,
|
||||
deletion,
|
||||
dormantLiveEntities,
|
||||
d.Options.DumpLiveSpawns ? d.Log : null);
|
||||
d.Options.DumpLiveSpawns ? d.Log : null,
|
||||
firstEntryDrive);
|
||||
bindings.Adopt(
|
||||
"landblock-loaded hydration",
|
||||
live.LandblockLoaded.Bind(hydration));
|
||||
|
|
@ -884,7 +958,8 @@ internal sealed class SessionPlayerCompositionPhase
|
|||
d.RemoteMovementObservations,
|
||||
live.RenderSceneShadow,
|
||||
live.PlacementProjection,
|
||||
placementProjectionRetry),
|
||||
placementProjectionRetry,
|
||||
firstEntryDrive),
|
||||
liveSessionCommands,
|
||||
d.Log);
|
||||
LiveSessionHost sessionHost = sessionRuntimeFactory.Create(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue