mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
Fix taxi griffin animation and improve mount texture loading
Use FlyForward/FlyIdle animations (IDs 158/159) for taxi mounts instead of ground movement animations (Stand/Run). Add detailed mount texture debug logging and improve fallback texture resolution for gryphon/wyvern models with multiple skin slots.
This commit is contained in:
parent
d567eae0f2
commit
c3e19f5dd4
2 changed files with 108 additions and 28 deletions
|
|
@ -4693,6 +4693,13 @@ void Application::processPendingMount() {
|
||||||
}
|
}
|
||||||
const auto* md = charRenderer->getModelData(modelId);
|
const auto* md = charRenderer->getModelData(modelId);
|
||||||
if (md) {
|
if (md) {
|
||||||
|
LOG_INFO("Mount model textures: ", md->textures.size(), " slots, skin1='", dispData.skin1,
|
||||||
|
"' skin2='", dispData.skin2, "' skin3='", dispData.skin3, "'");
|
||||||
|
for (size_t ti = 0; ti < md->textures.size(); ti++) {
|
||||||
|
LOG_INFO(" tex[", ti, "] type=", md->textures[ti].type,
|
||||||
|
" filename='", md->textures[ti].filename, "'");
|
||||||
|
}
|
||||||
|
|
||||||
int replaced = 0;
|
int replaced = 0;
|
||||||
for (size_t ti = 0; ti < md->textures.size(); ti++) {
|
for (size_t ti = 0; ti < md->textures.size(); ti++) {
|
||||||
const auto& tex = md->textures[ti];
|
const auto& tex = md->textures[ti];
|
||||||
|
|
@ -4708,49 +4715,92 @@ void Application::processPendingMount() {
|
||||||
GLuint skinTex = charRenderer->loadTexture(texPath);
|
GLuint skinTex = charRenderer->loadTexture(texPath);
|
||||||
if (skinTex != 0) {
|
if (skinTex != 0) {
|
||||||
charRenderer->setModelTexture(modelId, static_cast<uint32_t>(ti), skinTex);
|
charRenderer->setModelTexture(modelId, static_cast<uint32_t>(ti), skinTex);
|
||||||
|
LOG_INFO(" Applied skin texture slot ", ti, ": ", texPath);
|
||||||
replaced++;
|
replaced++;
|
||||||
|
} else {
|
||||||
|
LOG_WARNING(" Failed to load skin texture slot ", ti, ": ", texPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Some mounts (gryphon/wyvern) use empty model textures; force skin1 onto slot 0.
|
|
||||||
if (replaced == 0 && !dispData.skin1.empty() && !md->textures.empty()) {
|
|
||||||
std::string texPath = modelDir + dispData.skin1 + ".blp";
|
|
||||||
GLuint skinTex = charRenderer->loadTexture(texPath);
|
|
||||||
if (skinTex != 0) {
|
|
||||||
charRenderer->setModelTexture(modelId, 0, skinTex);
|
|
||||||
LOG_INFO("Forced mount skin1 texture on slot 0: ", texPath);
|
|
||||||
replaced++;
|
|
||||||
}
|
|
||||||
} else if (replaced == 0 && !md->textures.empty() && !md->textures[0].filename.empty()) {
|
|
||||||
// Last-resort: use the model's first texture filename if it exists.
|
|
||||||
GLuint texId = charRenderer->loadTexture(md->textures[0].filename);
|
|
||||||
if (texId != 0) {
|
|
||||||
charRenderer->setModelTexture(modelId, 0, texId);
|
|
||||||
LOG_INFO("Forced mount model texture on slot 0: ", md->textures[0].filename);
|
|
||||||
replaced++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final taxi mount fallback for gryphon/wyvern models when display tables are sparse.
|
// Force skin textures onto type-0 (hardcoded) slots that have no filename
|
||||||
|
if (replaced == 0) {
|
||||||
|
for (size_t ti = 0; ti < md->textures.size(); ti++) {
|
||||||
|
const auto& tex = md->textures[ti];
|
||||||
|
if (tex.type == 0 && tex.filename.empty()) {
|
||||||
|
// Empty hardcoded slot — try skin1 then skin2
|
||||||
|
std::string texPath;
|
||||||
|
if (!dispData.skin1.empty() && replaced == 0) {
|
||||||
|
texPath = modelDir + dispData.skin1 + ".blp";
|
||||||
|
} else if (!dispData.skin2.empty()) {
|
||||||
|
texPath = modelDir + dispData.skin2 + ".blp";
|
||||||
|
}
|
||||||
|
if (!texPath.empty()) {
|
||||||
|
GLuint skinTex = charRenderer->loadTexture(texPath);
|
||||||
|
if (skinTex != 0) {
|
||||||
|
charRenderer->setModelTexture(modelId, static_cast<uint32_t>(ti), skinTex);
|
||||||
|
LOG_INFO(" Forced skin on empty hardcoded slot ", ti, ": ", texPath);
|
||||||
|
replaced++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If still no textures, try hardcoded model texture filenames
|
||||||
|
if (replaced == 0) {
|
||||||
|
for (size_t ti = 0; ti < md->textures.size(); ti++) {
|
||||||
|
if (!md->textures[ti].filename.empty()) {
|
||||||
|
GLuint texId = charRenderer->loadTexture(md->textures[ti].filename);
|
||||||
|
if (texId != 0) {
|
||||||
|
charRenderer->setModelTexture(modelId, static_cast<uint32_t>(ti), texId);
|
||||||
|
LOG_INFO(" Used model embedded texture slot ", ti, ": ", md->textures[ti].filename);
|
||||||
|
replaced++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final fallback for gryphon/wyvern: try well-known skin texture names
|
||||||
if (replaced == 0 && !md->textures.empty()) {
|
if (replaced == 0 && !md->textures.empty()) {
|
||||||
std::string lowerMountPath = m2Path;
|
std::string lowerMountPath = m2Path;
|
||||||
std::transform(lowerMountPath.begin(), lowerMountPath.end(), lowerMountPath.begin(),
|
std::transform(lowerMountPath.begin(), lowerMountPath.end(), lowerMountPath.begin(),
|
||||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||||
if (lowerMountPath.find("creature\\gryphon\\gryphon.m2") != std::string::npos) {
|
if (lowerMountPath.find("gryphon") != std::string::npos) {
|
||||||
GLuint texId = charRenderer->loadTexture("Creature\\Gryphon\\Gryphon.blp");
|
const char* gryphonSkins[] = {
|
||||||
|
"Creature\\Gryphon\\Gryphon_Skin.blp",
|
||||||
|
"Creature\\Gryphon\\Gryphon_Skin01.blp",
|
||||||
|
"Creature\\Gryphon\\GRYPHON_SKIN01.BLP",
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
for (const char** p = gryphonSkins; *p; ++p) {
|
||||||
|
GLuint texId = charRenderer->loadTexture(*p);
|
||||||
if (texId != 0) {
|
if (texId != 0) {
|
||||||
charRenderer->setModelTexture(modelId, 0, texId);
|
charRenderer->setModelTexture(modelId, 0, texId);
|
||||||
LOG_INFO("Forced canonical gryphon texture on slot 0");
|
LOG_INFO(" Forced gryphon skin fallback: ", *p);
|
||||||
|
replaced++;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (lowerMountPath.find("creature\\wyvern\\wyvern.m2") != std::string::npos) {
|
}
|
||||||
GLuint texId = charRenderer->loadTexture("Creature\\Wyvern\\Wyvern.blp");
|
} else if (lowerMountPath.find("wyvern") != std::string::npos) {
|
||||||
|
const char* wyvernSkins[] = {
|
||||||
|
"Creature\\Wyvern\\Wyvern_Skin.blp",
|
||||||
|
"Creature\\Wyvern\\Wyvern_Skin01.blp",
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
for (const char** p = wyvernSkins; *p; ++p) {
|
||||||
|
GLuint texId = charRenderer->loadTexture(*p);
|
||||||
if (texId != 0) {
|
if (texId != 0) {
|
||||||
charRenderer->setModelTexture(modelId, 0, texId);
|
charRenderer->setModelTexture(modelId, 0, texId);
|
||||||
LOG_INFO("Forced canonical wyvern texture on slot 0");
|
LOG_INFO(" Forced wyvern skin fallback: ", *p);
|
||||||
|
replaced++;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LOG_INFO("Mount texture setup: ", replaced, " textures applied");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mountModelId_ = modelId;
|
mountModelId_ = modelId;
|
||||||
|
|
@ -4790,7 +4840,15 @@ void Application::processPendingMount() {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer->setMounted(instanceId, mountDisplayId, heightOffset, m2Path);
|
renderer->setMounted(instanceId, mountDisplayId, heightOffset, m2Path);
|
||||||
charRenderer->playAnimation(instanceId, 0, true);
|
|
||||||
|
// For taxi mounts, start with flying animation; for ground mounts, start with stand
|
||||||
|
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
|
||||||
|
}
|
||||||
|
charRenderer->playAnimation(instanceId, startAnim, true);
|
||||||
|
|
||||||
LOG_INFO("processPendingMount: DONE displayId=", mountDisplayId, " model=", m2Path, " heightOffset=", heightOffset);
|
LOG_INFO("processPendingMount: DONE displayId=", mountDisplayId, " model=", m2Path, " heightOffset=", heightOffset);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -948,6 +948,8 @@ void Renderer::updateCharacterAnimation() {
|
||||||
constexpr uint32_t ANIM_SWIM_IDLE = 41; // Treading water (SwimIdle)
|
constexpr uint32_t ANIM_SWIM_IDLE = 41; // Treading water (SwimIdle)
|
||||||
constexpr uint32_t ANIM_SWIM = 42; // Swimming forward (Swim)
|
constexpr uint32_t ANIM_SWIM = 42; // Swimming forward (Swim)
|
||||||
constexpr uint32_t ANIM_MOUNT = 91; // Seated on mount
|
constexpr uint32_t ANIM_MOUNT = 91; // Seated on mount
|
||||||
|
constexpr uint32_t ANIM_FLY_IDLE = 158; // Flying mount idle/hover
|
||||||
|
constexpr uint32_t ANIM_FLY_FORWARD = 159; // Flying mount forward
|
||||||
|
|
||||||
CharAnimState newState = charAnimState;
|
CharAnimState newState = charAnimState;
|
||||||
|
|
||||||
|
|
@ -1019,6 +1021,25 @@ void Renderer::updateCharacterAnimation() {
|
||||||
float curMountTime = 0, curMountDur = 0;
|
float curMountTime = 0, curMountDur = 0;
|
||||||
bool haveMountState = characterRenderer->getAnimationState(mountInstanceId_, curMountAnim, curMountTime, curMountDur);
|
bool haveMountState = characterRenderer->getAnimationState(mountInstanceId_, curMountAnim, curMountTime, curMountDur);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!haveMountState || curMountAnim != mountAnimId) {
|
||||||
|
characterRenderer->playAnimation(mountInstanceId_, mountAnimId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip all ground mount logic (jumps, fidgets, etc.)
|
||||||
|
goto taxi_mount_done;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for jump trigger - use cached per-mount animation IDs
|
// Check for jump trigger - use cached per-mount animation IDs
|
||||||
if (cameraController->isJumpKeyPressed() && grounded && mountAction_ == MountAction::None) {
|
if (cameraController->isJumpKeyPressed() && grounded && mountAction_ == MountAction::None) {
|
||||||
if (moving && mountAnims_.jumpLoop > 0) {
|
if (moving && mountAnims_.jumpLoop > 0) {
|
||||||
|
|
@ -1180,6 +1201,7 @@ void Renderer::updateCharacterAnimation() {
|
||||||
characterRenderer->playAnimation(mountInstanceId_, mountAnimId, loop);
|
characterRenderer->playAnimation(mountInstanceId_, mountAnimId, loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taxi_mount_done:
|
||||||
// Rider bob: sinusoidal motion synced to mount's run animation (only used in fallback positioning)
|
// Rider bob: sinusoidal motion synced to mount's run animation (only used in fallback positioning)
|
||||||
mountBob = 0.0f;
|
mountBob = 0.0f;
|
||||||
if (moving && haveMountState && curMountDur > 1.0f) {
|
if (moving && haveMountState && curMountDur > 1.0f) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue