diff options
Diffstat (limited to 'src/server/game')
52 files changed, 1498 insertions, 719 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 48a74a3cd79..83e5d00ec63 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -34,6 +34,7 @@ #include "MotionMaster.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "Random.h" #include "SmartAI.h" #include "SpellAuras.h" @@ -1246,7 +1247,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - (*itr)->SetInPhase(e.action.ingamePhaseId.id, true, e.action.ingamePhaseId.apply == 1); + { + if (e.action.ingamePhaseId.apply == 1) + PhasingHandler::AddPhase(*itr, e.action.ingamePhaseId.id, true); + else + PhasingHandler::RemovePhase(*itr, e.action.ingamePhaseId.id, true); + } delete targets; break; @@ -1258,11 +1264,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!targets) break; - std::set<uint32> phases = sDB2Manager.GetPhasesForGroup(e.action.ingamePhaseGroup.groupId); - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - for (auto phase : phases) - (*itr)->SetInPhase(phase, true, e.action.ingamePhaseGroup.apply == 1); + { + if (e.action.ingamePhaseGroup.apply == 1) + PhasingHandler::AddPhaseGroup(*itr, e.action.ingamePhaseGroup.groupId, true); + else + PhasingHandler::RemovePhaseGroup(*itr, e.action.ingamePhaseGroup.groupId, true); + } delete targets; break; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index a2096248851..f6d0ad7b443 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -1374,7 +1374,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) return false; } - if (sDB2Manager.GetPhasesForGroup(phaseGroup).empty()) + if (!sDB2Manager.GetPhasesForGroup(phaseGroup)) { TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid phase group id %u for creature " SI64FMTD ", skipped", phaseGroup, e.entryOrGuid); return false; diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index e7aacf6c159..8ef212e6d85 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -1097,7 +1097,7 @@ LocaleConstant ChatHandler::GetSessionDbcLocale() const return m_session->GetSessionDbcLocale(); } -int ChatHandler::GetSessionDbLocaleIndex() const +LocaleConstant ChatHandler::GetSessionDbLocaleIndex() const { return m_session->GetSessionDbLocaleIndex(); } @@ -1183,7 +1183,7 @@ LocaleConstant CliHandler::GetSessionDbcLocale() const return sWorld->GetDefaultDbcLocale(); } -int CliHandler::GetSessionDbLocaleIndex() const +LocaleConstant CliHandler::GetSessionDbLocaleIndex() const { return sObjectMgr->GetDBCLocaleIndex(); } diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index f7c27bfd90d..9e4b6e35702 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -101,7 +101,7 @@ class TC_GAME_API ChatHandler virtual std::string GetNameLink() const; virtual bool needReportToTarget(Player* chr) const; virtual LocaleConstant GetSessionDbcLocale() const; - virtual int GetSessionDbLocaleIndex() const; + virtual LocaleConstant GetSessionDbLocaleIndex() const; bool HasLowerSecurity(Player* target, ObjectGuid guid, bool strong = false); bool HasLowerSecurityAccount(WorldSession* target, uint32 account, bool strong = false); @@ -166,7 +166,7 @@ class TC_GAME_API CliHandler : public ChatHandler std::string GetNameLink() const override; bool needReportToTarget(Player* chr) const override; LocaleConstant GetSessionDbcLocale() const override; - int GetSessionDbLocaleIndex() const override; + LocaleConstant GetSessionDbLocaleIndex() const override; private: void* m_callbackArg; diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 8598b44915d..50726b91cad 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -30,6 +30,7 @@ #include "LootMgr.h" #include "Map.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "Pet.h" #include "ReputationMgr.h" @@ -413,7 +414,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const } case CONDITION_PHASEID: { - condMeets = object->IsInPhase(ConditionValue1); + condMeets = object->GetPhaseShift().HasPhase(ConditionValue1); break; } case CONDITION_TITLE: @@ -454,7 +455,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const } case CONDITION_TERRAIN_SWAP: { - condMeets = object->IsInTerrainSwap(ConditionValue1); + condMeets = object->GetPhaseShift().HasVisibleMapId(ConditionValue1); break; } case CONDITION_STAND_STATE: @@ -1066,17 +1067,7 @@ void ConditionMgr::LoadConditions(bool isReload) sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists(); - TC_LOG_INFO("misc", "Re-Loading `terrain_phase_info` Table for Conditions!"); - sObjectMgr->LoadTerrainPhaseInfo(); - - TC_LOG_INFO("misc", "Re-Loading `terrain_swap_defaults` Table for Conditions!"); - sObjectMgr->LoadTerrainSwapDefaults(); - - TC_LOG_INFO("misc", "Re-Loading `terrain_worldmap` Table for Conditions!"); - sObjectMgr->LoadTerrainWorldMaps(); - - TC_LOG_INFO("misc", "Re-Loading `phase_area` Table for Conditions!"); - sObjectMgr->LoadAreaPhases(); + sObjectMgr->UnloadPhaseConditions(); } QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, " @@ -1464,28 +1455,33 @@ bool ConditionMgr::addToPhases(Condition* cond) const { if (!cond->SourceEntry) { - bool found = false; - PhaseInfo& p = sObjectMgr->GetAreaAndZonePhasesForLoading(); - for (auto phaseItr = p.begin(); phaseItr != p.end(); ++phaseItr) + if (PhaseInfoStruct const* phaseInfo = sObjectMgr->GetPhaseInfo(cond->SourceGroup)) { - for (PhaseInfoStruct& phase : phaseItr->second) + bool found = false; + for (uint32 areaId : phaseInfo->Areas) { - if (phase.Id == cond->SourceGroup) + if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(areaId))) { - phase.Conditions.push_back(cond); - found = true; + for (PhaseAreaInfo& phase : *phases) + { + if (phase.PhaseInfo->Id == cond->SourceGroup) + { + phase.Conditions.push_back(cond); + found = true; + } + } } } - } - if (found) - return true; + if (found) + return true; + } } - else if (std::vector<PhaseInfoStruct>* phases = sObjectMgr->GetPhasesForAreaOrZoneForLoading(cond->SourceEntry)) + else if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(cond->SourceEntry))) { - for (PhaseInfoStruct& phase : *phases) + for (PhaseAreaInfo& phase : *phases) { - if (phase.Id == cond->SourceGroup) + if (phase.PhaseInfo->Id == cond->SourceGroup) { phase.Conditions.push_back(cond); return true; @@ -2809,15 +2805,9 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio || condition->MinExpansionLevel > int32(sWorld->getIntConfig(CONFIG_EXPANSION)))) return false; - if (condition->PhaseID && !player->IsInPhase(condition->PhaseID)) - return false; - - if (condition->PhaseGroupID) - { - std::set<uint32> phases = sDB2Manager.GetPhasesForGroup(condition->PhaseGroupID); - if (!Trinity::Containers::Intersects(phases.begin(), phases.end(), player->GetPhases().begin(), player->GetPhases().end())) + if (condition->PhaseID || condition->PhaseGroupID || condition->PhaseUseFlags) + if (!PhasingHandler::InDbPhaseShift(player, condition->PhaseUseFlags, condition->PhaseID, condition->PhaseGroupID)) return false; - } if (condition->QuestKillID) { diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index dd3d58b1340..486b9356ecd 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -309,7 +309,7 @@ typedef std::unordered_map<uint32, DB2Manager::MountTypeXCapabilitySet> MountCap typedef std::unordered_map<uint32, DB2Manager::MountXDisplayContainer> MountDisplaysCointainer; typedef std::unordered_map<uint32, std::array<std::vector<NameGenEntry const*>, 2>> NameGenContainer; typedef std::array<std::vector<Trinity::wregex>, TOTAL_LOCALES + 1> NameValidationRegexContainer; -typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer; +typedef std::unordered_map<uint32, std::vector<uint32>> PhaseGroupContainer; typedef std::array<PowerTypeEntry const*, MAX_POWERS> PowerTypesContainer; typedef std::vector<PvpTalentEntry const*> PvpTalentsByPosition[MAX_CLASSES][MAX_PVP_TALENT_TIERS][MAX_PVP_TALENT_COLUMNS]; typedef std::unordered_map<uint32, std::pair<std::vector<QuestPackageItemEntry const*>, std::vector<QuestPackageItemEntry const*>>> QuestPackageItemContainer; @@ -935,7 +935,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) for (PhaseXPhaseGroupEntry const* group : sPhaseXPhaseGroupStore) if (PhaseEntry const* phase = sPhaseStore.LookupEntry(group->PhaseID)) - _phasesByGroup[group->PhaseGroupID].insert(phase->ID); + _phasesByGroup[group->PhaseGroupID].push_back(phase->ID); for (PowerTypeEntry const* powerType : sPowerTypeStore) { @@ -1963,13 +1963,13 @@ uint32 DB2Manager::GetQuestUniqueBitFlag(uint32 questId) return v2->UniqueBitFlag; } -std::set<uint32> DB2Manager::GetPhasesForGroup(uint32 group) const +std::vector<uint32> const* DB2Manager::GetPhasesForGroup(uint32 group) const { auto itr = _phasesByGroup.find(group); if (itr != _phasesByGroup.end()) - return itr->second; + return &itr->second; - return std::set<uint32>(); + return nullptr; } PowerTypeEntry const* DB2Manager::GetPowerTypeEntry(Powers power) const diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 886ab57822f..f923d6c437b 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -206,6 +206,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<WorldEffectEntry> sWorldEffectStore; +TC_GAME_API extern DB2Storage<WorldMapAreaEntry> sWorldMapAreaStore; TC_GAME_API extern DB2Storage<WorldMapOverlayEntry> sWorldMapOverlayStore; TC_GAME_API extern DB2Storage<WorldSafeLocsEntry> sWorldSafeLocsStore; @@ -302,7 +303,7 @@ public: MountTypeXCapabilitySet const* GetMountCapabilities(uint32 mountType) const; MountXDisplayContainer const* GetMountDisplays(uint32 mountId) const; ResponseCodes ValidateName(std::wstring const& name, LocaleConstant locale) const; - std::set<uint32> GetPhasesForGroup(uint32 group) const; + std::vector<uint32> const* GetPhasesForGroup(uint32 group) const; PowerTypeEntry const* GetPowerTypeEntry(Powers power) const; PowerTypeEntry const* GetPowerTypeByName(std::string const& name) const; uint8 GetPvpItemLevelBonus(uint32 itemId) const; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 5ea1ff3d2a8..404c5de75a8 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -814,6 +814,23 @@ enum MountFlags MOUNT_FLAG_HIDE_IF_UNKNOWN = 0x40 }; +enum PhaseEntryFlags : uint16 +{ + PHASE_FLAG_NORMAL = 0x08, + PHASE_FLAG_COSMETIC = 0x10, + PHASE_FLAG_PERSONAL = 0x20 +}; + +// PhaseUseFlags fields in different db2s +enum PhaseUseFlagsValues : uint8 +{ + PHASE_USE_FLAGS_NONE = 0x0, + PHASE_USE_FLAGS_ALWAYS_VISIBLE = 0x1, + PHASE_USE_FLAGS_INVERSE = 0x2, + + PHASE_USE_FLAGS_ALL = PHASE_USE_FLAGS_ALWAYS_VISIBLE | PHASE_USE_FLAGS_INVERSE +}; + enum PrestigeLevelInfoFlags : uint8 { PRESTIGE_FLAG_DISABLED = 0x01 // Prestige levels with this flag won't be included to calculate max prestigelevel. diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index 671ca840102..6c36fec788f 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -28,6 +28,7 @@ #include "Log.h" #include "Object.h" #include "ObjectAccessor.h" +#include "PhasingHandler.h" #include "Player.h" #include "ScriptMgr.h" #include "SpellInfo.h" @@ -127,7 +128,7 @@ bool AreaTrigger::Create(uint32 spellMiscId, Unit* caster, Unit* target, SpellIn if (GetMiscTemplate()->ScaleInfo.ExtraScale[scaleCurveIndex].AsInt32) SetUInt32Value(AREATRIGGER_EXTRA_SCALE_CURVE + scaleCurveIndex, GetMiscTemplate()->ScaleInfo.ExtraScale[scaleCurveIndex].AsInt32); - CopyPhaseFrom(caster); + PhasingHandler::InheritPhaseShift(this, caster); if (target && GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_ATTACHED)) { diff --git a/src/server/game/Entities/Conversation/Conversation.cpp b/src/server/game/Entities/Conversation/Conversation.cpp index 1d7d5a6cfae..13339f3169f 100644 --- a/src/server/game/Entities/Conversation/Conversation.cpp +++ b/src/server/game/Entities/Conversation/Conversation.cpp @@ -20,6 +20,7 @@ #include "IteratorPair.h" #include "Log.h" #include "Map.h" +#include "PhasingHandler.h" #include "ScriptMgr.h" #include "Unit.h" #include "UpdateData.h" @@ -115,7 +116,7 @@ bool Conversation::Create(ObjectGuid::LowType lowGuid, uint32 conversationEntry, Relocate(pos); Object::_Create(ObjectGuid::Create<HighGuid::Conversation>(GetMapId(), conversationEntry, lowGuid)); - CopyPhaseFrom(creator); + PhasingHandler::InheritPhaseShift(this, creator); SetEntry(conversationEntry); SetObjectScale(1.0f); diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 436032b89fe..a62b2ecbbc1 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -23,6 +23,7 @@ #include "Log.h" #include "Map.h" #include "ObjectAccessor.h" +#include "PhasingHandler.h" #include "Player.h" #include "UpdateData.h" #include "World.h" @@ -89,7 +90,7 @@ bool Corpse::Create(ObjectGuid::LowType guidlow, Player* owner) _cellCoord = Trinity::ComputeCellCoord(GetPositionX(), GetPositionY()); - CopyPhaseFrom(owner); + PhasingHandler::InheritPhaseShift(this, owner); return true; } @@ -119,12 +120,12 @@ void Corpse::SaveToDB() stmt->setUInt32(index++, GetInstanceId()); // instanceId trans->Append(stmt); - for (uint32 phaseId : GetPhases()) + for (PhaseShift::PhaseRef const& phase : GetPhaseShift().GetPhases()) { index = 0; stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CORPSE_PHASES); stmt->setUInt64(index++, GetOwnerGUID().GetCounter()); // OwnerGuid - stmt->setUInt32(index++, phaseId); // PhaseId + stmt->setUInt32(index++, phase.Id); // PhaseId trans->Append(stmt); } diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 6b28aae6562..9881945a825 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -38,6 +38,7 @@ #include "MotionMaster.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "PoolMgr.h" #include "QuestDef.h" @@ -861,12 +862,11 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 entry, float ASSERT(map); SetMap(map); - if (data && data->phaseId) - SetInPhase(data->phaseId, false, true); - - if (data && data->phaseGroup) - for (auto ph : sDB2Manager.GetPhasesForGroup(data->phaseGroup)) - SetInPhase(ph, false, true); + if (data) + { + PhasingHandler::InitDbPhaseShift(GetPhaseShift(), data->phaseUseFlags, data->phaseId, data->phaseGroup); + PhasingHandler::InitDbVisibleMapId(GetPhaseShift(), data->terrainSwapMap); + } CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry); if (!cinfo) @@ -1471,7 +1471,7 @@ bool Creature::LoadCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool ad m_deathState = DEAD; if (CanFly()) { - float tz = map->GetHeight(GetPhases(), data->posX, data->posY, data->posZ, true, MAX_FALL_DISTANCE); + float tz = map->GetHeight(GetPhaseShift(), data->posX, data->posY, data->posZ, true, MAX_FALL_DISTANCE); if (data->posZ - tz > 0.1f && Trinity::IsValidMapCoord(tz)) Relocate(data->posX, data->posY, tz); } @@ -2809,7 +2809,7 @@ void Creature::UpdateMovementFlags() return; // Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc) - float ground = GetMap()->GetHeight(GetPhases(), GetPositionX(), GetPositionY(), GetPositionZMinusOffset()); + float ground = GetMap()->GetHeight(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZMinusOffset()); bool isInAir = (G3D::fuzzyGt(GetPositionZMinusOffset(), ground + 0.05f) || G3D::fuzzyLt(GetPositionZMinusOffset(), ground - 0.05f)); // Can be underground too, prevent the falling diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index b933f6cb399..fddbc672542 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -500,7 +500,7 @@ struct CreatureData posX(0.0f), posY(0.0f), posZ(0.0f), orientation(0.0f), spawntimesecs(0), spawndist(0.0f), currentwaypoint(0), curhealth(0), curmana(0), movementType(0), spawnMask(0), npcflag(0), unit_flags(0), unit_flags2(0), unit_flags3(0), dynamicflags(0), - phaseId(0), phaseGroup(0), ScriptId(0), dbData(true) { } + phaseUseFlags(0), phaseId(0), phaseGroup(0), terrainSwapMap(-1), ScriptId(0), dbData(true) { } uint32 id; // entry in creature_template uint16 mapid; uint32 displayid; @@ -521,8 +521,10 @@ struct CreatureData uint32 unit_flags2; // enum UnitFlags2 mask values uint32 unit_flags3; // enum UnitFlags3 mask values uint32 dynamicflags; + uint8 phaseUseFlags; uint32 phaseId; uint32 phaseGroup; + int32 terrainSwapMap; uint32 ScriptId; bool dbData; }; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 26d70dcb2a1..f4c2c9fbe40 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -35,6 +35,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "OutdoorPvPMgr.h" +#include "PhasingHandler.h" #include "PoolMgr.h" #include "ScriptMgr.h" #include "SpellMgr.h" @@ -988,15 +989,8 @@ bool GameObject::LoadGameObjectFromDB(ObjectGuid::LowType spawnId, Map* map, boo if (!Create(entry, map, pos, data->rotation, animprogress, go_state, artKit)) return false; - if (data->phaseId) - SetInPhase(data->phaseId, false, true); - - if (data->phaseGroup) - { - // Set the gameobject in all the phases of the phasegroup - for (auto ph : sDB2Manager.GetPhasesForGroup(data->phaseGroup)) - SetInPhase(ph, false, true); - } + PhasingHandler::InitDbPhaseShift(GetPhaseShift(), data->phaseUseFlags, data->phaseId, data->phaseGroup); + PhasingHandler::InitDbVisibleMapId(GetPhaseShift(), data->terrainSwapMap); if (data->spawntimesecs >= 0) { @@ -2623,7 +2617,7 @@ public: virtual bool IsSpawned() const override { return _owner->isSpawned(); } virtual uint32 GetDisplayId() const override { return _owner->GetDisplayId(); } - virtual bool IsInPhase(std::set<uint32> const& phases) const override { return _owner->IsInPhase(phases); } + virtual bool IsInPhase(PhaseShift const& phaseShift) const override { return _owner->GetPhaseShift().CanSee(phaseShift); } virtual G3D::Vector3 GetPosition() const override { return G3D::Vector3(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()); } virtual float GetOrientation() const override { return _owner->GetOrientation(); } virtual float GetScale() const override { return _owner->GetObjectScale(); } diff --git a/src/server/game/Entities/GameObject/GameObjectData.h b/src/server/game/Entities/GameObject/GameObjectData.h index 5dddb33aeee..7491a3d8ac9 100644 --- a/src/server/game/Entities/GameObject/GameObjectData.h +++ b/src/server/game/Entities/GameObject/GameObjectData.h @@ -855,7 +855,8 @@ struct GameObjectAddon struct GameObjectData { explicit GameObjectData() : id(0), mapid(0), posX(0.0f), posY(0.0f), posZ(0.0f), orientation(0.0f), spawntimesecs(0), - animprogress(0), go_state(GO_STATE_ACTIVE), spawnMask(0), artKit(0), phaseId(0), phaseGroup(0), ScriptId(0), dbData(true) { } + animprogress(0), go_state(GO_STATE_ACTIVE), spawnMask(0), artKit(0), + phaseUseFlags(0), phaseId(0), phaseGroup(0), terrainSwapMap(-1), ScriptId(0), dbData(true) { } uint32 id; // entry in gamobject_template uint16 mapid; float posX; @@ -868,8 +869,10 @@ struct GameObjectData GOState go_state; uint64 spawnMask; uint8 artKit; + uint8 phaseUseFlags; uint32 phaseId; uint32 phaseGroup; + int32 terrainSwapMap; uint32 ScriptId; bool dbData; }; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 05f7a37abb0..1ec8586c90f 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -33,6 +33,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "OutdoorPvPMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "SharedDefines.h" #include "SpellAuraEffects.h" @@ -1780,7 +1781,7 @@ bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const else GetHitSpherePointFor({ ox, oy, oz }, x, y, z); - return GetMap()->isInLineOfSight(x, y, z + 2.0f, ox, oy, oz + 2.0f, GetPhases()); + return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z + 2.0f, ox, oy, oz + 2.0f); } return true; @@ -1950,7 +1951,7 @@ Position WorldObject::GetRandomPoint(const Position &srcPos, float distance) con void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const { - float new_z = GetMap()->GetHeight(GetPhases(), x, y, z + 2.0f, true); + float new_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z + 2.0f, true); if (new_z > INVALID_HEIGHT) z = new_z + 0.05f; // just to be sure that we are not a few pixel under the surface } @@ -1972,8 +1973,8 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const bool canSwim = ToCreature()->CanSwim(); float ground_z = z; float max_z = canSwim - ? GetMap()->GetWaterOrGroundLevel(GetPhases(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK)) - : ((ground_z = GetMap()->GetHeight(GetPhases(), x, y, z, true))); + ? GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK)) + : ((ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true))); if (max_z > INVALID_HEIGHT) { if (z > max_z) @@ -1984,7 +1985,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } else { - float ground_z = GetMap()->GetHeight(GetPhases(), x, y, z, true); + float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true); if (z < ground_z) z = ground_z; } @@ -1996,7 +1997,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const if (!ToPlayer()->CanFly()) { float ground_z = z; - float max_z = GetMap()->GetWaterOrGroundLevel(GetPhases(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK)); + float max_z = GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK)); if (max_z > INVALID_HEIGHT) { if (z > max_z) @@ -2007,7 +2008,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } else { - float ground_z = GetMap()->GetHeight(GetPhases(), x, y, z, true); + float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true); if (z < ground_z) z = ground_z; } @@ -2015,7 +2016,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } default: { - float ground_z = GetMap()->GetHeight(GetPhases(), x, y, z, true); + float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true); if (ground_z > INVALID_HEIGHT) z = ground_z; break; @@ -2428,7 +2429,8 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert } // Set the summon to the summoner's phase - summon->CopyPhaseFrom(summoner); + if (summoner) + PhasingHandler::InheritPhaseShift(summon, summoner); summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId); @@ -2533,7 +2535,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, Position const& pos, Qua if (!go) return nullptr; - go->CopyPhaseFrom(this); + PhasingHandler::InheritPhaseShift(go, this); go->SetRespawnTime(respawnTime); if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT) //not sure how to handle this @@ -2748,8 +2750,8 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle) return; } - ground = GetMap()->GetHeight(GetPhases(), destx, desty, MAX_HEIGHT, true); - floor = GetMap()->GetHeight(GetPhases(), destx, desty, pos.m_positionZ, true); + ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true); + floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true); destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor; float step = dist/10.0f; @@ -2761,8 +2763,8 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle) { destx -= step * std::cos(angle); desty -= step * std::sin(angle); - ground = GetMap()->GetHeight(GetPhases(), destx, desty, MAX_HEIGHT, true); - floor = GetMap()->GetHeight(GetPhases(), destx, desty, pos.m_positionZ, true); + ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true); + floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true); destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor; } // we have correct destz now @@ -2782,8 +2784,8 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle) // @todo: replace with WorldObject::UpdateAllowedPositionZ float NormalizeZforCollision(WorldObject* obj, float x, float y, float z) { - float ground = obj->GetMap()->GetHeight(obj->GetPhases(), x, y, MAX_HEIGHT, true); - float floor = obj->GetMap()->GetHeight(obj->GetPhases(), x, y, z + 2.0f, true); + float ground = obj->GetMap()->GetHeight(obj->GetPhaseShift(), x, y, MAX_HEIGHT, true); + float floor = obj->GetMap()->GetHeight(obj->GetPhaseShift(), x, y, z + 2.0f, true); float helper = std::fabs(ground - z) <= std::fabs(floor - z) ? ground : floor; if (z > helper) // must be above ground { @@ -2832,7 +2834,7 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float } // check dynamic collision - col = GetMap()->getObjectHitPos(GetPhases(), pos.m_positionX, pos.m_positionY, pos.m_positionZ + 0.5f, destx, desty, destz + 0.5f, destx, desty, destz, -0.5f); + col = GetMap()->getObjectHitPos(GetPhaseShift(), pos.m_positionX, pos.m_positionY, pos.m_positionZ + 0.5f, destx, desty, destz + 0.5f, destx, desty, destz, -0.5f); // Collided with a gameobject if (col) @@ -2867,150 +2869,6 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float pos.SetOrientation(GetOrientation()); } -bool WorldObject::HasInPhaseList(uint32 phase) -{ - return _phases.find(phase) != _phases.end(); -} - -// Updates Area based phases, does not remove phases from auras -// Phases from gm commands are not taken into calculations, they can be lost!! -void WorldObject::UpdateAreaAndZonePhase() -{ - bool updateNeeded = false; - PhaseInfo const& allAreasPhases = sObjectMgr->GetAreaAndZonePhases(); - uint32 zoneAndArea[] = { GetZoneId(), GetAreaId() }; - - // We first remove all phases from other areas & zones - for (auto itr = allAreasPhases.begin(); itr != allAreasPhases.end(); ++itr) - for (PhaseInfoStruct const& phase : itr->second) - if (!DB2Manager::IsInArea(GetAreaId(), itr->first)) - updateNeeded = SetInPhase(phase.Id, false, false) || updateNeeded; // not in area, remove phase, true if there was something removed - - // Then we add the phases from this area and zone if conditions are met - // Zone is done before Area, so if Area does not meet condition, the phase will be removed - for (uint32 area : zoneAndArea) - { - if (std::vector<PhaseInfoStruct> const* currentPhases = sObjectMgr->GetPhasesForArea(area)) - { - for (PhaseInfoStruct const& phaseInfoStruct : *currentPhases) - { - bool apply = sConditionMgr->IsObjectMeetToConditions(this, phaseInfoStruct.Conditions); - - // add or remove phase depending of condition - updateNeeded = SetInPhase(phaseInfoStruct.Id, false, apply) || updateNeeded; - } - } - } - - // do not remove a phase if it would be removed by an area but we have the same phase from an aura - if (Unit* unit = ToUnit()) - { - Unit::AuraEffectList const& auraPhaseList = unit->GetAuraEffectsByType(SPELL_AURA_PHASE); - for (Unit::AuraEffectList::const_iterator itr = auraPhaseList.begin(); itr != auraPhaseList.end(); ++itr) - { - uint32 phase = uint32((*itr)->GetMiscValueB()); - updateNeeded = SetInPhase(phase, false, true) || updateNeeded; - } - Unit::AuraEffectList const& auraPhaseGroupList = unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP); - for (Unit::AuraEffectList::const_iterator itr = auraPhaseGroupList.begin(); itr != auraPhaseGroupList.end(); ++itr) - { - uint32 phaseGroup = uint32((*itr)->GetMiscValueB()); - std::set<uint32> phaseIDs = sDB2Manager.GetPhasesForGroup(phaseGroup); - for (uint32 phase : phaseIDs) - updateNeeded = SetInPhase(phase, false, true) || updateNeeded; - } - } - - // only update visibility and send packets if there was a change in the phase list - if (updateNeeded && GetTypeId() == TYPEID_PLAYER && IsInWorld()) - ToPlayer()->GetSession()->SendSetPhaseShift(GetPhases(), GetTerrainSwaps(), GetWorldMapAreaSwaps()); - - // only update visibilty once, to prevent objects appearing for a moment while adding in multiple phases - if (updateNeeded && IsInWorld()) - UpdateObjectVisibility(); -} - -bool WorldObject::SetInPhase(uint32 id, bool update, bool apply) -{ - if (id) - { - if (apply) - { - // do not run the updates if we are already in this phase - if (!_phases.insert(id).second) - return false; - } - else - { - auto phaseItr = _phases.find(id); - if (phaseItr == _phases.end()) - return false; - - // if area phase passes the condition we should not remove it (ie: if remove called from aura remove) - // this however breaks the .mod phase command, you wont be able to remove any area based phases with it - if (std::vector<PhaseInfoStruct> const* phases = sObjectMgr->GetPhasesForArea(GetAreaId())) - for (PhaseInfoStruct const& phase : *phases) - if (id == phase.Id) - if (sConditionMgr->IsObjectMeetToConditions(this, phase.Conditions)) - return false; - - _phases.erase(phaseItr); - } - } - - RebuildTerrainSwaps(); - - if (update && IsInWorld()) - UpdateObjectVisibility(); - - return true; -} - -void WorldObject::CopyPhaseFrom(WorldObject* obj, bool update) -{ - if (!obj) - return; - - for (uint32 phase : obj->GetPhases()) - SetInPhase(phase, false, true); - - if (update && IsInWorld()) - UpdateObjectVisibility(); -} - -void WorldObject::ClearPhases(bool update) -{ - _phases.clear(); - - RebuildTerrainSwaps(); - - if (update && IsInWorld()) - UpdateObjectVisibility(); -} - -bool WorldObject::IsInPhase(std::set<uint32> const& phases) const -{ - // PhaseId 169 is the default fallback phase - if (_phases.empty() && phases.empty()) - return true; - - if (_phases.empty() && phases.count(DEFAULT_PHASE) > 0) - return true; - - if (phases.empty() && _phases.count(DEFAULT_PHASE) > 0) - return true; - - return Trinity::Containers::Intersects(_phases.begin(), _phases.end(), phases.begin(), phases.end()); -} - -bool WorldObject::IsInPhase(WorldObject const* obj) const -{ - if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster()) - return true; - - return IsInPhase(obj->GetPhases()); -} - void WorldObject::PlayDistanceSound(uint32 soundId, Player* target /*= nullptr*/) { if (target) @@ -3165,66 +3023,6 @@ ObjectGuid WorldObject::GetTransGUID() const return ObjectGuid::Empty; } -void WorldObject::RebuildTerrainSwaps() -{ - // Clear all terrain swaps, will be rebuilt below - // Reason for this is, multiple phases can have the same terrain swap, we should not remove the swap if another phase still use it - _terrainSwaps.clear(); - - // Check all applied phases for terrain swap and add it only once - for (uint32 phaseId : _phases) - { - if (std::vector<uint32> const* swaps = sObjectMgr->GetPhaseTerrainSwaps(phaseId)) - { - for (uint32 const& swap : *swaps) - { - // only add terrain swaps for current map - MapEntry const* mapEntry = sMapStore.LookupEntry(swap); - if (!mapEntry || mapEntry->ParentMapID != int32(GetMapId())) - continue; - - if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap, this)) - _terrainSwaps.insert(swap); - } - } - } - - // get default terrain swaps, only for current map always - if (std::vector<uint32> const* mapSwaps = sObjectMgr->GetDefaultTerrainSwaps(GetMapId())) - for (uint32 const& swap : *mapSwaps) - if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap, this)) - _terrainSwaps.insert(swap); - - // online players have a game client with world map display - if (GetTypeId() == TYPEID_PLAYER) - RebuildWorldMapAreaSwaps(); -} - -void WorldObject::RebuildWorldMapAreaSwaps() -{ - // Clear all world map area swaps, will be rebuilt below - _worldMapAreaSwaps.clear(); - - // get ALL default terrain swaps, if we are using it (condition is true) - // send the worldmaparea for it, to see swapped worldmaparea in client from other maps too, not just from our current - TerrainPhaseInfo const& defaults = sObjectMgr->GetDefaultTerrainSwapStore(); - for (TerrainPhaseInfo::const_iterator itr = defaults.begin(); itr != defaults.end(); ++itr) - for (uint32 const& swap : itr->second) - if (std::vector<uint32> const* uiMapSwaps = sObjectMgr->GetTerrainWorldMaps(swap)) - if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap, this)) - for (uint32 worldMapAreaId : *uiMapSwaps) - _worldMapAreaSwaps.insert(worldMapAreaId); - - // Check all applied phases for world map area swaps - for (uint32 phaseId : _phases) - if (std::vector<uint32> const* swaps = sObjectMgr->GetPhaseTerrainSwaps(phaseId)) - for (uint32 const& swap : *swaps) - if (std::vector<uint32> const* uiMapSwaps = sObjectMgr->GetTerrainWorldMaps(swap)) - if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap, this)) - for (uint32 worldMapAreaId : *uiMapSwaps) - _worldMapAreaSwaps.insert(worldMapAreaId); -} - template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>&, uint32, float) const; template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque<GameObject*>&, uint32, float) const; template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector<GameObject*>&, uint32, float) const; diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index db8e40a45e7..3dcc769b8ab 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -25,12 +25,11 @@ #include "MovementInfo.h" #include "ObjectDefines.h" #include "ObjectGuid.h" +#include "PhaseShift.h" #include "Position.h" #include "SharedDefines.h" - #include "UpdateFields.h" #include <list> -#include <set> #include <unordered_map> class AreaTrigger; @@ -408,20 +407,15 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation uint32 GetInstanceId() const { return m_InstanceId; } - virtual bool SetInPhase(uint32 id, bool update, bool apply); - void CopyPhaseFrom(WorldObject* obj, bool update = false); - void UpdateAreaAndZonePhase(); - void ClearPhases(bool update = false); - void RebuildTerrainSwaps(); - void RebuildWorldMapAreaSwaps(); - bool HasInPhaseList(uint32 phase); - bool IsInPhase(uint32 phase) const { return _phases.find(phase) != _phases.end(); } - bool IsInPhase(std::set<uint32> const& phases) const; - bool IsInPhase(WorldObject const* obj) const; - bool IsInTerrainSwap(uint32 terrainSwap) const { return _terrainSwaps.find(terrainSwap) != _terrainSwaps.end(); } - std::set<uint32> const& GetPhases() const { return _phases; } - std::set<uint32> const& GetTerrainSwaps() const { return _terrainSwaps; } - std::set<uint32> const& GetWorldMapAreaSwaps() const { return _worldMapAreaSwaps; } + bool IsInPhase(WorldObject const* obj) const + { + return GetPhaseShift().CanSee(obj->GetPhaseShift()); + } + + PhaseShift& GetPhaseShift() { return _phaseShift; } + PhaseShift const& GetPhaseShift() const { return _phaseShift; } + PhaseShift& GetSuppressedPhaseShift() { return _suppressedPhaseShift; } + PhaseShift const& GetSuppressedPhaseShift() const { return _suppressedPhaseShift; } int32 GetDBPhase() const { return _dbPhase; } // if negative it is used as PhaseGroupId @@ -606,9 +600,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation //uint32 m_mapId; // object at map with map_id uint32 m_InstanceId; // in map copy with instance id - std::set<uint32> _phases; - std::set<uint32> _terrainSwaps; - std::set<uint32> _worldMapAreaSwaps; + PhaseShift _phaseShift; + PhaseShift _suppressedPhaseShift; // contains phases for current area but not applied due to conditions int32 _dbPhase; uint16 m_notifyflags; diff --git a/src/server/game/Entities/Object/ObjectDefines.h b/src/server/game/Entities/Object/ObjectDefines.h index 72d5f80109c..4891da4e61c 100644 --- a/src/server/game/Entities/Object/ObjectDefines.h +++ b/src/server/game/Entities/Object/ObjectDefines.h @@ -38,8 +38,6 @@ #define NOMINAL_MELEE_RANGE 5.0f #define MELEE_RANGE (NOMINAL_MELEE_RANGE - MIN_MELEE_REACH * 2) //center to center for players -#define DEFAULT_PHASE 169 - enum TempSummonType { TEMPSUMMON_TIMED_OR_DEAD_DESPAWN = 1, // despawns after a specified time OR when the creature disappears diff --git a/src/server/game/Entities/Object/PhaseShift.cpp b/src/server/game/Entities/Object/PhaseShift.cpp deleted file mode 100644 index 7bbf5dfe667..00000000000 --- a/src/server/game/Entities/Object/PhaseShift.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "PhaseShift.h" diff --git a/src/server/game/Entities/Object/PhaseShift.h b/src/server/game/Entities/Object/PhaseShift.h deleted file mode 100644 index e830938f41e..00000000000 --- a/src/server/game/Entities/Object/PhaseShift.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef PhaseShift_h__ -#define PhaseShift_h__ - -#include "Define.h" -#include <set> - -class PhaseShift -{ -private: - std::set<uint32> _phases; - std::set<uint32> _terrainSwaps; - std::set<uint32> _worldMapAreaSwaps; -}; - -#endif // PhaseShift_h__ diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 24f63d43472..3e08a2ad31f 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -25,6 +25,7 @@ #include "Map.h" #include "ObjectMgr.h" #include "PetPackets.h" +#include "PhasingHandler.h" #include "Player.h" #include "Spell.h" #include "SpellAuraEffects.h" @@ -182,7 +183,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c if (!Create(map->GenerateLowGuid<HighGuid::Pet>(), map, petEntry)) return false; - CopyPhaseFrom(owner); + PhasingHandler::InheritPhaseShift(this, owner); setPetType(petType); setFaction(owner->getFaction()); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f3c115cd6d1..d5da4d8e66b 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -87,6 +87,7 @@ #include "OutdoorPvPMgr.h" #include "Pet.h" #include "PetPackets.h" +#include "PhasingHandler.h" #include "QueryHolder.h" #include "QuestDef.h" #include "QuestObjectiveCriteriaMgr.h" @@ -2195,10 +2196,13 @@ void Player::SetGameMaster(bool on) getHostileRefManager().setOnlineOfflineState(false); CombatStopWithPets(); + PhasingHandler::SetAlwaysVisible(GetPhaseShift(), true); m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, GetSession()->GetSecurity()); } else { + PhasingHandler::SetAlwaysVisible(GetPhaseShift(), false); + m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON; setFactionForRace(getRace()); RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); @@ -6984,7 +6988,7 @@ void Player::UpdateArea(uint32 newArea) UpdatePvPState(true); UpdateAreaDependentAuras(newArea); - UpdateAreaAndZonePhase(); + PhasingHandler::OnAreaChange(this); if (IsAreaThatActivatesPvpTalents(newArea)) EnablePvpRules(); @@ -7093,8 +7097,6 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) UpdateLocalChannels(newZone); UpdateZoneDependentAuras(newZone); - - UpdateAreaAndZonePhase(); } //If players are too far away from the duel flag... they lose the duel @@ -16188,7 +16190,7 @@ void Player::SendQuestUpdate(uint32 questId) } UpdateForQuestWorldObjects(); - SendUpdatePhasing(); + PhasingHandler::OnConditionChange(this); } QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) @@ -23820,6 +23822,8 @@ void Player::SendInitialPacketsAfterAddToMap() SendRaidDifficulty((difficulty->Flags & DIFFICULTY_FLAG_LEGACY) != 0); } + PhasingHandler::OnMapChange(this); + if (_garrison) _garrison->SendRemoteInfo(); @@ -27751,7 +27755,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy return nullptr; } - pet->CopyPhaseFrom(this); + PhasingHandler::InheritPhaseShift(pet, this); pet->SetCreatorGUID(GetGUID()); pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction()); @@ -27895,16 +27899,6 @@ void Player::ValidateMovementInfo(MovementInfo* mi) #undef REMOVE_VIOLATING_FLAGS } -void Player::SendUpdatePhasing() -{ - if (!IsInWorld()) - return; - - RebuildTerrainSwaps(); // to set default map swaps - - GetSession()->SendSetPhaseShift(GetPhases(), GetTerrainSwaps(), GetWorldMapAreaSwaps()); -} - void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) const { WorldPackets::Spells::SupercededSpells supercededSpells; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 11076546fd5..ebe275a0f0a 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2183,6 +2183,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> // currently visible objects at player client GuidUnorderedSet m_clientGUIDs; + GuidUnorderedSet m_visibleTransports; bool HaveAtClient(Object const* u) const; @@ -2196,8 +2197,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void UpdateVisibilityOf(WorldObject* target); void UpdateTriggerVisibility(); - void SendUpdatePhasing(); - template<class T> void UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow); diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index cdfaa3f33c9..bd86313e004 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -24,6 +24,7 @@ #include "Log.h" #include "MapManager.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "ScriptMgr.h" #include "Spline.h" @@ -326,13 +327,8 @@ Creature* Transport::CreateNPCPassenger(ObjectGuid::LowType guid, CreatureData c return nullptr; } - if (data->phaseId) - creature->SetInPhase(data->phaseId, false, true); - else if (data->phaseGroup) - for (auto phase : sDB2Manager.GetPhasesForGroup(data->phaseGroup)) - creature->SetInPhase(phase, false, true); - else - creature->CopyPhaseFrom(this); + PhasingHandler::InitDbPhaseShift(creature->GetPhaseShift(), data->phaseUseFlags, data->phaseId, data->phaseGroup); + PhasingHandler::InitDbVisibleMapId(creature->GetPhaseShift(), data->terrainSwapMap); if (!map->AddToMap(creature)) { @@ -375,6 +371,9 @@ GameObject* Transport::CreateGOPassenger(ObjectGuid::LowType guid, GameObjectDat return nullptr; } + PhasingHandler::InitDbPhaseShift(go->GetPhaseShift(), data->phaseUseFlags, data->phaseId, data->phaseGroup); + PhasingHandler::InitDbVisibleMapId(go->GetPhaseShift(), data->terrainSwapMap); + if (!map->AddToMap(go)) { delete go; @@ -439,12 +438,6 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu } } - std::set<uint32> phases; - if (summoner) - phases = summoner->GetPhases(); - else - phases = GetPhases(); // If there was no summoner, try to use the transport phases - TempSummon* summon = nullptr; switch (mask) { @@ -475,8 +468,7 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu return nullptr; } - for (uint32 phase : phases) - summon->SetInPhase(phase, false, true); + PhasingHandler::InheritPhaseShift(summon, summoner ? static_cast<WorldObject*>(summoner) : static_cast<WorldObject*>(this)); summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId); diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index 03bd3bcb2c7..b3bdcae034c 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -27,7 +27,7 @@ struct CreatureData; class TC_GAME_API Transport : public GameObject, public TransportBase { - friend Transport* TransportMgr::CreateTransport(uint32, ObjectGuid::LowType, Map*, uint32, uint32); + friend Transport* TransportMgr::CreateTransport(uint32, ObjectGuid::LowType, Map*, uint8, uint32, uint32); Transport(); public: diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 719f58ad870..75590a0c44d 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -55,6 +55,7 @@ #include "PassiveAI.h" #include "Pet.h" #include "PetAI.h" +#include "PhasingHandler.h" #include "Player.h" #include "PlayerAI.h" #include "QuestDef.h" @@ -3849,7 +3850,7 @@ void Unit::RemoveAurasWithAttribute(uint32 flags) } } -void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid) +void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/) { // single target auras from other casters // Iterate m_ownedAuras - aura is marked as single target in Unit::AddAura (and pushed to m_ownedAuras). @@ -3866,12 +3867,12 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid) if (aura->GetCasterGUID() != GetGUID() && aura->IsSingleTarget()) { - if (!newPhase && !phaseid) + if (!onPhaseChange) RemoveOwnedAura(iter); else { Unit* caster = aura->GetCaster(); - if (!caster || (newPhase && !caster->IsInPhase(newPhase)) || (!newPhase && !caster->IsInPhase(this))) + if (!caster || !caster->IsInPhase(this)) RemoveOwnedAura(iter); else ++iter; @@ -3886,7 +3887,7 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid) for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();) { Aura* aura = *iter; - if (aura->GetUnitOwner() != this && !aura->GetUnitOwner()->IsInPhase(newPhase)) + if (aura->GetUnitOwner() != this && (!onPhaseChange || !aura->GetUnitOwner()->IsInPhase(this))) { aura->Remove(); iter = scAuras.begin(); @@ -9466,15 +9467,6 @@ int32 Unit::GetCreatePowers(Powers power) const return 0; } -void Unit::AddToWorld() -{ - if (!IsInWorld()) - { - WorldObject::AddToWorld(); - } - RebuildTerrainSwaps(); -} - void Unit::RemoveFromWorld() { // cleanup @@ -10751,7 +10743,7 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id) return false; } - pet->CopyPhaseFrom(this); + PhasingHandler::InheritPhaseShift(pet, this); pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true); // this enables pet details window (Shift+P) @@ -11976,14 +11968,12 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, u return missChance; } -bool Unit::SetInPhase(uint32 id, bool update, bool apply) +void Unit::OnPhaseChange() { - bool res = WorldObject::SetInPhase(id, update, apply); - if (!IsInWorld()) - return res; + return; - if (GetTypeId() == TYPEID_UNIT || (!ToPlayer()->IsGameMaster() && !ToPlayer()->GetSession()->PlayerLogout())) + if (GetTypeId() == TYPEID_UNIT || !ToPlayer()->GetSession()->PlayerLogout()) { HostileRefManager& refManager = getHostileRefManager(); HostileReference* ref = refManager.getFirst(); @@ -12013,19 +12003,6 @@ bool Unit::SetInPhase(uint32 id, bool update, bool apply) unit->getHostileRefManager().setOnlineOfflineState(ToCreature(), unit->IsInPhase(this)); } } - - for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) - if ((*itr)->GetTypeId() == TYPEID_UNIT) - (*itr)->SetInPhase(id, true, apply); - - for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i) - if (!m_SummonSlot[i].IsEmpty()) - if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i])) - summon->SetInPhase(id, true, apply); - - RemoveNotOwnSingleTargetAuras(0, true); - - return res; } void Unit::UpdateObjectVisibility(bool forced) @@ -12848,7 +12825,7 @@ void Unit::_ExitVehicle(Position const* exitPosition) Movement::MoveSplineInit init(this); // Creatures without inhabit type air should begin falling after exiting the vehicle - if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(GetPhases(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), &height) + 0.1f) + if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), &height) + 0.1f) init.SetFall(); init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 6a8b7d94817..b5a023620da 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -930,7 +930,6 @@ class TC_GAME_API Unit : public WorldObject UnitAI* GetAI() { return i_AI; } void SetAI(UnitAI* newAI) { i_AI = newAI; } - void AddToWorld() override; void RemoveFromWorld() override; void CleanupBeforeRemoveFromMap(bool finalCleanup); @@ -1436,7 +1435,7 @@ class TC_GAME_API Unit : public WorldObject void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, Unit* stealer); void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid); void RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID = ObjectGuid::Empty, Aura* except = NULL, bool negative = true, bool positive = true); - void RemoveNotOwnSingleTargetAuras(uint32 newPhase = 0x0, bool phaseid = false); + void RemoveNotOwnSingleTargetAuras(bool onPhaseChange = false); template <typename InterruptFlags> void RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except = 0); void RemoveAurasWithAttribute(uint32 flags); @@ -1625,7 +1624,7 @@ class TC_GAME_API Unit : public WorldObject void SetVisible(bool x); // common function for visibility checks for player/creatures with detection code - bool SetInPhase(uint32 id, bool update, bool apply) override; + void OnPhaseChange(); void UpdateObjectVisibility(bool forced = true) override; SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY]; diff --git a/src/server/game/Garrison/Garrison.cpp b/src/server/game/Garrison/Garrison.cpp index 1e2766a93d5..4dc4db59775 100644 --- a/src/server/game/Garrison/Garrison.cpp +++ b/src/server/game/Garrison/Garrison.cpp @@ -25,6 +25,7 @@ #include "Map.h" #include "MapManager.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "VehicleDefines.h" @@ -235,7 +236,7 @@ bool Garrison::Create(uint32 garrSiteId) WorldPackets::Garrison::GarrisonCreateResult garrisonCreateResult; garrisonCreateResult.GarrSiteLevelID = _siteLevel->ID; _owner->SendDirectMessage(garrisonCreateResult.Write()); - _owner->SendUpdatePhasing(); + PhasingHandler::OnConditionChange(_owner); SendRemoteInfo(); return true; } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 8a8651f3aa0..78cd1e7e5b9 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1872,8 +1872,8 @@ void ObjectMgr::LoadCreatures() QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, " // 11 12 13 14 15 16 17 18 19 20 21 "currentwaypoint, curhealth, curmana, MovementType, spawnMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.unit_flags2, creature.unit_flags3, " - // 22 23 24 25 - "creature.dynamicflags, creature.phaseid, creature.phasegroup, creature.ScriptName " + // 22 23 24 25 26 27 + "creature.dynamicflags, creature.phaseUseFlags, creature.phaseid, creature.phasegroup, creature.terrainSwapMap, creature.ScriptName " "FROM creature " "LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid " "LEFT OUTER JOIN pool_creature ON creature.guid = pool_creature.guid"); @@ -1930,9 +1930,11 @@ void ObjectMgr::LoadCreatures() data.unit_flags2 = fields[20].GetUInt32(); data.unit_flags3 = fields[21].GetUInt32(); data.dynamicflags = fields[22].GetUInt32(); - data.phaseId = fields[23].GetUInt32(); - data.phaseGroup = fields[24].GetUInt32(); - data.ScriptId = GetScriptId(fields[25].GetString()); + data.phaseUseFlags = fields[23].GetUInt8(); + data.phaseId = fields[24].GetUInt32(); + data.phaseGroup = fields[25].GetUInt32(); + data.terrainSwapMap = fields[26].GetInt32(); + data.ScriptId = GetScriptId(fields[27].GetString()); if (!data.ScriptId) data.ScriptId = cInfo->ScriptID; @@ -2020,6 +2022,19 @@ void ObjectMgr::LoadCreatures() data.orientation = Position::NormalizeOrientation(data.orientation); } + if (data.phaseUseFlags & ~PHASE_USE_FLAGS_ALL) + { + TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) has unknown `phaseUseFlags` set, removed unknown value.", guid, data.id); + data.phaseUseFlags &= PHASE_USE_FLAGS_ALL; + } + + if (data.phaseUseFlags & PHASE_USE_FLAGS_ALWAYS_VISIBLE && data.phaseUseFlags & PHASE_USE_FLAGS_INVERSE) + { + TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE," + " removing PHASE_USE_FLAGS_INVERSE.", guid, data.id); + data.phaseUseFlags &= ~PHASE_USE_FLAGS_INVERSE; + } + if (data.phaseGroup && data.phaseId) { TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.id); @@ -2037,13 +2052,28 @@ void ObjectMgr::LoadCreatures() if (data.phaseGroup) { - if (sDB2Manager.GetPhasesForGroup(data.phaseGroup).empty()) + if (!sDB2Manager.GetPhasesForGroup(data.phaseGroup)) { TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with `phasegroup` %u does not exist, set to 0", guid, data.id, data.phaseGroup); data.phaseGroup = 0; } } + if (data.terrainSwapMap != -1) + { + MapEntry const* terrainSwapEntry = sMapStore.LookupEntry(data.terrainSwapMap); + if (!terrainSwapEntry) + { + TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u does not exist, set to -1", guid, data.id, data.terrainSwapMap); + data.terrainSwapMap = -1; + } + else if (terrainSwapEntry->ParentMapID != data.mapid) + { + TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u which cannot be used on spawn map, set to -1", guid, data.id, data.terrainSwapMap); + data.terrainSwapMap = -1; + } + } + if (sWorld->getBoolConfig(CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA)) { uint32 zoneId = 0; @@ -2202,8 +2232,8 @@ void ObjectMgr::LoadGameobjects() QueryResult result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation, " // 7 8 9 10 11 12 13 14 15 16 "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, eventEntry, pool_entry, " - // 17 18 19 - "phaseid, phasegroup, ScriptName " + // 17 18 19 20 21 + "phaseUseFlags, phaseid, phasegroup, terrainSwapMap, ScriptName " "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid " "LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid"); @@ -2317,8 +2347,22 @@ void ObjectMgr::LoadGameobjects() int16 gameEvent = fields[15].GetInt8(); uint32 PoolId = fields[16].GetUInt32(); - data.phaseId = fields[17].GetUInt32(); - data.phaseGroup = fields[18].GetUInt32(); + data.phaseUseFlags = fields[17].GetUInt8(); + data.phaseId = fields[18].GetUInt32(); + data.phaseGroup = fields[19].GetUInt32(); + + if (data.phaseUseFlags & ~PHASE_USE_FLAGS_ALL) + { + TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) has unknown `phaseUseFlags` set, removed unknown value.", guid, data.id); + data.phaseUseFlags &= PHASE_USE_FLAGS_ALL; + } + + if (data.phaseUseFlags & PHASE_USE_FLAGS_ALWAYS_VISIBLE && data.phaseUseFlags & PHASE_USE_FLAGS_INVERSE) + { + TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE," + " removing PHASE_USE_FLAGS_INVERSE.", guid, data.id); + data.phaseUseFlags &= ~PHASE_USE_FLAGS_INVERSE; + } if (data.phaseGroup && data.phaseId) { @@ -2337,14 +2381,30 @@ void ObjectMgr::LoadGameobjects() if (data.phaseGroup) { - if (sDB2Manager.GetPhasesForGroup(data.phaseGroup).empty()) + if (!sDB2Manager.GetPhasesForGroup(data.phaseGroup)) { TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) with `phaseGroup` %u does not exist, set to 0", guid, data.id, data.phaseGroup); data.phaseGroup = 0; } } - data.ScriptId = GetScriptId(fields[19].GetString()); + data.terrainSwapMap = fields[20].GetInt32(); + if (data.terrainSwapMap != -1) + { + MapEntry const* terrainSwapEntry = sMapStore.LookupEntry(data.terrainSwapMap); + if (!terrainSwapEntry) + { + TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u does not exist, set to -1", guid, data.id, data.terrainSwapMap); + data.terrainSwapMap = -1; + } + else if (terrainSwapEntry->ParentMapID != data.mapid) + { + TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u which cannot be used on spawn map, set to -1", guid, data.id, data.terrainSwapMap); + data.terrainSwapMap = -1; + } + } + + data.ScriptId = GetScriptId(fields[21].GetString()); if (!data.ScriptId) data.ScriptId = gInfo->ScriptId; @@ -9394,18 +9454,42 @@ void ObjectMgr::LoadFactionChangeTitles() TC_LOG_INFO("server.loading", ">> Loaded %u faction change title pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadTerrainSwapDefaults() +void ObjectMgr::LoadPhases() +{ + for (PhaseEntry const* phase : sPhaseStore) + _phaseInfoById.emplace(std::make_pair(phase->ID, PhaseInfoStruct{ phase->ID, std::unordered_set<uint32>{} })); + + for (MapEntry const* map : sMapStore) + if (map->ParentMapID != -1) + _terrainSwapInfoById.emplace(std::make_pair(map->ID, TerrainSwapInfo{ map->ID, std::vector<uint32>{} })); + + TC_LOG_INFO("server.loading", "Loading Terrain World Map definitions..."); + LoadTerrainWorldMaps(); + + TC_LOG_INFO("server.loading", "Loading Terrain Swap Default definitions..."); + LoadTerrainSwapDefaults(); + + TC_LOG_INFO("server.loading", "Loading Phase Area definitions..."); + LoadAreaPhases(); +} + +void ObjectMgr::UnloadPhaseConditions() { - _terrainMapDefaultStore.clear(); + for (auto itr = _phaseInfoByArea.begin(); itr != _phaseInfoByArea.end(); ++itr) + for (PhaseAreaInfo& phase : itr->second) + phase.Conditions.clear(); +} +void ObjectMgr::LoadTerrainWorldMaps() +{ uint32 oldMSTime = getMSTime(); - // 0 1 - QueryResult result = WorldDatabase.Query("SELECT MapId, TerrainSwapMap FROM `terrain_swap_defaults`"); + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT TerrainSwapMap, WorldMapArea FROM `terrain_worldmap`"); if (!result) { - TC_LOG_INFO("server.loading", ">> Loaded 0 terrain swap defaults. DB table `terrain_swap_defaults` is empty."); + TC_LOG_INFO("server.loading", ">> Loaded 0 terrain world maps. DB table `terrain_worldmap` is empty."); return; } @@ -9415,41 +9499,40 @@ void ObjectMgr::LoadTerrainSwapDefaults() Field* fields = result->Fetch(); uint32 mapId = fields[0].GetUInt32(); + uint32 worldMapArea = fields[1].GetUInt32(); if (!sMapStore.LookupEntry(mapId)) { - TC_LOG_ERROR("sql.sql", "Map %u defined in `terrain_swap_defaults` does not exist, skipped.", mapId); + TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_worldmap` does not exist, skipped.", mapId); continue; } - uint32 terrainSwap = fields[1].GetUInt32(); - - if (!sMapStore.LookupEntry(terrainSwap)) + if (!sWorldMapAreaStore.LookupEntry(worldMapArea)) { - TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_swap_defaults` does not exist, skipped.", terrainSwap); + TC_LOG_ERROR("sql.sql", "WorldMapArea %u defined in `terrain_worldmap` does not exist, skipped.", worldMapArea); continue; } - _terrainMapDefaultStore[mapId].push_back(terrainSwap); + TerrainSwapInfo* terrainSwapInfo = &_terrainSwapInfoById[mapId]; + terrainSwapInfo->Id = mapId; + terrainSwapInfo->UiWorldMapAreaIDSwaps.push_back(worldMapArea); ++count; } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u terrain swap defaults in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u terrain world maps in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadTerrainPhaseInfo() +void ObjectMgr::LoadTerrainSwapDefaults() { - _terrainPhaseInfoStore.clear(); - uint32 oldMSTime = getMSTime(); // 0 1 - QueryResult result = WorldDatabase.Query("SELECT Id, TerrainSwapMap FROM `terrain_phase_info`"); + QueryResult result = WorldDatabase.Query("SELECT MapId, TerrainSwapMap FROM `terrain_swap_defaults`"); if (!result) { - TC_LOG_INFO("server.loading", ">> Loaded 0 terrain phase infos. DB table `terrain_phase_info` is empty."); + TC_LOG_INFO("server.loading", ">> Loaded 0 terrain swap defaults. DB table `terrain_swap_defaults` is empty."); return; } @@ -9458,92 +9541,130 @@ void ObjectMgr::LoadTerrainPhaseInfo() { Field* fields = result->Fetch(); - uint32 phaseId = fields[0].GetUInt32(); + uint32 mapId = fields[0].GetUInt32(); - if (!sPhaseStore.LookupEntry(phaseId)) + if (!sMapStore.LookupEntry(mapId)) { - TC_LOG_ERROR("sql.sql", "Phase %u defined in `terrain_phase_info` does not exist, skipped.", phaseId); + TC_LOG_ERROR("sql.sql", "Map %u defined in `terrain_swap_defaults` does not exist, skipped.", mapId); continue; } uint32 terrainSwap = fields[1].GetUInt32(); - _terrainPhaseInfoStore[phaseId].push_back(terrainSwap); + if (!sMapStore.LookupEntry(terrainSwap)) + { + TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_swap_defaults` does not exist, skipped.", terrainSwap); + continue; + } + + TerrainSwapInfo* terrainSwapInfo = &_terrainSwapInfoById[terrainSwap]; + terrainSwapInfo->Id = terrainSwap; + _terrainSwapInfoByMap[mapId].push_back(terrainSwapInfo); ++count; - } - while (result->NextRow()); + } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u terrain phase infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u terrain swap defaults in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadTerrainWorldMaps() +void ObjectMgr::LoadAreaPhases() { - _terrainWorldMapStore.clear(); - uint32 oldMSTime = getMSTime(); - // 0 1 - QueryResult result = WorldDatabase.Query("SELECT TerrainSwapMap, WorldMapArea FROM `terrain_worldmap`"); + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT AreaId, PhaseId FROM `phase_area`"); if (!result) { - TC_LOG_INFO("server.loading", ">> Loaded 0 terrain world maps. DB table `terrain_worldmap` is empty."); + TC_LOG_INFO("server.loading", ">> Loaded 0 phase areas. DB table `phase_area` is empty."); return; } + auto getOrCreatePhaseIfMissing = [this](uint32 phaseId) + { + PhaseInfoStruct* phaseInfo = &_phaseInfoById[phaseId]; + phaseInfo->Id = phaseId; + return phaseInfo; + }; + uint32 count = 0; do { Field* fields = result->Fetch(); - - uint32 mapId = fields[0].GetUInt32(); - - if (!sMapStore.LookupEntry(mapId)) + uint32 area = fields[0].GetUInt32(); + uint32 phaseId = fields[1].GetUInt32(); + if (!sAreaTableStore.LookupEntry(area)) { - TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_worldmap` does not exist, skipped.", mapId); + TC_LOG_ERROR("sql.sql", "Area %u defined in `phase_area` does not exist, skipped.", area); continue; } - uint32 worldMapArea = fields[1].GetUInt32(); + if (!sPhaseStore.LookupEntry(phaseId)) + { + TC_LOG_ERROR("sql.sql", "Phase %u defined in `phase_area` does not exist, skipped.", phaseId); + continue; + } - _terrainWorldMapStore[mapId].push_back(worldMapArea); + PhaseInfoStruct* phase = getOrCreatePhaseIfMissing(phaseId); + phase->Areas.insert(area); + _phaseInfoByArea[area].emplace_back(phase); ++count; } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u terrain world maps in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); -} - -void ObjectMgr::LoadAreaPhases() -{ - _phases.clear(); + for (auto itr = _phaseInfoByArea.begin(); itr != _phaseInfoByArea.end(); ++itr) + { + for (PhaseAreaInfo& phase : itr->second) + { + uint32 parentAreaId = itr->first; + do + { + AreaTableEntry const* area = sAreaTableStore.LookupEntry(parentAreaId); + if (!area) + break; - uint32 oldMSTime = getMSTime(); + parentAreaId = area->ParentAreaID; + if (!parentAreaId) + break; - // 0 1 - QueryResult result = WorldDatabase.Query("SELECT AreaId, PhaseId FROM `phase_area`"); + if (std::vector<PhaseAreaInfo>* parentAreaPhases = Trinity::Containers::MapGetValuePtr(_phaseInfoByArea, parentAreaId)) + for (PhaseAreaInfo& parentAreaPhase : *parentAreaPhases) + if (parentAreaPhase.PhaseInfo->Id == phase.PhaseInfo->Id) + parentAreaPhase.SubAreaExclusions.insert(itr->first); - if (!result) - { - TC_LOG_INFO("server.loading", ">> Loaded 0 phase areas. DB table `phase_area` is empty."); - return; + } while (true); + } } - uint32 count = 0; - do + TC_LOG_INFO("server.loading", ">> Loaded %u phase areas in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + +bool PhaseInfoStruct::IsAllowedInArea(uint32 areaId) const +{ + return std::any_of(Areas.begin(), Areas.end(), [areaId](uint32 areaToCheck) { - Field* fields = result->Fetch(); + return DB2Manager::IsInArea(areaId, areaToCheck); + }); +} - PhaseInfoStruct phase; - uint32 area = fields[0].GetUInt32(); - phase.Id = fields[1].GetUInt32(); - _phases[area].push_back(phase); +PhaseInfoStruct const* ObjectMgr::GetPhaseInfo(uint32 phaseId) const +{ + return Trinity::Containers::MapGetValuePtr(_phaseInfoById, phaseId); +} - ++count; - } while (result->NextRow()); +std::vector<PhaseAreaInfo> const* ObjectMgr::GetPhasesForArea(uint32 areaId) const +{ + return Trinity::Containers::MapGetValuePtr(_phaseInfoByArea, areaId); +} - TC_LOG_INFO("server.loading", ">> Loaded %u phase areas in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +TerrainSwapInfo const* ObjectMgr::GetTerrainSwapInfo(uint32 terrainSwapId) const +{ + return Trinity::Containers::MapGetValuePtr(_terrainSwapInfoById, terrainSwapId); +} + +std::vector<TerrainSwapInfo*> const* ObjectMgr::GetTerrainSwapsForMap(uint32 mapId) const +{ + return Trinity::Containers::MapGetValuePtr(_terrainSwapInfoByMap, mapId); } GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry) const diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 34824b704d4..6812f3ece18 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -892,15 +892,28 @@ struct DungeonEncounter typedef std::list<DungeonEncounter const*> DungeonEncounterList; typedef std::unordered_map<uint64, DungeonEncounterList> DungeonEncounterContainer; +struct TerrainSwapInfo +{ + uint32 Id; + std::vector<uint32> UiWorldMapAreaIDSwaps; +}; + struct PhaseInfoStruct { uint32 Id; - ConditionContainer Conditions; + std::unordered_set<uint32> Areas; + + bool IsAllowedInArea(uint32 areaId) const; }; -typedef std::unordered_map<uint32, std::vector<uint32 /*id*/>> TerrainPhaseInfo; // terrain swap -typedef std::unordered_map<uint32, std::vector<uint32>> TerrainUIPhaseInfo; // worldmaparea swap -typedef std::unordered_map<uint32, std::vector<PhaseInfoStruct>> PhaseInfo; // phase +struct PhaseAreaInfo +{ + PhaseAreaInfo(PhaseInfoStruct const* phaseInfo) : PhaseInfo(phaseInfo) { } + + PhaseInfoStruct const* PhaseInfo; + std::unordered_set<uint32> SubAreaExclusions; + ConditionContainer Conditions; +}; struct RaceUnlockRequirement { @@ -1249,7 +1262,9 @@ class TC_GAME_API ObjectMgr void LoadTrainers(); void LoadCreatureDefaultTrainers(); - void LoadTerrainPhaseInfo(); + void LoadPhases(); + void UnloadPhaseConditions(); + void LoadTerrainSwapDefaults(); void LoadTerrainWorldMaps(); void LoadAreaPhases(); @@ -1513,36 +1528,6 @@ class TC_GAME_API ObjectMgr return _gossipMenuItemsStore.equal_range(uiMenuId); } - std::vector<uint32> const* GetPhaseTerrainSwaps(uint32 phaseid) const - { - auto itr = _terrainPhaseInfoStore.find(phaseid); - return itr != _terrainPhaseInfoStore.end() ? &itr->second : nullptr; - } - std::vector<uint32> const* GetDefaultTerrainSwaps(uint32 mapid) const - { - auto itr = _terrainMapDefaultStore.find(mapid); - return itr != _terrainMapDefaultStore.end() ? &itr->second : nullptr; - } - std::vector<uint32> const* GetTerrainWorldMaps(uint32 terrainId) const - { - auto itr = _terrainWorldMapStore.find(terrainId); - return itr != _terrainWorldMapStore.end() ? &itr->second : nullptr; - } - std::vector<PhaseInfoStruct> const* GetPhasesForArea(uint32 area) const - { - auto itr = _phases.find(area); - return itr != _phases.end() ? &itr->second : nullptr; - } - TerrainPhaseInfo const& GetDefaultTerrainSwapStore() const { return _terrainMapDefaultStore; } - PhaseInfo const& GetAreaAndZonePhases() const { return _phases; } - // condition loading helpers - std::vector<PhaseInfoStruct>* GetPhasesForAreaOrZoneForLoading(uint32 areaOrZone) - { - auto itr = _phases.find(areaOrZone); - return itr != _phases.end() ? &itr->second : nullptr; - } - PhaseInfo& GetAreaAndZonePhasesForLoading() { return _phases; } - // for wintergrasp only GraveYardContainer GraveYardStore; @@ -1684,10 +1669,17 @@ class TC_GAME_API ObjectMgr PageTextContainer _pageTextStore; InstanceTemplateContainer _instanceTemplateStore; - TerrainPhaseInfo _terrainPhaseInfoStore; - TerrainPhaseInfo _terrainMapDefaultStore; - TerrainUIPhaseInfo _terrainWorldMapStore; - PhaseInfo _phases; + public: + PhaseInfoStruct const* GetPhaseInfo(uint32 phaseId) const; + std::vector<PhaseAreaInfo> const* GetPhasesForArea(uint32 areaId) const; + TerrainSwapInfo const* GetTerrainSwapInfo(uint32 terrainSwapId) const; + std::vector<TerrainSwapInfo*> const* GetTerrainSwapsForMap(uint32 mapId) const; + + private: + std::unordered_map<uint32, PhaseInfoStruct> _phaseInfoById; + std::unordered_map<uint32, TerrainSwapInfo> _terrainSwapInfoById; + std::unordered_map<uint32, std::vector<PhaseAreaInfo>> _phaseInfoByArea; + std::unordered_map<uint32, std::vector<TerrainSwapInfo*>> _terrainSwapInfoByMap; private: void LoadScripts(ScriptsType type); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 44965fbd8e6..296cd80e323 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1062,17 +1062,6 @@ void WorldSession::HandleUITimeRequest(WorldPackets::Misc::UITimeRequest& /*requ SendPacket(response.Write()); } -void WorldSession::SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps, std::set<uint32> const& worldMapAreaSwaps) -{ - WorldPackets::Misc::PhaseShift phaseShift; - phaseShift.ClientGUID = _player->GetGUID(); - phaseShift.PersonalGUID = _player->GetGUID(); - phaseShift.PhaseShifts = phaseIds; - phaseShift.VisibleMapIDs = terrainswaps; - phaseShift.UiWorldMapAreaIDSwaps = worldMapAreaSwaps; - SendPacket(phaseShift.Write()); -} - void WorldSession::HandleInstanceLockResponse(WorldPackets::Instance::InstanceLockResponse& packet) { if (!_player->HasPendingBind()) diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index 7c8048d8a73..273bf287821 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -204,7 +204,7 @@ void WorldSession::HandleQueryCorpseLocation(WorldPackets::Query::QueryCorpseLoc mapID = corpseMapEntry->CorpseMapID; x = corpseMapEntry->Corpse.X; y = corpseMapEntry->Corpse.Y; - z = entranceMap->GetHeight(player->GetPhases(), x, y, MAX_HEIGHT); + z = entranceMap->GetHeight(player->GetPhaseShift(), x, y, MAX_HEIGHT); } } } diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 563388f64c1..78eb27430b6 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -32,6 +32,7 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "Pet.h" +#include "PhasingHandler.h" #include "Player.h" #include "RBAC.h" #include "ScriptMgr.h" @@ -762,7 +763,7 @@ void InstanceScript::UpdatePhasing() Map::PlayerList const& players = instance->GetPlayers(); for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) if (Player* player = itr->GetSource()) - player->SendUpdatePhasing(); + PhasingHandler::SendToPlayer(player); } std::string InstanceScript::GetBossStateName(uint8 state) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index ceb50e2e985..6ffa688ca08 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -41,6 +41,7 @@ #include "ObjectGridLoader.h" #include "ObjectMgr.h" #include "Pet.h" +#include "PhasingHandler.h" #include "ScriptMgr.h" #include "Transport.h" #include "Vehicle.h" @@ -568,7 +569,7 @@ bool Map::AddPlayerToMap(Player* player, bool initPlayer /*= true*/) player->m_clientGUIDs.clear(); player->UpdateObjectVisibility(false); - player->SendUpdatePhasing(); + PhasingHandler::SendToPlayer(player); if (player->IsAlive()) ConvertCorpseToBones(player->GetGUID()); @@ -631,8 +632,6 @@ bool Map::AddToMap(T* obj) if (obj->isActiveObject()) AddToActive(obj); - obj->RebuildTerrainSwaps(); - //something, such as vehicle, needs to be update immediately //also, trigger needs to cast spell, if not update, cannot see visual obj->UpdateObjectVisibilityOnCreate(); @@ -665,6 +664,7 @@ bool Map::AddToMap(Transport* obj) { UpdateData data(GetId()); obj->BuildCreateUpdateBlockForPlayer(&data, itr->GetSource()); + itr->GetSource()->m_visibleTransports.insert(obj->GetGUID()); WorldPacket packet; data.BuildPacket(&packet); itr->GetSource()->SendDirectMessage(&packet); @@ -969,8 +969,13 @@ void Map::RemoveFromMap(Transport* obj, bool remove) WorldPacket packet; data.BuildPacket(&packet); for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { if (itr->GetSource()->GetTransport() != obj) + { itr->GetSource()->SendDirectMessage(&packet); + itr->GetSource()->m_visibleTransports.erase(obj->GetGUID()); + } + } } if (_transportsUpdateIter != _transports.end()) @@ -2495,12 +2500,12 @@ inline GridMap* Map::GetGrid(float x, float y) return GridMaps[gx][gy]; } -float Map::GetWaterOrGroundLevel(std::set<uint32> const& phases, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/) const +float Map::GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/) const { if (const_cast<Map*>(this)->GetGrid(x, y)) { // we need ground level (including grid height version) for proper return water level in point - float ground_z = GetHeight(phases, x, y, z, true, 50.0f); + float ground_z = GetHeight(phaseShift, x, y, z, true, 50.0f); if (ground) *ground = ground_z; @@ -2789,19 +2794,19 @@ float Map::GetWaterLevel(float x, float y) const return 0; } -bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, std::set<uint32> const& phases) const +bool Map::isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2) const { return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2) - && _dynamicTree.isInLineOfSight({ x1, y1, z1 }, { x2, y2, z2 }, phases); + && _dynamicTree.isInLineOfSight({ x1, y1, z1 }, { x2, y2, z2 }, phaseShift); } -bool Map::getObjectHitPos(std::set<uint32> const& phases, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) +bool Map::getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) { G3D::Vector3 startPos(x1, y1, z1); G3D::Vector3 dstPos(x2, y2, z2); G3D::Vector3 resultPos; - bool result = _dynamicTree.getObjectHitPos(phases, startPos, dstPos, resultPos, modifyDist); + bool result = _dynamicTree.getObjectHitPos(startPos, dstPos, resultPos, modifyDist, phaseShift); rx = resultPos.x; ry = resultPos.y; @@ -2809,9 +2814,9 @@ bool Map::getObjectHitPos(std::set<uint32> const& phases, float x1, float y1, fl return result; } -float Map::GetHeight(std::set<uint32> const& phases, float x, float y, float z, bool vmap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const +float Map::GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const { - return std::max<float>(GetHeight(x, y, z, vmap, maxSearchDist), _dynamicTree.getHeight(x, y, z, maxSearchDist, phases)); + return std::max<float>(GetHeight(x, y, z, vmap, maxSearchDist), _dynamicTree.getHeight(x, y, z, maxSearchDist, phaseShift)); } bool Map::IsInWater(float x, float y, float pZ, LiquidData* data) const @@ -2858,6 +2863,7 @@ void Map::SendInitSelf(Player* player) if (Transport* transport = player->GetTransport()) { transport->BuildCreateUpdateBlockForPlayer(&data, player); + player->m_visibleTransports.insert(transport->GetGUID()); } // build data for self presence in world at own client (one time for map) @@ -2865,9 +2871,9 @@ void Map::SendInitSelf(Player* player) // build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map if (Transport* transport = player->GetTransport()) - for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr) - if (player != (*itr) && player->HaveAtClient(*itr)) - (*itr)->BuildCreateUpdateBlockForPlayer(&data, player); + for (WorldObject* passenger : transport->GetPassengers()) + if (player != passenger && player->HaveAtClient(passenger)) + passenger->BuildCreateUpdateBlockForPlayer(&data, player); WorldPacket packet; data.BuildPacket(&packet); @@ -2878,9 +2884,14 @@ void Map::SendInitTransports(Player* player) { // Hack to send out transports UpdateData transData(player->GetMapId()); - for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i) - if (*i != player->GetTransport() && player->IsInPhase(*i)) - (*i)->BuildCreateUpdateBlockForPlayer(&transData, player); + for (Transport* transport : _transports) + { + if (transport != player->GetTransport() && player->IsInPhase(transport)) + { + transport->BuildCreateUpdateBlockForPlayer(&transData, player); + player->m_visibleTransports.insert(transport->GetGUID()); + } + } WorldPacket packet; transData.BuildPacket(&packet); @@ -2891,28 +2902,40 @@ void Map::SendRemoveTransports(Player* player) { // Hack to send out transports UpdateData transData(player->GetMapId()); - for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i) - if (*i != player->GetTransport()) - (*i)->BuildOutOfRangeUpdateBlock(&transData); + for (Transport* transport : _transports) + { + if (transport != player->GetTransport()) + { + transport->BuildOutOfRangeUpdateBlock(&transData); + player->m_visibleTransports.erase(transport->GetGUID()); + } + } WorldPacket packet; transData.BuildPacket(&packet); player->GetSession()->SendPacket(&packet); } -void Map::SendUpdateTransportVisibility(Player* player, std::set<uint32> const& previousPhases) +void Map::SendUpdateTransportVisibility(Player* player) { // Hack to send out transports UpdateData transData(player->GetMapId()); - for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i) + for (Transport* transport : _transports) { - if (*i == player->GetTransport()) - continue; - - if (player->IsInPhase(*i) && !Trinity::Containers::Intersects(previousPhases.begin(), previousPhases.end(), (*i)->GetPhases().begin(), (*i)->GetPhases().end())) - (*i)->BuildCreateUpdateBlockForPlayer(&transData, player); - else if (!player->IsInPhase(*i)) - (*i)->BuildOutOfRangeUpdateBlock(&transData); + auto transportItr = player->m_visibleTransports.find(transport->GetGUID()); + if (player->IsInPhase(transport)) + { + if (transportItr == player->m_visibleTransports.end()) + { + transport->BuildCreateUpdateBlockForPlayer(&transData, player); + player->m_visibleTransports.insert(transport->GetGUID()); + } + } + else if (transportItr != player->m_visibleTransports.end()) + { + transport->BuildOutOfRangeUpdateBlock(&transData); + player->m_visibleTransports.erase(transportItr); + } } WorldPacket packet; @@ -4030,8 +4053,8 @@ void Map::LoadCorpseData() continue; } - for (auto phaseId : phases[guid]) - corpse->SetInPhase(phaseId, false, true); + for (uint32 phaseId : phases[guid]) + PhasingHandler::AddPhase(corpse, phaseId, false); AddCorpse(corpse); @@ -4111,7 +4134,7 @@ Corpse* Map::ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia /*= bones->SetUInt32Value(CORPSE_FIELD_FLAGS, corpse->GetUInt32Value(CORPSE_FIELD_FLAGS) | CORPSE_FLAG_BONES); - bones->CopyPhaseFrom(corpse); + PhasingHandler::InheritPhaseShift(bones, corpse); AddCorpse(bones); diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 03f5f1bb6e6..ee43874fe2c 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -48,6 +48,7 @@ class InstanceScript; class InstanceScenario; class MapInstanced; class Object; +class PhaseShift; class Player; class TempSummon; class Unit; @@ -487,14 +488,14 @@ class TC_GAME_API Map : public GridRefManager<NGridType> BattlegroundMap* ToBattlegroundMap() { if (IsBattlegroundOrArena()) return reinterpret_cast<BattlegroundMap*>(this); else return NULL; } BattlegroundMap const* ToBattlegroundMap() const { if (IsBattlegroundOrArena()) return reinterpret_cast<BattlegroundMap const*>(this); return NULL; } - float GetWaterOrGroundLevel(std::set<uint32> const& phases, float x, float y, float z, float* ground = nullptr, bool swim = false) const; - float GetHeight(std::set<uint32> const& phases, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; - bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, std::set<uint32> const& phases) const; + float GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground = nullptr, bool swim = false) const; + float GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; + bool isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2) const; void Balance() { _dynamicTree.balance(); } void RemoveGameObjectModel(const GameObjectModel& model) { _dynamicTree.remove(model); } void InsertGameObjectModel(const GameObjectModel& model) { _dynamicTree.insert(model); } bool ContainsGameObjectModel(const GameObjectModel& model) const { return _dynamicTree.contains(model);} - bool getObjectHitPos(std::set<uint32> const& phases, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float modifyDist); + bool getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float modifyDist); virtual ObjectGuid::LowType GetOwnerGuildId(uint32 /*team*/ = TEAM_OTHER) const { return UI64LIT(0); } /* @@ -537,7 +538,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType> void SendInitTransports(Player* player); void SendRemoveTransports(Player* player); - void SendUpdateTransportVisibility(Player* player, std::set<uint32> const& previousPhases); + void SendUpdateTransportVisibility(Player* player); void SendZoneDynamicInfo(uint32 zoneId, Player* player) const; void SendZoneWeather(uint32 zoneId, Player* player) const; void SendZoneWeather(ZoneDynamicInfo const& zoneDynamicInfo, Player* player) const; diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index 9980a72dfb8..8435b86ecae 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -23,6 +23,7 @@ #include "MoveSplineInitArgs.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "Spline.h" #include "Transport.h" @@ -364,7 +365,7 @@ void TransportMgr::AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg, animNode.Path[timeSeg] = node; } -Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid /*= 0*/, Map* map /*= NULL*/, uint32 phaseid /*= 0*/, uint32 phasegroup /*= 0*/) +Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid /*= 0*/, Map* map /*= nullptr*/, uint8 phaseUseFlags /*= 0*/, uint32 phaseId /*= 0*/, uint32 phaseGroupId /*= 0*/) { // instance case, execute GetGameObjectEntry hook if (map) @@ -404,12 +405,7 @@ Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid return NULL; } - if (phaseid) - trans->SetInPhase(phaseid, false, true); - - if (phasegroup) - for (auto ph : sDB2Manager.GetPhasesForGroup(phasegroup)) - trans->SetInPhase(ph, false, true); + PhasingHandler::InitDbPhaseShift(trans->GetPhaseShift(), phaseUseFlags, phaseId, phaseGroupId); if (MapEntry const* mapEntry = sMapStore.LookupEntry(mapId)) { @@ -439,7 +435,7 @@ void TransportMgr::SpawnContinentTransports() uint32 oldMSTime = getMSTime(); - QueryResult result = WorldDatabase.Query("SELECT guid, entry, phaseid, phasegroup FROM transports"); + QueryResult result = WorldDatabase.Query("SELECT guid, entry, phaseUseFlags, phaseid, phasegroup FROM transports"); uint32 count = 0; if (result) @@ -449,12 +445,50 @@ void TransportMgr::SpawnContinentTransports() Field* fields = result->Fetch(); ObjectGuid::LowType guid = fields[0].GetUInt64(); uint32 entry = fields[1].GetUInt32(); - uint32 phaseid = fields[2].GetUInt32(); - uint32 phasegroup = fields[3].GetUInt32(); + uint8 phaseUseFlags = fields[2].GetUInt8(); + uint32 phaseId = fields[3].GetUInt32(); + uint32 phaseGroupId = fields[4].GetUInt32(); + + if (phaseUseFlags & ~PHASE_USE_FLAGS_ALL) + { + TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) with unknown `phaseUseFlags` set, removed unknown value.", guid, entry); + phaseUseFlags &= PHASE_USE_FLAGS_ALL; + } + + if (phaseUseFlags & PHASE_USE_FLAGS_ALWAYS_VISIBLE && phaseUseFlags & PHASE_USE_FLAGS_INVERSE) + { + TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE," + " removing PHASE_USE_FLAGS_INVERSE.", guid, entry); + phaseUseFlags &= ~PHASE_USE_FLAGS_INVERSE; + } + + if (phaseGroupId && phaseId) + { + TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, entry); + phaseGroupId = 0; + } + + if (phaseId) + { + if (!sPhaseStore.LookupEntry(phaseId)) + { + TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) with `phaseid` %u does not exist, set to 0", guid, entry, phaseId); + phaseId = 0; + } + } + + if (phaseGroupId) + { + if (!sDB2Manager.GetPhasesForGroup(phaseGroupId)) + { + TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) with `phaseGroup` %u does not exist, set to 0", guid, entry, phaseGroupId); + phaseGroupId = 0; + } + } if (TransportTemplate const* tInfo = GetTransportTemplate(entry)) if (!tInfo->inInstance) - if (CreateTransport(entry, guid, nullptr, phaseid, phasegroup)) + if (CreateTransport(entry, guid, nullptr, phaseUseFlags, phaseId, phaseGroupId)) ++count; } while (result->NextRow()); diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index 902052200aa..aca00038205 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -114,7 +114,7 @@ class TC_GAME_API TransportMgr void LoadTransportAnimationAndRotation(); // Creates a transport using given GameObject template entry - Transport* CreateTransport(uint32 entry, ObjectGuid::LowType guid = UI64LIT(0), Map* map = nullptr, uint32 phaseid = 0, uint32 phasegroup = 0); + Transport* CreateTransport(uint32 entry, ObjectGuid::LowType guid = UI64LIT(0), Map* map = nullptr, uint8 phaseUseFlags = 0, uint32 phaseId = 0, uint32 phaseGroupId = 0); // Spawns all continent transports, used at core startup void SpawnContinentTransports(); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 8f8c8ab8d92..0f4135cad3a 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -212,16 +212,16 @@ enum TrinityStrings LANG_LIQUID_STATUS = 175, LANG_INVALID_GAMEOBJECT_TYPE = 176, LANG_GAMEOBJECT_DAMAGED = 177, + LANG_GRID_POSITION = 178, - LANG_PHASING_SUCCESS = 178, - LANG_PHASING_FAILED = 179, - LANG_PHASING_LAST_PHASE = 180, - LANG_PHASING_LIST = 181, - LANG_PHASING_PHASEMASK = 182, - LANG_PHASING_REPORT_STATUS = 183, - LANG_PHASING_NO_DEFINITIONS = 184, // Phasing + LANG_PHASESHIFT_STATUS = 179, + LANG_PHASESHIFT_PHASES = 180, + LANG_PHASESHIFT_VISIBLE_MAP_IDS = 181, + LANG_PHASESHIFT_UI_WORLD_MAP_AREA_SWAPS = 182, + LANG_PHASE_FLAG_COSMETIC = 183, + LANG_PHASE_FLAG_PERSONAL = 184, - LANG_GRID_POSITION = 185, + // 185 not used LANG_TRANSPORT_POSITION = 186, // Room for more level 1 187-199 not used diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 98e8863ee99..6d2c336cbc3 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -506,7 +506,7 @@ void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool if (_owner->IsFlying()) point.z = z; else - point.z = _owner->GetMap()->GetHeight(_owner->GetPhases(), point.x, point.y, z); + point.z = _owner->GetMap()->GetHeight(_owner->GetPhaseShift(), point.x, point.y, z); init.Path().push_back(point); } @@ -589,7 +589,7 @@ void MotionMaster::ResumeSplineChain(SplineChainResumeInfo const& info) void MotionMaster::MoveFall(uint32 id /*=0*/) { // use larger distance for vmap height search than in most other cases - float tz = _owner->GetMap()->GetHeight(_owner->GetPhases(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ(), true, MAX_FALL_DISTANCE); + float tz = _owner->GetMap()->GetHeight(_owner->GetPhaseShift(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ(), true, MAX_FALL_DISTANCE); if (tz <= INVALID_HEIGHT) { TC_LOG_DEBUG("misc", "MotionMaster::MoveFall: unable to retrieve a proper height at map %u (x: %f, y: %f, z: %f).", diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index 46443db4aa6..6603aeade68 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -64,7 +64,7 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature) // Limit height change const float distanceZ = float(rand_norm()) * travelDistZ/2.0f; destZ = respZ + distanceZ; - float levelZ = map->GetWaterOrGroundLevel(creature->GetPhases(), destX, destY, destZ-2.5f); + float levelZ = map->GetWaterOrGroundLevel(creature->GetPhaseShift(), destX, destY, destZ-2.5f); // Problem here, we must fly above the ground and water, not under. Let's try on next tick if (levelZ >= destZ) @@ -78,17 +78,17 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature) // The fastest way to get an accurate result 90% of the time. // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long. - destZ = map->GetHeight(creature->GetPhases(), destX, destY, respZ+travelDistZ-2.0f, false); + destZ = map->GetHeight(creature->GetPhaseShift(), destX, destY, respZ+travelDistZ-2.0f, false); if (std::fabs(destZ - respZ) > travelDistZ) // Map check { // Vmap Horizontal or above - destZ = map->GetHeight(creature->GetPhases(), destX, destY, respZ - 2.0f, true); + destZ = map->GetHeight(creature->GetPhaseShift(), destX, destY, respZ - 2.0f, true); if (std::fabs(destZ - respZ) > travelDistZ) { // Vmap Higher - destZ = map->GetHeight(creature->GetPhases(), destX, destY, respZ+travelDistZ-2.0f, true); + destZ = map->GetHeight(creature->GetPhaseShift(), destX, destY, respZ+travelDistZ-2.0f, true); // let's forget this bad coords where a z cannot be find and retry at next tick if (std::fabs(destZ - respZ) > travelDistZ) diff --git a/src/server/game/Phasing/PhaseShift.cpp b/src/server/game/Phasing/PhaseShift.cpp new file mode 100644 index 00000000000..b2885ae15bb --- /dev/null +++ b/src/server/game/Phasing/PhaseShift.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "PhaseShift.h" +#include "Containers.h" + +bool PhaseShift::AddPhase(uint32 phaseId, PhaseFlags flags, std::vector<Condition*> const* areaConditions, int32 references /*= 1*/) +{ + auto insertResult = Phases.emplace(phaseId, flags, nullptr); + ModifyPhasesReferences(insertResult.first, references); + if (areaConditions) + insertResult.first->AreaConditions = areaConditions; + + return insertResult.second; +} + +PhaseShift::EraseResult<PhaseShift::PhaseContainer> PhaseShift::RemovePhase(uint32 phaseId) +{ + auto itr = Phases.find(PhaseRef(phaseId, PhaseFlags::None, nullptr)); + if (itr != Phases.end()) + { + ModifyPhasesReferences(itr, -1); + if (!itr->References) + return { Phases.erase(itr), true }; + return { itr, false }; + } + return { Phases.end(), false }; +} + +bool PhaseShift::AddVisibleMapId(uint32 visibleMapId, TerrainSwapInfo const* visibleMapInfo, int32 references /*= 1*/) +{ + auto insertResult = VisibleMapIds.emplace(visibleMapId, VisibleMapIdRef{ 0, visibleMapInfo }); + insertResult.first->second.References += references; + return insertResult.second; +} + +PhaseShift::EraseResult<PhaseShift::VisibleMapIdContainer> PhaseShift::RemoveVisibleMapId(uint32 visibleMapId) +{ + auto itr = VisibleMapIds.find(visibleMapId); + if (itr != VisibleMapIds.end()) + { + if (!--itr->second.References) + return { VisibleMapIds.erase(itr), true }; + return { itr, false }; + } + return { VisibleMapIds.end(), false }; +} + +bool PhaseShift::AddUiWorldMapAreaIdSwap(uint32 uiWorldMapAreaId, int32 references /*= 1*/) +{ + auto insertResult = UiWorldMapAreaIdSwaps.emplace(uiWorldMapAreaId, UiWorldMapAreaIdSwapRef{ 0 }); + insertResult.first->second.References += references; + return insertResult.second; +} + +PhaseShift::EraseResult<PhaseShift::UiWorldMapAreaIdSwapContainer> PhaseShift::RemoveUiWorldMapAreaIdSwap(uint32 uiWorldMapAreaId) +{ + auto itr = UiWorldMapAreaIdSwaps.find(uiWorldMapAreaId); + if (itr != UiWorldMapAreaIdSwaps.end()) + { + if (!--itr->second.References) + return { UiWorldMapAreaIdSwaps.erase(itr), true }; + return { itr, false }; + } + return { UiWorldMapAreaIdSwaps.end(), false }; +} + +void PhaseShift::Clear() +{ + ClearPhases(); + PersonalGuid.Clear(); + VisibleMapIds.clear(); + UiWorldMapAreaIdSwaps.clear(); +} + +void PhaseShift::ClearPhases() +{ + Flags &= EnumClassFlag<PhaseShiftFlags>(PhaseShiftFlags::AlwaysVisible) | PhaseShiftFlags::Inverse; + Phases.clear(); + NonCosmeticReferences = 0; + CosmeticReferences = 0; + DefaultReferences = 0; + UpdateUnphasedFlag(); +} + +bool PhaseShift::CanSee(PhaseShift const& other) const +{ + if (Flags.HasFlag(PhaseShiftFlags::Unphased) && other.Flags.HasFlag(PhaseShiftFlags::Unphased)) + return true; + if (Flags.HasFlag(PhaseShiftFlags::AlwaysVisible) || other.Flags.HasFlag(PhaseShiftFlags::AlwaysVisible)) + return true; + if (Flags.HasFlag(PhaseShiftFlags::Inverse) && other.Flags.HasFlag(PhaseShiftFlags::Inverse)) + return true; + + PhaseFlags excludePhasesWithFlag = PhaseFlags::None; + if (Flags.HasFlag(PhaseShiftFlags::NoCosmetic) && other.Flags.HasFlag(PhaseShiftFlags::NoCosmetic)) + excludePhasesWithFlag = PhaseFlags::Cosmetic; + + if (!Flags.HasFlag(PhaseShiftFlags::Inverse) && !other.Flags.HasFlag(PhaseShiftFlags::Inverse)) + { + ObjectGuid ownerGuid = PersonalGuid; + ObjectGuid otherPersonalGuid = other.PersonalGuid; + return Trinity::Containers::Intersects(Phases.begin(), Phases.end(), other.Phases.begin(), other.Phases.end(), + [&ownerGuid, &otherPersonalGuid, excludePhasesWithFlag](PhaseRef const& myPhase, PhaseRef const& /*otherPhase*/) + { + return !myPhase.Flags.HasFlag(excludePhasesWithFlag) && (!myPhase.Flags.HasFlag(PhaseFlags::Personal) || ownerGuid == otherPersonalGuid); + }); + } + + auto checkInversePhaseShift = [excludePhasesWithFlag](PhaseShift const& phaseShift, PhaseShift const& excludedPhaseShift) + { + if (phaseShift.Flags.HasFlag(PhaseShiftFlags::Unphased) && !excludedPhaseShift.Flags.HasFlag(PhaseShiftFlags::InverseUnphased)) + return true; + + for (auto itr = phaseShift.Phases.begin(); itr != phaseShift.Phases.end(); ++itr) + { + if (itr->Flags.HasFlag(excludePhasesWithFlag)) + continue; + + auto itr2 = std::find(excludedPhaseShift.Phases.begin(), excludedPhaseShift.Phases.end(), *itr); + if (itr2 == excludedPhaseShift.Phases.end() || itr2->Flags.HasFlag(excludePhasesWithFlag)) + return true; + } + + return false; + }; + + if (other.Flags.HasFlag(PhaseShiftFlags::Inverse)) + return checkInversePhaseShift(*this, other); + + return checkInversePhaseShift(other, *this); +} + +void PhaseShift::ModifyPhasesReferences(PhaseContainer::iterator itr, int32 references) +{ + itr->References += references; + + if (!IsDbPhaseShift) + { + if (itr->Flags.HasFlag(PhaseFlags::Cosmetic)) + CosmeticReferences += references; + else if (itr->Id != DEFAULT_PHASE) + NonCosmeticReferences += references; + else + DefaultReferences += references; + + if (CosmeticReferences) + Flags |= PhaseShiftFlags::NoCosmetic; + else + Flags &= ~EnumClassFlag<PhaseShiftFlags>(PhaseShiftFlags::NoCosmetic); + + UpdateUnphasedFlag(); + } +} + +void PhaseShift::UpdateUnphasedFlag() +{ + EnumClassFlag<PhaseShiftFlags> unphasedFlag = !Flags.HasFlag(PhaseShiftFlags::Inverse) ? PhaseShiftFlags::Unphased : PhaseShiftFlags::InverseUnphased; + Flags &= ~EnumClassFlag<PhaseShiftFlags>(!Flags.HasFlag(PhaseShiftFlags::Inverse) ? PhaseShiftFlags::InverseUnphased : PhaseShiftFlags::Unphased); + if (NonCosmeticReferences && !DefaultReferences) + Flags &= ~unphasedFlag; + else + Flags |= unphasedFlag; +} diff --git a/src/server/game/Phasing/PhaseShift.h b/src/server/game/Phasing/PhaseShift.h new file mode 100644 index 00000000000..8755868ae9d --- /dev/null +++ b/src/server/game/Phasing/PhaseShift.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PhaseShift_h__ +#define PhaseShift_h__ + +#include "Define.h" +#include "EnumClassFlag.h" +#include "ObjectGuid.h" +#include <boost/container/flat_set.hpp> +#include <map> + +class PhasingHandler; +struct Condition; +struct TerrainSwapInfo; + +#define DEFAULT_PHASE 169 + +enum class PhaseShiftFlags : uint32 +{ + None = 0x00, + AlwaysVisible = 0x01, // Ignores all phasing, can see everything and be seen by everything + Inverse = 0x02, // By default having at least one shared phase for two objects means they can see each other + // this flag makes objects see each other if they have at least one non-shared phase + InverseUnphased = 0x04, + Unphased = 0x08, + NoCosmetic = 0x10 // This flag ignores shared cosmetic phases (two players that both have shared cosmetic phase but no other phase cannot see each other) +}; + +enum class PhaseFlags : uint16 +{ + None = 0x0, + Cosmetic = 0x1, + Personal = 0x2 +}; + +class TC_GAME_API PhaseShift +{ +public: + struct PhaseRef + { + PhaseRef(uint32 id, PhaseFlags flags, std::vector<Condition*> const* conditions) + : Id(id), Flags(flags), References(0), AreaConditions(conditions) { } + + uint16 Id; + EnumClassFlag<PhaseFlags> Flags; + int32 References; + std::vector<Condition*> const* AreaConditions; + bool operator<(PhaseRef const& right) const { return Id < right.Id; } + bool operator==(PhaseRef const& right) const { return Id == right.Id; } + }; + struct VisibleMapIdRef + { + int32 References = 0; + TerrainSwapInfo const* VisibleMapInfo = nullptr; + }; + struct UiWorldMapAreaIdSwapRef + { + int32 References = 0; + }; + template<typename Container> + struct EraseResult + { + typename Container::iterator Iterator; + bool Erased; + }; + typedef boost::container::flat_set<PhaseRef> PhaseContainer; + typedef std::map<uint32, VisibleMapIdRef> VisibleMapIdContainer; + typedef std::map<uint32, UiWorldMapAreaIdSwapRef> UiWorldMapAreaIdSwapContainer; + + bool AddPhase(uint32 phaseId, PhaseFlags flags, std::vector<Condition*> const* areaConditions, int32 references = 1); + EraseResult<PhaseContainer> RemovePhase(uint32 phaseId); + bool HasPhase(uint32 phaseId) const { return Phases.find(PhaseRef(phaseId, PhaseFlags::None, nullptr)) != Phases.end(); } + PhaseContainer const& GetPhases() const { return Phases; } + + bool AddVisibleMapId(uint32 visibleMapId, TerrainSwapInfo const* visibleMapInfo, int32 references = 1); + EraseResult<VisibleMapIdContainer> RemoveVisibleMapId(uint32 visibleMapId); + bool HasVisibleMapId(uint32 visibleMapId) const { return VisibleMapIds.find(visibleMapId) != VisibleMapIds.end(); } + VisibleMapIdContainer const& GetVisibleMapIds() const { return VisibleMapIds; } + + bool AddUiWorldMapAreaIdSwap(uint32 uiWorldMapAreaId, int32 references = 1); + EraseResult<UiWorldMapAreaIdSwapContainer> RemoveUiWorldMapAreaIdSwap(uint32 uiWorldMapAreaId); + bool HasUiWorldMapAreaIdSwap(uint32 uiWorldMapAreaId) const { return UiWorldMapAreaIdSwaps.find(uiWorldMapAreaId) != UiWorldMapAreaIdSwaps.end(); } + UiWorldMapAreaIdSwapContainer const& GetUiWorldMapAreaIdSwaps() const { return UiWorldMapAreaIdSwaps; } + + void Clear(); + void ClearPhases(); + + bool CanSee(PhaseShift const& other) const; + +protected: + friend class PhasingHandler; + + EnumClassFlag<PhaseShiftFlags> Flags = PhaseShiftFlags::Unphased; + ObjectGuid PersonalGuid; + PhaseContainer Phases; + VisibleMapIdContainer VisibleMapIds; + UiWorldMapAreaIdSwapContainer UiWorldMapAreaIdSwaps; + + void ModifyPhasesReferences(PhaseContainer::iterator itr, int32 references); + void UpdateUnphasedFlag(); + int32 NonCosmeticReferences = 0; + int32 CosmeticReferences = 0; + int32 DefaultReferences = 0; + bool IsDbPhaseShift = false; +}; + +#endif // PhaseShift_h__ diff --git a/src/server/game/Phasing/PhasingHandler.cpp b/src/server/game/Phasing/PhasingHandler.cpp new file mode 100644 index 00000000000..2f0fd7d870e --- /dev/null +++ b/src/server/game/Phasing/PhasingHandler.cpp @@ -0,0 +1,545 @@ +/* + * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "PhasingHandler.h" +#include "Chat.h" +#include "ConditionMgr.h" +#include "Creature.h" +#include "DB2Stores.h" +#include "Language.h" +#include "Map.h" +#include "MiscPackets.h" +#include "ObjectMgr.h" +#include "PartyPackets.h" +#include "PhaseShift.h" +#include "Player.h" +#include "SpellAuraEffects.h" + +namespace +{ +inline PhaseFlags GetPhaseFlags(uint32 phaseId) +{ + if (PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseId)) + { + if (phase->Flags & PHASE_FLAG_COSMETIC) + return PhaseFlags::Cosmetic; + + if (phase->Flags & PHASE_FLAG_PERSONAL) + return PhaseFlags::Personal; + } + + return PhaseFlags::None; +} + +template<typename Func> +inline void ForAllControlled(Unit* unit, Func&& func) +{ + for (Unit* controlled : unit->m_Controlled) + if (controlled->GetTypeId() != TYPEID_PLAYER) + func(controlled); + + for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i) + if (!unit->m_SummonSlot[i].IsEmpty()) + if (Creature* summon = unit->GetMap()->GetCreature(unit->m_SummonSlot[i])) + func(summon); +} +} + +void PhasingHandler::AddPhase(WorldObject* object, uint32 phaseId, bool updateVisibility) +{ + bool changed = object->GetPhaseShift().AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr); + + if (Unit* unit = object->ToUnit()) + { + unit->OnPhaseChange(); + ForAllControlled(unit, [&](Unit* controlled) + { + AddPhase(controlled, phaseId, updateVisibility); + }); + unit->RemoveNotOwnSingleTargetAuras(true); + } + + UpdateVisibilityIfNeeded(object, updateVisibility, changed); +} + +void PhasingHandler::RemovePhase(WorldObject* object, uint32 phaseId, bool updateVisibility) +{ + bool changed = object->GetPhaseShift().RemovePhase(phaseId).Erased; + + if (Unit* unit = object->ToUnit()) + { + unit->OnPhaseChange(); + ForAllControlled(unit, [&](Unit* controlled) + { + RemovePhase(controlled, phaseId, updateVisibility); + }); + unit->RemoveNotOwnSingleTargetAuras(true); + } + + UpdateVisibilityIfNeeded(object, updateVisibility, changed); +} + +void PhasingHandler::AddPhaseGroup(WorldObject* object, uint32 phaseGroupId, bool updateVisibility) +{ + std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(phaseGroupId); + if (!phasesInGroup) + return; + + bool changed = false; + for (uint32 phaseId : *phasesInGroup) + changed = object->GetPhaseShift().AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr) || changed; + + if (Unit* unit = object->ToUnit()) + { + unit->OnPhaseChange(); + ForAllControlled(unit, [&](Unit* controlled) + { + AddPhaseGroup(controlled, phaseGroupId, updateVisibility); + }); + unit->RemoveNotOwnSingleTargetAuras(true); + } + + UpdateVisibilityIfNeeded(object, updateVisibility, changed); +} + +void PhasingHandler::RemovePhaseGroup(WorldObject* object, uint32 phaseGroupId, bool updateVisibility) +{ + std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(phaseGroupId); + if (!phasesInGroup) + return; + + bool changed = false; + for (uint32 phaseId : *phasesInGroup) + changed = object->GetPhaseShift().RemovePhase(phaseId).Erased || changed; + + if (Unit* unit = object->ToUnit()) + { + unit->OnPhaseChange(); + ForAllControlled(unit, [&](Unit* controlled) + { + RemovePhaseGroup(controlled, phaseGroupId, updateVisibility); + }); + unit->RemoveNotOwnSingleTargetAuras(true); + } + + UpdateVisibilityIfNeeded(object, updateVisibility, changed); +} + +void PhasingHandler::AddVisibleMapId(WorldObject* object, uint32 visibleMapId) +{ + TerrainSwapInfo const* terrainSwapInfo = sObjectMgr->GetTerrainSwapInfo(visibleMapId); + bool changed = object->GetPhaseShift().AddVisibleMapId(visibleMapId, terrainSwapInfo); + + for (uint32 uiWorldMapAreaIDSwap : terrainSwapInfo->UiWorldMapAreaIDSwaps) + changed = object->GetPhaseShift().AddUiWorldMapAreaIdSwap(uiWorldMapAreaIDSwap) || changed; + + if (Unit* unit = object->ToUnit()) + { + ForAllControlled(unit, [&](Unit* controlled) + { + AddVisibleMapId(controlled, visibleMapId); + }); + } + + UpdateVisibilityIfNeeded(object, false, changed); +} + +void PhasingHandler::RemoveVisibleMapId(WorldObject* object, uint32 visibleMapId) +{ + TerrainSwapInfo const* terrainSwapInfo = sObjectMgr->GetTerrainSwapInfo(visibleMapId); + bool changed = object->GetPhaseShift().RemoveVisibleMapId(visibleMapId).Erased; + + for (uint32 uiWorldMapAreaIDSwap : terrainSwapInfo->UiWorldMapAreaIDSwaps) + changed = object->GetPhaseShift().RemoveUiWorldMapAreaIdSwap(uiWorldMapAreaIDSwap).Erased || changed; + + if (Unit* unit = object->ToUnit()) + { + ForAllControlled(unit, [&](Unit* controlled) + { + RemoveVisibleMapId(controlled, visibleMapId); + }); + } + + UpdateVisibilityIfNeeded(object, false, changed); +} + +void PhasingHandler::ResetPhaseShift(WorldObject* object) +{ + object->GetPhaseShift().Clear(); + object->GetSuppressedPhaseShift().Clear(); +} + +void PhasingHandler::InheritPhaseShift(WorldObject* target, WorldObject const* source) +{ + target->GetPhaseShift() = source->GetPhaseShift(); + target->GetSuppressedPhaseShift() = source->GetSuppressedPhaseShift(); +} + +void PhasingHandler::OnMapChange(WorldObject* object) +{ + PhaseShift& phaseShift = object->GetPhaseShift(); + PhaseShift& suppressedPhaseShift = object->GetSuppressedPhaseShift(); + ConditionSourceInfo srcInfo = ConditionSourceInfo(object); + + object->GetPhaseShift().VisibleMapIds.clear(); + object->GetPhaseShift().UiWorldMapAreaIdSwaps.clear(); + object->GetSuppressedPhaseShift().VisibleMapIds.clear(); + + if (std::vector<TerrainSwapInfo*> const* visibleMapIds = sObjectMgr->GetTerrainSwapsForMap(object->GetMapId())) + { + for (TerrainSwapInfo const* visibleMapInfo : *visibleMapIds) + { + if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, visibleMapInfo->Id, srcInfo)) + { + phaseShift.AddVisibleMapId(visibleMapInfo->Id, visibleMapInfo); + for (uint32 uiWorldMapAreaIdSwap : visibleMapInfo->UiWorldMapAreaIDSwaps) + phaseShift.AddUiWorldMapAreaIdSwap(uiWorldMapAreaIdSwap); + } + else + suppressedPhaseShift.AddVisibleMapId(visibleMapInfo->Id, visibleMapInfo); + } + } + + UpdateVisibilityIfNeeded(object, false, true); +} + +void PhasingHandler::OnAreaChange(WorldObject* object) +{ + PhaseShift& phaseShift = object->GetPhaseShift(); + PhaseShift& suppressedPhaseShift = object->GetSuppressedPhaseShift(); + PhaseShift::PhaseContainer oldPhases = std::move(phaseShift.Phases); // for comparison + ConditionSourceInfo srcInfo = ConditionSourceInfo(object); + + object->GetPhaseShift().ClearPhases(); + object->GetSuppressedPhaseShift().ClearPhases(); + + uint32 areaId = object->GetAreaId(); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId); + while (areaEntry) + { + if (std::vector<PhaseAreaInfo> const* newAreaPhases = sObjectMgr->GetPhasesForArea(areaEntry->ID)) + { + for (PhaseAreaInfo const& phaseArea : *newAreaPhases) + { + if (phaseArea.SubAreaExclusions.find(areaId) != phaseArea.SubAreaExclusions.end()) + continue; + + uint32 phaseId = phaseArea.PhaseInfo->Id; + if (sConditionMgr->IsObjectMeetToConditions(srcInfo, phaseArea.Conditions)) + phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), &phaseArea.Conditions); + else + suppressedPhaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), &phaseArea.Conditions); + } + } + + areaEntry = sAreaTableStore.LookupEntry(areaEntry->ParentAreaID); + } + + bool changed = phaseShift.Phases != oldPhases; + if (Unit* unit = object->ToUnit()) + { + for (AuraEffect const* aurEff : unit->GetAuraEffectsByType(SPELL_AURA_PHASE)) + { + uint32 phaseId = uint32(aurEff->GetMiscValueB()); + changed = phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr) || changed; + } + + for (AuraEffect const* aurEff : unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP)) + if (std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(uint32(aurEff->GetMiscValueB()))) + for (uint32 phaseId : *phasesInGroup) + changed = phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr) || changed; + + if (changed) + unit->OnPhaseChange(); + + ForAllControlled(unit, [&](Unit* controlled) + { + InheritPhaseShift(controlled, unit); + }); + + if (changed) + unit->RemoveNotOwnSingleTargetAuras(true); + } + + UpdateVisibilityIfNeeded(object, true, changed); +} + +void PhasingHandler::OnConditionChange(WorldObject* object) +{ + PhaseShift& phaseShift = object->GetPhaseShift(); + PhaseShift& suppressedPhaseShift = object->GetSuppressedPhaseShift(); + PhaseShift newSuppressions; + ConditionSourceInfo srcInfo = ConditionSourceInfo(object); + bool changed = false; + + for (auto itr = phaseShift.Phases.begin(); itr != phaseShift.Phases.end();) + { + if (itr->AreaConditions && !sConditionMgr->IsObjectMeetToConditions(srcInfo, *itr->AreaConditions)) + { + newSuppressions.AddPhase(itr->Id, itr->Flags, itr->AreaConditions, itr->References); + itr = phaseShift.Phases.erase(itr); + } + else + ++itr; + } + + for (auto itr = suppressedPhaseShift.Phases.begin(); itr != suppressedPhaseShift.Phases.end();) + { + if (sConditionMgr->IsObjectMeetToConditions(srcInfo, *ASSERT_NOTNULL(itr->AreaConditions))) + { + changed = phaseShift.AddPhase(itr->Id, itr->Flags, itr->AreaConditions, itr->References) || changed; + itr = suppressedPhaseShift.Phases.erase(itr); + } + else + ++itr; + } + + for (auto itr = phaseShift.VisibleMapIds.begin(); itr != phaseShift.VisibleMapIds.end();) + { + if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, itr->first, srcInfo)) + { + newSuppressions.AddVisibleMapId(itr->first, itr->second.VisibleMapInfo, itr->second.References); + for (uint32 uiWorldMapAreaIdSwap : itr->second.VisibleMapInfo->UiWorldMapAreaIDSwaps) + changed = phaseShift.RemoveUiWorldMapAreaIdSwap(uiWorldMapAreaIdSwap).Erased || changed; + + itr = phaseShift.VisibleMapIds.erase(itr); + } + else + ++itr; + } + + for (auto itr = suppressedPhaseShift.VisibleMapIds.begin(); itr != suppressedPhaseShift.VisibleMapIds.end();) + { + if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, itr->first, srcInfo)) + { + changed = phaseShift.AddVisibleMapId(itr->first, itr->second.VisibleMapInfo, itr->second.References) || changed; + for (uint32 uiWorldMapAreaIdSwap : itr->second.VisibleMapInfo->UiWorldMapAreaIDSwaps) + changed = phaseShift.AddUiWorldMapAreaIdSwap(uiWorldMapAreaIdSwap) || changed; + + itr = suppressedPhaseShift.VisibleMapIds.erase(itr); + } + else + ++itr; + } + + Unit* unit = object->ToUnit(); + if (unit) + { + for (AuraEffect const* aurEff : unit->GetAuraEffectsByType(SPELL_AURA_PHASE)) + { + uint32 phaseId = uint32(aurEff->GetMiscValueB()); + auto eraseResult = newSuppressions.RemovePhase(phaseId); + // if condition was met previously there is nothing to erase + if (eraseResult.Iterator != newSuppressions.Phases.end() || eraseResult.Erased) + phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr); + } + + for (AuraEffect const* aurEff : unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP)) + { + if (std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(uint32(aurEff->GetMiscValueB()))) + { + for (uint32 phaseId : *phasesInGroup) + { + auto eraseResult = newSuppressions.RemovePhase(phaseId); + // if condition was met previously there is nothing to erase + if (eraseResult.Iterator != newSuppressions.Phases.end() || eraseResult.Erased) + phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr); + } + } + } + } + + changed = changed || !newSuppressions.Phases.empty() || !newSuppressions.VisibleMapIds.empty(); + for (auto itr = newSuppressions.Phases.begin(); itr != newSuppressions.Phases.end(); ++itr) + suppressedPhaseShift.AddPhase(itr->Id, itr->Flags, itr->AreaConditions, itr->References); + + for (auto itr = newSuppressions.VisibleMapIds.begin(); itr != newSuppressions.VisibleMapIds.end(); ++itr) + suppressedPhaseShift.AddVisibleMapId(itr->first, itr->second.VisibleMapInfo, itr->second.References); + + if (unit) + { + if (changed) + unit->OnPhaseChange(); + + ForAllControlled(unit, [&](Unit* controlled) + { + InheritPhaseShift(controlled, unit); + }); + + if (changed) + unit->RemoveNotOwnSingleTargetAuras(true); + } + + UpdateVisibilityIfNeeded(object, true, changed); +} + +void PhasingHandler::SendToPlayer(Player const* player, PhaseShift const& phaseShift) +{ + WorldPackets::Misc::PhaseShiftChange phaseShiftChange; + phaseShiftChange.Client = player->GetGUID(); + phaseShiftChange.Phaseshift.PhaseShiftFlags = phaseShift.Flags.AsUnderlyingType(); + phaseShiftChange.Phaseshift.PersonalGUID = phaseShift.PersonalGuid; + phaseShiftChange.Phaseshift.Phases.reserve(phaseShift.Phases.size()); + std::transform(phaseShift.Phases.begin(), phaseShift.Phases.end(), std::back_inserter(phaseShiftChange.Phaseshift.Phases), + [](PhaseShift::PhaseRef const& phase) -> WorldPackets::Misc::PhaseShiftDataPhase { return { phase.Flags.AsUnderlyingType(), phase.Id }; }); + phaseShiftChange.VisibleMapIDs.reserve(phaseShift.VisibleMapIds.size()); + std::transform(phaseShift.VisibleMapIds.begin(), phaseShift.VisibleMapIds.end(), std::back_inserter(phaseShiftChange.VisibleMapIDs), + [](PhaseShift::VisibleMapIdContainer::value_type const& visibleMapId) { return visibleMapId.first; }); + phaseShiftChange.UiWorldMapAreaIDSwaps.reserve(phaseShift.UiWorldMapAreaIdSwaps.size()); + std::transform(phaseShift.UiWorldMapAreaIdSwaps.begin(), phaseShift.UiWorldMapAreaIdSwaps.end(), std::back_inserter(phaseShiftChange.UiWorldMapAreaIDSwaps), + [](PhaseShift::UiWorldMapAreaIdSwapContainer::value_type const& uiWorldMapAreaIdSwap) { return uiWorldMapAreaIdSwap.first; }); + + player->SendDirectMessage(phaseShiftChange.Write()); +} + +void PhasingHandler::SendToPlayer(Player const* player) +{ + SendToPlayer(player, player->GetPhaseShift()); +} + +void PhasingHandler::FillPartyMemberPhase(WorldPackets::Party::PartyMemberPhaseStates* partyMemberPhases, PhaseShift const& phaseShift) +{ + partyMemberPhases->PhaseShiftFlags = phaseShift.Flags.AsUnderlyingType(); + partyMemberPhases->PersonalGUID = phaseShift.PersonalGuid; + partyMemberPhases->List.reserve(phaseShift.Phases.size()); + std::transform(phaseShift.Phases.begin(), phaseShift.Phases.end(), std::back_inserter(partyMemberPhases->List), + [](PhaseShift::PhaseRef const& phase) -> WorldPackets::Party::PartyMemberPhase { return { phase.Flags.AsUnderlyingType(), phase.Id }; }); +} + +void PhasingHandler::InitDbPhaseShift(PhaseShift& phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId) +{ + phaseShift.IsDbPhaseShift = true; + + EnumClassFlag<PhaseShiftFlags> flags = PhaseShiftFlags::None; + if (phaseUseFlags & PHASE_USE_FLAGS_ALWAYS_VISIBLE) + flags = flags | PhaseShiftFlags::AlwaysVisible | PhaseShiftFlags::Unphased; + if (phaseUseFlags & PHASE_USE_FLAGS_INVERSE) + flags |= PhaseShiftFlags::Inverse; + + if (phaseId) + phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr); + else if (std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(phaseGroupId)) + for (uint32 phaseInGroup : *phasesInGroup) + phaseShift.AddPhase(phaseInGroup, GetPhaseFlags(phaseInGroup), nullptr); + + if (phaseShift.Phases.empty() || phaseShift.HasPhase(DEFAULT_PHASE)) + { + if (flags.HasFlag(PhaseShiftFlags::Inverse)) + flags |= PhaseShiftFlags::InverseUnphased; + else + flags |= PhaseShiftFlags::Unphased; + } + + phaseShift.Flags = flags; +} + +void PhasingHandler::InitDbVisibleMapId(PhaseShift& phaseShift, int32 visibleMapId) +{ + if (visibleMapId != -1) + phaseShift.AddVisibleMapId(visibleMapId, sObjectMgr->GetTerrainSwapInfo(visibleMapId)); +} + +bool PhasingHandler::InDbPhaseShift(WorldObject const* object, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId) +{ + PhaseShift phaseShift; + InitDbPhaseShift(phaseShift, phaseUseFlags, phaseId, phaseGroupId); + return object->GetPhaseShift().CanSee(phaseShift); +} + +void PhasingHandler::SetAlwaysVisible(PhaseShift& phaseShift, bool apply) +{ + if (apply) + phaseShift.Flags |= PhaseShiftFlags::AlwaysVisible; + else + phaseShift.Flags &= ~EnumClassFlag<PhaseShiftFlags>(PhaseShiftFlags::AlwaysVisible); +} + +void PhasingHandler::SetInversed(PhaseShift& phaseShift, bool apply) +{ + if (apply) + phaseShift.Flags |= PhaseShiftFlags::Inverse; + else + phaseShift.Flags &= ~EnumClassFlag<PhaseShiftFlags>(PhaseShiftFlags::Inverse); + + phaseShift.UpdateUnphasedFlag(); +} + +void PhasingHandler::PrintToChat(ChatHandler* chat, PhaseShift const& phaseShift) +{ + chat->PSendSysMessage(LANG_PHASESHIFT_STATUS, phaseShift.Flags.AsUnderlyingType(), phaseShift.PersonalGuid.ToString().c_str()); + if (!phaseShift.Phases.empty()) + { + std::ostringstream phases; + std::string cosmetic = sObjectMgr->GetTrinityString(LANG_PHASE_FLAG_COSMETIC, chat->GetSessionDbLocaleIndex()); + std::string personal = sObjectMgr->GetTrinityString(LANG_PHASE_FLAG_PERSONAL, chat->GetSessionDbLocaleIndex()); + for (PhaseShift::PhaseRef const& phase : phaseShift.Phases) + { + phases << phase.Id; + if (phase.Flags.HasFlag(PhaseFlags::Cosmetic)) + phases << ' ' << '(' << cosmetic << ')'; + if (phase.Flags.HasFlag(PhaseFlags::Personal)) + phases << ' ' << '(' << personal << ')'; + phases << ", "; + } + + chat->PSendSysMessage(LANG_PHASESHIFT_PHASES, phases.str().c_str()); + } + + if (!phaseShift.VisibleMapIds.empty()) + { + std::ostringstream visibleMapIds; + for (PhaseShift::VisibleMapIdContainer::value_type const& visibleMapId : phaseShift.VisibleMapIds) + visibleMapIds << visibleMapId.first << ',' << ' '; + + chat->PSendSysMessage(LANG_PHASESHIFT_VISIBLE_MAP_IDS, visibleMapIds.str().c_str()); + } + + if (!phaseShift.UiWorldMapAreaIdSwaps.empty()) + { + std::ostringstream uiWorldMapAreaIdSwaps; + for (PhaseShift::UiWorldMapAreaIdSwapContainer::value_type const& uiWorldMapAreaIdSwap : phaseShift.UiWorldMapAreaIdSwaps) + uiWorldMapAreaIdSwaps << uiWorldMapAreaIdSwap.first << ',' << ' '; + + chat->PSendSysMessage(LANG_PHASESHIFT_UI_WORLD_MAP_AREA_SWAPS, uiWorldMapAreaIdSwaps.str().c_str()); + } +} + +std::string PhasingHandler::FormatPhases(PhaseShift const& phaseShift) +{ + std::ostringstream phases; + for (PhaseShift::PhaseRef const& phase : phaseShift.Phases) + phases << phase.Id << ','; + + return phases.str(); +} + +void PhasingHandler::UpdateVisibilityIfNeeded(WorldObject* object, bool updateVisibility, bool changed) +{ + if (changed && object->IsInWorld()) + { + if (Player* player = object->ToPlayer()) + SendToPlayer(player); + + if (updateVisibility) + { + if (Player* player = object->ToPlayer()) + player->GetMap()->SendUpdateTransportVisibility(player); + + object->UpdateObjectVisibility(); + } + } +} diff --git a/src/server/game/Phasing/PhasingHandler.h b/src/server/game/Phasing/PhasingHandler.h new file mode 100644 index 00000000000..e759f2e68e1 --- /dev/null +++ b/src/server/game/Phasing/PhasingHandler.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PhasingHandler_h__ +#define PhasingHandler_h__ + +#include "Define.h" +#include <string> + +class ChatHandler; +class PhaseShift; +class Player; +class WorldObject; +namespace WorldPackets +{ + namespace Party + { + struct PartyMemberPhaseStates; + } +} + +class TC_GAME_API PhasingHandler +{ +public: + static void AddPhase(WorldObject* object, uint32 phaseId, bool updateVisibility); + static void RemovePhase(WorldObject* object, uint32 phaseId, bool updateVisibility); + static void AddPhaseGroup(WorldObject* object, uint32 phaseGroupId, bool updateVisibility); + static void RemovePhaseGroup(WorldObject* object, uint32 phaseGroupId, bool updateVisibility); + + static void AddVisibleMapId(WorldObject* object, uint32 visibleMapId); + static void RemoveVisibleMapId(WorldObject* object, uint32 visibleMapId); + + static void ResetPhaseShift(WorldObject* object); + static void InheritPhaseShift(WorldObject* target, WorldObject const* source); + + static void OnMapChange(WorldObject* object); + static void OnAreaChange(WorldObject* object); + static void OnConditionChange(WorldObject* object); + + static void SendToPlayer(Player const* player, PhaseShift const& phaseShift); + static void SendToPlayer(Player const* player); + static void FillPartyMemberPhase(WorldPackets::Party::PartyMemberPhaseStates* partyMemberPhases, PhaseShift const& phaseShift); + + static void InitDbPhaseShift(PhaseShift& phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId); + static void InitDbVisibleMapId(PhaseShift& phaseShift, int32 visibleMapId); + static bool InDbPhaseShift(WorldObject const* object, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId); + + static void SetAlwaysVisible(PhaseShift& phaseShift, bool apply); + static void SetInversed(PhaseShift& phaseShift, bool apply); + + static void PrintToChat(ChatHandler* chat, PhaseShift const& phaseShift); + static std::string FormatPhases(PhaseShift const& phaseShift); + +private: + static void UpdateVisibilityIfNeeded(WorldObject* object, bool updateVisibility, bool changed); +}; + +#endif // PhasingHandler_h__ diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp index e5795b6b7f4..a03f1ff35fc 100644 --- a/src/server/game/Server/Packets/MiscPackets.cpp +++ b/src/server/game/Server/Packets/MiscPackets.cpp @@ -376,29 +376,39 @@ WorldPacket const* WorldPackets::Misc::RandomRoll::Write() return &_worldPacket; } -WorldPacket const* WorldPackets::Misc::PhaseShift::Write() +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Misc::PhaseShiftDataPhase const& phaseShiftDataPhase) { - _worldPacket << ClientGUID; // CLientGUID - _worldPacket << uint32(PhaseShifts.size() ? 0 : 8); // PhaseShiftFlags - _worldPacket << uint32(PhaseShifts.size()); // PhaseShiftCount - _worldPacket << PersonalGUID; // PersonalGUID - for (uint32 phase : PhaseShifts) - { - _worldPacket << uint16(1); // PhaseFlags - _worldPacket << uint16(phase); // PhaseID - } + data << uint16(phaseShiftDataPhase.PhaseFlags); + data << uint16(phaseShiftDataPhase.Id); + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Misc::PhaseShiftData const& phaseShiftData) +{ + data << uint32(phaseShiftData.PhaseShiftFlags); + data << uint32(phaseShiftData.Phases.size()); + data << phaseShiftData.PersonalGUID; + for (WorldPackets::Misc::PhaseShiftDataPhase const& phaseShiftDataPhase : phaseShiftData.Phases) + data << phaseShiftDataPhase; + + return data; +} - _worldPacket << uint32(VisibleMapIDs.size() * 2); // Active terrain swaps size - for (uint32 map : VisibleMapIDs) - _worldPacket << uint16(map); // Active terrain swap map id +WorldPacket const* WorldPackets::Misc::PhaseShiftChange::Write() +{ + _worldPacket << Client; + _worldPacket << Phaseshift; + _worldPacket << uint32(VisibleMapIDs.size() * 2); // size in bytes + for (uint16 visibleMapId : VisibleMapIDs) + _worldPacket << uint16(visibleMapId); // Active terrain swap map id - _worldPacket << uint32(PreloadMapIDs.size() * 2); // Inactive terrain swaps size - for (uint32 map : PreloadMapIDs) - _worldPacket << uint16(map); // Inactive terrain swap map id + _worldPacket << uint32(PreloadMapIDs.size() * 2); // size in bytes + for (uint16 preloadMapId : PreloadMapIDs) + _worldPacket << uint16(preloadMapId); // Inactive terrain swap map id - _worldPacket << uint32(UiWorldMapAreaIDSwaps.size() * 2); // UI map swaps size - for (uint32 map : UiWorldMapAreaIDSwaps) - _worldPacket << uint16(map); // UI map id, WorldMapArea.dbc, controls map display + _worldPacket << uint32(UiWorldMapAreaIDSwaps.size() * 2); // size in bytes + for (uint16 uiWorldMapAreaIDSwap : UiWorldMapAreaIDSwaps) + _worldPacket << uint16(uiWorldMapAreaIDSwap); // UI map id, WorldMapArea.db2, controls map display return &_worldPacket; } diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h index e875885864f..26affbaf934 100644 --- a/src/server/game/Server/Packets/MiscPackets.h +++ b/src/server/game/Server/Packets/MiscPackets.h @@ -28,7 +28,6 @@ #include "SharedDefines.h" #include <array> #include <map> -#include <set> enum MountStatusFlags : uint8; enum UnitStandStateType : uint8; @@ -529,19 +528,31 @@ namespace WorldPackets WorldPacket const* Write() override { return &_worldPacket; } }; - class PhaseShift final : public ServerPacket + struct PhaseShiftDataPhase + { + uint16 PhaseFlags = 0; + uint16 Id = 0; + }; + + struct PhaseShiftData + { + uint32 PhaseShiftFlags = 0; + std::vector<PhaseShiftDataPhase> Phases; + ObjectGuid PersonalGUID; + }; + + class PhaseShiftChange final : public ServerPacket { public: - PhaseShift() : ServerPacket(SMSG_PHASE_SHIFT_CHANGE, 4) { } + PhaseShiftChange() : ServerPacket(SMSG_PHASE_SHIFT_CHANGE, 16 + 4 + 4 + 16 + 4 + 4 + 4) { } WorldPacket const* Write() override; - ObjectGuid ClientGUID; - ObjectGuid PersonalGUID; - std::set<uint32> PhaseShifts; - std::set<uint32> PreloadMapIDs; - std::set<uint32> UiWorldMapAreaIDSwaps; - std::set<uint32> VisibleMapIDs; + ObjectGuid Client; + PhaseShiftData Phaseshift; + std::vector<uint16> PreloadMapIDs; + std::vector<uint16> UiWorldMapAreaIDSwaps; + std::vector<uint16> VisibleMapIDs; }; class ZoneUnderAttack final : public ServerPacket diff --git a/src/server/game/Server/Packets/PartyPackets.cpp b/src/server/game/Server/Packets/PartyPackets.cpp index d3d1f45995d..939f0a65db1 100644 --- a/src/server/game/Server/Packets/PartyPackets.cpp +++ b/src/server/game/Server/Packets/PartyPackets.cpp @@ -17,6 +17,7 @@ #include "PartyPackets.h" #include "Pet.h" +#include "PhasingHandler.h" #include "Player.h" #include "Realm.h" #include "SpellAuraEffects.h" @@ -625,16 +626,7 @@ void WorldPackets::Party::PartyMemberState::Initialize(Player const* player) } // Phases - std::set<uint32> const& phases = player->GetPhases(); - MemberStats.Phases.PhaseShiftFlags = 0x08 | (phases.size() ? 0x10 : 0); - MemberStats.Phases.PersonalGUID = ObjectGuid::Empty; - for (uint32 phaseId : phases) - { - WorldPackets::Party::PartyMemberPhase phase; - phase.Id = phaseId; - phase.Flags = 1; - MemberStats.Phases.List.push_back(phase); - } + PhasingHandler::FillPartyMemberPhase(&MemberStats.Phases, player->GetPhaseShift()); // Pet if (player->GetPet()) diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 9de54534f0e..7346b14d312 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -31,7 +31,6 @@ #include "QueryCallbackProcessor.h" #include "SharedDefines.h" #include <array> -#include <set> #include <unordered_map> #include <unordered_set> @@ -908,7 +907,6 @@ class TC_GAME_API WorldSession void SendNotification(uint32 stringId, ...); void SendPetNameInvalid(uint32 error, std::string const& name, DeclinedName *declinedName); void SendPartyResult(PartyOperation operation, std::string const& member, PartyResult res, uint32 val = 0); - void SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps, std::set<uint32> const& worldMapAreaSwaps); void SendQueryTimeResponse(); void SendAuthResponse(uint32 code, bool queued, uint32 queuePos = 0); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index d4367398ba6..8347202166d 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -34,6 +34,7 @@ #include "Opcodes.h" #include "OutdoorPvPMgr.h" #include "Pet.h" +#include "PhasingHandler.h" #include "Player.h" #include "ReputationMgr.h" #include "ScriptMgr.h" @@ -1671,27 +1672,17 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app Unit* target = aurApp->GetTarget(); - std::set<uint32> const& oldPhases = target->GetPhases(); - target->SetInPhase(GetMiscValueB(), false, apply); - - // call functions which may have additional effects after chainging state of unit - // phase auras normally not expected at BG but anyway better check if (apply) { + PhasingHandler::AddPhase(target, uint32(GetMiscValueB()), true); + + // call functions which may have additional effects after chainging state of unit + // phase auras normally not expected at BG but anyway better check // drop flag at invisibiliy in bg target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); } - - if (Player* player = target->ToPlayer()) - { - if (player->IsInWorld()) - player->GetMap()->SendUpdateTransportVisibility(player, oldPhases); - player->SendUpdatePhasing(); - } - - // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases) - if (target->IsVisible()) - target->UpdateObjectVisibility(); + else + PhasingHandler::RemovePhase(target, uint32(GetMiscValueB()), true); } void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -1701,29 +1692,17 @@ void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, boo Unit* target = aurApp->GetTarget(); - std::set<uint32> const& oldPhases = target->GetPhases(); - std::set<uint32> phases = sDB2Manager.GetPhasesForGroup(GetMiscValueB()); - for (auto phase : phases) - target->SetInPhase(phase, false, apply); - - // call functions which may have additional effects after chainging state of unit - // phase auras normally not expected at BG but anyway better check if (apply) { + PhasingHandler::AddPhaseGroup(target, uint32(GetMiscValueB()), true); + + // call functions which may have additional effects after chainging state of unit + // phase auras normally not expected at BG but anyway better check // drop flag at invisibiliy in bg target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); } - - if (Player* player = target->ToPlayer()) - { - if (player->IsInWorld()) - player->GetMap()->SendUpdateTransportVisibility(player, oldPhases); - player->SendUpdatePhasing(); - } - - // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases) - if (target->IsVisible()) - target->UpdateObjectVisibility(); + else + PhasingHandler::RemovePhaseGroup(target, uint32(GetMiscValueB()), true); } /**********************/ @@ -5964,7 +5943,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con DamageInfo dotDamageInfo(damageInfo, DOT, BASE_ATTACK, hitMask); caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dotDamageInfo, nullptr); - + caster->SendSpellNonMeleeDamageLog(&damageInfo); } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 912de1a315d..0763be83110 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1302,7 +1302,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici float angle = float(rand_norm()) * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f); m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dist, angle); - float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhases(), x, y, z, true, 50.0f); + float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhaseShift(), x, y, z, true, 50.0f); float liquidLevel = VMAP_INVALID_HEIGHT_VALUE; LiquidData liquidData; if (m_caster->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData)) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index ceafaaf797f..a03b124f4b4 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -51,6 +51,7 @@ #include "OutdoorPvPMgr.h" #include "PathGenerator.h" #include "Pet.h" +#include "PhasingHandler.h" #include "Player.h" #include "ReputationMgr.h" #include "ScriptMgr.h" @@ -3086,7 +3087,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) if (!go) return; - go->CopyPhaseFrom(m_caster); + PhasingHandler::InheritPhaseShift(go, m_caster); int32 duration = m_spellInfo->CalcDuration(m_caster); @@ -3105,7 +3106,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) if (GameObject* linkedTrap = go->GetLinkedTrap()) { - linkedTrap->CopyPhaseFrom(m_caster); + PhasingHandler::InheritPhaseShift(linkedTrap , m_caster); linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0); linkedTrap->SetSpellId(m_spellInfo->Id); @@ -3641,7 +3642,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex) if (!go) return; - go->CopyPhaseFrom(m_caster); + PhasingHandler::InheritPhaseShift(go, m_caster); go->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction()); go->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1); @@ -3971,7 +3972,7 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex) if (!go) return; - go->CopyPhaseFrom(m_caster); + PhasingHandler::InheritPhaseShift(go, m_caster); //go->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); int32 duration = m_spellInfo->CalcDuration(m_caster); @@ -4654,7 +4655,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) if (!go) return; - go->CopyPhaseFrom(m_caster); + PhasingHandler::InheritPhaseShift(go, m_caster); int32 duration = m_spellInfo->CalcDuration(m_caster); @@ -4717,7 +4718,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) if (GameObject* linkedTrap = go->GetLinkedTrap()) { - linkedTrap->CopyPhaseFrom(m_caster); + PhasingHandler::InheritPhaseShift(linkedTrap, m_caster); linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0); //linkedTrap->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); @@ -5713,7 +5714,7 @@ void Spell::EffectUpdatePlayerPhase(SpellEffIndex /*effIndex*/) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - unitTarget->UpdateAreaAndZonePhase(); + PhasingHandler::OnConditionChange(unitTarget); } void Spell::EffectUpdateZoneAurasAndPhases(SpellEffIndex /*effIndex*/) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 93d4cdebadd..65f5f9bd59c 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1972,17 +1972,7 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading World States..."); // must be loaded before battleground, outdoor PvP and conditions LoadWorldStates(); - TC_LOG_INFO("server.loading", "Loading Terrain Phase definitions..."); - sObjectMgr->LoadTerrainPhaseInfo(); - - TC_LOG_INFO("server.loading", "Loading Terrain Swap Default definitions..."); - sObjectMgr->LoadTerrainSwapDefaults(); - - TC_LOG_INFO("server.loading", "Loading Terrain World Map definitions..."); - sObjectMgr->LoadTerrainWorldMaps(); - - TC_LOG_INFO("server.loading", "Loading Phase Area definitions..."); - sObjectMgr->LoadAreaPhases(); + sObjectMgr->LoadPhases(); TC_LOG_INFO("server.loading", "Loading Conditions..."); sConditionMgr->LoadConditions(); |