Skip to content

feat(gateway): let players sit, bind and see their intro the way the client expects - #702

Merged
Mathih13 merged 2 commits into
mainfrom
feat/opcode-parity-character-world
Oct 15, 2026
Merged

Mathih13 merged 2 commits into
mainfrom
feat/opcode-parity-character-world

Conversation

@Mathih13

@Mathih13 Mathih13 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

The 1.12.1 client sends and expects many character, session and world-state messages that LyraCore did not handle. A sit request got "Stand-state changes are not available". A bind gave no " is now your home" line. A new Character never saw its race's intro. Some requests did worse: the protocol library panics on a bad account-data upload and rejects an unknown zone id, and opcodes it cannot read ended the World Session.

This change closes those gaps where the state already exists:

  • Stand, sit, sleep and kneel requests reach a new Module verb, gw_set_stand_state. It stores the state in the Character's unit bytes, so observers see it. A ghost can sit, as in vmangos. Damage stands a seated player who is not mounted, as vmangos DealDamage does. The self relay sends SMSG_STANDSTATE_UPDATE on every stored change, and a refused request sends the stored state back so the client snaps back.
  • CMSG_EMOTE (the wave after an auction bid) plays its animation through the existing emote event, with no text line.
  • A completed innkeeper bind sends SMSG_PLAYERBOUND. It names the Character's zone; vmangos names the sub-area, which the Gateway cannot read without terrain data.
  • A first world entry sends SMSG_TRIGGER_CINEMATIC with the race's id from ChrRaces.dbc. Later logins play none.
  • World entry and each zone crossing send an empty SMSG_INIT_WORLD_STATES.
  • A rename gets SMSG_CHAR_RENAME with CHAR_CREATE_ERROR, because no Character has a rename flag. An account-data request gets an empty section. A second login in one World Session gets SMSG_CHARACTER_LOGIN_FAILED and keeps the session.
  • Bug reports, GM surveys, /whois and Warden replies are explicitly ignored. Account-data uploads, zone reports and opcodes the library cannot read are dropped before decoding.

Each packet has a byte-for-byte codec test. Each dispatcher path has a Fake test, and Headless Client tests cover the dropped requests and the cinematic. The durable tests in module/tests/stand_state.rs cover sitting, refusals, a sitting ghost and standing on damage. They were compiled but not run locally; CI's module-durable workflow runs them.

Some vmangos stand-state rules are still missing: auras that sitting or standing cancels, the automatic critical hit on a seated victim, the NOT_STANDING cast failure, 1.5x regeneration while seated, and the UNIT_FLAG_PREVENT_ANIM gate. Account data is not stored, and the bind confirmation names the zone rather than the sub-area. docs/benilla-compatibility.md lists these gaps.

Verification

  • cargo fmt --all -- --check, Gateway and Module clippy with -D warnings, cargo test -p lyracore-gateway (2073 passed), Module lib tests (1581 passed), the wasm check, and every durable target with --no-run.
  • The durable tests in module/tests/stand_state.rs were not run locally; CI's module-durable workflow runs them.
  • Comment review, as CODING_STANDARDS.md defines it. Scope: every added or changed comment in the diff against origin/main, in source, tests and Fakes, plus comments near changed code. Result: passed. The kept comments are one-line contracts (CharacterStore::set_stand_state and stand_state) and technical facts: packet layouts, the ChrRaces.dbc column, the rename result quirk, the first-login read ordering, the reader hazards behind each raw ignore, and the client's stand-state behaviour. The diff removes no comments. I deleted the vmangos citation essays; the behaviour they described is in docs/benilla-compatibility.md.

Made by Claude Opus 5.5 in Claude Code.

🤖 Generated with Claude Code

@Mathih13
Mathih13 force-pushed the feat/opcode-parity-character-world branch from f5d55da to 2b96b6b Compare October 15, 2026 08:07
Mathih13 and others added 2 commits October 15, 2026 12:44
gw_set_stand_state writes stand, sit, sleep or kneel into byte 0 of the
Character's unit bytes; any other state is a Refusal. Damage stands a seated
player who is not mounted, as vmangos DealDamage does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stand-state changes reach the Module, and the self relay sends
SMSG_STANDSTATE_UPDATE on every stored change; a Refusal sends the stored
state back. CMSG_EMOTE plays its animation, a completed bind sends
SMSG_PLAYERBOUND, and a first world entry plays the race's opening
cinematic. World entry and each zone crossing send an empty
SMSG_INIT_WORLD_STATES. Renames, account-data requests and a second login
get their protocol Refusals. Debug, GM and Warden requests are explicitly
ignored, and requests the protocol library cannot read safely are dropped
before decoding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Mathih13
Mathih13 force-pushed the feat/opcode-parity-character-world branch from 2b96b6b to 1162576 Compare October 15, 2026 10:44
@Mathih13
Mathih13 merged commit 03207a7 into main Oct 15, 2026
9 checks passed
@Mathih13
Mathih13 deleted the feat/opcode-parity-character-world branch October 15, 2026 11:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant