Throttle player equipment compositing and spawning to fix walking stutter

Defer equipment texture compositing to a queue processed max 1 per frame
instead of compositing immediately on callback (each compositeWithRegions
call does file I/O + CPU blit + GPU upload on the main thread). Reduce
MAX_SPAWNS_PER_FRAME from 96 to 8 and increase inspect rate limit from
0.75s to 2s. Demote noisy per-frame logs to DEBUG level.
This commit is contained in:
Kelsi 2026-02-16 00:51:59 -08:00
parent d87a86e35c
commit 35034ca544
3 changed files with 23 additions and 7 deletions

View file

@ -584,6 +584,8 @@ void Application::update(float deltaTime) {
processPlayerSpawnQueue();
// Process deferred online creature spawns (throttled)
processCreatureSpawnQueue();
// Process deferred equipment compositing (max 1 per frame to avoid stutter)
processDeferredEquipmentQueue();
auto cq2 = std::chrono::high_resolution_clock::now();
creatureQTime += std::chrono::duration<float, std::milli>(cq2 - cq1).count();
@ -1209,7 +1211,10 @@ void Application::setupUICallbacks() {
gameHandler->setPlayerEquipmentCallback([this](uint64_t guid,
const std::array<uint32_t, 19>& displayInfoIds,
const std::array<uint8_t, 19>& inventoryTypes) {
setOnlinePlayerEquipment(guid, displayInfoIds, inventoryTypes);
// Queue equipment compositing instead of doing it immediately —
// compositeWithRegions is expensive (file I/O + CPU blit + GPU upload)
// and causes frame stutters if multiple players update at once.
deferredEquipmentQueue_.push_back({guid, {displayInfoIds, inventoryTypes}});
});
// Creature despawn callback (online mode) - remove creature models
@ -4496,13 +4501,21 @@ void Application::processPlayerSpawnQueue() {
// Apply any equipment updates that arrived before the player was spawned.
auto pit = pendingOnlinePlayerEquipment_.find(s.guid);
if (pit != pendingOnlinePlayerEquipment_.end()) {
setOnlinePlayerEquipment(s.guid, pit->second.first, pit->second.second);
deferredEquipmentQueue_.push_back({s.guid, pit->second});
pendingOnlinePlayerEquipment_.erase(pit);
}
processed++;
}
}
void Application::processDeferredEquipmentQueue() {
if (deferredEquipmentQueue_.empty()) return;
// Process at most 1 per frame — compositeWithRegions is expensive
auto [guid, equipData] = deferredEquipmentQueue_.front();
deferredEquipmentQueue_.erase(deferredEquipmentQueue_.begin());
setOnlinePlayerEquipment(guid, equipData.first, equipData.second);
}
void Application::processGameObjectSpawnQueue() {
if (pendingGameObjectSpawns_.empty()) return;