diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0357408b..0698607a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,6 +59,10 @@ jobs: - name: Configure run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release + - name: Verify Release Config + run: | + cmake -LA -N build | grep -E '^CMAKE_BUILD_TYPE:STRING=Release$' + - name: Build run: cmake --build build --parallel $(nproc) @@ -123,6 +127,10 @@ jobs: -DCMAKE_PREFIX_PATH="$BREW" \ -DOPENSSL_ROOT_DIR="$(brew --prefix openssl@3)" + - name: Verify Release Config + run: | + cmake -LA -N build | grep -E '^CMAKE_BUILD_TYPE:STRING=Release$' + - name: Build run: cmake --build build --parallel $(sysctl -n hw.logicalcpu) @@ -271,6 +279,11 @@ jobs: shell: msys2 {0} run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release + - name: Verify Release Config + shell: msys2 {0} + run: | + cmake -LA -N build | grep -E '^CMAKE_BUILD_TYPE:STRING=Release$' + - name: Build shell: msys2 {0} run: cmake --build build --parallel $(nproc) diff --git a/CMakeLists.txt b/CMakeLists.txt index ecfc7c1d..14f55887 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,13 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# Explicitly tag optimized configs so runtime defaults can enforce low-noise logging. +add_compile_definitions( + $<$:WOWEE_RELEASE_LOGGING> + $<$:WOWEE_RELEASE_LOGGING> + $<$:WOWEE_RELEASE_LOGGING> +) + # Output directories set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) diff --git a/include/core/logger.hpp b/include/core/logger.hpp index 4ba4e3ce..8e0d8f0a 100644 --- a/include/core/logger.hpp +++ b/include/core/logger.hpp @@ -65,6 +65,13 @@ public: } private: + static constexpr int kDefaultMinLevelValue = +#if defined(NDEBUG) || defined(WOWEE_RELEASE_LOGGING) + static_cast(LogLevel::WARNING); +#else + static_cast(LogLevel::INFO); +#endif + Logger() = default; ~Logger() = default; Logger(const Logger&) = delete; @@ -77,13 +84,21 @@ private: return oss.str(); } - std::atomic minLevel_{static_cast(LogLevel::INFO)}; + std::atomic minLevel_{kDefaultMinLevelValue}; std::mutex mutex; std::ofstream fileStream; bool fileReady = false; bool echoToStdout_ = true; std::chrono::steady_clock::time_point lastFlushTime_{}; uint32_t flushIntervalMs_ = 250; + bool dedupeEnabled_ = true; + uint32_t dedupeWindowMs_ = 250; + LogLevel lastLevel_ = LogLevel::DEBUG; + std::string lastMessage_; + std::chrono::steady_clock::time_point lastMessageTime_{}; + uint64_t suppressedCount_ = 0; + void emitLineLocked(LogLevel level, const std::string& message); + void flushSuppressedLocked(); void ensureFile(); }; diff --git a/include/ui/auth_screen.hpp b/include/ui/auth_screen.hpp index 484797e3..9f34ff46 100644 --- a/include/ui/auth_screen.hpp +++ b/include/ui/auth_screen.hpp @@ -120,6 +120,7 @@ private: bool musicInitAttempted = false; bool musicPlaying = false; + bool missingIntroTracksLogged_ = false; bool loginMusicVolumeAdjusted_ = false; int savedMusicVolume_ = 30; }; diff --git a/src/auth/auth_packets.cpp b/src/auth/auth_packets.cpp index f2bd2128..f95a5344 100644 --- a/src/auth/auth_packets.cpp +++ b/src/auth/auth_packets.cpp @@ -122,12 +122,9 @@ network::Packet LogonChallengePacket::build(const std::string& account, const Cl packet.writeUInt8(localIp[1]); packet.writeUInt8(localIp[2]); packet.writeUInt8(localIp[3]); - LOG_DEBUG("LOGON_CHALLENGE client IP=", static_cast(localIp[0]), ".", - static_cast(localIp[1]), ".", static_cast(localIp[2]), ".", - static_cast(localIp[3])); } else { packet.writeUInt32(0); - LOG_WARNING("LOGON_CHALLENGE client IP detection failed; falling back to 0.0.0.0"); + LOG_DEBUG("LOGON_CHALLENGE client IP detection failed; using 0.0.0.0 fallback"); } } diff --git a/src/core/logger.cpp b/src/core/logger.cpp index 498dd219..f513b836 100644 --- a/src/core/logger.cpp +++ b/src/core/logger.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include namespace wowee { namespace core { @@ -28,20 +30,35 @@ void Logger::ensureFile() { flushIntervalMs_ = static_cast(parsed); } } + if (const char* dedupe = std::getenv("WOWEE_LOG_DEDUPE")) { + dedupeEnabled_ = !(dedupe[0] == '0' || dedupe[0] == 'f' || dedupe[0] == 'F' || + dedupe[0] == 'n' || dedupe[0] == 'N'); + } + if (const char* dedupeMs = std::getenv("WOWEE_LOG_DEDUPE_MS")) { + char* end = nullptr; + unsigned long parsed = std::strtoul(dedupeMs, &end, 10); + if (end != dedupeMs && parsed <= 60000ul) { + dedupeWindowMs_ = static_cast(parsed); + } + } + if (const char* level = std::getenv("WOWEE_LOG_LEVEL")) { + std::string v(level); + std::transform(v.begin(), v.end(), v.begin(), [](unsigned char c) { + return static_cast(std::tolower(c)); + }); + if (v == "debug") setLogLevel(LogLevel::DEBUG); + else if (v == "info") setLogLevel(LogLevel::INFO); + else if (v == "warn" || v == "warning") setLogLevel(LogLevel::WARNING); + else if (v == "error") setLogLevel(LogLevel::ERROR); + else if (v == "fatal") setLogLevel(LogLevel::FATAL); + } std::error_code ec; std::filesystem::create_directories("logs", ec); fileStream.open("logs/wowee.log", std::ios::out | std::ios::trunc); lastFlushTime_ = std::chrono::steady_clock::now(); } -void Logger::log(LogLevel level, const std::string& message) { - if (!shouldLog(level)) { - return; - } - - std::lock_guard lock(mutex); - ensureFile(); - +void Logger::emitLineLocked(LogLevel level, const std::string& message) { // Get current time auto now = std::chrono::system_clock::now(); auto time = std::chrono::system_clock::to_time_t(now); @@ -92,6 +109,38 @@ void Logger::log(LogLevel level, const std::string& message) { } } +void Logger::flushSuppressedLocked() { + if (suppressedCount_ == 0) return; + emitLineLocked(lastLevel_, "Previous message repeated " + std::to_string(suppressedCount_) + " times"); + suppressedCount_ = 0; +} + +void Logger::log(LogLevel level, const std::string& message) { + if (!shouldLog(level)) { + return; + } + + std::lock_guard lock(mutex); + ensureFile(); + + auto nowSteady = std::chrono::steady_clock::now(); + if (dedupeEnabled_ && !lastMessage_.empty() && + level == lastLevel_ && message == lastMessage_) { + auto elapsedMs = std::chrono::duration_cast(nowSteady - lastMessageTime_).count(); + if (elapsedMs >= 0 && elapsedMs <= static_cast(dedupeWindowMs_)) { + ++suppressedCount_; + lastMessageTime_ = nowSteady; + return; + } + } + + flushSuppressedLocked(); + emitLineLocked(level, message); + lastLevel_ = level; + lastMessage_ = message; + lastMessageTime_ = nowSteady; +} + void Logger::setLogLevel(LogLevel level) { minLevel_.store(static_cast(level), std::memory_order_relaxed); } diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 03ad0679..6887e8ee 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -1235,7 +1235,7 @@ void GameHandler::handlePacket(network::Packet& packet) { ++wardenPacketsAfterGate_; } if (preLogicalOp && isAuthCharPipelineOpcode(*preLogicalOp)) { - LOG_INFO("AUTH/CHAR RX opcode=0x", std::hex, opcode, std::dec, + LOG_DEBUG("AUTH/CHAR RX opcode=0x", std::hex, opcode, std::dec, " state=", worldStateName(state), " size=", packet.getSize()); } @@ -3462,7 +3462,7 @@ bool GameHandler::loadWardenCRFile(const std::string& moduleHashHex) { for (int i = 0; i < 9; i++) { char s[16]; snprintf(s, sizeof(s), "%s=0x%02X ", names[i], wardenCheckOpcodes_[i]); opcHex += s; } - LOG_INFO("Warden: Check opcodes: ", opcHex); + LOG_DEBUG("Warden: Check opcodes: ", opcHex); } size_t entryCount = (static_cast(fileSize) - CR_HEADER_SIZE) / CR_ENTRY_SIZE; @@ -3522,7 +3522,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { } if (decrypted.size() > 64) hex += "... (" + std::to_string(decrypted.size() - 64) + " more)"; - LOG_INFO("Warden: Decrypted (", decrypted.size(), " bytes): ", hex); + LOG_DEBUG("Warden: Decrypted (", decrypted.size(), " bytes): ", hex); } if (decrypted.empty()) { @@ -3541,7 +3541,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { } if (socket && socket->isConnected()) { socket->send(response); - LOG_INFO("Warden: Sent response (", plaintext.size(), " bytes plaintext)"); + LOG_DEBUG("Warden: Sent response (", plaintext.size(), " bytes plaintext)"); } }; @@ -3564,7 +3564,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { { std::string hashHex; for (auto b : wardenModuleHash_) { char s[4]; snprintf(s, 4, "%02x", b); hashHex += s; } - LOG_INFO("Warden: MODULE_USE hash=", hashHex, " size=", wardenModuleSize_); + LOG_DEBUG("Warden: MODULE_USE hash=", hashHex, " size=", wardenModuleSize_); // Try to load pre-computed challenge/response entries loadWardenCRFile(hashHex); @@ -3574,7 +3574,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { std::vector resp = { 0x00 }; // WARDEN_CMSG_MODULE_MISSING sendWardenResponse(resp); wardenState_ = WardenState::WAIT_MODULE_CACHE; - LOG_INFO("Warden: Sent MODULE_MISSING, waiting for module data chunks"); + LOG_DEBUG("Warden: Sent MODULE_MISSING, waiting for module data chunks"); break; } @@ -3598,7 +3598,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { decrypted.begin() + 3, decrypted.begin() + 3 + chunkSize); - LOG_INFO("Warden: MODULE_CACHE chunk ", chunkSize, " bytes, total ", + LOG_DEBUG("Warden: MODULE_CACHE chunk ", chunkSize, " bytes, total ", wardenModuleData_.size(), "/", wardenModuleSize_); // Check if module download is complete @@ -3627,7 +3627,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { std::ofstream wf(cachePath, std::ios::binary); if (wf) { wf.write(reinterpret_cast(wardenModuleData_.data()), wardenModuleData_.size()); - LOG_INFO("Warden: Cached module to ", cachePath); + LOG_DEBUG("Warden: Cached module to ", cachePath); } } @@ -3644,7 +3644,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { // Send MODULE_OK (opcode 0x01) std::vector resp = { 0x01 }; // WARDEN_CMSG_MODULE_OK sendWardenResponse(resp); - LOG_INFO("Warden: Sent MODULE_OK"); + LOG_DEBUG("Warden: Sent MODULE_OK"); } // No response for intermediate chunks break; @@ -3670,7 +3670,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { } if (match) { - LOG_INFO("Warden: Found matching CR entry for seed"); + LOG_DEBUG("Warden: Found matching CR entry for seed"); // Log the reply we're sending { @@ -3678,7 +3678,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { for (int i = 0; i < 20; i++) { char s[4]; snprintf(s, 4, "%02x", match->reply[i]); replyHex += s; } - LOG_INFO("Warden: Sending pre-computed reply=", replyHex); + LOG_DEBUG("Warden: Sending pre-computed reply=", replyHex); } // Send HASH_RESULT (opcode 0x04 + 20-byte reply) @@ -3693,7 +3693,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { std::vector newDecryptKey(match->serverKey, match->serverKey + 16); wardenCrypto_->replaceKeys(newEncryptKey, newDecryptKey); - LOG_INFO("Warden: Switched to CR key set"); + LOG_DEBUG("Warden: Switched to CR key set"); wardenState_ = WardenState::WAIT_CHECKS; break; @@ -3721,7 +3721,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { const auto& firstCR = wardenCREntries_[0]; std::string expectedHex; for (int i = 0; i < 20; i++) { char s[4]; snprintf(s, 4, "%02x", firstCR.reply[i]); expectedHex += s; } - LOG_INFO("Warden: Empirical test — expected reply from CR[0]=", expectedHex); + LOG_DEBUG("Warden: Empirical test — expected reply from CR[0]=", expectedHex); // Test 1: SHA1(moduleImage) { @@ -3729,7 +3729,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { auto h = auth::Crypto::sha1(data); bool match = (std::memcmp(h.data(), firstCR.reply, 20) == 0); std::string hex; for (auto b : h) { char s[4]; snprintf(s, 4, "%02x", b); hex += s; } - LOG_INFO("Warden: SHA1(moduleImage)=", hex, match ? " MATCH!" : ""); + LOG_DEBUG("Warden: SHA1(moduleImage)=", hex, match ? " MATCH!" : ""); } // Test 2: SHA1(seed || moduleImage) { @@ -3739,7 +3739,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { auto h = auth::Crypto::sha1(data); bool match = (std::memcmp(h.data(), firstCR.reply, 20) == 0); std::string hex; for (auto b : h) { char s[4]; snprintf(s, 4, "%02x", b); hex += s; } - LOG_INFO("Warden: SHA1(seed||image)=", hex, match ? " MATCH!" : ""); + LOG_DEBUG("Warden: SHA1(seed||image)=", hex, match ? " MATCH!" : ""); } // Test 3: SHA1(moduleImage || seed) { @@ -3748,21 +3748,21 @@ void GameHandler::handleWardenData(network::Packet& packet) { auto h = auth::Crypto::sha1(data); bool match = (std::memcmp(h.data(), firstCR.reply, 20) == 0); std::string hex; for (auto b : h) { char s[4]; snprintf(s, 4, "%02x", b); hex += s; } - LOG_INFO("Warden: SHA1(image||seed)=", hex, match ? " MATCH!" : ""); + LOG_DEBUG("Warden: SHA1(image||seed)=", hex, match ? " MATCH!" : ""); } // Test 4: SHA1(decompressedData) { auto h = auth::Crypto::sha1(decompressedData); bool match = (std::memcmp(h.data(), firstCR.reply, 20) == 0); std::string hex; for (auto b : h) { char s[4]; snprintf(s, 4, "%02x", b); hex += s; } - LOG_INFO("Warden: SHA1(decompressed)=", hex, match ? " MATCH!" : ""); + LOG_DEBUG("Warden: SHA1(decompressed)=", hex, match ? " MATCH!" : ""); } // Test 5: SHA1(rawModuleData) { auto h = auth::Crypto::sha1(wardenModuleData_); bool match = (std::memcmp(h.data(), firstCR.reply, 20) == 0); std::string hex; for (auto b : h) { char s[4]; snprintf(s, 4, "%02x", b); hex += s; } - LOG_INFO("Warden: SHA1(rawModule)=", hex, match ? " MATCH!" : ""); + LOG_DEBUG("Warden: SHA1(rawModule)=", hex, match ? " MATCH!" : ""); } // Test 6: Check if all CR replies are the same (constant hash) { @@ -3773,7 +3773,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { break; } } - LOG_INFO("Warden: All ", wardenCREntries_.size(), " CR replies identical? ", allSame ? "YES" : "NO"); + LOG_DEBUG("Warden: All ", wardenCREntries_.size(), " CR replies identical? ", allSame ? "YES" : "NO"); } } @@ -3786,7 +3786,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { { std::string hex; for (auto b : reply) { char s[4]; snprintf(s, 4, "%02x", b); hex += s; } - LOG_INFO("Warden: Sending SHA1(moduleImage)=", hex); + LOG_DEBUG("Warden: Sending SHA1(moduleImage)=", hex); } // Send HASH_RESULT (opcode 0x04 + 20-byte hash) @@ -3807,7 +3807,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { wardenCrypto_->replaceKeys(ek, dk); for (auto& b : newEncryptKey) b = 0; for (auto& b : newDecryptKey) b = 0; - LOG_INFO("Warden: Derived and applied key update from seed"); + LOG_DEBUG("Warden: Derived and applied key update from seed"); } wardenState_ = WardenState::WAIT_CHECKS; @@ -3815,7 +3815,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { } case 0x02: { // WARDEN_SMSG_CHEAT_CHECKS_REQUEST - LOG_INFO("Warden: CHEAT_CHECKS_REQUEST (", decrypted.size(), " bytes)"); + LOG_DEBUG("Warden: CHEAT_CHECKS_REQUEST (", decrypted.size(), " bytes)"); if (decrypted.size() < 3) { LOG_ERROR("Warden: CHEAT_CHECKS_REQUEST too short"); @@ -3833,14 +3833,14 @@ void GameHandler::handleWardenData(network::Packet& packet) { strings.emplace_back(reinterpret_cast(decrypted.data() + pos), slen); pos += slen; } - LOG_INFO("Warden: String table: ", strings.size(), " entries"); + LOG_DEBUG("Warden: String table: ", strings.size(), " entries"); for (size_t i = 0; i < strings.size(); i++) { - LOG_INFO("Warden: [", i, "] = \"", strings[i], "\""); + LOG_DEBUG("Warden: [", i, "] = \"", strings[i], "\""); } // XOR byte is the last byte of the packet uint8_t xorByte = decrypted.back(); - LOG_INFO("Warden: XOR byte = 0x", [&]{ char s[4]; snprintf(s,4,"%02x",xorByte); return std::string(s); }()); + LOG_DEBUG("Warden: XOR byte = 0x", [&]{ char s[4]; snprintf(s,4,"%02x",xorByte); return std::string(s); }()); // Check type enum indices enum CheckType { CT_MEM=0, CT_PAGE_A=1, CT_PAGE_B=2, CT_MPQ=3, CT_LUA=4, @@ -3958,7 +3958,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { pos++; checkCount++; - LOG_INFO("Warden: Check #", checkCount, " type=", checkTypeNames[ct], + LOG_DEBUG("Warden: Check #", checkCount, " type=", checkTypeNames[ct], " at offset ", pos - 1); switch (ct) { @@ -3984,10 +3984,10 @@ void GameHandler::handleWardenData(network::Packet& packet) { | (uint32_t(decrypted[pos+2])<<16) | (uint32_t(decrypted[pos+3])<<24); pos += 4; uint8_t readLen = decrypted[pos++]; - LOG_INFO("Warden: MEM offset=0x", [&]{char s[12];snprintf(s,12,"%08x",offset);return std::string(s);}(), + LOG_DEBUG("Warden: MEM offset=0x", [&]{char s[12];snprintf(s,12,"%08x",offset);return std::string(s);}(), " len=", (int)readLen); if (!moduleName.empty()) { - LOG_INFO("Warden: MEM module=\"", moduleName, "\""); + LOG_DEBUG("Warden: MEM module=\"", moduleName, "\""); } // Lazy-load WoW.exe PE image on first MEM_CHECK @@ -4001,7 +4001,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { // Read bytes from PE image (includes patched runtime globals) std::vector memBuf(readLen, 0); if (wardenMemory_->isLoaded() && wardenMemory_->readMemory(offset, readLen, memBuf.data())) { - LOG_INFO("Warden: MEM_CHECK served from PE image"); + LOG_DEBUG("Warden: MEM_CHECK served from PE image"); } else { LOG_WARNING("Warden: MEM_CHECK fallback to zeros for 0x", [&]{char s[12];snprintf(s,12,"%08x",offset);return std::string(s);}()); @@ -4054,7 +4054,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { pageResult = 0x4A; // PatternFound } } - LOG_INFO("Warden: PAGE_A request bytes=", consume, + LOG_DEBUG("Warden: PAGE_A request bytes=", consume, " result=0x", [&]{char s[4];snprintf(s,4,"%02x",pageResult);return std::string(s);}()); pos += consume; resultData.push_back(pageResult); @@ -4093,7 +4093,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { pageResult = 0x4A; // PatternFound } } - LOG_INFO("Warden: PAGE_B request bytes=", consume, + LOG_DEBUG("Warden: PAGE_B request bytes=", consume, " result=0x", [&]{char s[4];snprintf(s,4,"%02x",pageResult);return std::string(s);}()); pos += consume; resultData.push_back(pageResult); @@ -4104,7 +4104,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { if (pos + 1 > checkEnd) { pos = checkEnd; break; } uint8_t strIdx = decrypted[pos++]; std::string filePath = resolveWardenString(strIdx); - LOG_INFO("Warden: MPQ file=\"", (filePath.empty() ? "?" : filePath), "\""); + LOG_DEBUG("Warden: MPQ file=\"", (filePath.empty() ? "?" : filePath), "\""); bool found = false; std::vector hash(20, 0); @@ -4150,7 +4150,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { if (pos + 1 > checkEnd) { pos = checkEnd; break; } uint8_t strIdx = decrypted[pos++]; std::string luaVar = resolveWardenString(strIdx); - LOG_INFO("Warden: LUA str=\"", (luaVar.empty() ? "?" : luaVar), "\""); + LOG_DEBUG("Warden: LUA str=\"", (luaVar.empty() ? "?" : luaVar), "\""); // Response: [uint8 result=0][uint16 len=0] // Lua string doesn't exist resultData.push_back(0x01); // not found @@ -4162,7 +4162,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { pos += 24; // skip seed + sha1 uint8_t strIdx = decrypted[pos++]; std::string driverName = resolveWardenString(strIdx); - LOG_INFO("Warden: DRIVER=\"", (driverName.empty() ? "?" : driverName), "\""); + LOG_DEBUG("Warden: DRIVER=\"", (driverName.empty() ? "?" : driverName), "\""); // Response: [uint8 result=1] (driver NOT found = clean) resultData.push_back(0x01); break; @@ -4219,7 +4219,7 @@ void GameHandler::handleWardenData(network::Packet& packet) { } } - LOG_INFO("Warden: Parsed ", checkCount, " checks, result data size=", resultData.size()); + LOG_DEBUG("Warden: Parsed ", checkCount, " checks, result data size=", resultData.size()); // --- Compute checksum: XOR of 5 uint32s from SHA1(resultData) --- auto resultHash = auth::Crypto::sha1(resultData); @@ -4244,18 +4244,18 @@ void GameHandler::handleWardenData(network::Packet& packet) { resp.push_back((checksum >> 24) & 0xFF); resp.insert(resp.end(), resultData.begin(), resultData.end()); sendWardenResponse(resp); - LOG_INFO("Warden: Sent CHEAT_CHECKS_RESULT (", resp.size(), " bytes, ", + LOG_DEBUG("Warden: Sent CHEAT_CHECKS_RESULT (", resp.size(), " bytes, ", checkCount, " checks, checksum=0x", [&]{char s[12];snprintf(s,12,"%08x",checksum);return std::string(s);}(), ")"); break; } case 0x03: // WARDEN_SMSG_MODULE_INITIALIZE - LOG_INFO("Warden: MODULE_INITIALIZE (", decrypted.size(), " bytes, no response needed)"); + LOG_DEBUG("Warden: MODULE_INITIALIZE (", decrypted.size(), " bytes, no response needed)"); break; default: - LOG_INFO("Warden: Unknown opcode 0x", std::hex, (int)wardenOpcode, std::dec, + LOG_DEBUG("Warden: Unknown opcode 0x", std::hex, (int)wardenOpcode, std::dec, " (state=", (int)wardenState_, ", size=", decrypted.size(), ")"); break; } diff --git a/src/ui/auth_screen.cpp b/src/ui/auth_screen.cpp index f76b21ba..6b63cd3f 100644 --- a/src/ui/auth_screen.cpp +++ b/src/ui/auth_screen.cpp @@ -263,7 +263,10 @@ void AuthScreen::render(auth::AuthHandler& authHandler) { LOG_INFO("AuthScreen: Playing login intro track: ", path); musicPlaying = music->isPlaying(); } else { - LOG_WARNING("AuthScreen: No login intro tracks found in assets/"); + if (!missingIntroTracksLogged_) { + LOG_WARNING("AuthScreen: No login intro tracks found in assets/"); + missingIntroTracksLogged_ = true; + } } } }