mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 00:03:50 +00:00
feat: parse SMSG_ARENA_TEAM_ROSTER and display member list in Arena UI
Add ArenaTeamMember / ArenaTeamRoster structs, parse the WotLK 3.3.5a roster packet (guid, online flag, name, per-player week/season W/L, personal rating), store per-teamId, and render a 4-column table (Name / Rating / Week / Season) inside the existing Arena social tab. Online members are highlighted green; offline members are greyed out.
This commit is contained in:
parent
a728952058
commit
91535fa9ae
3 changed files with 137 additions and 4 deletions
|
|
@ -1247,6 +1247,29 @@ public:
|
|||
};
|
||||
const std::vector<ArenaTeamStats>& getArenaTeamStats() const { return arenaTeamStats_; }
|
||||
|
||||
// ---- Arena Team Roster ----
|
||||
struct ArenaTeamMember {
|
||||
uint64_t guid = 0;
|
||||
std::string name;
|
||||
bool online = false;
|
||||
uint32_t weekGames = 0;
|
||||
uint32_t weekWins = 0;
|
||||
uint32_t seasonGames = 0;
|
||||
uint32_t seasonWins = 0;
|
||||
uint32_t personalRating = 0;
|
||||
};
|
||||
struct ArenaTeamRoster {
|
||||
uint32_t teamId = 0;
|
||||
std::vector<ArenaTeamMember> members;
|
||||
};
|
||||
// Returns roster for the given teamId, or nullptr if not yet received
|
||||
const ArenaTeamRoster* getArenaTeamRoster(uint32_t teamId) const {
|
||||
for (const auto& r : arenaTeamRosters_) {
|
||||
if (r.teamId == teamId) return &r;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ---- Phase 5: Loot ----
|
||||
void lootTarget(uint64_t guid);
|
||||
void lootItem(uint8_t slotIndex);
|
||||
|
|
@ -2080,6 +2103,7 @@ private:
|
|||
void handleInstanceDifficulty(network::Packet& packet);
|
||||
void handleArenaTeamCommandResult(network::Packet& packet);
|
||||
void handleArenaTeamQueryResponse(network::Packet& packet);
|
||||
void handleArenaTeamRoster(network::Packet& packet);
|
||||
void handleArenaTeamInvite(network::Packet& packet);
|
||||
void handleArenaTeamEvent(network::Packet& packet);
|
||||
void handleArenaTeamStats(network::Packet& packet);
|
||||
|
|
@ -2454,7 +2478,9 @@ private:
|
|||
std::vector<InstanceLockout> instanceLockouts_;
|
||||
|
||||
// Arena team stats (indexed by team slot, updated by SMSG_ARENA_TEAM_STATS)
|
||||
std::vector<ArenaTeamStats> arenaTeamStats_;
|
||||
std::vector<ArenaTeamStats> arenaTeamStats_;
|
||||
// Arena team rosters (updated by SMSG_ARENA_TEAM_ROSTER)
|
||||
std::vector<ArenaTeamRoster> arenaTeamRosters_;
|
||||
|
||||
// BG scoreboard (MSG_PVP_LOG_DATA)
|
||||
BgScoreboardData bgScoreboard_;
|
||||
|
|
|
|||
|
|
@ -5113,7 +5113,7 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
|||
handleArenaTeamQueryResponse(packet);
|
||||
break;
|
||||
case Opcode::SMSG_ARENA_TEAM_ROSTER:
|
||||
LOG_INFO("Received SMSG_ARENA_TEAM_ROSTER");
|
||||
handleArenaTeamRoster(packet);
|
||||
break;
|
||||
case Opcode::SMSG_ARENA_TEAM_INVITE:
|
||||
handleArenaTeamInvite(packet);
|
||||
|
|
@ -13692,6 +13692,70 @@ void GameHandler::handleArenaTeamQueryResponse(network::Packet& packet) {
|
|||
LOG_INFO("Arena team query response: id=", teamId, " name=", teamName);
|
||||
}
|
||||
|
||||
void GameHandler::handleArenaTeamRoster(network::Packet& packet) {
|
||||
// SMSG_ARENA_TEAM_ROSTER (WotLK 3.3.5a):
|
||||
// uint32 teamId
|
||||
// uint8 unk (0 = not captainship packet)
|
||||
// uint32 memberCount
|
||||
// For each member:
|
||||
// uint64 guid
|
||||
// uint8 online (1=online, 0=offline)
|
||||
// string name (null-terminated)
|
||||
// uint32 gamesWeek
|
||||
// uint32 winsWeek
|
||||
// uint32 gamesSeason
|
||||
// uint32 winsSeason
|
||||
// uint32 personalRating
|
||||
// float modDay (unused here)
|
||||
// float modWeek (unused here)
|
||||
if (packet.getSize() - packet.getReadPos() < 9) return;
|
||||
|
||||
uint32_t teamId = packet.readUInt32();
|
||||
/*uint8_t unk =*/ packet.readUInt8();
|
||||
uint32_t memberCount = packet.readUInt32();
|
||||
|
||||
// Sanity cap to avoid huge allocations from malformed packets
|
||||
if (memberCount > 100) memberCount = 100;
|
||||
|
||||
ArenaTeamRoster roster;
|
||||
roster.teamId = teamId;
|
||||
roster.members.reserve(memberCount);
|
||||
|
||||
for (uint32_t i = 0; i < memberCount; ++i) {
|
||||
if (packet.getSize() - packet.getReadPos() < 12) break;
|
||||
|
||||
ArenaTeamMember m;
|
||||
m.guid = packet.readUInt64();
|
||||
m.online = (packet.readUInt8() != 0);
|
||||
m.name = packet.readString();
|
||||
if (packet.getSize() - packet.getReadPos() < 20) break;
|
||||
m.weekGames = packet.readUInt32();
|
||||
m.weekWins = packet.readUInt32();
|
||||
m.seasonGames = packet.readUInt32();
|
||||
m.seasonWins = packet.readUInt32();
|
||||
m.personalRating = packet.readUInt32();
|
||||
// skip 2 floats (modDay, modWeek)
|
||||
if (packet.getSize() - packet.getReadPos() >= 8) {
|
||||
packet.readFloat();
|
||||
packet.readFloat();
|
||||
}
|
||||
roster.members.push_back(std::move(m));
|
||||
}
|
||||
|
||||
// Replace existing roster for this team or append
|
||||
for (auto& r : arenaTeamRosters_) {
|
||||
if (r.teamId == teamId) {
|
||||
r = std::move(roster);
|
||||
LOG_INFO("SMSG_ARENA_TEAM_ROSTER: updated teamId=", teamId,
|
||||
" members=", r.members.size());
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG_INFO("SMSG_ARENA_TEAM_ROSTER: new teamId=", teamId,
|
||||
" members=", roster.members.size());
|
||||
arenaTeamRosters_.push_back(std::move(roster));
|
||||
}
|
||||
|
||||
void GameHandler::handleArenaTeamInvite(network::Packet& packet) {
|
||||
std::string playerName = packet.readString();
|
||||
std::string teamName = packet.readString();
|
||||
|
|
|
|||
|
|
@ -11854,11 +11854,11 @@ void GameScreen::renderSocialFrame(game::GameHandler& gameHandler) {
|
|||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
// ---- Arena tab (WotLK: shows per-team rating/record) ----
|
||||
// ---- Arena tab (WotLK: shows per-team rating/record + roster) ----
|
||||
const auto& arenaStats = gameHandler.getArenaTeamStats();
|
||||
if (!arenaStats.empty()) {
|
||||
if (ImGui::BeginTabItem("Arena")) {
|
||||
ImGui::BeginChild("##ArenaList", ImVec2(200, 200), false);
|
||||
ImGui::BeginChild("##ArenaList", ImVec2(0, 0), false);
|
||||
|
||||
for (size_t ai = 0; ai < arenaStats.size(); ++ai) {
|
||||
const auto& ts = arenaStats[ai];
|
||||
|
|
@ -11887,6 +11887,49 @@ void GameScreen::renderSocialFrame(game::GameHandler& gameHandler) {
|
|||
? ts.seasonGames - ts.seasonWins : 0;
|
||||
ImGui::Text("Season: %u W / %u L", ts.seasonWins, seasLosses);
|
||||
|
||||
// Roster members (from SMSG_ARENA_TEAM_ROSTER)
|
||||
const auto* roster = gameHandler.getArenaTeamRoster(ts.teamId);
|
||||
if (roster && !roster->members.empty()) {
|
||||
ImGui::Spacing();
|
||||
ImGui::TextDisabled("-- Roster (%zu members) --",
|
||||
roster->members.size());
|
||||
// Column headers
|
||||
ImGui::Columns(4, "##arenaRosterCols", false);
|
||||
ImGui::SetColumnWidth(0, 110.0f);
|
||||
ImGui::SetColumnWidth(1, 60.0f);
|
||||
ImGui::SetColumnWidth(2, 60.0f);
|
||||
ImGui::SetColumnWidth(3, 60.0f);
|
||||
ImGui::TextDisabled("Name"); ImGui::NextColumn();
|
||||
ImGui::TextDisabled("Rating"); ImGui::NextColumn();
|
||||
ImGui::TextDisabled("Week"); ImGui::NextColumn();
|
||||
ImGui::TextDisabled("Season"); ImGui::NextColumn();
|
||||
ImGui::Separator();
|
||||
|
||||
for (const auto& m : roster->members) {
|
||||
// Name coloured green (online) or grey (offline)
|
||||
if (m.online)
|
||||
ImGui::TextColored(ImVec4(0.4f,1.0f,0.4f,1.0f),
|
||||
"%s", m.name.c_str());
|
||||
else
|
||||
ImGui::TextDisabled("%s", m.name.c_str());
|
||||
ImGui::NextColumn();
|
||||
|
||||
ImGui::Text("%u", m.personalRating);
|
||||
ImGui::NextColumn();
|
||||
|
||||
uint32_t wL = m.weekGames > m.weekWins
|
||||
? m.weekGames - m.weekWins : 0;
|
||||
ImGui::Text("%uW/%uL", m.weekWins, wL);
|
||||
ImGui::NextColumn();
|
||||
|
||||
uint32_t sL = m.seasonGames > m.seasonWins
|
||||
? m.seasonGames - m.seasonWins : 0;
|
||||
ImGui::Text("%uW/%uL", m.seasonWins, sL);
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
ImGui::Columns(1);
|
||||
}
|
||||
|
||||
ImGui::Unindent(8.0f);
|
||||
|
||||
if (ai + 1 < arenaStats.size())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue