fix(exit): flush 0x03 Redirect before WorldState cleanup races the socket#335
Merged
Conversation
…cket PacketHandler_0x0B (endSignal=0) previously enqueued the Redirect with the default 1200ms TransmitDelay *after* Map.Remove had already enqueued a 0x0E AoiDeparture. Two problems compound: 1. FlushSendBuffer breaks when it hits a delayed packet after buffering a no-delay one — so the 0x03 was always deferred to the next 50ms ProcessOutbound tick rather than going out in the immediate flush that Client.Redirect's Enqueue(flush: true) tried to force. 2. When the deferred 0x03 *did* get picked up, its 1200ms Task.Delay easily outlived the live-socket window. Clients that close the connection eagerly after the confirm packet (or that the server itself tore down via the cleanup below this line) never saw the Redirect at all — the client interpreted the silent socket close as an unexpected disconnect and showed "Connection Lost". Fix: send the Redirect first, with a short TransmitDelay (50ms) so the immediate flush from Enqueue(flush: true) actually picks it up. The rest of the cleanup (Map.Remove, AuthInfo state, Save, RemoveUser) follows after the 0x03 is already in flight. Verified diagnosis via client-side packet log: after the fix is deployed, the client should see `inbound opcode=0x03` ahead of the disconnect, follow the redirect normally, and land at the login screen without a "Connection Lost" popup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #335 +/- ##
==========================================
+ Coverage 31.79% 31.84% +0.04%
==========================================
Files 339 339
Lines 26485 26485
Branches 3681 3681
==========================================
+ Hits 8422 8433 +11
+ Misses 17349 17337 -12
- Partials 714 715 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
baughj
approved these changes
May 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On
PacketHandler_0x0B (endSignal=0), the0x03 Redirectpacket was queued afterMap.Remove(user)had already enqueued a0x0E AoiDeparture, and with the defaulttransmitDelay = 1200ms. Two compounding problems:FlushSendBufferbreaks out when it hits a delayed packet after buffering a no-delay one — so the0x03was always deferred to the next 50msProcessOutboundtick rather than going out in the immediate flush thatClient.Redirect'sEnqueue(flush: true)was trying to force.0x03did get picked up, its 1200msTask.Delayeasily outlived the live-socket window. Eager-closing clients (or downstream socket teardown from the cleanup below this line) meant the Redirect never reached the wire.The visible client symptom: a spurious "Connection Lost" popup on Exit Game because the client interpreted the silent socket close as an unexpected disconnect rather than a logout-and-redirect.
Fix
Two changes in one block (World.cs):
SendRedirectruns first. Itsflush: trueEnqueue triggers an immediateFlushSendBufferagainst an empty queue — the0x03is the only packet, so the "break on delayed packet after no-delay" rule doesn't fire.transmitDelayfrom 1200 to 50 so the inter-packet hold is short enough that the live-socket window comfortably covers it.Diagnosis trail
Verified via client-side packet log (Chaos.Client
notice-debug.log). Before fix:No
0x03ever arrives at the client. After this fix the0x03should appear ahead of the disconnect and the client's normal redirect flow takes over.Test plan
endSignal=1(query) branch🤖 Generated with Claude Code