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

@ -705,7 +705,7 @@ bool ClassicPacketParsers::parseGossipMessage(network::Packet& packet, GossipMes
// Classic: NO questFlags, NO isRepeatable
quest.questFlags = 0;
quest.isRepeatable = 0;
quest.title = packet.readString();
quest.title = normalizeWowTextTokens(packet.readString());
data.quests.push_back(quest);
}
@ -1220,6 +1220,14 @@ network::Packet ClassicPacketParsers::buildQueryQuestPacket(uint64_t npcGuid, ui
return packet;
}
network::Packet ClassicPacketParsers::buildAcceptQuestPacket(uint64_t npcGuid, uint32_t questId) {
network::Packet packet(wireOpcode(Opcode::CMSG_QUESTGIVER_ACCEPT_QUEST));
packet.writeUInt64(npcGuid);
packet.writeUInt32(questId);
// Classic/Turtle: no trailing unk1 uint32
return packet;
}
// ============================================================================
// Classic SMSG_QUESTGIVER_QUEST_DETAILS — Vanilla 1.12 format
// WotLK inserts an informUnit GUID (8 bytes) between npcGuid and questId.
@ -1231,9 +1239,9 @@ bool ClassicPacketParsers::parseQuestDetails(network::Packet& packet, QuestDetai
data.npcGuid = packet.readUInt64();
// Vanilla: questId follows immediately — no informUnit GUID
data.questId = packet.readUInt32();
data.title = packet.readString();
data.details = packet.readString();
data.objectives = packet.readString();
data.title = normalizeWowTextTokens(packet.readString());
data.details = normalizeWowTextTokens(packet.readString());
data.objectives = normalizeWowTextTokens(packet.readString());
if (packet.getReadPos() + 5 > packet.getSize()) {
LOG_INFO("Quest details classic (short): id=", data.questId, " title='", data.title, "'");