Reduce update-object and inventory update overhead

This commit is contained in:
Kelsi 2026-02-22 08:37:02 -08:00
parent 37888c666d
commit 0631b9f5dc
2 changed files with 71 additions and 48 deletions

View file

@ -4750,7 +4750,9 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
// Process out-of-range objects first // Process out-of-range objects first
for (uint64_t guid : data.outOfRangeGuids) { for (uint64_t guid : data.outOfRangeGuids) {
if (entityManager.hasEntity(guid)) { auto entity = entityManager.getEntity(guid);
if (!entity) continue;
const bool isKnownTransport = transportGuids_.count(guid) > 0; const bool isKnownTransport = transportGuids_.count(guid) > 0;
if (isKnownTransport) { if (isKnownTransport) {
// Keep transports alive across out-of-range flapping. // Keep transports alive across out-of-range flapping.
@ -4769,8 +4771,6 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
LOG_DEBUG("Entity went out of range: 0x", std::hex, guid, std::dec); LOG_DEBUG("Entity went out of range: 0x", std::hex, guid, std::dec);
// Trigger despawn callbacks before removing entity // Trigger despawn callbacks before removing entity
auto entity = entityManager.getEntity(guid);
if (entity) {
if (entity->getType() == ObjectType::UNIT && creatureDespawnCallback_) { if (entity->getType() == ObjectType::UNIT && creatureDespawnCallback_) {
creatureDespawnCallback_(guid); creatureDespawnCallback_(guid);
} else if (entity->getType() == ObjectType::PLAYER && playerDespawnCallback_) { } else if (entity->getType() == ObjectType::PLAYER && playerDespawnCallback_) {
@ -4783,7 +4783,6 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
} else if (entity->getType() == ObjectType::GAMEOBJECT && gameObjectDespawnCallback_) { } else if (entity->getType() == ObjectType::GAMEOBJECT && gameObjectDespawnCallback_) {
gameObjectDespawnCallback_(guid); gameObjectDespawnCallback_(guid);
} }
}
transportGuids_.erase(guid); transportGuids_.erase(guid);
serverUpdatedTransportGuids_.erase(guid); serverUpdatedTransportGuids_.erase(guid);
clearTransportAttachment(guid); clearTransportAttachment(guid);
@ -4792,7 +4791,6 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
} }
entityManager.removeEntity(guid); entityManager.removeEntity(guid);
} }
}
// Process update blocks // Process update blocks
for (const auto& block : data.blocks) { for (const auto& block : data.blocks) {
@ -5466,7 +5464,12 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
} }
// Update XP / inventory slot / skill fields for player entity // Update XP / inventory slot / skill fields for player entity
if (block.guid == playerGuid) { if (block.guid == playerGuid) {
std::map<uint16_t, uint32_t> oldFieldsSnapshot = lastPlayerFields_; const bool needCoinageDetectSnapshot =
(pendingMoneyDelta_ != 0 && pendingMoneyDeltaTimer_ > 0.0f);
std::map<uint16_t, uint32_t> oldFieldsSnapshot;
if (needCoinageDetectSnapshot) {
oldFieldsSnapshot = lastPlayerFields_;
}
if (block.hasMovement && block.runSpeed > 0.1f && block.runSpeed < 100.0f) { if (block.hasMovement && block.runSpeed > 0.1f && block.runSpeed < 100.0f) {
serverRunSpeed_ = block.runSpeed; serverRunSpeed_ = block.runSpeed;
// Some server dismount paths update run speed without updating mount display field. // Some server dismount paths update run speed without updating mount display field.
@ -5480,10 +5483,13 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
} }
} }
} }
auto mergeHint = lastPlayerFields_.end();
for (const auto& [key, val] : block.fields) { for (const auto& [key, val] : block.fields) {
lastPlayerFields_[key] = val; mergeHint = lastPlayerFields_.insert_or_assign(mergeHint, key, val);
} }
if (needCoinageDetectSnapshot) {
maybeDetectCoinageIndex(oldFieldsSnapshot, lastPlayerFields_); maybeDetectCoinageIndex(oldFieldsSnapshot, lastPlayerFields_);
}
maybeDetectVisibleItemLayout(); maybeDetectVisibleItemLayout();
detectInventorySlotBases(block.fields); detectInventorySlotBases(block.fields);
bool slotsChanged = false; bool slotsChanged = false;
@ -5545,18 +5551,34 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
// Update item stack count for online items // Update item stack count for online items
if (entity->getType() == ObjectType::ITEM || entity->getType() == ObjectType::CONTAINER) { if (entity->getType() == ObjectType::ITEM || entity->getType() == ObjectType::CONTAINER) {
bool inventoryChanged = false;
const uint16_t itemStackField = fieldIndex(UF::ITEM_FIELD_STACK_COUNT);
const uint16_t containerNumSlotsField = fieldIndex(UF::CONTAINER_FIELD_NUM_SLOTS);
const uint16_t containerSlot1Field = fieldIndex(UF::CONTAINER_FIELD_SLOT_1);
for (const auto& [key, val] : block.fields) { for (const auto& [key, val] : block.fields) {
if (key == fieldIndex(UF::ITEM_FIELD_STACK_COUNT)) { if (key == itemStackField) {
auto it = onlineItems_.find(block.guid); auto it = onlineItems_.find(block.guid);
if (it != onlineItems_.end()) it->second.stackCount = val; if (it != onlineItems_.end() && it->second.stackCount != val) {
it->second.stackCount = val;
inventoryChanged = true;
}
} }
} }
// Update container slot GUIDs on bag content changes // Update container slot GUIDs on bag content changes
if (entity->getType() == ObjectType::CONTAINER) { if (entity->getType() == ObjectType::CONTAINER) {
for (const auto& [key, _] : block.fields) {
if ((containerNumSlotsField != 0xFFFF && key == containerNumSlotsField) ||
(containerSlot1Field != 0xFFFF && key >= containerSlot1Field && key < containerSlot1Field + 72)) {
inventoryChanged = true;
break;
}
}
extractContainerFields(block.guid, block.fields); extractContainerFields(block.guid, block.fields);
} }
if (inventoryChanged) {
rebuildOnlineInventory(); rebuildOnlineInventory();
} }
}
if (block.hasMovement && entity->getType() == ObjectType::GAMEOBJECT) { if (block.hasMovement && entity->getType() == ObjectType::GAMEOBJECT) {
if (transportGuids_.count(block.guid) && transportMoveCallback_) { if (transportGuids_.count(block.guid) && transportMoveCallback_) {
serverUpdatedTransportGuids_.insert(block.guid); serverUpdatedTransportGuids_.insert(block.guid);

View file

@ -1117,7 +1117,8 @@ bool UpdateObjectParser::parseUpdateFields(network::Packet& packet, UpdateBlock&
highestSetBit = fieldIndex; highestSetBit = fieldIndex;
} }
uint32_t value = packet.readUInt32(); uint32_t value = packet.readUInt32();
block.fields[fieldIndex] = value; // fieldIndex is monotonically increasing here, so end() is a good insertion hint.
block.fields.emplace_hint(block.fields.end(), fieldIndex, value);
valuesReadCount++; valuesReadCount++;
LOG_DEBUG(" Field[", fieldIndex, "] = 0x", std::hex, value, std::dec); LOG_DEBUG(" Field[", fieldIndex, "] = 0x", std::hex, value, std::dec);
@ -1256,7 +1257,7 @@ bool UpdateObjectParser::parse(network::Packet& packet, UpdateObjectData& data)
return false; return false;
} }
data.blocks.push_back(block); data.blocks.emplace_back(std::move(block));
} }