mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
feat: parse arena header in MSG_PVP_LOG_DATA and show arena scoreboard
Previously the arena path in handlePvpLogData consumed the packet and returned early with no data. Now the two-team header is parsed (rating change, new rating, team name), followed by the same player list and winner fields as battlegrounds. The BgScoreboardData struct gains ArenaTeamScore fields (teamName, ratingChange, newRating) populated when isArena=true. The BG scoreboard UI is updated to: - Use "Arena Score" window title for arenas - Show each team's name and rating delta at the top - Identify the winner by team name instead of faction label
This commit is contained in:
parent
de5c122307
commit
74d5984ee2
3 changed files with 67 additions and 13 deletions
|
|
@ -433,11 +433,18 @@ public:
|
|||
uint32_t bonusHonor = 0;
|
||||
std::vector<std::pair<std::string, uint32_t>> bgStats; // BG-specific fields
|
||||
};
|
||||
struct ArenaTeamScore {
|
||||
std::string teamName;
|
||||
uint32_t ratingChange = 0; // signed delta packed as uint32
|
||||
uint32_t newRating = 0;
|
||||
};
|
||||
struct BgScoreboardData {
|
||||
std::vector<BgPlayerScore> players;
|
||||
bool hasWinner = false;
|
||||
uint8_t winner = 0; // 0=Horde, 1=Alliance
|
||||
bool isArena = false;
|
||||
// Arena-only fields (valid when isArena=true)
|
||||
ArenaTeamScore arenaTeams[2]; // team 0 = first, team 1 = second
|
||||
};
|
||||
void requestPvpLog();
|
||||
const BgScoreboardData* getBgScoreboard() const {
|
||||
|
|
|
|||
|
|
@ -14992,12 +14992,19 @@ void GameHandler::handlePvpLogData(network::Packet& packet) {
|
|||
bgScoreboard_.isArena = (packet.readUInt8() != 0);
|
||||
|
||||
if (bgScoreboard_.isArena) {
|
||||
// Skip arena-specific header (two teams × (rating change uint32 + name string + 5×uint32))
|
||||
// Rather than hardcoding arena parse we skip gracefully up to playerCount
|
||||
// Each arena team block: uint32 + string + uint32*5 — variable length due to string.
|
||||
// Skip by scanning for the uint32 playerCount heuristically; simply consume rest.
|
||||
packet.setReadPos(packet.getSize());
|
||||
return;
|
||||
// WotLK 3.3.5a MSG_PVP_LOG_DATA arena header:
|
||||
// two team blocks × (uint32 ratingChange + uint32 newRating + uint32 unk1 + uint32 unk2 + uint32 unk3 + CString teamName)
|
||||
// After both team blocks: same player list and winner fields as battleground.
|
||||
for (int t = 0; t < 2; ++t) {
|
||||
if (remaining() < 20) { packet.setReadPos(packet.getSize()); return; }
|
||||
bgScoreboard_.arenaTeams[t].ratingChange = packet.readUInt32();
|
||||
bgScoreboard_.arenaTeams[t].newRating = packet.readUInt32();
|
||||
packet.readUInt32(); // unk1
|
||||
packet.readUInt32(); // unk2
|
||||
packet.readUInt32(); // unk3
|
||||
bgScoreboard_.arenaTeams[t].teamName = remaining() > 0 ? packet.readString() : "";
|
||||
}
|
||||
// Fall through to parse player list and winner fields below (same layout as BG)
|
||||
}
|
||||
|
||||
if (remaining() < 4) return;
|
||||
|
|
@ -15046,8 +15053,17 @@ void GameHandler::handlePvpLogData(network::Packet& packet) {
|
|||
bgScoreboard_.winner = packet.readUInt8();
|
||||
}
|
||||
|
||||
LOG_INFO("PvP log: ", bgScoreboard_.players.size(), " players, hasWinner=",
|
||||
bgScoreboard_.hasWinner, " winner=", (int)bgScoreboard_.winner);
|
||||
if (bgScoreboard_.isArena) {
|
||||
LOG_INFO("Arena log: ", bgScoreboard_.players.size(), " players, hasWinner=",
|
||||
bgScoreboard_.hasWinner, " winner=", (int)bgScoreboard_.winner,
|
||||
" team0='", bgScoreboard_.arenaTeams[0].teamName,
|
||||
"' ratingChange=", (int32_t)bgScoreboard_.arenaTeams[0].ratingChange,
|
||||
" team1='", bgScoreboard_.arenaTeams[1].teamName,
|
||||
"' ratingChange=", (int32_t)bgScoreboard_.arenaTeams[1].ratingChange);
|
||||
} else {
|
||||
LOG_INFO("PvP log: ", bgScoreboard_.players.size(), " players, hasWinner=",
|
||||
bgScoreboard_.hasWinner, " winner=", (int)bgScoreboard_.winner);
|
||||
}
|
||||
}
|
||||
|
||||
void GameHandler::handleOtherPlayerMovement(network::Packet& packet) {
|
||||
|
|
|
|||
|
|
@ -20400,7 +20400,8 @@ void GameScreen::renderBgScoreboard(game::GameHandler& gameHandler) {
|
|||
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImVec2(150, 100), ImGuiCond_FirstUseEver);
|
||||
|
||||
const char* title = "Battleground Score###BgScore";
|
||||
const char* title = data && data->isArena ? "Arena Score###BgScore"
|
||||
: "Battleground Score###BgScore";
|
||||
if (!ImGui::Begin(title, &showBgScoreboard_, ImGuiWindowFlags_NoCollapse)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
|
|
@ -20408,16 +20409,46 @@ void GameScreen::renderBgScoreboard(game::GameHandler& gameHandler) {
|
|||
|
||||
if (!data) {
|
||||
ImGui::TextDisabled("No score data yet.");
|
||||
ImGui::TextDisabled("Use /score to request the scoreboard while in a battleground.");
|
||||
ImGui::TextDisabled("Use /score to request the scoreboard while in a battleground or arena.");
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
// Arena team rating banner (shown only for arenas)
|
||||
if (data->isArena) {
|
||||
for (int t = 0; t < 2; ++t) {
|
||||
const auto& at = data->arenaTeams[t];
|
||||
if (at.teamName.empty()) continue;
|
||||
int32_t ratingDelta = static_cast<int32_t>(at.ratingChange);
|
||||
ImVec4 teamCol = (t == 0) ? ImVec4(1.0f, 0.35f, 0.35f, 1.0f) // team 0: red
|
||||
: ImVec4(0.4f, 0.6f, 1.0f, 1.0f); // team 1: blue
|
||||
ImGui::TextColored(teamCol, "%s", at.teamName.c_str());
|
||||
ImGui::SameLine();
|
||||
char ratingBuf[32];
|
||||
if (ratingDelta >= 0)
|
||||
std::snprintf(ratingBuf, sizeof(ratingBuf), "Rating: %u (+%d)", at.newRating, ratingDelta);
|
||||
else
|
||||
std::snprintf(ratingBuf, sizeof(ratingBuf), "Rating: %u (%d)", at.newRating, ratingDelta);
|
||||
ImGui::TextDisabled("%s", ratingBuf);
|
||||
}
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
// Winner banner
|
||||
if (data->hasWinner) {
|
||||
const char* winnerStr = (data->winner == 1) ? "Alliance" : "Horde";
|
||||
ImVec4 winnerColor = (data->winner == 1) ? ImVec4(0.4f, 0.6f, 1.0f, 1.0f)
|
||||
: ImVec4(1.0f, 0.35f, 0.35f, 1.0f);
|
||||
const char* winnerStr;
|
||||
ImVec4 winnerColor;
|
||||
if (data->isArena) {
|
||||
// For arenas, winner byte 0/1 refers to team index in arenaTeams[]
|
||||
const auto& winTeam = data->arenaTeams[data->winner & 1];
|
||||
winnerStr = winTeam.teamName.empty() ? "Team 1" : winTeam.teamName.c_str();
|
||||
winnerColor = (data->winner == 0) ? ImVec4(1.0f, 0.35f, 0.35f, 1.0f)
|
||||
: ImVec4(0.4f, 0.6f, 1.0f, 1.0f);
|
||||
} else {
|
||||
winnerStr = (data->winner == 1) ? "Alliance" : "Horde";
|
||||
winnerColor = (data->winner == 1) ? ImVec4(0.4f, 0.6f, 1.0f, 1.0f)
|
||||
: ImVec4(1.0f, 0.35f, 0.35f, 1.0f);
|
||||
}
|
||||
float textW = ImGui::CalcTextSize(winnerStr).x + ImGui::CalcTextSize(" Victory!").x;
|
||||
ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - textW) * 0.5f);
|
||||
ImGui::TextColored(winnerColor, "%s", winnerStr);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue