diff options
| -rw-r--r-- | src/server/game/DataStores/DBCStores.cpp | 44 | ||||
| -rw-r--r-- | src/server/game/DataStores/DBCStores.h | 6 | ||||
| -rw-r--r-- | src/server/game/DataStores/DBCStructure.h | 32 | ||||
| -rw-r--r-- | src/server/game/DataStores/DBCfmt.h | 1 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 74 | 
5 files changed, 90 insertions, 67 deletions
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 731266f1ca3..34df901175a 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -20,6 +20,7 @@  #include "DBCFileLoader.h"  #include "DBCfmt.h"  #include "Errors.h" +#include "IteratorPair.h"  #include "Log.h"  #include "ObjectDefines.h"  #include "Regex.h" @@ -37,7 +38,6 @@ typedef std::map<uint32, uint32> AreaFlagByMapID;  typedef std::tuple<int16, int8, int32> WMOAreaTableKey;  typedef std::map<WMOAreaTableKey, WMOAreaTableEntry const*> WMOAreaInfoByTripple; -typedef std::multimap<uint32, CharSectionsEntry const*> CharSectionsMap;  DBCStorage <AreaTableEntry> sAreaTableStore(AreaTableEntryfmt);  DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt); @@ -53,10 +53,12 @@ DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore(BankBagSlotPricesEnt  DBCStorage <BannedAddOnsEntry> sBannedAddOnsStore(BannedAddOnsfmt);  DBCStorage <BattlemasterListEntry> sBattlemasterListStore(BattlemasterListEntryfmt);  DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore(BarberShopStyleEntryfmt); +DBCStorage <CharacterFacialHairStylesEntry> sCharacterFacialHairStylesStore(CharacterFacialHairStylesfmt); +std::unordered_map<uint32, CharacterFacialHairStylesEntry const*> sCharFacialHairMap; +DBCStorage <CharSectionsEntry> sCharSectionsStore(CharSectionsEntryfmt); +std::unordered_multimap<uint32, CharSectionsEntry const*> sCharSectionMap;  DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore(CharStartOutfitEntryfmt);  std::map<uint32, CharStartOutfitEntry const*> sCharStartOutfitMap; -DBCStorage <CharSectionsEntry> sCharSectionsStore(CharSectionsEntryfmt); -CharSectionsMap sCharSectionMap;  DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt);  DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);  DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt); @@ -283,8 +285,9 @@ void LoadDBCStores(const std::string& dataPath)      LOAD_DBC(sBannedAddOnsStore,                  "BannedAddOns.dbc");      LOAD_DBC(sBattlemasterListStore,              "BattlemasterList.dbc");      LOAD_DBC(sBarberShopStyleStore,               "BarberShopStyle.dbc"); -    LOAD_DBC(sCharStartOutfitStore,               "CharStartOutfit.dbc"); +    LOAD_DBC(sCharacterFacialHairStylesStore,     "CharacterFacialHairStyles.dbc");      LOAD_DBC(sCharSectionsStore,                  "CharSections.dbc"); +    LOAD_DBC(sCharStartOutfitStore,               "CharStartOutfit.dbc");      LOAD_DBC(sCharTitlesStore,                    "CharTitles.dbc");      LOAD_DBC(sChatChannelsStore,                  "ChatChannels.dbc");      LOAD_DBC(sChrClassesStore,                    "ChrClasses.dbc"); @@ -395,13 +398,17 @@ void LoadDBCStores(const std::string& dataPath)  #undef LOAD_DBC_EXT -    for (CharStartOutfitEntry const* outfit : sCharStartOutfitStore) -        sCharStartOutfitMap[outfit->Race | (outfit->Class << 8) | (outfit->Gender << 16)] = outfit; +    for (CharacterFacialHairStylesEntry const* entry : sCharacterFacialHairStylesStore) +        if (entry->Race && ((1 << (entry->Race - 1)) & RACEMASK_ALL_PLAYABLE) != 0) // ignore nonplayable races +            sCharFacialHairMap.insert({ entry->Race | (entry->Gender << 8) | (entry->Variation << 16), entry });      for (CharSectionsEntry const* entry : sCharSectionsStore) -        if (entry->Race && ((1 << (entry->Race - 1)) & RACEMASK_ALL_PLAYABLE) != 0) //ignore Nonplayable races +        if (entry->Race && ((1 << (entry->Race - 1)) & RACEMASK_ALL_PLAYABLE) != 0) // ignore nonplayable races              sCharSectionMap.insert({ entry->GenType | (entry->Gender << 8) | (entry->Race << 16), entry }); +    for (CharStartOutfitEntry const* outfit : sCharStartOutfitStore) +        sCharStartOutfitMap[outfit->Race | (outfit->Class << 8) | (outfit->Gender << 16)] = outfit; +      for (EmotesTextSoundEntry const* entry : sEmotesTextSoundStore)          sEmotesTextSoundMap[EmotesTextSoundKey(entry->EmotesTextId, entry->RaceId, entry->SexId)] = entry; @@ -854,10 +861,10 @@ uint32 GetLiquidFlags(uint32 liquidType)      return 0;  } -CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender) +CharacterFacialHairStylesEntry const* GetCharFacialHairEntry(uint8 race, uint8 gender, uint8 facialHairID)  { -    std::map<uint32, CharStartOutfitEntry const*>::const_iterator itr = sCharStartOutfitMap.find(race | (class_ << 8) | (gender << 16)); -    if (itr == sCharStartOutfitMap.end()) +    auto itr = sCharFacialHairMap.find(uint32(race) | uint32(gender << 8) | uint32(facialHairID << 16)); +    if (itr == sCharFacialHairMap.end())          return nullptr;      return itr->second; @@ -865,16 +872,25 @@ CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, ui  CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color)  { -    std::pair<CharSectionsMap::const_iterator, CharSectionsMap::const_iterator> eqr = sCharSectionMap.equal_range(uint32(genType) | uint32(gender << 8) | uint32(race << 16)); -    for (CharSectionsMap::const_iterator itr = eqr.first; itr != eqr.second; ++itr) +    uint32 const key = uint32(genType) | uint32(gender << 8) | uint32(race << 16); +    for (auto const& section : Trinity::Containers::MapEqualRange(sCharSectionMap, key))      { -        if (itr->second->Type == type && itr->second->Color == color) -            return itr->second; +        if (section.second->Type == type && section.second->Color == color) +            return section.second;      }      return nullptr;  } +CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender) +{ +    std::map<uint32, CharStartOutfitEntry const*>::const_iterator itr = sCharStartOutfitMap.find(race | (class_ << 8) | (gender << 16)); +    if (itr == sCharStartOutfitMap.end()) +        return nullptr; + +    return itr->second; +} +  /// Returns LFGDungeonEntry for a specific map and difficulty. Will return first found entry if multiple dungeons use the same map (such as Scarlet Monastery)  LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty)  { diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index fec15aae55e..8bcc9c5ac24 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -71,8 +71,9 @@ TC_GAME_API uint32 GetLiquidFlags(uint32 liquidType);  TC_GAME_API PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level);  TC_GAME_API PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id); -TC_GAME_API CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender); +TC_GAME_API CharacterFacialHairStylesEntry const* GetCharFacialHairEntry(uint8 race, uint8 gender, uint8 facialHairID);  TC_GAME_API CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color); +TC_GAME_API CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender);  TC_GAME_API LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty); @@ -98,8 +99,9 @@ TC_GAME_API extern DBCStorage <BannedAddOnsEntry>            sBannedAddOnsStore;  TC_GAME_API extern DBCStorage <BarberShopStyleEntry>         sBarberShopStyleStore;  TC_GAME_API extern DBCStorage <BattlemasterListEntry>        sBattlemasterListStore;  TC_GAME_API extern DBCStorage <ChatChannelsEntry>            sChatChannelsStore; -TC_GAME_API extern DBCStorage <CharStartOutfitEntry>         sCharStartOutfitStore; +TC_GAME_API extern DBCStorage <CharacterFacialHairStylesEntry> sCharacterFacialHairStylesStore;  TC_GAME_API extern DBCStorage <CharSectionsEntry>            sCharSectionsStore; +TC_GAME_API extern DBCStorage <CharStartOutfitEntry>         sCharStartOutfitStore;  TC_GAME_API extern DBCStorage <CharTitlesEntry>              sCharTitlesStore;  TC_GAME_API extern DBCStorage <ChrClassesEntry>              sChrClassesStore;  TC_GAME_API extern DBCStorage <ChrRacesEntry>                sChrRacesStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index b5ee0f89d6b..b0bea8ca81c 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -302,18 +302,12 @@ struct BattlemasterListEntry      //uint32 SomeLevel;                                     // 31, may be max level  }; -#define MAX_OUTFIT_ITEMS 24 - -struct CharStartOutfitEntry +struct CharacterFacialHairStylesEntry  { -    //uint32 Id;                                            // 0 -    uint8 Race;                                             // 1 -    uint8 Class;                                            // 2 -    uint8 Gender;                                           // 3 -    //uint8 Unused;                                         // 4 -    int32 ItemId[MAX_OUTFIT_ITEMS];                         // 5-28 -    //int32 ItemDisplayId[MAX_OUTFIT_ITEMS];                // 29-52 not required at server side -    //int32 ItemInventorySlot[MAX_OUTFIT_ITEMS];            // 53-76 not required at server side +    uint32 Race; +    uint32 Gender; +    uint32 Variation; +    // uint32 Geoset[5];  };  enum CharSectionFlags @@ -341,6 +335,22 @@ struct CharSectionsEntry      uint32 Flags;      uint32 Type;      uint32 Color; + +    inline bool HasFlag(CharSectionFlags flag) const { return !!(Flags & flag); } +}; + +#define MAX_OUTFIT_ITEMS 24 + +struct CharStartOutfitEntry +{ +    //uint32 Id;                                            // 0 +    uint8 Race;                                             // 1 +    uint8 Class;                                            // 2 +    uint8 Gender;                                           // 3 +    //uint8 Unused;                                         // 4 +    int32 ItemId[MAX_OUTFIT_ITEMS];                         // 5-28 +    //int32 ItemDisplayId[MAX_OUTFIT_ITEMS];                // 29-52 not required at server side +    //int32 ItemInventorySlot[MAX_OUTFIT_ITEMS];            // 53-76 not required at server side  };  struct CharTitlesEntry diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 5d8132ea6a6..dd74cffb51e 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -32,6 +32,7 @@ char const BankBagSlotPricesEntryfmt[] = "ni";  char const BannedAddOnsfmt[] = "nxxxxxxxxxx";  char const BarberShopStyleEntryfmt[] = "nixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiii";  char const BattlemasterListEntryfmt[] = "niiiiiiiiixssssssssssssssssxiixx"; +char const CharacterFacialHairStylesfmt[] = "iiixxxxx";  char const CharStartOutfitEntryfmt[] = "dbbbXiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";  char const CharSectionsEntryfmt[] = "diiixxxiii";  char const CharTitlesEntryfmt[] = "nxssssssssssssssssxssssssssssssssssxi"; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c757645606d..4b8a7b57742 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -26526,54 +26526,48 @@ void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) const  bool Player::ValidateAppearance(uint8 race, uint8 class_, uint8 gender, uint8 hairID, uint8 hairColor, uint8 faceID, uint8 facialHair, uint8 skinColor, bool create /*=false*/)  { -    // Check skin color -    // For Skin type is always 0 -    if (CharSectionsEntry const* entry = GetCharSectionEntry(race, SECTION_TYPE_SKIN, gender, 0, skinColor)) -    {   // Skin Color defined as Face color, too, we check skin & face in one pass -        if (CharSectionsEntry const* entry2 = GetCharSectionEntry(race, SECTION_TYPE_FACE, gender, faceID, skinColor)) -        { -            // Check DeathKnight exclusive -            if (((entry->Flags & SECTION_FLAG_DEATH_KNIGHT) || (entry2->Flags & SECTION_FLAG_DEATH_KNIGHT)) && class_ != CLASS_DEATH_KNIGHT) -                return false; -            if (create && !((entry->Flags & SECTION_FLAG_PLAYER) && (entry2->Flags & SECTION_FLAG_PLAYER))) -                return false; -        } -        else +    auto validateCharSection = [class_, create](CharSectionsEntry const* entry) -> bool +    { +        if (!entry)              return false; -    } -    else + +        // Check Death Knight exclusive +        if (class_ != CLASS_DEATH_KNIGHT && entry->HasFlag(SECTION_FLAG_DEATH_KNIGHT)) +            return false; + +        // Character creation/customize has some limited sections (as opposed to barbershop) +        if (create && !entry->HasFlag(SECTION_FLAG_PLAYER)) +            return false; + +        return true; +    }; + +    // For Skin type is always 0 +    CharSectionsEntry const* skinEntry = GetCharSectionEntry(race, SECTION_TYPE_SKIN, gender, 0, skinColor); +    if (!validateCharSection(skinEntry))          return false; -    // These combinations don't have an entry of Type SECTION_TYPE_FACIAL_HAIR, exclude them from that check -    bool excludeCheck = (race == RACE_TAUREN) || (race == RACE_DRAENEI) || (gender == GENDER_FEMALE && race != RACE_NIGHTELF && race != RACE_UNDEAD_PLAYER); +    // Skin Color defined as Face color, too +    CharSectionsEntry const* faceEntry = GetCharSectionEntry(race, SECTION_TYPE_FACE, gender, faceID, skinColor); +    if (!validateCharSection(faceEntry)) +        return false;      // Check Hair -    if (CharSectionsEntry const* entry = GetCharSectionEntry(race, SECTION_TYPE_HAIR, gender, hairID, hairColor)) +    CharSectionsEntry const* hairEntry = GetCharSectionEntry(race, SECTION_TYPE_HAIR, gender, hairID, hairColor); +    if (!validateCharSection(hairEntry)) +        return false; + +    // These combinations don't have an entry of Type SECTION_TYPE_FACIAL_HAIR, exclude them from that check +    bool const excludeCheck = (race == RACE_TAUREN) || (race == RACE_DRAENEI) || (gender == GENDER_FEMALE && race != RACE_NIGHTELF && race != RACE_UNDEAD_PLAYER); +    if (!excludeCheck)      { -        if ((entry->Flags & SECTION_FLAG_DEATH_KNIGHT) && class_ != CLASS_DEATH_KNIGHT) +        CharSectionsEntry const* facialHairEntry = GetCharSectionEntry(race, SECTION_TYPE_FACIAL_HAIR, gender, facialHair, hairColor); +        if (!validateCharSection(facialHairEntry))              return false; -        if (create && !(entry->Flags & SECTION_FLAG_PLAYER)) -            return false; - -        if (!excludeCheck) -        { -            if (CharSectionsEntry const* entry2 = GetCharSectionEntry(race, SECTION_TYPE_FACIAL_HAIR, gender, facialHair, hairColor)) -            { -                if ((entry2->Flags & SECTION_FLAG_DEATH_KNIGHT) && class_ != CLASS_DEATH_KNIGHT) -                    return false; -                if (create && !(entry2->Flags & SECTION_FLAG_PLAYER)) -                    return false; -            } -            else -                return false; -        } -        else -        { -            // @TODO: Bound checking for facialHair ID (used clientside for markings, tauren beard, etc.) -            // Not present in DBC -        }      } -    else + +    CharacterFacialHairStylesEntry const* entry = GetCharFacialHairEntry(race, gender, facialHair); +    if (!entry)          return false;      return true;  | 
