mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-25 00:20:16 +00:00
Fix vanilla M2 animations, movement packets, and DBC locale
- Parse vanilla M2 animation tracks (flat arrays with M2Range indices) instead of skipping them, fixing T-pose on all vanilla models - Use C4Quaternion (float[4]) for vanilla bone rotations instead of CompressedQuat (int16[4]) which produced garbage transforms - Fix vanilla M2 attachment struct size (48 bytes, not 40) so weapons attach to correct bones instead of model origin - Route movement packets through expansion-specific packet parsers instead of hardcoded WotLK format, fixing server-side position sync - Fix Spell.dbc field indices for classic/turtle (Name=120, Rank=129, IconID=117) - were pointing to Portuguese locale column (+7 offset) - Change guild roster keybind from J to O (WoW default) - Add guild opcodes for all expansions
This commit is contained in:
parent
60c93fa1e3
commit
22728b461f
16 changed files with 951 additions and 26 deletions
|
|
@ -314,6 +314,19 @@ public:
|
|||
void demoteGuildMember(const std::string& playerName);
|
||||
void leaveGuild();
|
||||
void inviteToGuild(const std::string& playerName);
|
||||
void kickGuildMember(const std::string& playerName);
|
||||
void acceptGuildInvite();
|
||||
void declineGuildInvite();
|
||||
void queryGuildInfo(uint32_t guildId);
|
||||
|
||||
// Guild state accessors
|
||||
bool isInGuild() const { return !guildName_.empty(); }
|
||||
const std::string& getGuildName() const { return guildName_; }
|
||||
const GuildRosterData& getGuildRoster() const { return guildRoster_; }
|
||||
bool hasGuildRoster() const { return hasGuildRoster_; }
|
||||
bool hasPendingGuildInvite() const { return pendingGuildInvite_; }
|
||||
const std::string& getPendingGuildInviterName() const { return pendingGuildInviterName_; }
|
||||
const std::string& getPendingGuildInviteGuildName() const { return pendingGuildInviteGuildName_; }
|
||||
|
||||
// Ready check
|
||||
void initiateReadyCheck();
|
||||
|
|
@ -878,6 +891,14 @@ private:
|
|||
void handleGroupUninvite(network::Packet& packet);
|
||||
void handlePartyCommandResult(network::Packet& packet);
|
||||
|
||||
// ---- Guild handlers ----
|
||||
void handleGuildInfo(network::Packet& packet);
|
||||
void handleGuildRoster(network::Packet& packet);
|
||||
void handleGuildQueryResponse(network::Packet& packet);
|
||||
void handleGuildEvent(network::Packet& packet);
|
||||
void handleGuildInvite(network::Packet& packet);
|
||||
void handleGuildCommandResult(network::Packet& packet);
|
||||
|
||||
// ---- Character creation handler ----
|
||||
void handleCharCreateResponse(network::Packet& packet);
|
||||
|
||||
|
|
@ -1155,6 +1176,15 @@ private:
|
|||
bool pendingGroupInvite = false;
|
||||
std::string pendingInviterName;
|
||||
|
||||
// ---- Guild state ----
|
||||
std::string guildName_;
|
||||
std::vector<std::string> guildRankNames_;
|
||||
GuildRosterData guildRoster_;
|
||||
bool hasGuildRoster_ = false;
|
||||
bool pendingGuildInvite_ = false;
|
||||
std::string pendingGuildInviterName_;
|
||||
std::string pendingGuildInviteGuildName_;
|
||||
|
||||
uint64_t activeCharacterGuid_ = 0;
|
||||
Race playerRace_ = Race::HUMAN;
|
||||
|
||||
|
|
|
|||
|
|
@ -114,6 +114,18 @@ public:
|
|||
return DestroyObjectParser::parse(packet, data);
|
||||
}
|
||||
|
||||
// --- Guild ---
|
||||
|
||||
/** Parse SMSG_GUILD_ROSTER */
|
||||
virtual bool parseGuildRoster(network::Packet& packet, GuildRosterData& data) {
|
||||
return GuildRosterParser::parse(packet, data);
|
||||
}
|
||||
|
||||
/** Parse SMSG_GUILD_QUERY_RESPONSE */
|
||||
virtual bool parseGuildQueryResponse(network::Packet& packet, GuildQueryResponseData& data) {
|
||||
return GuildQueryResponseParser::parse(packet, data);
|
||||
}
|
||||
|
||||
// --- Utility ---
|
||||
|
||||
/** Read a packed GUID from the packet */
|
||||
|
|
@ -190,6 +202,8 @@ public:
|
|||
const MovementInfo& info,
|
||||
uint64_t playerGuid = 0) override;
|
||||
bool parseMessageChat(network::Packet& packet, MessageChatData& data) override;
|
||||
bool parseGuildRoster(network::Packet& packet, GuildRosterData& data) override;
|
||||
bool parseGuildQueryResponse(network::Packet& packet, GuildQueryResponseData& data) override;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -880,6 +880,166 @@ public:
|
|||
static network::Packet build(const std::string& playerName);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_QUERY packet builder */
|
||||
class GuildQueryPacket {
|
||||
public:
|
||||
static network::Packet build(uint32_t guildId);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_REMOVE packet builder */
|
||||
class GuildRemovePacket {
|
||||
public:
|
||||
static network::Packet build(const std::string& playerName);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_ACCEPT packet builder (empty body) */
|
||||
class GuildAcceptPacket {
|
||||
public:
|
||||
static network::Packet build();
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_DECLINE_INVITATION packet builder (empty body) */
|
||||
class GuildDeclineInvitationPacket {
|
||||
public:
|
||||
static network::Packet build();
|
||||
};
|
||||
|
||||
// Guild event type constants
|
||||
namespace GuildEvent {
|
||||
constexpr uint8_t PROMOTION = 0;
|
||||
constexpr uint8_t DEMOTION = 1;
|
||||
constexpr uint8_t MOTD = 2;
|
||||
constexpr uint8_t JOINED = 3;
|
||||
constexpr uint8_t LEFT = 4;
|
||||
constexpr uint8_t REMOVED = 5;
|
||||
constexpr uint8_t LEADER_IS = 6;
|
||||
constexpr uint8_t LEADER_CHANGED = 7;
|
||||
constexpr uint8_t DISBANDED = 8;
|
||||
constexpr uint8_t SIGNED_ON = 14;
|
||||
constexpr uint8_t SIGNED_OFF = 15;
|
||||
}
|
||||
|
||||
/** SMSG_GUILD_QUERY_RESPONSE data */
|
||||
struct GuildQueryResponseData {
|
||||
uint32_t guildId = 0;
|
||||
std::string guildName;
|
||||
std::string rankNames[10];
|
||||
uint32_t emblemStyle = 0;
|
||||
uint32_t emblemColor = 0;
|
||||
uint32_t borderStyle = 0;
|
||||
uint32_t borderColor = 0;
|
||||
uint32_t backgroundColor = 0;
|
||||
uint32_t rankCount = 0;
|
||||
|
||||
bool isValid() const { return guildId != 0 && !guildName.empty(); }
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_QUERY_RESPONSE parser */
|
||||
class GuildQueryResponseParser {
|
||||
public:
|
||||
static bool parse(network::Packet& packet, GuildQueryResponseData& data);
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_INFO data */
|
||||
struct GuildInfoData {
|
||||
std::string guildName;
|
||||
uint32_t creationDay = 0;
|
||||
uint32_t creationMonth = 0;
|
||||
uint32_t creationYear = 0;
|
||||
uint32_t numMembers = 0;
|
||||
uint32_t numAccounts = 0;
|
||||
|
||||
bool isValid() const { return !guildName.empty(); }
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_INFO parser */
|
||||
class GuildInfoParser {
|
||||
public:
|
||||
static bool parse(network::Packet& packet, GuildInfoData& data);
|
||||
};
|
||||
|
||||
/** Guild roster member entry */
|
||||
struct GuildRosterMember {
|
||||
uint64_t guid = 0;
|
||||
bool online = false;
|
||||
std::string name;
|
||||
uint32_t rankIndex = 0;
|
||||
uint8_t level = 0;
|
||||
uint8_t classId = 0;
|
||||
uint8_t gender = 0;
|
||||
uint32_t zoneId = 0;
|
||||
float lastOnline = 0.0f;
|
||||
std::string publicNote;
|
||||
std::string officerNote;
|
||||
};
|
||||
|
||||
/** Guild rank info */
|
||||
struct GuildRankInfo {
|
||||
uint32_t rights = 0;
|
||||
uint32_t goldLimit = 0;
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_ROSTER data */
|
||||
struct GuildRosterData {
|
||||
std::string motd;
|
||||
std::string guildInfo;
|
||||
std::vector<GuildRankInfo> ranks;
|
||||
std::vector<GuildRosterMember> members;
|
||||
|
||||
bool isEmpty() const { return members.empty(); }
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_ROSTER parser */
|
||||
class GuildRosterParser {
|
||||
public:
|
||||
static bool parse(network::Packet& packet, GuildRosterData& data);
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_EVENT data */
|
||||
struct GuildEventData {
|
||||
uint8_t eventType = 0;
|
||||
uint8_t numStrings = 0;
|
||||
std::string strings[3];
|
||||
uint64_t guid = 0;
|
||||
|
||||
bool isValid() const { return true; }
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_EVENT parser */
|
||||
class GuildEventParser {
|
||||
public:
|
||||
static bool parse(network::Packet& packet, GuildEventData& data);
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_INVITE data */
|
||||
struct GuildInviteResponseData {
|
||||
std::string inviterName;
|
||||
std::string guildName;
|
||||
|
||||
bool isValid() const { return !inviterName.empty(); }
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_INVITE parser */
|
||||
class GuildInviteResponseParser {
|
||||
public:
|
||||
static bool parse(network::Packet& packet, GuildInviteResponseData& data);
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_COMMAND_RESULT data */
|
||||
struct GuildCommandResultData {
|
||||
uint32_t command = 0;
|
||||
std::string name;
|
||||
uint32_t errorCode = 0;
|
||||
|
||||
bool isValid() const { return true; }
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_COMMAND_RESULT parser */
|
||||
class GuildCommandResultParser {
|
||||
public:
|
||||
static bool parse(network::Packet& packet, GuildCommandResultData& data);
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Ready Check
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ private:
|
|||
bool showEntityWindow = false;
|
||||
bool showChatWindow = true;
|
||||
bool showPlayerInfo = false;
|
||||
bool showGuildRoster_ = false;
|
||||
bool refocusChatInput = false;
|
||||
bool chatWindowLocked = true;
|
||||
ImVec2 chatWindowPos_ = ImVec2(0.0f, 0.0f);
|
||||
|
|
@ -166,6 +167,8 @@ private:
|
|||
void renderSettingsWindow();
|
||||
void renderQuestMarkers(game::GameHandler& gameHandler);
|
||||
void renderMinimapMarkers(game::GameHandler& gameHandler);
|
||||
void renderGuildRoster(game::GameHandler& gameHandler);
|
||||
void renderGuildInvitePopup(game::GameHandler& gameHandler);
|
||||
|
||||
/**
|
||||
* Inventory screen
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue