Add mount system and crash mouse-release handler

Render mount M2 model under player with seated animation, apply creature
skin textures, server-driven speed via SMSG_FORCE_RUN_SPEED_CHANGE, and
/dismount command. X11 XUngrabPointer on crash/hang to always release mouse.
This commit is contained in:
Kelsi 2026-02-07 17:59:40 -08:00
parent 4a932dd8cd
commit 643611ee79
13 changed files with 363 additions and 3 deletions

View file

@ -189,6 +189,10 @@ public:
uint32_t getDisplayId() const { return displayId; }
void setDisplayId(uint32_t id) { displayId = id; }
// Mount display ID (UNIT_FIELD_MOUNTDISPLAYID, index 69)
uint32_t getMountDisplayId() const { return mountDisplayId; }
void setMountDisplayId(uint32_t id) { mountDisplayId = id; }
// Unit flags (UNIT_FIELD_FLAGS, index 59)
uint32_t getUnitFlags() const { return unitFlags; }
void setUnitFlags(uint32_t f) { unitFlags = f; }
@ -216,6 +220,7 @@ protected:
uint32_t level = 1;
uint32_t entry = 0;
uint32_t displayId = 0;
uint32_t mountDisplayId = 0;
uint32_t unitFlags = 0;
uint32_t npcFlags = 0;
uint32_t factionTemplate = 0;

View file

@ -455,6 +455,13 @@ public:
}
const std::unordered_map<uint64_t, QuestGiverStatus>& getNpcQuestStatuses() const { return npcQuestStatus_; }
// Mount state
using MountCallback = std::function<void(uint32_t mountDisplayId)>; // 0 = dismount
void setMountCallback(MountCallback cb) { mountCallback_ = std::move(cb); }
bool isMounted() const { return currentMountDisplayId_ != 0; }
float getServerRunSpeed() const { return serverRunSpeed_; }
void dismount();
// Taxi / Flight Paths
bool isTaxiWindowOpen() const { return taxiWindowOpen_; }
void closeTaxi();
@ -630,6 +637,9 @@ private:
// ---- Teleport handler ----
void handleTeleportAck(network::Packet& packet);
// ---- Speed change handler ----
void handleForceRunSpeedChange(network::Packet& packet);
// ---- Taxi handlers ----
void handleShowTaxiNodes(network::Packet& packet);
void handleActivateTaxiReply(network::Packet& packet);
@ -844,6 +854,8 @@ private:
ShowTaxiNodesData currentTaxiData_;
uint64_t taxiNpcGuid_ = 0;
bool onTaxiFlight_ = false;
uint32_t knownTaxiMask_[12] = {}; // Track previously known nodes for discovery alerts
bool taxiMaskInitialized_ = false; // First SMSG_SHOWTAXINODES seeds mask without alerts
// Vendor
bool vendorWindowOpen = false;
@ -877,6 +889,9 @@ private:
NpcRespawnCallback npcRespawnCallback_;
MeleeSwingCallback meleeSwingCallback_;
NpcSwingCallback npcSwingCallback_;
MountCallback mountCallback_;
uint32_t currentMountDisplayId_ = 0;
float serverRunSpeed_ = 7.0f;
bool playerDead_ = false;
};

View file

@ -241,9 +241,16 @@ enum class Opcode : uint16_t {
MSG_MOVE_TELEPORT_ACK = 0x0C7,
SMSG_TRANSFER_PENDING = 0x003F,
// ---- Speed Changes ----
SMSG_FORCE_RUN_SPEED_CHANGE = 0x00E2,
// ---- Mount ----
CMSG_CANCEL_MOUNT_AURA = 0x0375,
// ---- Taxi / Flight Paths ----
SMSG_SHOWTAXINODES = 0x01A9,
SMSG_ACTIVATETAXIREPLY = 0x01AE,
SMSG_NEW_TAXI_PATH = 0x01AF,
CMSG_ACTIVATETAXIEXPRESS = 0x0312,
};