Release v4.1 (2026-04-02)
What's Changed
Fixes
- While in Release build upon login the empty while loop is optimized out and the app hangs. by @Xian55 in #1
- Replace Thread.Sleep spell delay with queue-based tracking by @Xian55 in #5
- Fix npc movement zig-zag at tile boundaries by @Xian55 in #6
- Fix: ItemEffect hotfix handling for duplicate keys and record removal by @Xian55 in #9
- Feature: .NET 10 migration with performance optimizations and CI modernization by @Xian55 in #16
- Fix
CMSG_ENABLE_NAGLEcausing decrypt failure when Optimize Network for Speed is disabled 2960e77
New Features
- Added metrics collection to measure opcode processing latency by @Xian55 in #7
- Feature/perf/span pooled packet handler by @Xian55 in #10
- Fix all 1,902 nullable compiler warnings by @Xian55 in #14
Performance
- Refactor WowGuid to value-type record structs by @Xian55 in #2
- BnetTcpSession: optimize packet parsing with Span by @Xian55 in #3
- BnetTcpSession: zero-allocation buffer management with Span by @Xian55 in #4
- Modernize threading, allocations, and runtime patterns for .NET 10 by @Xian55 in #15
New Contributors
Performance comparison
Measured with --metrics flag, 8-minute sessions, same game world and activity pattern. Baseline from PR #7 (master branch).
Client → Server (top improvements by P50)
| Opcode | Count (old/new) | P50 before | P50 after | Speedup | P99 before | P99 after |
|---|---|---|---|---|---|---|
CMSG_CAST_SPELL |
121 / 45 | 16.145ms | 0.092ms | 175x | 17.164ms | 2.301ms |
CMSG_DB_QUERY_BULK |
2 / 2 | 3.478ms | 1.544ms | 2.3x | 5.720ms | 1.924ms |
CMSG_MOVE_START_FORWARD |
112 / 93 | 0.070ms | 0.043ms | 1.6x | 0.461ms | 0.351ms |
CMSG_MOVE_HEARTBEAT |
93 / 32 | 0.072ms | 0.045ms | 1.6x | 2.361ms | 1.607ms |
CMSG_QUEST_GIVER_STATUS_MULTIPLE |
24 / 27 | 0.035ms | 0.030ms | 1.2x | 1.676ms | 0.946ms |
Server → Client (top improvements by P50)
| Opcode | Count (old/new) | P50 before | P50 after | Speedup | P99 before | P99 after |
|---|---|---|---|---|---|---|
SMSG_CAST_FAILED |
149 / 55 | 15.959ms | 0.002ms | 7,980x | 17.043ms | 0.885ms |
SMSG_SPELL_GO |
160 / 62 | 16.041ms | 0.065ms | 247x | 17.173ms | 2.616ms |
SMSG_ENUM_CHARACTERS_RESULT |
1 / 1 | 29.215ms | 17.247ms | 1.7x | — | — |
SMSG_SEND_KNOWN_SPELLS |
1 / 1 | 4.159ms | 1.367ms | 3x | — | — |
SMSG_ACCOUNT_DATA_TIMES |
1 / 1 | 8.113ms | 4.250ms | 1.9x | — | — |
SMSG_ITEM_QUERY_SINGLE_RESPONSE |
42 / 24 | 0.256ms | 0.570ms | ~same | 25.301ms | 10.203ms |
SMSG_LOOT_RESPONSE |
44 / 31 | 0.081ms | 0.072ms | 1.1x | 3.508ms | 2.507ms |
Analysis
The spell-related opcodes (CAST_SPELL, SPELL_GO, CAST_FAILED) showed a ~16ms median latency floor on master — the classic signature of Mutex kernel-mode transitions under contention. Replacing with System.Threading.Lock eliminated this entirely, bringing medians to sub-100μs.
One-shot startup opcodes (ENUM_CHARACTERS_RESULT, ACCOUNT_DATA_TIMES, SEND_KNOWN_SPELLS) show 1.7–3x improvement from BinaryPrimitives / allocation reduction in serialization paths.
┌──────────────────────────────────────────────────────────────┐
│ HOW THE PROXY SETUP WORKS │
│ │
│ Your PC Internet │
│ ┌──────────┐ same computer ┌───────┐ ┌──────┐ │
│ │ WoW │ ◄──── instant ──────► │ Proxy │ ◄──► │Server│ │
│ │ Client │ (0ms delay) │ │ slow │ │ │
│ └──────────┘ └───────┘ └──────┘ │
│ │
│ The WoW client talks to the Proxy on your own computer. │
│ The Proxy talks to the game server over the internet. │
└──────────────────────────────────────────────────────────────┘
Shall i set the Optimize Network for Speed enabled or not ?
┌──────────────────────────────────────────────────────────────┐
│ "OPTIMIZE NETWORK FOR SPEED" = ON (default) │
│ │
│ WoW sends every tiny message immediately, one at a time: │
│ │
│ WoW ──► Proxy: "move" Proxy ──► Server: "move" │
│ WoW ──► Proxy: "jump" Proxy ──► Server: "jump" │
│ WoW ──► Proxy: "cast spell" Proxy ──► Server: "cast" │
│ │
│ 3 separate deliveries across the internet │
│ Like sending 3 separate letters in 3 envelopes │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ "OPTIMIZE NETWORK FOR SPEED" = OFF │
│ │
│ WoW batches nearby messages together before sending: │
│ │
│ WoW ──► Proxy: "move+jump+cast" │
│ │ │
│ ▼ │
│ Proxy ──► Server: "move+jump+cast" │
│ │
│ 1 delivery across the internet instead of 3 │
│ Like putting 3 letters in 1 envelope │
│ │
│ The batching between WoW and Proxy is FREE │
│ because they're on the same computer (instant). │
│ But it saves real time on the internet hop! │
└──────────────────────────────────────────────────────────────
Full Changelog: https://github.com/Xian55/HermesProxy/commits/v4.1