mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
feat: add /who results window with sortable player table
Store structured WhoEntry data from SMSG_WHO responses and show them in a dedicated popup window with Name/Guild/Level/Class/Zone columns. Right-click on any row to Whisper, Invite, Add Friend, or Ignore. Window auto-opens when /who or /whois is typed; shows online count in the title bar. Results persist until the next /who query.
This commit is contained in:
parent
2f0fe302bc
commit
367390a852
4 changed files with 137 additions and 14 deletions
|
|
@ -353,6 +353,19 @@ public:
|
|||
uint32_t getTotalTimePlayed() const { return totalTimePlayed_; }
|
||||
uint32_t getLevelTimePlayed() const { return levelTimePlayed_; }
|
||||
|
||||
// Who results (structured, from last SMSG_WHO response)
|
||||
struct WhoEntry {
|
||||
std::string name;
|
||||
std::string guildName;
|
||||
uint32_t level = 0;
|
||||
uint32_t classId = 0;
|
||||
uint32_t raceId = 0;
|
||||
uint32_t zoneId = 0;
|
||||
};
|
||||
const std::vector<WhoEntry>& getWhoResults() const { return whoResults_; }
|
||||
uint32_t getWhoOnlineCount() const { return whoOnlineCount_; }
|
||||
std::string getWhoAreaName(uint32_t zoneId) const { return getAreaName(zoneId); }
|
||||
|
||||
// Social commands
|
||||
void addFriend(const std::string& playerName, const std::string& note = "");
|
||||
void removeFriend(const std::string& playerName);
|
||||
|
|
@ -2303,6 +2316,10 @@ private:
|
|||
uint32_t totalTimePlayed_ = 0;
|
||||
uint32_t levelTimePlayed_ = 0;
|
||||
|
||||
// Who results (last SMSG_WHO response)
|
||||
std::vector<WhoEntry> whoResults_;
|
||||
uint32_t whoOnlineCount_ = 0;
|
||||
|
||||
// Trade state
|
||||
TradeStatus tradeStatus_ = TradeStatus::None;
|
||||
uint64_t tradePeerGuid_= 0;
|
||||
|
|
|
|||
|
|
@ -396,6 +396,10 @@ private:
|
|||
int bagBarPickedSlot_ = -1; // Visual drag in progress (-1 = none)
|
||||
int bagBarDragSource_ = -1; // Mouse pressed on this slot, waiting for drag or click (-1 = none)
|
||||
|
||||
// Who Results window
|
||||
bool showWhoWindow_ = false;
|
||||
void renderWhoWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// Instance Lockouts window
|
||||
bool showInstanceLockouts_ = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -18352,13 +18352,15 @@ void GameHandler::handleWho(network::Packet& packet) {
|
|||
|
||||
LOG_INFO("WHO response: ", displayCount, " players displayed, ", onlineCount, " total online");
|
||||
|
||||
// Store structured results for the who-results window
|
||||
whoResults_.clear();
|
||||
whoOnlineCount_ = onlineCount;
|
||||
|
||||
if (displayCount == 0) {
|
||||
addSystemChatMessage("No players found.");
|
||||
return;
|
||||
}
|
||||
|
||||
addSystemChatMessage(std::to_string(onlineCount) + " player(s) online:");
|
||||
|
||||
for (uint32_t i = 0; i < displayCount; ++i) {
|
||||
if (packet.getReadPos() >= packet.getSize()) break;
|
||||
std::string playerName = packet.readString();
|
||||
|
|
@ -18373,19 +18375,16 @@ void GameHandler::handleWho(network::Packet& packet) {
|
|||
if (packet.getSize() - packet.getReadPos() >= 4)
|
||||
zoneId = packet.readUInt32();
|
||||
|
||||
const char* className = getClassName(static_cast<Class>(classId));
|
||||
// Store structured entry
|
||||
WhoEntry entry;
|
||||
entry.name = playerName;
|
||||
entry.guildName = guildName;
|
||||
entry.level = level;
|
||||
entry.classId = classId;
|
||||
entry.raceId = raceId;
|
||||
entry.zoneId = zoneId;
|
||||
whoResults_.push_back(std::move(entry));
|
||||
|
||||
std::string msg = " " + playerName;
|
||||
if (!guildName.empty())
|
||||
msg += " <" + guildName + ">";
|
||||
msg += " - Level " + std::to_string(level) + " " + className;
|
||||
if (zoneId != 0) {
|
||||
std::string zoneName = getAreaName(zoneId);
|
||||
if (!zoneName.empty())
|
||||
msg += " [" + zoneName + "]";
|
||||
}
|
||||
|
||||
addSystemChatMessage(msg);
|
||||
LOG_INFO(" ", playerName, " (", guildName, ") Lv", level, " Class:", classId,
|
||||
" Race:", raceId, " Zone:", zoneId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "pipeline/dbc_layout.hpp"
|
||||
|
||||
#include "game/expansion_profile.hpp"
|
||||
#include "game/character.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
|
@ -596,6 +597,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
|||
renderAuctionHouseWindow(gameHandler);
|
||||
renderDungeonFinderWindow(gameHandler);
|
||||
renderInstanceLockouts(gameHandler);
|
||||
renderWhoWindow(gameHandler);
|
||||
renderAchievementWindow(gameHandler);
|
||||
renderGmTicketWindow(gameHandler);
|
||||
renderInspectWindow(gameHandler);
|
||||
|
|
@ -4040,6 +4042,7 @@ void GameScreen::sendChatMessage(game::GameHandler& gameHandler) {
|
|||
}
|
||||
|
||||
gameHandler.queryWho(query);
|
||||
showWhoWindow_ = true;
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
|
@ -16838,6 +16841,106 @@ void GameScreen::renderBattlegroundScore(game::GameHandler& gameHandler) {
|
|||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
// ─── Who Results Window ───────────────────────────────────────────────────────
|
||||
void GameScreen::renderWhoWindow(game::GameHandler& gameHandler) {
|
||||
if (!showWhoWindow_) return;
|
||||
|
||||
const auto& results = gameHandler.getWhoResults();
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(500, 300), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImVec2(200, 180), ImGuiCond_FirstUseEver);
|
||||
|
||||
char title[64];
|
||||
uint32_t onlineCount = gameHandler.getWhoOnlineCount();
|
||||
if (onlineCount > 0)
|
||||
snprintf(title, sizeof(title), "Players Online: %u###WhoWindow", onlineCount);
|
||||
else
|
||||
snprintf(title, sizeof(title), "Who###WhoWindow");
|
||||
|
||||
if (!ImGui::Begin(title, &showWhoWindow_)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.empty()) {
|
||||
ImGui::TextDisabled("No results. Use /who [filter] to search.");
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
// Table: Name | Guild | Level | Class | Zone
|
||||
if (ImGui::BeginTable("##WhoTable", 5,
|
||||
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
|
||||
ImGuiTableFlags_ScrollY | ImGuiTableFlags_SizingStretchProp,
|
||||
ImVec2(0, 0))) {
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.22f);
|
||||
ImGui::TableSetupColumn("Guild", ImGuiTableColumnFlags_WidthStretch, 0.20f);
|
||||
ImGui::TableSetupColumn("Level", ImGuiTableColumnFlags_WidthFixed, 40.0f);
|
||||
ImGui::TableSetupColumn("Class", ImGuiTableColumnFlags_WidthStretch, 0.20f);
|
||||
ImGui::TableSetupColumn("Zone", ImGuiTableColumnFlags_WidthStretch, 0.28f);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (size_t i = 0; i < results.size(); ++i) {
|
||||
const auto& e = results[i];
|
||||
ImGui::TableNextRow();
|
||||
ImGui::PushID(static_cast<int>(i));
|
||||
|
||||
// Name (class-colored if class is known)
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
uint8_t cid = static_cast<uint8_t>(e.classId);
|
||||
ImVec4 nameCol = classColorVec4(cid);
|
||||
ImGui::TextColored(nameCol, "%s", e.name.c_str());
|
||||
|
||||
// Right-click context menu on the name
|
||||
if (ImGui::BeginPopupContextItem("##WhoCtx")) {
|
||||
ImGui::TextDisabled("%s", e.name.c_str());
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Whisper")) {
|
||||
selectedChatType = 4;
|
||||
strncpy(whisperTargetBuffer, e.name.c_str(), sizeof(whisperTargetBuffer) - 1);
|
||||
whisperTargetBuffer[sizeof(whisperTargetBuffer) - 1] = '\0';
|
||||
refocusChatInput = true;
|
||||
}
|
||||
if (ImGui::MenuItem("Invite to Group"))
|
||||
gameHandler.inviteToGroup(e.name);
|
||||
if (ImGui::MenuItem("Add Friend"))
|
||||
gameHandler.addFriend(e.name);
|
||||
if (ImGui::MenuItem("Ignore"))
|
||||
gameHandler.addIgnore(e.name);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Guild
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
if (!e.guildName.empty())
|
||||
ImGui::TextDisabled("<%s>", e.guildName.c_str());
|
||||
|
||||
// Level
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
ImGui::Text("%u", e.level);
|
||||
|
||||
// Class
|
||||
ImGui::TableSetColumnIndex(3);
|
||||
const char* className = game::getClassName(static_cast<game::Class>(e.classId));
|
||||
ImGui::TextColored(nameCol, "%s", className);
|
||||
|
||||
// Zone
|
||||
ImGui::TableSetColumnIndex(4);
|
||||
if (e.zoneId != 0) {
|
||||
std::string zoneName = gameHandler.getWhoAreaName(e.zoneId);
|
||||
ImGui::TextUnformatted(zoneName.empty() ? "Unknown" : zoneName.c_str());
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// ─── Achievement Window ───────────────────────────────────────────────────────
|
||||
void GameScreen::renderAchievementWindow(game::GameHandler& gameHandler) {
|
||||
if (!showAchievementWindow_) return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue