Files
EscapistsReintroduced/docs/player-lifecycle.md
T

34 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Player lifecycle and pending admission
The successor keeps one round-owned life record per authenticated account. A connection number is only the current binding to that record. A new life can enter during prison, radio search or radio defence; extraction and terminal phases refuse new admission. Successful initial assignment spends the life. Cancelling an unassigned preload never restores or spends a life.
Native reconnect reservation and handoff remain separate from new-character admission. A returning account may reclaim its surviving reserved actor through Reforger's reconnect system. A dead actor remains a spent life; unconsciousness is not death. Reserved living actors remain participants while their connections are absent. These policies are implemented, but real remote reconnect and reservation-expiry acceptance remains unfinished.
## Placement
Prison placement searches a 4×4 lattice with axis coordinates -4.5, -1.5, 1.5 and 4.5m relative to the authored center. The four inner positions are checked first, then eight edge positions, then four corners. Neighboring centers are 3m apart and remain 1.5m inside walls positioned at ±6m. The inner and edge positions are within 5m of the prison center. Terrain height and slope, physical scene/character occupancy, and pending reservations can reject a slot. Connection IDs 1 and 13 receive no special or shared position. Disconnected physical bodies still obstruct the native query.
If every candidate is occupied or reserved, admission retries once per second within a budget of thirty active, eligible admission attempts. Missing faction/respawn prerequisites and rejected native spawn requests consume the same budget. Once exhausted, the existing SPAWN_UNAVAILABLE spectator path explains that no prisoner could be spawned; no unsafe fallback is used and no life is consumed. Mission preparation does not spend attempts, and an already-pending native request cannot spend another attempt. A temporary obstruction can still clear before the budget expires. Later arrivals first search bounded clear ground near a conscious friendly survivor outside a vehicle, with terrain-height and line-of-sight checks, then try the same prison grid. Placement does not imply a navigable route or safe proximity to enemies. Both late-join anchors and spectator follow targets now require the exact current round body through `ERR_PlayerRoster.CurrentActor`, in addition to the existing living/friendly checks. A controlled replacement, unfinished admission or recycled connection ID cannot supply a survivor target. Spawn anchors still require consciousness and the existing placement checks; living unconscious canonical prisoners remain eligible spectator targets. If no valid spawn anchor remains, the prison-grid fallback is unchanged.
The previous 25-point grid passed reservation enumeration but exhausted at eight actual actors (archive `native-2026-09-19-062251`). Adding a ring to 49 candidates while keeping the central positions first still exhausted at nine (`native-2026-09-19-062847`). Diagnostics showed character world bounds about 4×4m; the old 1.5m lattice left adjacent candidates inside those conservative query bounds. The replacement 3m lattice changes packing rather than weakening the query or lowering the required population. All sixteen candidates still pass through the unchanged clearance predicate. The prisoner fixture must populate one real player plus eleven additional physical actors before capacity is accepted; this new packing awaits that native result. Manual crowding, movement, collision and spawn usability remain required.
## Finalization and cleanup
The server records each initial free-spawn admission in a ticket bound to the mission instance, account, connection, controller, native request, exact request data object and created actor. Immediately before native assignment it rechecks current phase, account binding, connection, spent life, controller and request ownership, absence of another controlled entity, actor health and placement. Horizontal drift is limited to 0.6m and vertical drift to 1m, allowing ordinary settling while refusing displaced or fallen preloads. The reserved location is checked against current terrain and physical occupancy again.
A refused ticket permits cleanup only of its owned unpossessed actor. An unknown or repeated request cannot claim an arbitrary actor for deletion. Stop, disconnect and closed-admission phases remove reservations, cancel the native repeated finalization callback and remove their pending actors. Pending/retry metadata is cleared before cancellation emits a response, so the response's failure callback cannot schedule a fresh admission. Cleanup rechecks actual player control: `ERR_Actors.DeleteSpawned` refuses any entity currently controlled by a player, regardless of its original ownership.
The native handler interception applies only to successor game modes or an existing handler whose owning respawn system still carries successor spawn logic during teardown. Other scenarios retain vanilla behavior. Delayed entity-loss observation also checks the captured controller and ignores a living actor that was reacquired before the callback runs.
## Validation status
`python3 tools/check.py` includes `tests/test_player_admission_policy.py`. It executes the actual source-local finalization and life-policy bodies plus the actual reservation rejection predicate through the existing C++ policy harness. Coverage includes every phase/life/connectivity/controller/request/identity combination, missing identities, displacement boundaries, radial distance, vertical reservation separation and own-reservation exclusion. The harness substitutes vector arithmetic and opaque identity equality; it does not emulate Enfusion collision, replication, native spawning or reconnect behavior.
`ERR_NativeLifecycleProbe` is an opt-in WORKBENCH fixture integrated by the central runner as `-errBaseSmoke 1 -errSmokeOutcome lifecycle`. It checks native prison capacity, physical character occupancy, actual local-controller handler rejection, exact request ownership, deferred deletion, cancellation without another life, delayed observer metadata protection and a native displaced actor. Movement checks wait 750ms and deletion checks wait 1000ms rather than assuming immediate native updates. Synthetic ticket creation is confined to WORKBENCH and never changes the real prisoner's life record or possession.
The native lifecycle fixture in [050403](evidence/native-2026-09-19-050403/report.json) completes 54 assertions, including an ordinary initial prisoner spawn. It finds 20 remaining clear positions around that prisoner. No script/VM exception occurs; seven inherited vanilla resource errors remain. Earlier reserved member-name and reflected-container failures are preserved in the validation archive. Normal Core/companion escape and restart regression remains a separate check. Remote 12-player concurrent join, slow client preload, disconnect during preload, recycled connection IDs, reconnect reservation handoff/expiry and spectator streaming cleanup remain separate multiplayer acceptance work.
`tests/test_participant_selection.py` executes the actual `CurrentActor`, `SpawnPosition` and server observer-selection methods with engine enumeration, geometry and streaming represented by adapters. It covers unregistered and pending actors, missing identity, disconnect, mismatched connection/body, recycled IDs, dead/foreign bodies, accepted canonical targets, cycling, loss of a previously selected target, unconscious following and unchanged prison/geometry fallback. This closes a source-proven membership omission; it does not establish native possession or multiplayer streaming behavior for the revision.
`tests/test_spawn_retry_budget.py` executes the actual `DoSpawn_S` method with native controller, respawn, geometry and scheduler adapters. It covers persistent blocked positions, missing prerequisites, thirty-attempt exhaustion, temporary recovery, request rejection, preparation waiting, spent/late life refusal and unchanged pending requests. The counter change has source-local regression evidence only until the next native integration run; this does not qualify slow remote clients or real multiplayer admission.