aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2016-06-18 23:03:16 +0200
committerShauren <shauren.trinity@gmail.com>2016-06-18 23:03:16 +0200
commit0de1adf2812a4fa896dc5cd21314e596b44457b9 (patch)
treec414e3a08e01293edad3993b760604d7a1399b3e /src
parent49d0823b7062fba05725d27c406dbbe1a88a40f3 (diff)
Core/PacketIO: Updated equipment set packets and implemented saving transmog outfits (even if transmog itself isnt updated)
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp12
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.h6
-rw-r--r--src/server/game/DataStores/DB2Stores.h1
-rw-r--r--src/server/game/Entities/Player/Player.cpp141
-rw-r--r--src/server/game/Entities/Player/Player.h19
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp46
-rw-r--r--src/server/game/Server/Packets/EquipmentSetPackets.cpp18
-rw-r--r--src/server/game/Server/Packets/EquipmentSetPackets.h1
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp6
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);