Fix resurrect: correct packet routing and show caster name in dialog

Two bugs fixed:

1. acceptResurrect() was always sending CMSG_SPIRIT_HEALER_ACTIVATE even
   for player-cast resurrections (Priest/Paladin/Druid). That opcode is
   only the correct response to SMSG_SPIRIT_HEALER_CONFIRM. For
   SMSG_RESURRECT_REQUEST the server expects CMSG_RESURRECT_RESPONSE
   with accept=1. Added resurrectIsSpiritHealer_ to track which path
   triggered the dialog and send the right packet per type.

2. The resurrect dialog showed a generic "Return to life?" string
   regardless of who cast the resurrection. Parse the optional CString
   name from SMSG_RESURRECT_REQUEST (or fall back to playerNameCache)
   and display "X wishes to resurrect you." when the caster is known.
This commit is contained in:
Kelsi 2026-03-09 22:27:24 -07:00
parent ede380ec60
commit c6e39707de
3 changed files with 39 additions and 10 deletions

View file

@ -735,6 +735,7 @@ public:
bool isPlayerGhost() const { return releasedSpirit_; }
bool showDeathDialog() const { return playerDead_ && !releasedSpirit_; }
bool showResurrectDialog() const { return resurrectRequestPending_; }
const std::string& getResurrectCasterName() const { return resurrectCasterName_; }
void releaseSpirit();
void acceptResurrect();
void declineResurrect();
@ -2160,7 +2161,9 @@ private:
uint64_t pendingSpiritHealerGuid_ = 0;
bool resurrectPending_ = false;
bool resurrectRequestPending_ = false;
bool resurrectIsSpiritHealer_ = false; // true = SMSG_SPIRIT_HEALER_CONFIRM, false = SMSG_RESURRECT_REQUEST
uint64_t resurrectCasterGuid_ = 0;
std::string resurrectCasterName_;
bool repopPending_ = false;
uint64_t lastRepopRequestMs_ = 0;

View file

@ -2942,6 +2942,8 @@ void GameHandler::handlePacket(network::Packet& packet) {
LOG_INFO("Spirit healer confirm from 0x", std::hex, npcGuid, std::dec);
if (npcGuid) {
resurrectCasterGuid_ = npcGuid;
resurrectCasterName_ = "";
resurrectIsSpiritHealer_ = true;
resurrectRequestPending_ = true;
}
break;
@ -2952,9 +2954,22 @@ void GameHandler::handlePacket(network::Packet& packet) {
break;
}
uint64_t casterGuid = packet.readUInt64();
LOG_INFO("Resurrect request from 0x", std::hex, casterGuid, std::dec);
// Optional caster name (CString, may be absent on some server builds)
std::string casterName;
if (packet.getReadPos() < packet.getSize()) {
casterName = packet.readString();
}
LOG_INFO("Resurrect request from 0x", std::hex, casterGuid, std::dec,
" name='", casterName, "'");
if (casterGuid) {
resurrectCasterGuid_ = casterGuid;
resurrectIsSpiritHealer_ = false;
if (!casterName.empty()) {
resurrectCasterName_ = casterName;
} else {
auto nit = playerNameCache.find(casterGuid);
resurrectCasterName_ = (nit != playerNameCache.end()) ? nit->second : "";
}
resurrectRequestPending_ = true;
}
break;
@ -9455,11 +9470,19 @@ void GameHandler::activateSpiritHealer(uint64_t npcGuid) {
void GameHandler::acceptResurrect() {
if (state != WorldState::IN_WORLD || !socket || !resurrectRequestPending_) return;
// Send spirit healer activate (correct response to SMSG_SPIRIT_HEALER_CONFIRM)
auto activate = SpiritHealerActivatePacket::build(resurrectCasterGuid_);
socket->send(activate);
LOG_INFO("Sent CMSG_SPIRIT_HEALER_ACTIVATE (0x21C) for 0x",
std::hex, resurrectCasterGuid_, std::dec);
if (resurrectIsSpiritHealer_) {
// Spirit healer resurrection — SMSG_SPIRIT_HEALER_CONFIRM → CMSG_SPIRIT_HEALER_ACTIVATE
auto activate = SpiritHealerActivatePacket::build(resurrectCasterGuid_);
socket->send(activate);
LOG_INFO("Sent CMSG_SPIRIT_HEALER_ACTIVATE for 0x",
std::hex, resurrectCasterGuid_, std::dec);
} else {
// Player-cast resurrection — SMSG_RESURRECT_REQUEST → CMSG_RESURRECT_RESPONSE (accept=1)
auto resp = ResurrectResponsePacket::build(resurrectCasterGuid_, true);
socket->send(resp);
LOG_INFO("Sent CMSG_RESURRECT_RESPONSE (accept) for 0x",
std::hex, resurrectCasterGuid_, std::dec);
}
resurrectRequestPending_ = false;
resurrectPending_ = true;
}

View file

@ -7034,10 +7034,13 @@ void GameScreen::renderResurrectDialog(game::GameHandler& gameHandler) {
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar)) {
ImGui::Spacing();
const char* text = "Return to life?";
float textW = ImGui::CalcTextSize(text).x;
ImGui::SetCursorPosX((dlgW - textW) / 2);
ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f), "%s", text);
const std::string& casterName = gameHandler.getResurrectCasterName();
std::string text = casterName.empty()
? "Return to life?"
: casterName + " wishes to resurrect you.";
float textW = ImGui::CalcTextSize(text.c_str()).x;
ImGui::SetCursorPosX(std::max(4.0f, (dlgW - textW) / 2));
ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f), "%s", text.c_str());
ImGui::Spacing();
ImGui::Spacing();