aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatan Shukry <matanshukry@gmail.com>2021-12-28 14:24:10 +0200
committerGitHub <noreply@github.com>2021-12-28 13:24:10 +0100
commit8fabe5a3aacf7797f03d074ab8434f445be64955 (patch)
treedd3c977290be47d5a708947893c3544678045194
parent1aad7f8ddd486e60f76730d3baa36ec63711c7e8 (diff)
Core/Phasing: Implemented db spawns in personal phases (#26345)
Co-authored-by: Shauren <shauren.trinity@gmail.com>
-rw-r--r--sql/updates/world/master/2021_12_28_00_world_trinity_string_phaseshift_status.sql6
-rw-r--r--src/server/game/Entities/Player/CinematicMgr.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.cpp8
-rw-r--r--src/server/game/Entities/Player/Player.h1
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rw-r--r--src/server/game/Events/GameEventMgr.cpp8
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp87
-rw-r--r--src/server/game/Globals/ObjectMgr.h23
-rw-r--r--src/server/game/Grids/ObjectGridLoader.cpp53
-rw-r--r--src/server/game/Grids/ObjectGridLoader.h59
-rw-r--r--src/server/game/Maps/Map.cpp26
-rw-r--r--src/server/game/Maps/Map.h14
-rw-r--r--src/server/game/Maps/MapObject.h2
-rw-r--r--src/server/game/Phasing/PersonalPhaseTracker.cpp203
-rw-r--r--src/server/game/Phasing/PersonalPhaseTracker.h85
-rw-r--r--src/server/game/Phasing/PhaseShift.cpp8
-rw-r--r--src/server/game/Phasing/PhaseShift.h5
-rw-r--r--src/server/game/Phasing/PhasingHandler.cpp28
-rw-r--r--src/server/game/Phasing/PhasingHandler.h5
-rw-r--r--src/server/game/Pools/PoolMgr.cpp8
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp2
-rw-r--r--src/server/scripts/Commands/cs_gobject.cpp6
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp4
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp10
24 files changed, 574 insertions, 81 deletions
diff --git a/sql/updates/world/master/2021_12_28_00_world_trinity_string_phaseshift_status.sql b/sql/updates/world/master/2021_12_28_00_world_trinity_string_phaseshift_status.sql
new file mode 100644
index 00000000000..19d0727572c
--- /dev/null
+++ b/sql/updates/world/master/2021_12_28_00_world_trinity_string_phaseshift_status.sql
@@ -0,0 +1,6 @@
+-- Add Name placeholder for phaseshift
+
+DELETE FROM `trinity_string` WHERE `entry` = 179;
+INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES
+(179, "PhaseShift:
+* Flags %u, PersonalGuid: %s (%s)");
diff --git a/src/server/game/Entities/Player/CinematicMgr.cpp b/src/server/game/Entities/Player/CinematicMgr.cpp
index 5a3888220b5..2d3adb01542 100644
--- a/src/server/game/Entities/Player/CinematicMgr.cpp
+++ b/src/server/game/Entities/Player/CinematicMgr.cpp
@@ -66,7 +66,7 @@ void CinematicMgr::NextCinematicCamera()
if (!pos.IsPositionValid())
return;
- player->GetMap()->LoadGrid(pos.GetPositionX(), pos.GetPositionY());
+ player->GetMap()->LoadGridForActiveObject(pos.GetPositionX(), pos.GetPositionY(), player);
m_CinematicObject = player->SummonCreature(VISUAL_WAYPOINT, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS);
if (m_CinematicObject)
{
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index a77afdfd8af..96091a7ebb6 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1239,7 +1239,6 @@ void Player::Update(uint32 p_time)
//because we don't want player's ghost teleported from graveyard
if (IsHasDelayedTeleport() && IsAlive())
TeleportTo(m_teleport_dest, m_teleport_options);
-
}
void Player::setDeathState(DeathState s)
@@ -29173,6 +29172,13 @@ void Player::UpdateWarModeAuras()
}
}
+void Player::OnPhaseChange()
+{
+ Unit::OnPhaseChange();
+
+ GetMap()->UpdatePersonalPhasesForPlayer(this);
+}
+
std::string Player::GetDebugInfo() const
{
std::stringstream sstr;
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index b16d0903e1e..aac7c3ace91 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2423,6 +2423,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool IsVisibleGloballyFor(Player const* player) const;
void SendInitialVisiblePackets(Unit* target) const;
+ void OnPhaseChange() override;
void UpdateObjectVisibility(bool forced = true) override;
void UpdateVisibilityForPlayer();
void UpdateVisibilityOf(WorldObject* target);
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 1de368514a1..f85f43731e7 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1601,7 +1601,7 @@ class TC_GAME_API Unit : public WorldObject
void SetVisible(bool x);
// common function for visibility checks for player/creatures with detection code
- void OnPhaseChange();
+ virtual void OnPhaseChange();
void UpdateObjectVisibility(bool forced = true) override;
SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY];
diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp
index 7e22c76f2f5..374522ae237 100644
--- a/src/server/game/Events/GameEventMgr.cpp
+++ b/src/server/game/Events/GameEventMgr.cpp
@@ -1231,7 +1231,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id)
// Add to correct cell
if (CreatureData const* data = sObjectMgr->GetCreatureData(*itr))
{
- sObjectMgr->AddCreatureToGrid(*itr, data);
+ sObjectMgr->AddCreatureToGrid(data);
// Spawn if necessary (loaded grids only)
Map* map = sMapMgr->CreateBaseMap(data->mapId);
@@ -1254,7 +1254,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id)
// Add to correct cell
if (GameObjectData const* data = sObjectMgr->GetGameObjectData(*itr))
{
- sObjectMgr->AddGameobjectToGrid(*itr, data);
+ sObjectMgr->AddGameobjectToGrid(data);
// Spawn if necessary (loaded grids only)
// this base map checked as non-instanced and then only existed
Map* map = sMapMgr->CreateBaseMap(data->mapId);
@@ -1305,7 +1305,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id)
// Remove the creature from grid
if (CreatureData const* data = sObjectMgr->GetCreatureData(*itr))
{
- sObjectMgr->RemoveCreatureFromGrid(*itr, data);
+ sObjectMgr->RemoveCreatureFromGrid(data);
sMapMgr->DoForAllMapsWithMapId(data->mapId, [&itr](Map* map)
{
@@ -1336,7 +1336,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id)
// Remove the gameobject from grid
if (GameObjectData const* data = sObjectMgr->GetGameObjectData(*itr))
{
- sObjectMgr->RemoveGameobjectFromGrid(*itr, data);
+ sObjectMgr->RemoveGameobjectFromGrid(data);
sMapMgr->DoForAllMapsWithMapId(data->mapId, [&itr](Map* map)
{
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index ec2bf4b499b..e665fc71aeb 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -2300,33 +2300,70 @@ void ObjectMgr::LoadCreatures()
// Add to grid if not managed by the game event or pool system
if (gameEvent == 0 && PoolId == 0)
- AddCreatureToGrid(guid, &data);
+ AddCreatureToGrid(&data);
}
while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " creatures in %u ms", _creatureDataStore.size(), GetMSTimeDiffToNow(oldMSTime));
}
-void ObjectMgr::AddCreatureToGrid(ObjectGuid::LowType guid, CreatureData const* data)
+bool ObjectMgr::HasPersonalSpawns(uint32 mapid, Difficulty spawnMode, uint32 phaseId) const
{
- for (Difficulty difficulty : data->spawnDifficulties)
+ return Trinity::Containers::MapGetValuePtr(_mapPersonalObjectGuidsStore, { mapid, spawnMode, phaseId }) != nullptr;
+}
+
+CellObjectGuids const* ObjectMgr::GetCellPersonalObjectGuids(uint32 mapid, Difficulty spawnMode, uint32 phaseId, uint32 cell_id) const
+{
+ if (CellObjectGuidsMap const* guids = Trinity::Containers::MapGetValuePtr(_mapPersonalObjectGuidsStore, { mapid, spawnMode, phaseId }))
+ return Trinity::Containers::MapGetValuePtr(*guids, cell_id);
+
+ return nullptr;
+}
+
+template<CellGuidSet CellObjectGuids::*guids>
+void ObjectMgr::AddSpawnDataToGrid(SpawnData const* data)
+{
+ uint32 cellId = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()).GetId();
+ bool isPersonalPhase = PhasingHandler::IsPersonalPhase(data->phaseId);
+ if (!isPersonalPhase)
+ {
+ for (Difficulty difficulty : data->spawnDifficulties)
+ (_mapObjectGuidsStore[{ data->mapId, difficulty }][cellId].*guids).insert(data->spawnId);
+ }
+ else
{
- CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[{ data->mapId, difficulty }][cellCoord.GetId()];
- cell_guids.creatures.insert(guid);
+ for (Difficulty difficulty : data->spawnDifficulties)
+ (_mapPersonalObjectGuidsStore[{ data->mapId, difficulty, data->phaseId }][cellId].*guids).insert(data->spawnId);
}
}
-void ObjectMgr::RemoveCreatureFromGrid(ObjectGuid::LowType guid, CreatureData const* data)
+template<CellGuidSet CellObjectGuids::*guids>
+void ObjectMgr::RemoveSpawnDataFromGrid(SpawnData const* data)
{
- for (Difficulty difficulty : data->spawnDifficulties)
+ uint32 cellId = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()).GetId();
+ bool isPersonalPhase = PhasingHandler::IsPersonalPhase(data->phaseId);
+ if (!isPersonalPhase)
+ {
+ for (Difficulty difficulty : data->spawnDifficulties)
+ (_mapObjectGuidsStore[{ data->mapId, difficulty }][cellId].*guids).erase(data->spawnId);
+ }
+ else
{
- CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[{ data->mapId, difficulty }][cellCoord.GetId()];
- cell_guids.creatures.erase(guid);
+ for (Difficulty difficulty : data->spawnDifficulties)
+ (_mapPersonalObjectGuidsStore[{ data->mapId, difficulty, data->phaseId }][cellId].*guids).erase(data->spawnId);
}
}
+void ObjectMgr::AddCreatureToGrid(CreatureData const* data)
+{
+ AddSpawnDataToGrid<&CellObjectGuids::creatures>(data);
+}
+
+void ObjectMgr::RemoveCreatureFromGrid(CreatureData const* data)
+{
+ RemoveSpawnDataFromGrid<&CellObjectGuids::creatures>(data);
+}
+
ObjectGuid::LowType ObjectMgr::AddGameObjectData(uint32 entry, uint32 mapId, Position const& pos, QuaternionData const& rot, uint32 spawntimedelay /*= 0*/)
{
GameObjectTemplate const* goinfo = GetGameObjectTemplate(entry);
@@ -2352,7 +2389,7 @@ ObjectGuid::LowType ObjectMgr::AddGameObjectData(uint32 entry, uint32 mapId, Pos
data.dbData = false;
data.spawnGroupData = GetLegacySpawnGroup();
- AddGameobjectToGrid(spawnId, &data);
+ AddGameobjectToGrid(&data);
// Spawn if necessary (loaded grids only)
// We use spawn coords to spawn
@@ -2407,7 +2444,7 @@ ObjectGuid::LowType ObjectMgr::AddCreatureData(uint32 entry, uint32 mapId, Posit
data.dynamicflags = cInfo->dynamicflags;
data.spawnGroupData = GetLegacySpawnGroup();
- AddCreatureToGrid(spawnId, &data);
+ AddCreatureToGrid(&data);
// We use spawn coords to spawn
if (!map->Instanceable() && !map->IsRemovalGrid(data.spawnPoint))
@@ -2663,7 +2700,7 @@ void ObjectMgr::LoadGameObjects()
}
if (gameEvent == 0 && PoolId == 0) // if not this is to be managed by GameEvent System or Pool system
- AddGameobjectToGrid(guid, &data);
+ AddGameobjectToGrid(&data);
}
while (result->NextRow());
@@ -2885,24 +2922,14 @@ void ObjectMgr::OnDeleteSpawnData(SpawnData const* data)
ASSERT(false, "Spawn data (%u," UI64FMTD ") being removed is member of spawn group %u, but not actually listed in the lookup table for that group!", uint32(data->type), data->spawnId, data->spawnGroupData->groupId);
}
-void ObjectMgr::AddGameobjectToGrid(ObjectGuid::LowType guid, GameObjectData const* data)
+void ObjectMgr::AddGameobjectToGrid(GameObjectData const* data)
{
- for (Difficulty difficulty : data->spawnDifficulties)
- {
- CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[{ data->mapId, difficulty }][cellCoord.GetId()];
- cell_guids.gameobjects.insert(guid);
- }
+ AddSpawnDataToGrid<&CellObjectGuids::gameobjects>(data);
}
-void ObjectMgr::RemoveGameobjectFromGrid(ObjectGuid::LowType guid, GameObjectData const* data)
+void ObjectMgr::RemoveGameobjectFromGrid(GameObjectData const* data)
{
- for (Difficulty difficulty : data->spawnDifficulties)
- {
- CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[{ data->mapId, difficulty }][cellCoord.GetId()];
- cell_guids.gameobjects.erase(guid);
- }
+ RemoveSpawnDataFromGrid<&CellObjectGuids::gameobjects>(data);
}
uint32 FillMaxDurability(uint32 itemClass, uint32 itemSubClass, uint32 inventoryType, uint32 quality, uint32 itemLevel)
@@ -8431,7 +8458,7 @@ void ObjectMgr::DeleteCreatureData(ObjectGuid::LowType guid)
CreatureData const* data = GetCreatureData(guid);
if (data)
{
- RemoveCreatureFromGrid(guid, data);
+ RemoveCreatureFromGrid(data);
OnDeleteSpawnData(data);
}
@@ -8444,7 +8471,7 @@ void ObjectMgr::DeleteGameObjectData(ObjectGuid::LowType guid)
GameObjectData const* data = GetGameObjectData(guid);
if (data)
{
- RemoveGameobjectFromGrid(guid, data);
+ RemoveGameobjectFromGrid(data);
OnDeleteSpawnData(data);
}
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 52eefdec97c..4443d8ba018 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -487,6 +487,7 @@ struct CellObjectGuids
};
typedef std::unordered_map<uint32/*cell_id*/, CellObjectGuids> CellObjectGuidsMap;
typedef std::unordered_map<std::pair<uint32 /*mapId*/, Difficulty>, CellObjectGuidsMap> MapObjectGuids;
+typedef std::map<std::tuple<uint32/*mapId*/, Difficulty, uint32 /*phaseId*/>, CellObjectGuidsMap> MapPersonalObjectGuids;
struct TrinityString
{
@@ -1454,16 +1455,19 @@ class TC_GAME_API ObjectMgr
return nullptr;
}
- CellObjectGuids const& GetCellObjectGuids(uint16 mapid, Difficulty spawnMode, uint32 cell_id)
+ CellObjectGuids const& GetCellObjectGuids(uint32 mapid, Difficulty spawnMode, uint32 cell_id)
{
return _mapObjectGuidsStore[{ mapid, spawnMode }][cell_id];
}
- CellObjectGuidsMap const& GetMapObjectGuids(uint16 mapid, Difficulty spawnMode)
+ CellObjectGuidsMap const& GetMapObjectGuids(uint32 mapid, Difficulty spawnMode)
{
return _mapObjectGuidsStore[{ mapid, spawnMode }];
}
+ bool HasPersonalSpawns(uint32 mapid, Difficulty spawnMode, uint32 phaseId) const;
+ CellObjectGuids const* GetCellPersonalObjectGuids(uint32 mapid, Difficulty spawnMode, uint32 phaseId, uint32 cell_id) const;
+
/**
* Gets temp summon data for all creatures of specified group.
*
@@ -1589,10 +1593,10 @@ class TC_GAME_API ObjectMgr
void SetDBCLocaleIndex(LocaleConstant locale) { DBCLocaleIndex = locale; }
// grid objects
- void AddCreatureToGrid(ObjectGuid::LowType guid, CreatureData const* data);
- void RemoveCreatureFromGrid(ObjectGuid::LowType guid, CreatureData const* data);
- void AddGameobjectToGrid(ObjectGuid::LowType guid, GameObjectData const* data);
- void RemoveGameobjectFromGrid(ObjectGuid::LowType guid, GameObjectData const* data);
+ void AddCreatureToGrid(CreatureData const* data);
+ void RemoveCreatureFromGrid(CreatureData const* data);
+ void AddGameobjectToGrid(GameObjectData const* data);
+ void RemoveGameobjectFromGrid(GameObjectData const* data);
ObjectGuid::LowType AddGameObjectData(uint32 entry, uint32 map, Position const& pos, QuaternionData const& rot, uint32 spawntimedelay = 0);
ObjectGuid::LowType AddCreatureData(uint32 entry, uint32 map, Position const& pos, uint32 spawntimedelay = 0);
@@ -1839,6 +1843,12 @@ class TC_GAME_API ObjectMgr
QuestRelationResult GetQuestRelationsFrom(QuestRelations const& map, uint32 key, bool onlyActive) const { return { map.equal_range(key), onlyActive }; }
void PlayerCreateInfoAddItemHelper(uint32 race_, uint32 class_, uint32 itemId, int32 count);
+ template<CellGuidSet CellObjectGuids::*guids>
+ void AddSpawnDataToGrid(SpawnData const* data);
+
+ template<CellGuidSet CellObjectGuids::*guids>
+ void RemoveSpawnDataFromGrid(SpawnData const* data);
+
MailLevelRewardContainer _mailLevelRewardStore;
CreatureBaseStatsContainer _creatureBaseStatsStore;
@@ -1865,6 +1875,7 @@ class TC_GAME_API ObjectMgr
HalfNameContainer _petHalfName1;
MapObjectGuids _mapObjectGuidsStore;
+ MapPersonalObjectGuids _mapPersonalObjectGuidsStore;
CreatureDataContainer _creatureDataStore;
CreatureTemplateContainer _creatureTemplateStore;
CreatureModelContainer _creatureModelStore;
diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp
index a718f455dab..9d2f16e13b1 100644
--- a/src/server/game/Grids/ObjectGridLoader.cpp
+++ b/src/server/game/Grids/ObjectGridLoader.cpp
@@ -84,15 +84,16 @@ class ObjectWorldLoader
uint32& i_corpses;
};
-template<class T> void ObjectGridLoader::SetObjectCell(T* /*obj*/, CellCoord const& /*cellCoord*/) { }
+template<class T>
+void ObjectGridLoaderBase::SetObjectCell(T* /*obj*/, CellCoord const& /*cellCoord*/) { }
-template<> void ObjectGridLoader::SetObjectCell(Creature* obj, CellCoord const& cellCoord)
+template<> void ObjectGridLoaderBase::SetObjectCell(Creature* obj, CellCoord const& cellCoord)
{
Cell cell(cellCoord);
obj->SetCurrentCell(cell);
}
-template<> void ObjectGridLoader::SetObjectCell(GameObject* obj, CellCoord const& cellCoord)
+template<> void ObjectGridLoaderBase::SetObjectCell(GameObject* obj, CellCoord const& cellCoord)
{
Cell cell(cellCoord);
obj->SetCurrentCell(cell);
@@ -120,7 +121,7 @@ void AddObjectHelper(CellCoord &cell, CreatureMapType &m, uint32 &count, Map* ma
}
template <class T>
-void LoadHelper(CellGuidSet const& guid_set, CellCoord &cell, GridRefManager<T> &m, uint32 &count, Map* map)
+void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefManager<T>& m, uint32& count, Map* map, uint32 phaseId = 0, Optional<ObjectGuid> phaseOwner = {})
{
for (CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid)
{
@@ -131,11 +132,18 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord &cell, GridRefManager<T>
T* obj = new T;
//TC_LOG_INFO("misc", "DEBUG: LoadHelper from table: %s for (guid: " UI64FMTD ") Loading", table, guid);
- if (!obj->LoadFromDB(guid, map, false, false))
+ if (!obj->LoadFromDB(guid, map, false, phaseOwner.is_initialized() /*allowDuplicate*/))
{
delete obj;
continue;
}
+
+ if (phaseOwner)
+ {
+ PhasingHandler::InitDbPersonalOwnership(obj->GetPhaseShift(), *phaseOwner);
+ map->GetMultiPersonalPhaseTracker().RegisterTrackedObject(phaseId, *phaseOwner, obj);
+ }
+
AddObjectHelper(cell, m, count, map, obj);
}
}
@@ -206,7 +214,40 @@ void ObjectGridLoader::LoadN(void)
}
}
}
- TC_LOG_DEBUG("maps", "%u GameObjects, %u Creatures, and %u Corpses/Bones loaded for grid %u on map %u", i_gameObjects, i_creatures, i_corpses, i_grid.GetGridId(), i_map->GetId());
+ TC_LOG_DEBUG("maps", "%u GameObjects, %u Creatures, %u AreaTrriggers, and %u Corpses/Bones loaded for grid %u on map %u",
+ i_gameObjects, i_creatures, i_areaTriggers, i_corpses, i_grid.GetGridId(), i_map->GetId());
+}
+
+void PersonalPhaseGridLoader::Visit(GameObjectMapType& m)
+{
+ CellCoord cellCoord = i_cell.GetCellCoord();
+ if (CellObjectGuids const* cell_guids = sObjectMgr->GetCellPersonalObjectGuids(i_map->GetId(), i_map->GetDifficultyID(), _phaseId, cellCoord.GetId()))
+ LoadHelper(cell_guids->gameobjects, cellCoord, m, i_gameObjects, i_map, _phaseId, _phaseOwner);
+}
+
+void PersonalPhaseGridLoader::Visit(CreatureMapType& m)
+{
+ CellCoord cellCoord = i_cell.GetCellCoord();
+ if (CellObjectGuids const* cell_guids = sObjectMgr->GetCellPersonalObjectGuids(i_map->GetId(), i_map->GetDifficultyID(), _phaseId, cellCoord.GetId()))
+ LoadHelper(cell_guids->creatures, cellCoord, m, i_creatures, i_map, _phaseId, _phaseOwner);
+}
+
+void PersonalPhaseGridLoader::Load(uint32 phaseId)
+{
+ _phaseId = phaseId;
+ i_cell.data.Part.cell_y = 0;
+ for (uint32 x = 0; x < MAX_NUMBER_OF_CELLS; ++x)
+ {
+ i_cell.data.Part.cell_x = x;
+ for (uint32 y = 0; y < MAX_NUMBER_OF_CELLS; ++y)
+ {
+ i_cell.data.Part.cell_y = y;
+
+ //Load creatures and game objects
+ TypeContainerVisitor<PersonalPhaseGridLoader, GridTypeMapContainer> visitor(*this);
+ i_grid.VisitGrid(x, y, visitor);
+ }
+ }
}
template<class T>
diff --git a/src/server/game/Grids/ObjectGridLoader.h b/src/server/game/Grids/ObjectGridLoader.h
index dfd02011001..c9f2de1ccb3 100644
--- a/src/server/game/Grids/ObjectGridLoader.h
+++ b/src/server/game/Grids/ObjectGridLoader.h
@@ -24,15 +24,41 @@
#include "GridDefines.h"
#include "Cell.h"
+class ObjectGuid;
class ObjectWorldLoader;
-class TC_GAME_API ObjectGridLoader
+class TC_GAME_API ObjectGridLoaderBase
+{
+ public:
+ ObjectGridLoaderBase(NGridType& grid, Map* map, Cell const& cell)
+ : i_cell(cell), i_grid(grid), i_map(map), i_gameObjects(0), i_creatures(0), i_corpses(0), i_areaTriggers(0)
+ { }
+
+ template<class T>
+ static void SetObjectCell(T* obj, CellCoord const& cellCoord);
+
+ uint32 GetLoadedCreatures() const { return i_creatures; }
+ uint32 GetLoadedGameObjects() const { return i_gameObjects; }
+ uint32 GetLoadedCorpses() const { return i_corpses; }
+ uint32 GetLoadedAreaTriggers() const { return i_areaTriggers; }
+
+ protected:
+ Cell i_cell;
+ NGridType &i_grid;
+ Map* i_map;
+ uint32 i_gameObjects;
+ uint32 i_creatures;
+ uint32 i_corpses;
+ uint32 i_areaTriggers;
+};
+
+class TC_GAME_API ObjectGridLoader : public ObjectGridLoaderBase
{
friend class ObjectWorldLoader;
public:
ObjectGridLoader(NGridType& grid, Map* map, Cell const& cell)
- : i_cell(cell), i_grid(grid), i_map(map), i_gameObjects(0), i_creatures(0), i_corpses(0), i_areaTriggers(0)
+ : ObjectGridLoaderBase(grid, map, cell)
{ }
void Visit(GameObjectMapType &m);
@@ -43,18 +69,29 @@ class TC_GAME_API ObjectGridLoader
void Visit(SceneObjectMapType&) const { }
void Visit(ConversationMapType&) const { }
- void LoadN(void);
+ void LoadN();
+};
- template<class T> static void SetObjectCell(T* obj, CellCoord const& cellCoord);
+class TC_GAME_API PersonalPhaseGridLoader : public ObjectGridLoaderBase
+{
+ public:
+ PersonalPhaseGridLoader(NGridType& grid, Map* map, Cell const& cell, ObjectGuid const& phaseOwner)
+ : ObjectGridLoaderBase(grid, map, cell), _phaseId(0), _phaseOwner(phaseOwner)
+ { }
+
+ void Visit(GameObjectMapType &m);
+ void Visit(CreatureMapType &m);
+ void Visit(AreaTriggerMapType&) const { }
+ void Visit(CorpseMapType&) const { }
+ void Visit(DynamicObjectMapType&) const { }
+ void Visit(SceneObjectMapType&) const { }
+ void Visit(ConversationMapType&) const { }
+
+ void Load(uint32 phaseId);
private:
- Cell i_cell;
- NGridType &i_grid;
- Map* i_map;
- uint32 i_gameObjects;
- uint32 i_creatures;
- uint32 i_corpses;
- uint32 i_areaTriggers;
+ uint32 _phaseId;
+ ObjectGuid const& _phaseOwner;
};
//Stop the creatures before unloading the NGrid
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 5e1b17d9d0d..9e553dd19e3 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -564,12 +564,15 @@ void Map::EnsureGridCreated_i(GridCoord const& p)
}
//Load NGrid and make it active
-void Map::EnsureGridLoadedForActiveObject(Cell const& cell, WorldObject* object)
+void Map::EnsureGridLoadedForActiveObject(Cell const& cell, WorldObject const* object)
{
EnsureGridLoaded(cell);
NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
ASSERT(grid != nullptr);
+ if (object->IsPlayer())
+ GetMultiPersonalPhaseTracker().LoadGrid(object->GetPhaseShift(), *grid, this, cell);
+
// refresh grid state & timer
if (grid->GetGridState() != GRID_STATE_ACTIVE)
{
@@ -635,6 +638,11 @@ void Map::LoadGrid(float x, float y)
EnsureGridLoaded(Cell(x, y));
}
+void Map::LoadGridForActiveObject(float x, float y, WorldObject const* object)
+{
+ EnsureGridLoadedForActiveObject(Cell(x, y), object);
+}
+
bool Map::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
{
CellCoord cellCoord = Trinity::ComputeCellCoord(player->GetPositionX(), player->GetPositionY());
@@ -671,6 +679,12 @@ bool Map::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
return true;
}
+void Map::UpdatePersonalPhasesForPlayer(Player const* player)
+{
+ Cell cell(player->GetPositionX(), player->GetPositionY());
+ GetMultiPersonalPhaseTracker().OnOwnerPhaseChanged(player, getNGrid(cell.GridX(), cell.GridY()), this, cell);
+}
+
template<class T>
void Map::InitializeObject(T* /*obj*/) { }
@@ -939,6 +953,9 @@ void Map::Update(uint32 t_diff)
_weatherUpdateTimer.Reset();
}
+ // update phase shift objects
+ GetMultiPersonalPhaseTracker().Update(this, t_diff);
+
MoveAllCreaturesInMoveList();
MoveAllGameObjectsInMoveList();
MoveAllAreaTriggersInMoveList();
@@ -1044,6 +1061,8 @@ void Map::RemovePlayerFromMap(Player* player, bool remove)
player->UpdateZone(MAP_INVALID_ZONE, 0);
sScriptMgr->OnPlayerLeaveMap(this, player);
+ GetMultiPersonalPhaseTracker().MarkAllPhasesForDeletion(player->GetGUID());
+
player->CombatStop();
bool const inWorld = player->IsInWorld();
@@ -1070,6 +1089,8 @@ void Map::RemoveFromMap(T *obj, bool remove)
if (obj->isActiveObject())
RemoveFromActive(obj);
+ GetMultiPersonalPhaseTracker().UnregisterTrackedObject(obj);
+
if (!inWorld) // if was in world, RemoveFromWorld() called DestroyForNearbyPlayers()
obj->DestroyForNearbyPlayers(); // previous obj->UpdateObjectVisibility(true)
@@ -1735,6 +1756,9 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
RemoveAllObjectsInRemoveList();
+ // After removing all objects from the map, purge empty tracked phases
+ GetMultiPersonalPhaseTracker().UnloadGrid(ngrid);
+
{
ObjectGridUnloader worker;
TypeContainerVisitor<ObjectGridUnloader, GridTypeMapContainer> visitor(worker);
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index e8a1a4d8a00..e5319376181 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -30,6 +30,7 @@
#include "MPSCQueue.h"
#include "ObjectGuid.h"
#include "Optional.h"
+#include "PersonalPhaseTracker.h"
#include "SharedDefines.h"
#include "SpawnData.h"
#include "Timer.h"
@@ -313,6 +314,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
bool GetUnloadLock(GridCoord const& p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); }
void SetUnloadLock(GridCoord const& p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); }
void LoadGrid(float x, float y);
+ void LoadGridForActiveObject(float x, float y, WorldObject const* object);
void LoadAllCells();
bool UnloadGrid(NGridType& ngrid, bool pForce);
void GridMarkNoUnload(uint32 x, uint32 y);
@@ -656,7 +658,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
void EnsureGridCreated(GridCoord const&);
void EnsureGridCreated_i(GridCoord const&);
bool EnsureGridLoaded(Cell const&);
- void EnsureGridLoadedForActiveObject(Cell const&, WorldObject* object);
+ void EnsureGridLoadedForActiveObject(Cell const&, WorldObject const* object);
void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); }
@@ -881,6 +883,16 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
std::unordered_set<Object*> _updateObjects;
MPSCQueue<FarSpellCallback> _farSpellCallbacks;
+
+ /*********************************************************/
+ /*** Phasing ***/
+ /*********************************************************/
+ public:
+ MultiPersonalPhaseTracker& GetMultiPersonalPhaseTracker() { return _multiPersonalPhaseTracker; }
+ void UpdatePersonalPhasesForPlayer(Player const* player);
+
+ private:
+ MultiPersonalPhaseTracker _multiPersonalPhaseTracker;
};
enum InstanceResetMethod
diff --git a/src/server/game/Maps/MapObject.h b/src/server/game/Maps/MapObject.h
index 94b88155f5c..6481fc87cc0 100644
--- a/src/server/game/Maps/MapObject.h
+++ b/src/server/game/Maps/MapObject.h
@@ -35,7 +35,7 @@ enum MapObjectCellMoveState
class TC_GAME_API MapObject
{
friend class Map; //map for moving creatures
- friend class ObjectGridLoader; //grid loader for loading creatures
+ friend class ObjectGridLoaderBase; //grid loader for loading creatures
protected:
MapObject() : _moveState(MAP_OBJECT_CELL_MOVE_NONE)
diff --git a/src/server/game/Phasing/PersonalPhaseTracker.cpp b/src/server/game/Phasing/PersonalPhaseTracker.cpp
new file mode 100644
index 00000000000..db73485b352
--- /dev/null
+++ b/src/server/game/Phasing/PersonalPhaseTracker.cpp
@@ -0,0 +1,203 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * 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 "PersonalPhaseTracker.h"
+#include "Containers.h"
+#include "Log.h"
+#include "Map.h"
+#include "Object.h"
+#include "ObjectGridLoader.h"
+#include "ObjectMgr.h"
+#include "PhasingHandler.h"
+
+ /*********************************************************/
+ /*** PlayerPersonalPhasesTracker ***/
+ /*********************************************************/
+
+void PlayerPersonalPhasesTracker::RegisterTrackedObject(uint32 phaseId, WorldObject* object)
+{
+ _spawns[phaseId].Objects.insert(object);
+}
+
+void PlayerPersonalPhasesTracker::UnregisterTrackedObject(WorldObject* object)
+{
+ for (auto& [_, spawns] : _spawns)
+ spawns.Objects.erase(object);
+}
+
+void PlayerPersonalPhasesTracker::OnOwnerPhasesChanged(WorldObject const* owner)
+{
+ PhaseShift const& phaseShift = owner->GetPhaseShift();
+
+ // Loop over all our tracked phases. If any don't exist - delete them
+ for (auto& [phaseId, spawns] : _spawns)
+ if (!spawns.DurationRemaining && !phaseShift.HasPhase(phaseId))
+ spawns.DurationRemaining = PersonalPhaseSpawns::DELETE_TIME_DEFAULT;
+
+ // loop over all owner phases. If any exist and marked for deletion - reset delete
+ for (PhaseShift::PhaseRef const& phaseRef : phaseShift.GetPhases())
+ if (PersonalPhaseSpawns* spawns = Trinity::Containers::MapGetValuePtr(_spawns, phaseRef.Id))
+ spawns->DurationRemaining.reset();
+}
+
+void PlayerPersonalPhasesTracker::MarkAllPhasesForDeletion()
+{
+ for (auto& [_, spawns] : _spawns)
+ spawns.DurationRemaining = PersonalPhaseSpawns::DELETE_TIME_DEFAULT;
+}
+
+void PlayerPersonalPhasesTracker::Update(Map* map, uint32 diff)
+{
+ for (auto itr = _spawns.begin(); itr != _spawns.end(); )
+ {
+ if (itr->second.DurationRemaining)
+ {
+ itr->second.DurationRemaining = *itr->second.DurationRemaining - Milliseconds(diff);
+ if (itr->second.DurationRemaining <= Milliseconds::zero())
+ {
+ DespawnPhase(map, itr->second);
+ itr = _spawns.erase(itr);
+ continue;
+ }
+ }
+ ++itr;
+ }
+}
+
+bool PlayerPersonalPhasesTracker::IsGridLoadedForPhase(uint32 gridId, uint32 phaseId) const
+{
+ if (PersonalPhaseSpawns const* spawns = Trinity::Containers::MapGetValuePtr(_spawns, phaseId))
+ return spawns->Grids.find(gridId) != spawns->Grids.cend();
+
+ return false;
+}
+
+void PlayerPersonalPhasesTracker::SetGridLoadedForPhase(uint32 gridId, uint32 phaseId)
+{
+ PersonalPhaseSpawns& group = _spawns[phaseId];
+ group.Grids.insert(gridId);
+}
+
+void PlayerPersonalPhasesTracker::SetGridUnloaded(uint32 gridId)
+{
+ for (auto itr = _spawns.begin(); itr != _spawns.end(); )
+ {
+ itr->second.Grids.erase(gridId);
+ if (itr->second.IsEmpty())
+ itr = _spawns.erase(itr);
+ else
+ ++itr;
+ }
+}
+
+void PlayerPersonalPhasesTracker::DespawnPhase(Map* map, PersonalPhaseSpawns& spawns)
+{
+ for (WorldObject* obj : spawns.Objects)
+ map->AddObjectToRemoveList(obj);
+
+ spawns.Objects.clear();
+ spawns.Grids.clear();
+}
+
+/*********************************************************/
+/*** MultiPersonalPhaseTracker ***/
+/*********************************************************/
+
+void MultiPersonalPhaseTracker::LoadGrid(PhaseShift const& phaseShift, NGridType& grid, Map* map, Cell const& cell)
+{
+ if (!phaseShift.HasPersonalPhase())
+ return;
+
+ PersonalPhaseGridLoader loader(grid, map, cell, phaseShift.GetPersonalGuid());
+ PlayerPersonalPhasesTracker& playerTracker = _playerData[phaseShift.GetPersonalGuid()];
+
+ for (PhaseShift::PhaseRef const& phaseRef : phaseShift.GetPhases())
+ {
+ if (!phaseRef.IsPersonal())
+ continue;
+
+ if (!sObjectMgr->HasPersonalSpawns(map->GetId(), map->GetDifficultyID(), phaseRef.Id))
+ continue;
+
+ if (playerTracker.IsGridLoadedForPhase(grid.GetGridId(), phaseRef.Id))
+ continue;
+
+ TC_LOG_DEBUG("maps", "Loading personal phase objects (phase %u) in grid[%u, %u] for map %u instance %u",
+ phaseRef.Id, cell.GridX(), cell.GridY(), map->GetId(), map->GetInstanceId());
+
+ loader.Load(phaseRef.Id);
+
+ playerTracker.SetGridLoadedForPhase(grid.GetGridId(), phaseRef.Id);
+ }
+
+ if (loader.GetLoadedGameObjects())
+ map->Balance();
+}
+
+void MultiPersonalPhaseTracker::UnloadGrid(NGridType& grid)
+{
+ for (auto itr = _playerData.begin(); itr != _playerData.end(); )
+ {
+ itr->second.SetGridUnloaded(grid.GetGridId());
+ if (itr->second.IsEmpty())
+ itr = _playerData.erase(itr);
+ else
+ ++itr;
+ }
+}
+
+void MultiPersonalPhaseTracker::RegisterTrackedObject(uint32 phaseId, ObjectGuid const& phaseOwner, WorldObject* object)
+{
+ ASSERT(phaseId);
+ ASSERT(!phaseOwner.IsEmpty());
+ ASSERT(object);
+
+ _playerData[phaseOwner].RegisterTrackedObject(phaseId, object);
+}
+
+void MultiPersonalPhaseTracker::UnregisterTrackedObject(WorldObject* object)
+{
+ if (PlayerPersonalPhasesTracker* playerTracker = Trinity::Containers::MapGetValuePtr(_playerData, object->GetPhaseShift().GetPersonalGuid()))
+ playerTracker->UnregisterTrackedObject(object);
+}
+
+void MultiPersonalPhaseTracker::OnOwnerPhaseChanged(WorldObject const* phaseOwner, NGridType* grid, Map* map, Cell const& cell)
+{
+ if (PlayerPersonalPhasesTracker* playerTracker = Trinity::Containers::MapGetValuePtr(_playerData, phaseOwner->GetGUID()))
+ playerTracker->OnOwnerPhasesChanged(phaseOwner);
+
+ if (grid)
+ LoadGrid(phaseOwner->GetPhaseShift(), *grid, map, cell);
+}
+
+void MultiPersonalPhaseTracker::MarkAllPhasesForDeletion(ObjectGuid const& phaseOwner)
+{
+ if (PlayerPersonalPhasesTracker* playerTracker = Trinity::Containers::MapGetValuePtr(_playerData, phaseOwner))
+ playerTracker->MarkAllPhasesForDeletion();
+}
+
+void MultiPersonalPhaseTracker::Update(Map* map, uint32 diff)
+{
+ for (auto itr = _playerData.begin(); itr != _playerData.end(); )
+ {
+ itr->second.Update(map, diff);
+ if (itr->second.IsEmpty())
+ itr = _playerData.erase(itr);
+ else
+ ++itr;
+ }
+}
diff --git a/src/server/game/Phasing/PersonalPhaseTracker.h b/src/server/game/Phasing/PersonalPhaseTracker.h
new file mode 100644
index 00000000000..641cbece9fa
--- /dev/null
+++ b/src/server/game/Phasing/PersonalPhaseTracker.h
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * 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 PersonalPhaseTracker_h__
+#define PersonalPhaseTracker_h__
+
+#include "Common.h"
+#include "Duration.h"
+#include "GridDefines.h"
+#include "ObjectGuid.h"
+#include "Optional.h"
+
+class Map;
+class PhaseShift;
+class WorldObject;
+struct Cell;
+
+struct PersonalPhaseSpawns
+{
+ static constexpr Milliseconds DELETE_TIME_DEFAULT = 1min;
+
+ std::unordered_set<WorldObject*> Objects;
+ std::unordered_set<uint16> Grids;
+ Optional<Milliseconds> DurationRemaining;
+
+ bool IsEmpty() const { return Objects.empty() && Grids.empty(); }
+};
+
+/* Tracks personal phases for a single owner */
+struct PlayerPersonalPhasesTracker
+{
+public:
+ void RegisterTrackedObject(uint32 phaseId, WorldObject* object);
+ void UnregisterTrackedObject(WorldObject* object);
+
+ void OnOwnerPhasesChanged(WorldObject const* owner);
+ void MarkAllPhasesForDeletion();
+
+ void Update(Map* map, uint32 diff);
+
+ bool IsGridLoadedForPhase(uint32 gridId, uint32 phaseId) const;
+ void SetGridLoadedForPhase(uint32 gridId, uint32 phaseId);
+ void SetGridUnloaded(uint32 gridId);
+
+ bool IsEmpty() const { return _spawns.empty(); }
+
+private:
+ void DespawnPhase(Map* map, PersonalPhaseSpawns& spawns);
+
+ std::unordered_map<uint32 /*phaseId*/, PersonalPhaseSpawns> _spawns;
+};
+
+/* Handles personal phase trackers for all owners */
+struct MultiPersonalPhaseTracker
+{
+ void LoadGrid(PhaseShift const& phaseShift, NGridType& grid, Map* map, Cell const& cell);
+ void UnloadGrid(NGridType& grid);
+
+ void RegisterTrackedObject(uint32 phaseId, ObjectGuid const& phaseOwner, WorldObject* object);
+ void UnregisterTrackedObject(WorldObject* object);
+
+ void OnOwnerPhaseChanged(WorldObject const* phaseOwner, NGridType* grid, Map* map, Cell const& cell);
+ void MarkAllPhasesForDeletion(ObjectGuid const& phaseOwner);
+
+ void Update(Map* map, uint32 diff);
+
+private:
+ std::unordered_map<ObjectGuid /*owner*/, PlayerPersonalPhasesTracker> _playerData;
+};
+
+#endif // PersonalPhaseTracker_h__
diff --git a/src/server/game/Phasing/PhaseShift.cpp b/src/server/game/Phasing/PhaseShift.cpp
index f9753226918..f0655bf01fa 100644
--- a/src/server/game/Phasing/PhaseShift.cpp
+++ b/src/server/game/Phasing/PhaseShift.cpp
@@ -186,3 +186,11 @@ void PhaseShift::UpdatePersonalGuid()
if (!PersonalReferences)
PersonalGuid.Clear();
}
+
+bool PhaseShift::HasPersonalPhase() const
+{
+ for (PhaseRef const& phaseRef : GetPhases())
+ if (phaseRef.IsPersonal())
+ return true;
+ return false;
+}
diff --git a/src/server/game/Phasing/PhaseShift.h b/src/server/game/Phasing/PhaseShift.h
index 133f58056a2..32fc4455877 100644
--- a/src/server/game/Phasing/PhaseShift.h
+++ b/src/server/game/Phasing/PhaseShift.h
@@ -65,6 +65,7 @@ public:
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; }
+ bool IsPersonal() const { return Flags.HasFlag(PhaseFlags::Personal); }
};
struct VisibleMapIdRef
{
@@ -85,6 +86,8 @@ public:
using VisibleMapIdContainer = std::map<uint32, VisibleMapIdRef>;
using UiMapPhaseIdContainer = std::map<uint32, UiMapPhaseIdRef>;
+ ObjectGuid GetPersonalGuid() const { return PersonalGuid; }
+
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(); }
@@ -105,6 +108,8 @@ public:
bool CanSee(PhaseShift const& other) const;
+ bool HasPersonalPhase() const;
+
protected:
friend class PhasingHandler;
diff --git a/src/server/game/Phasing/PhasingHandler.cpp b/src/server/game/Phasing/PhasingHandler.cpp
index e1432b49351..31a28010c71 100644
--- a/src/server/game/Phasing/PhasingHandler.cpp
+++ b/src/server/game/Phasing/PhasingHandler.cpp
@@ -496,6 +496,13 @@ void PhasingHandler::InitDbPhaseShift(PhaseShift& phaseShift, uint8 phaseUseFlag
phaseShift.Flags = flags;
}
+void PhasingHandler::InitDbPersonalOwnership(PhaseShift& phaseShift, ObjectGuid const& personalGuid)
+{
+ ASSERT(phaseShift.IsDbPhaseShift);
+ ASSERT(phaseShift.HasPersonalPhase());
+ phaseShift.PersonalGuid = personalGuid;
+}
+
void PhasingHandler::InitDbVisibleMapId(PhaseShift& phaseShift, int32 visibleMapId)
{
phaseShift.VisibleMapIds.clear();
@@ -551,9 +558,18 @@ void PhasingHandler::SetInversed(WorldObject* object, bool apply, bool updateVis
UpdateVisibilityIfNeeded(object, updateVisibility, true);
}
-void PhasingHandler::PrintToChat(ChatHandler* chat, PhaseShift const& phaseShift)
+void PhasingHandler::PrintToChat(ChatHandler* chat, WorldObject const* target)
{
- chat->PSendSysMessage(LANG_PHASESHIFT_STATUS, phaseShift.Flags.AsUnderlyingType(), phaseShift.PersonalGuid.ToString().c_str());
+ PhaseShift const& phaseShift = target->GetPhaseShift();
+
+ std::string phaseOwnerName = "N/A";
+ if (phaseShift.HasPersonalPhase())
+ if (WorldObject* personalGuid = ObjectAccessor::GetWorldObject(*target, phaseShift.PersonalGuid))
+ phaseOwnerName = personalGuid->GetName();
+
+ chat->PSendSysMessage(LANG_PHASESHIFT_STATUS, phaseShift.Flags.AsUnderlyingType(),
+ phaseShift.PersonalGuid.ToString().c_str(), phaseOwnerName.c_str());
+
if (!phaseShift.Phases.empty())
{
std::ostringstream phases;
@@ -601,6 +617,14 @@ std::string PhasingHandler::FormatPhases(PhaseShift const& phaseShift)
return phases.str();
}
+bool PhasingHandler::IsPersonalPhase(uint32 phaseId)
+{
+ if (PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseId))
+ return phase->GetFlags().HasFlag(PhaseEntryFlags::Personal);
+
+ return false;
+}
+
void PhasingHandler::UpdateVisibilityIfNeeded(WorldObject* object, bool updateVisibility, bool changed)
{
if (changed && object->IsInWorld())
diff --git a/src/server/game/Phasing/PhasingHandler.h b/src/server/game/Phasing/PhasingHandler.h
index 73003029cfc..17d40977e56 100644
--- a/src/server/game/Phasing/PhasingHandler.h
+++ b/src/server/game/Phasing/PhasingHandler.h
@@ -59,6 +59,7 @@ public:
static PhaseShift const& GetEmptyPhaseShift();
static void InitDbPhaseShift(PhaseShift& phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId);
+ static void InitDbPersonalOwnership(PhaseShift& phaseShift, ObjectGuid const& personalGuid);
static void InitDbVisibleMapId(PhaseShift& phaseShift, int32 visibleMapId);
static bool InDbPhaseShift(WorldObject const* object, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId);
@@ -67,9 +68,11 @@ public:
static void SetAlwaysVisible(WorldObject* object, bool apply, bool updateVisibility);
static void SetInversed(WorldObject* object, bool apply, bool updateVisibility);
- static void PrintToChat(ChatHandler* chat, PhaseShift const& phaseShift);
+ static void PrintToChat(ChatHandler* chat, WorldObject const* target);
static std::string FormatPhases(PhaseShift const& phaseShift);
+ static bool IsPersonalPhase(uint32 phaseId);
+
private:
static void AddPhase(WorldObject* object, uint32 phaseId, ObjectGuid const& personalGuid, bool updateVisibility);
static void AddPhaseGroup(WorldObject* object, uint32 phaseGroupId, ObjectGuid const& personalGuid, bool updateVisibility);
diff --git a/src/server/game/Pools/PoolMgr.cpp b/src/server/game/Pools/PoolMgr.cpp
index d9402f7797a..070323fc99d 100644
--- a/src/server/game/Pools/PoolMgr.cpp
+++ b/src/server/game/Pools/PoolMgr.cpp
@@ -175,7 +175,7 @@ void PoolGroup<Creature>::Despawn1Object(uint64 guid)
{
if (CreatureData const* data = sObjectMgr->GetCreatureData(guid))
{
- sObjectMgr->RemoveCreatureFromGrid(guid, data);
+ sObjectMgr->RemoveCreatureFromGrid(data);
Map* map = sMapMgr->FindMap(data->mapId, 0);
if (map && !map->Instanceable())
@@ -200,7 +200,7 @@ void PoolGroup<GameObject>::Despawn1Object(uint64 guid)
{
if (GameObjectData const* data = sObjectMgr->GetGameObjectData(guid))
{
- sObjectMgr->RemoveGameobjectFromGrid(guid, data);
+ sObjectMgr->RemoveGameobjectFromGrid(data);
Map* map = sMapMgr->FindMap(data->mapId, 0);
if (map && !map->Instanceable())
@@ -320,7 +320,7 @@ void PoolGroup<Creature>::Spawn1Object(PoolObject* obj)
{
if (CreatureData const* data = sObjectMgr->GetCreatureData(obj->guid))
{
- sObjectMgr->AddCreatureToGrid(obj->guid, data);
+ sObjectMgr->AddCreatureToGrid(data);
// Spawn if necessary (loaded grids only)
Map* map = sMapMgr->FindMap(data->mapId, 0);
@@ -336,7 +336,7 @@ void PoolGroup<GameObject>::Spawn1Object(PoolObject* obj)
{
if (GameObjectData const* data = sObjectMgr->GetGameObjectData(obj->guid))
{
- sObjectMgr->AddGameobjectToGrid(obj->guid, data);
+ sObjectMgr->AddGameobjectToGrid(data);
// Spawn if necessary (loaded grids only)
// this base map checked as non-instanced and then only existed
Map* map = sMapMgr->FindMap(data->mapId, 0);
diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp
index 6de82fcd0eb..e66fbe3e573 100644
--- a/src/server/scripts/Commands/cs_debug.cpp
+++ b/src/server/scripts/Commands/cs_debug.cpp
@@ -1453,7 +1453,7 @@ public:
else if (target->GetDBPhase() < 0)
handler->PSendSysMessage("Target creature's PhaseGroup in DB: %d", abs(target->GetDBPhase()));
- PhasingHandler::PrintToChat(handler, target->GetPhaseShift());
+ PhasingHandler::PrintToChat(handler, target);
return true;
}
diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp
index 3bf6b0ba3f2..debd992ebec 100644
--- a/src/server/scripts/Commands/cs_gobject.cpp
+++ b/src/server/scripts/Commands/cs_gobject.cpp
@@ -183,7 +183,7 @@ public:
return false;
/// @todo is it really necessary to add both the real and DB table guid here ?
- sObjectMgr->AddGameobjectToGrid(spawnId, ASSERT_NOTNULL(sObjectMgr->GetGameObjectData(spawnId)));
+ sObjectMgr->AddGameobjectToGrid(ASSERT_NOTNULL(sObjectMgr->GetGameObjectData(spawnId)));
handler->PSendSysMessage(LANG_GAMEOBJECT_ADD, objectId, objectInfo->name.c_str(), std::to_string(spawnId).c_str(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
return true;
@@ -487,9 +487,9 @@ public:
object->Relocate(x, y, z, object->GetOrientation());
// update which cell has this gameobject registered for loading
- sObjectMgr->RemoveGameobjectFromGrid(guidLow, object->GetGameObjectData());
+ sObjectMgr->RemoveGameobjectFromGrid(object->GetGameObjectData());
object->SaveToDB();
- sObjectMgr->AddGameobjectToGrid(guidLow, object->GetGameObjectData());
+ sObjectMgr->AddGameobjectToGrid(object->GetGameObjectData());
// Generate a completely new spawn with new guid
// 3.3.5a client caches recently deleted objects and brings them back to life
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 7bf851699ca..d7515aa40aa 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -302,7 +302,7 @@ public:
if (status)
handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, uint32(liquidStatus.type_flags.AsUnderlyingType()), status);
- PhasingHandler::PrintToChat(handler, object->GetPhaseShift());
+ PhasingHandler::PrintToChat(handler, object);
return true;
}
@@ -1905,7 +1905,7 @@ public:
// Output XIII. phases
if (target)
- PhasingHandler::PrintToChat(handler, target->GetPhaseShift());
+ PhasingHandler::PrintToChat(handler, target);
// Output XIV. LANG_PINFO_CHR_MONEY
uint32 gold = money / GOLD;
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 06c092f9de2..2c32d1b6687 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -225,7 +225,7 @@ public:
if (Creature* creature = trans->CreateNPCPassenger(guid, &data))
{
creature->SaveToDB(trans->GetGOInfo()->moTransport.SpawnMap, { map->GetDifficultyID() });
- sObjectMgr->AddCreatureToGrid(guid, &data);
+ sObjectMgr->AddCreatureToGrid(&data);
}
return true;
}
@@ -248,7 +248,7 @@ public:
if (!creature)
return false;
- sObjectMgr->AddCreatureToGrid(db_guid, sObjectMgr->GetCreatureData(db_guid));
+ sObjectMgr->AddCreatureToGrid(sObjectMgr->GetCreatureData(db_guid));
return true;
}
@@ -697,7 +697,7 @@ public:
if (CreatureData const* data = sObjectMgr->GetCreatureData(target->GetSpawnId()))
{
handler->PSendSysMessage(LANG_NPCINFO_PHASES, data->phaseId, data->phaseGroup);
- PhasingHandler::PrintToChat(handler, target->GetPhaseShift());
+ PhasingHandler::PrintToChat(handler, target);
}
handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor());
@@ -812,9 +812,9 @@ public:
}
// update position in memory
- sObjectMgr->RemoveCreatureFromGrid(lowguid, data);
+ sObjectMgr->RemoveCreatureFromGrid(data);
const_cast<CreatureData*>(data)->spawnPoint.Relocate(*player);
- sObjectMgr->AddCreatureToGrid(lowguid, data);
+ sObjectMgr->AddCreatureToGrid(data);
// update position in DB
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_POSITION);