Join destination scheduling to the canonical reveal generation, protect its share across every typed frame-budget dimension, and prevent stale work from clearing a replacement reservation. Remove forced incomplete materialization and project retail's centered portal wait cue while the authored tunnel remains active. Tests: Release build clean; 91 focused reservation/reveal tests; full solution 8,158 passed, 5 skipped. Co-authored-by: Codex <noreply@openai.com>
6.8 KiB
Retail landblock/object retirement and portal blocking — pseudocode
Purpose: Oracle boundary for Modern Runtime Slice E.
Named-retail sources
CLandBlock::destroy_static_objects @ 0x0052FA50CLandBlock::Destroy @ 0x0052FAA0CObjectMaint::DestroyObjects @ 0x00508C30CObjectMaint::AddObjectToBeDestroyed @ 0x00508F70SmartBox::UseTime @ 0x00455410gmSmartBoxUI::UseTime @ 0x004D6E30
The Sept 2013 named pseudo-C is the behavioral oracle. WorldBuilder has no equivalent live-client teardown scheduler; its extracted mesh/cache owners are implementation references only.
CLandBlock::destroy_static_objects
for i = 0 .. num_static_objects - 1:
object = static_objects[i]
if object != null:
object.leave_world()
delete object
num_static_objects = 0
The operation is synchronous in retail. Each object leaves the world before its memory is destroyed.
CLandBlock::Destroy
destroy_static_objects()
destroy_buildings()
if landblock_info != null:
landblock_info.Release()
landblock_info = null
closest = invalid
lbi_exists = false
direction = unknown
if draw_array != null:
delete[] draw_array
draw_array = null
draw_array_size = 0
Retail does not expose a partially active destroyed landblock. The visible, spatial, ticking, and memory lifetimes end in one call.
CObjectMaint::DestroyObjects
for every physics object:
object.exit_world()
object.leave_world()
remove object from object_table
remove object from null_object_table
remove object from destruction schedule
object.unset_parent()
object.unparent_children()
delete object
for every weenie object:
remove from weenie tables
delete object
destroy all object/null/weenie/inventory tables
destroy lost-cell table
Again, execution is complete once begun. Parent/child and spatial withdrawal precede physical deletion.
CObjectMaint::AddObjectToBeDestroyed
remove any prior destruction schedule for object_id
deadline = Timer.cur_time + 25 seconds
destruction_table[object_id] = deadline
destruction_priority_queue.Insert(deadline, object_id)
This queue delays when complete object destruction begins. It is not precedent for leaving an object active while destroying it one field at a time. Acdream's 25-second nonresident live-object lifetime already ports this separate behavior.
SmartBox::UseTime
if cell_manager.blocking_for_cells == false:
if not all_cells_available and CheckPrefetchStatus():
CellManager.UpdateLoadPoint()
if player exists and player has a cell:
CellManager.ChangePosition(player.position)
if player exists and not waiting_for_teleport
and not position_update_complete:
position_update_complete = true
has_been_teleported = true
ObjectMaint.UseTime()
Physics.UseTime()
GameTime.UseTime()
LScape.UseTime()
Ambient.UseTime()
else:
CellManager.CheckPrefetchStatus()
SceneTool.Think()
drain inbound SmartBox event queue
CommandInterpreter.UseTime()
Render.CalcDegLevel()
While retail is blocked for destination cells, the old world does not advance object maintenance, physics, landscape, game time, or ambient sound. UI/event dispatch and the portal presentation continue. This is the retail basis for Slice E's immediate old-generation quiesce.
gmSmartBoxUI::UseTime portal wait presentation
The portal CreatureMode remains live while SmartBox is blocked. Its camera
continues one random roll segment at a time:
if now >= rotationStart + rotationDuration:
currentAngle = rotationEndAngle
rotationStart = now
rotationDuration = RandomUniform(0.6, 1.8) seconds
rotationStartAngle = currentAngle
rotationEndAngle = RandomUniform(0, 360) degrees
ECM_UI.SendNotice_DisplayStringInfo(
channel = 0x1A,
text = "In Portal Space - Please Wait...")
else:
level = UIGlobals.GetAnimLevel(
(now - rotationStart) / rotationDuration)
currentAngle = Lerp(
rotationStartAngle,
rotationEndAngle,
level / 1024)
CreatureMode.SetCameraDirection_Degrees((0, currentAngle, 0))
The notice is a centered UI display string, not chat. Slice E's asynchronous adaptation delays its first projection until the recorded five-second reveal stall threshold, then repeats it on the same rotation-segment boundary while the authored tunnel keeps animating.
Acdream asynchronous adaptation
Retail performs each teardown synchronously and can synchronously block cell loading. Acdream prepares content on a worker and must not spend an unbounded render/update frame reproducing that transaction. The faithful observable contract is therefore split at a different boundary:
begin destination generation:
mark prior world generation unavailable
replace normal world viewport with portal presentation
freeze old-generation object/static/effect simulation
silence old-generation audio
reject old generation from collision, picking, radar, and targeting
over later update/resource-maintenance frames:
detach old landblocks through exact retry receipts
release scripts/effects/lights/plugin projections
release CPU owners
admit renderer retirement; physical GL release remains fence delayed
in parallel, under reserved destination budgets:
admit destination completions
publish collision and required Near render state
request/upload required assets
reveal only when the one destination-generation readiness state proves:
collision root ready
required Near scene ready
required composite textures ready
camera/player identity belongs to destination generation
if the portal reveal is still incomplete after five seconds:
keep the DAT-authored portal scene animating
display the centered retail wait notice
emit one generation-scoped diagnostic
do not materialize early
Release-later never means run-later: an old owner may retain memory until its cursor runs, but it cannot keep simulating, colliding, rendering, targeting, or emitting audible work after the generation-quiesce edge.
Port constraints
- Preserve existing exact retry receipts; successful stages never replay.
- FIFO is stable within priority and generation.
- A time limit is checked between atomic owner operations. If one atomic operation itself exceeds its ceiling, diagnostics name that operation; it is then split at its natural cursor rather than interrupted mid-mutation.
- No deferred callback may mutate GL from a worker.
- Destination-critical work receives a reserved share of each frame; it does not bypass all budgets.
- A reveal delay beyond retail's five-second fade ceiling keeps the portal tunnel active and displays the retail wait cue. It never reveals an incomplete world.