diff --git a/include/platform/process.hpp b/include/platform/process.hpp index 0fa9e981..5356b04b 100644 --- a/include/platform/process.hpp +++ b/include/platform/process.hpp @@ -92,8 +92,8 @@ inline ProcessHandle spawnProcess(const std::vector& args) { if (pid == 0) { // Child process setpgid(0, 0); - freopen("/dev/null", "w", stdout); - freopen("/dev/null", "w", stderr); + if (!freopen("/dev/null", "w", stdout)) { _exit(1); } + if (!freopen("/dev/null", "w", stderr)) { _exit(1); } // Build argv for exec std::vector argv; diff --git a/src/audio/activity_sound_manager.cpp b/src/audio/activity_sound_manager.cpp index 9ab37a2d..5b28d5c8 100644 --- a/src/audio/activity_sound_manager.cpp +++ b/src/audio/activity_sound_manager.cpp @@ -91,7 +91,7 @@ void ActivitySoundManager::shutdown() { assetManager = nullptr; } -void ActivitySoundManager::update(float deltaTime) { +void ActivitySoundManager::update([[maybe_unused]] float deltaTime) { reapProcesses(); // Play swimming stroke sounds periodically when swimming and moving @@ -168,7 +168,7 @@ void ActivitySoundManager::rebuildJumpClipsForProfile(const std::string& raceFol } } -void ActivitySoundManager::rebuildSwimLoopClipsForProfile(const std::string& raceFolder, const std::string& raceBase, bool male) { +void ActivitySoundManager::rebuildSwimLoopClipsForProfile([[maybe_unused]] const std::string& raceFolder, [[maybe_unused]] const std::string& raceBase, [[maybe_unused]] bool male) { swimLoopClips.clear(); // WoW 3.3.5a doesn't have dedicated swim loop sounds diff --git a/src/audio/ambient_sound_manager.cpp b/src/audio/ambient_sound_manager.cpp index f976cbdf..7ab88689 100644 --- a/src/audio/ambient_sound_manager.cpp +++ b/src/audio/ambient_sound_manager.cpp @@ -117,10 +117,10 @@ bool AmbientSoundManager::initialize(pipeline::AssetManager* assets) { bool forestNightLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\ForestNormalNight.wav", forestNormalNightSounds_[0], assets); forestSnowDaySounds_.resize(1); - bool forestSnowDayLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\ForestSnowDay.wav", forestSnowDaySounds_[0], assets); + loadSound("Sound\\Ambience\\ZoneAmbience\\ForestSnowDay.wav", forestSnowDaySounds_[0], assets); forestSnowNightSounds_.resize(1); - bool forestSnowNightLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\ForestSnowNight.wav", forestSnowNightSounds_[0], assets); + loadSound("Sound\\Ambience\\ZoneAmbience\\ForestSnowNight.wav", forestSnowNightSounds_[0], assets); beachDaySounds_.resize(1); bool beachDayLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\BeachDay.wav", beachDaySounds_[0], assets); @@ -129,34 +129,34 @@ bool AmbientSoundManager::initialize(pipeline::AssetManager* assets) { bool beachNightLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\BeachNight.wav", beachNightSounds_[0], assets); grasslandsDaySounds_.resize(1); - bool grasslandsDayLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\GrasslandsDay.wav", grasslandsDaySounds_[0], assets); + loadSound("Sound\\Ambience\\ZoneAmbience\\GrasslandsDay.wav", grasslandsDaySounds_[0], assets); grasslandsNightSounds_.resize(1); - bool grasslandsNightLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\GrassLandsNight.wav", grasslandsNightSounds_[0], assets); + loadSound("Sound\\Ambience\\ZoneAmbience\\GrassLandsNight.wav", grasslandsNightSounds_[0], assets); jungleDaySounds_.resize(1); - bool jungleDayLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\JungleDay.wav", jungleDaySounds_[0], assets); + loadSound("Sound\\Ambience\\ZoneAmbience\\JungleDay.wav", jungleDaySounds_[0], assets); jungleNightSounds_.resize(1); - bool jungleNightLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\JungleNight.wav", jungleNightSounds_[0], assets); + loadSound("Sound\\Ambience\\ZoneAmbience\\JungleNight.wav", jungleNightSounds_[0], assets); marshDaySounds_.resize(1); - bool marshDayLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\MarshDay.wav", marshDaySounds_[0], assets); + loadSound("Sound\\Ambience\\ZoneAmbience\\MarshDay.wav", marshDaySounds_[0], assets); marshNightSounds_.resize(1); - bool marshNightLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\MarshNight.wav", marshNightSounds_[0], assets); + loadSound("Sound\\Ambience\\ZoneAmbience\\MarshNight.wav", marshNightSounds_[0], assets); desertCanyonDaySounds_.resize(1); bool desertCanyonDayLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\CanyonDesertDay.wav", desertCanyonDaySounds_[0], assets); desertCanyonNightSounds_.resize(1); - bool desertCanyonNightLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\CanyonDesertNight.wav", desertCanyonNightSounds_[0], assets); + loadSound("Sound\\Ambience\\ZoneAmbience\\CanyonDesertNight.wav", desertCanyonNightSounds_[0], assets); desertPlainsDaySounds_.resize(1); bool desertPlainsDayLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\PlainsDesertDay.wav", desertPlainsDaySounds_[0], assets); desertPlainsNightSounds_.resize(1); - bool desertPlainsNightLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\PlainsDesertNight.wav", desertPlainsNightSounds_[0], assets); + loadSound("Sound\\Ambience\\ZoneAmbience\\PlainsDesertNight.wav", desertPlainsNightSounds_[0], assets); // Load city ambience sounds (day and night where available) stormwindDaySounds_.resize(1); @@ -169,10 +169,10 @@ bool AmbientSoundManager::initialize(pipeline::AssetManager* assets) { bool ironforgeLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\Ironforge.wav", ironforgeSounds_[0], assets); darnassusDaySounds_.resize(1); - bool darnassusDayLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\DarnassusDay.wav", darnassusDaySounds_[0], assets); + loadSound("Sound\\Ambience\\WMOAmbience\\DarnassusDay.wav", darnassusDaySounds_[0], assets); darnassusNightSounds_.resize(1); - bool darnassusNightLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\DarnassusNight.wav", darnassusNightSounds_[0], assets); + loadSound("Sound\\Ambience\\WMOAmbience\\DarnassusNight.wav", darnassusNightSounds_[0], assets); orgrimmarDaySounds_.resize(1); bool orgrimmarDayLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\OrgrimmarDay.wav", orgrimmarDaySounds_[0], assets); @@ -181,13 +181,13 @@ bool AmbientSoundManager::initialize(pipeline::AssetManager* assets) { bool orgrimmarNightLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\OrgrimmarNight.wav", orgrimmarNightSounds_[0], assets); undercitySounds_.resize(1); - bool undercityLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\Undercity.wav", undercitySounds_[0], assets); + loadSound("Sound\\Ambience\\WMOAmbience\\Undercity.wav", undercitySounds_[0], assets); thunderbluffDaySounds_.resize(1); - bool thunderbluffDayLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\ThunderBluffDay.wav", thunderbluffDaySounds_[0], assets); + loadSound("Sound\\Ambience\\WMOAmbience\\ThunderBluffDay.wav", thunderbluffDaySounds_[0], assets); thunderbluffNightSounds_.resize(1); - bool thunderbluffNightLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\ThunderBluffNight.wav", thunderbluffNightSounds_[0], assets); + loadSound("Sound\\Ambience\\WMOAmbience\\ThunderBluffNight.wav", thunderbluffNightSounds_[0], assets); // Load bell toll sounds bellAllianceSounds_.resize(1); diff --git a/src/audio/combat_sound_manager.cpp b/src/audio/combat_sound_manager.cpp index d433a40c..55352459 100644 --- a/src/audio/combat_sound_manager.cpp +++ b/src/audio/combat_sound_manager.cpp @@ -295,7 +295,7 @@ void CombatSoundManager::playWeaponMiss(bool twoHanded) { } } -void CombatSoundManager::playImpact(WeaponSize weaponSize, ImpactType impactType, bool isCrit) { +void CombatSoundManager::playImpact([[maybe_unused]] WeaponSize weaponSize, ImpactType impactType, bool isCrit) { // Select appropriate impact sound library const std::vector* normalLibrary = nullptr; const std::vector* critLibrary = nullptr; diff --git a/src/audio/ui_sound_manager.cpp b/src/audio/ui_sound_manager.cpp index 626263d3..f50f1d6f 100644 --- a/src/audio/ui_sound_manager.cpp +++ b/src/audio/ui_sound_manager.cpp @@ -34,16 +34,16 @@ bool UiSoundManager::initialize(pipeline::AssetManager* assets) { bool charSheetCloseLoaded = loadSound("Sound\\Interface\\iAbilitiesCloseA.wav", characterSheetCloseSounds_[0], assets); auctionOpenSounds_.resize(1); - bool auctionOpenLoaded = loadSound("Sound\\Interface\\AuctionWindowOpen.wav", auctionOpenSounds_[0], assets); + loadSound("Sound\\Interface\\AuctionWindowOpen.wav", auctionOpenSounds_[0], assets); auctionCloseSounds_.resize(1); - bool auctionCloseLoaded = loadSound("Sound\\Interface\\AuctionWindowClose.wav", auctionCloseSounds_[0], assets); + loadSound("Sound\\Interface\\AuctionWindowClose.wav", auctionCloseSounds_[0], assets); guildBankOpenSounds_.resize(1); - bool guildBankOpenLoaded = loadSound("Sound\\Interface\\GuildVaultOpen.wav", guildBankOpenSounds_[0], assets); + loadSound("Sound\\Interface\\GuildVaultOpen.wav", guildBankOpenSounds_[0], assets); guildBankCloseSounds_.resize(1); - bool guildBankCloseLoaded = loadSound("Sound\\Interface\\GuildVaultClose.wav", guildBankCloseSounds_[0], assets); + loadSound("Sound\\Interface\\GuildVaultClose.wav", guildBankCloseSounds_[0], assets); // Load button sounds buttonClickSounds_.resize(1); @@ -63,7 +63,7 @@ bool UiSoundManager::initialize(pipeline::AssetManager* assets) { bool questFailedLoaded = loadSound("Sound\\Interface\\igQuestFailed.wav", questFailedSounds_[0], assets); questUpdateSounds_.resize(1); - bool questUpdateLoaded = loadSound("Sound\\Interface\\iQuestUpdate.wav", questUpdateSounds_[0], assets); + loadSound("Sound\\Interface\\iQuestUpdate.wav", questUpdateSounds_[0], assets); // Load loot sounds lootCoinSmallSounds_.resize(1); @@ -86,13 +86,13 @@ bool UiSoundManager::initialize(pipeline::AssetManager* assets) { bool pickupBookLoaded = loadSound("Sound\\Interface\\PickUp\\PickUpBook.wav", pickupBookSounds_[0], assets); pickupClothSounds_.resize(1); - bool pickupClothLoaded = loadSound("Sound\\Interface\\PickUp\\PickUpCloth_Leather01.wav", pickupClothSounds_[0], assets); + loadSound("Sound\\Interface\\PickUp\\PickUpCloth_Leather01.wav", pickupClothSounds_[0], assets); pickupFoodSounds_.resize(1); - bool pickupFoodLoaded = loadSound("Sound\\Interface\\PickUp\\PickUpFoodGeneric.wav", pickupFoodSounds_[0], assets); + loadSound("Sound\\Interface\\PickUp\\PickUpFoodGeneric.wav", pickupFoodSounds_[0], assets); pickupGemSounds_.resize(1); - bool pickupGemLoaded = loadSound("Sound\\Interface\\PickUp\\PickUpGems.wav", pickupGemSounds_[0], assets); + loadSound("Sound\\Interface\\PickUp\\PickUpGems.wav", pickupGemSounds_[0], assets); // Load eating/drinking sounds eatingSounds_.resize(1); @@ -107,13 +107,13 @@ bool UiSoundManager::initialize(pipeline::AssetManager* assets) { // Load error/feedback sounds errorSounds_.resize(1); - bool errorLoaded = loadSound("Sound\\Interface\\Error.wav", errorSounds_[0], assets); + loadSound("Sound\\Interface\\Error.wav", errorSounds_[0], assets); selectTargetSounds_.resize(1); - bool selectTargetLoaded = loadSound("Sound\\Interface\\iSelectTarget.wav", selectTargetSounds_[0], assets); + loadSound("Sound\\Interface\\iSelectTarget.wav", selectTargetSounds_[0], assets); deselectTargetSounds_.resize(1); - bool deselectTargetLoaded = loadSound("Sound\\Interface\\iDeselectTarget.wav", deselectTargetSounds_[0], assets); + loadSound("Sound\\Interface\\iDeselectTarget.wav", deselectTargetSounds_[0], assets); LOG_INFO("UISoundManager: Window sounds - Bag: ", (bagOpenLoaded && bagCloseLoaded) ? "YES" : "NO", ", QuestLog: ", (questLogOpenLoaded && questLogCloseLoaded) ? "YES" : "NO", diff --git a/src/game/warden_emulator.cpp b/src/game/warden_emulator.cpp index 11ff861f..1d43768b 100644 --- a/src/game/warden_emulator.cpp +++ b/src/game/warden_emulator.cpp @@ -122,7 +122,7 @@ bool WardenEmulator::initialize(const void* moduleCode, size_t moduleSize, uint3 uint32_t WardenEmulator::hookAPI(const std::string& dllName, const std::string& functionName, - std::function&)> handler) { + [[maybe_unused]] std::function&)> handler) { // Allocate address for this API stub static uint32_t nextStubAddr = API_STUB_BASE; uint32_t stubAddr = nextStubAddr; @@ -239,7 +239,7 @@ std::string WardenEmulator::readString(uint32_t address, size_t maxLen) { return std::string(buffer.data()); } -uint32_t WardenEmulator::allocateMemory(size_t size, uint32_t protection) { +uint32_t WardenEmulator::allocateMemory(size_t size, [[maybe_unused]] uint32_t protection) { // Align to 4KB size = (size + 0xFFF) & ~0xFFF; @@ -315,7 +315,7 @@ uint32_t WardenEmulator::apiVirtualFree(WardenEmulator& emu, const std::vector& args) { +uint32_t WardenEmulator::apiGetTickCount([[maybe_unused]] WardenEmulator& emu, [[maybe_unused]] const std::vector& args) { auto now = std::chrono::steady_clock::now(); auto ms = std::chrono::duration_cast(now.time_since_epoch()).count(); uint32_t ticks = static_cast(ms & 0xFFFFFFFF); @@ -324,7 +324,7 @@ uint32_t WardenEmulator::apiGetTickCount(WardenEmulator& emu, const std::vector< return ticks; } -uint32_t WardenEmulator::apiSleep(WardenEmulator& emu, const std::vector& args) { +uint32_t WardenEmulator::apiSleep([[maybe_unused]] WardenEmulator& emu, const std::vector& args) { if (args.size() < 1) return 0; uint32_t dwMilliseconds = args[0]; @@ -333,12 +333,12 @@ uint32_t WardenEmulator::apiSleep(WardenEmulator& emu, const std::vector& args) { +uint32_t WardenEmulator::apiGetCurrentThreadId([[maybe_unused]] WardenEmulator& emu, [[maybe_unused]] const std::vector& args) { std::cout << "[WinAPI] GetCurrentThreadId() = 1234" << '\n'; return 1234; // Fake thread ID } -uint32_t WardenEmulator::apiGetCurrentProcessId(WardenEmulator& emu, const std::vector& args) { +uint32_t WardenEmulator::apiGetCurrentProcessId([[maybe_unused]] WardenEmulator& emu, [[maybe_unused]] const std::vector& args) { std::cout << "[WinAPI] GetCurrentProcessId() = 5678" << '\n'; return 5678; // Fake process ID } @@ -347,7 +347,7 @@ uint32_t WardenEmulator::apiReadProcessMemory(WardenEmulator& emu, const std::ve // ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead) if (args.size() < 5) return 0; - uint32_t hProcess = args[0]; + [[maybe_unused]] uint32_t hProcess = args[0]; uint32_t lpBaseAddress = args[1]; uint32_t lpBuffer = args[2]; uint32_t nSize = args[3]; @@ -377,13 +377,11 @@ uint32_t WardenEmulator::apiReadProcessMemory(WardenEmulator& emu, const std::ve // Unicorn Callbacks // ============================================================================ -void WardenEmulator::hookCode(uc_engine* uc, uint64_t address, uint32_t size, void* userData) { - WardenEmulator* emu = static_cast(userData); +void WardenEmulator::hookCode([[maybe_unused]] uc_engine* uc, uint64_t address, [[maybe_unused]] uint32_t size, [[maybe_unused]] void* userData) { 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) { - WardenEmulator* emu = static_cast(userData); +void WardenEmulator::hookMemInvalid([[maybe_unused]] uc_engine* uc, int type, uint64_t address, int size, [[maybe_unused]] int64_t value, [[maybe_unused]] void* userData) { const char* typeStr = "UNKNOWN"; switch (type) { diff --git a/src/game/warden_module.cpp b/src/game/warden_module.cpp index fba39960..bad36430 100644 --- a/src/game/warden_module.cpp +++ b/src/game/warden_module.cpp @@ -129,7 +129,7 @@ bool WardenModule::load(const std::vector& moduleData, } bool WardenModule::processCheckRequest(const std::vector& checkData, - std::vector& responseOut) { + [[maybe_unused]] std::vector& responseOut) { if (!loaded_) { std::cerr << "[WardenModule] Module not loaded, cannot process checks" << '\n'; return false; @@ -198,7 +198,7 @@ bool WardenModule::processCheckRequest(const std::vector& checkData, return false; } -uint32_t WardenModule::tick(uint32_t deltaMs) { +uint32_t WardenModule::tick([[maybe_unused]] uint32_t deltaMs) { if (!loaded_ || !funcList_.tick) { return 0; // No tick needed } @@ -209,7 +209,7 @@ uint32_t WardenModule::tick(uint32_t deltaMs) { return 0; } -void WardenModule::generateRC4Keys(uint8_t* packet) { +void WardenModule::generateRC4Keys([[maybe_unused]] uint8_t* packet) { if (!loaded_ || !funcList_.generateRC4Keys) { return; } @@ -633,9 +633,11 @@ bool WardenModule::applyRelocations() { currentOffset += delta; if (currentOffset + 4 <= moduleSize_) { - uint32_t* ptr = reinterpret_cast( - static_cast(moduleMemory_) + currentOffset); - *ptr += moduleBase_; + uint8_t* addr = static_cast(moduleMemory_) + currentOffset; + uint32_t val; + std::memcpy(&val, addr, sizeof(uint32_t)); + val += moduleBase_; + std::memcpy(addr, &val, sizeof(uint32_t)); relocCount++; } else { std::cerr << "[WardenModule] Relocation offset " << currentOffset @@ -755,16 +757,16 @@ bool WardenModule::initializeModule() { void (*logMessage)(const char* msg); }; - // Setup client callbacks - ClientCallbacks callbacks = {}; + // Setup client callbacks (used when calling module entry point below) + [[maybe_unused]] ClientCallbacks callbacks = {}; // Stub callbacks (would need real implementations) - callbacks.sendPacket = [](uint8_t* data, size_t len) { + callbacks.sendPacket = []([[maybe_unused]] uint8_t* data, size_t len) { std::cout << "[WardenModule Callback] sendPacket(" << len << " bytes)" << '\n'; // TODO: Send CMSG_WARDEN_DATA packet }; - callbacks.validateModule = [](uint8_t* hash) { + callbacks.validateModule = []([[maybe_unused]] uint8_t* hash) { std::cout << "[WardenModule Callback] validateModule()" << '\n'; // TODO: Validate module hash }; @@ -779,7 +781,7 @@ bool WardenModule::initializeModule() { free(ptr); }; - callbacks.generateRC4 = [](uint8_t* seed) { + callbacks.generateRC4 = []([[maybe_unused]] uint8_t* seed) { std::cout << "[WardenModule Callback] generateRC4()" << '\n'; // TODO: Re-key RC4 cipher }; diff --git a/src/pipeline/blp_loader.cpp b/src/pipeline/blp_loader.cpp index e0df4639..8c817890 100644 --- a/src/pipeline/blp_loader.cpp +++ b/src/pipeline/blp_loader.cpp @@ -30,34 +30,39 @@ BLPImage BLPLoader::load(const std::vector& blpData) { } BLPImage BLPLoader::loadBLP1(const uint8_t* data, size_t size) { - // BLP1 header has all uint32 fields (different layout from BLP2) - const BLP1Header* header = reinterpret_cast(data); + // Copy header to stack to avoid unaligned reinterpret_cast (UB on strict platforms) + if (size < sizeof(BLP1Header)) { + LOG_ERROR("BLP1 data too small for header"); + return BLPImage(); + } + BLP1Header header; + std::memcpy(&header, data, sizeof(BLP1Header)); BLPImage image; image.format = BLPFormat::BLP1; - image.width = header->width; - image.height = header->height; + image.width = header.width; + image.height = header.height; image.channels = 4; - image.mipLevels = header->hasMips ? 16 : 1; + image.mipLevels = header.hasMips ? 16 : 1; // BLP1 compression: 0=JPEG (not used in WoW), 1=palette/indexed // BLP1 does NOT support DXT — only palette with optional alpha - if (header->compression == 1) { + if (header.compression == 1) { image.compression = BLPCompression::PALETTE; - } else if (header->compression == 0) { + } else if (header.compression == 0) { LOG_WARNING("BLP1 JPEG compression not supported"); return BLPImage(); } else { - LOG_WARNING("BLP1 unknown compression: ", header->compression); + LOG_WARNING("BLP1 unknown compression: ", header.compression); return BLPImage(); } LOG_DEBUG("Loading BLP1: ", image.width, "x", image.height, " ", - getCompressionName(image.compression), " alpha=", header->alphaBits); + getCompressionName(image.compression), " alpha=", header.alphaBits); // Get first mipmap (full resolution) - uint32_t offset = header->mipOffsets[0]; - uint32_t mipSize = header->mipSizes[0]; + uint32_t offset = header.mipOffsets[0]; + uint32_t mipSize = header.mipSizes[0]; if (offset + mipSize > size) { LOG_ERROR("BLP1 mipmap data out of bounds (offset=", offset, " size=", mipSize, " fileSize=", size, ")"); @@ -70,45 +75,50 @@ BLPImage BLPLoader::loadBLP1(const uint8_t* data, size_t size) { int pixelCount = image.width * image.height; image.data.resize(pixelCount * 4); // RGBA8 - decompressPalette(mipData, image.data.data(), header->palette, - image.width, image.height, static_cast(header->alphaBits)); + decompressPalette(mipData, image.data.data(), header.palette, + image.width, image.height, static_cast(header.alphaBits)); return image; } BLPImage BLPLoader::loadBLP2(const uint8_t* data, size_t size) { - // BLP2 header has uint8 fields for compression/alpha/encoding - const BLP2Header* header = reinterpret_cast(data); + // Copy header to stack to avoid unaligned reinterpret_cast (UB on strict platforms) + if (size < sizeof(BLP2Header)) { + LOG_ERROR("BLP2 data too small for header"); + return BLPImage(); + } + BLP2Header header; + std::memcpy(&header, data, sizeof(BLP2Header)); BLPImage image; image.format = BLPFormat::BLP2; - image.width = header->width; - image.height = header->height; + image.width = header.width; + image.height = header.height; image.channels = 4; - image.mipLevels = header->hasMips ? 16 : 1; + image.mipLevels = header.hasMips ? 16 : 1; // BLP2 compression types: // 1 = palette/uncompressed // 2 = DXTC (DXT1/DXT3/DXT5 based on alphaDepth + alphaEncoding) // 3 = plain A8R8G8B8 - if (header->compression == 1) { + if (header.compression == 1) { image.compression = BLPCompression::PALETTE; - } else if (header->compression == 2) { + } else if (header.compression == 2) { // BLP2 DXTC format selection based on alphaDepth + alphaEncoding: // alphaDepth=0 → DXT1 (no alpha) // alphaDepth>0, alphaEncoding=0 → DXT1 (1-bit alpha) // alphaDepth>0, alphaEncoding=1 → DXT3 (explicit 4-bit alpha) // alphaDepth>0, alphaEncoding=7 → DXT5 (interpolated alpha) - if (header->alphaDepth == 0 || header->alphaEncoding == 0) { + if (header.alphaDepth == 0 || header.alphaEncoding == 0) { image.compression = BLPCompression::DXT1; - } else if (header->alphaEncoding == 1) { + } else if (header.alphaEncoding == 1) { image.compression = BLPCompression::DXT3; - } else if (header->alphaEncoding == 7) { + } else if (header.alphaEncoding == 7) { image.compression = BLPCompression::DXT5; } else { image.compression = BLPCompression::DXT1; } - } else if (header->compression == 3) { + } else if (header.compression == 3) { image.compression = BLPCompression::ARGB8888; } else { image.compression = BLPCompression::ARGB8888; @@ -116,13 +126,13 @@ BLPImage BLPLoader::loadBLP2(const uint8_t* data, size_t size) { LOG_DEBUG("Loading BLP2: ", image.width, "x", image.height, " ", getCompressionName(image.compression), - " (comp=", (int)header->compression, " alphaDepth=", (int)header->alphaDepth, - " alphaEnc=", (int)header->alphaEncoding, " mipOfs=", header->mipOffsets[0], - " mipSize=", header->mipSizes[0], ")"); + " (comp=", (int)header.compression, " alphaDepth=", (int)header.alphaDepth, + " alphaEnc=", (int)header.alphaEncoding, " mipOfs=", header.mipOffsets[0], + " mipSize=", header.mipSizes[0], ")"); // Get first mipmap (full resolution) - uint32_t offset = header->mipOffsets[0]; - uint32_t mipSize = header->mipSizes[0]; + uint32_t offset = header.mipOffsets[0]; + uint32_t mipSize = header.mipSizes[0]; if (offset + mipSize > size) { LOG_ERROR("BLP2 mipmap data out of bounds"); @@ -149,8 +159,8 @@ BLPImage BLPLoader::loadBLP2(const uint8_t* data, size_t size) { break; case BLPCompression::PALETTE: - decompressPalette(mipData, image.data.data(), header->palette, - image.width, image.height, header->alphaDepth); + decompressPalette(mipData, image.data.data(), header.palette, + image.width, image.height, header.alphaDepth); break; case BLPCompression::ARGB8888: diff --git a/src/pipeline/dbc_loader.cpp b/src/pipeline/dbc_loader.cpp index dd1d6f52..f7e040da 100644 --- a/src/pipeline/dbc_loader.cpp +++ b/src/pipeline/dbc_loader.cpp @@ -42,19 +42,20 @@ bool DBCFile::load(const std::vector& dbcData) { return false; } - // Read header - const DBCHeader* header = reinterpret_cast(dbcData.data()); + // Read header safely (avoid unaligned reinterpret_cast — UB on strict platforms) + DBCHeader header; + std::memcpy(&header, dbcData.data(), sizeof(DBCHeader)); // Verify magic - if (std::memcmp(header->magic, "WDBC", 4) != 0) { - LOG_ERROR("Invalid DBC magic: ", std::string(header->magic, 4)); + if (std::memcmp(header.magic, "WDBC", 4) != 0) { + LOG_ERROR("Invalid DBC magic: ", std::string(header.magic, 4)); return false; } - recordCount = header->recordCount; - fieldCount = header->fieldCount; - recordSize = header->recordSize; - stringBlockSize = header->stringBlockSize; + recordCount = header.recordCount; + fieldCount = header.fieldCount; + recordSize = header.recordSize; + stringBlockSize = header.stringBlockSize; // Validate sizes uint32_t expectedSize = sizeof(DBCHeader) + (recordCount * recordSize) + stringBlockSize; @@ -111,8 +112,9 @@ uint32_t DBCFile::getUInt32(uint32_t recordIndex, uint32_t fieldIndex) const { return 0; } - const uint32_t* field = reinterpret_cast(record + (fieldIndex * 4)); - return *field; + uint32_t value; + std::memcpy(&value, record + (fieldIndex * 4), sizeof(uint32_t)); + return value; } int32_t DBCFile::getInt32(uint32_t recordIndex, uint32_t fieldIndex) const { @@ -129,8 +131,9 @@ float DBCFile::getFloat(uint32_t recordIndex, uint32_t fieldIndex) const { return 0.0f; } - const float* field = reinterpret_cast(record + (fieldIndex * 4)); - return *field; + float value; + std::memcpy(&value, record + (fieldIndex * 4), sizeof(float)); + return value; } std::string DBCFile::getString(uint32_t recordIndex, uint32_t fieldIndex) const { diff --git a/src/pipeline/m2_loader.cpp b/src/pipeline/m2_loader.cpp index fc4cf6ae..b3d057d6 100644 --- a/src/pipeline/m2_loader.cpp +++ b/src/pipeline/m2_loader.cpp @@ -1456,9 +1456,7 @@ bool M2Loader::loadSkin(const std::vector& skinData, M2Model& model) { if (header.nSubmeshes > 0 && header.ofsSubmeshes > 0) { submeshes = readArray(skinData, header.ofsSubmeshes, header.nSubmeshes); core::Logger::getInstance().debug(" Submeshes: ", submeshes.size()); - for (size_t i = 0; i < submeshes.size(); i++) { - const auto& sm = submeshes[i]; - } + (void)submeshes; } // Read batches with proper submesh references diff --git a/src/rendering/character_renderer.cpp b/src/rendering/character_renderer.cpp index 522f6a48..33ff425a 100644 --- a/src/rendering/character_renderer.cpp +++ b/src/rendering/character_renderer.cpp @@ -1610,7 +1610,7 @@ glm::mat4 CharacterRenderer::getBoneTransform(const pipeline::M2Bone& bone, floa // --- Rendering --- -void CharacterRenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const Camera& camera) { +void CharacterRenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, [[maybe_unused]] const Camera& camera) { if (instances.empty() || !opaquePipeline_) { return; } diff --git a/src/rendering/vk_render_target.cpp b/src/rendering/vk_render_target.cpp index 48e3a50e..f2099bbf 100644 --- a/src/rendering/vk_render_target.cpp +++ b/src/rendering/vk_render_target.cpp @@ -19,7 +19,7 @@ bool VkRenderTarget::create(VkContext& ctx, uint32_t width, uint32_t height, // Create color image (multisampled if MSAA) colorImage_ = createImage(device, allocator, width, height, format, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | (useMSAA ? VkImageUsageFlags(0) : VK_IMAGE_USAGE_SAMPLED_BIT), + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | (useMSAA ? static_cast(0) : static_cast(VK_IMAGE_USAGE_SAMPLED_BIT)), msaaSamples); if (!colorImage_.image) {