Fix taxi flights, mounts, and movement recovery

This commit is contained in:
Kelsi 2026-02-08 03:05:38 -08:00
parent d910073d7a
commit 6736ec328b
13 changed files with 607 additions and 49 deletions

View file

@ -70,6 +70,8 @@ public:
const std::vector<std::string>& getUnderwearPaths() const { return underwearPaths_; }
uint32_t getSkinTextureSlotIndex() const { return skinTextureSlotIndex_; }
uint32_t getCloakTextureSlotIndex() const { return cloakTextureSlotIndex_; }
uint32_t getGryphonDisplayId() const { return gryphonDisplayId_; }
uint32_t getWyvernDisplayId() const { return wyvernDisplayId_; }
private:
void update(float deltaTime);
@ -154,6 +156,10 @@ private:
std::unordered_map<uint64_t, uint32_t> creatureModelIds_; // guid → loaded modelId
std::unordered_map<uint32_t, uint32_t> displayIdModelCache_; // displayId → modelId (model caching)
uint32_t nextCreatureModelId_ = 5000; // Model IDs for online creatures
uint32_t gryphonDisplayId_ = 0;
uint32_t wyvernDisplayId_ = 0;
bool lastTaxiFlight_ = false;
float taxiStreamCooldown_ = 0.0f;
// Online gameobject model spawning
struct GameObjectInstanceInfo {

View file

@ -503,6 +503,8 @@ public:
uint32_t mapId = 0;
float x = 0, y = 0, z = 0;
std::string name;
uint32_t mountDisplayIdAlliance = 0;
uint32_t mountDisplayIdHorde = 0;
};
struct TaxiPathEdge {
uint32_t pathId = 0;
@ -668,6 +670,7 @@ private:
// ---- Teleport handler ----
void handleTeleportAck(network::Packet& packet);
void handleNewWorld(network::Packet& packet);
// ---- Speed change handler ----
void handleForceRunSpeedChange(network::Packet& packet);
@ -858,6 +861,7 @@ private:
std::string pendingInviterName;
uint64_t activeCharacterGuid_ = 0;
Race playerRace_ = Race::HUMAN;
// ---- Phase 5: Loot ----
bool lootWindowOpen = false;
@ -904,10 +908,25 @@ private:
ShowTaxiNodesData currentTaxiData_;
uint64_t taxiNpcGuid_ = 0;
bool onTaxiFlight_ = false;
bool taxiMountActive_ = false;
uint32_t taxiMountDisplayId_ = 0;
bool taxiActivatePending_ = false;
float taxiActivateTimer_ = 0.0f;
bool taxiClientActive_ = false;
size_t taxiClientIndex_ = 0;
std::vector<glm::vec3> taxiClientPath_;
float taxiClientSpeed_ = 32.0f;
float taxiClientSegmentProgress_ = 0.0f;
bool taxiRecoverPending_ = false;
uint32_t taxiRecoverMapId_ = 0;
glm::vec3 taxiRecoverPos_{0.0f};
uint32_t knownTaxiMask_[12] = {}; // Track previously known nodes for discovery alerts
bool taxiMaskInitialized_ = false; // First SMSG_SHOWTAXINODES seeds mask without alerts
std::unordered_map<uint32_t, uint32_t> taxiCostMap_; // destNodeId -> total cost in copper
void buildTaxiCostMap();
void applyTaxiMountForCurrentNode();
void startClientTaxiPath(const std::vector<uint32_t>& pathNodes);
void updateClientTaxi(float deltaTime);
// Vendor
bool vendorWindowOpen = false;

View file

@ -250,6 +250,9 @@ enum class Opcode : uint16_t {
// ---- Teleport / Transfer ----
MSG_MOVE_TELEPORT_ACK = 0x0C7,
SMSG_TRANSFER_PENDING = 0x003F,
SMSG_NEW_WORLD = 0x003E,
MSG_MOVE_WORLDPORT_ACK = 0x00DC,
SMSG_TRANSFER_ABORTED = 0x0040,
// ---- Speed Changes ----
SMSG_FORCE_RUN_SPEED_CHANGE = 0x00E2,
@ -261,6 +264,8 @@ enum class Opcode : uint16_t {
// ---- Taxi / Flight Paths ----
SMSG_SHOWTAXINODES = 0x01A9,
SMSG_ACTIVATETAXIREPLY = 0x01AE,
// Some cores send activate taxi reply on 0x029D (observed in logs)
SMSG_ACTIVATETAXIREPLY_ALT = 0x029D,
SMSG_NEW_TAXI_PATH = 0x01AF,
CMSG_ACTIVATETAXIEXPRESS = 0x0312,

View file

@ -1733,7 +1733,7 @@ public:
/** CMSG_ACTIVATETAXIEXPRESS packet builder */
class ActivateTaxiExpressPacket {
public:
static network::Packet build(uint64_t npcGuid, const std::vector<uint32_t>& pathNodes);
static network::Packet build(uint64_t npcGuid, uint32_t totalCost, const std::vector<uint32_t>& pathNodes);
};
/** CMSG_ACTIVATETAXI packet builder */

View file

@ -75,6 +75,9 @@ public:
void setRunSpeedOverride(float speed) { runSpeedOverride_ = speed; }
void setMounted(bool m) { mounted_ = m; }
void setMountHeightOffset(float offset) { mountHeightOffset_ = offset; }
void setExternalFollow(bool enabled) { externalFollow_ = enabled; }
void setExternalMoving(bool moving) { externalMoving_ = moving; }
void clearMovementInputs();
// For first-person player hiding
void setCharacterRenderer(class CharacterRenderer* cr, uint32_t playerId) {
@ -113,6 +116,7 @@ private:
float userTargetDistance = 10.0f; // What the player wants (scroll wheel)
float currentDistance = 10.0f; // Smoothed actual distance
float collisionDistance = 10.0f; // Max allowed by collision
bool externalFollow_ = false;
static constexpr float MIN_DISTANCE = 0.5f; // Minimum zoom (first-person threshold)
static constexpr float MAX_DISTANCE = 50.0f; // Maximum zoom out
static constexpr float ZOOM_SMOOTH_SPEED = 15.0f; // How fast zoom eases
@ -195,6 +199,7 @@ private:
float runSpeedOverride_ = 0.0f;
bool mounted_ = false;
float mountHeightOffset_ = 0.0f;
bool externalMoving_ = false;
// Online mode: trust server position, don't prefer outdoors over WMO floors
bool onlineMode = false;

View file

@ -111,6 +111,7 @@ public:
glm::vec3& getCharacterPosition() { return characterPosition; }
uint32_t getCharacterInstanceId() const { return characterInstanceId; }
float getCharacterYaw() const { return characterYaw; }
void setCharacterYaw(float yawDeg) { characterYaw = yawDeg; }
// Emote support
void playEmote(const std::string& emoteName);
@ -127,6 +128,7 @@ public:
// Mount rendering
void setMounted(uint32_t mountInstId, float heightOffset);
void setTaxiFlight(bool onTaxi) { taxiFlight_ = onTaxi; }
void clearMount();
bool isMounted() const { return mountInstanceId_ != 0; }
@ -272,6 +274,7 @@ private:
// Mount state
uint32_t mountInstanceId_ = 0;
float mountHeightOffset_ = 0.0f;
bool taxiFlight_ = false;
bool terrainEnabled = true;
bool terrainLoaded = false;

View file

@ -171,6 +171,7 @@ public:
void setLoadRadius(int radius) { loadRadius = radius; }
void setUnloadRadius(int radius) { unloadRadius = radius; }
void setStreamingEnabled(bool enabled) { streamingEnabled = enabled; }
void setUpdateInterval(float seconds) { updateInterval = seconds; }
void setWaterRenderer(WaterRenderer* renderer) { waterRenderer = renderer; }
void setM2Renderer(M2Renderer* renderer) { m2Renderer = renderer; }
void setWMORenderer(WMORenderer* renderer) { wmoRenderer = renderer; }