diff --git a/include/core/logger.hpp b/include/core/logger.hpp index 967df38d..f8873a82 100644 --- a/include/core/logger.hpp +++ b/include/core/logger.hpp @@ -74,6 +74,7 @@ private: std::mutex mutex; std::ofstream fileStream; bool fileReady = false; + bool echoToStdout_ = true; std::chrono::steady_clock::time_point lastFlushTime_{}; uint32_t flushIntervalMs_ = 250; void ensureFile(); diff --git a/include/network/packet.hpp b/include/network/packet.hpp index 4171fbad..fbfb85bf 100644 --- a/include/network/packet.hpp +++ b/include/network/packet.hpp @@ -12,6 +12,7 @@ public: Packet() = default; explicit Packet(uint16_t opcode); Packet(uint16_t opcode, const std::vector& data); + Packet(uint16_t opcode, std::vector&& data); void writeUInt8(uint8_t value); void writeUInt16(uint16_t value); diff --git a/src/core/logger.cpp b/src/core/logger.cpp index f58770dc..23d4ba5a 100644 --- a/src/core/logger.cpp +++ b/src/core/logger.cpp @@ -16,6 +16,11 @@ Logger& Logger::getInstance() { void Logger::ensureFile() { if (fileReady) return; fileReady = true; + if (const char* logStdout = std::getenv("WOWEE_LOG_STDOUT")) { + if (logStdout[0] == '0') { + echoToStdout_ = false; + } + } if (const char* flushMs = std::getenv("WOWEE_LOG_FLUSH_MS")) { char* end = nullptr; unsigned long parsed = std::strtoul(flushMs, &end, 10); @@ -67,7 +72,9 @@ void Logger::log(LogLevel level, const std::string& message) { line << "] " << message; - std::cout << line.str() << '\n'; + if (echoToStdout_) { + std::cout << line.str() << '\n'; + } if (fileStream.is_open()) { fileStream << line.str() << '\n'; bool shouldFlush = (level >= LogLevel::WARNING); diff --git a/src/network/packet.cpp b/src/network/packet.cpp index 7c8b55a3..d82469b9 100644 --- a/src/network/packet.cpp +++ b/src/network/packet.cpp @@ -1,5 +1,6 @@ #include "network/packet.hpp" #include +#include namespace wowee { namespace network { @@ -9,6 +10,9 @@ Packet::Packet(uint16_t opcode) : opcode(opcode) {} Packet::Packet(uint16_t opcode, const std::vector& data) : opcode(opcode), data(data), readPos(0) {} +Packet::Packet(uint16_t opcode, std::vector&& data) + : opcode(opcode), data(std::move(data)), readPos(0) {} + void Packet::writeUInt8(uint8_t value) { data.push_back(value); } diff --git a/src/network/world_socket.cpp b/src/network/world_socket.cpp index fcee6a92..349eea7f 100644 --- a/src/network/world_socket.cpp +++ b/src/network/world_socket.cpp @@ -325,27 +325,31 @@ void WorldSocket::update() { void WorldSocket::tryParsePackets() { // World server packets have 4-byte incoming header: size(2) + opcode(2) int parsedThisTick = 0; - while (receiveBuffer.size() >= 4 && parsedThisTick < kMaxParsedPacketsPerUpdate) { + size_t parseOffset = 0; + size_t localHeaderBytesDecrypted = headerBytesDecrypted; + std::vector parsedPackets; + parsedPackets.reserve(32); + while ((receiveBuffer.size() - parseOffset) >= 4 && parsedThisTick < kMaxParsedPacketsPerUpdate) { uint8_t rawHeader[4] = {0, 0, 0, 0}; - std::memcpy(rawHeader, receiveBuffer.data(), 4); + std::memcpy(rawHeader, receiveBuffer.data() + parseOffset, 4); // Decrypt header bytes in-place if encryption is enabled // Only decrypt bytes we haven't already decrypted - if (encryptionEnabled && headerBytesDecrypted < 4) { - size_t toDecrypt = 4 - headerBytesDecrypted; + if (encryptionEnabled && localHeaderBytesDecrypted < 4) { + size_t toDecrypt = 4 - localHeaderBytesDecrypted; if (useVanillaCrypt) { - vanillaCrypt.decrypt(receiveBuffer.data() + headerBytesDecrypted, toDecrypt); + vanillaCrypt.decrypt(receiveBuffer.data() + parseOffset + localHeaderBytesDecrypted, toDecrypt); } else { - decryptCipher.process(receiveBuffer.data() + headerBytesDecrypted, toDecrypt); + decryptCipher.process(receiveBuffer.data() + parseOffset + localHeaderBytesDecrypted, toDecrypt); } - headerBytesDecrypted = 4; + localHeaderBytesDecrypted = 4; } // Parse header (now decrypted in-place). // Size: 2 bytes big-endian. For world packets, this includes opcode bytes. - uint16_t size = (receiveBuffer[0] << 8) | receiveBuffer[1]; + uint16_t size = (receiveBuffer[parseOffset + 0] << 8) | receiveBuffer[parseOffset + 1]; // Opcode: 2 bytes little-endian. - uint16_t opcode = receiveBuffer[2] | (receiveBuffer[3] << 8); + uint16_t opcode = receiveBuffer[parseOffset + 2] | (receiveBuffer[parseOffset + 3] << 8); if (size < 2) { LOG_ERROR("World packet framing desync: invalid size=", size, " rawHdr=", std::hex, @@ -381,45 +385,50 @@ void WorldSocket::tryParsePackets() { static_cast(rawHeader[2]), " ", static_cast(rawHeader[3]), " dec=", - static_cast(receiveBuffer[0]), " ", - static_cast(receiveBuffer[1]), " ", - static_cast(receiveBuffer[2]), " ", - static_cast(receiveBuffer[3]), + static_cast(receiveBuffer[parseOffset + 0]), " ", + static_cast(receiveBuffer[parseOffset + 1]), " ", + static_cast(receiveBuffer[parseOffset + 2]), " ", + static_cast(receiveBuffer[parseOffset + 3]), std::dec, " size=", size, " payload=", payloadLen, " opcode=0x", std::hex, opcode, std::dec, - " buffered=", receiveBuffer.size()); + " buffered=", (receiveBuffer.size() - parseOffset)); --headerTracePacketsLeft; } if (isLoginPipelineSmsg(opcode)) { LOG_INFO("WS RX LOGIN opcode=0x", std::hex, opcode, std::dec, " size=", size, " payload=", payloadLen, - " buffered=", receiveBuffer.size(), + " buffered=", (receiveBuffer.size() - parseOffset), " enc=", encryptionEnabled ? "yes" : "no"); } - if (receiveBuffer.size() < totalSize) { + if ((receiveBuffer.size() - parseOffset) < totalSize) { // Not enough data yet - header stays decrypted in buffer break; } // Extract payload (skip header) - std::vector packetData(receiveBuffer.begin() + 4, - receiveBuffer.begin() + totalSize); + std::vector packetData(receiveBuffer.begin() + parseOffset + 4, + receiveBuffer.begin() + parseOffset + totalSize); - // Create packet with opcode and payload - Packet packet(opcode, packetData); + // Queue packet; callbacks run after buffer state is finalized. + parsedPackets.emplace_back(opcode, std::move(packetData)); + parseOffset += totalSize; + localHeaderBytesDecrypted = 0; + ++parsedThisTick; + } - // Remove parsed data from buffer and reset header decryption counter - receiveBuffer.erase(receiveBuffer.begin(), receiveBuffer.begin() + totalSize); - headerBytesDecrypted = 0; + if (parseOffset > 0) { + receiveBuffer.erase(receiveBuffer.begin(), receiveBuffer.begin() + parseOffset); + } + headerBytesDecrypted = localHeaderBytesDecrypted; - // Call callback if set - if (packetCallback) { + if (packetCallback) { + for (const auto& packet : parsedPackets) { + if (!connected) break; packetCallback(packet); } - ++parsedThisTick; } if (parsedThisTick >= kMaxParsedPacketsPerUpdate && receiveBuffer.size() >= 4) {