mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-27 01:00:13 +00:00
fix: direct CMSG_LOOT for chest GOs and increase M2 descriptor pools
Chest-type game objects (quest pickups, treasure chests) now send CMSG_LOOT directly with the GO GUID instead of CMSG_GAMEOBJ_USE + delayed CMSG_LOOT. The server's loot handler activates the GO and sends SMSG_LOOT_RESPONSE in one step. The old approach failed because CMSG_GAMEOBJ_USE opened+despawned the GO before CMSG_LOOT arrived. Double M2 bone and material descriptor pool sizes (8192 → 16384) to handle the increased NPC count from the spline parsing fix — patrolling NPCs that were previously invisible now spawn correctly, exhausting the old pool limits.
This commit is contained in:
parent
98cc282e7e
commit
8a617e842b
2 changed files with 43 additions and 61 deletions
|
|
@ -413,8 +413,8 @@ private:
|
|||
// Descriptor pools
|
||||
VkDescriptorPool materialDescPool_ = VK_NULL_HANDLE;
|
||||
VkDescriptorPool boneDescPool_ = VK_NULL_HANDLE;
|
||||
static constexpr uint32_t MAX_MATERIAL_SETS = 8192;
|
||||
static constexpr uint32_t MAX_BONE_SETS = 8192;
|
||||
static constexpr uint32_t MAX_MATERIAL_SETS = 16384;
|
||||
static constexpr uint32_t MAX_BONE_SETS = 16384;
|
||||
|
||||
// Dummy identity bone buffer + descriptor set for non-animated models.
|
||||
// The pipeline layout declares set 2 (bones) and some drivers (Intel ANV)
|
||||
|
|
|
|||
|
|
@ -21306,41 +21306,14 @@ void GameHandler::performGameObjectInteractionNow(uint64_t guid) {
|
|||
sendMovement(Opcode::MSG_MOVE_HEARTBEAT);
|
||||
}
|
||||
|
||||
auto packet = GameObjectUsePacket::build(guid);
|
||||
LOG_INFO("GO interaction: guid=0x", std::hex, guid, std::dec,
|
||||
" entry=", goEntry, " type=", goType,
|
||||
" name='", goName, "' wireOp=0x", std::hex, packet.getOpcode(), std::dec,
|
||||
" pktSize=", packet.getSize(),
|
||||
" dist=", entity ? std::sqrt(
|
||||
(entity->getX() - movementInfo.x) * (entity->getX() - movementInfo.x) +
|
||||
(entity->getY() - movementInfo.y) * (entity->getY() - movementInfo.y) +
|
||||
(entity->getZ() - movementInfo.z) * (entity->getZ() - movementInfo.z)) : -1.0f);
|
||||
socket->send(packet);
|
||||
lastInteractedGoGuid_ = guid;
|
||||
|
||||
// For mailbox GameObjects (type 19), open mail UI and request mail list.
|
||||
// In Vanilla/Classic there is no SMSG_SHOW_MAILBOX — the server just sends
|
||||
// animation/sound and expects the client to request the mail list.
|
||||
// Determine GO type for interaction strategy
|
||||
bool isMailbox = false;
|
||||
bool chestLike = false;
|
||||
// Do NOT send CMSG_LOOT after CMSG_GAMEOBJ_USE — the server handles loot
|
||||
// automatically as part of the USE handler. Sending a redundant CMSG_LOOT
|
||||
// triggers DoLootRelease() on the server, which closes the loot the server
|
||||
// just opened before the client ever sees SMSG_LOOT_RESPONSE.
|
||||
bool shouldSendLoot = false;
|
||||
if (entity && entity->getType() == ObjectType::GAMEOBJECT) {
|
||||
auto go = std::static_pointer_cast<GameObject>(entity);
|
||||
auto* info = getCachedGameObjectInfo(go->getEntry());
|
||||
if (info && info->type == 19) {
|
||||
isMailbox = true;
|
||||
shouldSendLoot = false;
|
||||
LOG_INFO("Mailbox interaction: opening mail UI and requesting mail list");
|
||||
mailboxGuid_ = guid;
|
||||
mailboxOpen_ = true;
|
||||
hasNewMail_ = false;
|
||||
selectedMailIndex_ = -1;
|
||||
showMailCompose_ = false;
|
||||
refreshMailList();
|
||||
} else if (info && info->type == 3) {
|
||||
chestLike = true;
|
||||
}
|
||||
|
|
@ -21353,40 +21326,49 @@ void GameHandler::performGameObjectInteractionNow(uint64_t guid) {
|
|||
lower.find("lockbox") != std::string::npos ||
|
||||
lower.find("strongbox") != std::string::npos ||
|
||||
lower.find("coffer") != std::string::npos ||
|
||||
lower.find("cache") != std::string::npos);
|
||||
lower.find("cache") != std::string::npos ||
|
||||
lower.find("bundle") != std::string::npos);
|
||||
}
|
||||
// Some servers require CMSG_GAMEOBJ_REPORT_USE for lootable gameobjects.
|
||||
// Only send it when the active opcode table actually supports it.
|
||||
if (!isMailbox) {
|
||||
const auto* table = getActiveOpcodeTable();
|
||||
if (table && table->hasOpcode(Opcode::CMSG_GAMEOBJ_REPORT_USE)) {
|
||||
network::Packet reportUse(wireOpcode(Opcode::CMSG_GAMEOBJ_REPORT_USE));
|
||||
reportUse.writeUInt64(guid);
|
||||
socket->send(reportUse);
|
||||
|
||||
LOG_INFO("GO interaction: guid=0x", std::hex, guid, std::dec,
|
||||
" entry=", goEntry, " type=", goType,
|
||||
" name='", goName, "' chestLike=", chestLike, " isMailbox=", isMailbox);
|
||||
|
||||
if (chestLike) {
|
||||
// For chest-like GOs (quest objects, treasure chests, etc.), send CMSG_LOOT
|
||||
// directly with the GO GUID — same as creature corpse looting. The server's
|
||||
// LOOT handler activates the GO, generates loot, and sends SMSG_LOOT_RESPONSE
|
||||
// in a single step. Sending CMSG_GAMEOBJ_USE + delayed CMSG_LOOT doesn't work
|
||||
// because the USE handler opens+despawns the GO before CMSG_LOOT arrives, and
|
||||
// CMSG_LOOT's DoLootRelease() closes any loot the USE handler already opened.
|
||||
lootTarget(guid);
|
||||
lastInteractedGoGuid_ = guid;
|
||||
} else {
|
||||
// Non-chest GOs (doors, buttons, quest givers, etc.): use CMSG_GAMEOBJ_USE
|
||||
auto packet = GameObjectUsePacket::build(guid);
|
||||
socket->send(packet);
|
||||
lastInteractedGoGuid_ = guid;
|
||||
|
||||
if (isMailbox) {
|
||||
LOG_INFO("Mailbox interaction: opening mail UI and requesting mail list");
|
||||
mailboxGuid_ = guid;
|
||||
mailboxOpen_ = true;
|
||||
hasNewMail_ = false;
|
||||
selectedMailIndex_ = -1;
|
||||
showMailCompose_ = false;
|
||||
refreshMailList();
|
||||
}
|
||||
|
||||
// CMSG_GAMEOBJ_REPORT_USE for GO AI scripts (quest givers, etc.)
|
||||
if (!isMailbox) {
|
||||
const auto* table = getActiveOpcodeTable();
|
||||
if (table && table->hasOpcode(Opcode::CMSG_GAMEOBJ_REPORT_USE)) {
|
||||
network::Packet reportUse(wireOpcode(Opcode::CMSG_GAMEOBJ_REPORT_USE));
|
||||
reportUse.writeUInt64(guid);
|
||||
socket->send(reportUse);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldSendLoot) {
|
||||
// Don't send CMSG_LOOT immediately — give the server time to process
|
||||
// CMSG_GAMEOBJ_USE first (chests need to transition to lootable state,
|
||||
// gathering nodes start a spell cast). A premature CMSG_LOOT can cause
|
||||
// an empty SMSG_LOOT_RESPONSE that clears our gather-cast loot state.
|
||||
pendingGameObjectLootOpens_.erase(
|
||||
std::remove_if(pendingGameObjectLootOpens_.begin(), pendingGameObjectLootOpens_.end(),
|
||||
[&](const PendingLootOpen& p) { return p.guid == guid; }),
|
||||
pendingGameObjectLootOpens_.end());
|
||||
// Short delay for chests (server makes them lootable quickly after USE),
|
||||
// plus a longer retry to catch slow state transitions.
|
||||
pendingGameObjectLootOpens_.push_back(PendingLootOpen{guid, 0.20f});
|
||||
pendingGameObjectLootOpens_.push_back(PendingLootOpen{guid, 0.75f});
|
||||
} else {
|
||||
// Non-lootable interaction (mailbox, door, button, etc.) — no CMSG_LOOT will be
|
||||
// sent, and no SMSG_LOOT_RESPONSE will arrive to clear it. Clear the gather-loot
|
||||
// guid now so a subsequent timed cast completion can't fire a spurious CMSG_LOOT.
|
||||
lastInteractedGoGuid_ = 0;
|
||||
}
|
||||
// Don't retry CMSG_GAMEOBJ_USE — resending can toggle chest state on some
|
||||
// servers (opening→closing the chest). The delayed CMSG_LOOT retries above
|
||||
// handle the case where the first loot attempt arrives too early.
|
||||
}
|
||||
|
||||
void GameHandler::selectGossipOption(uint32_t optionId) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue