/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef TRINITYCORE_CHARACTER_PACKETS_H #define TRINITYCORE_CHARACTER_PACKETS_H #include "Packet.h" #include "ObjectGuid.h" #include "Optional.h" #include "PacketUtilities.h" #include "Position.h" #include "RaceMask.h" #include "SharedDefines.h" #include "UnitDefines.h" #include "UpdateFields.h" #include #include class Field; namespace UF { struct ChrCustomizationChoice; ByteBuffer& operator<<(ByteBuffer& data, ChrCustomizationChoice const& customizationChoice); ByteBuffer& operator>>(ByteBuffer& data, ChrCustomizationChoice& customizationChoice); } namespace WorldPackets { namespace Character { using ChrCustomizationChoice = UF::ChrCustomizationChoice; class EnumCharacters final : public ClientPacket { public: explicit EnumCharacters(WorldPacket&& packet); void Read() override { } }; struct CharacterCreateInfo { /// User specified variables uint8 Race = RACE_NONE; uint8 Class = CLASS_NONE; uint8 Sex = GENDER_NONE; Array Customizations; Optional TemplateSet; int32 TimerunningSeasonID = 0; bool IsTrialBoost = false; bool UseNPE = false; bool HardcoreSelfFound = false; std::string Name; /// Server side data uint8 CharCount = 0; }; struct CharacterRenameInfo { std::string NewName; ObjectGuid Guid; }; struct CharCustomizeInfo { ObjectGuid CharGUID; uint8 SexID = GENDER_NONE; std::string CharName; Array Customizations; }; struct CharRaceOrFactionChangeInfo { uint8 RaceID = RACE_NONE; uint8 InitialRaceID = RACE_NONE; uint8 SexID = GENDER_NONE; ObjectGuid Guid; bool FactionChange = false; std::string Name; Array Customizations; }; struct CharacterUndeleteInfo { /// User specified variables ObjectGuid CharacterGuid; ///< Guid of the character to restore int32 ClientToken = 0; ///< @todo: research /// Server side data std::string Name; }; struct CustomTabardInfo { int32 EmblemStyle = -1; int32 EmblemColor = -1; int32 BorderStyle = -1; int32 BorderColor = -1; int32 BackgroundColor = -1; }; struct WarbandGroupMember { uint32 WarbandScenePlacementID = 0; int32 Type = 0; int32 ContentSetID = 0; ObjectGuid Guid; }; struct WarbandGroup { uint64 GroupID = 0; uint8 OrderIndex = 0; uint32 WarbandSceneID = 0; uint32 Flags = 0; ///< enum WarbandGroupFlags { Collapsed = 1 } int32 ContentSetID = 0; std::vector Members; std::string_view Name; }; class EnumCharactersResult final : public ServerPacket { public: struct CharacterInfoBasic { /** * @fn void WorldPackets::Character::EnumCharactersResult::CharacterInfo::CharacterInfo(Field* fields); * * @brief Initialize the struct with values from QueryResult * * @param fields Field set of CharacterDatabaseStatements::CHAR_SEL_ENUM */ CharacterInfoBasic(Field const* fields); ObjectGuid Guid; uint32 VirtualRealmAddress = 0; uint64 GuildClubMemberID = 0; ///< same as bgs.protocol.club.v1.MemberId.unique_id, guessed basing on SMSG_QUERY_PLAYER_NAME_RESPONSE (that one is known) std::string Name; uint16 ListPosition = 0; ///< Order of the characters in list uint8 RaceID = 0; uint8 ClassID = 0; uint8 SexID = 0; std::vector Customizations; uint8 ExperienceLevel = 0; int32 ZoneID = 0; int32 MapID = 0; TaggedPosition PreloadPos; ObjectGuid GuildGUID; uint32 Flags = 0; ///< Character flag @see enum CharacterFlags uint32 Flags2 = 0; ///< Character customization flags @see enum CharacterCustomizeFlags uint32 Flags3 = 0; ///< Character flags 3 @todo research uint32 Flags4 = 0; ///< Character flags 4 @todo research bool FirstLogin = false; uint8 CantLoginReason = 0; Timestamp<> CreateTime; Timestamp<> LastActiveTime; uint16 SpecID = 0; uint32 SaveVersion = 0; uint32 LastLoginVersion = 0; uint32 OverrideSelectScreenFileDataID = 0; int32 TimerunningSeasonID = 0; uint32 PetCreatureDisplayID = 0; uint32 PetExperienceLevel = 0; uint32 PetCreatureFamilyID = 0; int32 ProfessionIds[2] = { }; ///< @todo struct VisualItemInfo { uint32 DisplayID = 0; uint32 DisplayEnchantID = 0; int32 SecondaryItemModifiedAppearanceID = 0; // also -1 is some special value uint8 InvType = 0; uint8 Subclass = 0; uint32 ItemID = 0; uint32 TransmogrifiedItemID = 0; }; std::array VisualItems = { }; CustomTabardInfo PersonalTabard; uint32 Unused1110_1 = 0; bool Unused1110_2 = false; bool Unused1110_3 = false; }; struct CharacterRestrictionAndMailData { bool BoostInProgress = false; ///< @todo uint32 RestrictionFlags = 0; std::vector MailSenders; std::vector MailSenderTypes; bool RpeAvailable = false; }; struct CharacterInfo { CharacterInfo(Field const* fields); CharacterInfoBasic Basic; CharacterRestrictionAndMailData RestrictionsAndMails; }; struct RegionwideCharacterListEntry { RegionwideCharacterListEntry(Field const* fields); CharacterInfoBasic Basic; uint64 Money = 0; float AvgEquippedItemLevel = 0.0f; float CurrentSeasonMythicPlusOverallScore = 0.0f; uint32 CurrentSeasonBestPvpRating = 0; int8 PvpRatingBracket = 0; int16 PvpRatingAssociatedSpecID = 0; }; struct RaceUnlock { int8 RaceID = 0; bool HasUnlockedLicense = false; bool HasUnlockedAchievement = false; bool HasHeritageArmorUnlockAchievement = false; bool HideRaceOnClient = false; bool Unused1027 = false; }; struct UnlockedConditionalAppearance { int32 AchievementID = 0; int32 ConditionalType = 0; }; struct RaceLimitDisableInfo { enum { Server, Level }; int8 RaceID = 0; int8 Reason = 0; }; explicit EnumCharactersResult() : ServerPacket(SMSG_ENUM_CHARACTERS_RESULT) { } WorldPacket const* Write() override; bool Success = false; bool Realmless = false; bool IsDeletedCharacters = false; ///< used for character undelete list bool IgnoreNewPlayerRestrictions = false; ///< allows client to skip new player restrictions bool IsRestrictedNewPlayer = false; ///< forbids using level boost and class trials bool IsNewcomerChatCompleted = false; ///< forbids hero classes and allied races bool IsRestrictedTrial = false; bool Unused1127 = false; bool DontCreateCharacterDisplays = false; int32 MaxCharacterLevel = 1; Optional ClassDisableMask; std::vector Characters; ///< all characters on the list std::vector RegionwideCharacters; std::vector RaceUnlockData; std::vector UnlockedConditionalAppearances; std::vector RaceLimitDisables; std::vector WarbandGroups; }; class CheckCharacterNameAvailability final : public ClientPacket { public: explicit CheckCharacterNameAvailability(WorldPacket&& packet) : ClientPacket(CMSG_CHECK_CHARACTER_NAME_AVAILABILITY, std::move(packet)) { } void Read() override; uint32 SequenceIndex = 0; std::string Name; }; class CheckCharacterNameAvailabilityResult final : public ServerPacket { public: explicit CheckCharacterNameAvailabilityResult(uint32 sequenceIndex, uint32 result) : ServerPacket(SMSG_CHECK_CHARACTER_NAME_AVAILABILITY_RESULT, 4 + 4), SequenceIndex(sequenceIndex), Result(result) { } WorldPacket const* Write() override; uint32 SequenceIndex; uint32 Result; }; class CreateCharacter final : public ClientPacket { public: explicit CreateCharacter(WorldPacket&& packet) : ClientPacket(CMSG_CREATE_CHARACTER, std::move(packet)) { } void Read() override; /** * @var uint8 Race * @var uint8 Class * @var uint8 Sex * @var uint8 Skin * @var uint8 Face * @var uint8 HairStyle * @var uint8 HairColor * @var uint8 FacialHairStyle * @var uint8 OutfitId * @var Optional TemplateSet * @var std::string Name */ std::shared_ptr CreateInfo; }; class CreateChar final : public ServerPacket { public: explicit CreateChar() : ServerPacket(SMSG_CREATE_CHAR, 1) { } WorldPacket const* Write() override; uint32 Code = 0; ///< Result code @see enum ResponseCodes ObjectGuid Guid; }; class CharDelete final : public ClientPacket { public: explicit CharDelete(WorldPacket&& packet): ClientPacket(CMSG_CHAR_DELETE, std::move(packet)) { } void Read() override; ObjectGuid Guid; ///< Guid of the character to delete }; class DeleteChar final : public ServerPacket { public: explicit DeleteChar(): ServerPacket(SMSG_DELETE_CHAR, 1) { } WorldPacket const* Write() override; uint32 Code = 0; ///< Result code @see enum ResponseCodes }; class CharacterRenameRequest final : public ClientPacket { public: explicit CharacterRenameRequest(WorldPacket&& packet) : ClientPacket(CMSG_CHARACTER_RENAME_REQUEST, std::move(packet)) { } void Read() override; /** * @var std::string NewName * @var ObjectGuid Guid */ std::shared_ptr RenameInfo; }; class CharacterRenameResult final : public ServerPacket { public: explicit CharacterRenameResult() : ServerPacket(SMSG_CHARACTER_RENAME_RESULT, 20) { } WorldPacket const* Write() override; std::string Name; uint32 Result = 0; Optional Guid; }; class CharCustomize final : public ClientPacket { public: explicit CharCustomize(WorldPacket&& packet) : ClientPacket(CMSG_CHAR_CUSTOMIZE, std::move(packet)) { } void Read() override; /** * @var uint8 HairStyleID * @var uint8 FaceID * @var ObjectGuid CharGUID * @var uint8 SexID * @var std::string CharName * @var uint8 HairColorID * @var uint8 FacialHairStyleID * @var uint8 SkinID */ std::shared_ptr CustomizeInfo; }; /// @todo: CharCustomizeResult class CharRaceOrFactionChange final : public ClientPacket { public: explicit CharRaceOrFactionChange(WorldPacket&& packet) : ClientPacket(CMSG_CHAR_RACE_OR_FACTION_CHANGE, std::move(packet)) { } void Read() override; /** * @var Optional HairColorID * @var uint8 RaceID * @var uint8 SexID * @var Optional SkinID * @var Optional FacialHairStyleID * @var ObjectGuid Guid * @var bool FactionChange * @var std::string Name * @var Optional FaceID * @var Optional HairStyleID */ std::shared_ptr RaceOrFactionChangeInfo; }; struct CharFactionChangeDisplayInfo { std::string Name; uint8 SexID = 0; uint8 RaceID = RACE_NONE; Array const* Customizations = nullptr; }; class CharFactionChangeResult final : public ServerPacket { public: explicit CharFactionChangeResult() : ServerPacket(SMSG_CHAR_FACTION_CHANGE_RESULT, 20 + sizeof(CharFactionChangeDisplayInfo)) { } WorldPacket const* Write() override; uint32 Result = 0; ///< @see enum ResponseCodes ObjectGuid Guid; Optional Display; }; class GenerateRandomCharacterName final : public ClientPacket { public: explicit GenerateRandomCharacterName(WorldPacket&& packet) : ClientPacket(CMSG_GENERATE_RANDOM_CHARACTER_NAME, std::move(packet)) { } void Read() override; uint8 Sex = 0; uint8 Race = 0; }; class GenerateRandomCharacterNameResult final : public ServerPacket { public: explicit GenerateRandomCharacterNameResult() : ServerPacket(SMSG_GENERATE_RANDOM_CHARACTER_NAME_RESULT, 20) { } WorldPacket const* Write() override; std::string Name; bool Success = false; }; class ReorderCharacters final : public ClientPacket { public: struct ReorderInfo { ObjectGuid PlayerGUID; uint8 NewPosition = 0; }; explicit ReorderCharacters(WorldPacket&& packet); void Read() override; Array Entries; }; class UndeleteCharacter final : public ClientPacket { public: explicit UndeleteCharacter(WorldPacket&& packet) : ClientPacket(CMSG_UNDELETE_CHARACTER, std::move(packet)) { } void Read() override; /** * @var ObjectGuid CharacterGuid * @var int32 ClientToken */ std::shared_ptr UndeleteInfo; }; class UndeleteCharacterResponse final : public ServerPacket { public: explicit UndeleteCharacterResponse() : ServerPacket(SMSG_UNDELETE_CHARACTER_RESPONSE, 26) { } WorldPacket const* Write() override; /** * @var ObjectGuid CharacterGuid * @var int32 ClientToken */ CharacterUndeleteInfo const* UndeleteInfo = nullptr; uint32 Result = 0; ///< @see enum CharacterUndeleteResult }; class GetUndeleteCharacterCooldownStatus final : public ClientPacket { public: explicit GetUndeleteCharacterCooldownStatus(WorldPacket&& packet) : ClientPacket(CMSG_GET_UNDELETE_CHARACTER_COOLDOWN_STATUS, std::move(packet)) { } void Read() override { } }; class UndeleteCooldownStatusResponse final : public ServerPacket { public: explicit UndeleteCooldownStatusResponse() : ServerPacket(SMSG_UNDELETE_COOLDOWN_STATUS_RESPONSE, 9) { } WorldPacket const* Write() override; uint32 MaxCooldown = 0; ///< Max. cooldown until next free character restoration. Displayed in undelete confirm message. (in sec) uint32 CurrentCooldown = 0; ///< Current cooldown until next free character restoration. (in sec) bool OnCooldown = false; ///< }; class PlayerLogin final : public ClientPacket { public: explicit PlayerLogin(WorldPacket&& packet) : ClientPacket(CMSG_PLAYER_LOGIN, std::move(packet)) { } void Read() override; ObjectGuid Guid; ///< Guid of the player that is logging in float FarClip = 0.0f; ///< Visibility distance (for terrain) bool RPE = false; }; class LoginVerifyWorld final : public ServerPacket { public: explicit LoginVerifyWorld() : ServerPacket(SMSG_LOGIN_VERIFY_WORLD, 4 + 4 * 4 + 4) { } WorldPacket const* Write() override; int32 MapID = -1; TaggedPosition Pos; uint32 Reason = 0; }; enum class LoginFailureReason : uint8 { Failed = 0, NoWorld = 1, DuplicateCharacter = 2, NoInstances = 3, Disabled = 4, NoCharacter = 5, LockedForTransfer = 6, LockedByBilling = 7, LockedByMobileAH = 8, TemporaryGMLock = 9, LockedByCharacterUpgrade = 10, LockedByRevokedCharacterUpgrade = 11, LockedByRevokedVASTransaction = 17, LockedByRestriction = 19, LockedForRealmPlaytype = 23 }; class CharacterLoginFailed final : public ServerPacket { public: explicit CharacterLoginFailed(LoginFailureReason code) : ServerPacket(SMSG_CHARACTER_LOGIN_FAILED, 1), Code(code) { } WorldPacket const* Write() override; LoginFailureReason Code = LoginFailureReason::Failed; }; class LogoutRequest final : public ClientPacket { public: explicit LogoutRequest(WorldPacket&& packet) : ClientPacket(CMSG_LOGOUT_REQUEST, std::move(packet)) { } void Read() override; bool IdleLogout = false; }; class LogoutResponse final : public ServerPacket { public: explicit LogoutResponse() : ServerPacket(SMSG_LOGOUT_RESPONSE, 4 + 1) { } WorldPacket const* Write() override; int32 LogoutResult = 0; bool Instant = false; }; struct GameModeData { int32 Unknown_1107_0 = 0; ObjectGuid Guid; uint8 GameMode = 0; int32 MapID = 0; uint8 Unknown_1107_1 = 0; uint8 Unknown_1107_2 = 0; uint8 Unknown_1107_3 = 0; Array Customizations; Array Unknown_1107_4; }; struct SwitchGameModeData { bool IsFastLogin = false; GameModeData Current; GameModeData New; }; class LogoutComplete final : public ServerPacket { public: LogoutComplete() : ServerPacket(SMSG_LOGOUT_COMPLETE, 1) { } WorldPacket const* Write() override; std::unique_ptr SwitchGameMode; }; class LogoutCancel final : public ClientPacket { public: explicit LogoutCancel(WorldPacket&& packet) : ClientPacket(CMSG_LOGOUT_CANCEL, std::move(packet)) { } void Read() override { } }; class LogoutCancelAck final : public ServerPacket { public: explicit LogoutCancelAck() : ServerPacket(SMSG_LOGOUT_CANCEL_ACK, 0) { } WorldPacket const* Write() override { return &_worldPacket; } }; class LoadingScreenNotify final : public ClientPacket { public: explicit LoadingScreenNotify(WorldPacket&& packet) : ClientPacket(CMSG_LOADING_SCREEN_NOTIFY, std::move(packet)) { } void Read() override; int32 MapID = -1; bool Showing = false; }; class InitialSetup final : public ServerPacket { public: explicit InitialSetup() : ServerPacket(SMSG_INITIAL_SETUP, 1 + 1) { } WorldPacket const* Write() override; uint8 ServerExpansionTier = 0; uint8 ServerExpansionLevel = 0; }; class SetActionBarToggles final : public ClientPacket { public: explicit SetActionBarToggles(WorldPacket&& packet) : ClientPacket(CMSG_SET_ACTION_BAR_TOGGLES, std::move(packet)) { } void Read() override; uint8 Mask = 0; }; class RequestPlayedTime final : public ClientPacket { public: explicit RequestPlayedTime(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_PLAYED_TIME, std::move(packet)) { } void Read() override; bool TriggerScriptEvent = false; }; class PlayedTime final : public ServerPacket { public: explicit PlayedTime() : ServerPacket(SMSG_PLAYED_TIME, 9) { } WorldPacket const* Write() override; int32 TotalTime = 0; int32 LevelTime = 0; bool TriggerEvent = false; }; class SetTitle final : public ClientPacket { public: explicit SetTitle(WorldPacket&& packet) : ClientPacket(CMSG_SET_TITLE, std::move(packet)) { } void Read() override; int32 TitleID = 0; }; class AlterApperance final : public ClientPacket { public: explicit AlterApperance(WorldPacket&& packet) : ClientPacket(CMSG_ALTER_APPEARANCE, std::move(packet)) { } void Read() override; uint8 NewSex = 0; Array Customizations; int8 CustomizedRace = 0; int32 CustomizedChrModelID = 0; int8 UnalteredVisualRaceID = 0; }; class BarberShopResult final : public ServerPacket { public: enum class ResultEnum : uint8 { Success = 0, NoMoney = 1, NotOnChair = 2, NoMoney2 = 3 }; explicit BarberShopResult(ResultEnum result) : ServerPacket(SMSG_BARBER_SHOP_RESULT, 4), Result(result) { } WorldPacket const* Write() override; ResultEnum Result = ResultEnum::Success; }; class LogXPGain final : public ServerPacket { public: explicit LogXPGain() : ServerPacket(SMSG_LOG_XP_GAIN, 16 + 4 + 1 + 4 + 4) { } WorldPacket const* Write() override; ObjectGuid Victim; int32 Original = 0; uint8 Reason = 0; int32 Amount = 0; float GroupBonus = 0.0f; }; class TitleEarned final : public ServerPacket { public: explicit TitleEarned(OpcodeServer opcode) : ServerPacket(opcode, 4) { } WorldPacket const* Write() override; uint32 Index = 0; }; class SetFactionAtWar final : public ClientPacket { public: explicit SetFactionAtWar(WorldPacket&& packet) : ClientPacket(CMSG_SET_FACTION_AT_WAR, std::move(packet)) { } void Read() override; uint16 FactionIndex = 0; }; class SetFactionNotAtWar final : public ClientPacket { public: explicit SetFactionNotAtWar(WorldPacket&& packet) : ClientPacket(CMSG_SET_FACTION_NOT_AT_WAR, std::move(packet)) { } void Read() override; uint16 FactionIndex = 0; }; class SetFactionInactive final : public ClientPacket { public: explicit SetFactionInactive(WorldPacket&& packet) : ClientPacket(CMSG_SET_FACTION_INACTIVE, std::move(packet)) { } void Read() override; uint32 Index = 0; bool State = false; }; class SetWatchedFaction final : public ClientPacket { public: explicit SetWatchedFaction(WorldPacket&& packet) : ClientPacket(CMSG_SET_WATCHED_FACTION, std::move(packet)) { } void Read() override; uint32 FactionIndex = 0; }; class SetFactionVisible : public ServerPacket { public: explicit SetFactionVisible(bool visible) : ServerPacket(visible ? SMSG_SET_FACTION_VISIBLE : SMSG_SET_FACTION_NOT_VISIBLE, 4) { } WorldPacket const* Write() override; uint32 FactionIndex = 0; }; class CharCustomizeSuccess final : public ServerPacket { public: explicit CharCustomizeSuccess(CharCustomizeInfo const* customizeInfo); WorldPacket const* Write() override; ObjectGuid CharGUID; std::string CharName; uint8 SexID = 0; Array const& Customizations; }; class CharCustomizeFailure final : public ServerPacket { public: explicit CharCustomizeFailure() : ServerPacket(SMSG_CHAR_CUSTOMIZE_FAILURE, 1 + 16) { } WorldPacket const* Write() override; uint32 Result = 0; ObjectGuid CharGUID; }; class SetPlayerDeclinedNames final : public ClientPacket { public: explicit SetPlayerDeclinedNames(WorldPacket&& packet) : ClientPacket(CMSG_SET_PLAYER_DECLINED_NAMES, std::move(packet)) { } void Read() override; ObjectGuid Player; DeclinedName DeclinedNames; }; class SetPlayerDeclinedNamesResult final : public ServerPacket { public: explicit SetPlayerDeclinedNamesResult() : ServerPacket(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 8 + 4) { } WorldPacket const* Write() override; ObjectGuid Player; int32 ResultCode = 0; }; class SavePersonalEmblem final : public ClientPacket { public: explicit SavePersonalEmblem(WorldPacket&& packet) : ClientPacket(CMSG_SAVE_PERSONAL_EMBLEM, std::move(packet)) { } void Read() override; ObjectGuid Vendor; CustomTabardInfo PersonalTabard; }; class PlayerSavePersonalEmblem final : public ServerPacket { public: explicit PlayerSavePersonalEmblem(int32 error) : ServerPacket(SMSG_PLAYER_SAVE_PERSONAL_EMBLEM, 4), Error(error) { } WorldPacket const* Write() override; int32 Error; }; } } #endif // TRINITYCORE_CHARACTER_PACKETS_H