Skip to content

fix: BadgeInfo response wrapping + ChallengeArenaResetInfo handler (stops client spam)#23

Open
Tom2096 wants to merge 3 commits into
decompfrontier:mainfrom
Tom2096:main
Open

fix: BadgeInfo response wrapping + ChallengeArenaResetInfo handler (stops client spam)#23
Tom2096 wants to merge 3 commits into
decompfrontier:mainfrom
Tom2096:main

Conversation

@Tom2096
Copy link
Copy Markdown

@Tom2096 Tom2096 commented May 11, 2026

Changes

  • BadgeInfo: Wrapped response under h23iRjGN dispatch key so the client's path B pipeline finds it
  • ChallengeArenaResetInfo: Registered handler returns server_time=now + daily_cooling_end=now+1h, which blocks the rare client retry spam (~1/s → ~1/hr)
  • Packet generator: Moved BadgeInfoResp and ChallengeArenaResetInfoResp into handlers.kdl; timestamp fields use datetime-unix::str

Root Cause (ChallengeArenaResetInfo spam)

Without a handler, the server returned GmeError{cmd=Close}, which the client interpreted as a connection failure and re-fired every frame (~50ms). With a handler returning empty timestamps, the client's needServerRefresh() uses a 1-second-resolution time() call, causing ~1s retries. Setting daily_cooling_end into the future blocks refreshes until it expires.

Verified

  • Server log confirms correct response format
  • Client retry cadence confirmed: 50ms (error) → 1s (empty) → 1hr (with +1h threshold)

Copy link
Copy Markdown
Member

@arves100 arves100 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution, please answer my comments left in the review, thanks

Comment thread .gitignore
Comment thread gimuserver/gme/ChallengeArenaResetInfo.cpp Outdated
Comment thread gimuserver/gme/ChallengeArenaResetInfo.cpp Outdated
Comment thread gimuserver/gme/ChallengeArenaResetInfo.cpp Outdated
Comment thread gimuserver/gme/ChallengeArenaResetInfo.cpp Outdated
@Tom2096 Tom2096 changed the title fix: Wrap BadgeInfo response under h23iRjGN dispatch key fix: BadgeInfo response wrapping + ChallengeArenaResetInfo handler (stops client spam) May 12, 2026
@Tom2096
Copy link
Copy Markdown
Author

Tom2096 commented May 12, 2026

to show the logs from when i tested with 5 second interval on ChallengeArenaResetInfo

 - HttpResponseImpl.cc:712
20260512 07:14:59.015000 UTC 16604 TRACE [addHeader] cookies!!!:JSESSIONID=6163bea6-fa9f-47b4-8d9b-9a0f4cc7727a - HttpRequestImpl.cc:432
20260512 07:14:59.015000 UTC 16604 TRACE [onHttpRequest] new request:127.0.0.1:61639->127.0.0.1:9960 - HttpServer.cc:415
20260512 07:14:59.015000 UTC 16604 TRACE [onHttpRequest] Headers POST /bf/gme/action.php - HttpServer.cc:417
20260512 07:14:59.015000 UTC 16604 TRACE [onHttpRequest] http path=/bf/gme/action.php - HttpServer.cc:418
20260512 07:14:59.016000 UTC 16604 TRACE [renderToBuffer] response(no body):HTTP/1.1 200 OK
content-length: 208
content-type: text/html; charset=utf-8
server: drogon/1.9.12
date: Tue, 12 May 2026 07:14:59 GMT

 - HttpResponseImpl.cc:712
20260512 07:15:05.015000 UTC 16604 TRACE [addHeader] cookies!!!:JSESSIONID=6163bea6-fa9f-47b4-8d9b-9a0f4cc7727a - HttpRequestImpl.cc:432
20260512 07:15:05.015000 UTC 16604 TRACE [onHttpRequest] new request:127.0.0.1:61639->127.0.0.1:9960 - HttpServer.cc:415
20260512 07:15:05.015000 UTC 16604 TRACE [onHttpRequest] Headers POST /bf/gme/action.php - HttpServer.cc:417
20260512 07:15:05.015000 UTC 16604 TRACE [onHttpRequest] http path=/bf/gme/action.php - HttpServer.cc:418
20260512 07:15:05.016000 UTC 16604 TRACE [renderToBuffer] response(no body):HTTP/1.1 200 OK
content-length: 208
content-type: text/html; charset=utf-8
server: drogon/1.9.12
date: Tue, 12 May 2026 07:15:05 GMT

@Tom2096
Copy link
Copy Markdown
Author

Tom2096 commented May 12, 2026

Polished up ChallengeArenaResetInfo.cpp, now it should retry every hour.

Copy link
Copy Markdown
Member

