From 1a3146395abbae9a531cb001831019eba5dcd7d9 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 23 Mar 2026 11:09:15 -0700 Subject: [PATCH] fix: validate splineMode in Classic spline parse to prevent desync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a WotLK NPC has durationMod=0.0, the Classic-first spline parser reads it as pointCount=0 and "succeeds", then consumes garbage bytes as splineMode and endPoint. This desynchronizes the read position for all subsequent update blocks in the packet, causing cascading failures (truncated update mask, unknown update type) that leave NPCs without displayIds — making them invisible. Fix: after reading splineMode, reject the Classic parse if splineMode > 3 (valid values are 0-3) and fall through to the WotLK format parser. --- src/game/world_packets.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index d7a294b4..cecbb38f 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -1088,6 +1088,7 @@ bool UpdateObjectParser::parseMovementBlock(network::Packet& packet, UpdateBlock // Helper: try to parse uncompressed spline points from current read position. auto tryParseUncompressedSpline = [&](const char* tag) -> bool { if (!bytesAvailable(4)) return false; + size_t prePointCount = packet.getReadPos(); uint32_t pc = packet.readUInt32(); if (pc > 256) return false; size_t needed = static_cast(pc) * 12ull + 13ull; @@ -1095,7 +1096,14 @@ bool UpdateObjectParser::parseMovementBlock(network::Packet& packet, UpdateBlock for (uint32_t i = 0; i < pc; i++) { packet.readFloat(); packet.readFloat(); packet.readFloat(); } - packet.readUInt8(); // splineMode + uint8_t splineMode = packet.readUInt8(); + // Validate splineMode (0=Linear, 1=CatmullRom, 2=BezierSpline, 3=unused) + // Values > 3 indicate we misidentified the format (e.g. WotLK durationMod=0.0 + // was read as pointCount=0, causing garbage to be read as splineMode). + if (splineMode > 3) { + packet.setReadPos(prePointCount); + return false; + } packet.readFloat(); packet.readFloat(); packet.readFloat(); // endPoint LOG_DEBUG(" Spline pointCount=", pc, " (", tag, ")"); return true;