acdream/docs/research/2026-07-26-slice-j5-owner-and-retail-order-inventory.md
Erik bb45afef33 docs(runtime): plan simulation ownership
Inventory the present selection, interaction, combat, movement, physics, and projectile owners; pin named-retail ordering; and define independently reversible J5.1-J5.7 gates without moving presentation into Runtime.

Co-authored-by: Codex <noreply@openai.com>
2026-07-26 10:25:46 +02:00

9.4 KiB

Slice J5 owner and retail-order inventory

Date: 2026-07-26 Scope: presentation-free selection, interaction, combat/magic intent, movement/outbound cadence, physics, and projectile ownership Parent plan: docs/plans/2026-07-26-modern-runtime-slice-j5.md

Purpose

Slice J5 moves gameplay simulation and intent out of the graphical App and into AcDream.Runtime. This note pins the current production owners and the retail ordering that cannot change while those owners move.

This is an ownership refactor, not a new movement, combat, interaction, or projectile implementation. Existing retail ports remain the behavioral oracle.

Current source ownership

Concern Current canonical state Construction/root Presentation coupling to split
Selection identity AcDream.Core.Selection.SelectionState Program constructs; GameWindow retains world ray picking, lighting pulse, vivid markers, status/UI projections
Combat notifications/mode AcDream.Core.Combat.CombatState GameWindow constructs combat/spell bars, camera target tracking, feedback
Pointer target mode AcDream.App.UI.InteractionState optional private construction inside ItemInteractionController cursor image only; state itself is presentation-free
Item-use/appraisal/pickup intent ItemInteractionController, SelectionInteractionController, InventoryTransactionState App retained-UI and live-presentation composition world picking, retained drag/drop, toasts, pending-slot mesh
Combat attack intent CombatAttackController, LiveCombatModeCommandController App retained-UI/session composition input action mapping and combat-bar projection
Spell-cast intent SpellCastingController inside App MagicRuntime App content/UI composition DAT catalog loading, component icons/text, spell bar
Local movement PlayerMovementController plus Core PhysicsBody, MotionInterpreter, MovementManager App player-mode composition Silk/input sampling, camera/mouse-look device state, animated pose publication
Outbound movement cadence LocalPlayerOutboundController GameWindow constructs App diagnostic sink only
Per-session collision Core PhysicsEngine, ShadowObjectRegistry, transition scratch GameWindow constructs streaming publishers and debug visualization
Remote movement/physics App RemotePhysicsUpdater, RemoteInboundMotionDispatcher, live sidecars App composition WorldEntity, render projection, animation pose/effect publication
Projectile simulation Core ProjectilePhysicsStepper plus App ProjectileController.Runtime App live-presentation composition WorldEntity, effect pose, shadow publication

RuntimeEntityRecord already owns canonical accepted identity, timestamps, full cell, raw/final physics state, object clock, PhysicsBody, and IPhysicsObjHost. The App LiveEntityRecord is a projection sidecar. J5 must extend the canonical record rather than add another entity or physics model.

RuntimeInventoryState already owns the exact inventory transaction/busy/use reservation state. J5 interaction work must borrow that owner and must not recreate a busy counter or pending inventory request.

Current reset ordering

LiveSessionResetManifest currently performs the relevant stages in this order:

  1. mouse/input capture;
  2. player presentation and teleport transit;
  3. dialogs/chat/settings;
  4. equipped children and external container;
  5. interaction plus selection;
  6. inventory transactions;
  7. selection presentation and object table;
  8. spellbook/magic;
  9. combat attack and combat state;
  10. local-player and remaining session state;
  11. live entity teardown;
  12. render projection drain and session identity;
  13. network effects/presentation tails.

Runtime ownership may combine internal stages, but App acknowledgements must retain the same dependency order: presentation releases references before the canonical owner is destroyed, while old session identity remains available until exact-incarnation teardown converges.

Named-retail ordering matrix

Selection

ACCWeenieObject::SetSelectedObject @ 0x0058C2E0

  1. If forced or changed, clear the old object's selected flag.
  2. Commit the new selected ID.
  3. Set the new object's selected flag.
  4. If the ID changed, commit previous and previous-valid IDs.
  5. Publish the UI selection notice.
  6. Publish the shared item-holder selection change.
  7. Notify the plugin API.

The state commit precedes every observer. Deduplicated selection does not publish the changed notice.

Session combat initialization

