From fd468ce7938952618ad7bdff4b2123c7d740e4bb Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 13 Feb 2026 00:48:56 -0800 Subject: [PATCH] Allow per-expansion login header fields + fix challenge FourCC encoding --- Data/expansions/turtle/expansion.json | 1 + include/game/expansion_profile.hpp | 7 +++++++ src/auth/auth_packets.cpp | 21 ++++++++++----------- src/game/expansion_profile.cpp | 9 +++++++++ src/ui/auth_screen.cpp | 5 +++++ 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Data/expansions/turtle/expansion.json b/Data/expansions/turtle/expansion.json index b0b032a0..989c21e1 100644 --- a/Data/expansions/turtle/expansion.json +++ b/Data/expansions/turtle/expansion.json @@ -5,6 +5,7 @@ "version": { "major": 1, "minor": 12, "patch": 1 }, "build": 5875, "protocolVersion": 8, + "locale": "enGB", "maxLevel": 60, "races": [1, 2, 3, 4, 5, 6, 7, 8], "classes": [1, 2, 3, 4, 5, 7, 8, 9, 11] diff --git a/include/game/expansion_profile.hpp b/include/game/expansion_profile.hpp index ce21650f..c1948c74 100644 --- a/include/game/expansion_profile.hpp +++ b/include/game/expansion_profile.hpp @@ -21,6 +21,13 @@ struct ExpansionProfile { uint8_t patchVersion = 0; uint16_t build = 0; uint8_t protocolVersion = 0; // SRP auth protocol version byte + // Client header fields used in LOGON_CHALLENGE. + // Defaults match a typical Windows x86 client. + std::string game = "WoW"; + std::string platform = "x86"; + std::string os = "Win"; + std::string locale = "enUS"; + uint32_t timezone = 0; std::string dataPath; // Absolute path to expansion data dir uint32_t maxLevel = 60; std::vector races; diff --git a/src/auth/auth_packets.cpp b/src/auth/auth_packets.cpp index 6f99c31f..cbfbd1a4 100644 --- a/src/auth/auth_packets.cpp +++ b/src/auth/auth_packets.cpp @@ -25,14 +25,13 @@ network::Packet LogonChallengePacket::build(const std::string& account, const Cl // Payload size packet.writeUInt16(payloadSize); - // Write a FourCC-like 4-byte ASCII field in the legacy login wire format: - // reverse the characters and null-pad to 4 bytes. - // Example (1.12.1): platform "x86" is sent as bytes "68x\\0"; os "Win" as "niW\\0"; locale "enGB" as "BGne". - auto writeFourCCLE = [&packet](const std::string& str) { + // Write a 4-byte ASCII field (FourCC-ish): bytes are sent in-order and null-padded. + // Auth servers expect literal "x86\\0", "Win\\0", "enUS"/"enGB", etc. + auto writeFourCC = [&packet](const std::string& str) { uint8_t buf[4] = {0, 0, 0, 0}; size_t len = std::min(4, str.length()); for (size_t i = 0; i < len; ++i) { - buf[i] = static_cast(str[len - 1 - i]); + buf[i] = static_cast(str[i]); } for (int i = 0; i < 4; ++i) { packet.writeUInt8(buf[i]); @@ -59,14 +58,14 @@ network::Packet LogonChallengePacket::build(const std::string& account, const Cl // Build (2 bytes) packet.writeUInt16(info.build); - // Platform (4 bytes, legacy reversed encoding) - writeFourCCLE(info.platform); + // Platform (4 bytes) + writeFourCC(info.platform); - // OS (4 bytes, legacy reversed encoding) - writeFourCCLE(info.os); + // OS (4 bytes) + writeFourCC(info.os); - // Locale (4 bytes, legacy reversed encoding) - writeFourCCLE(info.locale); + // Locale (4 bytes) + writeFourCC(info.locale); // Timezone packet.writeUInt32(info.timezone); diff --git a/src/game/expansion_profile.cpp b/src/game/expansion_profile.cpp index 63b30aeb..600135fb 100644 --- a/src/game/expansion_profile.cpp +++ b/src/game/expansion_profile.cpp @@ -166,6 +166,15 @@ bool ExpansionRegistry::loadProfile(const std::string& jsonPath, const std::stri p.build = static_cast(jsonInt(json, "build")); p.protocolVersion = static_cast(jsonInt(json, "protocolVersion")); + // Optional client header fields (LOGON_CHALLENGE) + { + std::string v; + v = jsonValue(json, "game"); if (!v.empty()) p.game = v; + v = jsonValue(json, "platform"); if (!v.empty()) p.platform = v; + v = jsonValue(json, "os"); if (!v.empty()) p.os = v; + v = jsonValue(json, "locale"); if (!v.empty()) p.locale = v; + p.timezone = static_cast(jsonInt(json, "timezone", static_cast(p.timezone))); + } p.maxLevel = static_cast(jsonInt(json, "maxLevel", 60)); p.races = jsonUintArray(json, "races"); p.classes = jsonUintArray(json, "classes"); diff --git a/src/ui/auth_screen.cpp b/src/ui/auth_screen.cpp index c0431774..55d6fa48 100644 --- a/src/ui/auth_screen.cpp +++ b/src/ui/auth_screen.cpp @@ -509,6 +509,11 @@ void AuthScreen::attemptAuth(auth::AuthHandler& authHandler) { info.patchVersion = profile->patchVersion; info.build = profile->build; info.protocolVersion = profile->protocolVersion; + info.game = profile->game; + info.platform = profile->platform; + info.os = profile->os; + info.locale = profile->locale; + info.timezone = profile->timezone; authHandler.setClientInfo(info); } }