Add transport support, gameobject queries, and fix item use

- Add setInstancePosition() to M2Renderer and WMORenderer for moving
  transport instances at runtime
- Detect UPDATEFLAG_TRANSPORT on gameobjects and track transport GUIDs
- Parse player-on-transport state from movement blocks
- Wire transport move callback in Application to update render positions
- Implement CMSG_GAMEOBJECT_QUERY / SMSG_GAMEOBJECT_QUERY_RESPONSE so
  gameobjects display proper names instead of "Unknown"
- Add name/entry fields to GameObject entity class
- Fix CMSG_USE_ITEM packet: remove extra uint8 that shifted the item
  GUID by one byte, breaking hearthstone and all item usage
- Remove redundant CMSG_LOOT after CMSG_GAMEOBJECT_USE for chests
- Show PvP enabled/disabled state in toggle message
- Relax WMO ramp wall-collision step-up check to allow walking on
  gentle ramps where floor rise per step is under 0.1 units
- Add M2 fallback when WMO group files fail to load for gameobjects
- Handle re-creation of existing gameobject render instances by
  updating position instead of silently ignoring
This commit is contained in:
Kelsi 2026-02-08 00:59:40 -08:00
parent 5610faa958
commit 0ce38cfb99
12 changed files with 391 additions and 65 deletions

View file

@ -256,10 +256,18 @@ public:
GameObject() { type = ObjectType::GAMEOBJECT; }
explicit GameObject(uint64_t guid) : Entity(guid) { type = ObjectType::GAMEOBJECT; }
const std::string& getName() const { return name; }
void setName(const std::string& n) { name = n; }
uint32_t getEntry() const { return entry; }
void setEntry(uint32_t e) { entry = e; }
uint32_t getDisplayId() const { return displayId; }
void setDisplayId(uint32_t id) { displayId = id; }
protected:
std::string name;
uint32_t entry = 0;
uint32_t displayId = 0;
};

View file

@ -5,6 +5,7 @@
#include "game/inventory.hpp"
#include "game/spell_defines.hpp"
#include "game/group_defines.hpp"
#include <glm/glm.hpp>
#include <memory>
#include <string>
#include <vector>
@ -297,6 +298,7 @@ public:
// ---- Phase 1: Name queries ----
void queryPlayerName(uint64_t guid);
void queryCreatureInfo(uint32_t entry, uint64_t guid);
void queryGameObjectInfo(uint32_t entry, uint64_t guid);
std::string getCachedPlayerName(uint64_t guid) const;
std::string getCachedCreatureName(uint32_t entry) const;
@ -395,6 +397,16 @@ public:
using CreatureMoveCallback = std::function<void(uint64_t guid, float x, float y, float z, uint32_t durationMs)>;
void setCreatureMoveCallback(CreatureMoveCallback cb) { creatureMoveCallback_ = std::move(cb); }
// Transport move callback (online mode - triggered when transport position updates)
// Parameters: guid, x, y, z (canonical), orientation
using TransportMoveCallback = std::function<void(uint64_t guid, float x, float y, float z, float orientation)>;
void setTransportMoveCallback(TransportMoveCallback cb) { transportMoveCallback_ = std::move(cb); }
// Transport state for player-on-transport
bool isOnTransport() const { return playerTransportGuid_ != 0; }
uint64_t getPlayerTransportGuid() const { return playerTransportGuid_; }
glm::vec3 getPlayerTransportOffset() const { return playerTransportOffset_; }
// Cooldowns
float getSpellCooldown(uint32_t spellId) const;
@ -600,6 +612,7 @@ private:
// ---- Phase 1 handlers ----
void handleNameQueryResponse(network::Packet& packet);
void handleCreatureQueryResponse(network::Packet& packet);
void handleGameObjectQueryResponse(network::Packet& packet);
void handleItemQueryResponse(network::Packet& packet);
void queryItemInfo(uint32_t entry, uint64_t guid);
void rebuildOnlineInventory();
@ -766,6 +779,8 @@ private:
std::unordered_set<uint64_t> pendingNameQueries;
std::unordered_map<uint32_t, CreatureQueryResponseData> creatureInfoCache;
std::unordered_set<uint32_t> pendingCreatureQueries;
std::unordered_map<uint32_t, GameObjectQueryResponseData> gameObjectInfoCache_;
std::unordered_set<uint32_t> pendingGameObjectQueries_;
// ---- Friend list cache ----
std::unordered_map<std::string, uint64_t> friendsCache; // name -> guid
@ -818,8 +833,14 @@ private:
CreatureSpawnCallback creatureSpawnCallback_;
CreatureDespawnCallback creatureDespawnCallback_;
CreatureMoveCallback creatureMoveCallback_;
TransportMoveCallback transportMoveCallback_;
GameObjectSpawnCallback gameObjectSpawnCallback_;
GameObjectDespawnCallback gameObjectDespawnCallback_;
// Transport tracking
std::unordered_set<uint64_t> transportGuids_; // GUIDs of known transport GameObjects
uint64_t playerTransportGuid_ = 0; // Transport the player is riding (0 = none)
glm::vec3 playerTransportOffset_ = glm::vec3(0.0f); // Player offset on transport
std::vector<uint32_t> knownSpells;
std::unordered_map<uint32_t, float> spellCooldowns; // spellId -> remaining seconds
uint8_t castCount = 0;

View file

@ -451,6 +451,14 @@ struct UpdateBlock {
float x = 0.0f, y = 0.0f, z = 0.0f, orientation = 0.0f;
float runSpeed = 0.0f;
// Update flags from movement block (for detecting transports, etc.)
uint16_t updateFlags = 0;
// Transport data from LIVING movement block (MOVEMENTFLAG_ONTRANSPORT)
bool onTransport = false;
uint64_t transportGuid = 0;
float transportX = 0.0f, transportY = 0.0f, transportZ = 0.0f, transportO = 0.0f;
// Field data (for VALUES and CREATE updates)
std::map<uint16_t, uint32_t> fields;
};
@ -1050,6 +1058,31 @@ public:
static bool parse(network::Packet& packet, CreatureQueryResponseData& data);
};
// ============================================================
// GameObject Query
// ============================================================
/** CMSG_GAMEOBJECT_QUERY packet builder */
class GameObjectQueryPacket {
public:
static network::Packet build(uint32_t entry, uint64_t guid);
};
/** SMSG_GAMEOBJECT_QUERY_RESPONSE data */
struct GameObjectQueryResponseData {
uint32_t entry = 0;
std::string name;
uint32_t type = 0; // GameObjectType (e.g. 3=chest, 2=questgiver)
bool isValid() const { return entry != 0 && !name.empty(); }
};
/** SMSG_GAMEOBJECT_QUERY_RESPONSE parser */
class GameObjectQueryResponseParser {
public:
static bool parse(network::Packet& packet, GameObjectQueryResponseData& data);
};
// ============================================================
// Item Query
// ============================================================