aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp8
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h4
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.cpp5
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.h4
-rw-r--r--src/server/game/DataStores/DB2LoadInfo.h28
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp2
-rw-r--r--src/server/game/DataStores/DB2Stores.h1
-rw-r--r--src/server/game/DataStores/DB2Structure.h21
-rw-r--r--src/server/game/DataStores/DBCEnums.h11
-rw-r--r--src/server/game/Entities/Player/CollectionMgr.cpp208
-rw-r--r--src/server/game/Entities/Player/CollectionMgr.h61
-rw-r--r--src/server/game/Entities/Player/Player.cpp8
-rw-r--r--src/server/game/Entities/Player/Player.h3
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp3
-rw-r--r--src/server/game/Handlers/CollectionsHandler.cpp2
-rw-r--r--src/server/game/Server/Packets/CollectionPackets.cpp30
-rw-r--r--src/server/game/Server/Packets/CollectionPackets.h21
-rw-r--r--src/server/game/Server/Packets/MiscPackets.cpp21
-rw-r--r--src/server/game/Server/Packets/MiscPackets.h11
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp4
-rw-r--r--src/server/game/Server/WorldSession.cpp6
-rw-r--r--src/server/game/Spells/Spell.h1
-rw-r--r--src/server/game/Spells/SpellEffects.cpp14
-rw-r--r--src/server/game/World/World.cpp3
24 files changed, 429 insertions, 51 deletions
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp
index f9adad39d00..d0a47a6ba82 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.cpp
+++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp
@@ -2009,6 +2009,14 @@ void HotfixDatabaseConnection::DoPrepareStatements()
PREPARE_MAX_ID_STMT(HOTFIX_SEL_VIGNETTE, "SELECT MAX(ID) + 1 FROM vignette", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_VIGNETTE, "SELECT ID, Name_lang FROM vignette_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?", CONNECTION_SYNCH);
+ // WarbandScene.db2
+ PrepareStatement(HOTFIX_SEL_WARBAND_SCENE, "SELECT Name, Description, Source, PositionX, PositionY, PositionZ, LookAtX, LookAtY, LookAtZ, ID, "
+ "MapID, Fov, TimeOfDay, Flags, SoundAmbienceID, Quality, TextureKit, DefaultScenePriority, SourceType FROM warband_scene"
+ " WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
+ PREPARE_MAX_ID_STMT(HOTFIX_SEL_WARBAND_SCENE, "SELECT MAX(ID) + 1 FROM warband_scene", CONNECTION_SYNCH);
+ PREPARE_LOCALE_STMT(HOTFIX_SEL_WARBAND_SCENE, "SELECT ID, Name_lang, Description_lang, Source_lang FROM warband_scene_locale"
+ " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?", CONNECTION_SYNCH);
+
// WmoAreaTable.db2
PrepareStatement(HOTFIX_SEL_WMO_AREA_TABLE, "SELECT AreaName, ID, WmoID, NameSetID, WmoGroupID, SoundProviderPref, SoundProviderPrefUnderwater, "
"AmbienceID, UwAmbience, ZoneMusic, UwZoneMusic, IntroSound, UwIntroSound, AreaTableID, Flags FROM wmo_area_table"
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h
index 1a7d158cdd7..f713884f6cb 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.h
+++ b/src/server/database/Database/Implementation/HotfixDatabase.h
@@ -1161,6 +1161,10 @@ enum HotfixDatabaseStatements : uint32
HOTFIX_SEL_VIGNETTE_MAX_ID,
HOTFIX_SEL_VIGNETTE_LOCALE,
+ HOTFIX_SEL_WARBAND_SCENE,
+ HOTFIX_SEL_WARBAND_SCENE_MAX_ID,
+ HOTFIX_SEL_WARBAND_SCENE_LOCALE,
+
HOTFIX_SEL_WMO_AREA_TABLE,
HOTFIX_SEL_WMO_AREA_TABLE_MAX_ID,
HOTFIX_SEL_WMO_AREA_TABLE_LOCALE,
diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp
index d67e753041f..f9cb219af61 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/database/Database/Implementation/LoginDatabase.cpp
@@ -191,6 +191,11 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_BNET_TRANSMOG_ILLUSIONS, "SELECT blobIndex, illusionMask FROM battlenet_account_transmog_illusions WHERE battlenetAccountId = ? ORDER BY blobIndex DESC", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_BNET_TRANSMOG_ILLUSIONS, "INSERT INTO battlenet_account_transmog_illusions (battlenetAccountId, blobIndex, illusionMask) VALUES (?, ?, ?) "
"ON DUPLICATE KEY UPDATE illusionMask = illusionMask | VALUES(illusionMask)", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_SEL_BNET_WARBAND_SCENES, "SELECT warbandSceneId, isFavorite, hasFanfare FROM battlenet_account_warband_scenes WHERE battlenetAccountId = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_INS_BNET_WARBAND_SCENE, "INSERT INTO battlenet_account_warband_scenes (battlenetAccountId, warbandSceneId, isFavorite, hasFanfare) VALUES (?, ?, ?, ?) "
+ "ON DUPLICATE KEY UPDATE isFavorite = VALUES(isFavorite)", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_UPD_BNET_WARBAND_SCENE, "UPDATE battlenet_account_warband_scenes SET isFavorite = ?, hasFanfare = ? WHERE battlenetAccountId = ? AND warbandSceneId = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_DEL_BNET_WARBAND_SCENE, "DELETE FROM battlenet_account_warband_scenes WHERE battlenetAccountId = ? AND warbandSceneId = ?", CONNECTION_ASYNC);
}
LoginDatabaseConnection::LoginDatabaseConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags) : MySQLConnection(connInfo, connectionFlags)
diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h
index e03fd277e02..7b70d063cb3 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.h
+++ b/src/server/database/Database/Implementation/LoginDatabase.h
@@ -176,6 +176,10 @@ enum LoginDatabaseStatements : uint32
LOGIN_DEL_BNET_ITEM_FAVORITE_APPEARANCE,
LOGIN_SEL_BNET_TRANSMOG_ILLUSIONS,
LOGIN_INS_BNET_TRANSMOG_ILLUSIONS,
+ LOGIN_SEL_BNET_WARBAND_SCENES,
+ LOGIN_INS_BNET_WARBAND_SCENE,
+ LOGIN_UPD_BNET_WARBAND_SCENE,
+ LOGIN_DEL_BNET_WARBAND_SCENE,
MAX_LOGINDATABASE_STATEMENTS
};
diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h
index cacc47ea059..f3fc6fa7366 100644
--- a/src/server/game/DataStores/DB2LoadInfo.h
+++ b/src/server/game/DataStores/DB2LoadInfo.h
@@ -6668,6 +6668,34 @@ struct VignetteLoadInfo
static constexpr DB2LoadInfo Instance{ Fields, 13, &VignetteMeta::Instance, HOTFIX_SEL_VIGNETTE };
};
+struct WarbandSceneLoadInfo
+{
+ static constexpr DB2FieldMeta Fields[19] =
+ {
+ { .IsSigned = false, .Type = FT_STRING, .Name = "Name" },
+ { .IsSigned = false, .Type = FT_STRING, .Name = "Description" },
+ { .IsSigned = false, .Type = FT_STRING, .Name = "Source" },
+ { .IsSigned = false, .Type = FT_FLOAT, .Name = "PositionX" },
+ { .IsSigned = false, .Type = FT_FLOAT, .Name = "PositionY" },
+ { .IsSigned = false, .Type = FT_FLOAT, .Name = "PositionZ" },
+ { .IsSigned = false, .Type = FT_FLOAT, .Name = "LookAtX" },
+ { .IsSigned = false, .Type = FT_FLOAT, .Name = "LookAtY" },
+ { .IsSigned = false, .Type = FT_FLOAT, .Name = "LookAtZ" },
+ { .IsSigned = false, .Type = FT_INT, .Name = "ID" },
+ { .IsSigned = false, .Type = FT_INT, .Name = "MapID" },
+ { .IsSigned = false, .Type = FT_FLOAT, .Name = "Fov" },
+ { .IsSigned = true, .Type = FT_INT, .Name = "TimeOfDay" },
+ { .IsSigned = true, .Type = FT_INT, .Name = "Flags" },
+ { .IsSigned = true, .Type = FT_INT, .Name = "SoundAmbienceID" },
+ { .IsSigned = true, .Type = FT_BYTE, .Name = "Quality" },
+ { .IsSigned = true, .Type = FT_INT, .Name = "TextureKit" },
+ { .IsSigned = true, .Type = FT_INT, .Name = "DefaultScenePriority" },
+ { .IsSigned = true, .Type = FT_BYTE, .Name = "SourceType" },
+ };
+
+ static constexpr DB2LoadInfo Instance{ Fields, 19, &WarbandSceneMeta::Instance, HOTFIX_SEL_WARBAND_SCENE };
+};
+
struct WmoAreaTableLoadInfo
{
static constexpr DB2FieldMeta Fields[15] =
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index c32c84e49cf..441123fe052 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -383,6 +383,7 @@ DB2Storage<UnitPowerBarEntry> sUnitPowerBarStore("UnitPowerBar
DB2Storage<VehicleEntry> sVehicleStore("Vehicle.db2", &VehicleLoadInfo::Instance);
DB2Storage<VehicleSeatEntry> sVehicleSeatStore("VehicleSeat.db2", &VehicleSeatLoadInfo::Instance);
DB2Storage<VignetteEntry> sVignetteStore("Vignette.db2", &VignetteLoadInfo::Instance);
+DB2Storage<WarbandSceneEntry> sWarbandSceneStore("WarbandScene.db2", &WarbandSceneLoadInfo::Instance);
DB2Storage<WMOAreaTableEntry> sWMOAreaTableStore("WMOAreaTable.db2", &WmoAreaTableLoadInfo::Instance);
DB2Storage<WorldEffectEntry> sWorldEffectStore("WorldEffect.db2", &WorldEffectLoadInfo::Instance);
DB2Storage<WorldMapOverlayEntry> sWorldMapOverlayStore("WorldMapOverlay.db2", &WorldMapOverlayLoadInfo::Instance);
@@ -1001,6 +1002,7 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul
LOAD_DB2(sVehicleStore);
LOAD_DB2(sVehicleSeatStore);
LOAD_DB2(sVignetteStore);
+ LOAD_DB2(sWarbandSceneStore);
LOAD_DB2(sWMOAreaTableStore);
LOAD_DB2(sWorldEffectStore);
LOAD_DB2(sWorldMapOverlayStore);
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index a9b1f73b614..17bdbc93c54 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -302,6 +302,7 @@ TC_GAME_API extern DB2Storage<UnitPowerBarEntry> sUnitPowerBa
TC_GAME_API extern DB2Storage<VehicleEntry> sVehicleStore;
TC_GAME_API extern DB2Storage<VehicleSeatEntry> sVehicleSeatStore;
TC_GAME_API extern DB2Storage<VignetteEntry> sVignetteStore;
+TC_GAME_API extern DB2Storage<WarbandSceneEntry> sWarbandSceneStore;
TC_GAME_API extern DB2Storage<WorldEffectEntry> sWorldEffectStore;
TC_GAME_API extern DB2Storage<WorldMapOverlayEntry> sWorldMapOverlayStore;
TC_GAME_API extern DB2Storage<WorldStateExpressionEntry> sWorldStateExpressionStore;
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index 846c095fe71..387795998d9 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -4770,6 +4770,27 @@ struct VignetteEntry
bool IsInfiniteAOI() const { return GetFlags().HasFlag(VignetteFlags::InfiniteAOI | VignetteFlags::ZoneInfiniteAOI); }
};
+struct WarbandSceneEntry
+{
+ LocalizedString Name;
+ LocalizedString Description;
+ LocalizedString Source;
+ DBCPosition3D Position;
+ DBCPosition3D LookAt;
+ uint32 ID;
+ uint32 MapID;
+ float Fov;
+ int32 TimeOfDay;
+ int32 Flags;
+ int32 SoundAmbienceID;
+ int8 Quality;
+ int32 TextureKit;
+ int32 DefaultScenePriority;
+ int8 SourceType;
+
+ EnumFlag<WarbandSceneFlags> GetFlags() const { return static_cast<WarbandSceneFlags>(Flags); }
+};
+
struct WMOAreaTableEntry
{
LocalizedString AreaName;
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 01919abb61a..8342b9cbe1b 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -2657,6 +2657,17 @@ enum class VignetteFlags
DEFINE_ENUM_FLAG(VignetteFlags);
+enum class WarbandSceneFlags : uint8
+{
+ DoNotInclude = 0x01,
+ HiddenUntilCollected = 0x02,
+ CannotBeSaved = 0x04,
+ AwardedAutomatically = 0x08,
+ IsDefault = 0x10
+};
+
+DEFINE_ENUM_FLAG(WarbandSceneFlags);
+
enum WorldMapTransformsFlags
{
WORLD_MAP_TRANSFORMS_FLAG_DUNGEON = 0x04
diff --git a/src/server/game/Entities/Player/CollectionMgr.cpp b/src/server/game/Entities/Player/CollectionMgr.cpp
index f5690ac2d59..5f833f7824e 100644
--- a/src/server/game/Entities/Player/CollectionMgr.cpp
+++ b/src/server/game/Entities/Player/CollectionMgr.cpp
@@ -16,10 +16,12 @@
*/
#include "CollectionMgr.h"
+#include "CollectionPackets.h"
#include "DatabaseEnv.h"
#include "DB2Stores.h"
#include "Item.h"
#include "Log.h"
+#include "MapUtils.h"
#include "MiscPackets.h"
#include "ObjectMgr.h"
#include "Player.h"
@@ -31,6 +33,7 @@
namespace
{
MountDefinitionMap FactionSpecificMounts;
+ std::vector<uint32> DefaultWarbandScenes;
}
void CollectionMgr::LoadMountDefinitions()
@@ -70,6 +73,13 @@ void CollectionMgr::LoadMountDefinitions()
TC_LOG_INFO("server.loading", ">> Loaded {} mount definitions in {} ms", FactionSpecificMounts.size(), GetMSTimeDiffToNow(oldMSTime));
}
+void CollectionMgr::LoadWarbandSceneDefinitions()
+{
+ for (WarbandSceneEntry const* warbandScene : sWarbandSceneStore)
+ if (warbandScene->GetFlags().HasFlag(WarbandSceneFlags::AwardedAutomatically))
+ DefaultWarbandScenes.push_back(warbandScene->ID);
+}
+
namespace
{
EnumFlag<ToyFlags> GetToyFlags(bool isFavourite, bool hasFanfare)
@@ -89,14 +99,12 @@ CollectionMgr::CollectionMgr(WorldSession* owner) : _owner(owner), _appearances(
{
}
-CollectionMgr::~CollectionMgr()
-{
-}
+CollectionMgr::~CollectionMgr() = default;
void CollectionMgr::LoadToys()
{
- for (auto const& t : _toys)
- _owner->GetPlayer()->AddToy(t.first, t.second.AsUnderlyingType());
+ for (auto const& [itemId, flags] : _toys)
+ _owner->GetPlayer()->AddToy(itemId, flags.AsUnderlyingType());
}
bool CollectionMgr::AddToy(uint32 itemId, bool isFavourite, bool hasFanfare)
@@ -275,7 +283,7 @@ void CollectionMgr::UpgradeHeirloom(uint32 itemId, int32 castItem)
// Get heirloom offset to update only one part of dynamic field
auto const& heirlooms = player->m_activePlayerData->Heirlooms;
- uint32 offset = uint32(std::distance(heirlooms.begin(), std::find(heirlooms.begin(), heirlooms.end(), int32(itemId))));
+ uint32 offset = uint32(std::ranges::distance(heirlooms.begin(), std::ranges::find(heirlooms, int32(itemId))));
player->SetHeirloomFlags(offset, flags);
itr->second.flags = flags;
@@ -315,7 +323,7 @@ void CollectionMgr::CheckHeirloomUpgrades(Item* item)
if (newItemId)
{
auto const& heirlooms = player->m_activePlayerData->Heirlooms;
- uint32 offset = uint32(std::distance(heirlooms.begin(), std::find(heirlooms.begin(), heirlooms.end(), int32(itr->first))));
+ uint32 offset = uint32(std::ranges::distance(heirlooms.begin(), std::ranges::find(heirlooms, int32(itr->first))));
player->SetHeirloom(offset, newItemId);
player->SetHeirloomFlags(offset, 0);
@@ -337,7 +345,7 @@ void CollectionMgr::CheckHeirloomUpgrades(Item* item)
}
}
- if (std::find(bonusListIDs.begin(), bonusListIDs.end(), int32(itr->second.bonusId)) == bonusListIDs.end())
+ if (!advstd::ranges::contains(bonusListIDs, int32(itr->second.bonusId)))
item->AddBonuses(itr->second.bonusId);
}
}
@@ -439,6 +447,7 @@ void CollectionMgr::SendSingleMountUpdate(std::pair<uint32, MountStatusFlags> mo
player->SendDirectMessage(mountUpdate.Write());
}
+template <std::invocable<uint32> OutputAction>
struct DynamicBitsetBlockOutputIterator
{
using iterator_category = std::output_iterator_tag;
@@ -447,11 +456,11 @@ struct DynamicBitsetBlockOutputIterator
using pointer = void;
using reference = void;
- explicit DynamicBitsetBlockOutputIterator(std::function<void(uint32)>&& action) : _action(std::forward<std::function<void(uint32)>>(action)) { }
+ explicit DynamicBitsetBlockOutputIterator(OutputAction const& action) : _action(&action) { }
DynamicBitsetBlockOutputIterator& operator=(uint32 value)
{
- _action(value);
+ std::invoke(*_action, value);
return *this;
}
@@ -460,7 +469,7 @@ struct DynamicBitsetBlockOutputIterator
DynamicBitsetBlockOutputIterator operator++(int) { return *this; }
private:
- std::function<void(uint32)> _action;
+ OutputAction const* _action;
};
void CollectionMgr::LoadItemAppearances()
@@ -471,8 +480,8 @@ void CollectionMgr::LoadItemAppearances()
owner->AddTransmogBlock(blockValue);
}));
- for (auto itr = _temporaryAppearances.begin(); itr != _temporaryAppearances.end(); ++itr)
- owner->AddConditionalTransmog(itr->first);
+ for (auto const& [itemModifiedAppearanceId, _] : _temporaryAppearances)
+ owner->AddConditionalTransmog(itemModifiedAppearanceId);
}
void CollectionMgr::LoadAccountItemAppearances(PreparedQueryResult knownAppearances, PreparedQueryResult favoriteAppearances)
@@ -498,7 +507,7 @@ void CollectionMgr::LoadAccountItemAppearances(PreparedQueryResult knownAppearan
{
do
{
- _favoriteAppearances[favoriteAppearances->Fetch()[0].GetUInt32()] = FavoriteAppearanceState::Unchanged;
+ _favoriteAppearances[favoriteAppearances->Fetch()[0].GetUInt32()] = CollectionItemState::Unchanged;
} while (favoriteAppearances->NextRow());
}
@@ -531,7 +540,7 @@ void CollectionMgr::LoadAccountItemAppearances(PreparedQueryResult knownAppearan
void CollectionMgr::SaveAccountItemAppearances(LoginDatabaseTransaction trans)
{
uint16 blockIndex = 0;
- boost::to_block_range(*_appearances, DynamicBitsetBlockOutputIterator([this, &blockIndex, trans](uint32 blockValue)
+ boost::to_block_range(*_appearances, DynamicBitsetBlockOutputIterator([this, &blockIndex, trans = trans.get()](uint32 blockValue)
{
if (blockValue) // this table is only appended/bits are set (never cleared) so don't save empty blocks
{
@@ -550,29 +559,30 @@ void CollectionMgr::SaveAccountItemAppearances(LoginDatabaseTransaction trans)
{
switch (itr->second)
{
- case FavoriteAppearanceState::New:
+ case CollectionItemState::New:
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ITEM_FAVORITE_APPEARANCE);
stmt->setUInt32(0, _owner->GetBattlenetAccountId());
stmt->setUInt32(1, itr->first);
trans->Append(stmt);
- itr->second = FavoriteAppearanceState::Unchanged;
+ itr->second = CollectionItemState::Unchanged;
++itr;
break;
- case FavoriteAppearanceState::Removed:
+ case CollectionItemState::Removed:
stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_ITEM_FAVORITE_APPEARANCE);
stmt->setUInt32(0, _owner->GetBattlenetAccountId());
stmt->setUInt32(1, itr->first);
trans->Append(stmt);
itr = _favoriteAppearances.erase(itr);
break;
- case FavoriteAppearanceState::Unchanged:
+ case CollectionItemState::Unchanged:
+ case CollectionItemState::Changed:
++itr;
break;
}
}
}
-uint32 const PlayerClassByArmorSubclass[MAX_ITEM_SUBCLASS_ARMOR] =
+constexpr uint32 PlayerClassByArmorSubclass[MAX_ITEM_SUBCLASS_ARMOR] =
{
CLASSMASK_ALL_PLAYABLE, //ITEM_SUBCLASS_ARMOR_MISCELLANEOUS
(1 << (CLASS_PRIEST - 1)) | (1 << (CLASS_MAGE - 1)) | (1 << (CLASS_WARLOCK - 1)), //ITEM_SUBCLASS_ARMOR_CLOTH
@@ -658,7 +668,7 @@ bool CollectionMgr::IsSetCompleted(uint32 transmogSetId) const
knownPieces[transmogSlot] = (hasAppearance && !isTemporary) ? 1 : 0;
}
- return std::find(knownPieces.begin(), knownPieces.end(), 0) == knownPieces.end();
+ return !advstd::ranges::contains(knownPieces, 0);
}
bool CollectionMgr::CanAddAppearance(ItemModifiedAppearanceEntry const* itemModifiedAppearance) const
@@ -808,12 +818,12 @@ void CollectionMgr::RemoveTemporaryAppearance(Item* item)
std::pair<bool, bool> CollectionMgr::HasItemAppearance(uint32 itemModifiedAppearanceId) const
{
if (itemModifiedAppearanceId < _appearances->size() && _appearances->test(itemModifiedAppearanceId))
- return{ true, false };
+ return { true, false };
- if (_temporaryAppearances.find(itemModifiedAppearanceId) != _temporaryAppearances.end())
- return{ true,true };
+ if (_temporaryAppearances.contains(itemModifiedAppearanceId))
+ return { true, true };
- return{ false,false };
+ return { false, false };
}
std::unordered_set<ObjectGuid> CollectionMgr::GetItemsProvidingTemporaryAppearance(uint32 itemModifiedAppearanceId) const
@@ -844,18 +854,18 @@ void CollectionMgr::SetAppearanceIsFavorite(uint32 itemModifiedAppearanceId, boo
if (apply)
{
if (itr == _favoriteAppearances.end())
- _favoriteAppearances[itemModifiedAppearanceId] = FavoriteAppearanceState::New;
- else if (itr->second == FavoriteAppearanceState::Removed)
- itr->second = FavoriteAppearanceState::Unchanged;
+ _favoriteAppearances[itemModifiedAppearanceId] = CollectionItemState::New;
+ else if (itr->second == CollectionItemState::Removed)
+ itr->second = CollectionItemState::Unchanged;
else
return;
}
else if (itr != _favoriteAppearances.end())
{
- if (itr->second == FavoriteAppearanceState::New)
+ if (itr->second == CollectionItemState::New)
_favoriteAppearances.erase(itemModifiedAppearanceId);
else
- itr->second = FavoriteAppearanceState::Removed;
+ itr->second = CollectionItemState::Removed;
}
else
return;
@@ -873,9 +883,9 @@ void CollectionMgr::SendFavoriteAppearances() const
WorldPackets::Transmogrification::AccountTransmogUpdate accountTransmogUpdate;
accountTransmogUpdate.IsFullUpdate = true;
accountTransmogUpdate.FavoriteAppearances.reserve(_favoriteAppearances.size());
- for (auto itr = _favoriteAppearances.begin(); itr != _favoriteAppearances.end(); ++itr)
- if (itr->second != FavoriteAppearanceState::Removed)
- accountTransmogUpdate.FavoriteAppearances.push_back(itr->first);
+ for (auto [itemModifiedAppearanceId, state] : _favoriteAppearances)
+ if (state != CollectionItemState::Removed)
+ accountTransmogUpdate.FavoriteAppearances.push_back(itemModifiedAppearanceId);
_owner->SendPacket(accountTransmogUpdate.Write());
}
@@ -933,7 +943,7 @@ void CollectionMgr::SaveAccountTransmogIllusions(LoginDatabaseTransaction trans)
{
uint16 blockIndex = 0;
- boost::to_block_range(*_transmogIllusions, DynamicBitsetBlockOutputIterator([this, &blockIndex, trans](uint32 blockValue)
+ boost::to_block_range(*_transmogIllusions, DynamicBitsetBlockOutputIterator([this, &blockIndex, trans = trans.get()](uint32 blockValue)
{
if (blockValue) // this table is only appended/bits are set (never cleared) so don't save empty blocks
{
@@ -970,3 +980,133 @@ bool CollectionMgr::HasTransmogIllusion(uint32 transmogIllusionId) const
{
return transmogIllusionId < _transmogIllusions->size() && _transmogIllusions->test(transmogIllusionId);
}
+
+void CollectionMgr::LoadWarbandScenes()
+{
+ Player* owner = _owner->GetPlayer();
+ for (auto const& [warbandSceneId, _] : _warbandScenes)
+ owner->AddWarbandScenesFlag(warbandSceneId / 32, 1 << warbandSceneId % 32);
+}
+
+void CollectionMgr::LoadAccountWarbandScenes(PreparedQueryResult knownWarbandScenes)
+{
+ if (knownWarbandScenes)
+ {
+ do
+ {
+ Field* fields = knownWarbandScenes->Fetch();
+ uint32 warbandSceneId = fields[0].GetUInt32();
+ if (!sWarbandSceneStore.HasRecord(warbandSceneId))
+ {
+ _warbandScenes[warbandSceneId].State = CollectionItemState::Removed;
+ continue;
+ }
+
+ bool isFavorite = fields[1].GetBool();
+ bool hasFanfare = fields[2].GetBool();
+
+ WarbandSceneCollectionItem& warbandScene = _warbandScenes.try_emplace(warbandSceneId).first->second;
+ if (isFavorite)
+ warbandScene.Flags |= WarbandSceneCollectionFlags::Favorite;
+
+ if (hasFanfare)
+ warbandScene.Flags |= WarbandSceneCollectionFlags::HasFanfare;
+
+ } while (knownWarbandScenes->NextRow());
+ }
+
+ for (uint32 warbandSceneId : DefaultWarbandScenes)
+ if (auto [itr, isNew] = _warbandScenes.try_emplace(warbandSceneId); isNew)
+ itr->second.State = CollectionItemState::New;
+}
+
+void CollectionMgr::SaveAccountWarbandScenes(LoginDatabaseTransaction trans)
+{
+ LoginDatabasePreparedStatement* stmt;
+ for (auto itr = _warbandScenes.begin(); itr != _warbandScenes.end(); )
+ {
+ auto& [warbandSceneId, data] = *itr;
+ switch (data.State)
+ {
+ case CollectionItemState::New:
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_WARBAND_SCENE);
+ stmt->setUInt32(0, _owner->GetBattlenetAccountId());
+ stmt->setUInt32(1, warbandSceneId);
+ stmt->setBool(2, data.Flags.HasFlag(WarbandSceneCollectionFlags::Favorite));
+ stmt->setBool(3, data.Flags.HasFlag(WarbandSceneCollectionFlags::HasFanfare));
+ trans->Append(stmt);
+ data.State = CollectionItemState::Unchanged;
+ break;
+ case CollectionItemState::Changed:
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_WARBAND_SCENE);
+ stmt->setBool(0, data.Flags.HasFlag(WarbandSceneCollectionFlags::Favorite));
+ stmt->setBool(1, data.Flags.HasFlag(WarbandSceneCollectionFlags::HasFanfare));
+ stmt->setUInt32(2, _owner->GetBattlenetAccountId());
+ stmt->setUInt32(3, warbandSceneId);
+ trans->Append(stmt);
+ data.State = CollectionItemState::Unchanged;
+ break;
+ case CollectionItemState::Removed:
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_WARBAND_SCENE);
+ stmt->setUInt32(0, _owner->GetBattlenetAccountId());
+ stmt->setUInt32(1, warbandSceneId);
+ trans->Append(stmt);
+ itr = _warbandScenes.erase(itr);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void CollectionMgr::AddWarbandScene(uint32 warbandSceneId)
+{
+ if (!sWarbandSceneStore.HasRecord(warbandSceneId))
+ return;
+
+ WarbandSceneCollectionItem& warbandScene = _warbandScenes.try_emplace(warbandSceneId).first->second;
+ warbandScene.State = CollectionItemState::New;
+
+ uint32 blockIndex = warbandSceneId / 32;
+ uint32 bitIndex = warbandSceneId % 32;
+ _owner->GetPlayer()->AddWarbandScenesFlag(blockIndex, 1 << bitIndex);
+}
+
+bool CollectionMgr::HasWarbandScene(uint32 warbandSceneId) const
+{
+ return _warbandScenes.contains(warbandSceneId);
+}
+
+void CollectionMgr::SetWarbandSceneIsFavorite(uint32 warbandSceneId, bool apply)
+{
+ WarbandSceneCollectionItem* warbandScene = Trinity::Containers::MapGetValuePtr(_warbandScenes, warbandSceneId);
+ if (!warbandScene)
+ return;
+
+ if (apply)
+ warbandScene->Flags |= WarbandSceneCollectionFlags::Favorite;
+ else
+ warbandScene->Flags &= ~WarbandSceneCollectionFlags::Favorite;
+
+ if (warbandScene->State == CollectionItemState::Unchanged)
+ warbandScene->State = CollectionItemState::Changed;
+}
+
+void CollectionMgr::SendWarbandSceneCollectionData() const
+{
+ WorldPackets::Collections::AccountItemCollectionData accountItemCollection;
+ accountItemCollection.Type = ItemCollectionType::WarbandScene;
+
+ for (auto const& [warbandSceneId, data] : _warbandScenes)
+ {
+ if (data.State == CollectionItemState::Removed)
+ continue;
+
+ WorldPackets::Collections::ItemCollectionItemData& item = accountItemCollection.Items.emplace_back();
+ item.ID = warbandSceneId;
+ item.Type = ItemCollectionType::WarbandScene;
+ item.Flags = data.Flags.AsUnderlyingType();
+ }
+
+ _owner->SendPacket(accountItemCollection.Write());
+}
diff --git a/src/server/game/Entities/Player/CollectionMgr.h b/src/server/game/Entities/Player/CollectionMgr.h
index 5e46afd8fd8..9b17eb0c8bf 100644
--- a/src/server/game/Entities/Player/CollectionMgr.h
+++ b/src/server/game/Entities/Player/CollectionMgr.h
@@ -15,8 +15,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef CollectionMgr_h__
-#define CollectionMgr_h__
+#ifndef TRINITYCORE_COLLECTION_MGR_H
+#define TRINITYCORE_COLLECTION_MGR_H
#include "Define.h"
#include "DatabaseEnvFwd.h"
@@ -31,6 +31,14 @@ class Item;
class WorldSession;
struct ItemModifiedAppearanceEntry;
+enum class CollectionItemState : uint8
+{
+ Unchanged,
+ New,
+ Changed,
+ Removed
+};
+
enum HeirloomPlayerFlags
{
HEIRLOOM_FLAG_NONE = 0x00,
@@ -79,13 +87,35 @@ enum MountStatusFlags : uint8
typedef std::map<uint32, MountStatusFlags> MountContainer;
typedef std::unordered_map<uint32, uint32> MountDefinitionMap;
+enum class WarbandSceneCollectionFlags : uint8
+{
+ None = 0x00,
+ Favorite = 0x01,
+ HasFanfare = 0x02
+};
+
+DEFINE_ENUM_FLAG(WarbandSceneCollectionFlags);
+
+struct WarbandSceneCollectionItem
+{
+ EnumFlag<WarbandSceneCollectionFlags> Flags = WarbandSceneCollectionFlags::None;
+ CollectionItemState State = CollectionItemState::Unchanged;
+};
+
+using WarbandSceneCollectionContainer = std::map<uint32, WarbandSceneCollectionItem>;
+
class TC_GAME_API CollectionMgr
{
public:
explicit CollectionMgr(WorldSession* owner);
+ CollectionMgr(CollectionMgr const&) = delete;
+ CollectionMgr(CollectionMgr&&) = delete;
+ CollectionMgr& operator=(CollectionMgr const&) = delete;
+ CollectionMgr& operator=(CollectionMgr&&) = delete;
~CollectionMgr();
static void LoadMountDefinitions();
+ static void LoadWarbandSceneDefinitions();
// Account-wide toys
void LoadToys();
@@ -96,7 +126,7 @@ public:
bool AddToy(uint32 itemId, bool isFavourite, bool hasFanfare);
bool UpdateAccountToys(uint32 itemId, bool isFavourite, bool hasFanfare);
- bool HasToy(uint32 itemId) const { return _toys.count(itemId) > 0; }
+ bool HasToy(uint32 itemId) const { return _toys.contains(itemId); }
ToyBoxContainer const& GetAccountToys() const { return _toys; }
@@ -139,6 +169,9 @@ public:
// returns ItemAppearance::ID, not ItemModifiedAppearance::ID
std::unordered_set<uint32> GetAppearanceIds() const;
+ void SetAppearanceIsFavorite(uint32 itemModifiedAppearanceId, bool apply);
+ void SendFavoriteAppearances() const;
+
// Illusions
void LoadTransmogIllusions();
void LoadAccountTransmogIllusions(PreparedQueryResult knownTransmogIllusions);
@@ -146,15 +179,16 @@ public:
void AddTransmogIllusion(uint32 transmogIllusionId);
bool HasTransmogIllusion(uint32 transmogIllusionId) const;
- enum class FavoriteAppearanceState
- {
- New,
- Removed,
- Unchanged
- };
+ // Warband Scenes
+ void LoadWarbandScenes();
+ void LoadAccountWarbandScenes(PreparedQueryResult knownWarbandScenes);
+ void SaveAccountWarbandScenes(LoginDatabaseTransaction trans);
+ void AddWarbandScene(uint32 warbandSceneId);
+ bool HasWarbandScene(uint32 warbandSceneId) const;
+ void SetWarbandSceneIsFavorite(uint32 warbandSceneId, bool apply);
+ WarbandSceneCollectionContainer const& GetWarbandScenes() const { return _warbandScenes; }
- void SetAppearanceIsFavorite(uint32 itemModifiedAppearanceId, bool apply);
- void SendFavoriteAppearances() const;
+ void SendWarbandSceneCollectionData() const;
private:
bool CanAddAppearance(ItemModifiedAppearanceEntry const* itemModifiedAppearance) const;
@@ -168,8 +202,9 @@ private:
MountContainer _mounts;
std::unique_ptr<boost::dynamic_bitset<uint32>> _appearances;
std::unordered_map<uint32, std::unordered_set<ObjectGuid>> _temporaryAppearances;
- std::unordered_map<uint32, FavoriteAppearanceState> _favoriteAppearances;
+ std::unordered_map<uint32, CollectionItemState> _favoriteAppearances;
std::unique_ptr<boost::dynamic_bitset<uint32>> _transmogIllusions;
+ WarbandSceneCollectionContainer _warbandScenes;
};
-#endif // CollectionMgr_h__
+#endif // TRINITYCORE_COLLECTION_MGR_H
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 96dd0fbc8fd..ee60c0324f1 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -18472,6 +18472,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
GetSession()->GetCollectionMgr()->LoadMounts();
GetSession()->GetCollectionMgr()->LoadItemAppearances();
GetSession()->GetCollectionMgr()->LoadTransmogIllusions();
+ GetSession()->GetCollectionMgr()->LoadWarbandScenes();
LearnSpecializationSpells();
@@ -20644,6 +20645,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
GetSession()->GetCollectionMgr()->SaveAccountMounts(loginTransaction);
GetSession()->GetCollectionMgr()->SaveAccountItemAppearances(loginTransaction);
GetSession()->GetCollectionMgr()->SaveAccountTransmogIllusions(loginTransaction);
+ GetSession()->GetCollectionMgr()->SaveAccountWarbandScenes(loginTransaction);
Battlenet::RealmHandle currentRealmId = sRealmList->GetCurrentRealmId();
@@ -24740,6 +24742,12 @@ void Player::SendInitialPacketsBeforeAddToMap()
GetSession()->GetCollectionMgr()->SendFavoriteAppearances();
+ // SMSG_ACCOUNT_WARBAND_SCENE_UPDATE
+ WorldPackets::Misc::AccountWarbandSceneUpdate warbandSceneUpdate;
+ warbandSceneUpdate.IsFullUpdate = true;
+ warbandSceneUpdate.WarbandScenes = &GetSession()->GetCollectionMgr()->GetWarbandScenes();
+ SendDirectMessage(warbandSceneUpdate.Write());
+
WorldPackets::Character::InitialSetup initialSetup;
initialSetup.ServerExpansionLevel = sWorld->getIntConfig(CONFIG_EXPANSION);
SendDirectMessage(initialSetup.Write());
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 4217aa81601..36bf7c764eb 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2909,6 +2909,9 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
void AddIllusionBlock(uint32 blockValue) { AddDynamicUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::TransmogIllusions)) = blockValue; }
void AddIllusionFlag(uint32 slot, uint32 flag) { SetUpdateFieldFlagValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::TransmogIllusions, slot), flag); }
+ void AddWarbandScenesBlock(uint32 blockValue) { AddDynamicUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::WarbandScenes)) = blockValue; }
+ void AddWarbandScenesFlag(uint32 slot, uint32 flag) { SetUpdateFieldFlagValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::WarbandScenes, slot), flag); }
+
void AddSelfResSpell(int32 spellId) { AddDynamicUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::SelfResSpells)) = spellId; }
void RemoveSelfResSpell(int32 spellId)
{
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 72037caa62f..9a5ba64b353 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -470,6 +470,9 @@ void WorldSession::HandleCharEnum(CharacterDatabaseQueryHolder const& holder)
}
SendPacket(charEnum.Write());
+
+ if (!charEnum.IsDeletedCharacters)
+ _collectionMgr->SendWarbandSceneCollectionData();
}
void WorldSession::HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters& /*enumCharacters*/)
diff --git a/src/server/game/Handlers/CollectionsHandler.cpp b/src/server/game/Handlers/CollectionsHandler.cpp
index 0302ad4b354..ea32d5f26e8 100644
--- a/src/server/game/Handlers/CollectionsHandler.cpp
+++ b/src/server/game/Handlers/CollectionsHandler.cpp
@@ -36,7 +36,9 @@ void WorldSession::HandleCollectionItemSetFavorite(WorldPackets::Collections::Co
break;
}
case ItemCollectionType::TransmogSetFavorite:
+ break;
case ItemCollectionType::WarbandScene:
+ GetCollectionMgr()->SetWarbandSceneIsFavorite(collectionItemSetFavorite.ID, collectionItemSetFavorite.IsFavorite);
break;
default:
break;
diff --git a/src/server/game/Server/Packets/CollectionPackets.cpp b/src/server/game/Server/Packets/CollectionPackets.cpp
index 5669d50a0c6..2f82f083376 100644
--- a/src/server/game/Server/Packets/CollectionPackets.cpp
+++ b/src/server/game/Server/Packets/CollectionPackets.cpp
@@ -18,9 +18,37 @@
#include "CollectionPackets.h"
#include "PacketUtilities.h"
-void WorldPackets::Collections::CollectionItemSetFavorite::Read()
+namespace WorldPackets::Collections
+{
+void CollectionItemSetFavorite::Read()
{
_worldPacket >> As<uint8>(Type);
_worldPacket >> ID;
_worldPacket >> Bits<1>(IsFavorite);
}
+
+ByteBuffer& operator<<(ByteBuffer& data, ItemCollectionItemData const& item)
+{
+ data << int32(item.ID);
+ data << uint8(item.Type);
+ data << int64(item.Unknown1110);
+ data << int32(item.Flags);
+
+ return data;
+}
+
+WorldPacket const* AccountItemCollectionData::Write()
+{
+ _worldPacket << uint32(Unknown1110_1);
+ _worldPacket << uint8(Type);
+ _worldPacket << uint32(Items.size());
+
+ for (ItemCollectionItemData const& item : Items)
+ _worldPacket << item;
+
+ _worldPacket << Bits<1>(Unknown1110_2);
+ _worldPacket.FlushBits();
+
+ return &_worldPacket;
+}
+}
diff --git a/src/server/game/Server/Packets/CollectionPackets.h b/src/server/game/Server/Packets/CollectionPackets.h
index c6a972d5bae..f9656623c27 100644
--- a/src/server/game/Server/Packets/CollectionPackets.h
+++ b/src/server/game/Server/Packets/CollectionPackets.h
@@ -36,6 +36,27 @@ namespace WorldPackets
uint32 ID = 0;
bool IsFavorite = false;
};
+
+ struct ItemCollectionItemData
+ {
+ int32 ID = 0;
+ ItemCollectionType Type = ItemCollectionType::None;
+ int64 Unknown1110 = 0;
+ int32 Flags = 0;
+ };
+
+ class AccountItemCollectionData final : public ServerPacket
+ {
+ public:
+ AccountItemCollectionData() : ServerPacket(SMSG_ACCOUNT_ITEM_COLLECTION_DATA) { }
+
+ WorldPacket const* Write() override;
+
+ uint32 Unknown1110_1 = 0;
+ ItemCollectionType Type = ItemCollectionType::None;
+ bool Unknown1110_2 = false;
+ std::vector<ItemCollectionItemData> Items;
+ };
}
}
diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp
index 310a118b316..9e75e365f69 100644
--- a/src/server/game/Server/Packets/MiscPackets.cpp
+++ b/src/server/game/Server/Packets/MiscPackets.cpp
@@ -816,3 +816,24 @@ WorldPacket const* WorldPackets::Misc::DisplayToast::Write()
return &_worldPacket;
}
+
+WorldPacket const* WorldPackets::Misc::AccountWarbandSceneUpdate::Write()
+{
+ _worldPacket << Bits<1>(IsFullUpdate);
+ _worldPacket << uint32(WarbandScenes->size());
+ _worldPacket << uint32(WarbandScenes->size());
+ _worldPacket << uint32(WarbandScenes->size());
+
+ for (auto [warbandSceneId, _] : *WarbandScenes)
+ _worldPacket << uint32(warbandSceneId);
+
+ for (auto [_, data] : *WarbandScenes)
+ _worldPacket << Bits<1>(data.Flags.HasFlag(WarbandSceneCollectionFlags::Favorite));
+
+ for (auto [_, data] : *WarbandScenes)
+ _worldPacket << Bits<1>(data.Flags.HasFlag(WarbandSceneCollectionFlags::HasFanfare));
+
+ _worldPacket.FlushBits();
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h
index 4cf942cf89f..5855ceeb233 100644
--- a/src/server/game/Server/Packets/MiscPackets.h
+++ b/src/server/game/Server/Packets/MiscPackets.h
@@ -1010,6 +1010,17 @@ namespace WorldPackets
::Gender Gender = GENDER_NONE;
uint32 CurrencyID = 0;
};
+
+ class AccountWarbandSceneUpdate final : public ServerPacket
+ {
+ public:
+ AccountWarbandSceneUpdate() : ServerPacket(SMSG_ACCOUNT_WARBAND_SCENE_UPDATE) { }
+
+ WorldPacket const* Write() override;
+
+ bool IsFullUpdate = false;
+ WarbandSceneCollectionContainer const* WarbandScenes = nullptr;
+ };
}
}
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 538cb0a0ee8..bf1576592f9 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -1048,7 +1048,7 @@ void OpcodeTable::InitializeServerOpcodes()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_CRITERIA_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_DATA_TIMES, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_EXPORT_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_ITEM_COLLECTION_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_ITEM_COLLECTION_DATA, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_HEIRLOOM_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_MOUNT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_MOUNT_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
@@ -1060,7 +1060,7 @@ void OpcodeTable::InitializeServerOpcodes()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_TOY_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_TRANSMOG_SET_FAVORITES_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_TRANSMOG_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_WARBAND_SCENE_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_WARBAND_SCENE_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_DELETED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTIVATE_ESSENCE_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM);
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 01591b0b3c8..2d095c59ac4 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -1100,6 +1100,7 @@ public:
ITEM_APPEARANCES,
ITEM_FAVORITE_APPEARANCES,
TRANSMOG_ILLUSIONS,
+ WARBAND_SCENES,
MAX_QUERIES
};
@@ -1147,6 +1148,10 @@ public:
stmt->setUInt32(0, battlenetAccountId);
ok = SetPreparedQuery(TRANSMOG_ILLUSIONS, stmt) && ok;
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_WARBAND_SCENES);
+ stmt->setUInt32(0, battlenetAccountId);
+ ok = SetPreparedQuery(WARBAND_SCENES, stmt) && ok;
+
return ok;
}
};
@@ -1199,6 +1204,7 @@ void WorldSession::InitializeSessionCallback(LoginDatabaseQueryHolder const& hol
_collectionMgr->LoadAccountMounts(holder.GetPreparedResult(AccountInfoQueryHolder::MOUNTS));
_collectionMgr->LoadAccountItemAppearances(holder.GetPreparedResult(AccountInfoQueryHolder::ITEM_APPEARANCES), holder.GetPreparedResult(AccountInfoQueryHolder::ITEM_FAVORITE_APPEARANCES));
_collectionMgr->LoadAccountTransmogIllusions(holder.GetPreparedResult(AccountInfoQueryHolder::TRANSMOG_ILLUSIONS));
+ _collectionMgr->LoadAccountWarbandScenes(holder.GetPreparedResult(AccountInfoQueryHolder::WARBAND_SCENES));
if (!m_inQueue)
SendAuthResponse(ERROR_OK, false);
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index db187dd3adb..fcb41cb16dd 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -441,6 +441,7 @@ class TC_GAME_API Spell
void EffectChangeActiveCombatTraitConfig();
void EffectTeleportGraveyard();
void EffectUpdateInteractions();
+ void EffectLearnWarbandScene();
typedef std::unordered_set<Aura*> UsedSpellMods;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 7bcb7d27f65..e01435dc9e8 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -429,7 +429,7 @@ NonDefaultConstructible<SpellEffectHandlerFn> SpellEffectHandlers[TOTAL_SPELL_EF
&Spell::EffectNULL, //338 SPELL_EFFECT_338
&Spell::EffectNULL, //339 SPELL_EFFECT_UI_ACTION
&Spell::EffectNULL, //340 SPELL_EFFECT_340
- &Spell::EffectNULL, //341 SPELL_EFFECT_LEARN_WARBAND_SCENE
+ &Spell::EffectLearnWarbandScene, //341 SPELL_EFFECT_LEARN_WARBAND_SCENE
};
void Spell::EffectNULL()
@@ -6177,3 +6177,15 @@ void Spell::EffectUpdateInteractions()
target->UpdateVisibleObjectInteractions(true, false, true, true);
}
+
+void Spell::EffectLearnWarbandScene()
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
+ return;
+
+ Player* target = Object::ToPlayer(unitTarget);
+ if (!target)
+ return;
+
+ target->GetSession()->GetCollectionMgr()->AddWarbandScene(effectInfo->MiscValue);
+}
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 4c5462b46af..920386c1fd5 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -2365,6 +2365,9 @@ bool World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading mount definitions...");
CollectionMgr::LoadMountDefinitions();
+ TC_LOG_INFO("server.loading", "Loading warband scene definitions...");
+ CollectionMgr::LoadWarbandSceneDefinitions();
+
TC_LOG_INFO("server.loading", "Loading GM bugs...");
sSupportMgr->LoadBugTickets();