Skip to content

Batch 37 · R2a player slots and exclusive device ownership

Checkpoint update, 2026-10-26: implementation committed separately as 936d7c76 at the owner's request. Documentation/evidence is kept in a separate commit; no push. The validation account below records the pre-commit work. Follow the per-batch commit workflow.

2026-10-26, dev-0.9.0-bootloader, HEAD remains dd0a666b. One bounded R2 implementation after batch 36. Added four C# files and five metadata files, and intentionally changed only the package manifest/lock to pin Input System 1.17.0. All previous runtime code/assets/settings, including batches 35/36, remain byte-preserved. No player build, commit or push.

Package and owner decisions

Pinned com.unity.inputsystem 1.17.0: Unity's 6.2 package reference lists that version as released for the Editor line. Resolved package metadata requires Unity 2022.3 or later, and this project's actual 6000.2.8f1 Editor compiles/tests it. No claim that it is the latest package. The sole package dependency is uielements 1.0.0, already present; no existing dependency version changed. Active Input Handling remains its original raw value2, with both SDK and legacy defines verified. Unity's installation reference describes this coexistence. This is a migration bridge, not completed physical compatibility or retirement of the legacy path.

The concrete pairing owner is InputUser per local roster slot. Future per-slot action copies must associate with this existing user; do not add an independently auto-pairing PlayerInput to the actor. InputUser API permits shared devices, so exclusivity is enforced by this roster rather than assumed from the SDK. PackageCache source was inspected for pairing/lost-device order and unpair semantics. InputUser is runtime/Play Mode scoped; the new service rejects Edit Mode construction.

LocalPlayerSlot has a unique session PlayerId, display slot, selected CharacterId and explicit device/user state. It is not a persistent profile ID, hardware index or actor. LocalPlayerRoster supports one through four slots: P1 keyboard or gamepad; P2–P4 distinct gamepads. It rejects unavailable, shared or externally paired devices before changing existing ownership. Reassignment and temporary unassignment preserve the surviving player and SDK user; leaving a slot releases its user, and rejoining allocates a new player identity. Character IDs are retained selection data, not proof of catalog/unlock validation.

A device change cannot select a different device by index/name/activity. Loss keeps the slot/player; restoration reconciles only the explicitly reserved reference after the SDK input update, avoiding a race with InputUser's Added reconciliation. Unexpected SDK auto-pairing by description is rejected. Native devices without a serial require explicit reassignment after loss, even when the backend reuses an object. Serial changes also invalidate automatic restoration. This is conservative identity handling; real backend serial quality/reconnect UX remains a physical-device gate. No auto-pause, invulnerability, player removal or reward-forfeiture policy is introduced.

RosterRunParticipant connects this same roster to the verified shared host. Preparation validates device assignments and locks setup; activation validates again; release unlocks setup without disposing the session's devices/users. Membership/device/character edits and disposal are rejected while locked. Retry and actual scene reload retain player identity, selected character and device/user. This does not assemble a production player or validate a complete stage/unlock/modifier request. No setup UI, action asset, sampler, binding IDs, remapping/profile writer, context routing, physical prompts or gameplay consumer migration was implemented in this slice. PS-03 and the other later gates remain open.

Checks and initial failure disposition

Actual required Editor 6000.2.8f1, direct batchmode/nographics entry TinyChaos.EditorTools.PlayerRosterChecks.RunBatch37, no immediate -quit. Final authoritative process exits 0, summary 9 passed / 0 failed.

The initial run reported 3 passed / 8 failures: six failed groups plus final-stop/scene-restore errors. Headless focus policy withheld keyboard availability; the fixture now clones InputSettings, permits its simulated devices under controlled focus, and restores the original settings object. The returning-device check also exposed eager roster pairing conflicting with InputUser's own lost-device reconciliation. Restoration now waits for onAfterUpdate; the same P05 case passes. The runner restores scene setup only after the native Play Mode exit has settled. These are recorded initial failures, not omitted passing evidence or a reproduction of the shipping game/freeze.

Group Final actual result
P01 PASS: invalid capacity/blank character rejected, four unique stable slots, retained selection, no device owner created by merely adding slots.
P02 PASS: eight approved keyboard-plus-pad/pad-only combinations for one through four slots; one SDK owner per assigned device, no leaked users.
P03 PASS: secondary keyboard, shared/unavailable/mouse/null/out-of-range/foreign-owner requests rejected; prior player/selection/pairing preserved.
P04 PASS: explicit pad/keyboard reassignment and unassign/reassign preserve player and SDK user; pad can move from P1 setup to P2 setup without being stolen/shared.
P05 PASS: disabled device cannot activate, failure releases preparation; removal during Running retains player and clock policy; exact-reference restoration retains the SDK user.
P06 PASS: SDK pairing of an unexpected replacement is rejected; explicit replacement preserves the player/user, and the old device cannot reclaim the slot.
P07 PASS: removing setup slots releases only their users and returning members get new identities. Also tests native/no-serial ambiguity using a fixture-owned device's SDK native flag, requiring explicit reassignment.
P08 PASS: invalid roster cannot leave partial active scene; three fresh run IDs, locked setup, retained identity/user/character across retry and actual scene reload, and unchanged F0 launcher path.
P09 PASS: idempotent owned disposal, externally shared device reported invalid, foreign cleanup preserves owned user, worker-thread mutations rejected, both backend defines and legacy GetAxis/GetKey API smoke succeed.

