From 92369c1cec448f2e95c30383b68c36f45e5170ed Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 30 Mar 2026 17:23:07 -0700 Subject: [PATCH] docs: add why-comments to rendering, packets, and UI code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - charge_effect: explain inversesqrt guard (prevents NaN on stationary character) and dust accumulator rate (30 particles/sec * 16ms) - swim_effects: explain why insect pipeline disables depth test (screen-space sprites must render above water geometry) - packet_parsers_classic: explain spline waypoint cap (DoS prevention) and packed GUID compression format (non-zero bytes only, mask byte) - talent_screen: explain class ID to bitmask conversion (1-indexed WoW class IDs → power-of-2 mask for TalentTab.classMask matching) - auth_screen: explain login music volume reduction (80% so UI sounds remain audible over background track) --- src/game/packet_parsers_classic.cpp | 5 ++++- src/rendering/charge_effect.cpp | 2 ++ src/rendering/swim_effects.cpp | 2 ++ src/ui/auth_screen.cpp | 4 +++- src/ui/talent_screen.cpp | 4 +++- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/game/packet_parsers_classic.cpp b/src/game/packet_parsers_classic.cpp index 03e76baa..5b02127b 100644 --- a/src/game/packet_parsers_classic.cpp +++ b/src/game/packet_parsers_classic.cpp @@ -282,6 +282,7 @@ bool ClassicPacketParsers::parseMovementBlock(network::Packet& packet, UpdateBlo /*uint32_t splineId =*/ packet.readUInt32(); uint32_t pointCount = packet.readUInt32(); + // Cap waypoints to prevent DoS from malformed packets allocating huge arrays if (pointCount > 256) return false; // points + endPoint (no splineMode in Classic) @@ -362,7 +363,9 @@ void ClassicPacketParsers::writeMovementPayload(network::Packet& packet, const M // Transport data (Classic ONTRANSPORT = 0x02000000, no timestamp) if (wireFlags & ClassicMoveFlags::ONTRANSPORT) { - // Packed transport GUID + // Packed GUID compression: only transmit non-zero bytes of the 8-byte GUID. + // The mask byte indicates which positions are present (bit N = byte N included). + // This is the standard WoW packed GUID wire format across all expansions. uint8_t transMask = 0; uint8_t transGuidBytes[8]; int transGuidByteCount = 0; diff --git a/src/rendering/charge_effect.cpp b/src/rendering/charge_effect.cpp index f6da288f..60cc5ae7 100644 --- a/src/rendering/charge_effect.cpp +++ b/src/rendering/charge_effect.cpp @@ -474,11 +474,13 @@ void ChargeEffect::emit(const glm::vec3& position, const glm::vec3& direction) { // Spawn dust puffs at feet glm::vec3 horizDir = glm::vec3(direction.x, direction.y, 0.0f); float horizLenSq = glm::dot(horizDir, horizDir); + // Skip dust when character is nearly stationary — prevents NaN from inversesqrt(0) if (horizLenSq < 1e-6f) return; float invHorizLen = glm::inversesqrt(horizLenSq); glm::vec3 backDir = -horizDir * invHorizLen; glm::vec3 sideDir = glm::vec3(-backDir.y, backDir.x, 0.0f); + // Accumulate ~0.48 per frame at 60fps (30 particles/sec * 16ms); emit when >= 1.0 dustAccum_ += 30.0f * 0.016f; while (dustAccum_ >= 1.0f && dustPuffs_.size() < MAX_DUST) { dustAccum_ -= 1.0f; diff --git a/src/rendering/swim_effects.cpp b/src/rendering/swim_effects.cpp index e964f736..5e7f4599 100644 --- a/src/rendering/swim_effects.cpp +++ b/src/rendering/swim_effects.cpp @@ -175,6 +175,8 @@ bool SwimEffects::initialize(VkContext* ctx, VkDescriptorSetLayout perFrameLayou return false; } + // Depth test disabled — insects are screen-space sprites that must always + // render above the water surface regardless of scene geometry. insectPipeline = PipelineBuilder() .setShaders(vertStage, fragStage) .setVertexInput({binding}, attrs) diff --git a/src/ui/auth_screen.cpp b/src/ui/auth_screen.cpp index 4c4b36ba..88264930 100644 --- a/src/ui/auth_screen.cpp +++ b/src/ui/auth_screen.cpp @@ -216,7 +216,9 @@ void AuthScreen::render(auth::AuthHandler& authHandler) { if (music) { if (!loginMusicVolumeAdjusted_) { savedMusicVolume_ = music->getVolume(); - int loginVolume = (savedMusicVolume_ * 80) / 100; // reduce auth music by 20% + // Reduce music to 80% during login so UI button clicks and error sounds + // remain audible over the background track + int loginVolume = (savedMusicVolume_ * 80) / 100; if (loginVolume < 0) loginVolume = 0; if (loginVolume > 100) loginVolume = 100; music->setVolume(loginVolume); diff --git a/src/ui/talent_screen.cpp b/src/ui/talent_screen.cpp index 752762d7..3afc6fd9 100644 --- a/src/ui/talent_screen.cpp +++ b/src/ui/talent_screen.cpp @@ -76,7 +76,9 @@ void TalentScreen::renderTalentTrees(game::GameHandler& gameHandler) { return; } - // Get talent tabs for this class, sorted by orderIndex + // Get talent tabs for this class, sorted by orderIndex. + // WoW class IDs are 1-indexed (Warrior=1..Druid=11); convert to bitmask for + // TalentTab.classMask matching (Warrior=0x1, Paladin=0x2, Hunter=0x4, etc.) uint32_t classMask = 1u << (playerClass - 1); std::vector classTabs; for (const auto& [tabId, tab] : gameHandler.getAllTalentTabs()) {