mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-26 13:13:50 +00:00
feat: show guild names on player nameplates
Read PLAYER_GUILDID from entity update fields (UNIT_END + 3) and query guild names via CMSG_GUILD_QUERY. Cache results in guildNameCache_ so each guild ID is queried only once. Display <Guild Name> in grey below the player name on nameplates. Fix handleGuildQueryResponse to not overwrite the local player's guild data when querying other guilds.
This commit is contained in:
parent
003ad8b20c
commit
e572cdfb4a
3 changed files with 76 additions and 11 deletions
|
|
@ -608,6 +608,13 @@ public:
|
||||||
uint32_t getPetitionCost() const { return petitionCost_; }
|
uint32_t getPetitionCost() const { return petitionCost_; }
|
||||||
uint64_t getPetitionNpcGuid() const { return petitionNpcGuid_; }
|
uint64_t getPetitionNpcGuid() const { return petitionNpcGuid_; }
|
||||||
|
|
||||||
|
// Guild name lookup for other players' nameplates
|
||||||
|
// Returns the guild name for a given guildId, or empty if unknown.
|
||||||
|
// Automatically queries the server for unknown guild IDs.
|
||||||
|
const std::string& lookupGuildName(uint32_t guildId);
|
||||||
|
// Returns the guildId for a player entity (from PLAYER_GUILDID update field).
|
||||||
|
uint32_t getEntityGuildId(uint64_t guid) const;
|
||||||
|
|
||||||
// Ready check
|
// Ready check
|
||||||
struct ReadyCheckResult {
|
struct ReadyCheckResult {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
@ -2952,6 +2959,8 @@ private:
|
||||||
GuildInfoData guildInfoData_;
|
GuildInfoData guildInfoData_;
|
||||||
GuildQueryResponseData guildQueryData_;
|
GuildQueryResponseData guildQueryData_;
|
||||||
bool hasGuildRoster_ = false;
|
bool hasGuildRoster_ = false;
|
||||||
|
std::unordered_map<uint32_t, std::string> guildNameCache_; // guildId → guild name
|
||||||
|
std::unordered_set<uint32_t> pendingGuildNameQueries_; // in-flight guild queries
|
||||||
bool pendingGuildInvite_ = false;
|
bool pendingGuildInvite_ = false;
|
||||||
std::string pendingGuildInviterName_;
|
std::string pendingGuildInviterName_;
|
||||||
std::string pendingGuildInviteGuildName_;
|
std::string pendingGuildInviteGuildName_;
|
||||||
|
|
|
||||||
|
|
@ -759,6 +759,8 @@ void GameHandler::disconnect() {
|
||||||
activeCharacterGuid_ = 0;
|
activeCharacterGuid_ = 0;
|
||||||
playerNameCache.clear();
|
playerNameCache.clear();
|
||||||
pendingNameQueries.clear();
|
pendingNameQueries.clear();
|
||||||
|
guildNameCache_.clear();
|
||||||
|
pendingGuildNameQueries_.clear();
|
||||||
friendGuids_.clear();
|
friendGuids_.clear();
|
||||||
contacts_.clear();
|
contacts_.clear();
|
||||||
transportAttachments_.clear();
|
transportAttachments_.clear();
|
||||||
|
|
@ -19577,6 +19579,28 @@ void GameHandler::queryGuildInfo(uint32_t guildId) {
|
||||||
LOG_INFO("Querying guild info: guildId=", guildId);
|
LOG_INFO("Querying guild info: guildId=", guildId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const std::string kEmptyString;
|
||||||
|
|
||||||
|
const std::string& GameHandler::lookupGuildName(uint32_t guildId) {
|
||||||
|
if (guildId == 0) return kEmptyString;
|
||||||
|
auto it = guildNameCache_.find(guildId);
|
||||||
|
if (it != guildNameCache_.end()) return it->second;
|
||||||
|
// Query the server if we haven't already
|
||||||
|
if (pendingGuildNameQueries_.insert(guildId).second) {
|
||||||
|
queryGuildInfo(guildId);
|
||||||
|
}
|
||||||
|
return kEmptyString;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GameHandler::getEntityGuildId(uint64_t guid) const {
|
||||||
|
auto entity = entityManager.getEntity(guid);
|
||||||
|
if (!entity || entity->getType() != ObjectType::PLAYER) return 0;
|
||||||
|
// PLAYER_GUILDID = UNIT_END + 3 across all expansions
|
||||||
|
const uint16_t ufUnitEnd = fieldIndex(UF::UNIT_END);
|
||||||
|
if (ufUnitEnd == 0xFFFF) return 0;
|
||||||
|
return entity->getField(ufUnitEnd + 3);
|
||||||
|
}
|
||||||
|
|
||||||
void GameHandler::createGuild(const std::string& guildName) {
|
void GameHandler::createGuild(const std::string& guildName) {
|
||||||
if (state != WorldState::IN_WORLD || !socket) return;
|
if (state != WorldState::IN_WORLD || !socket) return;
|
||||||
auto packet = GuildCreatePacket::build(guildName);
|
auto packet = GuildCreatePacket::build(guildName);
|
||||||
|
|
@ -19661,18 +19685,30 @@ void GameHandler::handleGuildQueryResponse(network::Packet& packet) {
|
||||||
GuildQueryResponseData data;
|
GuildQueryResponseData data;
|
||||||
if (!packetParsers_->parseGuildQueryResponse(packet, data)) return;
|
if (!packetParsers_->parseGuildQueryResponse(packet, data)) return;
|
||||||
|
|
||||||
const bool wasUnknown = guildName_.empty();
|
// Always cache the guild name for nameplate lookups
|
||||||
guildName_ = data.guildName;
|
if (data.guildId != 0 && !data.guildName.empty()) {
|
||||||
guildQueryData_ = data;
|
guildNameCache_[data.guildId] = data.guildName;
|
||||||
guildRankNames_.clear();
|
pendingGuildNameQueries_.erase(data.guildId);
|
||||||
for (uint32_t i = 0; i < 10; ++i) {
|
}
|
||||||
guildRankNames_.push_back(data.rankNames[i]);
|
|
||||||
|
// Check if this is the local player's guild
|
||||||
|
const Character* ch = getActiveCharacter();
|
||||||
|
bool isLocalGuild = (ch && ch->hasGuild() && ch->guildId == data.guildId);
|
||||||
|
|
||||||
|
if (isLocalGuild) {
|
||||||
|
const bool wasUnknown = guildName_.empty();
|
||||||
|
guildName_ = data.guildName;
|
||||||
|
guildQueryData_ = data;
|
||||||
|
guildRankNames_.clear();
|
||||||
|
for (uint32_t i = 0; i < 10; ++i) {
|
||||||
|
guildRankNames_.push_back(data.rankNames[i]);
|
||||||
|
}
|
||||||
|
LOG_INFO("Guild name set to: ", guildName_);
|
||||||
|
if (wasUnknown && !guildName_.empty())
|
||||||
|
addSystemChatMessage("Guild: <" + guildName_ + ">");
|
||||||
|
} else {
|
||||||
|
LOG_INFO("Cached guild name: id=", data.guildId, " name=", data.guildName);
|
||||||
}
|
}
|
||||||
LOG_INFO("Guild name set to: ", guildName_);
|
|
||||||
// Only announce once — when we first learn our own guild name at login.
|
|
||||||
// Subsequent queries (e.g. querying other players' guilds) are silent.
|
|
||||||
if (wasUnknown && !guildName_.empty())
|
|
||||||
addSystemChatMessage("Guild: <" + guildName_ + ">");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameHandler::handleGuildEvent(network::Packet& packet) {
|
void GameHandler::handleGuildEvent(network::Packet& packet) {
|
||||||
|
|
|
||||||
|
|
@ -11125,9 +11125,29 @@ void GameScreen::renderNameplates(game::GameHandler& gameHandler) {
|
||||||
? IM_COL32(220, 80, 80, A(230)) // red — hostile NPC
|
? IM_COL32(220, 80, 80, A(230)) // red — hostile NPC
|
||||||
: IM_COL32(240, 200, 100, A(230)); // yellow — friendly NPC
|
: IM_COL32(240, 200, 100, A(230)); // yellow — friendly NPC
|
||||||
}
|
}
|
||||||
|
// Guild name for player nameplates: shift name up to make room
|
||||||
|
std::string guildTag;
|
||||||
|
if (isPlayer) {
|
||||||
|
uint32_t guildId = gameHandler.getEntityGuildId(guid);
|
||||||
|
if (guildId != 0) {
|
||||||
|
const std::string& gn = gameHandler.lookupGuildName(guildId);
|
||||||
|
if (!gn.empty()) guildTag = "<" + gn + ">";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!guildTag.empty()) nameY -= 10.0f; // shift name up for guild line
|
||||||
|
|
||||||
drawList->AddText(ImVec2(nameX + 1.0f, nameY + 1.0f), IM_COL32(0, 0, 0, A(160)), labelBuf);
|
drawList->AddText(ImVec2(nameX + 1.0f, nameY + 1.0f), IM_COL32(0, 0, 0, A(160)), labelBuf);
|
||||||
drawList->AddText(ImVec2(nameX, nameY), nameColor, labelBuf);
|
drawList->AddText(ImVec2(nameX, nameY), nameColor, labelBuf);
|
||||||
|
|
||||||
|
// Guild tag below the name (WoW-style <Guild Name> in lighter color)
|
||||||
|
if (!guildTag.empty()) {
|
||||||
|
ImVec2 guildSz = ImGui::CalcTextSize(guildTag.c_str());
|
||||||
|
float guildX = sx - guildSz.x * 0.5f;
|
||||||
|
float guildY = nameY + textSize.y + 1.0f;
|
||||||
|
drawList->AddText(ImVec2(guildX + 1.0f, guildY + 1.0f), IM_COL32(0, 0, 0, A(120)), guildTag.c_str());
|
||||||
|
drawList->AddText(ImVec2(guildX, guildY), IM_COL32(180, 180, 180, A(200)), guildTag.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
// Group leader crown to the right of the name on player nameplates
|
// Group leader crown to the right of the name on player nameplates
|
||||||
if (isPlayer && gameHandler.isInGroup() &&
|
if (isPlayer && gameHandler.isInGroup() &&
|
||||||
gameHandler.getPartyData().leaderGuid == guid) {
|
gameHandler.getPartyData().leaderGuid == guid) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue