Join wait: animated waiting screen instead of "Not Responding"

The relay seat-wait loop (RelayRequestSeat -- the join/join_lan "patient
walk-up") blocked the window thread's message pump for its whole 30-minute
patience window: dial (2s timeout) -> Sleep(2000) -> repeat, with status
going only to the parent bat console.  Windows flagged the frozen game
window "Not Responding" until the operator started the session
(user-reported).

- BTWaitScreenPaint (L4VIDEO.cpp): a GDI waiting screen on the main window
  -- headline + detail line in the console green + a 12-segment marching
  spinner phased on the tick clock.  Pure GDI: flicker-free during the
  seat wait (no D3D presenting yet), and re-painted after each
  ExecuteIdle Present so the WaitingForEgg phase (previously a bare black
  frame) shows "WAITING FOR MISSION ASSIGNMENT" too.
- RelayWaitTick (L4NET.CPP): PeekMessage pump + paint.  The outer dial
  loop's Sleep(2000) becomes 20 pumped 100ms slices ("WAITING FOR THE
  OPERATOR'S SESSION" / "session at <ip:port> -- close this window to
  cancel"); the inner seat-reply wait pumps per 200ms select slice.

Verified live against a dead relay address: window-only PrintWindow capture
shows the animated screen, and user32 IsHungAppWindow (the API behind "Not
Responding") reports FALSE throughout the wait.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-22 08:16:13 -05:00
co-authored by Claude Opus 4.8
parent af22c4c78d
commit f5e0ffcd14
2 changed files with 99 additions and 2 deletions
+31 -1
View File
@@ -1506,6 +1506,24 @@ void L4NetworkManager::HostDisconnectedMessageHandler(HostDisconnectedMessage* H
// relaySelf and everything downstream (egg self-match, HELLO) proceeds as if
// BT_SELF had been set. SEAT_FULL / timeout => False.
//
//
// RelayWaitTick -- pump the window thread + paint the animated waiting screen
// (join/join_lan UX fix 2026-07-22: the seat-wait loop blocked the message
// pump for its whole 30-min patience window, so the main window showed "Not
// Responding" until the console started the game).
//
static void RelayWaitTick(const char *line1, const char *line2)
{
MSG msg;
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
extern void BTWaitScreenPaint(const char *, const char *);
BTWaitScreenPaint(line1, line2);
}
Logical L4NetworkManager::RelayRequestSeat()
{
//
@@ -1541,7 +1559,17 @@ Logical L4NetworkManager::RelayRequestSeat()
{
BTRelayWaitStatus("\n");
}
Sleep(2000);
{
char detail[128];
sprintf(detail, "session at %s:%d -- close this window to cancel",
inet_ntoa(relayGameAddress.sin_addr),
(int)ntohs(relayGameAddress.sin_port) - 1);
for (int slice = 0; slice < 20; ++slice) // 2s, pumped + animated
{
RelayWaitTick("WAITING FOR THE OPERATOR'S SESSION", detail);
Sleep(100);
}
}
continue;
}
Logical got_seat = False;
@@ -1564,6 +1592,8 @@ Logical L4NetworkManager::RelayRequestSeat()
tv.tv_usec = 200000;
if (select(0, &read_set, NULL, NULL, &tv) != 1)
{
RelayWaitTick("WAITING FOR THE OPERATOR'S SESSION",
"requesting a seat...");
continue;
}
int received = recv(seat_socket, reply + have,