mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-14 00:23:50 +00:00
fix(quest): quest log population, NPC marker updates on accept/abandon
- Delegate GameHandler::getQuestGiverStatus() to QuestHandler instead of reading from GameHandler's own empty npcQuestStatus_ map - Immediately add quest to local log in acceptQuest() instead of waiting for field updates, fixing quests not appearing after accept - Handle duplicate accept path (server already has quest) by also adding to local log - Remove early return on empty questLog_ in applyQuestStateFromFields() - Re-query nearby quest giver NPC statuses on abandon so markers refresh Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
This commit is contained in:
parent
9c1ffae140
commit
759d6046bb
3 changed files with 49 additions and 7 deletions
|
|
@ -1699,10 +1699,7 @@ public:
|
|||
bool isServerMovementAllowed() const;
|
||||
|
||||
// Quest giver status (! and ? markers)
|
||||
QuestGiverStatus getQuestGiverStatus(uint64_t guid) const {
|
||||
auto it = npcQuestStatus_.find(guid);
|
||||
return (it != npcQuestStatus_.end()) ? it->second : QuestGiverStatus::NONE;
|
||||
}
|
||||
QuestGiverStatus getQuestGiverStatus(uint64_t guid) const;
|
||||
const std::unordered_map<uint64_t, QuestGiverStatus>& getNpcQuestStatuses() const;
|
||||
|
||||
// Charge callback — fires when player casts a charge spell toward target
|
||||
|
|
|
|||
|
|
@ -2261,6 +2261,10 @@ const std::unordered_map<uint64_t, QuestGiverStatus>& GameHandler::getNpcQuestSt
|
|||
static const std::unordered_map<uint64_t, QuestGiverStatus> empty;
|
||||
return empty;
|
||||
}
|
||||
QuestGiverStatus GameHandler::getQuestGiverStatus(uint64_t guid) const {
|
||||
if (questHandler_) return questHandler_->getQuestGiverStatus(guid);
|
||||
return QuestGiverStatus::NONE;
|
||||
}
|
||||
const std::vector<GameHandler::QuestLogEntry>& GameHandler::getQuestLog() const {
|
||||
if (questHandler_) return questHandler_->getQuestLog();
|
||||
static const std::vector<QuestLogEntry> empty;
|
||||
|
|
|
|||
|
|
@ -339,6 +339,8 @@ void QuestHandler::registerOpcodes(DispatchTable& table) {
|
|||
if (packet.hasRemaining(9)) {
|
||||
uint64_t npcGuid = packet.readUInt64();
|
||||
uint8_t status = owner_.getPacketParsers()->readQuestGiverStatus(packet);
|
||||
LOG_INFO("SMSG_QUESTGIVER_STATUS: npcGuid=0x", std::hex, npcGuid, std::dec,
|
||||
" status=", static_cast<int>(status));
|
||||
npcQuestStatus_[npcGuid] = static_cast<QuestGiverStatus>(status);
|
||||
}
|
||||
};
|
||||
|
|
@ -1075,8 +1077,17 @@ void QuestHandler::acceptQuest() {
|
|||
const bool inLocalLog = hasQuestInLog(questId);
|
||||
const int serverSlot = findQuestLogSlotIndexFromServer(questId);
|
||||
if (serverSlot >= 0) {
|
||||
LOG_INFO("Ignoring duplicate quest accept already in server quest log: questId=", questId,
|
||||
" slot=", serverSlot);
|
||||
LOG_INFO("Quest already in server quest log: questId=", questId,
|
||||
" slot=", serverSlot, " inLocalLog=", inLocalLog);
|
||||
// Ensure it's in our local log even if server already has it
|
||||
addQuestToLocalLogIfMissing(questId, currentQuestDetails_.title, currentQuestDetails_.objectives);
|
||||
requestQuestQuery(questId, false);
|
||||
// Re-query NPC status from server
|
||||
if (npcGuid && owner_.getSocket()) {
|
||||
network::Packet qsPkt(wireOpcode(Opcode::CMSG_QUESTGIVER_STATUS_QUERY));
|
||||
qsPkt.writeUInt64(npcGuid);
|
||||
owner_.getSocket()->send(qsPkt);
|
||||
}
|
||||
questDetailsOpen_ = false;
|
||||
questDetailsOpenTime_ = std::chrono::steady_clock::time_point{};
|
||||
currentQuestDetails_ = QuestDetailsData{};
|
||||
|
|
@ -1094,6 +1105,9 @@ void QuestHandler::acceptQuest() {
|
|||
pendingQuestAcceptTimeouts_[questId] = 5.0f;
|
||||
pendingQuestAcceptNpcGuids_[questId] = npcGuid;
|
||||
|
||||
// Immediately add to local quest log using available details
|
||||
addQuestToLocalLogIfMissing(questId, currentQuestDetails_.title, currentQuestDetails_.objectives);
|
||||
|
||||
// Play quest-accept sound
|
||||
if (auto* ac = owner_.services().audioCoordinator) {
|
||||
if (auto* sfx = ac->getUiSoundManager())
|
||||
|
|
@ -1223,6 +1237,19 @@ void QuestHandler::abandonQuest(uint32_t questId) {
|
|||
}
|
||||
}
|
||||
|
||||
// Re-query nearby quest giver NPCs so markers refresh (e.g. "?" → "!")
|
||||
if (owner_.getSocket()) {
|
||||
for (const auto& [guid, entity] : owner_.getEntityManager().getEntities()) {
|
||||
if (entity->getType() != ObjectType::UNIT) continue;
|
||||
auto unit = std::static_pointer_cast<Unit>(entity);
|
||||
if (unit->getNpcFlags() & 0x02) {
|
||||
network::Packet qsPkt(wireOpcode(Opcode::CMSG_QUESTGIVER_STATUS_QUERY));
|
||||
qsPkt.writeUInt64(guid);
|
||||
owner_.getSocket()->send(qsPkt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any quest POI minimap markers for this quest.
|
||||
gossipPois_.erase(
|
||||
std::remove_if(gossipPois_.begin(), gossipPois_.end(),
|
||||
|
|
@ -1376,7 +1403,7 @@ bool QuestHandler::resyncQuestLogFromServerSlots(bool forceQueryMetadata) {
|
|||
|
||||
void QuestHandler::applyQuestStateFromFields(const std::map<uint16_t, uint32_t>& fields) {
|
||||
const uint16_t ufQuestStart = fieldIndex(UF::PLAYER_QUEST_LOG_START);
|
||||
if (ufQuestStart == 0xFFFF || questLog_.empty()) return;
|
||||
if (ufQuestStart == 0xFFFF) return;
|
||||
|
||||
const uint8_t qStride = owner_.getPacketParsers() ? owner_.getPacketParsers()->questLogStride() : 5;
|
||||
if (qStride < 2) return;
|
||||
|
|
@ -1391,6 +1418,20 @@ void QuestHandler::applyQuestStateFromFields(const std::map<uint16_t, uint32_t>&
|
|||
uint32_t questId = idIt->second;
|
||||
if (questId == 0) continue;
|
||||
|
||||
// Add quest to local log only if we have a pending accept for it
|
||||
if (!hasQuestInLog(questId) && pendingQuestAcceptTimeouts_.count(questId) != 0) {
|
||||
addQuestToLocalLogIfMissing(questId, "Quest #" + std::to_string(questId), "");
|
||||
requestQuestQuery(questId, false);
|
||||
// Re-query quest giver status for the NPC that gave us this quest
|
||||
auto pendingIt = pendingQuestAcceptNpcGuids_.find(questId);
|
||||
if (pendingIt != pendingQuestAcceptNpcGuids_.end() && pendingIt->second != 0 && owner_.getSocket()) {
|
||||
network::Packet qsPkt(wireOpcode(Opcode::CMSG_QUESTGIVER_STATUS_QUERY));
|
||||
qsPkt.writeUInt64(pendingIt->second);
|
||||
owner_.getSocket()->send(qsPkt);
|
||||
}
|
||||
clearPendingQuestAccept(questId);
|
||||
}
|
||||
|
||||
auto stateIt = fields.find(stateField);
|
||||
if (stateIt == fields.end()) continue;
|
||||
bool serverComplete = ((stateIt->second & 0xFF) == kQuestStatusComplete);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue