Complete the retail cast-intent, target, component, enchantment, and busy-state paths; mount the DAT-authored spell bar, spellbook, component book, effects panels, and shared panel lifecycle; and add scoped input plus conformance coverage.
Co-Authored-By: Codex <noreply@openai.com>
Preserve PlayerDescription inventory/equipment ownership across authoritative manifest replacement, make weapon switching and combat/UI consumers read the same canonical object state, and carry the complete outbound player position frame across landblocks.
Route target-facing and mouse-look through the shared MovementManager and MotionInterpreter completion owner. Match retail input aggregation, toggle ordering, turn/sidestep remapping, per-axis hold keys, and synchronous movement publication without render-only heading state.
Initialize the live streaming origin from the first accepted canonical player Position, defer other projections until that origin exists, and retain logical entity identity through hydration.
Advance the project ledger from completed M2 to active M3, synchronize CLAUDE.md/AGENTS.md and durable memory, and record the next cast-lifecycle, spellbook/enchantment, and two-client portal gates.
Co-Authored-By: Codex <noreply@openai.com>
Parse and route the complete 0x0264 guid/fraction/valid response, send exact 0x0263 item-mana queries, and reproduce retail meter visibility plus guid-zero cancellation for mana and health selection changes. Keep the behavior in Core state and the retained selected-object controller with wire/state/UI conformance coverage.
Co-Authored-By: Codex <codex@openai.com>
Lands the codex-worktree D.2b stream plus the extraction the 2026-07-02
UI architecture review mandated before commit:
- ItemInteractionController: single owner of double-click use/equip/
container-open, targeted-use mode (health kits), drag-out drop;
toolbar shortcut drags don't drop the real item. ItemEquipRules for
multi-slot (coat) coverage via equip masks.
- Cursor phase: CursorFeedbackController (semantic priority chain:
drag > resize > window-move > target-mode > text) + RetailCursorCatalog
(enums 0x27/0x28/0x29, hotspot 14,14; ClientUISystem::UpdateCursorState
0x00564630) resolved through the portal EnumIDMap chain by
RetailCursorResolver; RetailCursorManager applies dat cursor art to the
OS cursor. Register row AP-72 covers the OS standard-cursor fallback.
- Character window goes live: CharacterSheetProvider owns sheet assembly,
XP-curve/raise-cost math and the raise flow — extracted out of
GameWindow per Code Structure Rule 1 instead of committing the ~430-line
feature body there. Optimistic XP/credit debits go through eventful
store APIs (new ClientObjectTable.UpdateInt64Property +
LocalPlayerState.DebitIntProperty/DebitInt64Property) instead of raw
property-dictionary writes; register row AP-73 covers the still-missing
raise ledger (#163).
- RetailWindowFrame: the shared nine-slice window mount recipe; the
character window uses it, remaining windows migrate via #164.
- Status-bar buttons toggle inventory/character windows; retail row-major
backpack ordering; WorldSession.SendUseWithTarget + raise/train sends.
GameWindow shrinks 14,214 -> 13,877 lines despite the new features; the
sheet/raise logic is unit-tested in CharacterSheetProviderTests instead
of trapped in the god object. Build green; full suite 3,286 tests pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implements the inbound GameEvent routing layer — the single biggest
network-protocol gap per r08 (94 sub-opcodes, zero handled before).
WorldSession now detects 0xF7B0, parses the 16-byte header (guid +
gameEventSequence + eventType), and forwards to a pluggable
GameEventDispatcher.
Added:
- GameEventEnvelope record + TryParse with layout from
ACE GameEventMessage.cs.
- GameEventType enum: all 94 S→C sub-opcodes from
ACE.Server.Network.GameEvent.GameEventType, named per ACE conventions.
- GameEventDispatcher: handler registry + unhandled-counts bag for
diagnostics ("which server events are firing that we don't parse?").
Handlers invoked synchronously on the decode thread; thrown exceptions
are swallowed + logged to stderr so one bad handler can't take down
the packet loop.
- GameEvents parsers: ChannelBroadcast, Tell, TransientMessage,
PopupString, WeenieError (+ WithString), UpdateHealth, PingResponse,
MagicUpdateSpell. Each returns a typed record or null on malformed
payload. String16L helper matches the existing CharacterList pattern
(u16 length + ASCII bytes + 4-byte pad).
- WorldSession.GameEvents property exposing the dispatcher so
GameWindow / UI / chat can register handlers at startup.
Wired into WorldSession.ProcessDatagram: new `else if (op ==
GameEventEnvelope.Opcode)` branch with TryParse + Dispatch.
Tests (13 new):
- Envelope: valid round-trip, wrong outer opcode, too-short body.
- Dispatcher: handler invoked, unhandled count, exception isolation,
unregister + rollover to unhandled.
- Event parsers: ChannelBroadcast, Tell, UpdateHealth, WeenieError,
Transient, MagicUpdateSpell.
Total: 521 tests pass (up from 508).
With this dispatcher in place, Phase F.2 (items + appraise), F.3 (combat
+ damage), F.4 (spell cast state machine), chat UI, allegiance, quest
tracker — all of which depend on GameEvent handling — are unblocked.
Ref: r08 §4 (GameEvent sub-opcode table), §2 (envelope wire shape).
Ref: ACE GameEventMessage.cs / GameEventType.cs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>