Files
benilla-octo/crates/benilla-protocol/src/messages/mod.rs
T
SamandClaude Fable 5.1 eebbcc050f NTFS load order, a title-sorted AddOns list, and tooltips at the cursor
- addons load in the order NTFS lists a folder, case-insensitive with an underscore before the letters, the order the vanilla corpus was written against and the one that decides which addon provides a shared library (2178)
- GetNumAddOns and the index form of every AddOn verb walk a title-sorted list that hides the Blizzard addons the server says to hide, and the character-select AddOns list is in title order (2175)
- SetPoint and SetAllPoints raise the reference's own errors for a frame name that does not exist or an omitted relative frame instead of quietly anchoring to the parent, and an explicit nil means the screen root (2176)
- a tooltip owned with ANCHOR_CURSOR follows the mouse, which pfUI's tooltip, xpbar and chat modules, pfQuest's browser and TipBuddy ask for; an omitted or unknown anchor is ANCHOR_LEFT (2176)
- a $parent name handed to CreateFrame, CreateTexture or CreateFontString expands as it does in XML, so FonzAppraiser's thirty dropdowns and pfQuest's search icon get the names they asked for (2176)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 21:03:49 +07:00

377 lines
19 KiB
Rust

//! The world (`mangosd`) message layer — in-repo replacement for `wow_world_messages` (decision
//! 0021), scoped to the opcodes benilla sends and receives.
//!
//! World packets are framed by a header-encrypted size+opcode (see [`crate::world`]); this module owns
//! only the *bodies*: parsing the server packets benilla decodes into [`ServerPacket`], and building
//! the client packet bodies benilla sends. The one genuinely complex packet is `SMSG_UPDATE_OBJECT`
//! (and its zlib twin) — an object list where each entry carries a [`MovementBlock`]-shaped position
//! and a sparse [`ObjectFields`] of descriptor fields; its decode lives in [`update_object`], and
//! [`crate::events`] pulls out the handful of fields the renderer uses.
//! The [`ServerPacket`] enum itself lives in `packet`; the opcode→variant dispatch
//! ([`parse_server`]) in `parse`.
//!
//! Proven byte-for-byte against `wow_world_messages` during the decision-0021 migration (oracle test
//! in git history); ongoing coverage is the oracle-free golden/fixture tests in `tests/*.rs` (split by
//! domain — client, movement, items, spells, update_object, simple_packets — sharing fixtures via
//! `tests/common`).
mod action_bar;
pub mod addons;
mod area_trigger;
mod attack;
mod auction;
mod bank;
mod battlefield;
mod binder;
mod broadcast;
mod channel;
mod chat;
mod client;
mod combat_log;
mod death;
mod duel;
mod gameobject;
mod gm_ticket;
mod gossip;
mod group;
mod guild;
mod instance;
mod items;
mod loot;
mod mail;
mod meeting_stone;
mod mirror_timer;
mod monster_move;
mod movement;
pub mod opcode;
mod opcode_names;
mod packet;
mod page_text;
mod parse;
mod pet;
mod petition;
mod pose;
mod progression;
mod pvp;
mod quest;
mod reputation;
mod roster;
mod skills;
mod social;
mod spellbook;
mod spells;
mod stable;
mod summon;
mod tabard;
mod taxi;
mod trade;
mod trainer;
mod tutorial;
mod update_object;
mod vendor;
mod world_state;
pub use action_bar::{
set_action_button, set_actionbar_toggles, ActionButton, ACTION_KIND_ITEM, ACTION_KIND_MACRO,
ACTION_KIND_SPELL,
};
pub use addons::{hidden_from_reply, SecureAddon, STANDARD_MODULUS_CRC, STOCK_SECURE_ADDONS};
pub use area_trigger::area_trigger;
pub use attack::{attack_swing, AttackSwingError, AttackerState};
pub use auction::{
auction_action, auction_duration, auction_error, auction_filter, auction_hello,
auction_list_bidder_items, auction_list_items, auction_list_owner_items, auction_place_bid,
auction_remove_item, auction_sell_item, AuctionBidderNotification, AuctionCommandTail,
AuctionListEntry, AuctionOwnerNotification, AUCTION_PAGE_SIZE, AUCTION_RECORD_BYTES,
};
pub use bank::{
autobank_item, autostore_bank_item, bank_slot_result, banker_activate, buy_bank_slot,
};
pub use battlefield::{
battlefield_join, battlefield_list, battlefield_port, battlemaster_join, leave_battlefield,
BattlefieldList, BattlefieldPosition, BattlefieldPositions, BattlefieldStatus, PvpLogData,
PvpLogRow, BATTLEFIELD_POSITIONS_MAX,
};
pub use binder::{binder_activate, PlayerBound};
pub use channel::{channel_notice, ChannelNoticeTail, ChannelNotify};
pub use chat::{
chat_tag, ChatMessage, CHAT_MSG_AFK, CHAT_MSG_BATTLEGROUND, CHAT_MSG_BATTLEGROUND_LEADER,
CHAT_MSG_BG_SYSTEM_ALLIANCE, CHAT_MSG_BG_SYSTEM_HORDE, CHAT_MSG_BG_SYSTEM_NEUTRAL,
CHAT_MSG_CHANNEL, CHAT_MSG_DND, CHAT_MSG_EMOTE, CHAT_MSG_FILTERED, CHAT_MSG_GUILD,
CHAT_MSG_IGNORED, CHAT_MSG_MONSTER_EMOTE, CHAT_MSG_MONSTER_SAY, CHAT_MSG_MONSTER_WHISPER,
CHAT_MSG_MONSTER_YELL, CHAT_MSG_OFFICER, CHAT_MSG_PARTY, CHAT_MSG_RAID,
CHAT_MSG_RAID_BOSS_EMOTE, CHAT_MSG_RAID_BOSS_WHISPER, CHAT_MSG_RAID_LEADER,
CHAT_MSG_RAID_WARNING, CHAT_MSG_SAY, CHAT_MSG_SYSTEM, CHAT_MSG_WHISPER,
CHAT_MSG_WHISPER_INFORM, CHAT_MSG_YELL, MACRO_EXPANDED_TYPES,
};
pub use client::{
auth_session, channel_announcements, channel_ban, channel_invite, channel_kick, channel_list,
channel_moderate, channel_moderator, channel_mute, channel_owner, channel_password,
channel_set_owner, channel_unban, channel_unmoderator, channel_unmute, char_create,
creature_query, force_speed_ack, full_guid, join_channel, knock_back_ack, leave_channel,
messagechat, messagechat_channel, messagechat_kind, messagechat_whisper, move_flag_ack,
move_spline_done, move_time_skipped, movement, pet_name_query, ping, played_time, query_time,
random_roll, teleport_ack, text_emote,
};
pub use combat_log::{
DamageShield, DispelFailed, EnchantmentLog, EnvironmentalDamageLog, ExecuteLog, PartyKillLog,
PeriodicAuraLog, PeriodicTick, SpellDamageLog, SpellDispelLog, SpellEnergizeLog, SpellHealLog,
SpellInstaKillLog, SpellLogExecute, SpellLogMiss, SpellOutcomeLog,
};
pub use death::{
area_spirit_healer, reclaim_corpse, resurrect_response, spirit_healer_activate,
AreaSpiritHealerTime, CorpseLocation, ResurrectRequestBody,
};
pub use duel::{
duel_accepted, duel_cancelled, read_duel_complete, read_duel_countdown, read_duel_requested,
read_duel_winner, DuelRequested, DuelWinner,
};
pub use gameobject::{gameobj_use, gameobject_query, GameObjectQueryInfo};
pub use gm_ticket::{
gm_ticket_create, gm_ticket_updatetext, GmTicket, GMTICKET_QUEUE_ENABLED,
GMTICKET_STATUS_DEFAULT, GMTICKET_STATUS_HASTEXT, RESERVED_FOR_FUTURE_USE,
};
pub use gossip::{
gossip_hello, gossip_select_option, npc_text_query, select_greeting, GossipOption, GossipPoi,
NpcTextBlock, QuestOption, NPC_TEXT_BLOCKS,
};
pub use group::{
group_accept, group_assistant_leader, group_change_sub_group, group_decline, group_disband,
group_invite, group_raid_convert, group_set_leader, group_swap_sub_group, group_uninvite,
group_uninvite_guid, loot_method, member_status, minimap_ping, party_member_mask,
party_operation, party_result, raid_target_request, raid_target_set, ready_check_answer,
ready_check_start, request_party_member_stats, request_raid_info, GroupLootInfo,
GroupMemberEntry, PartyMemberStatsInfo, RaidInstanceEntry, RaidTargetUpdate, ReadyCheck,
GROUP_MEMBER_ASSISTANT,
};
pub use guild::{
guild_accept, guild_add_rank, guild_command, guild_command_error, guild_create, guild_decline,
guild_default_rank, guild_del_rank, guild_demote, guild_disband, guild_event, guild_info,
guild_info_text, guild_invite, guild_leader, guild_leave, guild_motd, guild_presence,
guild_promote, guild_query, guild_rank, guild_rank_right, guild_remove, guild_roster,
guild_set_officer_note, guild_set_public_note, GuildCommandResult, GuildEventNotice, GuildInfo,
GuildQueryResponse, GuildRoster, GuildRosterMember, GUILD_INFO_MAX_LENGTH,
GUILD_MOTD_MAX_LENGTH, GUILD_NAME_MAX_LENGTH, GUILD_NOTE_MAX_LENGTH, GUILD_RANKS_MAX_COUNT,
GUILD_RANKS_MIN_COUNT, GUILD_RANK_MAX_LENGTH, GUILD_RANK_RIGHT_ORDER,
};
pub use instance::{
reset_instances, InstanceResetFailed, InstanceResetFailure, RaidGroupOnly, RaidInstanceMessage,
RaidInstanceWarning,
};
pub use items::{
auto_equip_item, auto_store_bag_item, destroy_item, item_query, open_item, set_ammo,
split_item, swap_inv_item, swap_item, use_item, wrap_item, ItemDamage, ItemInfo,
ItemSpellEntry, ItemUseSpell, UseItemTarget, BAG_PLAYER_INVENTORY, ITEM_DYNFLAG_UNLOCKED,
ITEM_DYNFLAG_WRAPPED, ITEM_FLAG_LOOTABLE, ITEM_FLAG_WRAPPER, SLOT_BAG_FIRST, SLOT_PACK_FIRST,
};
pub use loot::{
autostore_loot_item, loot, loot_error, loot_master_give, loot_money, loot_release, loot_roll,
loot_type, roll_vote, slot_type, ItemPushResult, LootAllPassed, LootItem, LootResponseBody,
LootRoll, LootRollWon, LootStartRoll,
};
pub use mail::{
get_mail_list, item_text_query, mail_action, mail_create_text_item, mail_delete, mail_error,
mail_mark_as_read, mail_message_type, mail_return_to_sender, mail_take_item, mail_take_money,
send_mail, MailAttachment, MailListEntry,
};
pub use meeting_stone::{meeting_stone_leave, MeetingStoneNotice, MeetingStoneSetQueue};
pub use mirror_timer::{
read_pause_mirror_timer, read_start_mirror_timer, read_stop_mirror_timer, MirrorTimerKind,
MirrorTimerStart,
};
pub use movement::{
JumpInfo, MoveMode, MovementInfo, RelayVerb, SpeedKind, SplineMode, TransportPose,
};
pub use opcode_names::opcode_name;
pub use packet::{CreatureQueryInfo, MonsterMoveFacing, ServerPacket};
pub use page_text::page_text_query;
pub use parse::parse_server;
pub use pet::{
pet_abandon, pet_action, pet_cancel_aura, pet_rename, pet_set_action, pet_spell_autocast,
pet_stop_attack, pet_tame_failure_key, pet_unlearn, PetActionEntry, PetMode, PetSpellCooldown,
PetSpells, PetUnlearnConfirm, PET_ACTION_SLOTS, PET_ACT_COMMAND, PET_ACT_DISABLED,
PET_ACT_ENABLED, PET_ACT_PASSIVE, PET_ACT_REACTION, PET_AUTOCAST_ALLOWED, PET_AUTOCAST_ON,
PET_COMMAND_ATTACK, PET_COMMAND_DISMISS, PET_COMMAND_FOLLOW, PET_COMMAND_STAY,
PET_COOLDOWN_PERMANENT, PET_REACT_AGGRESSIVE, PET_REACT_DEFENSIVE, PET_REACT_PASSIVE,
PET_STATE_BAR_DISABLED, PET_TALK_ATTACK, PET_TALK_ORDER, PET_TYPE_SPELL_FIRST,
PET_TYPE_SPELL_LAST, PET_UNUSABLE_UNIT_FLAGS,
};
pub use petition::{
offer_petition, petition_buy, petition_decline, petition_query, petition_rename,
petition_result, petition_show_list, petition_show_signatures, petition_sign, turn_in_petition,
PetitionQueryResponse, PetitionRename, PetitionShowList, PetitionShowListEntry,
PetitionShowSignatures, PetitionSignResults, PetitionSignature, CHARTER_DISPLAY_ID,
CHARTER_ITEM_ENTRY, CHARTER_NAME_MAX_LENGTH, ITEM_FLAG_CHARTER, MAX_PETITION_SIGNATURES,
};
pub use pose::{set_sheathed, stand_state_change};
pub use progression::{
learn_talent, talent_wipe_confirm, ExplorationXp, LevelUpInfo, TalentWipeConfirm, XpGain,
};
pub use pvp::{inspect_honor_stats, InspectHonorStats, PvpCredit};
pub use quest::{
dialog_status, push_quest_to_party, quest_confirm_accept, quest_flags, quest_push_result,
quest_query, questgiver_accept_quest, questgiver_choose_reward, questgiver_complete_quest,
questgiver_hello, questgiver_query_quest, questgiver_request_reward, questgiver_status_query,
questlog_remove_quest, questlog_swap_quest, QuestComplete, QuestConfirmAccept, QuestDetails,
QuestGiverList, QuestListEntry, QuestObjective, QuestOfferReward, QuestPushResult,
QuestRequestItems, QuestRequiredItem, QuestRewardItem, QuestShareMsg, QuestTemplate,
QUEST_EMOTE_COUNT, QUEST_OBJECTIVES_COUNT, QUEST_REWARDS_COUNT, QUEST_REWARD_CHOICES_COUNT,
};
pub use reputation::{
set_faction_at_war, set_faction_inactive, set_watched_faction, WATCHED_FACTION_NONE,
};
pub use roster::{
CharCreateReq, CharEnumItem, Character, CHARACTER_FLAG_GHOST, CHARACTER_FLAG_HIDE_CLOAK,
CHARACTER_FLAG_HIDE_HELM, CHARACTER_FLAG_RENAME, CHAR_CREATE_NAME_IN_USE,
CHAR_CREATE_SERVER_LIMIT, CHAR_CREATE_SUCCESS, CHAR_DELETE_SUCCESS, CLASS_WARRIOR, GENDER_MALE,
RACE_HUMAN,
};
pub use skills::unlearn_skill;
pub use social::{
add_friend, add_ignore, del_friend, del_ignore, friend_list, friend_result, friend_status,
read_friend_list, read_friend_status, read_ignore_list, read_who, set_looking_for_group, who,
FriendEntry, FriendOnline, FriendStatusUpdate, WhoEntry, WhoRequest, WhoResults,
WHO_MAX_SEARCH_TERMS, WHO_MAX_ZONES,
};
pub use spellbook::SpellCooldown;
pub use spells::{
cancel_aura, cast_spell, cast_spell_at_dest, cast_spell_gameobject, cast_spell_item,
CastOutcome, SpellCastTargets, SpellChainTargets, SpellGo, SpellStart,
};
pub use stable::{
buy_stable_slot, list_stabled_pets, stable_pet, stable_result, stable_swap_pet, unstable_pet,
StabledPet,
};
pub use summon::{summon_response, SummonRequest};
pub use tabard::{
battlemaster_hello, save_guild_emblem, tabard_vendor_activate, GUILD_EMBLEM_RESULT_MESSAGES,
};
pub use taxi::{
activate_taxi, activate_taxi_express, taxi_node_status_query, taxi_query_available_nodes,
taxi_reply, TaxiMask,
};
pub use trade::{
accept_trade, clear_trade_item, initiate_trade, set_trade_gold, set_trade_item, TradeItem,
TradeStatus, TradeStatusExtended, TRADE_SLOT_COUNT, TRADE_SLOT_NONTRADED,
TRADE_SLOT_TRADED_COUNT,
};
pub use trainer::{train_fail, trainer_buy_spell, trainer_list, trainer_spell_state, TrainerSpell};
pub use tutorial::{tutorial_flag, TutorialFlags};
pub use update_object::{
power_display_scale, quest_slot_state, CorpseLook, CreateSpline, MovementBlock, MoverState,
Object, ObjectFields, ObjectType, OwnerFallback, PlayerSkillSlot, QuestLogSlot, UnitAuraSlot,
AURA_FLAG_CANCELABLE, AURA_FLAG_EFF_INDEX_MASK, FIELD_PLAYER_SKILL_INFO_1_1,
PLAYER_EXPLORED_ZONES_SLOTS, PLAYER_QUEST_LOG_SLOTS, PLAYER_SKILL_SLOTS,
UNIT_AURA_POSITIVE_SLOTS, UNIT_AURA_SLOTS,
};
pub use vendor::{
buy_item, buy_item_in_slot, buy_result, buyback_item, list_inventory, repair_item, sell_item,
sell_result, VendorItem,
};
pub use world_state::InitWorldStates;
/// The **world server's** `SMSG_AUTH_RESPONSE` result codes — a **different enum** from the
/// realmd logon-proof's `AuthLogonResult` (`crate::AuthReject`, 0x00..=0x12), which is the trap
/// this block exists to close: both are "the auth result byte", they overlap numerically, and they
/// mean unrelated things. 0x0C is `AUTH_OK` here and `AUTH_LOGON_FAILED_SUSPENDED` there.
///
/// VERIFIED two ways. The client's own dispatch over exactly this enum is decompiled in wow-re
/// `system/net/scratch/w2b-pack.c` — case 0x0c → `AUTH_OK`, 0x0d → `AUTH_FAILED`, 0x0e →
/// `AUTH_REJECT`, … 0x15 → `AUTH_UNKNOWN_ACCOUNT`, 0x16 → `AUTH_INCORRECT_PASSWORD`, 0x1b →
/// `AUTH_WAIT_QUEUE`, 0x22..=0x26 → the `REALM_LIST_*` strings — and the same numbering is
/// `AuthResponseCodes` in cmangos `src/game/Globals/SharedDefines.h:1721+`. Each constant's name
/// is the `GlueStrings` key the client shows for it, which is what makes the mapping in
/// `crate::login`'s `world_refusal_text` a transcription rather than a judgement call.
pub const AUTH_OK: u8 = 0x0C;
pub const AUTH_FAILED: u8 = 0x0D;
pub const AUTH_REJECT: u8 = 0x0E;
pub const AUTH_BAD_SERVER_PROOF: u8 = 0x0F;
pub const AUTH_UNAVAILABLE: u8 = 0x10;
pub const AUTH_SYSTEM_ERROR: u8 = 0x11;
pub const AUTH_BILLING_ERROR: u8 = 0x12;
pub const AUTH_BILLING_EXPIRED: u8 = 0x13;
pub const AUTH_VERSION_MISMATCH: u8 = 0x14;
pub const AUTH_UNKNOWN_ACCOUNT: u8 = 0x15;
pub const AUTH_INCORRECT_PASSWORD: u8 = 0x16;
pub const AUTH_SESSION_EXPIRED: u8 = 0x17;
pub const AUTH_SERVER_SHUTTING_DOWN: u8 = 0x18;
pub const AUTH_ALREADY_LOGGING_IN: u8 = 0x19;
pub const AUTH_LOGIN_SERVER_NOT_FOUND: u8 = 0x1A;
/// The realm is full and we are **queued**, not refused — the one code here that is not an ending.
pub const AUTH_WAIT_QUEUE: u8 = 0x1B;
// The tail past the queue. These five are exactly the codes the client's `OKAY_WITH_URL` table
// (`0x803740`, 5 records, stride 0x24) keys on — banned/no-time/db-busy/suspended/parental — which
// is why the URL dialog is reachable ONLY from this enum and never from realmd.
pub const AUTH_BANNED: u8 = 0x1C;
pub const AUTH_ALREADY_ONLINE: u8 = 0x1D;
pub const AUTH_NO_TIME: u8 = 0x1E;
pub const AUTH_DB_BUSY: u8 = 0x1F;
pub const AUTH_SUSPENDED: u8 = 0x20;
pub const AUTH_PARENTAL_CONTROL: u8 = 0x21;
/// `LogoutResult::Success` (`SMSG_LOGOUT_RESPONSE`).
pub const LOGOUT_SUCCESS: u32 = 0x0;
/// Chat `Language` wire ids (VERIFIED vmangos `SharedDefines.h:256-261`): the faction tongues.
/// `Universal` (0) is server-reserved — vmangos rejects it from clients for ordinary chat.
pub const LANGUAGE_COMMON: u32 = 0x7;
pub const LANGUAGE_ORCISH: u32 = 0x1;
/// `LANG_ADDON` (VERIFIED vmangos `SharedDefines.h:270`) — **not a tongue**. 1.12.1 has no addon
/// opcode: `SendAddonMessage` rides the ordinary chat lanes and this sentinel in the `language`
/// field is the *only* thing that marks the line as addon-to-addon data rather than speech
/// (decision 1029). The real client routes it to the `CHAT_MSG_ADDON` event; it never reaches the
/// chat frame.
///
/// The server treats it as its own class throughout: exempt from the `KnowsLanguage` gate, from
/// flood control, and from message sanitizing (`SanitizeChatMessage` returns early,
/// `Handlers/ChatHandler.cpp:49`); gated instead by the `AddonChannel` config
/// (`ChatHandler.cpp:165`); and restricted by `WorldSession::IsLanguageAllowedForChatType`
/// (`ChatHandler.cpp:84`) to the group/guild/channel lanes — PARTY, RAID, RAID_LEADER,
/// RAID_WARNING, GUILD, OFFICER, BATTLEGROUND, BATTLEGROUND_LEADER, CHANNEL. Never
/// SAY/YELL/EMOTE/WHISPER, which is why addon traffic can never reach a chat bubble or a
/// `/r` target. It is also the one language the server never rewrites: the whole
/// GM/two-side/`SPELL_AURA_MOD_LANGUAGE` normalisation block lives in that check's `else`
/// (`ChatHandler.cpp:176-218`), so on the party lane a line's language is either a tongue (often
/// normalised to `Universal`) or exactly this.
///
/// **The client's own send set is narrower than the server's permission list.** VERIFIED in
/// `WoW.exe` (5875) — wow-re `system/ui/scratch/addon-chat-law.md`: `SendAddonMessage`
/// (`0x49f920`) hard-whitelists **four** types at `0x49fa3f`-`0x49fa4e` — PARTY, RAID, GUILD,
/// BATTLEGROUND — and the receive side's `distribution` argument uses the same four (remap table
/// `0x49aff4`), reporting every other type as the literal `"UNKNOWN"`. So a real client accepts
/// addon traffic on lanes it will never itself send on.
pub const LANGUAGE_ADDON: u32 = 0xFFFF_FFFF;
/// The language a character speaks by default — its faction tongue. Every send must carry a
/// language the character *knows*: vmangos drops the whole message (including a `.command`
/// payload, which is intercepted downstream of the check) with a "not learned" notification
/// otherwise (`HandleChatMessageOpcode`'s `KnowsLanguage` gate, `Handlers/ChatHandler.cpp`).
/// Race → tongue VERIFIED against the live world DB (`playercreateinfo_spell`): races 1/3/4/7
/// (Alliance) learn spell 668 Language Common, races 2/5/6/8 (Horde) learn 669 Language Orcish.
pub fn faction_language(race: u8) -> u32 {
match race {
2 | 5 | 6 | 8 => LANGUAGE_ORCISH, // orc, undead, tauren, troll
_ => LANGUAGE_COMMON, // human, dwarf, night elf, gnome
}
}
/// `ChatMsg` wire values benilla sends, widened to `u32` (VERIFIED vmangos `SharedDefines.h:
/// 1191-1301`) — `CMSG_MESSAGECHAT`'s `type` field is a `u32` on the wire
/// (`WorldPackets::Chat::ChatMessage::type`, `Server/Packets/Chat.h:12`), unlike the inbound
/// `SMSG_MESSAGECHAT` decode's `u8` (hence the separate, narrower [`CHAT_MSG_SAY`] etc. set there):
/// two constant sets for the same enum because the two wire fields are different widths.
pub const CHAT_TYPE_SAY: u32 = 0x0;
pub const CHAT_TYPE_PARTY: u32 = 0x1;
pub const CHAT_TYPE_RAID: u32 = 0x2;
pub const CHAT_TYPE_GUILD: u32 = 0x3;
pub const CHAT_TYPE_OFFICER: u32 = 0x4;
pub const CHAT_TYPE_YELL: u32 = 0x5;
pub const CHAT_TYPE_WHISPER: u32 = 0x6;
pub const CHAT_TYPE_EMOTE: u32 = 0x8;
pub const CHAT_TYPE_CHANNEL: u32 = 0xE;
pub const CHAT_TYPE_AFK: u32 = 0x14;
pub const CHAT_TYPE_DND: u32 = 0x15;
/// `#if SUPPORTED_CLIENT_BUILD > CLIENT_BUILD_1_10_2` — active for 5875.
pub const CHAT_TYPE_RAID_LEADER: u32 = 0x57;
pub const CHAT_TYPE_RAID_WARNING: u32 = 0x58;
/// `#if SUPPORTED_CLIENT_BUILD > CLIENT_BUILD_1_11_2` — active for 5875.
pub const CHAT_TYPE_BATTLEGROUND: u32 = 0x5C;
pub const CHAT_TYPE_BATTLEGROUND_LEADER: u32 = 0x5D;