mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
fix: eliminate full spatial index rebuild on M2 instance removal
M2Renderer::removeInstance() was calling rebuildSpatialIndex() for every single removal, causing 25-90ms frame hitches during entity despawns. Now uses O(1) lookup via instanceIndexById, incremental spatial grid cell removal, and swap-remove from the instance vector. The auxiliary index vectors are rebuilt cheaply since they're small.
This commit is contained in:
parent
702155ff4f
commit
379ca116d1
1 changed files with 59 additions and 6 deletions
|
|
@ -4008,14 +4008,67 @@ void M2Renderer::setInstanceTransform(uint32_t instanceId, const glm::mat4& tran
|
|||
}
|
||||
|
||||
void M2Renderer::removeInstance(uint32_t instanceId) {
|
||||
for (auto it = instances.begin(); it != instances.end(); ++it) {
|
||||
if (it->id == instanceId) {
|
||||
destroyInstanceBones(*it);
|
||||
instances.erase(it);
|
||||
rebuildSpatialIndex();
|
||||
return;
|
||||
auto idxIt = instanceIndexById.find(instanceId);
|
||||
if (idxIt == instanceIndexById.end()) return;
|
||||
size_t idx = idxIt->second;
|
||||
if (idx >= instances.size()) return;
|
||||
|
||||
auto& inst = instances[idx];
|
||||
|
||||
// Remove from spatial grid incrementally (same pattern as the move-update path)
|
||||
GridCell minCell = toCell(inst.worldBoundsMin);
|
||||
GridCell maxCell = toCell(inst.worldBoundsMax);
|
||||
for (int z = minCell.z; z <= maxCell.z; z++) {
|
||||
for (int y = minCell.y; y <= maxCell.y; y++) {
|
||||
for (int x = minCell.x; x <= maxCell.x; x++) {
|
||||
auto gIt = spatialGrid.find(GridCell{x, y, z});
|
||||
if (gIt != spatialGrid.end()) {
|
||||
auto& vec = gIt->second;
|
||||
vec.erase(std::remove(vec.begin(), vec.end(), instanceId), vec.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from dedup map
|
||||
if (!inst.cachedIsGroundDetail) {
|
||||
DedupKey dk{inst.modelId,
|
||||
static_cast<int32_t>(std::round(inst.position.x * 10.0f)),
|
||||
static_cast<int32_t>(std::round(inst.position.y * 10.0f)),
|
||||
static_cast<int32_t>(std::round(inst.position.z * 10.0f))};
|
||||
instanceDedupMap_.erase(dk);
|
||||
}
|
||||
|
||||
destroyInstanceBones(inst);
|
||||
|
||||
// Swap-remove: move last element to the hole and pop_back to avoid O(n) shift
|
||||
instanceIndexById.erase(instanceId);
|
||||
if (idx < instances.size() - 1) {
|
||||
uint32_t movedId = instances.back().id;
|
||||
instances[idx] = std::move(instances.back());
|
||||
instances.pop_back();
|
||||
instanceIndexById[movedId] = idx;
|
||||
} else {
|
||||
instances.pop_back();
|
||||
}
|
||||
|
||||
// Rebuild the lightweight auxiliary index vectors (smoke, portal, etc.)
|
||||
// These are small vectors of indices that are rebuilt cheaply.
|
||||
smokeInstanceIndices_.clear();
|
||||
portalInstanceIndices_.clear();
|
||||
animatedInstanceIndices_.clear();
|
||||
particleOnlyInstanceIndices_.clear();
|
||||
particleInstanceIndices_.clear();
|
||||
for (size_t i = 0; i < instances.size(); i++) {
|
||||
auto& ri = instances[i];
|
||||
if (ri.cachedIsSmoke) smokeInstanceIndices_.push_back(i);
|
||||
if (ri.cachedIsInstancePortal) portalInstanceIndices_.push_back(i);
|
||||
if (ri.cachedHasParticleEmitters) particleInstanceIndices_.push_back(i);
|
||||
if (ri.cachedHasAnimation && !ri.cachedDisableAnimation)
|
||||
animatedInstanceIndices_.push_back(i);
|
||||
else if (ri.cachedHasParticleEmitters)
|
||||
particleOnlyInstanceIndices_.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
void M2Renderer::setSkipCollision(uint32_t instanceId, bool skip) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue