diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index c418494a..4c6f325b 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -1061,6 +1061,10 @@ public: uint32_t getLfgProposalId() const { return lfgProposalId_; } int32_t getLfgAvgWaitSec() const { return lfgAvgWaitSec_; } uint32_t getLfgTimeInQueueMs() const { return lfgTimeInQueueMs_; } + uint32_t getLfgBootVotes() const { return lfgBootVotes_; } + uint32_t getLfgBootTotal() const { return lfgBootTotal_; } + uint32_t getLfgBootTimeLeft() const { return lfgBootTimeLeft_; } + uint32_t getLfgBootNeeded() const { return lfgBootNeeded_; } // ---- Phase 5: Loot ---- void lootTarget(uint64_t guid); @@ -2128,6 +2132,10 @@ private: uint32_t lfgProposalId_ = 0; // pending proposal id (0 = none) int32_t lfgAvgWaitSec_ = -1; // estimated wait, -1=unknown uint32_t lfgTimeInQueueMs_= 0; // ms already in queue + uint32_t lfgBootVotes_ = 0; // current boot-yes votes + uint32_t lfgBootTotal_ = 0; // total votes cast + uint32_t lfgBootTimeLeft_ = 0; // seconds remaining + uint32_t lfgBootNeeded_ = 0; // votes needed to kick // Ready check state bool pendingReadyCheck_ = false; diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 10cd17a6..8157d44c 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -5001,10 +5001,34 @@ void GameHandler::handlePacket(network::Packet& packet) { case Opcode::MSG_QUERY_NEXT_MAIL_TIME: handleQueryNextMailTime(packet); break; - case Opcode::SMSG_CHANNEL_LIST: - // Channel member listing currently not rendered in UI. - packet.setReadPos(packet.getSize()); + case Opcode::SMSG_CHANNEL_LIST: { + // string channelName + uint8 flags + uint32 count + count×(uint64 guid + uint8 memberFlags) + std::string chanName = packet.readString(); + if (packet.getSize() - packet.getReadPos() < 5) break; + /*uint8_t chanFlags =*/ packet.readUInt8(); + uint32_t memberCount = packet.readUInt32(); + memberCount = std::min(memberCount, 200u); + addSystemChatMessage(chanName + " has " + std::to_string(memberCount) + " member(s):"); + for (uint32_t i = 0; i < memberCount; ++i) { + if (packet.getSize() - packet.getReadPos() < 9) break; + uint64_t memberGuid = packet.readUInt64(); + uint8_t memberFlags = packet.readUInt8(); + // Look up the name from our entity manager + auto entity = entityManager.getEntity(memberGuid); + std::string name = "(unknown)"; + if (entity) { + auto player = std::dynamic_pointer_cast(entity); + if (player && !player->getName().empty()) name = player->getName(); + } + std::string entry = " " + name; + if (memberFlags & 0x01) entry += " [Moderator]"; + if (memberFlags & 0x02) entry += " [Muted]"; + addSystemChatMessage(entry); + LOG_DEBUG(" channel member: 0x", std::hex, memberGuid, std::dec, + " flags=", (int)memberFlags, " name=", name); + } break; + } case Opcode::SMSG_INSPECT_RESULTS_UPDATE: handleInspectResults(packet); break; @@ -12971,15 +12995,18 @@ void GameHandler::handleLfgBootProposalUpdate(network::Packet& packet) { uint32_t timeLeft = packet.readUInt32(); uint32_t votesNeeded = packet.readUInt32(); - (void)myVote; (void)totalVotes; (void)bootVotes; (void)timeLeft; (void)votesNeeded; + (void)myVote; + + lfgBootVotes_ = bootVotes; + lfgBootTotal_ = totalVotes; + lfgBootTimeLeft_ = timeLeft; + lfgBootNeeded_ = votesNeeded; if (inProgress) { lfgState_ = LfgState::Boot; - addSystemChatMessage( - std::string("Dungeon Finder: Vote to kick in progress (") + - std::to_string(timeLeft) + "s remaining)."); } else { // Boot vote ended — return to InDungeon state regardless of outcome + lfgBootVotes_ = lfgBootTotal_ = lfgBootTimeLeft_ = lfgBootNeeded_ = 0; lfgState_ = LfgState::InDungeon; if (myAnswer) { addSystemChatMessage("Dungeon Finder: Vote kick passed — member removed."); diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index f8f95801..b9232000 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -7973,8 +7973,7 @@ void GameScreen::renderSocialFrame(game::GameHandler& gameHandler) { if (c.isFriend() && c.isOnline()) ++onlineCount; auto* window = core::Application::getInstance().getWindow(); - float screenW = window ? static_cast(window->getWidth()) : 1280.0f; - float screenH = window ? static_cast(window->getHeight()) : 720.0f; + float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW - 230.0f, 240.0f), ImGuiCond_Once); ImGui::SetNextWindowSize(ImVec2(220.0f, 0.0f), ImGuiCond_Always); @@ -13983,6 +13982,14 @@ void GameScreen::renderDungeonFinderWindow(game::GameHandler& gameHandler) { // ---- Vote-to-kick buttons ---- if (state == LfgState::Boot) { ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "Vote to kick in progress:"); + uint32_t bootVotes = gameHandler.getLfgBootVotes(); + uint32_t bootTotal = gameHandler.getLfgBootTotal(); + uint32_t bootNeeded = gameHandler.getLfgBootNeeded(); + uint32_t bootTimeLeft= gameHandler.getLfgBootTimeLeft(); + if (bootNeeded > 0) { + ImGui::Text("Votes: %u / %u (need %u) %us left", + bootVotes, bootTotal, bootNeeded, bootTimeLeft); + } ImGui::Spacing(); if (ImGui::Button("Vote Yes (kick)", ImVec2(140, 0))) { gameHandler.lfgSetBootVote(true);