@arves100 arves100 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mm lgtm, I would wait for packet-generator PR to be merged first then update the commit baseline of this and try in my PC, thanks

Seltraeh added a commit to Seltraeh/server that referenced this pull request May 13, 2026
…allengeArenaResetInfo cooldown

Cherry-picks the three upstream packet-generator commits (5472598 / d2893ba /
61fedcc) onto our quests-branch submodule, then wires the matching handler
fixes into gimuserver/gme/ on the server side.  Reference: upstream PR
decompfrontier#23 (Tom2096).

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
DISCOVERED CLIENT BEHAVIOUR (the actual headline)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

The PR uncovered two important client-side patterns that we should treat
as general principles, not just BadgeInfo/ChallengeArenaResetInfo trivia:

  (1) WRAPPER STRUCT vs INNER STRUCT — the dispatch-key trap
      When a KDL schema defines `XxxInfo` + `XxxInfoResp` (with XxxInfoResp
      having one field of type XxxInfo keyed under a dispatch hash), the
      WRAPPER is what handlers must serialize.  Sending the inner struct
      directly puts the inner field-key at the root of the response body,
      where the client's dispatch pipeline doesn't recognise it.  The
      handler appears successful but no UI update fires — silent drop.

  (2) THE CONNECT-SCENE POLL CASCADE
      Handlers the client polls during the connect scene (notably
      ChallengeArenaResetInfo) have THREE escalating failure modes:
        - unregistered → GmeError{cmd=Close} → 50 ms retry (~20 req/s spam)
        - registered but `{}` → parse OK, needServerRefresh() trips on
          zero-valued timestamps → 1 second retry
        - registered with future-dated daily_cooling_end → no retry until
          the timestamp expires

      Formula: server_time + now() - local_snapshot > daily_cooling_end
      Resolution: 1-second tick from time().  Epoch zero is treated as
      "expired now".  ALWAYS set future timestamps on cooling/refresh
      response fields.

Both patterns are documented in the handbook (§6.11 and §6.12) for future
reference.  The "stubs return {} for now" default we've been using is
actively harmful for any handler the client polls — we should audit all
handlers currently returning {} to see if any of them are causing similar
unmetered request rates in deploy/log/.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
WHAT CHANGED
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

packet-generator submodule (cherry-picked, 3 commits)
  5472598  BadgeInfoResp wrapper struct with dispatch key h23iRjGN
  d2893ba  ChallengeArenaResetInfo + ChallengeArenaResetInfoResp wrapper
           (dispatch key t6bRQfln)
  61fedcc  Move BadgeInfoResp and ChallengeArenaResetInfoResp into
           handlers.kdl; switch timestamp fields to datetime-unix::str

  These commits are now on Seltraeh/packet-generator
  packet-generator-quests at 1192091; the submodule pointer bump in
  this commit picks them up.  On next cmake build the regenerated
  gimuserver/packets/all.hpp will contain BadgeInfoResp,
  ChallengeArenaResetInfo, and ChallengeArenaResetInfoResp with the
  correct glz::meta specializations.

gimuserver/gme/BadgeInfo.cpp
  Switched `::BadgeInfo resp{}` → `::BadgeInfoResp resp{}` so the
  serialized response carries the h23iRjGN dispatch key at the root
  instead of u7Htm9P4.  Inline comment cross-references PR decompfrontier#23.

gimuserver/gme/ChallengeArenaResetInfo.cpp
  Replaced the empty `{}` stub with the PR decompfrontier#23 logic:
    resp.reset_info.server_time       = now (ms precision)
    resp.reset_info.daily_cooling_end = server_time + 1h
  Other timestamps (daily_cooling_start, weekly_reset_time) stay at
  epoch — the client doesn't gate on those for this handler's polling
  logic.  TODO marker placed for deriving the real cooldown end from
  the arena reset schedule instead of a fixed +1h offset.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
WHAT'S NEXT
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  [1] Audit all handlers currently returning `{}`.  Anything the client
      treats as a cooldown/refresh-style poll will spam at 1 req/s
      indefinitely under the empty-handler regime documented above.
      Top candidates to check (high frequency in deploy/log/):
        - Zw3WIoWu ChallengeArenaResetInfo  (FIXED in this commit)
        - any other handler showing >2 calls/min in a single session

  [2] BadgeInfoResp default values.  Our current BadgeInfo struct ships
      everything at 0, which means no badges/scenarios/new content
      indicators.  Wire it to user_campaign_missions.state count and
      F_SCENARIO_MST so the home-screen "New" badges reflect actual
      player progress.

  [3] Continue the original backlog (Cordelica click-crash, F_MISSION_MST
      loading, etc. — see existing TODOs).
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.

3 participants