Fix online mode creature spawning and packet parsing

- Fix encryption desync by tracking decrypted header bytes in world socket
- Fix UPDATE_OBJECT movement block parsing to handle 3.3.5a update flags
- Fix UNIT_FIELD_DISPLAYID index (67, not 71)
- Add creature spawn/despawn callbacks with DBC-based model loading
- Add SMSG_COMPRESSED_UPDATE_OBJECT opcode support
This commit is contained in:
Kelsi 2026-02-05 21:55:52 -08:00
parent a4fcc38c12
commit c28376e193
9 changed files with 445 additions and 30 deletions

View file

@ -6,6 +6,7 @@
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
namespace wowee {
@ -81,6 +82,10 @@ private:
std::string getPlayerModelPath() const;
static const char* mapIdToName(uint32_t mapId);
void loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float z);
void spawnOnlineCreature(uint64_t guid, uint32_t displayId, float x, float y, float z, float orientation);
void despawnOnlineCreature(uint64_t guid);
void buildCreatureDisplayLookups();
std::string getModelPathForDisplayId(uint32_t displayId) const;
static Application* instance;
@ -118,6 +123,14 @@ private:
std::vector<std::string> underwearPaths_;
uint32_t skinTextureSlotIndex_ = 0;
uint32_t cloakTextureSlotIndex_ = 0;
// Online creature model spawning
std::unordered_map<uint32_t, uint32_t> displayToModelId_; // displayId → modelId (from CreatureDisplayInfo.dbc)
std::unordered_map<uint32_t, std::string> modelIdToPath_; // modelId → M2 path (from CreatureModelData.dbc)
std::unordered_map<uint64_t, uint32_t> creatureInstances_; // guid → render instanceId
std::unordered_map<uint64_t, uint32_t> creatureModelIds_; // guid → loaded modelId
uint32_t nextCreatureModelId_ = 5000; // Model IDs for online creatures
bool creatureLookupsBuilt_ = false;
};
} // namespace core

View file

@ -147,6 +147,10 @@ public:
uint32_t getEntry() const { return entry; }
void setEntry(uint32_t e) { entry = e; }
// Display ID (model display)
uint32_t getDisplayId() const { return displayId; }
void setDisplayId(uint32_t id) { displayId = id; }
protected:
std::string name;
uint32_t health = 0;
@ -156,6 +160,7 @@ protected:
uint8_t powerType = 0; // 0=mana, 1=rage, 2=focus, 3=energy
uint32_t level = 1;
uint32_t entry = 0;
uint32_t displayId = 0;
};
/**

View file

@ -276,6 +276,15 @@ public:
using WorldEntryCallback = std::function<void(uint32_t mapId, float x, float y, float z)>;
void setWorldEntryCallback(WorldEntryCallback cb) { worldEntryCallback_ = std::move(cb); }
// Creature spawn callback (online mode - triggered when creature enters view)
// Parameters: guid, displayId, x, y, z (canonical), orientation
using CreatureSpawnCallback = std::function<void(uint64_t guid, uint32_t displayId, float x, float y, float z, float orientation)>;
void setCreatureSpawnCallback(CreatureSpawnCallback cb) { creatureSpawnCallback_ = std::move(cb); }
// Creature despawn callback (online mode - triggered when creature leaves view)
using CreatureDespawnCallback = std::function<void(uint64_t guid)>;
void setCreatureDespawnCallback(CreatureDespawnCallback cb) { creatureDespawnCallback_ = std::move(cb); }
// Cooldowns
float getSpellCooldown(uint32_t spellId) const;
@ -383,6 +392,11 @@ private:
*/
void handleUpdateObject(network::Packet& packet);
/**
* Handle SMSG_COMPRESSED_UPDATE_OBJECT from server
*/
void handleCompressedUpdateObject(network::Packet& packet);
/**
* Handle SMSG_DESTROY_OBJECT from server
*/
@ -529,6 +543,8 @@ private:
// ---- Phase 3: Spells ----
HearthstoneCallback hearthstoneCallback;
WorldEntryCallback worldEntryCallback_;
CreatureSpawnCallback creatureSpawnCallback_;
CreatureDespawnCallback creatureDespawnCallback_;
std::vector<uint32_t> knownSpells;
std::unordered_map<uint32_t, float> spellCooldowns; // spellId -> remaining seconds
uint8_t castCount = 0;

View file

@ -46,6 +46,7 @@ enum class Opcode : uint16_t {
// ---- Entity/Object updates ----
SMSG_UPDATE_OBJECT = 0x0A9,
SMSG_COMPRESSED_UPDATE_OBJECT = 0x1F6,
SMSG_DESTROY_OBJECT = 0x0AA,
// ---- Chat ----

View file

@ -85,6 +85,10 @@ private:
// Receive buffer
std::vector<uint8_t> receiveBuffer;
// Track how many header bytes have been decrypted (0-4)
// This prevents re-decrypting the same header when waiting for more data
size_t headerBytesDecrypted = 0;
// Packet callback
std::function<void(const Packet&)> packetCallback;
};