ClientCombatSystem::Begin @ 0x0056A460

  1. Commit NonCombat and clear pending mode.
  2. Clear jump, build, response, attack, repeat, and tracking transients.
  3. Restore medium attack height and UI requested power 0.5.
  4. Register the global notice handler.

Runtime combat reset must clear the complete intent transaction before App projects the peace-mode UI.

Ordinary use and target mode

ItemHolder::UseObject @ 0x00588A80

  1. Enforce the strict 0.2-second local use gate.
  2. Verify inventory-request readiness and vendor restrictions.
  3. Resolve automatic wield/use policy and targeted-use policy.
  4. For ordinary use, emit CM_Inventory::Event_UseEvent.
  5. Increment the shared UI busy reference.
  6. Invoke CPlayerSystem::UsingItem and publish local text.
  7. For a targeted item without an acquired target, store the source object and enter TARGET_MODE_USE_TARGET; do not emit the use-with-target packet yet.
  8. Once a compatible target is acquired, emit Event_UseWithTargetEvent, increment busy, then invoke UsingItem.

ClientUISystem::Handle_Item__UseDone @ 0x00564900

  1. Decrement exactly one busy reference.
  2. Refresh cursor state only when the count reaches zero.
  3. Present a nonzero server error afterward.

The current production correction remains authoritative for local ACE: ordinary Use is sent immediately and ACE owns spatial approach. Pickup retains the existing ordered local approach transaction and post-arrival send.

Local movement output

CommandInterpreter::SendMovementEvent @ 0x006B4680

  1. Require player, SmartBox, raw motion state, and nonzero autonomy.
  2. Read the player's current raw state, canonical Position, contact state, long-jump state, and four retail timestamps.
  3. build/send MoveToStatePack.
  4. Stamp last_sent_position_time only after send.

CommandInterpreter::SendPositionEvent @ 0x006B4770

  1. Require SmartBox, player, active/in-world transient state, and valid canonical Position.
  2. Read current contact and timestamps.
  3. build/send AutonomousPositionPack.
  4. After send, stamp time and copy the complete sent Position and contact plane as the next comparison baseline.

The existing pre-inbound movement/jump and post-inbound autonomous-position slots remain unchanged.

Object physics

CPhysicsObj::UpdatePositionInternal @ 0x00512C30, CPhysicsObj::transition @ 0x00512DC0, CPhysicsObj::SetPositionInternal(CTransition const*) @ 0x00515330, and the ordered object tail recorded in docs/research/2026-07-19-r6-update-object-order-pseudocode.md remain the simulation oracle.

Runtime owns the canonical body and simulation. App may publish the final accepted root/part poses only after that simulation result commits. A render callback must never become position, cell, velocity, or collision authority.

Projectile collision exclusion

OBJECTINFO::missile_ignore @ 0x0050CEB0

The existing Core ProjectilePhysicsStepper port remains unchanged:

  • ignore other missiles;
  • ignore ethereal weenies unless they are the designated target;
  • with a nonzero designated target, ignore other creatures;
  • do not infer a designated target from UI selection.

Fixed dependency direction

Silk / retained UI / camera
        |
        v
App typed input + presentation adapters
        |
        v
AcDream.Runtime intent/simulation owners
        |
        v
Core algorithms + Core.Net transport/content seams

Runtime never references App, Silk, OpenGL, OpenAL, ImGui, Arch, or retained UI. App may synchronously acknowledge a committed runtime mutation and project it; it may not keep a second mutable copy.

Source hazards

  1. ItemInteractionController can currently create a private InteractionState; this is a duplicate-owner seam and must be removed when J5.1 lands.
  2. Program currently constructs selection while GameWindow constructs combat. Both must move under one Runtime owner before higher-level controllers move.
  3. PlayerMovementController contains environment reads for test-era default skills. A Runtime move must use typed construction options and the existing Runtime character skill projection.
  4. LocalPlayerOutboundController directly accepts WorldSession and an App diagnostic sink. Runtime may use Core.Net, but diagnostics must cross a narrow optional interface.
  5. App LiveEntityRecord still stores remote/projectile component interfaces. Simulation components must migrate to RuntimeEntityRecord; only animation/effect/render projection belongs in the App sidecar.
  6. Remote/projectile callbacks can synchronously delete or replace a GUID. Every split-phase commit must retain the existing exact-record, incarnation, authority-version, and object-clock-epoch revalidation.
  7. PhysicsEngine transition scratch is per engine and same-thread LIFO. Immutable prepared collision content may be shared; the engine and scratch may not be shared by concurrent sessions.