diff options
9 files changed, 153 insertions, 2 deletions
diff --git a/sql/updates/world/master/2022_07_03_00_world.sql b/sql/updates/world/master/2022_07_03_00_world.sql new file mode 100644 index 00000000000..c25cda30004 --- /dev/null +++ b/sql/updates/world/master/2022_07_03_00_world.sql @@ -0,0 +1,18 @@ +-- +-- Table structure for table `creature_summoned_data` +-- +DROP TABLE IF EXISTS `creature_summoned_data`; +CREATE TABLE `creature_summoned_data` ( + `CreatureID` int unsigned NOT NULL, + `CreatureIDVisibleToSummoner` int DEFAULT NULL, + `GroundMountDisplayID` int unsigned DEFAULT NULL, + `FlyingMountDisplayID` int unsigned DEFAULT NULL, + PRIMARY KEY (`CreatureID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `creature_summoned_data` +-- +INSERT INTO `creature_summoned_data` VALUES +(90382,90240,54563,46930), +(91911,91913,59339,NULL); diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index e01d020120c..d11577da3bd 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -20,6 +20,7 @@ #include "Common.h" #include "DBCEnums.h" +#include "Optional.h" #include "SharedDefines.h" #include "SpawnData.h" #include "UnitDefines.h" @@ -605,6 +606,13 @@ struct CreatureModelInfo bool is_trigger; }; +struct CreatureSummonedData +{ + Optional<uint32> CreatureIDVisibleToSummoner; + Optional<uint32> GroundMountDisplayID; + Optional<uint32> FlyingMountDisplayID; +}; + enum InhabitTypeValues { INHABIT_GROUND = 1, diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index a389ff5f8fc..249edcf3e15 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.cpp +++ b/src/server/game/Entities/Creature/TemporarySummon.cpp @@ -25,6 +25,7 @@ #include "Log.h" #include "Map.h" #include "ObjectAccessor.h" +#include "ObjectMgr.h" #include "Pet.h" #include "Player.h" #include "SmoothPhasing.h" @@ -194,6 +195,19 @@ void TempSummon::InitStats(uint32 duration) if (owner->GetTypeId() == TYPEID_PLAYER) m_ControlledByPlayer = true; + if (owner && owner->IsPlayer()) + { + if (CreatureSummonedData const* summonedData = sObjectMgr->GetCreatureSummonedData(GetEntry())) + { + m_creatureIdVisibleToSummoner = summonedData->CreatureIDVisibleToSummoner; + if (summonedData->CreatureIDVisibleToSummoner) + { + CreatureTemplate const* creatureTemplateVisibleToSummoner = ASSERT_NOTNULL(sObjectMgr->GetCreatureTemplate(*summonedData->CreatureIDVisibleToSummoner)); + m_displayIdVisibleToSummoner = ObjectMgr::ChooseDisplayId(creatureTemplateVisibleToSummoner, nullptr)->CreatureDisplayID; + } + } + } + if (!m_Properties) return; diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h index d9501cce342..27dfea28506 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.h +++ b/src/server/game/Entities/Creature/TemporarySummon.h @@ -61,6 +61,8 @@ class TC_GAME_API TempSummon : public Creature ObjectGuid GetSummonerGUID() const { return m_summonerGUID; } TempSummonType GetSummonType() const { return m_type; } uint32 GetTimer() const { return m_timer; } + Optional<uint32> GetCreatureIdVisibleToSummoner() const { return m_creatureIdVisibleToSummoner; } + Optional<uint32> GetDisplayIdVisibleToSummoner() const { return m_displayIdVisibleToSummoner; } bool CanFollowOwner() const { return m_canFollowOwner; } void SetCanFollowOwner(bool can) { m_canFollowOwner = can; } @@ -72,6 +74,8 @@ class TC_GAME_API TempSummon : public Creature uint32 m_timer; uint32 m_lifetime; ObjectGuid m_summonerGUID; + Optional<uint32> m_creatureIdVisibleToSummoner; + Optional<uint32> m_displayIdVisibleToSummoner; bool m_canFollowOwner; }; diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.cpp b/src/server/game/Entities/Object/Updates/UpdateFields.cpp index 70e228847b4..c3146b13bdc 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateFields.cpp @@ -37,7 +37,7 @@ namespace UF { void ObjectData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const { - data << int32(EntryID); + data << int32(ViewerDependentValue<EntryIDTag>::GetValue(this, owner, receiver)); data << uint32(ViewerDependentValue<DynamicFlagsTag>::GetValue(this, owner, receiver)); data << float(Scale); } @@ -56,7 +56,7 @@ void ObjectData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ign { if (changesMask[1]) { - data << int32(EntryID); + data << int32(ViewerDependentValue<EntryIDTag>::GetValue(this, owner, receiver)); } if (changesMask[2]) { diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.h b/src/server/game/Entities/Object/Updates/UpdateFields.h index a4fcd0b65dd..5beb9c4b93a 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.h +++ b/src/server/game/Entities/Object/Updates/UpdateFields.h @@ -47,6 +47,7 @@ namespace UF struct ObjectData : public IsUpdateFieldStructureTag, public HasChangesMask<4> { UpdateField<int32, 0, 1> EntryID; + struct EntryIDTag : ViewerDependentValueTag<int32> {}; UpdateField<uint32, 0, 2> DynamicFlags; struct DynamicFlagsTag : ViewerDependentValueTag<uint32> {}; UpdateField<float, 0, 3> Scale; diff --git a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h index 564b31a9b86..028fdd91a26 100644 --- a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h +++ b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h @@ -26,6 +26,7 @@ #include "Player.h" #include "SpellInfo.h" #include "SpellMgr.h" +#include "TemporarySummon.h" #include "World.h" #include "WorldSession.h" @@ -37,6 +38,25 @@ class ViewerDependentValue }; template<> +class ViewerDependentValue<UF::ObjectData::EntryIDTag> +{ +public: + using value_type = UF::ObjectData::EntryIDTag::value_type; + + static value_type GetValue(UF::ObjectData const* objectData, Object const* object, Player const* receiver) + { + value_type entryId = objectData->EntryID; + + if (Unit const* unit = object->ToUnit()) + if (TempSummon const* summon = unit->ToTempSummon()) + if (summon->GetSummonerGUID() == receiver->GetGUID() && summon->GetCreatureIdVisibleToSummoner()) + entryId = *summon->GetCreatureIdVisibleToSummoner(); + + return entryId; + } +}; + +template<> class ViewerDependentValue<UF::ObjectData::DynamicFlagsTag> { public: @@ -121,6 +141,18 @@ public: { CreatureTemplate const* cinfo = unit->ToCreature()->GetCreatureTemplate(); + if (TempSummon const* summon = unit->ToTempSummon()) + { + if (summon->GetSummonerGUID() == receiver->GetGUID()) + { + if (summon->GetCreatureIdVisibleToSummoner()) + cinfo = sObjectMgr->GetCreatureTemplate(*summon->GetCreatureIdVisibleToSummoner()); + + if (summon->GetDisplayIdVisibleToSummoner()) + displayId = *summon->GetDisplayIdVisibleToSummoner(); + } + } + // this also applies for transform auras if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(unit->GetTransformSpell(), unit->GetMap()->GetDifficultyID())) { diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index de8e1092919..cae5700ef64 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -391,6 +391,8 @@ void ObjectMgr::LoadCreatureTemplates() // We load the creature models after loading but before checking LoadCreatureTemplateModels(); + LoadCreatureSummonedData(); + // Checking needs to be done after loading because of the difficulty self referencing for (auto const& ctPair : _creatureTemplateStore) CheckCreatureTemplate(&ctPair.second); @@ -642,6 +644,70 @@ void ObjectMgr::LoadCreatureTemplateModels() TC_LOG_INFO("server.loading", ">> Loaded %u creature template models in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadCreatureSummonedData() +{ + uint32 oldMSTime = getMSTime(); + + // 0 1 2 3 + QueryResult result = WorldDatabase.Query("SELECT CreatureID, CreatureIDVisibleToSummoner, GroundMountDisplayID, FlyingMountDisplayID FROM creature_summoned_data"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 creature summoned data definitions. DB table `creature_summoned_data` is empty."); + return; + } + + do + { + Field* fields = result->Fetch(); + + uint32 creatureId = fields[0].GetUInt32(); + if (!GetCreatureTemplate(creatureId)) + { + TC_LOG_ERROR("sql.sql", "Table `creature_summoned_data` references non-existing creature %u, skipped", creatureId); + continue; + } + + CreatureSummonedData& summonedData = _creatureSummonedDataStore[creatureId]; + + if (!fields[1].IsNull()) + { + summonedData.CreatureIDVisibleToSummoner = fields[1].GetUInt32(); + if (!GetCreatureTemplate(*summonedData.CreatureIDVisibleToSummoner)) + { + TC_LOG_ERROR("sql.sql", "Table `creature_summoned_data` references non-existing creature %u in CreatureIDVisibleToSummoner for creature %u, set to 0", + *summonedData.CreatureIDVisibleToSummoner, creatureId); + summonedData.CreatureIDVisibleToSummoner.reset(); + } + } + + if (!fields[2].IsNull()) + { + summonedData.GroundMountDisplayID = fields[2].GetUInt32(); + if (!sCreatureDisplayInfoStore.LookupEntry(*summonedData.GroundMountDisplayID)) + { + TC_LOG_ERROR("sql.sql", "Table `creature_summoned_data` references non-existing display id %u in GroundMountDisplayID for creature %u, set to 0", + *summonedData.GroundMountDisplayID, creatureId); + summonedData.CreatureIDVisibleToSummoner.reset(); + } + } + + if (!fields[3].IsNull()) + { + summonedData.FlyingMountDisplayID = fields[3].GetUInt32(); + if (!sCreatureDisplayInfoStore.LookupEntry(*summonedData.FlyingMountDisplayID)) + { + TC_LOG_ERROR("sql.sql", "Table `creature_summoned_data` references non-existing display id %u in FlyingMountDisplayID for creature %u, set to 0", + *summonedData.FlyingMountDisplayID, creatureId); + summonedData.GroundMountDisplayID.reset(); + } + } + + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " creature summoned data definitions in %u ms", _creatureSummonedDataStore.size(), GetMSTimeDiffToNow(oldMSTime)); +} + void ObjectMgr::LoadCreatureTemplateAddons() { uint32 oldMSTime = getMSTime(); @@ -1616,6 +1682,11 @@ CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelId) const return nullptr; } +CreatureSummonedData const* ObjectMgr::GetCreatureSummonedData(uint32 entryId) const +{ + return Trinity::Containers::MapGetValuePtr(_creatureSummonedDataStore, entryId); +} + CreatureModel const* ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data /*= nullptr*/) { // Load creature model (display id) diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 9a93903ebc3..047002d74a0 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1140,6 +1140,7 @@ class TC_GAME_API ObjectMgr CreatureTemplateContainer const& GetCreatureTemplates() const { return _creatureTemplateStore; } CreatureModelInfo const* GetCreatureModelInfo(uint32 modelId) const; CreatureModelInfo const* GetCreatureModelRandomGender(CreatureModel* model, CreatureTemplate const* creatureTemplate) const; + CreatureSummonedData const* GetCreatureSummonedData(uint32 entryId) const; static CreatureModel const* ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data = nullptr); static void ChooseCreatureFlags(CreatureTemplate const* cInfo, uint64* npcFlags, uint32* unitFlags, uint32* unitFlags2, uint32* unitFlags3, uint32* dynamicFlags, CreatureData const* data = nullptr); EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id) const; @@ -1318,6 +1319,7 @@ class TC_GAME_API ObjectMgr void LoadCreatureTemplateResistances(); void LoadCreatureTemplateSpells(); void LoadCreatureTemplateModels(); + void LoadCreatureSummonedData(); void LoadCreatureScalingData(); void CheckCreatureTemplate(CreatureTemplate const* cInfo); void CheckCreatureMovement(char const* table, uint64 id, CreatureMovementData& creatureMovement); @@ -1908,6 +1910,7 @@ class TC_GAME_API ObjectMgr CreatureDataContainer _creatureDataStore; CreatureTemplateContainer _creatureTemplateStore; CreatureModelContainer _creatureModelStore; + std::unordered_map<uint32, CreatureSummonedData> _creatureSummonedDataStore; CreatureAddonContainer _creatureAddonStore; CreatureTemplateAddonContainer _creatureTemplateAddonStore; std::unordered_map<ObjectGuid::LowType, CreatureMovementData> _creatureMovementOverrides; |