Merge owned systems into one addon while preserving resource identities. Gate player admission on the replicated prison scene, restore the original framed door, and hold enemy AI until escape. Correct scenario branding and author metadata, include publishing assets, and retain regression and native verification evidence.
9.2 KiB
Mission preparation presentation
Dedicated replication barrier (0.0.4)
The user retested 0.0.3 on RKS #2 and reported that the black preparation screen still disappeared before the walls arrived. Inspection of the installed package confirmed that it contained both the enabled native preload and extended message. The earlier local Workbench success did not establish runtime replication readiness on a remote client.
Each owned free-spawn request now takes a bounded server snapshot of nearby
mission-owned objects (120m around the requested position), recursively including
the prison's walls and gate, plus the pending player actor. Their replication
nodes are held in the joining client's stream until finalization or cancellation.
The owner receives their exact IDs and acknowledges the attempt only after every
node resolves to a local entity. CanFinalize_S requires both this acknowledgement
and the native resource preload. Final assignment retains all existing
ticket/account/phase/placement checks and separately requires scene readiness.
Each attempt has its own token; stale or cancelled acknowledgements cannot open a later attempt. A 60-second scene timeout makes that attempt ineligible for assignment. Once native preloading has completed, it rejects the pending actor through the existing failure/retry path; it never treats missing objects as ready. Failed responses retain the native loading screen, and a new scene request restores it if absent. Successful assignment, spectator handoff and normal teardown retain native screen and audio cleanup. Destroyed objects are excluded when a retry takes a fresh snapshot. Objects outside the nearby snapshot continue normal streaming.
tests/test_spawn_scene.py executes production client checks, token/cancellation/
timeout handling and handler finalization with native-boundary adapters. Missing
root/wall/gate nodes and a node without its entity prevent acknowledgement;
native preload and scene readiness are independently required. Timeout and failed
identity/life checks cannot assign an actor. These are controlled tests, not a
remote-network acceptance run.
The native 0.0.4 candidate run completed 103 assertions without script/runtime failures. Its log records a 39-object snapshot, receipt and acknowledgement on the local client, then prisoner assignment after native preload completion. Cleanup and unchanged source were verified. The same four external localization errors remain in the strict native verdict. A dedicated fresh-join test with the published update is still required; local RPC execution does not simulate network delivery delays.
Native preload and message (0.0.3)
The successor places persistent status text inside the native respawn loading placeholder during server preparation and the joining client's spawn-area preload. Normal preparation displays Preparing mission and the shared explanation that the prisoner will spawn when sites and equipment are ready. Once the server is active, the message changes to Please wait while your spawn area and equipment finish loading. You will take control when preparation is complete. A replicated preparation failure changes the title to Mission could not start, displays the shared restart/administrator guidance, and hides the loading spinner. The administrator's existing /esc status response retains the specific cause.
Prefabs/ERR/GameMode.et now enables native m_bUseSpawnPreload. Previously it explicitly disabled that handshake, allowing server-side readiness to assign a prisoner before the remote client loaded the surrounding prison. Installed vanilla SCR_SpawnHandlerComponent.OnFinalizeBegin_S starts a per-request spawn preload, which adds a replication observer at the spawn position. Its CanFinalize_S waits for the owning client to report preload completion before assigning the actor. Existing successor ticket, identity, life and placement checks still run at final assignment. This uses the engine's completion condition, not a new fixed sleep; it does not preload every distant part of the island.
Previously the scenario inherited the vanilla opaque loading splash, but the only successor preparation/failure guidance was a 15-second hint. No native mission task is created before the first successful phase transition. Failed preparation stops admission and cannot activate the normal survivor observer path which removes the loading placeholder. The new status therefore belongs to that existing loading surface instead of relying on an expiring hint or a player camera.
ERR_PreparationStatus.c extends the installed SCR_RespawnSystemComponent.UpdateLoadingPlaceholder(float dt) callback. Vanilla's DeployMenuSystem already invokes it; no new timer is added. The adapter compares vanilla's protected m_pGameMode field (assigned from owner by SCR_RespawnSystemComponent.OnInit(IEntity owner)) with the exact current ERR_GameMode; it runs only for that owner, with a live native placeholder, outside a console application and during PREPARING or an active mission phase. Keeping the text during active phases also covers late arrivals. It preserves the superclass update and all other modes. The authored child layout uses its own identity, {BCCAE287751344D9}UI/layouts/ERR/PreparationStatus.layout, and native default fonts; it adds no vanilla resource reference.
The adapter remembers the exact placeholder, owned status widgets and original spinner visibility. Replacing or deleting the placeholder, moving the owned child away, ending the mission, or calling native DestroyLoadingPlaceholder clears the child and cached text. A hidden spinner is restored to its recorded visibility when still alive. The native spawn response or existing spectator handoff destroys the placeholder and restores audio. The presentation adapter does not change camera, input, actor, mission state or inventory and never recreates a destroyed loading screen.
tests/test_preparation_status.py executes the actual presentation and cleanup methods through widget/native-boundary adapters. It checks unchanged behavior for unrelated/console modes, persistent text without repeated creation or text writes, preparation-to-failure changes, stale state clearing, missing UI resources/children, parent replacement, deleted weak widget references, reparenting, server-ready/client-loading transitions, late arrivals, terminal phases, native destruction and restoration of an initially hidden spinner. It also verifies that the mission enables preloading and executes the native observation probe's continuous-time, reset and timeout rules. These are source-policy checks, not native rendering or network evidence.
The combined Workbench smoke now records whether native StartSpawnPreload was called and checks that it completed before the initial prisoner was admitted. When the preload spans a smoke tick, it also checks the actual preparation widgets after the server reaches the prison phase. The code is Workbench-only. Dedicated-server verification still requires publishing the update, updating both server and client, then testing a fresh join and a late join with the new package.
The 2026-09-20 native run completed 103 assertions with no script/runtime failures. At 14:23:13 it observed the preparation widgets during native preloading in the active prison phase; the prisoner was assigned at 14:23:14, after preload completion. All repository checks passed. Four existing RHS/WCS localization errors remain. The runner also reported a transient exiting-process classification failure during cleanup; the separate follow-up check confirmed the prefix idle and source identical to the launch snapshot. The original failed cleanup result is retained. This is local Workbench evidence, not a successful dedicated join or a clean overall native verdict.
The existing opt-in Core startup-failure fixture now waits up to 30 seconds for actual production-created loading widgets. It requires the expected title and shared body text, correct parent ownership, visible nonzero-sized title/body/root widgets, a visible loading parent and a hidden native spinner. It observes these continuously for 17 seconds, exceeding the old hint duration, then requests $logs:err-preparation-failure and waits another half-second before its original negative-path assertions complete. It does not create or update the widgets itself. The deliberate faction setup error remains a native ERROR and must retain the negative fixture's failed/error verdict; a successful UI assertion does not turn that run into a clean mission startup. The first native compilation rejected an assumed GetOwner() API, which this native respawn system does not expose. That call has been replaced with its installed vanilla m_pGameMode owner field; the second native run compiled and passed the continuous 17-second checks on the actual title/body/root widgets, parent ownership and hidden spinner. Its captured Workbench image was a blank blue editor viewport, so it provides no visual proof that the status is readable in an ordinary player view. Ordinary-player visual inspection remains pending; the deliberately failed setup still retains its negative engine-error verdict.