From 758ca76bd3ad0ea4d38d40ea3868c5c1e8d76d5b Mon Sep 17 00:00:00 2001 From: Kelsi Date: Thu, 12 Mar 2026 21:27:02 -0700 Subject: [PATCH] feat: parse MSG_INSPECT_ARENA_TEAMS and display in inspect window Implements MSG_INSPECT_ARENA_TEAMS (WotLK): reads the inspected player's arena team data (2v2/3v3/5v5 bracket, team name, personal rating, week/season W-L) and stores it in InspectResult.arenaTeams. The inspect window now shows an "Arena Teams" section below the gear list when arena team data is available, displaying bracket, team name, rating, and win/loss record. Also implement SMSG_COMPLAIN_RESULT with user-visible feedback for report-player results. --- include/game/game_handler.hpp | 11 ++++++++ src/game/game_handler.cpp | 47 ++++++++++++++++++++++++++++++++--- src/ui/game_screen.cpp | 22 ++++++++++++++++ 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 1cdd20ea..42403a32 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -339,6 +339,16 @@ public: // Inspection void inspectTarget(); + struct InspectArenaTeam { + uint32_t teamId = 0; + uint8_t type = 0; // bracket size: 2, 3, or 5 + uint32_t weekGames = 0; + uint32_t weekWins = 0; + uint32_t seasonGames = 0; + uint32_t seasonWins = 0; + std::string name; + uint32_t personalRating = 0; + }; struct InspectResult { uint64_t guid = 0; std::string playerName; @@ -348,6 +358,7 @@ public: uint8_t activeTalentGroup = 0; std::array itemEntries{}; // 0=head…18=ranged std::array enchantIds{}; // permanent enchant per slot (0 = none) + std::vector arenaTeams; // from MSG_INSPECT_ARENA_TEAMS (WotLK) }; const InspectResult* getInspectResult() const { return inspectResult_.guid ? &inspectResult_ : nullptr; diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 7c96b73a..07b56112 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -5166,9 +5166,37 @@ void GameHandler::handlePacket(network::Packet& packet) { case Opcode::MSG_PVP_LOG_DATA: handlePvpLogData(packet); break; - case Opcode::MSG_INSPECT_ARENA_TEAMS: - LOG_INFO("Received MSG_INSPECT_ARENA_TEAMS"); + case Opcode::MSG_INSPECT_ARENA_TEAMS: { + // WotLK: uint64 playerGuid + uint8 teamCount + per-team fields + if (packet.getSize() - packet.getReadPos() < 9) { + packet.setReadPos(packet.getSize()); + break; + } + uint64_t inspGuid = packet.readUInt64(); + uint8_t teamCount = packet.readUInt8(); + if (teamCount > 3) teamCount = 3; // 2v2, 3v3, 5v5 + if (inspGuid == inspectResult_.guid || inspectResult_.guid == 0) { + inspectResult_.guid = inspGuid; + inspectResult_.arenaTeams.clear(); + for (uint8_t t = 0; t < teamCount; ++t) { + if (packet.getSize() - packet.getReadPos() < 21) break; + InspectArenaTeam team; + team.teamId = packet.readUInt32(); + team.type = packet.readUInt8(); + team.weekGames = packet.readUInt32(); + team.weekWins = packet.readUInt32(); + team.seasonGames = packet.readUInt32(); + team.seasonWins = packet.readUInt32(); + team.name = packet.readString(); + if (packet.getSize() - packet.getReadPos() < 4) break; + team.personalRating = packet.readUInt32(); + inspectResult_.arenaTeams.push_back(std::move(team)); + } + } + LOG_DEBUG("MSG_INSPECT_ARENA_TEAMS: guid=0x", std::hex, inspGuid, std::dec, + " teams=", (int)teamCount); break; + } case Opcode::MSG_TALENT_WIPE_CONFIRM: { // Server sends: uint64 npcGuid + uint32 cost // Client must respond with the same opcode containing uint64 npcGuid to confirm. @@ -5869,10 +5897,21 @@ void GameHandler::handlePacket(network::Packet& packet) { LOG_DEBUG("SMSG_ITEM_ENCHANT_TIME_UPDATE: slot=", enchSlot, " dur=", durationSec, "s"); break; } - case Opcode::SMSG_COMPLAIN_RESULT: + case Opcode::SMSG_COMPLAIN_RESULT: { + // uint8 result: 0=success, 1=failed, 2=disabled + if (packet.getSize() - packet.getReadPos() >= 1) { + uint8_t result = packet.readUInt8(); + if (result == 0) + addSystemChatMessage("Your complaint has been submitted."); + else if (result == 2) + addUIError("Report a Player is currently disabled."); + } + packet.setReadPos(packet.getSize()); + break; + } case Opcode::SMSG_ITEM_REFUND_INFO_RESPONSE: case Opcode::SMSG_LOOT_LIST: - // Consume — not yet processed + // Consume silently — informational, no UI action needed packet.setReadPos(packet.getSize()); break; diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index e53d6748..e5526b09 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -20697,6 +20697,28 @@ void GameScreen::renderInspectWindow(game::GameHandler& gameHandler) { ImGui::EndChild(); } + // Arena teams (WotLK — from MSG_INSPECT_ARENA_TEAMS) + if (!result->arenaTeams.empty()) { + ImGui::Separator(); + ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.2f, 1.0f), "Arena Teams"); + ImGui::Spacing(); + for (const auto& team : result->arenaTeams) { + const char* bracket = (team.type == 2) ? "2v2" + : (team.type == 3) ? "3v3" + : (team.type == 5) ? "5v5" : "?v?"; + ImGui::TextColored(ImVec4(0.9f, 0.9f, 0.9f, 1.0f), + "[%s] %s", bracket, team.name.c_str()); + ImGui::SameLine(); + ImGui::TextColored(ImVec4(0.4f, 0.85f, 1.0f, 1.0f), + " Rating: %u", team.personalRating); + if (team.weekGames > 0 || team.seasonGames > 0) { + ImGui::TextDisabled(" Week: %u/%u Season: %u/%u", + team.weekWins, team.weekGames, + team.seasonWins, team.seasonGames); + } + } + } + ImGui::End(); }