game/rendering: drive Walk(4) and swim state from movement flags

Add UnitMoveFlagsCallback fired on every MSG_MOVE_* with the raw
movement flags field. Application.cpp uses it to update swimming
and walking state from any packet, not just explicit START_SWIM/
STOP_SWIM opcodes — fixing cold-join cases where a player is already
swimming when we enter the world.

Per-frame animation sync now selects Walk(4) when the WALKING flag is
set, Run(5) otherwise, and Swim(42)/SwimIdle(41) when swimming.
UnitAnimHintCallback is simplified to jump (38=JumpMid) only.
This commit is contained in:
Kelsi 2026-03-10 10:55:23 -07:00
parent 333ada8eb6
commit d7ebc5c8c7
4 changed files with 41 additions and 24 deletions

View file

@ -188,7 +188,8 @@ private:
std::unordered_map<uint64_t, uint32_t> creatureModelIds_; // guid → loaded modelId
std::unordered_map<uint64_t, glm::vec3> creatureRenderPosCache_; // guid -> last synced render position
std::unordered_map<uint64_t, bool> creatureWasMoving_; // guid -> previous-frame movement state
std::unordered_map<uint64_t, bool> creatureSwimmingState_; // guid -> currently in swim mode
std::unordered_map<uint64_t, bool> creatureSwimmingState_; // guid -> currently in swim mode (SWIMMING flag)
std::unordered_map<uint64_t, bool> creatureWalkingState_; // guid -> walking (WALKING flag, selects Walk(4) vs Run(5))
std::unordered_set<uint64_t> creatureWeaponsAttached_; // guid set when NPC virtual weapons attached
std::unordered_map<uint64_t, uint8_t> creatureWeaponAttachAttempts_; // guid -> attach attempts
std::unordered_map<uint32_t, bool> modelIdIsWolfLike_; // modelId → cached wolf/worg check

View file

@ -637,10 +637,15 @@ public:
using SpellCastAnimCallback = std::function<void(uint64_t guid, bool start, bool isChannel)>;
void setSpellCastAnimCallback(SpellCastAnimCallback cb) { spellCastAnimCallback_ = std::move(cb); }
// Unit animation hint: signal jump (animId=38) or swim (animId=42) for other players/NPCs
// Unit animation hint: signal jump (animId=38) for other players/NPCs
using UnitAnimHintCallback = std::function<void(uint64_t guid, uint32_t animId)>;
void setUnitAnimHintCallback(UnitAnimHintCallback cb) { unitAnimHintCallback_ = std::move(cb); }
// Unit move-flags callback: fired on every MSG_MOVE_* for other players with the raw flags field.
// Drives Walk(4) vs Run(5) selection and swim state initialization from heartbeat packets.
using UnitMoveFlagsCallback = std::function<void(uint64_t guid, uint32_t moveFlags)>;
void setUnitMoveFlagsCallback(UnitMoveFlagsCallback cb) { unitMoveFlagsCallback_ = std::move(cb); }
// NPC swing callback (plays attack animation on NPC)
using NpcSwingCallback = std::function<void(uint64_t guid)>;
void setNpcSwingCallback(NpcSwingCallback cb) { npcSwingCallback_ = std::move(cb); }
@ -2268,6 +2273,7 @@ private:
MeleeSwingCallback meleeSwingCallback_;
SpellCastAnimCallback spellCastAnimCallback_;
UnitAnimHintCallback unitAnimHintCallback_;
UnitMoveFlagsCallback unitMoveFlagsCallback_;
NpcSwingCallback npcSwingCallback_;
NpcGreetingCallback npcGreetingCallback_;
NpcFarewellCallback npcFarewellCallback_;