mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 00:03:50 +00:00
rendering/game: fix other-player movement animations and add jump/swim hints
- MSG_MOVE_STOP/STOP_STRAFE/STOP_TURN/STOP_SWIM/FALL_LAND: snap entity to stop position (duration=0) and pass durationMs=0 to renderer so the Run-animation flash is suppressed; per-frame sync plays Stand on next frame - MSG_MOVE_JUMP: fire new UnitAnimHintCallback with anim 38 (JumpMid) so other players and NPCs visually leave the ground during jumps - MSG_MOVE_START_SWIM: fire UnitAnimHintCallback with anim 42 (Swim) - Wire up UnitAnimHintCallback in application.cpp; skips Death (anim 1)
This commit is contained in:
parent
137b25f318
commit
14c2bc97b1
3 changed files with 54 additions and 3 deletions
|
|
@ -637,6 +637,10 @@ public:
|
||||||
using SpellCastAnimCallback = std::function<void(uint64_t guid, bool start, bool isChannel)>;
|
using SpellCastAnimCallback = std::function<void(uint64_t guid, bool start, bool isChannel)>;
|
||||||
void setSpellCastAnimCallback(SpellCastAnimCallback cb) { spellCastAnimCallback_ = std::move(cb); }
|
void setSpellCastAnimCallback(SpellCastAnimCallback cb) { spellCastAnimCallback_ = std::move(cb); }
|
||||||
|
|
||||||
|
// Unit animation hint: signal jump (animId=38) or swim (animId=42) for other players/NPCs
|
||||||
|
using UnitAnimHintCallback = std::function<void(uint64_t guid, uint32_t animId)>;
|
||||||
|
void setUnitAnimHintCallback(UnitAnimHintCallback cb) { unitAnimHintCallback_ = std::move(cb); }
|
||||||
|
|
||||||
// NPC swing callback (plays attack animation on NPC)
|
// NPC swing callback (plays attack animation on NPC)
|
||||||
using NpcSwingCallback = std::function<void(uint64_t guid)>;
|
using NpcSwingCallback = std::function<void(uint64_t guid)>;
|
||||||
void setNpcSwingCallback(NpcSwingCallback cb) { npcSwingCallback_ = std::move(cb); }
|
void setNpcSwingCallback(NpcSwingCallback cb) { npcSwingCallback_ = std::move(cb); }
|
||||||
|
|
@ -2263,6 +2267,7 @@ private:
|
||||||
GhostStateCallback ghostStateCallback_;
|
GhostStateCallback ghostStateCallback_;
|
||||||
MeleeSwingCallback meleeSwingCallback_;
|
MeleeSwingCallback meleeSwingCallback_;
|
||||||
SpellCastAnimCallback spellCastAnimCallback_;
|
SpellCastAnimCallback spellCastAnimCallback_;
|
||||||
|
UnitAnimHintCallback unitAnimHintCallback_;
|
||||||
NpcSwingCallback npcSwingCallback_;
|
NpcSwingCallback npcSwingCallback_;
|
||||||
NpcGreetingCallback npcGreetingCallback_;
|
NpcGreetingCallback npcGreetingCallback_;
|
||||||
NpcFarewellCallback npcFarewellCallback_;
|
NpcFarewellCallback npcFarewellCallback_;
|
||||||
|
|
|
||||||
|
|
@ -2771,6 +2771,29 @@ void Application::setupUICallbacks() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Unit animation hint callback — play jump (38) or swim (42) on other players/NPCs
|
||||||
|
// when MSG_MOVE_JUMP or MSG_MOVE_START_SWIM arrives. The per-frame sync handles the
|
||||||
|
// return to Stand/Run once the unit lands or exits water.
|
||||||
|
gameHandler->setUnitAnimHintCallback([this](uint64_t guid, uint32_t animId) {
|
||||||
|
if (!renderer) return;
|
||||||
|
auto* cr = renderer->getCharacterRenderer();
|
||||||
|
if (!cr) return;
|
||||||
|
uint32_t instanceId = 0;
|
||||||
|
{
|
||||||
|
auto it = playerInstances_.find(guid);
|
||||||
|
if (it != playerInstances_.end()) instanceId = it->second;
|
||||||
|
}
|
||||||
|
if (instanceId == 0) {
|
||||||
|
auto it = creatureInstances_.find(guid);
|
||||||
|
if (it != creatureInstances_.end()) instanceId = it->second;
|
||||||
|
}
|
||||||
|
if (instanceId == 0) return;
|
||||||
|
// Don't override Death animation (1)
|
||||||
|
uint32_t curAnim = 0; float curT = 0.0f, curDur = 0.0f;
|
||||||
|
if (cr->getAnimationState(instanceId, curAnim, curT, curDur) && curAnim == 1) return;
|
||||||
|
cr->playAnimation(instanceId, animId, /*loop=*/true);
|
||||||
|
});
|
||||||
|
|
||||||
// Emote animation callback — play server-driven emote animations on NPCs and other players
|
// Emote animation callback — play server-driven emote animations on NPCs and other players
|
||||||
gameHandler->setEmoteAnimCallback([this](uint64_t guid, uint32_t emoteAnim) {
|
gameHandler->setEmoteAnimCallback([this](uint64_t guid, uint32_t emoteAnim) {
|
||||||
if (!renderer || emoteAnim == 0) return;
|
if (!renderer || emoteAnim == 0) return;
|
||||||
|
|
|
||||||
|
|
@ -12165,11 +12165,34 @@ void GameHandler::handleOtherPlayerMovement(network::Packet& packet) {
|
||||||
}
|
}
|
||||||
otherPlayerMoveTimeMs_[moverGuid] = info.time;
|
otherPlayerMoveTimeMs_[moverGuid] = info.time;
|
||||||
|
|
||||||
entity->startMoveTo(canonical.x, canonical.y, canonical.z, canYaw, durationMs / 1000.0f);
|
// Classify the opcode so we can drive the correct entity update and animation.
|
||||||
|
const uint16_t wireOp = packet.getOpcode();
|
||||||
|
const bool isStopOpcode =
|
||||||
|
(wireOp == wireOpcode(Opcode::MSG_MOVE_STOP)) ||
|
||||||
|
(wireOp == wireOpcode(Opcode::MSG_MOVE_STOP_STRAFE)) ||
|
||||||
|
(wireOp == wireOpcode(Opcode::MSG_MOVE_STOP_TURN)) ||
|
||||||
|
(wireOp == wireOpcode(Opcode::MSG_MOVE_STOP_SWIM)) ||
|
||||||
|
(wireOp == wireOpcode(Opcode::MSG_MOVE_FALL_LAND));
|
||||||
|
const bool isJumpOpcode = (wireOp == wireOpcode(Opcode::MSG_MOVE_JUMP));
|
||||||
|
const bool isSwimOpcode = (wireOp == wireOpcode(Opcode::MSG_MOVE_START_SWIM));
|
||||||
|
|
||||||
// Notify renderer
|
// For stop opcodes snap the entity position (duration=0) so it doesn't keep interpolating,
|
||||||
|
// and pass durationMs=0 to the renderer so the Run-anim flash is suppressed.
|
||||||
|
// The per-frame sync will detect no movement and play Stand on the next frame.
|
||||||
|
const float entityDuration = isStopOpcode ? 0.0f : (durationMs / 1000.0f);
|
||||||
|
entity->startMoveTo(canonical.x, canonical.y, canonical.z, canYaw, entityDuration);
|
||||||
|
|
||||||
|
// Notify renderer of position change
|
||||||
if (creatureMoveCallback_) {
|
if (creatureMoveCallback_) {
|
||||||
creatureMoveCallback_(moverGuid, canonical.x, canonical.y, canonical.z, durationMs);
|
const uint32_t notifyDuration = isStopOpcode ? 0u : durationMs;
|
||||||
|
creatureMoveCallback_(moverGuid, canonical.x, canonical.y, canonical.z, notifyDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal specific animation transitions that the per-frame sync can't detect reliably.
|
||||||
|
// WoW M2 animation IDs: 38=JumpMid (loops during airborne), 42=Swim
|
||||||
|
if (unitAnimHintCallback_) {
|
||||||
|
if (isJumpOpcode) unitAnimHintCallback_(moverGuid, 38u);
|
||||||
|
else if (isSwimOpcode) unitAnimHintCallback_(moverGuid, 42u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue