diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 12 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.h | 6 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 141 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 19 | ||||
-rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 46 | ||||
-rw-r--r-- | src/server/game/Server/Packets/EquipmentSetPackets.cpp | 18 | ||||
-rw-r--r-- | src/server/game/Server/Packets/EquipmentSetPackets.h | 1 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 6 |
9 files changed, 204 insertions, 46 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 14e7ac54bab..ea5cc8ae3ae 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -126,6 +126,9 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS, "SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, ignore_mask, item0, item1, item2, item3, item4, item5, item6, item7, item8, " "item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = ? ORDER BY setindex", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS, "SELECT setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, appearance3, appearance4, " + "appearance5, appearance6, appearance7, appearance8, appearance9, appearance10, appearance11, appearance12, appearance13, appearance14, appearance15, appearance16, " + "appearance17, appearance18, mainHandEnchant, offHandEnchant FROM character_transmog_outfits WHERE guid = ? ORDER BY setindex", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell FROM character_battleground_data WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT spell, talentGroup FROM character_talent WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?", CONNECTION_ASYNC); @@ -263,6 +266,14 @@ void CharacterDatabaseConnection::DoPrepareStatements() "item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_EQUIP_SET, "DELETE FROM character_equipmentsets WHERE setguid=?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_TRANSMOG_OUTFIT, "UPDATE character_transmog_outfits SET name=?, iconname=?, ignore_mask=?, appearance0=?, appearance1=?, appearance2=?, appearance3=?, " + "appearance4=?, appearance5=?, appearance6=?, appearance7=?, appearance8=?, appearance9=?, appearance10=?, appearance11=?, appearance12=?, appearance13=?, appearance14=?, " + "appearance15=?, appearance16=?, appearance17=?, appearance18=?, mainHandEnchant=?, offHandEnchant=? WHERE guid=? AND setguid=? AND setindex=?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_TRANSMOG_OUTFIT, "INSERT INTO character_transmog_outfits (guid, setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, " + "appearance3, appearance4, appearance5, appearance6, appearance7, appearance8, appearance9, appearance10, appearance11, appearance12, appearance13, appearance14, appearance15, " + "appearance16, appearance17, appearance18, mainHandEnchant, offHandEnchant) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_TRANSMOG_OUTFIT, "DELETE FROM character_transmog_outfits WHERE setguid=?", CONNECTION_ASYNC); // Auras PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (guid, casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemLevel) " @@ -550,6 +561,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_MAIL_ITEMS, "DELETE FROM mail_items WHERE receiver = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENTS, "DELETE FROM character_achievement WHERE guid = ? AND achievement NOT IN (456,457,458,459,460,461,462,463,464,465,466,467,1400,1402,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1463,3117,3259,4078,4576,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,6433,6523,6524,6743,6744,6745,6746,6747,6748,6749,6750,6751,6752,6829,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,6869,6870,6871,6872,6873)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_EQUIPMENTSETS, "DELETE FROM character_equipmentsets WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFITS, "DELETE FROM character_transmog_outfits WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER, "DELETE FROM guild_eventlog WHERE PlayerGuid1 = ? OR PlayerGuid2 = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, "DELETE FROM guild_bank_eventlog WHERE PlayerGuid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_TALENT, "DELETE FROM character_talent WHERE guid = ?", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index ea6d9bd186f..fedc4087704 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -109,6 +109,7 @@ enum CharacterDatabaseStatements CHAR_SEL_CHARACTER_ACHIEVEMENTS, CHAR_SEL_CHARACTER_CRITERIAPROGRESS, CHAR_SEL_CHARACTER_EQUIPMENTSETS, + CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS, CHAR_SEL_CHARACTER_BGDATA, CHAR_SEL_CHARACTER_TALENTS, CHAR_SEL_CHARACTER_SKILLS, @@ -219,6 +220,10 @@ enum CharacterDatabaseStatements CHAR_INS_EQUIP_SET, CHAR_DEL_EQUIP_SET, + CHAR_UPD_TRANSMOG_OUTFIT, + CHAR_INS_TRANSMOG_OUTFIT, + CHAR_DEL_TRANSMOG_OUTFIT, + CHAR_INS_AURA, CHAR_INS_AURA_EFFECT, @@ -466,6 +471,7 @@ enum CharacterDatabaseStatements CHAR_DEL_MAIL_ITEMS, CHAR_DEL_CHAR_ACHIEVEMENTS, CHAR_DEL_CHAR_EQUIPMENTSETS, + CHAR_DEL_CHAR_TRANSMOG_OUTFITS, CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER, CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, CHAR_DEL_CHAR_TALENT, diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 78bebed07d0..72f7f741b78 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -102,6 +102,7 @@ TC_GAME_API extern DB2Storage<ItemEffectEntry> sItemEffectS TC_GAME_API extern DB2Storage<ItemEntry> sItemStore; TC_GAME_API extern DB2Storage<ItemExtendedCostEntry> sItemExtendedCostStore; TC_GAME_API extern DB2Storage<ItemLimitCategoryEntry> sItemLimitCategoryStore; +TC_GAME_API extern DB2Storage<ItemModifiedAppearanceEntry> sItemModifiedAppearanceStore; TC_GAME_API extern DB2Storage<ItemPriceBaseEntry> sItemPriceBaseStore; TC_GAME_API extern DB2Storage<ItemRandomPropertiesEntry> sItemRandomPropertiesStore; TC_GAME_API extern DB2Storage<ItemRandomSuffixEntry> sItemRandomSuffixStore; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d98c18bf6db..bf85a856d96 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4003,6 +4003,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt64(0, guid); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFITS); + stmt->setUInt64(0, guid); + trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER); stmt->setUInt64(0, guid); stmt->setUInt64(1, guid); @@ -16131,7 +16135,7 @@ void Player::_LoadArenaTeamInfo(PreparedQueryResult result) void Player::_LoadEquipmentSets(PreparedQueryResult result) { - // SetPQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, item0, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = '%u' ORDER BY setindex", GUID_LOPART(m_guid)); + // SetPQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, ignore_mask, item0, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = '%u' ORDER BY setindex", GUID_LOPART(m_guid)); if (!result) return; @@ -16141,6 +16145,7 @@ void Player::_LoadEquipmentSets(PreparedQueryResult result) EquipmentSetInfo eqSet; eqSet.Data.Guid = fields[0].GetUInt64(); + eqSet.Data.Type = EquipmentSetInfo::EQUIPMENT; eqSet.Data.SetID = fields[1].GetUInt8(); eqSet.Data.SetName = fields[2].GetString(); eqSet.Data.SetIcon = fields[3].GetString(); @@ -16151,14 +16156,55 @@ void Player::_LoadEquipmentSets(PreparedQueryResult result) if (ObjectGuid::LowType guid = fields[5 + i].GetUInt64()) eqSet.Data.Pieces[i] = ObjectGuid::Create<HighGuid::Item>(guid); + eqSet.Data.Appearances.fill(0); + eqSet.Data.Enchants.fill(0); + if (eqSet.Data.SetID >= MAX_EQUIPMENT_SET_INDEX) // client limit continue; - _equipmentSets[eqSet.Data.SetID] = eqSet; + _equipmentSets[eqSet.Data.Guid] = eqSet; } while (result->NextRow()); } +void Player::_LoadTransmogOutfits(PreparedQueryResult result) +{ + // 0 1 2 3 4 5 6 7 8 9 + //SELECT setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, appearance3, appearance4, + // 10 11 12 13 14 15 16 17 18 19 20 21 + // appearance5, appearance6, appearance7, appearance8, appearance9, appearance10, appearance11, appearance12, appearance13, appearance14, appearance15, appearance16, + // 22 23 24 25 + // appearance17, appearance18, mainHandEnchant, offHandEnchant FROM character_transmog_outfits WHERE guid = ? ORDER BY setindex + if (!result) + return; + + do + { + Field* fields = result->Fetch(); + EquipmentSetInfo eqSet; + + eqSet.Data.Guid = fields[0].GetUInt64(); + eqSet.Data.Type = EquipmentSetInfo::TRANSMOG; + eqSet.Data.SetID = fields[1].GetUInt8(); + eqSet.Data.SetName = fields[2].GetString(); + eqSet.Data.SetIcon = fields[3].GetString(); + eqSet.Data.IgnoreMask = fields[4].GetUInt32(); + eqSet.State = EQUIPMENT_SET_UNCHANGED; + eqSet.Data.Pieces.fill(ObjectGuid::Empty); + + for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) + eqSet.Data.Appearances[i] = fields[5 + i].GetInt32(); + + for (std::size_t i = 0; i < eqSet.Data.Enchants.size(); ++i) + eqSet.Data.Enchants[i] = fields[24 + i].GetInt32(); + + if (eqSet.Data.SetID >= MAX_EQUIPMENT_SET_INDEX) // client limit + continue; + + _equipmentSets[eqSet.Data.Guid] = eqSet; + } while (result->NextRow()); +} + void Player::_LoadBGData(PreparedQueryResult result) { if (!result) @@ -16972,6 +17018,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) _LoadDeclinedNames(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES)); _LoadEquipmentSets(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS)); + _LoadTransmogOutfits(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS)); _LoadCUFProfiles(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES)); @@ -24799,12 +24846,12 @@ void Player::SendEquipmentSetList() SendDirectMessage(data.Write()); } -void Player::SetEquipmentSet(EquipmentSetInfo::EquipmentSetData&& newEqSet) +void Player::SetEquipmentSet(EquipmentSetInfo::EquipmentSetData const& newEqSet) { if (newEqSet.Guid != 0) { // something wrong... - EquipmentSetContainer::const_iterator itr = _equipmentSets.find(newEqSet.SetID); + EquipmentSetContainer::const_iterator itr = _equipmentSets.find(newEqSet.Guid); if (itr == _equipmentSets.end() || itr->second.Data.Guid != newEqSet.Guid) { TC_LOG_ERROR("entities.player", "Player::SetEquipmentSet: Player '%s' (%s) tried to save nonexistent equipment set " UI64FMTD " (index: %u)", @@ -24813,7 +24860,7 @@ void Player::SetEquipmentSet(EquipmentSetInfo::EquipmentSetData&& newEqSet) } } - EquipmentSetInfo& eqSlot = _equipmentSets[newEqSet.SetID]; + EquipmentSetInfo& eqSlot = _equipmentSets[newEqSet.Guid]; EquipmentSetUpdateState oldState = eqSlot.State; @@ -24825,6 +24872,7 @@ void Player::SetEquipmentSet(EquipmentSetInfo::EquipmentSetData&& newEqSet) WorldPackets::EquipmentSet::EquipmentSetID data; data.GUID = eqSlot.Data.Guid; + data.Type = eqSlot.Data.Type; data.SetID = eqSlot.Data.SetID; SendDirectMessage(data.Write()); } @@ -24845,39 +24893,76 @@ void Player::_SaveEquipmentSets(SQLTransaction& trans) ++itr; break; // nothing do case EQUIPMENT_SET_CHANGED: - stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_EQUIP_SET); - stmt->setString(j++, eqSet.Data.SetName); - stmt->setString(j++, eqSet.Data.SetIcon); - stmt->setUInt32(j++, eqSet.Data.IgnoreMask); - - for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) - stmt->setUInt64(j++, eqSet.Data.Pieces[i].GetCounter()); - - stmt->setUInt64(j++, GetGUID().GetCounter()); - stmt->setUInt64(j++, eqSet.Data.Guid); - stmt->setUInt32(j, eqSet.Data.SetID); + { + if (eqSet.Data.Type == EquipmentSetInfo::EQUIPMENT) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_EQUIP_SET); + stmt->setString(j++, eqSet.Data.SetName); + stmt->setString(j++, eqSet.Data.SetIcon); + stmt->setUInt32(j++, eqSet.Data.IgnoreMask); + for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + stmt->setUInt64(j++, eqSet.Data.Pieces[i].GetCounter()); + stmt->setUInt64(j++, GetGUID().GetCounter()); + stmt->setUInt64(j++, eqSet.Data.Guid); + stmt->setUInt32(j, eqSet.Data.SetID); + } + else + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_TRANSMOG_OUTFIT); + stmt->setString(j++, eqSet.Data.SetName); + stmt->setString(j++, eqSet.Data.SetIcon); + stmt->setUInt32(j++, eqSet.Data.IgnoreMask); + for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + stmt->setInt32(j++, eqSet.Data.Appearances[i]); + for (std::size_t i = 0; i < eqSet.Data.Enchants.size(); ++i) + stmt->setInt32(j++, eqSet.Data.Enchants[i]); + stmt->setUInt64(j++, GetGUID().GetCounter()); + stmt->setUInt64(j++, eqSet.Data.Guid); + stmt->setUInt32(j, eqSet.Data.SetID); + } trans->Append(stmt); eqSet.State = EQUIPMENT_SET_UNCHANGED; ++itr; break; + } case EQUIPMENT_SET_NEW: - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_EQUIP_SET); - stmt->setUInt64(j++, GetGUID().GetCounter()); - stmt->setUInt64(j++, eqSet.Data.Guid); - stmt->setUInt32(j++, eqSet.Data.SetID); - stmt->setString(j++, eqSet.Data.SetName); - stmt->setString(j++, eqSet.Data.SetIcon); - stmt->setUInt32(j++, eqSet.Data.IgnoreMask); - - for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) - stmt->setUInt64(j++, eqSet.Data.Pieces[i].GetCounter()); - + { + if (eqSet.Data.Type == EquipmentSetInfo::EQUIPMENT) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_EQUIP_SET); + stmt->setUInt64(j++, GetGUID().GetCounter()); + stmt->setUInt64(j++, eqSet.Data.Guid); + stmt->setUInt32(j++, eqSet.Data.SetID); + stmt->setString(j++, eqSet.Data.SetName); + stmt->setString(j++, eqSet.Data.SetIcon); + stmt->setUInt32(j++, eqSet.Data.IgnoreMask); + for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + stmt->setUInt64(j++, eqSet.Data.Pieces[i].GetCounter()); + } + else + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_TRANSMOG_OUTFIT); + stmt->setUInt64(j++, GetGUID().GetCounter()); + stmt->setUInt64(j++, eqSet.Data.Guid); + stmt->setUInt32(j++, eqSet.Data.SetID); + stmt->setString(j++, eqSet.Data.SetName); + stmt->setString(j++, eqSet.Data.SetIcon); + stmt->setUInt32(j++, eqSet.Data.IgnoreMask); + for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + stmt->setInt32(j++, eqSet.Data.Appearances[i]); + for (std::size_t i = 0; i < eqSet.Data.Enchants.size(); ++i) + stmt->setInt32(j++, eqSet.Data.Enchants[i]); + } trans->Append(stmt); eqSet.State = EQUIPMENT_SET_UNCHANGED; ++itr; break; + } case EQUIPMENT_SET_DELETED: - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EQUIP_SET); + if (eqSet.Data.Type == EquipmentSetInfo::EQUIPMENT) + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EQUIP_SET); + else + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TRANSMOG_OUTFIT); stmt->setUInt64(0, eqSet.Data.Guid); trans->Append(stmt); itr = _equipmentSets.erase(itr); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 4e4e116f65e..bf1880a1f6e 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -808,24 +808,33 @@ enum EquipmentSetUpdateState struct EquipmentSetInfo { + enum EquipmentSetType : int32 + { + EQUIPMENT = 0, + TRANSMOG = 1 + }; + /// Data sent in EquipmentSet related packets struct EquipmentSetData { + EquipmentSetType Type = EQUIPMENT; uint64 Guid = 0; ///< Set Identifier uint32 SetID = 0; ///< Index uint32 IgnoreMask = 0; ///< Mask of EquipmentSlot std::string SetName; std::string SetIcon; - ObjectGuid Pieces[EQUIPMENT_SLOT_END]; + std::array<ObjectGuid, EQUIPMENT_SLOT_END> Pieces; + std::array<int32, EQUIPMENT_SLOT_END> Appearances; ///< ItemModifiedAppearanceID + std::array<int32, 2> Enchants; ///< SpellItemEnchantmentID } Data; /// Server-side data EquipmentSetUpdateState State = EQUIPMENT_SET_NEW; }; -#define MAX_EQUIPMENT_SET_INDEX 10 // client limit +#define MAX_EQUIPMENT_SET_INDEX 20 // client limit -typedef std::map<uint32, EquipmentSetInfo> EquipmentSetContainer; +typedef std::map<uint64, EquipmentSetInfo> EquipmentSetContainer; struct ItemPosCount { @@ -955,6 +964,7 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS, PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS, PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS, + PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS, PLAYER_LOGIN_QUERY_LOAD_BG_DATA, PLAYER_LOGIN_QUERY_LOAD_TALENTS, PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA, @@ -2139,7 +2149,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto); void SendEquipmentSetList(); - void SetEquipmentSet(EquipmentSetInfo::EquipmentSetData&& newEqSet); + void SetEquipmentSet(EquipmentSetInfo::EquipmentSetData const& newEqSet); void DeleteEquipmentSet(uint64 id); void SendInitWorldStates(uint32 zone, uint32 area); @@ -2519,6 +2529,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void _LoadDeclinedNames(PreparedQueryResult result); void _LoadArenaTeamInfo(PreparedQueryResult result); void _LoadEquipmentSets(PreparedQueryResult result); + void _LoadTransmogOutfits(PreparedQueryResult result); void _LoadBGData(PreparedQueryResult result); void _LoadTalents(PreparedQueryResult result); void _LoadInstanceTimeRestrictions(PreparedQueryResult result); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index b8c6072f60e..63a37b42efd 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -192,6 +192,10 @@ bool LoginQueryHolder::Initialize() stmt->setUInt64(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUF_PROFILES); stmt->setUInt64(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES, stmt); @@ -1623,29 +1627,53 @@ void WorldSession::HandleEquipmentSetSave(WorldPackets::EquipmentSet::SaveEquipm if (saveEquipmentSet.Set.SetID >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount return; + if (saveEquipmentSet.Set.Type > EquipmentSetInfo::TRANSMOG) + return; + for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) { if (!(saveEquipmentSet.Set.IgnoreMask & (1 << i))) { - ObjectGuid const& itemGuid = saveEquipmentSet.Set.Pieces[i]; + if (saveEquipmentSet.Set.Type == EquipmentSetInfo::EQUIPMENT) + { + saveEquipmentSet.Set.Appearances[i] = 0; - Item* item = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + ObjectGuid const& itemGuid = saveEquipmentSet.Set.Pieces[i]; - /// cheating check 1 (item equipped but sent empty guid) - if (!item && !itemGuid.IsEmpty()) - return; + Item* item = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); - /// cheating check 2 (sent guid does not match equipped item) - if (item && item->GetGUID() != itemGuid) - return; + /// cheating check 1 (item equipped but sent empty guid) + if (!item && !itemGuid.IsEmpty()) + return; + + /// cheating check 2 (sent guid does not match equipped item) + if (item && item->GetGUID() != itemGuid) + return; + } + else + { + saveEquipmentSet.Set.Pieces[i].Clear(); + if (saveEquipmentSet.Set.Appearances[i] && !sItemModifiedAppearanceStore.LookupEntry(saveEquipmentSet.Set.Appearances[i])) + return; + + // TODO: validata whether appearance is known + } } else + { saveEquipmentSet.Set.Pieces[i].Clear(); + saveEquipmentSet.Set.Appearances[i] = 0; + } } saveEquipmentSet.Set.IgnoreMask &= 0x7FFFF; /// clear invalid bits (i > EQUIPMENT_SLOT_END) + if (saveEquipmentSet.Set.Type == EquipmentSetInfo::EQUIPMENT) + { + saveEquipmentSet.Set.Enchants[0] = 0; + saveEquipmentSet.Set.Enchants[1] = 0; + } - _player->SetEquipmentSet(std::move(saveEquipmentSet.Set)); + _player->SetEquipmentSet(saveEquipmentSet.Set); } void WorldSession::HandleDeleteEquipmentSet(WorldPackets::EquipmentSet::DeleteEquipmentSet& deleteEquipmentSet) diff --git a/src/server/game/Server/Packets/EquipmentSetPackets.cpp b/src/server/game/Server/Packets/EquipmentSetPackets.cpp index 783def93e88..dbc40c63e7d 100644 --- a/src/server/game/Server/Packets/EquipmentSetPackets.cpp +++ b/src/server/game/Server/Packets/EquipmentSetPackets.cpp @@ -20,6 +20,7 @@ WorldPacket const* WorldPackets::EquipmentSet::EquipmentSetID::Write() { _worldPacket << uint64(GUID); + _worldPacket << int32(Type); _worldPacket << uint32(SetID); return &_worldPacket; @@ -31,12 +32,18 @@ WorldPacket const* WorldPackets::EquipmentSet::LoadEquipmentSet::Write() for (EquipmentSetInfo::EquipmentSetData const* equipSet : SetData) { + _worldPacket << int32(equipSet->Type); _worldPacket << uint64(equipSet->Guid); _worldPacket << uint32(equipSet->SetID); _worldPacket << uint32(equipSet->IgnoreMask); - for (ObjectGuid const& guid : equipSet->Pieces) - _worldPacket << guid; + for (std::size_t i = 0; i < EQUIPMENT_SLOT_END; ++i) + { + _worldPacket << equipSet->Pieces[i]; + _worldPacket << int32(equipSet->Appearances[i]); + } + + _worldPacket.append(equipSet->Enchants.data(), equipSet->Enchants.size()); _worldPacket.WriteBits(equipSet->SetName.length(), 8); _worldPacket.WriteBits(equipSet->SetIcon.length(), 9); @@ -51,12 +58,19 @@ WorldPacket const* WorldPackets::EquipmentSet::LoadEquipmentSet::Write() void WorldPackets::EquipmentSet::SaveEquipmentSet::Read() { + Set.Type = EquipmentSetInfo::EquipmentSetType(_worldPacket.read<int32>()); _worldPacket >> Set.Guid; _worldPacket >> Set.SetID; _worldPacket >> Set.IgnoreMask; for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + { _worldPacket >> Set.Pieces[i]; + _worldPacket >> Set.Appearances[i]; + } + + _worldPacket >> Set.Enchants[0]; + _worldPacket >> Set.Enchants[1]; uint32 setNameLength = _worldPacket.ReadBits(8); uint32 setIconLength = _worldPacket.ReadBits(9); diff --git a/src/server/game/Server/Packets/EquipmentSetPackets.h b/src/server/game/Server/Packets/EquipmentSetPackets.h index e33b6a6cdca..42f6fd5df05 100644 --- a/src/server/game/Server/Packets/EquipmentSetPackets.h +++ b/src/server/game/Server/Packets/EquipmentSetPackets.h @@ -33,6 +33,7 @@ namespace WorldPackets WorldPacket const* Write() override; uint64 GUID = 0; ///< Set Identifier + int32 Type = 0; uint32 SetID = 0; ///< Index }; diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 7bfbb88e9bd..f4c246068a1 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -676,7 +676,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_REVERT_MONUMENT_APPEARANCE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_RIDE_VEHICLE_INTERACT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::RideVehicleInteract, &WorldSession::HandleRideVehicleInteract); DEFINE_HANDLER(CMSG_SAVE_CUF_PROFILES, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Misc::SaveCUFProfiles, &WorldSession::HandleSaveCUFProfiles); - DEFINE_HANDLER(CMSG_SAVE_EQUIPMENT_SET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::EquipmentSet::SaveEquipmentSet, &WorldSession::HandleEquipmentSetSave); + DEFINE_HANDLER(CMSG_SAVE_EQUIPMENT_SET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::EquipmentSet::SaveEquipmentSet, &WorldSession::HandleEquipmentSetSave); DEFINE_HANDLER(CMSG_SAVE_GUILD_EMBLEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Guild::SaveGuildEmblem, &WorldSession::HandleSaveGuildEmblem); DEFINE_HANDLER(CMSG_SCENE_PLAYBACK_CANCELED, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Scenes::ScenePlaybackCanceled, &WorldSession::HandleScenePlaybackCanceled); DEFINE_HANDLER(CMSG_SCENE_PLAYBACK_COMPLETE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Scenes::ScenePlaybackComplete, &WorldSession::HandleScenePlaybackComplete); @@ -1077,7 +1077,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENCOUNTER_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENUM_CHARACTERS_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENVIRONMENTAL_DAMAGE_LOG, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_ID, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_ID, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_EXPECTED_SPAM_RECORDS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_EXPLORATION_EXPERIENCE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FACTION_BONUS_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); @@ -1297,7 +1297,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_LIVE_REGION_CHARACTER_COPY_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LIVE_REGION_GET_ACCOUNT_CHARACTER_LIST_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_CUF_PROFILES, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_EQUIPMENT_SET, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_EQUIPMENT_SET, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_SELECTED_TROPHY_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGIN_SET_TIME_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGIN_VERIFY_WORLD, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); |