diff --git a/.gitignore b/.gitignore index 3a4759e..1cfe52f 100644 --- a/.gitignore +++ b/.gitignore @@ -486,3 +486,7 @@ vcpkg_installed/ .vscode generated/ .cmake/ + +# Project-specific +CONTEXT.md +out/ diff --git a/gimuserver/gme/BadgeInfo.cpp b/gimuserver/gme/BadgeInfo.cpp index b72092a..2d8c691 100644 --- a/gimuserver/gme/BadgeInfo.cpp +++ b/gimuserver/gme/BadgeInfo.cpp @@ -3,7 +3,7 @@ HANDLEF(BadgeInfo) { - ::BadgeInfo resp{}; + ::BadgeInfoResp resp{}; std::string buffer{}; const auto& ec = glz::write_json(resp, buffer); if (ec) diff --git a/gimuserver/gme/ChallengeArenaResetInfo.cpp b/gimuserver/gme/ChallengeArenaResetInfo.cpp new file mode 100644 index 0000000..d553965 --- /dev/null +++ b/gimuserver/gme/ChallengeArenaResetInfo.cpp @@ -0,0 +1,49 @@ +#include "App.hpp" +#include "Handlers.hpp" + +// ChallengeArenaResetInfo +// +// By default the server returns GmeError{cmd=Close}, which the +// client interpreted as a connection failure. The connect scene never +// transitioned away, so the game loop re-fired the request every frame. +// +// With this handler returning empty timestamps (instead of an error), the client parses +// a valid response and stores server_time + a local snapshot. needServerRefresh() computes: +// +// server_time + now() - local_snapshot > daily_cooling_end +// +// Assume fields start at zero. After parsing the empty response, server_time stays 0, +// local_snapshot is set to the current time (via time()), and daily_cooling_end stays 0. +// So the check becomes: 0 + now() - local_snapshot > 0. +// +// Since local_snapshot == the time() value from just after parsing, this is false until +// now() ticks forward to the next second. +// +// To stop the client from retrying every second, we'll set daily_cooling_end to an hour in the +// future. +// +// TODO: figure out the actual intended cooldown time and use that instead. +HANDLEF(ChallengeArenaResetInfo) +{ + using namespace std::chrono; + using namespace std::chrono_literals; + + ::ChallengeArenaResetInfoResp resp{}; + + // I've tested this with 5 seconds as well, which causes the client to retry every 6 seconds. + // This makes sense since its an explicit greater-than check. + // Using an hour here as a placeholder to prevent the client from constantly retrying and polluting + // our logs (and our disks :D). + resp.reset_info.server_time = floor(system_clock::now()); + resp.reset_info.daily_cooling_end = resp.reset_info.server_time + 1h; + + std::string buffer{}; + const auto& ec = glz::write_json(resp, buffer); + if (ec) { + const auto& glze = glz::format_error(ec, buffer); + LOG_DEBUG << "Gme ChallengeArenaResetInfo Error during JSON writing: " << glze; + co_return HandleResult::error("Serialization error", glze); + } + + co_return HandleResult::success(buffer); +} \ No newline at end of file diff --git a/gimuserver/gme/GmeControllerHandlers.cpp b/gimuserver/gme/GmeControllerHandlers.cpp index 27f3458..de5661b 100644 --- a/gimuserver/gme/GmeControllerHandlers.cpp +++ b/gimuserver/gme/GmeControllerHandlers.cpp @@ -65,6 +65,7 @@ static GmeHandler getHandler(std::string_view cmd) REGISTER("MfZyu1q9", Initialize, "EmcshnQoDr20TZz1"); + REGISTER("Zw3WIoWu", ChallengeArenaResetInfo, "KlwYMGF1"); REGISTER("nJ3A7qFp", BadgeInfo, "bGxX67KB"); REGISTER("uYF93Mhc", ControlCenterEnter, "d0k6LGUu"); REGISTER("m2Ve9PkJ", DeckEdit, "d7UuQsq8"); diff --git a/gimuserver/gme/Handlers.hpp b/gimuserver/gme/Handlers.hpp index c3bce4d..debda14 100644 --- a/gimuserver/gme/Handlers.hpp +++ b/gimuserver/gme/Handlers.hpp @@ -81,6 +81,7 @@ namespace GmeHandlers { HANDLE(Initialize); HANDLE(BadgeInfo); + HANDLE(ChallengeArenaResetInfo); HANDLE(ControlCenterEnter); HANDLE(DeckEdit); HANDLE(FriendGet); diff --git a/packet-generator b/packet-generator index 37256a2..61fedcc 160000 --- a/packet-generator +++ b/packet-generator @@ -1 +1 @@ -Subproject commit 37256a25049637980fcac4c7f5fafa1654b45d2e +Subproject commit 61fedcc3275d4abc209ba997f980d51010c87453