Devices are SDK-created keyboard/gamepads/mouse; no physical-controller UX is certified. The native-identity branch uses narrow Editor reflection on the pinned SDK's device flags for a fixture-owned gamepad, restoring flags afterward. It is not an OS reconnect test. Controlled InputSystem.Update calls settle synthetic device processing, not movement/timing performance. Scoped settings, virtual devices/users, run state and scene setup are cleaned up. No existing input action is remapped, no command sampler/press-edge behavior is verified, and no actor moves from these pairings yet.

Final log has no unexpected exception/compiler-error marker. Existing-category CS8785 generator warnings (two emitted) and unchanged StabilizationChecks CS0252 warnings (three emitted) remain; this is not warning-free. Raw local diagnostics stay private: /tmp/tinychaos-batch37-editor.log for the initial failures and /tmp/tinychaos-batch37-editor-final.log for the passing run, with matching redirected stdout. Retained checks reproduce the scenarios; temporary paths are not portable test archives.

Preservation and exact implementation manifest

Pre-run backup: /tmp/tinychaos-batch37-preserve-215da5615a/, containing exact project bytes/hashes for 2,838 files, 8,160 inspected Unity/profile files and documentation hashes. Final differences among those project files are exactly the two intentionally updated package files; all other 2,836 match, including the previous 19 batch-35/36 additions and Gameplay.unity. The original 608-file baseline is not regenerated: 606 pins match; manifest/lock are the two explicitly expected SDK-install differences, with current hashes below.

Unity additionally inserted its Linux toolchain dependency during verification. Generated copies were archived and only that unrequested dependency removed, retaining the intentional input dependency. No existing dependency version changes. Shared engine preferences changed three values and were restored. Four automatic Unity session/count keys in the normal game's prefs were restored; its one captured existing file now matches. No normal game save/config IO is called by the roster/checks. Five external engine bookkeeping files changed and remain engine state; no new external profile file. Do not claim the entire Unity tree is unchanged. New metadata empty-field trailing spaces were trimmed with parsed YAML/GUID equality; existing metadata was not reformatted.

Implementation path Kind SHA-256
Assets/Script/External/Editor/PlayerRosterChecks.cs Editor checks 60916a438554f703c8cec741255dad7002a6d26e4e2b41a89e143eb05f9e932f
Assets/Script/External/Editor/PlayerRosterChecks.cs.meta metadata e45f27a6d4aa6e6f0394730d4a6f55cdae7ab86f2426e043e32b1e871eeb9dee
Assets/Script/Game/GameSystem/Input.meta metadata d3449b1776c09bc56e280e86d9cdaf6f431ffaa5aef31ccae2f5ac1bb29f7bf4
Assets/Script/Game/GameSystem/Input/LocalPlayerRoster.cs runtime roster/input ownership 63428c22208a296ffc6b15b3005e26febcdbfa8840f19a9c13baaf39e57263bb
Assets/Script/Game/GameSystem/Input/LocalPlayerRoster.cs.meta metadata 03ef3fba2b978dd09ec1ffd096796a6fd16e0421befe338bea35d5ed0ef276ee
Assets/Script/Game/GameSystem/Input/LocalPlayerSlot.cs runtime roster/input ownership 9bb5acadfd48df1c974181ae9637c51d94181ae367a0a2884f172a047bcbdfb8
Assets/Script/Game/GameSystem/Input/LocalPlayerSlot.cs.meta metadata 6ce9d9e97d823a113aa7943dafd5111155cb2dac194c26f1c4c0a6ceece8df14
Assets/Script/Game/GameSystem/Input/RosterRunParticipant.cs runtime roster/input ownership ff2078e4a7335c7b2fb7524ba8cd068a694ab2d10e9cadbb4e5f2738fd895020
Assets/Script/Game/GameSystem/Input/RosterRunParticipant.cs.meta metadata d2ab756c9b2f6d8c394a2562a3bc9b0228f7e263163815962dba1a5a21c5c9d3
Packages/manifest.json pinned package manifest/lock f30669e7f986120f363f5688feb0e0b53f4b7d228e3bed920dbe8d32583f6a5f
Packages/packages-lock.json pinned package manifest/lock e0cb5239f78a95b790178443a7558b4dd782d1c111a91f75091e7f974f79770a

Final static checks pass: all 2,836 non-package prior project files and 19 previous implementation files match; the original pin set is retained with exactly two intended package differences and 606 unchanged pins. Five new GUIDs are unique, inventory covers 239 scripts with all 235 prior rows byte-preserved, and the legacy map adds only one Editor smoke row. All 50 prior gate rows remain byte-preserved; nine new SDK groups pass while all 27 later workstream follow-ups stay open. All 53 issue IDs route once; 697 local documentation links and whitespace pass. Isolated Git-index reviews verify the combined 30-file implementation group and separate documentation/evidence without changing the real index or HEAD.

Next and commit boundaries

Next is a bounded R2 input-session/action-definition/context slice using these existing InputUsers. Specify stable action/binding identities and the concrete package override format; preserve legacy layouts, dead zones/smoothing/normalization/button edges and UI timing with controlled traces before moving consumers. Minimum profile import/persistence/rebind behavior must pass disposable fixtures before normal-profile writes; PS-03 is not cleared by installing the package. Setup/reassignment recovery UI and per-profile remapping remain required R2 work. Actor assembly and production selection integration follow their dependencies. No new Reroll shortcut, hot join, split keyboard, guessed payout or unrelated feature.

Keep this implementation group (nine additions plus two package changes) separate from documentation/inventory/gate/status evidence, and preserve prior batch-35/36 groups. These groups are now committed separately in dependency order; future verified implementation batches also require separate commits. Documentation-only planning checkpoint remains dd0a666b. No commit/push is implied. GAME-01 and Tutorial completion stay deferred; no full-game playability, Windows/IL2CPP, physical-input equivalence or release acceptance is claimed.