Harden runtime against stutter-inducing log floods and missing display IDs

- Re-gate M2 glow diagnostics behind WOWEE_M2_GLOW_DIAG and DEBUG

- Deduplicate missing/failed texture warnings in asset and M2 texture loaders

- Deduplicate unhandled opcode warnings by state/opcode key in non-IN_WORLD phases

- Throttle malformed spline point-count warnings across world/classic/tbc parsers

- Ignore suspiciously huge display IDs from malformed packets with throttled warning

- Add nearest-known displayId model fallback cache for missing creature display mappings

- Clear display fallback caches on expansion reload and logout
This commit is contained in:
Kelsi 2026-02-21 04:05:53 -08:00
parent dc91b316ed
commit fa3060bdf7
8 changed files with 124 additions and 36 deletions

View file

@ -2823,19 +2823,24 @@ void GameHandler::handlePacket(network::Packet& packet) {
// In pre-world states we need full visibility (char create/login handshakes).
// In-world we keep de-duplication to avoid heavy log I/O in busy areas.
if (state != WorldState::IN_WORLD) {
LOG_WARNING("Unhandled world opcode: 0x", std::hex, opcode, std::dec,
" state=", static_cast<int>(state),
" size=", packet.getSize());
const auto& data = packet.getData();
std::string hex;
size_t limit = std::min<size_t>(data.size(), 48);
hex.reserve(limit * 3);
for (size_t i = 0; i < limit; ++i) {
char b[4];
snprintf(b, sizeof(b), "%02x ", data[i]);
hex += b;
static std::unordered_set<uint32_t> loggedUnhandledByState;
const uint32_t key = (static_cast<uint32_t>(static_cast<uint8_t>(state)) << 16) |
static_cast<uint32_t>(opcode);
if (loggedUnhandledByState.insert(key).second) {
LOG_WARNING("Unhandled world opcode: 0x", std::hex, opcode, std::dec,
" state=", static_cast<int>(state),
" size=", packet.getSize());
const auto& data = packet.getData();
std::string hex;
size_t limit = std::min<size_t>(data.size(), 48);
hex.reserve(limit * 3);
for (size_t i = 0; i < limit; ++i) {
char b[4];
snprintf(b, sizeof(b), "%02x ", data[i]);
hex += b;
}
LOG_INFO("Unhandled opcode payload hex (first ", limit, " bytes): ", hex);
}
LOG_INFO("Unhandled opcode payload hex (first ", limit, " bytes): ", hex);
} else {
static std::unordered_set<uint16_t> loggedUnhandledOpcodes;
if (loggedUnhandledOpcodes.insert(static_cast<uint16_t>(opcode)).second) {

View file

@ -126,7 +126,12 @@ bool ClassicPacketParsers::parseMovementBlock(network::Packet& packet, UpdateBlo
uint32_t pointCount = packet.readUInt32();
if (pointCount > 256) {
LOG_WARNING(" [Classic] Spline pointCount=", pointCount, " exceeds max, capping");
static uint32_t badClassicSplineCount = 0;
++badClassicSplineCount;
if (badClassicSplineCount <= 5 || (badClassicSplineCount % 100) == 0) {
LOG_WARNING(" [Classic] Spline pointCount=", pointCount,
" exceeds max, capping (occurrence=", badClassicSplineCount, ")");
}
pointCount = 0;
}
for (uint32_t i = 0; i < pointCount; i++) {
@ -1135,7 +1140,12 @@ bool TurtlePacketParsers::parseMovementBlock(network::Packet& packet, UpdateBloc
uint32_t pointCount = packet.readUInt32();
if (pointCount > 256) {
LOG_WARNING(" [Turtle] Spline pointCount=", pointCount, " exceeds max, capping");
static uint32_t badTurtleSplineCount = 0;
++badTurtleSplineCount;
if (badTurtleSplineCount <= 5 || (badTurtleSplineCount % 100) == 0) {
LOG_WARNING(" [Turtle] Spline pointCount=", pointCount,
" exceeds max, capping (occurrence=", badTurtleSplineCount, ")");
}
pointCount = 0;
}
for (uint32_t i = 0; i < pointCount; i++) {

View file

@ -140,7 +140,12 @@ bool TbcPacketParsers::parseMovementBlock(network::Packet& packet, UpdateBlock&
uint32_t pointCount = packet.readUInt32();
if (pointCount > 256) {
LOG_WARNING(" [TBC] Spline pointCount=", pointCount, " exceeds max, capping");
static uint32_t badTbcSplineCount = 0;
++badTbcSplineCount;
if (badTbcSplineCount <= 5 || (badTbcSplineCount % 100) == 0) {
LOG_WARNING(" [TBC] Spline pointCount=", pointCount,
" exceeds max, capping (occurrence=", badTbcSplineCount, ")");
}
pointCount = 0;
}
for (uint32_t i = 0; i < pointCount; i++) {

View file

@ -911,8 +911,14 @@ bool UpdateObjectParser::parseMovementBlock(network::Packet& packet, UpdateBlock
uint32_t pointCount = packet.readUInt32();
if (pointCount > 256) {
LOG_WARNING(" Spline pointCount=", pointCount, " exceeds maximum, capping at 0 (readPos=",
packet.getReadPos(), "/", packet.getSize(), ")");
static uint32_t badSplineCount = 0;
++badSplineCount;
if (badSplineCount <= 5 || (badSplineCount % 100) == 0) {
LOG_WARNING(" Spline pointCount=", pointCount,
" exceeds maximum, capping at 0 (readPos=",
packet.getReadPos(), "/", packet.getSize(),
", occurrence=", badSplineCount, ")");
}
pointCount = 0;
} else {
LOG_DEBUG(" Spline pointCount=", pointCount);