Fix quest accept/abandon flow and expansion-specific accept packet format

Normalize WoW quest text tokens during parsing so quest titles/details no longer leak raw markup like  and |n into UI. Apply to WotLK and Classic parser paths, including quest list parsing in GameHandler.

Harden quest state handling by mapping abandon requests to authoritative server quest-log slots (PLAYER_QUEST_LOG_START) instead of local vector order, with a guarded fallback when update fields are unavailable.

Improve accept de-duplication by trusting server slot state over stale local cache; allow re-accept when local/server state diverges and trigger resync semantics.

Add expansion-aware CMSG_QUESTGIVER_ACCEPT_QUEST builders: WotLK sends guid+questId+unk1(uint32), while TBC/Classic/Turtle send guid+questId only. Wire GameHandler through PacketParsers for compatibility across expansions and cores.
This commit is contained in:
Kelsi 2026-02-20 23:20:02 -08:00
parent 73273a6ab5
commit ace24e8ccc
7 changed files with 125 additions and 34 deletions

View file

@ -1130,6 +1130,7 @@ private:
void clearPendingQuestAccept(uint32_t questId);
void triggerQuestAcceptResync(uint32_t questId, uint64_t npcGuid, const char* reason);
bool hasQuestInLog(uint32_t questId) const;
int findQuestLogSlotIndexFromServer(uint32_t questId) const;
void addQuestToLocalLogIfMissing(uint32_t questId, const std::string& title, const std::string& objectives);
bool resyncQuestLogFromServerSlots(bool forceQueryMetadata);
void handleListInventory(network::Packet& packet);

View file

@ -156,6 +156,12 @@ public:
return QuestgiverQueryQuestPacket::build(npcGuid, questId); // includes unk1
}
/** Build CMSG_QUESTGIVER_ACCEPT_QUEST.
* WotLK/AzerothCore expects trailing unk1 uint32; older expansions may not. */
virtual network::Packet buildAcceptQuestPacket(uint64_t npcGuid, uint32_t questId) {
return QuestgiverAcceptQuestPacket::build(npcGuid, questId);
}
/** Parse SMSG_QUESTGIVER_QUEST_DETAILS.
* WotLK has an extra informUnit GUID before questId; Vanilla/Classic do not. */
virtual bool parseQuestDetails(network::Packet& packet, QuestDetailsData& data) {
@ -279,6 +285,7 @@ public:
bool parseAuraUpdate(network::Packet& packet, AuraUpdateData& data, bool isAll = false) override;
bool parseNameQueryResponse(network::Packet& packet, NameQueryResponseData& data) override;
bool parseItemQueryResponse(network::Packet& packet, ItemQueryResponseData& data) override;
network::Packet buildAcceptQuestPacket(uint64_t npcGuid, uint32_t questId) override;
};
/**
@ -324,6 +331,7 @@ public:
bool parseItemQueryResponse(network::Packet& packet, ItemQueryResponseData& data) override;
uint8_t readQuestGiverStatus(network::Packet& packet) override;
network::Packet buildQueryQuestPacket(uint64_t npcGuid, uint32_t questId) override;
network::Packet buildAcceptQuestPacket(uint64_t npcGuid, uint32_t questId) override;
bool parseQuestDetails(network::Packet& packet, QuestDetailsData& data) override;
uint8_t questLogStride() const override { return 3; }
bool parseMonsterMove(network::Packet& packet, MonsterMoveData& data) override {

View file

@ -16,6 +16,9 @@
namespace wowee {
namespace game {
// Normalize WoW in-text tokens (e.g. "$B", "|n") into plain text suitable for UI.
std::string normalizeWowTextTokens(std::string text);
/**
* SMSG_AUTH_CHALLENGE data (from server)
*