mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-16 09:13:50 +00:00
fix: spline parse order (WotLK-first) fixes missing NPCs; bound WMO liquid loading
Spline auto-detection: try WotLK format before Classic to prevent false-positive matches where durationMod float bytes resemble a valid Classic pointCount. This caused the movement block to consume wrong byte count, corrupting the update mask read (maskBlockCount=57/129/203 instead of ~5) and silently dropping NPC spawns. Terrain latency: bound WMO liquid group loading to 4 groups per advanceFinalization call. Large WMOs (e.g., Stormwind canals with 40+ liquid groups) previously loaded all groups in one unbounded loop, blowing past the 8ms frame budget and causing stalls up to 1300ms. Now yields back to processReadyTiles() after 4 groups so the time budget check can break out.
This commit is contained in:
parent
d26eed1e7c
commit
a795239e77
3 changed files with 58 additions and 27 deletions
|
|
@ -157,6 +157,7 @@ struct FinalizingTile {
|
|||
size_t wmoModelIndex = 0; // Next WMO model to upload
|
||||
size_t wmoInstanceIndex = 0; // Next WMO placement to instantiate
|
||||
size_t wmoDoodadIndex = 0; // Next WMO doodad to upload
|
||||
size_t wmoLiquidGroupIndex = 0; // Next liquid group within current WMO instance
|
||||
|
||||
// Incremental terrain upload state (splits TERRAIN phase across frames)
|
||||
bool terrainPreloaded = false; // True after preloaded textures uploaded
|
||||
|
|
|
|||
|
|
@ -1019,12 +1019,11 @@ bool UpdateObjectParser::parseMovementBlock(network::Packet& packet, UpdateBlock
|
|||
return true;
|
||||
};
|
||||
|
||||
// --- Try 1: Classic format (uncompressed points immediately after splineId) ---
|
||||
bool splineParsed = tryParseSplinePoints(false, "classic");
|
||||
|
||||
// --- Try 2: WotLK format (durationMod+durationModNext+conditional+compressed points) ---
|
||||
if (!splineParsed) {
|
||||
packet.setReadPos(afterSplineId);
|
||||
// --- Try 1: WotLK format (durationMod+durationModNext+parabolic+compressed points) ---
|
||||
// Try WotLK first since this is a WotLK parser; Classic auto-detect can false-positive
|
||||
// when durationMod bytes happen to look like a valid Classic pointCount.
|
||||
bool splineParsed = false;
|
||||
{
|
||||
bool wotlkOk = bytesAvailable(8); // durationMod + durationModNext
|
||||
if (wotlkOk) {
|
||||
/*float durationMod =*/ packet.readFloat();
|
||||
|
|
@ -1050,6 +1049,12 @@ bool UpdateObjectParser::parseMovementBlock(network::Packet& packet, UpdateBlock
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Try 2: Classic format (uncompressed points immediately after splineId) ---
|
||||
if (!splineParsed) {
|
||||
packet.setReadPos(afterSplineId);
|
||||
splineParsed = tryParseSplinePoints(false, "classic");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (updateFlags & UPDATEFLAG_POSITION) {
|
||||
|
|
|
|||
|
|
@ -980,43 +980,68 @@ bool TerrainManager::advanceFinalization(FinalizingTile& ft) {
|
|||
|
||||
case FinalizationPhase::WMO_INSTANCES: {
|
||||
// Create WMO instances incrementally to avoid stalls on tiles with many WMOs.
|
||||
// Liquid group loading is also budgeted (max 4 per call) to prevent stalls
|
||||
// on WMOs with many liquid groups (e.g. Stormwind canals).
|
||||
if (wmoRenderer && ft.wmoInstanceIndex < pending->wmoModels.size()) {
|
||||
constexpr size_t kWmoInstancesPerStep = 4;
|
||||
constexpr size_t kLiquidGroupsPerStep = 4;
|
||||
size_t created = 0;
|
||||
size_t liquidGroupsLoaded = 0;
|
||||
while (ft.wmoInstanceIndex < pending->wmoModels.size() && created < kWmoInstancesPerStep) {
|
||||
auto& wmoReady = pending->wmoModels[ft.wmoInstanceIndex++];
|
||||
auto& wmoReady = pending->wmoModels[ft.wmoInstanceIndex];
|
||||
// Skip duplicates and unloaded models
|
||||
if (wmoReady.uniqueId != 0 && placedWmoIds.count(wmoReady.uniqueId)) {
|
||||
ft.wmoInstanceIndex++;
|
||||
ft.wmoLiquidGroupIndex = 0;
|
||||
continue;
|
||||
}
|
||||
if (!wmoRenderer->isModelLoaded(wmoReady.modelId)) {
|
||||
ft.wmoInstanceIndex++;
|
||||
ft.wmoLiquidGroupIndex = 0;
|
||||
continue;
|
||||
}
|
||||
uint32_t wmoInstId = wmoRenderer->createInstance(wmoReady.modelId, wmoReady.position, wmoReady.rotation);
|
||||
if (wmoInstId) {
|
||||
// Create the instance on first visit (liquidGroupIndex == 0)
|
||||
if (ft.wmoLiquidGroupIndex == 0) {
|
||||
uint32_t wmoInstId = wmoRenderer->createInstance(wmoReady.modelId, wmoReady.position, wmoReady.rotation);
|
||||
if (!wmoInstId) {
|
||||
ft.wmoInstanceIndex++;
|
||||
continue;
|
||||
}
|
||||
ft.wmoInstanceIds.push_back(wmoInstId);
|
||||
if (wmoReady.uniqueId != 0) {
|
||||
placedWmoIds.insert(wmoReady.uniqueId);
|
||||
ft.tileWmoUniqueIds.push_back(wmoReady.uniqueId);
|
||||
}
|
||||
// Load WMO liquids (canals, pools, etc.)
|
||||
if (waterRenderer) {
|
||||
glm::mat4 modelMatrix = glm::mat4(1.0f);
|
||||
modelMatrix = glm::translate(modelMatrix, wmoReady.position);
|
||||
modelMatrix = glm::rotate(modelMatrix, wmoReady.rotation.z, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
modelMatrix = glm::rotate(modelMatrix, wmoReady.rotation.y, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
modelMatrix = glm::rotate(modelMatrix, wmoReady.rotation.x, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
for (const auto& group : wmoReady.model.groups) {
|
||||
if (!group.liquid.hasLiquid()) continue;
|
||||
if (group.flags & 0x2000) {
|
||||
uint16_t lt = group.liquid.materialId;
|
||||
uint8_t basicType = (lt == 0) ? 0 : ((lt - 1) % 4);
|
||||
if (basicType < 2) continue;
|
||||
}
|
||||
waterRenderer->loadFromWMO(group.liquid, modelMatrix, wmoInstId);
|
||||
}
|
||||
}
|
||||
created++;
|
||||
}
|
||||
// Load WMO liquids incrementally (canals, pools, etc.)
|
||||
if (waterRenderer) {
|
||||
uint32_t wmoInstId = ft.wmoInstanceIds.back();
|
||||
glm::mat4 modelMatrix = glm::mat4(1.0f);
|
||||
modelMatrix = glm::translate(modelMatrix, wmoReady.position);
|
||||
modelMatrix = glm::rotate(modelMatrix, wmoReady.rotation.z, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
modelMatrix = glm::rotate(modelMatrix, wmoReady.rotation.y, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
modelMatrix = glm::rotate(modelMatrix, wmoReady.rotation.x, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
const auto& groups = wmoReady.model.groups;
|
||||
while (ft.wmoLiquidGroupIndex < groups.size() && liquidGroupsLoaded < kLiquidGroupsPerStep) {
|
||||
const auto& group = groups[ft.wmoLiquidGroupIndex];
|
||||
ft.wmoLiquidGroupIndex++;
|
||||
if (!group.liquid.hasLiquid()) continue;
|
||||
if (group.flags & 0x2000) {
|
||||
uint16_t lt = group.liquid.materialId;
|
||||
uint8_t basicType = (lt == 0) ? 0 : ((lt - 1) % 4);
|
||||
if (basicType < 2) continue;
|
||||
}
|
||||
waterRenderer->loadFromWMO(group.liquid, modelMatrix, wmoInstId);
|
||||
liquidGroupsLoaded++;
|
||||
}
|
||||
// More liquid groups remain on this WMO — yield
|
||||
if (ft.wmoLiquidGroupIndex < groups.size()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ft.wmoInstanceIndex++;
|
||||
ft.wmoLiquidGroupIndex = 0;
|
||||
created++;
|
||||
}
|
||||
if (ft.wmoInstanceIndex < pending->wmoModels.size()) {
|
||||
return false; // More WMO instances to create — yield
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue