diff --git a/CMakeLists.txt b/CMakeLists.txt index a3a8c7cb..19051b55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -384,6 +384,20 @@ else() target_compile_options(wowee PRIVATE -Wall -Wextra -Wpedantic) endif() +# Release build optimizations +include(CheckIPOSupported) +check_ipo_supported(RESULT _ipo_supported OUTPUT _ipo_error) +if(_ipo_supported) + set_property(TARGET wowee PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) +endif() +if(NOT MSVC) + # -O3: more aggressive inlining and auto-vectorization vs CMake's default -O2 + target_compile_options(wowee PRIVATE $<$:-O3>) + # -fvisibility=hidden: keeps all symbols internal by default, shrinks binary + # and gives the linker and optimizer more freedom to dead-strip and inline + target_compile_options(wowee PRIVATE $<$:-fvisibility=hidden -fvisibility-inlines-hidden>) +endif() + # Copy assets to build directory file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/assets DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) diff --git a/include/rendering/scene.hpp b/include/rendering/scene.hpp index 6c4bc92b..9f640b06 100644 --- a/include/rendering/scene.hpp +++ b/include/rendering/scene.hpp @@ -14,7 +14,7 @@ public: ~Scene() = default; void addMesh(std::shared_ptr mesh); - void removeMesh(std::shared_ptr mesh); + void removeMesh(const std::shared_ptr& mesh); void clear(); const std::vector>& getMeshes() const { return meshes; } diff --git a/src/game/entity.cpp b/src/game/entity.cpp index 0f51723c..add06327 100644 --- a/src/game/entity.cpp +++ b/src/game/entity.cpp @@ -10,7 +10,7 @@ void EntityManager::addEntity(uint64_t guid, std::shared_ptr entity) { return; } - entities[guid] = entity; + entities[guid] = std::move(entity); LOG_DEBUG("Added entity: GUID=0x", std::hex, guid, std::dec, ", Type=", static_cast(entity->getType())); diff --git a/src/game/warden_emulator.cpp b/src/game/warden_emulator.cpp index 9e204cad..11ff861f 100644 --- a/src/game/warden_emulator.cpp +++ b/src/game/warden_emulator.cpp @@ -41,17 +41,17 @@ WardenEmulator::~WardenEmulator() { bool WardenEmulator::initialize(const void* moduleCode, size_t moduleSize, uint32_t baseAddress) { if (uc_) { - std::cerr << "[WardenEmulator] Already initialized" << std::endl; + std::cerr << "[WardenEmulator] Already initialized" << '\n'; return false; } - std::cout << "[WardenEmulator] Initializing x86 emulator (Unicorn Engine)" << std::endl; - std::cout << "[WardenEmulator] Module: " << moduleSize << " bytes at 0x" << std::hex << baseAddress << std::dec << std::endl; + std::cout << "[WardenEmulator] Initializing x86 emulator (Unicorn Engine)" << '\n'; + std::cout << "[WardenEmulator] Module: " << moduleSize << " bytes at 0x" << std::hex << baseAddress << std::dec << '\n'; // Create x86 32-bit emulator uc_err err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc_); if (err != UC_ERR_OK) { - std::cerr << "[WardenEmulator] uc_open failed: " << uc_strerror(err) << std::endl; + std::cerr << "[WardenEmulator] uc_open failed: " << uc_strerror(err) << '\n'; return false; } @@ -61,7 +61,7 @@ bool WardenEmulator::initialize(const void* moduleCode, size_t moduleSize, uint3 // Map module memory (code + data) err = uc_mem_map(uc_, moduleBase_, moduleSize_, UC_PROT_ALL); if (err != UC_ERR_OK) { - std::cerr << "[WardenEmulator] Failed to map module memory: " << uc_strerror(err) << std::endl; + std::cerr << "[WardenEmulator] Failed to map module memory: " << uc_strerror(err) << '\n'; uc_close(uc_); uc_ = nullptr; return false; @@ -70,7 +70,7 @@ bool WardenEmulator::initialize(const void* moduleCode, size_t moduleSize, uint3 // Write module code to emulated memory err = uc_mem_write(uc_, moduleBase_, moduleCode, moduleSize); if (err != UC_ERR_OK) { - std::cerr << "[WardenEmulator] Failed to write module code: " << uc_strerror(err) << std::endl; + std::cerr << "[WardenEmulator] Failed to write module code: " << uc_strerror(err) << '\n'; uc_close(uc_); uc_ = nullptr; return false; @@ -79,7 +79,7 @@ bool WardenEmulator::initialize(const void* moduleCode, size_t moduleSize, uint3 // Map stack err = uc_mem_map(uc_, stackBase_, stackSize_, UC_PROT_READ | UC_PROT_WRITE); if (err != UC_ERR_OK) { - std::cerr << "[WardenEmulator] Failed to map stack: " << uc_strerror(err) << std::endl; + std::cerr << "[WardenEmulator] Failed to map stack: " << uc_strerror(err) << '\n'; uc_close(uc_); uc_ = nullptr; return false; @@ -93,7 +93,7 @@ bool WardenEmulator::initialize(const void* moduleCode, size_t moduleSize, uint3 // Map heap err = uc_mem_map(uc_, heapBase_, heapSize_, UC_PROT_READ | UC_PROT_WRITE); if (err != UC_ERR_OK) { - std::cerr << "[WardenEmulator] Failed to map heap: " << uc_strerror(err) << std::endl; + std::cerr << "[WardenEmulator] Failed to map heap: " << uc_strerror(err) << '\n'; uc_close(uc_); uc_ = nullptr; return false; @@ -102,7 +102,7 @@ bool WardenEmulator::initialize(const void* moduleCode, size_t moduleSize, uint3 // Map API stub area err = uc_mem_map(uc_, apiStubBase_, 0x10000, UC_PROT_ALL); if (err != UC_ERR_OK) { - std::cerr << "[WardenEmulator] Failed to map API stub area: " << uc_strerror(err) << std::endl; + std::cerr << "[WardenEmulator] Failed to map API stub area: " << uc_strerror(err) << '\n'; uc_close(uc_); uc_ = nullptr; return false; @@ -113,9 +113,9 @@ bool WardenEmulator::initialize(const void* moduleCode, size_t moduleSize, uint3 uc_hook_add(uc_, &hh, UC_HOOK_MEM_INVALID, (void*)hookMemInvalid, this, 1, 0); hooks_.push_back(hh); - std::cout << "[WardenEmulator] ✓ Emulator initialized successfully" << std::endl; - std::cout << "[WardenEmulator] Stack: 0x" << std::hex << stackBase_ << " - 0x" << (stackBase_ + stackSize_) << std::endl; - std::cout << "[WardenEmulator] Heap: 0x" << heapBase_ << " - 0x" << (heapBase_ + heapSize_) << std::dec << std::endl; + std::cout << "[WardenEmulator] ✓ Emulator initialized successfully" << '\n'; + std::cout << "[WardenEmulator] Stack: 0x" << std::hex << stackBase_ << " - 0x" << (stackBase_ + stackSize_) << '\n'; + std::cout << "[WardenEmulator] Heap: 0x" << heapBase_ << " - 0x" << (heapBase_ + heapSize_) << std::dec << '\n'; return true; } @@ -132,7 +132,7 @@ uint32_t WardenEmulator::hookAPI(const std::string& dllName, apiAddresses_[dllName][functionName] = stubAddr; std::cout << "[WardenEmulator] Hooked " << dllName << "!" << functionName - << " at 0x" << std::hex << stubAddr << std::dec << std::endl; + << " at 0x" << std::hex << stubAddr << std::dec << '\n'; // TODO: Write stub code that triggers a hook callback // For now, just return the address for IAT patching @@ -141,7 +141,7 @@ uint32_t WardenEmulator::hookAPI(const std::string& dllName, } void WardenEmulator::setupCommonAPIHooks() { - std::cout << "[WardenEmulator] Setting up common Windows API hooks..." << std::endl; + std::cout << "[WardenEmulator] Setting up common Windows API hooks..." << '\n'; // kernel32.dll hookAPI("kernel32.dll", "VirtualAlloc", apiVirtualAlloc); @@ -152,7 +152,7 @@ void WardenEmulator::setupCommonAPIHooks() { hookAPI("kernel32.dll", "GetCurrentProcessId", apiGetCurrentProcessId); hookAPI("kernel32.dll", "ReadProcessMemory", apiReadProcessMemory); - std::cout << "[WardenEmulator] ✓ Common API hooks registered" << std::endl; + std::cout << "[WardenEmulator] ✓ Common API hooks registered" << '\n'; } uint32_t WardenEmulator::writeData(const void* data, size_t size) { @@ -176,12 +176,12 @@ std::vector WardenEmulator::readData(uint32_t address, size_t size) { uint32_t WardenEmulator::callFunction(uint32_t address, const std::vector& args) { if (!uc_) { - std::cerr << "[WardenEmulator] Not initialized" << std::endl; + std::cerr << "[WardenEmulator] Not initialized" << '\n'; return 0; } std::cout << "[WardenEmulator] Calling function at 0x" << std::hex << address << std::dec - << " with " << args.size() << " args" << std::endl; + << " with " << args.size() << " args" << '\n'; // Get current ESP uint32_t esp; @@ -205,7 +205,7 @@ uint32_t WardenEmulator::callFunction(uint32_t address, const std::vector heapBase_ + heapSize_) { - std::cerr << "[WardenEmulator] Heap exhausted" << std::endl; + std::cerr << "[WardenEmulator] Heap exhausted" << '\n'; return 0; } @@ -253,7 +253,7 @@ uint32_t WardenEmulator::allocateMemory(size_t size, uint32_t protection) { allocations_[addr] = size; - std::cout << "[WardenEmulator] Allocated " << size << " bytes at 0x" << std::hex << addr << std::dec << std::endl; + std::cout << "[WardenEmulator] Allocated " << size << " bytes at 0x" << std::hex << addr << std::dec << '\n'; return addr; } @@ -261,11 +261,11 @@ uint32_t WardenEmulator::allocateMemory(size_t size, uint32_t protection) { bool WardenEmulator::freeMemory(uint32_t address) { auto it = allocations_.find(address); if (it == allocations_.end()) { - std::cerr << "[WardenEmulator] Invalid free at 0x" << std::hex << address << std::dec << std::endl; + std::cerr << "[WardenEmulator] Invalid free at 0x" << std::hex << address << std::dec << '\n'; return false; } - std::cout << "[WardenEmulator] Freed " << it->second << " bytes at 0x" << std::hex << address << std::dec << std::endl; + std::cout << "[WardenEmulator] Freed " << it->second << " bytes at 0x" << std::hex << address << std::dec << '\n'; allocations_.erase(it); return true; } @@ -298,7 +298,7 @@ uint32_t WardenEmulator::apiVirtualAlloc(WardenEmulator& emu, const std::vector< uint32_t flProtect = args[3]; std::cout << "[WinAPI] VirtualAlloc(0x" << std::hex << lpAddress << ", " << std::dec - << dwSize << ", 0x" << std::hex << flAllocationType << ", 0x" << flProtect << ")" << std::dec << std::endl; + << dwSize << ", 0x" << std::hex << flAllocationType << ", 0x" << flProtect << ")" << std::dec << '\n'; // Ignore lpAddress hint for now return emu.allocateMemory(dwSize, flProtect); @@ -310,7 +310,7 @@ uint32_t WardenEmulator::apiVirtualFree(WardenEmulator& emu, const std::vector(now.time_since_epoch()).count(); uint32_t ticks = static_cast(ms & 0xFFFFFFFF); - std::cout << "[WinAPI] GetTickCount() = " << ticks << std::endl; + std::cout << "[WinAPI] GetTickCount() = " << ticks << '\n'; return ticks; } @@ -328,18 +328,18 @@ uint32_t WardenEmulator::apiSleep(WardenEmulator& emu, const std::vector& args) { - std::cout << "[WinAPI] GetCurrentThreadId() = 1234" << std::endl; + std::cout << "[WinAPI] GetCurrentThreadId() = 1234" << '\n'; return 1234; // Fake thread ID } uint32_t WardenEmulator::apiGetCurrentProcessId(WardenEmulator& emu, const std::vector& args) { - std::cout << "[WinAPI] GetCurrentProcessId() = 5678" << std::endl; + std::cout << "[WinAPI] GetCurrentProcessId() = 5678" << '\n'; return 5678; // Fake process ID } @@ -354,7 +354,7 @@ uint32_t WardenEmulator::apiReadProcessMemory(WardenEmulator& emu, const std::ve uint32_t lpNumberOfBytesRead = args[4]; std::cout << "[WinAPI] ReadProcessMemory(0x" << std::hex << lpBaseAddress - << ", " << std::dec << nSize << " bytes)" << std::endl; + << ", " << std::dec << nSize << " bytes)" << '\n'; // Read from emulated memory and write to buffer std::vector data(nSize); @@ -379,7 +379,7 @@ uint32_t WardenEmulator::apiReadProcessMemory(WardenEmulator& emu, const std::ve void WardenEmulator::hookCode(uc_engine* uc, uint64_t address, uint32_t size, void* userData) { WardenEmulator* emu = static_cast(userData); - std::cout << "[Trace] 0x" << std::hex << address << std::dec << std::endl; + std::cout << "[Trace] 0x" << std::hex << address << std::dec << '\n'; } void WardenEmulator::hookMemInvalid(uc_engine* uc, int type, uint64_t address, int size, int64_t value, void* userData) { @@ -397,7 +397,7 @@ void WardenEmulator::hookMemInvalid(uc_engine* uc, int type, uint64_t address, i std::cerr << "[WardenEmulator] Invalid memory access: " << typeStr << " at 0x" << std::hex << address << std::dec - << " (size=" << size << ")" << std::endl; + << " (size=" << size << ")" << '\n'; } #else // !HAVE_UNICORN diff --git a/src/game/warden_module.cpp b/src/game/warden_module.cpp index c6e9fa78..8244165e 100644 --- a/src/game/warden_module.cpp +++ b/src/game/warden_module.cpp @@ -51,25 +51,25 @@ bool WardenModule::load(const std::vector& moduleData, for (size_t i = 0; i < std::min(md5Hash.size(), size_t(8)); ++i) { printf("%02X", md5Hash[i]); } - std::cout << "...)" << std::endl; + std::cout << "...)" << '\n'; // Step 1: Verify MD5 hash if (!verifyMD5(moduleData, md5Hash)) { - std::cerr << "[WardenModule] MD5 verification failed!" << std::endl; + std::cerr << "[WardenModule] MD5 verification failed!" << '\n'; return false; } - std::cout << "[WardenModule] ✓ MD5 verified" << std::endl; + std::cout << "[WardenModule] ✓ MD5 verified" << '\n'; // Step 2: RC4 decrypt if (!decryptRC4(moduleData, rc4Key, decryptedData_)) { - std::cerr << "[WardenModule] RC4 decryption failed!" << std::endl; + std::cerr << "[WardenModule] RC4 decryption failed!" << '\n'; return false; } - std::cout << "[WardenModule] ✓ RC4 decrypted (" << decryptedData_.size() << " bytes)" << std::endl; + std::cout << "[WardenModule] ✓ RC4 decrypted (" << decryptedData_.size() << " bytes)" << '\n'; // Step 3: Verify RSA signature if (!verifyRSASignature(decryptedData_)) { - std::cerr << "[WardenModule] RSA signature verification failed!" << std::endl; + std::cerr << "[WardenModule] RSA signature verification failed!" << '\n'; // Note: Currently returns true (skipping verification) due to placeholder modulus } @@ -81,31 +81,31 @@ bool WardenModule::load(const std::vector& moduleData, dataWithoutSig = decryptedData_; } if (!decompressZlib(dataWithoutSig, decompressedData_)) { - std::cerr << "[WardenModule] zlib decompression failed!" << std::endl; + std::cerr << "[WardenModule] zlib decompression failed!" << '\n'; return false; } // Step 5: Parse custom executable format if (!parseExecutableFormat(decompressedData_)) { - std::cerr << "[WardenModule] Executable format parsing failed!" << std::endl; + std::cerr << "[WardenModule] Executable format parsing failed!" << '\n'; return false; } // Step 6: Apply relocations if (!applyRelocations()) { - std::cerr << "[WardenModule] Address relocations failed!" << std::endl; + std::cerr << "[WardenModule] Address relocations failed!" << '\n'; return false; } // Step 7: Bind APIs if (!bindAPIs()) { - std::cerr << "[WardenModule] API binding failed!" << std::endl; + std::cerr << "[WardenModule] API binding failed!" << '\n'; // Note: Currently returns true (stub) on both Windows and Linux } // Step 8: Initialize module if (!initializeModule()) { - std::cerr << "[WardenModule] Module initialization failed!" << std::endl; + std::cerr << "[WardenModule] Module initialization failed!" << '\n'; return false; } @@ -113,13 +113,13 @@ bool WardenModule::load(const std::vector& moduleData, // Note: Steps 6-8 are stubs/platform-limited, but infrastructure is ready loaded_ = true; // Mark as loaded (infrastructure complete) - std::cout << "[WardenModule] ✓ Module loading pipeline COMPLETE" << std::endl; - std::cout << "[WardenModule] Status: Infrastructure ready, execution stubs in place" << std::endl; - std::cout << "[WardenModule] Limitations:" << std::endl; - std::cout << "[WardenModule] - Relocations: needs real module data" << std::endl; - std::cout << "[WardenModule] - API Binding: Windows only (or Wine on Linux)" << std::endl; - std::cout << "[WardenModule] - Execution: disabled (unsafe without validation)" << std::endl; - std::cout << "[WardenModule] For strict servers: Would need to enable actual x86 execution" << std::endl; + std::cout << "[WardenModule] ✓ Module loading pipeline COMPLETE" << '\n'; + std::cout << "[WardenModule] Status: Infrastructure ready, execution stubs in place" << '\n'; + std::cout << "[WardenModule] Limitations:" << '\n'; + std::cout << "[WardenModule] - Relocations: needs real module data" << '\n'; + std::cout << "[WardenModule] - API Binding: Windows only (or Wine on Linux)" << '\n'; + std::cout << "[WardenModule] - Execution: disabled (unsafe without validation)" << '\n'; + std::cout << "[WardenModule] For strict servers: Would need to enable actual x86 execution" << '\n'; return true; } @@ -127,25 +127,25 @@ bool WardenModule::load(const std::vector& moduleData, bool WardenModule::processCheckRequest(const std::vector& checkData, std::vector& responseOut) { if (!loaded_) { - std::cerr << "[WardenModule] Module not loaded, cannot process checks" << std::endl; + std::cerr << "[WardenModule] Module not loaded, cannot process checks" << '\n'; return false; } #ifdef HAVE_UNICORN if (emulator_ && emulator_->isInitialized() && funcList_.packetHandler) { - std::cout << "[WardenModule] Processing check request via emulator..." << std::endl; - std::cout << "[WardenModule] Check data: " << checkData.size() << " bytes" << std::endl; + std::cout << "[WardenModule] Processing check request via emulator..." << '\n'; + std::cout << "[WardenModule] Check data: " << checkData.size() << " bytes" << '\n'; // Allocate memory for check data in emulated space uint32_t checkDataAddr = emulator_->allocateMemory(checkData.size(), 0x04); if (checkDataAddr == 0) { - std::cerr << "[WardenModule] Failed to allocate memory for check data" << std::endl; + std::cerr << "[WardenModule] Failed to allocate memory for check data" << '\n'; return false; } // Write check data to emulated memory if (!emulator_->writeMemory(checkDataAddr, checkData.data(), checkData.size())) { - std::cerr << "[WardenModule] Failed to write check data" << std::endl; + std::cerr << "[WardenModule] Failed to write check data" << '\n'; emulator_->freeMemory(checkDataAddr); return false; } @@ -153,7 +153,7 @@ bool WardenModule::processCheckRequest(const std::vector& checkData, // Allocate response buffer in emulated space (assume max 1KB response) uint32_t responseAddr = emulator_->allocateMemory(1024, 0x04); if (responseAddr == 0) { - std::cerr << "[WardenModule] Failed to allocate response buffer" << std::endl; + std::cerr << "[WardenModule] Failed to allocate response buffer" << '\n'; emulator_->freeMemory(checkDataAddr); return false; } @@ -162,13 +162,13 @@ bool WardenModule::processCheckRequest(const std::vector& checkData, // Call module's PacketHandler // void PacketHandler(uint8_t* checkData, size_t checkSize, // uint8_t* responseOut, size_t* responseSizeOut) - std::cout << "[WardenModule] Calling PacketHandler..." << std::endl; + std::cout << "[WardenModule] Calling PacketHandler..." << '\n'; // For now, this is a placeholder - actual calling would depend on // the module's exact function signature - std::cout << "[WardenModule] ⚠ PacketHandler execution stubbed" << std::endl; - std::cout << "[WardenModule] Would call emulated function to process checks" << std::endl; - std::cout << "[WardenModule] This would generate REAL responses (not fakes!)" << std::endl; + std::cout << "[WardenModule] ⚠ PacketHandler execution stubbed" << '\n'; + std::cout << "[WardenModule] Would call emulated function to process checks" << '\n'; + std::cout << "[WardenModule] This would generate REAL responses (not fakes!)" << '\n'; // Clean up emulator_->freeMemory(checkDataAddr); @@ -179,7 +179,7 @@ bool WardenModule::processCheckRequest(const std::vector& checkData, return false; } catch (const std::exception& e) { - std::cerr << "[WardenModule] Exception during PacketHandler: " << e.what() << std::endl; + std::cerr << "[WardenModule] Exception during PacketHandler: " << e.what() << '\n'; emulator_->freeMemory(checkDataAddr); emulator_->freeMemory(responseAddr); return false; @@ -187,8 +187,8 @@ bool WardenModule::processCheckRequest(const std::vector& checkData, } #endif - std::cout << "[WardenModule] ⚠ processCheckRequest NOT IMPLEMENTED" << std::endl; - std::cout << "[WardenModule] Would call module->PacketHandler() here" << std::endl; + std::cout << "[WardenModule] ⚠ processCheckRequest NOT IMPLEMENTED" << '\n'; + std::cout << "[WardenModule] Would call module->PacketHandler() here" << '\n'; // For now, return false to fall back to fake responses in GameHandler return false; @@ -219,13 +219,13 @@ void WardenModule::unload() { if (moduleMemory_) { // Call module's Unload() function if loaded if (loaded_ && funcList_.unload) { - std::cout << "[WardenModule] Calling module unload callback..." << std::endl; + std::cout << "[WardenModule] Calling module unload callback..." << '\n'; // TODO: Implement callback when execution layer is complete // funcList_.unload(nullptr); } // Free executable memory region - std::cout << "[WardenModule] Freeing " << moduleSize_ << " bytes of executable memory" << std::endl; + std::cout << "[WardenModule] Freeing " << moduleSize_ << " bytes of executable memory" << '\n'; #ifdef _WIN32 VirtualFree(moduleMemory_, 0, MEM_RELEASE); #else @@ -264,7 +264,7 @@ bool WardenModule::decryptRC4(const std::vector& encrypted, const std::vector& key, std::vector& decryptedOut) { if (key.size() != 16) { - std::cerr << "[WardenModule] Invalid RC4 key size: " << key.size() << " (expected 16)" << std::endl; + std::cerr << "[WardenModule] Invalid RC4 key size: " << key.size() << " (expected 16)" << '\n'; return false; } @@ -299,7 +299,7 @@ bool WardenModule::decryptRC4(const std::vector& encrypted, bool WardenModule::verifyRSASignature(const std::vector& data) { // RSA-2048 signature is last 256 bytes if (data.size() < 256) { - std::cerr << "[WardenModule] Data too small for RSA signature (need at least 256 bytes)" << std::endl; + std::cerr << "[WardenModule] Data too small for RSA signature (need at least 256 bytes)" << '\n'; return false; } @@ -345,7 +345,7 @@ bool WardenModule::verifyRSASignature(const std::vector& data) { // Create RSA public key structure RSA* rsa = RSA_new(); if (!rsa) { - std::cerr << "[WardenModule] Failed to create RSA structure" << std::endl; + std::cerr << "[WardenModule] Failed to create RSA structure" << '\n'; return false; } @@ -375,7 +375,7 @@ bool WardenModule::verifyRSASignature(const std::vector& data) { RSA_free(rsa); if (decryptedLen < 0) { - std::cerr << "[WardenModule] RSA public decrypt failed" << std::endl; + std::cerr << "[WardenModule] RSA public decrypt failed" << '\n'; return false; } @@ -388,24 +388,24 @@ bool WardenModule::verifyRSASignature(const std::vector& data) { std::vector actualHash(decryptedSig.end() - 20, decryptedSig.end()); if (std::memcmp(actualHash.data(), expectedHash.data(), 20) == 0) { - std::cout << "[WardenModule] ✓ RSA signature verified" << std::endl; + std::cout << "[WardenModule] ✓ RSA signature verified" << '\n'; return true; } } - std::cerr << "[WardenModule] RSA signature verification FAILED (hash mismatch)" << std::endl; - std::cerr << "[WardenModule] NOTE: Using placeholder modulus - extract real modulus from WoW.exe for actual verification" << std::endl; + std::cerr << "[WardenModule] RSA signature verification FAILED (hash mismatch)" << '\n'; + std::cerr << "[WardenModule] NOTE: Using placeholder modulus - extract real modulus from WoW.exe for actual verification" << '\n'; // For development, return true to proceed (since we don't have real modulus) // TODO: Set to false once real modulus is extracted - std::cout << "[WardenModule] ⚠ Skipping RSA verification (placeholder modulus)" << std::endl; + std::cout << "[WardenModule] ⚠ Skipping RSA verification (placeholder modulus)" << '\n'; return true; // TEMPORARY - change to false for production } bool WardenModule::decompressZlib(const std::vector& compressed, std::vector& decompressedOut) { if (compressed.size() < 4) { - std::cerr << "[WardenModule] Compressed data too small (need at least 4 bytes for size header)" << std::endl; + std::cerr << "[WardenModule] Compressed data too small (need at least 4 bytes for size header)" << '\n'; return false; } @@ -416,11 +416,11 @@ bool WardenModule::decompressZlib(const std::vector& compressed, (compressed[2] << 16) | (compressed[3] << 24); - std::cout << "[WardenModule] Uncompressed size: " << uncompressedSize << " bytes" << std::endl; + std::cout << "[WardenModule] Uncompressed size: " << uncompressedSize << " bytes" << '\n'; // Sanity check (modules shouldn't be larger than 10MB) if (uncompressedSize > 10 * 1024 * 1024) { - std::cerr << "[WardenModule] Uncompressed size suspiciously large: " << uncompressedSize << " bytes" << std::endl; + std::cerr << "[WardenModule] Uncompressed size suspiciously large: " << uncompressedSize << " bytes" << '\n'; return false; } @@ -437,7 +437,7 @@ bool WardenModule::decompressZlib(const std::vector& compressed, // Initialize inflater int ret = inflateInit(&stream); if (ret != Z_OK) { - std::cerr << "[WardenModule] inflateInit failed: " << ret << std::endl; + std::cerr << "[WardenModule] inflateInit failed: " << ret << '\n'; return false; } @@ -448,19 +448,19 @@ bool WardenModule::decompressZlib(const std::vector& compressed, inflateEnd(&stream); if (ret != Z_STREAM_END) { - std::cerr << "[WardenModule] inflate failed: " << ret << std::endl; + std::cerr << "[WardenModule] inflate failed: " << ret << '\n'; return false; } std::cout << "[WardenModule] ✓ zlib decompression successful (" - << stream.total_out << " bytes decompressed)" << std::endl; + << stream.total_out << " bytes decompressed)" << '\n'; return true; } bool WardenModule::parseExecutableFormat(const std::vector& exeData) { if (exeData.size() < 4) { - std::cerr << "[WardenModule] Executable data too small for header" << std::endl; + std::cerr << "[WardenModule] Executable data too small for header" << '\n'; return false; } @@ -471,11 +471,11 @@ bool WardenModule::parseExecutableFormat(const std::vector& exeData) { (exeData[2] << 16) | (exeData[3] << 24); - std::cout << "[WardenModule] Final code size: " << finalCodeSize << " bytes" << std::endl; + std::cout << "[WardenModule] Final code size: " << finalCodeSize << " bytes" << '\n'; // Sanity check (executable shouldn't be larger than 5MB) if (finalCodeSize > 5 * 1024 * 1024 || finalCodeSize == 0) { - std::cerr << "[WardenModule] Invalid final code size: " << finalCodeSize << std::endl; + std::cerr << "[WardenModule] Invalid final code size: " << finalCodeSize << '\n'; return false; } @@ -490,7 +490,7 @@ bool WardenModule::parseExecutableFormat(const std::vector& exeData) { PAGE_EXECUTE_READWRITE ); if (!moduleMemory_) { - std::cerr << "[WardenModule] VirtualAlloc failed" << std::endl; + std::cerr << "[WardenModule] VirtualAlloc failed" << '\n'; return false; } #else @@ -503,7 +503,7 @@ bool WardenModule::parseExecutableFormat(const std::vector& exeData) { 0 ); if (moduleMemory_ == MAP_FAILED) { - std::cerr << "[WardenModule] mmap failed: " << strerror(errno) << std::endl; + std::cerr << "[WardenModule] mmap failed: " << strerror(errno) << '\n'; moduleMemory_ = nullptr; return false; } @@ -513,7 +513,7 @@ bool WardenModule::parseExecutableFormat(const std::vector& exeData) { std::memset(moduleMemory_, 0, moduleSize_); // Zero-initialize std::cout << "[WardenModule] Allocated " << moduleSize_ << " bytes of executable memory at " - << moduleMemory_ << std::endl; + << moduleMemory_ << '\n'; // Parse skip/copy pairs // Format: repeated [2B skip_count][2B copy_count][copy_count bytes data] @@ -537,7 +537,7 @@ bool WardenModule::parseExecutableFormat(const std::vector& exeData) { // Read copy count (2 bytes LE) if (pos + 2 > exeData.size()) { - std::cerr << "[WardenModule] Unexpected end of data reading copy count" << std::endl; + std::cerr << "[WardenModule] Unexpected end of data reading copy count" << '\n'; break; } uint16_t copyCount = exeData[pos] | (exeData[pos + 1] << 8); @@ -545,7 +545,7 @@ bool WardenModule::parseExecutableFormat(const std::vector& exeData) { if (copyCount > 0) { if (pos + copyCount > exeData.size()) { - std::cerr << "[WardenModule] Copy section extends beyond data bounds" << std::endl; + std::cerr << "[WardenModule] Copy section extends beyond data bounds" << '\n'; #ifdef _WIN32 VirtualFree(moduleMemory_, 0, MEM_RELEASE); #else @@ -556,7 +556,7 @@ bool WardenModule::parseExecutableFormat(const std::vector& exeData) { } if (destOffset + copyCount > moduleSize_) { - std::cerr << "[WardenModule] Copy section exceeds module size" << std::endl; + std::cerr << "[WardenModule] Copy section exceeds module size" << '\n'; #ifdef _WIN32 VirtualFree(moduleMemory_, 0, MEM_RELEASE); #else @@ -577,23 +577,23 @@ bool WardenModule::parseExecutableFormat(const std::vector& exeData) { pairCount++; std::cout << "[WardenModule] Pair " << pairCount << ": skip " << skipCount - << ", copy " << copyCount << " (dest offset=" << destOffset << ")" << std::endl; + << ", copy " << copyCount << " (dest offset=" << destOffset << ")" << '\n'; } // Save position — remaining decompressed data contains relocation entries relocDataOffset_ = pos; std::cout << "[WardenModule] Parsed " << pairCount << " skip/copy pairs, final offset: " - << destOffset << "/" << finalCodeSize << std::endl; + << destOffset << "/" << finalCodeSize << '\n'; std::cout << "[WardenModule] Relocation data starts at decompressed offset " << relocDataOffset_ - << " (" << (exeData.size() - relocDataOffset_) << " bytes remaining)" << std::endl; + << " (" << (exeData.size() - relocDataOffset_) << " bytes remaining)" << '\n'; return true; } bool WardenModule::applyRelocations() { if (!moduleMemory_ || moduleSize_ == 0) { - std::cerr << "[WardenModule] No module memory allocated for relocations" << std::endl; + std::cerr << "[WardenModule] No module memory allocated for relocations" << '\n'; return false; } @@ -602,7 +602,7 @@ bool WardenModule::applyRelocations() { // Each offset in the module image has moduleBase_ added to the 32-bit value there if (relocDataOffset_ == 0 || relocDataOffset_ >= decompressedData_.size()) { - std::cout << "[WardenModule] No relocation data available" << std::endl; + std::cout << "[WardenModule] No relocation data available" << '\n'; return true; } @@ -625,23 +625,23 @@ bool WardenModule::applyRelocations() { relocCount++; } else { std::cerr << "[WardenModule] Relocation offset " << currentOffset - << " out of bounds (moduleSize=" << moduleSize_ << ")" << std::endl; + << " out of bounds (moduleSize=" << moduleSize_ << ")" << '\n'; } } std::cout << "[WardenModule] Applied " << relocCount << " relocations (base=0x" - << std::hex << moduleBase_ << std::dec << ")" << std::endl; + << std::hex << moduleBase_ << std::dec << ")" << '\n'; return true; } bool WardenModule::bindAPIs() { if (!moduleMemory_ || moduleSize_ == 0) { - std::cerr << "[WardenModule] No module memory allocated for API binding" << std::endl; + std::cerr << "[WardenModule] No module memory allocated for API binding" << '\n'; return false; } - std::cout << "[WardenModule] Binding Windows APIs for module..." << std::endl; + std::cout << "[WardenModule] Binding Windows APIs for module..." << '\n'; // Common Windows APIs used by Warden modules: // @@ -661,14 +661,14 @@ bool WardenModule::bindAPIs() { #ifdef _WIN32 // On Windows: Use GetProcAddress to resolve imports - std::cout << "[WardenModule] Platform: Windows - using GetProcAddress" << std::endl; + std::cout << "[WardenModule] Platform: Windows - using GetProcAddress" << '\n'; HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); HMODULE user32 = GetModuleHandleA("user32.dll"); HMODULE ntdll = GetModuleHandleA("ntdll.dll"); if (!kernel32 || !user32 || !ntdll) { - std::cerr << "[WardenModule] Failed to get module handles" << std::endl; + std::cerr << "[WardenModule] Failed to get module handles" << '\n'; return false; } @@ -679,8 +679,8 @@ bool WardenModule::bindAPIs() { // - Resolve address using GetProcAddress // - Write address to Import Address Table (IAT) - std::cout << "[WardenModule] ⚠ Windows API binding is STUB (needs PE import table parsing)" << std::endl; - std::cout << "[WardenModule] Would parse PE headers and patch IAT with resolved addresses" << std::endl; + std::cout << "[WardenModule] ⚠ Windows API binding is STUB (needs PE import table parsing)" << '\n'; + std::cout << "[WardenModule] Would parse PE headers and patch IAT with resolved addresses" << '\n'; #else // On Linux: Cannot directly execute Windows code @@ -689,15 +689,15 @@ bool WardenModule::bindAPIs() { // 2. Implement Windows API stubs (limited functionality) // 3. Use binfmt_misc + Wine (transparent Windows executable support) - std::cout << "[WardenModule] Platform: Linux - Windows module execution NOT supported" << std::endl; - std::cout << "[WardenModule] Options:" << std::endl; - std::cout << "[WardenModule] 1. Run wowee under Wine (provides Windows API layer)" << std::endl; - std::cout << "[WardenModule] 2. Use a Windows VM" << std::endl; - std::cout << "[WardenModule] 3. Implement Windows API stubs (limited, complex)" << std::endl; + std::cout << "[WardenModule] Platform: Linux - Windows module execution NOT supported" << '\n'; + std::cout << "[WardenModule] Options:" << '\n'; + std::cout << "[WardenModule] 1. Run wowee under Wine (provides Windows API layer)" << '\n'; + std::cout << "[WardenModule] 2. Use a Windows VM" << '\n'; + std::cout << "[WardenModule] 3. Implement Windows API stubs (limited, complex)" << '\n'; // For now, we'll return true to continue the loading pipeline // Real execution would fail, but this allows testing the infrastructure - std::cout << "[WardenModule] ⚠ Skipping API binding (Linux platform limitation)" << std::endl; + std::cout << "[WardenModule] ⚠ Skipping API binding (Linux platform limitation)" << '\n'; #endif return true; // Return true to continue (stub implementation) @@ -705,11 +705,11 @@ bool WardenModule::bindAPIs() { bool WardenModule::initializeModule() { if (!moduleMemory_ || moduleSize_ == 0) { - std::cerr << "[WardenModule] No module memory allocated for initialization" << std::endl; + std::cerr << "[WardenModule] No module memory allocated for initialization" << '\n'; return false; } - std::cout << "[WardenModule] Initializing Warden module..." << std::endl; + std::cout << "[WardenModule] Initializing Warden module..." << '\n'; // Module initialization protocol: // @@ -746,27 +746,27 @@ bool WardenModule::initializeModule() { // Stub callbacks (would need real implementations) callbacks.sendPacket = [](uint8_t* data, size_t len) { - std::cout << "[WardenModule Callback] sendPacket(" << len << " bytes)" << std::endl; + std::cout << "[WardenModule Callback] sendPacket(" << len << " bytes)" << '\n'; // TODO: Send CMSG_WARDEN_DATA packet }; callbacks.validateModule = [](uint8_t* hash) { - std::cout << "[WardenModule Callback] validateModule()" << std::endl; + std::cout << "[WardenModule Callback] validateModule()" << '\n'; // TODO: Validate module hash }; callbacks.allocMemory = [](size_t size) -> void* { - std::cout << "[WardenModule Callback] allocMemory(" << size << ")" << std::endl; + std::cout << "[WardenModule Callback] allocMemory(" << size << ")" << '\n'; return malloc(size); }; callbacks.freeMemory = [](void* ptr) { - std::cout << "[WardenModule Callback] freeMemory()" << std::endl; + std::cout << "[WardenModule Callback] freeMemory()" << '\n'; free(ptr); }; callbacks.generateRC4 = [](uint8_t* seed) { - std::cout << "[WardenModule Callback] generateRC4()" << std::endl; + std::cout << "[WardenModule Callback] generateRC4()" << '\n'; // TODO: Re-key RC4 cipher }; @@ -775,7 +775,7 @@ bool WardenModule::initializeModule() { }; callbacks.logMessage = [](const char* msg) { - std::cout << "[WardenModule Log] " << msg << std::endl; + std::cout << "[WardenModule Log] " << msg << '\n'; }; // Module entry point is typically at offset 0 (first bytes of loaded code) @@ -783,24 +783,24 @@ bool WardenModule::initializeModule() { #ifdef HAVE_UNICORN // Use Unicorn emulator for cross-platform execution - std::cout << "[WardenModule] Initializing Unicorn emulator..." << std::endl; + std::cout << "[WardenModule] Initializing Unicorn emulator..." << '\n'; emulator_ = std::make_unique(); if (!emulator_->initialize(moduleMemory_, moduleSize_, moduleBase_)) { - std::cerr << "[WardenModule] Failed to initialize emulator" << std::endl; + std::cerr << "[WardenModule] Failed to initialize emulator" << '\n'; return false; } // Setup Windows API hooks emulator_->setupCommonAPIHooks(); - std::cout << "[WardenModule] ✓ Emulator initialized successfully" << std::endl; - std::cout << "[WardenModule] Ready to execute module at 0x" << std::hex << moduleBase_ << std::dec << std::endl; + std::cout << "[WardenModule] ✓ Emulator initialized successfully" << '\n'; + std::cout << "[WardenModule] Ready to execute module at 0x" << std::hex << moduleBase_ << std::dec << '\n'; // Allocate memory for ClientCallbacks structure in emulated space uint32_t callbackStructAddr = emulator_->allocateMemory(sizeof(ClientCallbacks), 0x04); if (callbackStructAddr == 0) { - std::cerr << "[WardenModule] Failed to allocate memory for callbacks" << std::endl; + std::cerr << "[WardenModule] Failed to allocate memory for callbacks" << '\n'; return false; } @@ -823,13 +823,13 @@ bool WardenModule::initializeModule() { emulator_->writeMemory(callbackStructAddr + (i * 4), &addr, 4); } - std::cout << "[WardenModule] Prepared ClientCallbacks at 0x" << std::hex << callbackStructAddr << std::dec << std::endl; + std::cout << "[WardenModule] Prepared ClientCallbacks at 0x" << std::hex << callbackStructAddr << std::dec << '\n'; // Call module entry point // Entry point is typically at module base (offset 0) uint32_t entryPoint = moduleBase_; - std::cout << "[WardenModule] Calling module entry point at 0x" << std::hex << entryPoint << std::dec << std::endl; + std::cout << "[WardenModule] Calling module entry point at 0x" << std::hex << entryPoint << std::dec << '\n'; try { // Call: WardenFuncList* InitModule(ClientCallbacks* callbacks) @@ -837,21 +837,21 @@ bool WardenModule::initializeModule() { uint32_t result = emulator_->callFunction(entryPoint, args); if (result == 0) { - std::cerr << "[WardenModule] Module entry returned NULL" << std::endl; + std::cerr << "[WardenModule] Module entry returned NULL" << '\n'; return false; } - std::cout << "[WardenModule] ✓ Module initialized, WardenFuncList at 0x" << std::hex << result << std::dec << std::endl; + std::cout << "[WardenModule] ✓ Module initialized, WardenFuncList at 0x" << std::hex << result << std::dec << '\n'; // Read WardenFuncList structure from emulated memory // Structure has 4 function pointers (16 bytes) uint32_t funcAddrs[4] = {}; if (emulator_->readMemory(result, funcAddrs, 16)) { - std::cout << "[WardenModule] Module exported functions:" << std::endl; - std::cout << "[WardenModule] generateRC4Keys: 0x" << std::hex << funcAddrs[0] << std::dec << std::endl; - std::cout << "[WardenModule] unload: 0x" << std::hex << funcAddrs[1] << std::dec << std::endl; - std::cout << "[WardenModule] packetHandler: 0x" << std::hex << funcAddrs[2] << std::dec << std::endl; - std::cout << "[WardenModule] tick: 0x" << std::hex << funcAddrs[3] << std::dec << std::endl; + std::cout << "[WardenModule] Module exported functions:" << '\n'; + std::cout << "[WardenModule] generateRC4Keys: 0x" << std::hex << funcAddrs[0] << std::dec << '\n'; + std::cout << "[WardenModule] unload: 0x" << std::hex << funcAddrs[1] << std::dec << '\n'; + std::cout << "[WardenModule] packetHandler: 0x" << std::hex << funcAddrs[2] << std::dec << '\n'; + std::cout << "[WardenModule] tick: 0x" << std::hex << funcAddrs[3] << std::dec << '\n'; // Store function addresses for later use // funcList_.generateRC4Keys = ... (would wrap emulator calls) @@ -860,10 +860,10 @@ bool WardenModule::initializeModule() { // funcList_.tick = ... } - std::cout << "[WardenModule] ✓ Module fully initialized and ready!" << std::endl; + std::cout << "[WardenModule] ✓ Module fully initialized and ready!" << '\n'; } catch (const std::exception& e) { - std::cerr << "[WardenModule] Exception during module initialization: " << e.what() << std::endl; + std::cerr << "[WardenModule] Exception during module initialization: " << e.what() << '\n'; return false; } @@ -872,14 +872,14 @@ bool WardenModule::initializeModule() { typedef void* (*ModuleEntryPoint)(ClientCallbacks*); ModuleEntryPoint entryPoint = reinterpret_cast(moduleMemory_); - std::cout << "[WardenModule] Calling module entry point at " << moduleMemory_ << std::endl; + std::cout << "[WardenModule] Calling module entry point at " << moduleMemory_ << '\n'; // NOTE: This would execute native x86 code // Extremely dangerous without proper validation! // void* result = entryPoint(&callbacks); - std::cout << "[WardenModule] ⚠ Module entry point call is DISABLED (unsafe without validation)" << std::endl; - std::cout << "[WardenModule] Would execute x86 code at " << moduleMemory_ << std::endl; + std::cout << "[WardenModule] ⚠ Module entry point call is DISABLED (unsafe without validation)" << '\n'; + std::cout << "[WardenModule] Would execute x86 code at " << moduleMemory_ << '\n'; // TODO: Extract WardenFuncList from result // funcList_.packetHandler = ... @@ -888,9 +888,9 @@ bool WardenModule::initializeModule() { // funcList_.unload = ... #else - std::cout << "[WardenModule] ⚠ Cannot execute Windows x86 code on Linux" << std::endl; - std::cout << "[WardenModule] Module entry point: " << moduleMemory_ << std::endl; - std::cout << "[WardenModule] Would call entry point with ClientCallbacks struct" << std::endl; + std::cout << "[WardenModule] ⚠ Cannot execute Windows x86 code on Linux" << '\n'; + std::cout << "[WardenModule] Module entry point: " << moduleMemory_ << '\n'; + std::cout << "[WardenModule] Would call entry point with ClientCallbacks struct" << '\n'; #endif // For now, return true to mark module as "loaded" at infrastructure level @@ -900,7 +900,7 @@ bool WardenModule::initializeModule() { // 3. Exception handling for crashes // 4. Sandboxing for security - std::cout << "[WardenModule] ⚠ Module initialization is STUB" << std::endl; + std::cout << "[WardenModule] ⚠ Module initialization is STUB" << '\n'; return true; // Stub implementation } @@ -925,7 +925,7 @@ WardenModuleManager::WardenModuleManager() { // Create cache directory if it doesn't exist std::filesystem::create_directories(cacheDirectory_); - std::cout << "[WardenModuleManager] Cache directory: " << cacheDirectory_ << std::endl; + std::cout << "[WardenModuleManager] Cache directory: " << cacheDirectory_ << '\n'; } WardenModuleManager::~WardenModuleManager() { @@ -963,11 +963,11 @@ bool WardenModuleManager::receiveModuleChunk(const std::vector& md5Hash buffer.insert(buffer.end(), chunkData.begin(), chunkData.end()); std::cout << "[WardenModuleManager] Received chunk (" << chunkData.size() - << " bytes, total: " << buffer.size() << ")" << std::endl; + << " bytes, total: " << buffer.size() << ")" << '\n'; if (isComplete) { std::cout << "[WardenModuleManager] Module download complete (" - << buffer.size() << " bytes)" << std::endl; + << buffer.size() << " bytes)" << '\n'; // Cache to disk cacheModule(md5Hash, buffer); @@ -987,14 +987,14 @@ bool WardenModuleManager::cacheModule(const std::vector& md5Hash, std::ofstream file(cachePath, std::ios::binary); if (!file) { - std::cerr << "[WardenModuleManager] Failed to write cache: " << cachePath << std::endl; + std::cerr << "[WardenModuleManager] Failed to write cache: " << cachePath << '\n'; return false; } file.write(reinterpret_cast(moduleData.data()), moduleData.size()); file.close(); - std::cout << "[WardenModuleManager] Cached module to: " << cachePath << std::endl; + std::cout << "[WardenModuleManager] Cached module to: " << cachePath << '\n'; return true; } @@ -1018,7 +1018,7 @@ bool WardenModuleManager::loadCachedModule(const std::vector& md5Hash, file.read(reinterpret_cast(moduleDataOut.data()), fileSize); file.close(); - std::cout << "[WardenModuleManager] Loaded cached module (" << fileSize << " bytes)" << std::endl; + std::cout << "[WardenModuleManager] Loaded cached module (" << fileSize << " bytes)" << '\n'; return true; } diff --git a/src/rendering/clouds.cpp b/src/rendering/clouds.cpp index ee3a9f2f..f7864083 100644 --- a/src/rendering/clouds.cpp +++ b/src/rendering/clouds.cpp @@ -182,13 +182,13 @@ void Clouds::generateMesh() { // Generate hemisphere mesh for clouds for (int ring = 0; ring <= RINGS; ++ring) { float phi = (ring / static_cast(RINGS)) * (M_PI * 0.5f); // 0 to π/2 - float y = RADIUS * cos(phi); - float ringRadius = RADIUS * sin(phi); + float y = RADIUS * cosf(phi); + float ringRadius = RADIUS * sinf(phi); for (int segment = 0; segment <= SEGMENTS; ++segment) { float theta = (segment / static_cast(SEGMENTS)) * (2.0f * M_PI); - float x = ringRadius * cos(theta); - float z = ringRadius * sin(theta); + float x = ringRadius * cosf(theta); + float z = ringRadius * sinf(theta); vertices.push_back(glm::vec3(x, y, z)); } diff --git a/src/rendering/scene.cpp b/src/rendering/scene.cpp index f0c29598..c10ad56d 100644 --- a/src/rendering/scene.cpp +++ b/src/rendering/scene.cpp @@ -6,10 +6,10 @@ namespace wowee { namespace rendering { void Scene::addMesh(std::shared_ptr mesh) { - meshes.push_back(mesh); + meshes.push_back(std::move(mesh)); } -void Scene::removeMesh(std::shared_ptr mesh) { +void Scene::removeMesh(const std::shared_ptr& mesh) { auto it = std::find(meshes.begin(), meshes.end(), mesh); if (it != meshes.end()) { meshes.erase(it); diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 6a5a0bf2..2469783d 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -5112,6 +5112,7 @@ void GameScreen::renderTrainerWindow(game::GameHandler& gameHandler) { } else { // Single tab or no categorization - flat list std::vector allSpells; + allSpells.reserve(trainer.spells.size()); for (const auto& spell : trainer.spells) { allSpells.push_back(&spell); }