Stabilize taxi/state sync and creature spawn handling

This commit is contained in:
Kelsi 2026-02-11 21:14:35 -08:00
parent 38cef8d9c6
commit 40b50454ce
18 changed files with 818 additions and 127 deletions

View file

@ -735,9 +735,45 @@ void CameraController::update(float deltaTime) {
}
// ===== WoW-style orbit camera =====
// Pivot point at upper chest/neck
// Pivot point at upper chest/neck.
float mountedOffset = mounted_ ? mountHeightOffset_ : 0.0f;
glm::vec3 pivot = targetPos + glm::vec3(0.0f, 0.0f, PIVOT_HEIGHT + mountedOffset);
float pivotLift = 0.0f;
if (terrainManager && !externalFollow_) {
float moved = glm::length(glm::vec2(targetPos.x - lastPivotLiftQueryPos_.x,
targetPos.y - lastPivotLiftQueryPos_.y));
float distDelta = std::abs(currentDistance - lastPivotLiftDistance_);
bool queryLift = (++pivotLiftQueryCounter_ >= PIVOT_LIFT_QUERY_INTERVAL) ||
(moved >= PIVOT_LIFT_POS_THRESHOLD) ||
(distDelta >= PIVOT_LIFT_DIST_THRESHOLD);
if (queryLift) {
pivotLiftQueryCounter_ = 0;
lastPivotLiftQueryPos_ = targetPos;
lastPivotLiftDistance_ = currentDistance;
// Estimate where camera sits horizontally and ensure enough terrain clearance.
glm::vec3 probeCam = targetPos + (-forward3D) * currentDistance;
auto terrainAtCam = terrainManager->getHeightAt(probeCam.x, probeCam.y);
auto terrainAtPivot = terrainManager->getHeightAt(targetPos.x, targetPos.y);
float desiredLift = 0.0f;
if (terrainAtCam) {
// Keep pivot high enough so near-hill camera rays don't cut through terrain.
constexpr float kMinRayClearance = 2.0f;
float basePivotZ = targetPos.z + PIVOT_HEIGHT + mountedOffset;
float rayClearance = basePivotZ - *terrainAtCam;
if (rayClearance < kMinRayClearance) {
desiredLift = std::clamp(kMinRayClearance - rayClearance, 0.0f, 1.4f);
}
}
// If character is already below local terrain sample, avoid lifting aggressively.
if (terrainAtPivot && targetPos.z < *terrainAtPivot - 0.2f) {
desiredLift = 0.0f;
}
cachedPivotLift_ = desiredLift;
}
pivotLift = cachedPivotLift_;
}
glm::vec3 pivot = targetPos + glm::vec3(0.0f, 0.0f, PIVOT_HEIGHT + mountedOffset + pivotLift);
// Camera direction from yaw/pitch (already computed as forward3D)
glm::vec3 camDir = -forward3D; // Camera looks at pivot, so it's behind

View file

@ -177,7 +177,7 @@ void Celestial::renderSun(const Camera& camera, float timeOfDay,
// Create model matrix
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, sunPos);
model = glm::scale(model, glm::vec3(500.0f, 500.0f, 1.0f)); // Large and visible
model = glm::scale(model, glm::vec3(95.0f, 95.0f, 1.0f)); // Match WotLK-like apparent size
// Set uniforms
glm::mat4 view = camera.getViewMatrix();

View file

@ -986,7 +986,7 @@ void CharacterRenderer::update(float deltaTime, const glm::vec3& cameraPos) {
static int logCounter = 0;
if (++logCounter >= 300) { // Log every 10 seconds at 30fps
LOG_INFO("CharacterRenderer: ", updatedCount, "/", instances.size(), " instances updated (",
LOG_DEBUG("CharacterRenderer: ", updatedCount, "/", instances.size(), " instances updated (",
instances.size() - updatedCount, " culled)");
logCounter = 0;
}
@ -1584,7 +1584,17 @@ void CharacterRenderer::setInstanceVisible(uint32_t instanceId, bool visible) {
}
void CharacterRenderer::removeInstance(uint32_t instanceId) {
instances.erase(instanceId);
auto it = instances.find(instanceId);
if (it == instances.end()) return;
// Remove child attachments first (helmets/weapons), otherwise they leak as
// orphan render instances when the parent creature despawns.
auto attachments = it->second.weaponAttachments;
for (const auto& wa : attachments) {
removeInstance(wa.weaponInstanceId);
}
instances.erase(it);
}
bool CharacterRenderer::getAnimationState(uint32_t instanceId, uint32_t& animationId,

View file

@ -2053,7 +2053,7 @@ void M2Renderer::render(const Camera& camera, const glm::mat4& view, const glm::
static int frameCounter = 0;
if (++frameCounter >= 120) {
frameCounter = 0;
LOG_INFO("M2 Render: ", totalMs, " ms (culling/sort: ", cullingSortMs,
LOG_DEBUG("M2 Render: ", totalMs, " ms (culling/sort: ", cullingSortMs,
" ms, draw: ", drawLoopMs, " ms) | ", sortedVisible_.size(), " visible | ",
totalBatchesDrawn, " batches | ", boneMatrixUploads, " bone uploads");
}

View file

@ -2143,7 +2143,7 @@ void Renderer::update(float deltaTime) {
// Log renderer profiling every 60 frames
if (++rendProfileCounter >= 60) {
LOG_INFO("RENDERER UPDATE PROFILE (60 frames): camera=", camTime / 60.0f,
LOG_DEBUG("RENDERER UPDATE PROFILE (60 frames): camera=", camTime / 60.0f,
"ms light=", lightTime / 60.0f, "ms charAnim=", charAnimTime / 60.0f,
"ms terrain=", terrainTime / 60.0f, "ms sky=", skyTime / 60.0f,
"ms charRend=", charRendTime / 60.0f, "ms audio=", audioTime / 60.0f,