mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Fix taxi flight: camera panning, world reload, gryphon display, and animations
- Clear introActive/idleOrbit in externalFollow block so mouse panning works during taxi - Skip full world reload on same-map teleports (taxi landing) by tracking loadedMapId - Collect all model IDs for a path when resolving gryphon display ID (fixes displayId=0) - Remove incorrect MountDisplayId fields from Vanilla/Turtle TaxiNodes DBC layouts - Add Vanilla fly animation IDs (234/229/233) to taxi mount animation candidates
This commit is contained in:
parent
4a08271b75
commit
85714fd7f6
8 changed files with 85 additions and 19 deletions
|
|
@ -41,8 +41,7 @@
|
|||
"Skin1": 6, "Skin2": 7, "Skin3": 8
|
||||
},
|
||||
"TaxiNodes": {
|
||||
"ID": 0, "MapID": 1, "X": 2, "Y": 3, "Z": 4, "Name": 5,
|
||||
"MountDisplayIdAlliance": 12, "MountDisplayIdHorde": 13
|
||||
"ID": 0, "MapID": 1, "X": 2, "Y": 3, "Z": 4, "Name": 5
|
||||
},
|
||||
"TaxiPath": { "ID": 0, "FromNode": 1, "ToNode": 2, "Cost": 3 },
|
||||
"TaxiPathNode": {
|
||||
|
|
|
|||
|
|
@ -41,8 +41,7 @@
|
|||
"Skin1": 6, "Skin2": 7, "Skin3": 8
|
||||
},
|
||||
"TaxiNodes": {
|
||||
"ID": 0, "MapID": 1, "X": 2, "Y": 3, "Z": 4, "Name": 5,
|
||||
"MountDisplayIdAlliance": 12, "MountDisplayIdHorde": 13
|
||||
"ID": 0, "MapID": 1, "X": 2, "Y": 3, "Z": 4, "Name": 5
|
||||
},
|
||||
"TaxiPath": { "ID": 0, "FromNode": 1, "ToNode": 2, "Cost": 3 },
|
||||
"TaxiPathNode": {
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ private:
|
|||
uint32_t gryphonDisplayId_ = 0;
|
||||
uint32_t wyvernDisplayId_ = 0;
|
||||
bool lastTaxiFlight_ = false;
|
||||
uint32_t loadedMapId_ = 0xFFFFFFFF; // Map ID of currently loaded terrain (0xFFFFFFFF = none)
|
||||
float taxiLandingClampTimer_ = 0.0f;
|
||||
float worldEntryMovementGraceTimer_ = 0.0f;
|
||||
float taxiStreamCooldown_ = 0.0f;
|
||||
|
|
|
|||
|
|
@ -339,6 +339,7 @@ private:
|
|||
float mountIdleSoundTimer_ = 0.0f; // Timer for ambient idle sounds
|
||||
uint32_t mountActiveFidget_ = 0; // Currently playing fidget animation ID (0 = none)
|
||||
bool taxiFlight_ = false;
|
||||
bool taxiAnimsLogged_ = false;
|
||||
|
||||
bool terrainEnabled = true;
|
||||
bool terrainLoaded = false;
|
||||
|
|
|
|||
|
|
@ -396,6 +396,7 @@ void Application::setState(AppState newState) {
|
|||
playerCharacterSpawned = false;
|
||||
weaponsSheathed_ = false;
|
||||
wasAutoAttacking_ = false;
|
||||
loadedMapId_ = 0xFFFFFFFF;
|
||||
spawnedPlayerGuid_ = 0;
|
||||
spawnedAppearanceBytes_ = 0;
|
||||
spawnedFacialFeatures_ = 0;
|
||||
|
|
@ -498,6 +499,7 @@ void Application::logoutToLogin() {
|
|||
playerCharacterSpawned = false;
|
||||
weaponsSheathed_ = false;
|
||||
wasAutoAttacking_ = false;
|
||||
loadedMapId_ = 0xFFFFFFFF;
|
||||
world.reset();
|
||||
if (renderer) {
|
||||
// Remove old player model so it doesn't persist into next session
|
||||
|
|
@ -998,10 +1000,30 @@ void Application::setupUICallbacks() {
|
|||
// World entry callback (online mode) - load terrain when entering world
|
||||
gameHandler->setWorldEntryCallback([this](uint32_t mapId, float x, float y, float z) {
|
||||
LOG_INFO("Online world entry: mapId=", mapId, " pos=(", x, ", ", y, ", ", z, ")");
|
||||
|
||||
// Same-map teleport (taxi landing, GM teleport on same continent):
|
||||
// just update position, let terrain streamer handle tile loading incrementally.
|
||||
// A full reload is only needed on first entry or map change.
|
||||
if (mapId == loadedMapId_ && renderer && renderer->getTerrainManager()) {
|
||||
LOG_INFO("Same-map teleport (map ", mapId, "), skipping full world reload");
|
||||
glm::vec3 canonical = core::coords::serverToCanonical(glm::vec3(x, y, z));
|
||||
glm::vec3 renderPos = core::coords::canonicalToRender(canonical);
|
||||
renderer->getCharacterPosition() = renderPos;
|
||||
if (renderer->getCameraController()) {
|
||||
auto* ft = renderer->getCameraController()->getFollowTargetMutable();
|
||||
if (ft) *ft = renderPos;
|
||||
}
|
||||
worldEntryMovementGraceTimer_ = 2.0f;
|
||||
taxiLandingClampTimer_ = 0.0f;
|
||||
lastTaxiFlight_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
worldEntryMovementGraceTimer_ = 2.0f;
|
||||
taxiLandingClampTimer_ = 0.0f;
|
||||
lastTaxiFlight_ = false;
|
||||
loadOnlineWorldTerrain(mapId, x, y, z);
|
||||
loadedMapId_ = mapId;
|
||||
});
|
||||
|
||||
auto sampleBestFloorAt = [this](float x, float y, float probeZ) -> std::optional<float> {
|
||||
|
|
@ -2824,18 +2846,23 @@ void Application::buildCreatureDisplayLookups() {
|
|||
};
|
||||
auto resolveDisplayIdForExactPath = [&](const std::string& exactPath) -> uint32_t {
|
||||
const std::string target = normalizePath(exactPath);
|
||||
uint32_t modelId = 0;
|
||||
// Collect ALL model IDs that map to this path (multiple model IDs can
|
||||
// share the same .m2 file, e.g. modelId 147 and 792 both → Gryphon.m2)
|
||||
std::vector<uint32_t> modelIds;
|
||||
for (const auto& [mid, path] : modelIdToPath_) {
|
||||
if (normalizePath(path) == target) {
|
||||
modelId = mid;
|
||||
break;
|
||||
modelIds.push_back(mid);
|
||||
}
|
||||
}
|
||||
if (modelId == 0) return 0;
|
||||
if (modelIds.empty()) return 0;
|
||||
uint32_t bestDisplayId = 0;
|
||||
int bestScore = -1;
|
||||
for (const auto& [dispId, data] : displayDataMap_) {
|
||||
if (data.modelId != modelId) continue;
|
||||
bool matches = false;
|
||||
for (uint32_t mid : modelIds) {
|
||||
if (data.modelId == mid) { matches = true; break; }
|
||||
}
|
||||
if (!matches) continue;
|
||||
int score = 0;
|
||||
if (!data.skin1.empty()) score += 3;
|
||||
if (!data.skin2.empty()) score += 2;
|
||||
|
|
@ -4845,8 +4872,15 @@ void Application::processPendingMount() {
|
|||
bool isTaxi = gameHandler && gameHandler->isOnTaxiFlight();
|
||||
uint32_t startAnim = 0; // ANIM_STAND
|
||||
if (isTaxi) {
|
||||
if (charRenderer->hasAnimation(instanceId, 159)) startAnim = 159; // FlyForward
|
||||
else if (charRenderer->hasAnimation(instanceId, 158)) startAnim = 158; // FlyIdle
|
||||
// Try WotLK fly anims first, then Vanilla-friendly fallbacks
|
||||
uint32_t taxiCandidates[] = {159, 158, 234, 229, 233, 141, 369, 6, 5}; // FlyForward, FlyIdle, FlyRun(234), FlyStand(229), FlyWalk(233), FlyMounted, FlyRun, Fly, Run
|
||||
for (uint32_t anim : taxiCandidates) {
|
||||
if (charRenderer->hasAnimation(instanceId, anim)) {
|
||||
startAnim = anim;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If none found, startAnim stays 0 (Stand/hover) which is fine for flying creatures
|
||||
}
|
||||
charRenderer->playAnimation(instanceId, startAnim, true);
|
||||
|
||||
|
|
|
|||
|
|
@ -8688,7 +8688,8 @@ void GameHandler::handleTeleportAck(network::Packet& packet) {
|
|||
LOG_INFO("Sent MSG_MOVE_TELEPORT_ACK response");
|
||||
}
|
||||
|
||||
// Notify application to reload terrain at new position
|
||||
// Notify application of teleport — the callback decides whether to do
|
||||
// a full world reload (map change) or just update position (same map).
|
||||
if (worldEntryCallback_) {
|
||||
worldEntryCallback_(currentMapId_, serverX, serverY, serverZ);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,12 @@ void CameraController::update(float deltaTime) {
|
|||
|
||||
// During taxi flights, skip movement logic but keep camera orbit/zoom controls.
|
||||
if (externalFollow_) {
|
||||
// Cancel any active intro/idle orbit so mouse panning works during taxi.
|
||||
// The intro handling code (below) is unreachable during externalFollow_.
|
||||
introActive = false;
|
||||
idleOrbit_ = false;
|
||||
idleTimer_ = 0.0f;
|
||||
|
||||
camera->setRotation(yaw, pitch);
|
||||
float zoomLerp = 1.0f - std::exp(-ZOOM_SMOOTH_SPEED * deltaTime);
|
||||
currentDistance += (userTargetDistance - currentDistance) * zoomLerp;
|
||||
|
|
|
|||
|
|
@ -1023,21 +1023,46 @@ void Renderer::updateCharacterAnimation() {
|
|||
|
||||
// Taxi flight: use flying animations instead of ground movement
|
||||
if (taxiFlight_) {
|
||||
// Prefer FlyForward, fall back to FlyIdle, then ANIM_RUN
|
||||
if (characterRenderer->hasAnimation(mountInstanceId_, ANIM_FLY_FORWARD)) {
|
||||
mountAnimId = ANIM_FLY_FORWARD;
|
||||
} else if (characterRenderer->hasAnimation(mountInstanceId_, ANIM_FLY_IDLE)) {
|
||||
mountAnimId = ANIM_FLY_IDLE;
|
||||
} else {
|
||||
mountAnimId = ANIM_RUN;
|
||||
// Log available animations once when taxi starts
|
||||
if (!taxiAnimsLogged_) {
|
||||
taxiAnimsLogged_ = true;
|
||||
LOG_INFO("Taxi flight active: mountInstanceId_=", mountInstanceId_,
|
||||
" curMountAnim=", curMountAnim, " haveMountState=", haveMountState);
|
||||
std::vector<pipeline::M2Sequence> seqs;
|
||||
if (characterRenderer->getAnimationSequences(mountInstanceId_, seqs)) {
|
||||
std::string animList;
|
||||
for (const auto& s : seqs) {
|
||||
if (!animList.empty()) animList += ", ";
|
||||
animList += std::to_string(s.id);
|
||||
}
|
||||
LOG_INFO("Taxi mount available animations: [", animList, "]");
|
||||
}
|
||||
}
|
||||
|
||||
// Try multiple flying animation IDs in priority order:
|
||||
// 159=FlyForward, 158=FlyIdle (WotLK flying mounts)
|
||||
// 234=FlyRun, 229=FlyStand (Vanilla creature fly anims)
|
||||
// 233=FlyWalk, 141=FlyMounted, 369=FlyRun (alternate IDs)
|
||||
// 6=Fly (classic creature fly)
|
||||
// Fallback: Run, then Stand (hover)
|
||||
uint32_t flyAnims[] = {ANIM_FLY_FORWARD, ANIM_FLY_IDLE, 234, 229, 233, 141, 369, 6, ANIM_RUN};
|
||||
mountAnimId = ANIM_STAND; // ultimate fallback: hover/idle
|
||||
for (uint32_t fa : flyAnims) {
|
||||
if (characterRenderer->hasAnimation(mountInstanceId_, fa)) {
|
||||
mountAnimId = fa;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!haveMountState || curMountAnim != mountAnimId) {
|
||||
LOG_INFO("Taxi mount: playing animation ", mountAnimId);
|
||||
characterRenderer->playAnimation(mountInstanceId_, mountAnimId, true);
|
||||
}
|
||||
|
||||
// Skip all ground mount logic (jumps, fidgets, etc.)
|
||||
goto taxi_mount_done;
|
||||
} else {
|
||||
taxiAnimsLogged_ = false;
|
||||
}
|
||||
|
||||
// Check for jump trigger - use cached per-mount animation IDs
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue