docs: add why-comments to TBC parsers, bell audio, portrait preview

- packet_parsers_tbc: explain spline waypoint cap (DoS prevention),
  spline compression flags (Catmull-Rom 0x80000 / linear 0x2000 use
  uncompressed format, others use packed delta), spell hit target cap
  (128 >> real AOE max of ~20), guild roster cap (1000 safety limit)
- ambient_sound_manager: explain 1.5s bell toll spacing — matches
  retail WoW cadence, allows each toll to ring out before the next
- character_preview.hpp: explain 4:5 portrait aspect ratio for
  full-body character display in creation/selection screen
This commit is contained in:
Kelsi 2026-03-30 17:26:13 -07:00
parent 92369c1cec
commit 2c50cc94e1
3 changed files with 11 additions and 1 deletions

View file

@ -81,6 +81,8 @@ private:
// ImGui texture handle for displaying the preview (VkDescriptorSet in Vulkan backend)
VkDescriptorSet imguiTextureId_ = VK_NULL_HANDLE;
// 4:5 portrait aspect ratio — taller than wide to show full character body
// from head to feet in the character creation/selection screen
static constexpr int fboWidth_ = 400;
static constexpr int fboHeight_ = 500;

View file

@ -921,7 +921,8 @@ void AmbientSoundManager::updateBellTolls(float deltaTime) {
static_cast<int>(currentCity_));
}
// Play remaining tolls with 1.5 second delay between each
// Play remaining tolls with 1.5s spacing — matches retail WoW bell cadence
// (long enough for each toll to ring out before the next begins)
if (remainingTolls_ > 0) {
bellTollDelay_ += deltaTime;

View file

@ -155,6 +155,7 @@ bool TbcPacketParsers::parseMovementBlock(network::Packet& packet, UpdateBlock&
/*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 TBC)
@ -690,6 +691,8 @@ bool TbcPacketParsers::parseMonsterMove(network::Packet& packet, MonsterMoveData
if (pointCount == 0) return true;
if (pointCount > 16384) return false;
// Spline points are stored uncompressed when Catmull-Rom interpolation (0x80000)
// or linear movement (0x2000) flags are set; otherwise they use packed delta format
bool uncompressed = (data.splineFlags & (0x00080000 | 0x00002000)) != 0;
if (uncompressed) {
for (uint32_t i = 0; i < pointCount - 1; i++) {
@ -1359,6 +1362,8 @@ bool TbcPacketParsers::parseSpellGo(network::Packet& packet, SpellGoData& data)
return false;
}
// Cap hit targets to prevent oversized allocations from malformed spell packets.
// 128 is well above any real WoW AOE spell target count (max ~20 in practice).
const uint8_t rawHitCount = packet.readUInt8();
if (rawHitCount > 128) {
LOG_WARNING("[TBC] Spell go: hitCount capped (requested=", static_cast<int>(rawHitCount), ")");
@ -1819,6 +1824,8 @@ bool TbcPacketParsers::parseGuildRoster(network::Packet& packet, GuildRosterData
}
uint32_t numMembers = packet.readUInt32();
// Safety cap — guilds rarely exceed 500 members; 1000 prevents excessive
// memory allocation from malformed packets while covering all real cases
const uint32_t MAX_GUILD_MEMBERS = 1000;
if (numMembers > MAX_GUILD_MEMBERS) {
LOG_WARNING("TBC GuildRoster: numMembers capped (requested=", numMembers, ")");