mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add property-based mount animation discovery and procedural lean
Mount Animation System: - Property-based jump animation discovery using sequence metadata - Chain linkage scoring (nextAnimation/aliasNext) for accurate detection - Correct loop detection: flags & 0x01 == 0 means looping - Avoids brake/stop animations via blendTime penalties - Works on any mount model without hardcoded animation IDs Mount Physics: - Physics-based jump height: vz = sqrt(2 * g * h) - Configurable MOUNT_JUMP_HEIGHT constant (1.0m default) - Procedural lean into turns for ground mounts - Smooth roll based on turn rate (±14° max, 6x/sec blend) Audio Improvements: - State-machine driven mount sounds (jump, land, rear-up) - Semantic sound methods (no animation ID dependencies) - Debug logging for missing sound files Bug Fixes: - Fixed mount animation sequencing (JumpStart → JumpLoop → JumpEnd) - Fixed animation loop flag interpretation (0x20 vs 0x21) - Rider bone attachment working correctly during all mount actions
This commit is contained in:
parent
3c783d1845
commit
c623fcef51
16 changed files with 1083 additions and 145 deletions
|
|
@ -150,6 +150,7 @@ void TerrainManager::update(const Camera& camera, float deltaTime) {
|
|||
}
|
||||
|
||||
// Always process ready tiles each frame (GPU uploads from background thread)
|
||||
// Time budget prevents frame spikes from heavy tiles
|
||||
processReadyTiles();
|
||||
|
||||
timeSinceLastUpdate += deltaTime;
|
||||
|
|
@ -641,7 +642,8 @@ void TerrainManager::finalizeTile(const std::shared_ptr<PendingTile>& pending) {
|
|||
m2Renderer->initialize(assetManager);
|
||||
}
|
||||
|
||||
// Upload unique M2 models to GPU (stays in VRAM permanently until shutdown)
|
||||
// Upload M2 models immediately (batching was causing hangs)
|
||||
// The 5ms time budget in processReadyTiles() limits the spike
|
||||
std::unordered_set<uint32_t> uploadedModelIds;
|
||||
for (auto& m2Ready : pending->m2Models) {
|
||||
if (m2Renderer->loadModel(m2Ready.model, m2Ready.modelId)) {
|
||||
|
|
@ -649,7 +651,7 @@ void TerrainManager::finalizeTile(const std::shared_ptr<PendingTile>& pending) {
|
|||
}
|
||||
}
|
||||
if (!uploadedModelIds.empty()) {
|
||||
LOG_DEBUG(" Uploaded ", uploadedModelIds.size(), " unique M2 models to VRAM for tile [", x, ",", y, "]");
|
||||
LOG_DEBUG(" Uploaded ", uploadedModelIds.size(), " M2 models for tile [", x, ",", y, "]");
|
||||
}
|
||||
|
||||
// Create instances (deduplicate by uniqueId across tile boundaries)
|
||||
|
|
@ -813,11 +815,13 @@ void TerrainManager::workerLoop() {
|
|||
}
|
||||
|
||||
void TerrainManager::processReadyTiles() {
|
||||
// Process up to 1 ready tile per frame to avoid main-thread stalls
|
||||
// Process tiles with time budget to avoid frame spikes
|
||||
// Budget: 5ms per frame (allows 3 tiles at ~1.5ms each or 1 heavy tile)
|
||||
const float timeBudgetMs = 5.0f;
|
||||
auto startTime = std::chrono::high_resolution_clock::now();
|
||||
int processed = 0;
|
||||
const int maxPerFrame = 1;
|
||||
|
||||
while (processed < maxPerFrame) {
|
||||
while (true) {
|
||||
std::shared_ptr<PendingTile> pending;
|
||||
|
||||
{
|
||||
|
|
@ -831,16 +835,48 @@ void TerrainManager::processReadyTiles() {
|
|||
|
||||
if (pending) {
|
||||
TileCoord coord = pending->coord;
|
||||
auto tileStart = std::chrono::high_resolution_clock::now();
|
||||
|
||||
finalizeTile(pending);
|
||||
|
||||
auto tileEnd = std::chrono::high_resolution_clock::now();
|
||||
float tileTimeMs = std::chrono::duration<float, std::milli>(tileEnd - tileStart).count();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(queueMutex);
|
||||
pendingTiles.erase(coord);
|
||||
}
|
||||
processed++;
|
||||
|
||||
// Check if we've exceeded time budget
|
||||
float elapsedMs = std::chrono::duration<float, std::milli>(tileEnd - startTime).count();
|
||||
if (elapsedMs >= timeBudgetMs) {
|
||||
if (processed > 1) {
|
||||
LOG_DEBUG("Processed ", processed, " tiles in ", elapsedMs, "ms (budget: ", timeBudgetMs, "ms)");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainManager::processM2UploadQueue() {
|
||||
// Upload up to MAX_M2_UPLOADS_PER_FRAME models per frame
|
||||
int uploaded = 0;
|
||||
while (!m2UploadQueue_.empty() && uploaded < MAX_M2_UPLOADS_PER_FRAME) {
|
||||
auto& upload = m2UploadQueue_.front();
|
||||
if (m2Renderer) {
|
||||
m2Renderer->loadModel(upload.model, upload.modelId);
|
||||
}
|
||||
m2UploadQueue_.pop();
|
||||
uploaded++;
|
||||
}
|
||||
|
||||
if (uploaded > 0) {
|
||||
LOG_DEBUG("Uploaded ", uploaded, " M2 models (", m2UploadQueue_.size(), " remaining in queue)");
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainManager::processAllReadyTiles() {
|
||||
while (true) {
|
||||
std::shared_ptr<PendingTile> pending;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue