feat: show kick target name and reason in LFG vote-kick UI

Parse the optional reason and target name strings from
SMSG_LFG_BOOT_PROPOSAL_UPDATE and display them in the Dungeon
Finder vote-kick section. Strings are cleared when the vote ends.
This commit is contained in:
Kelsi 2026-03-12 09:09:41 -07:00
parent d8d59dcdc8
commit c1a090a17c
3 changed files with 30 additions and 5 deletions

View file

@ -1120,10 +1120,12 @@ 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_; }
uint32_t getLfgBootVotes() const { return lfgBootVotes_; }
uint32_t getLfgBootTotal() const { return lfgBootTotal_; }
uint32_t getLfgBootTimeLeft() const { return lfgBootTimeLeft_; }
uint32_t getLfgBootNeeded() const { return lfgBootNeeded_; }
const std::string& getLfgBootTargetName() const { return lfgBootTargetName_; }
const std::string& getLfgBootReason() const { return lfgBootReason_; }
// ---- Arena Team Stats ----
struct ArenaTeamStats {
@ -2257,6 +2259,8 @@ private:
uint32_t lfgBootTotal_ = 0; // total votes cast
uint32_t lfgBootTimeLeft_ = 0; // seconds remaining
uint32_t lfgBootNeeded_ = 0; // votes needed to kick
std::string lfgBootTargetName_; // name of player being voted on
std::string lfgBootReason_; // reason given for kick
// Ready check state
bool pendingReadyCheck_ = false;

View file

@ -13111,11 +13111,19 @@ void GameHandler::handleLfgBootProposalUpdate(network::Packet& packet) {
lfgBootTimeLeft_ = timeLeft;
lfgBootNeeded_ = votesNeeded;
// Optional: reason string and target name (null-terminated) follow the fixed fields
if (packet.getSize() - packet.getReadPos() > 0)
lfgBootReason_ = packet.readString();
if (packet.getSize() - packet.getReadPos() > 0)
lfgBootTargetName_ = packet.readString();
if (inProgress) {
lfgState_ = LfgState::Boot;
} else {
// Boot vote ended — return to InDungeon state regardless of outcome
lfgBootVotes_ = lfgBootTotal_ = lfgBootTimeLeft_ = lfgBootNeeded_ = 0;
lfgBootTargetName_.clear();
lfgBootReason_.clear();
lfgState_ = LfgState::InDungeon;
if (myAnswer) {
addSystemChatMessage("Dungeon Finder: Vote kick passed — member removed.");
@ -13125,7 +13133,8 @@ void GameHandler::handleLfgBootProposalUpdate(network::Packet& packet) {
}
LOG_INFO("SMSG_LFG_BOOT_PROPOSAL_UPDATE: inProgress=", inProgress,
" bootVotes=", bootVotes, "/", totalVotes);
" bootVotes=", bootVotes, "/", totalVotes,
" target=", lfgBootTargetName_, " reason=", lfgBootReason_);
}
void GameHandler::handleLfgTeleportDenied(network::Packet& packet) {

View file

@ -16059,6 +16059,18 @@ 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:");
const std::string& bootTarget = gameHandler.getLfgBootTargetName();
const std::string& bootReason = gameHandler.getLfgBootReason();
if (!bootTarget.empty()) {
ImGui::Text("Player: ");
ImGui::SameLine();
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.3f, 1.0f), "%s", bootTarget.c_str());
}
if (!bootReason.empty()) {
ImGui::Text("Reason: ");
ImGui::SameLine();
ImGui::TextWrapped("%s", bootReason.c_str());
}
uint32_t bootVotes = gameHandler.getLfgBootVotes();
uint32_t bootTotal = gameHandler.getLfgBootTotal();
uint32_t bootNeeded = gameHandler.getLfgBootNeeded();