diff --git a/src/audio/audio_engine.cpp b/src/audio/audio_engine.cpp index f15b161a..1b4d5aa3 100644 --- a/src/audio/audio_engine.cpp +++ b/src/audio/audio_engine.cpp @@ -98,8 +98,11 @@ static bool decodeWavCached(const std::vector& wavData, DecodedWavCache entry.sampleRate = sampleRate; entry.frames = framesRead; entry.pcmData = pcmData; - // Evict oldest half when cache grows too large (keeps ~128 most-recent sounds) - if (gDecodedWavCache.size() >= 256) { + // Evict oldest half when cache grows too large. 256 entries ≈ 50-100 MB of decoded + // PCM data depending on file lengths; halving keeps memory bounded while retaining + // recently-heard sounds (footsteps, UI clicks, combat hits) for instant replay. + constexpr size_t kMaxCachedSounds = 256; + if (gDecodedWavCache.size() >= kMaxCachedSounds) { auto it = gDecodedWavCache.begin(); for (size_t n = gDecodedWavCache.size() / 2; n > 0; --n, ++it) {} gDecodedWavCache.erase(gDecodedWavCache.begin(), it); @@ -239,7 +242,9 @@ bool AudioEngine::playSound2D(const std::vector& wavData, float volume, decoded.pcmData->data(), nullptr // No custom allocator ); - bufferConfig.sampleRate = decoded.sampleRate; // Critical: preserve original sample rate! + // Must set explicitly — miniaudio defaults to device sample rate, which causes + // pitch distortion if it differs from the file's native rate (e.g. 22050 vs 44100 Hz). + bufferConfig.sampleRate = decoded.sampleRate; ma_audio_buffer* audioBuffer = static_cast(std::malloc(sizeof(ma_audio_buffer))); if (!audioBuffer) return false; @@ -394,7 +399,9 @@ bool AudioEngine::playSound3D(const std::vector& wavData, const glm::ve decoded.pcmData->data(), nullptr ); - bufferConfig.sampleRate = decoded.sampleRate; // Critical: preserve original sample rate! + // Must set explicitly — miniaudio defaults to device sample rate, which causes + // pitch distortion if it differs from the file's native rate (e.g. 22050 vs 44100 Hz). + bufferConfig.sampleRate = decoded.sampleRate; ma_audio_buffer* audioBuffer = static_cast(std::malloc(sizeof(ma_audio_buffer))); if (!audioBuffer) return false; diff --git a/src/game/zone_manager.cpp b/src/game/zone_manager.cpp index 6ace1a60..c7590b2c 100644 --- a/src/game/zone_manager.cpp +++ b/src/game/zone_manager.cpp @@ -296,7 +296,12 @@ void ZoneManager::initialize() { }; zones[1657] = darnassus; - // Tile-to-zone mappings for Azeroth (Eastern Kingdoms) + // Tile-to-zone fallback mappings for Azeroth (Eastern Kingdoms). + // WoW's world is a grid of 64×64 ADT tiles per continent. We encode (tileX, tileY) + // into a single key as tileX * 100 + tileY (safe because tileY < 64 < 100). + // These ranges are empirically determined from the retail map layout and provide + // zone identification when AreaTable.dbc data is unavailable. + // // Elwynn Forest tiles for (int tx = 31; tx <= 34; tx++) { for (int ty = 48; ty <= 51; ty++) { diff --git a/src/network/tcp_socket.cpp b/src/network/tcp_socket.cpp index c0d7ffd3..33c21ce1 100644 --- a/src/network/tcp_socket.cpp +++ b/src/network/tcp_socket.cpp @@ -139,6 +139,9 @@ void TCPSocket::update() { bool sawClose = false; bool receivedAny = false; for (;;) { + // 4 KB per recv() call — large enough for any single game packet while keeping + // stack usage reasonable. Typical WoW packets are 20-500 bytes; UPDATE_OBJECT + // can reach ~2 KB in crowded zones. uint8_t buffer[4096]; ssize_t received = net::portableRecv(sockfd, buffer, sizeof(buffer));