Skip to content

fix: opcode-196 desync after player inventory - #6

Closed
renanchavess wants to merge 1 commit into
zimbadev:mainfrom
renanchavess:fix/opcode-196-desync
Closed

fix: opcode-196 desync after player inventory#6
renanchavess wants to merge 1 commit into
zimbadev:mainfrom
renanchavess:fix/opcode-196-desync

Conversation

@renanchavess

Copy link
Copy Markdown

Summary

  • Fixes parsing misalignment after 0xF5 (GameServerPlayerInventory) that caused the client to interpret residual bytes as 0xC4 (196) and abort the processing of aggregated packets, resulting in visual delays in creature deaths and equipment swaps.

  • Makes the default handler for unmapped opcodes resilient: logs metadata and resynchronizes to the next valid opcode instead of interrupting.

Problem

  • After receiving 0xF5 (PlayerInventory), the client left unread bytes in the buffer.

  • The first residual byte was treated as if it were a 0xC4 (196) opcode, leading to parser exceptions and blocking subsequent opcodes from the same packet.

  • Symptoms: sprite took a long time to change to "dead", equipment updates were delayed, map errors ("no thing at pos…").

Root Cause

  • PlayerInventory uses variable encoding for counting (1–4 bytes depending on the value). The parser was not correctly consuming this variation, leaving leftovers in the buffer.

  • The default handler for unknown opcodes interrupted processing at the first residual byte.

Changes

  • Inventory parser updated to correctly consume the variable encoding for counting:

  • src/client/protocolgameparse.cpp:3293-3316

  • Routing for GameServerPlayerInventory (245) now directs to the parser:

  • src/client/protocolgameparse.cpp:577-579

  • Resilient default handler:

  • Logs opcode, prevOpcode, readPos, unread, msgSize and writes only the unread segment (UNREAD_HEX) to packet.log.

  • Re-synchronizes by searching for nearby candidate opcodes (0xF5, 0xC3, 0xC6, 0xC7, and other common ones); if not found, skips unreading altogether.

  • src/client/protocolgameparse.cpp:608-659
    Evidence

  • Before the fix, recurring entries in otclient.log and packet.log:

  • “unhandled opcode 0xC4 (196), prev opcode is 0xF5 (245), unread …”

  • After the fix, PlayerInventory fully consumes its payload and the default handler avoids aborts, allowing subsequent opcodes in the packet to be processed without delay.

Impact

  • Eliminates delays in visual updates (death and equipment) caused by aborts of aggregated packets.

  • Improves diagnostics in case of future unknown opcodes, without interrupting the game flow. Compatibility

  • Server-side does not emit 0xC4; Cyclopedia messages for houses use 0xC3, 0xC6, 0xC7. The fix maintains compatibility with the current protocol.

  • No changes to public APIs; only internal parsing and logging.

How to Test

  • Log into the game, trigger events that activate PlayerInventory and quick actions (kill creature, change equipment).

  • Verify that:

  • Creature sprite changes to "dead" immediately.

  • Equipment updates without delay.

  • otclient.log does not show new entries of "unhandled opcode 0xC4".

  • If any unknown opcode occurs, packet.log contains UNREAD_HEX only for the unread portion, and the client continues processing.

Notes

  • Code references:

  • Switch for PlayerInventory: src/client/protocolgameparse.cpp:577-579

  • Corrected parser: src/client/protocolgameparse.cpp:3293-3316

  • Default handler and re-synchronization: src/client/protocolgameparse.cpp:608-659

@github-actions

Copy link
Copy Markdown

This PR is stale because it has been open 45 days with no activity.

@github-actions github-actions Bot added the Stale label Dec 14, 2025
@renanchavess renanchavess closed this by deleting the head repository Jan 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant