Core/Maps: Removed MapInstanced - no longer neccessary for grid data reference counting (moved to TerrainInfo)
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
#include "Item.h"
|
||||
#include "LanguageMgr.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "PhasingHandler.h"
|
||||
|
||||
@@ -28,11 +28,9 @@
|
||||
#include "GroupMgr.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "MapManager.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "WorldSession.h"
|
||||
#include <G3D/g3dmath.h>
|
||||
|
||||
Battlefield::Battlefield(Map* map)
|
||||
|
||||
@@ -37,8 +37,6 @@
|
||||
#include "GameEventMgr.h"
|
||||
#include "Language.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "MapInstanced.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
|
||||
@@ -1430,7 +1430,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
|
||||
|
||||
// Check enter rights before map getting to avoid creating instance copy for player
|
||||
// this check not dependent from map instance copy and same for all instance copies of selected map
|
||||
if (sMapMgr->PlayerCannotEnter(mapid, this, false))
|
||||
if (Map::PlayerCannotEnter(mapid, this, false))
|
||||
return false;
|
||||
|
||||
// Seamless teleport can happen only if cosmetic maps match
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "GameObjectAI.h"
|
||||
#include "GameTime.h"
|
||||
#include "Log.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "PhasingHandler.h"
|
||||
#include "Player.h"
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "GameTime.h"
|
||||
#include "Language.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
|
||||
@@ -100,8 +100,8 @@ void GarrisonGridLoader::Visit(CreatureMapType& /*m*/)
|
||||
|
||||
}
|
||||
|
||||
GarrisonMap::GarrisonMap(uint32 id, time_t expiry, uint32 instanceId, Map* parent, ObjectGuid const& owner)
|
||||
: Map(id, expiry, instanceId, DIFFICULTY_NORMAL, parent), _owner(owner), _loadingPlayer(nullptr)
|
||||
GarrisonMap::GarrisonMap(uint32 id, time_t expiry, uint32 instanceId, ObjectGuid const& owner)
|
||||
: Map(id, expiry, instanceId, DIFFICULTY_NORMAL), _owner(owner), _loadingPlayer(nullptr)
|
||||
{
|
||||
GarrisonMap::InitVisibilityDistance();
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class Player;
|
||||
class TC_GAME_API GarrisonMap : public Map
|
||||
{
|
||||
public:
|
||||
GarrisonMap(uint32 id, time_t, uint32 instanceId, Map* parent, ObjectGuid const& owner);
|
||||
GarrisonMap(uint32 id, time_t, uint32 instanceId, ObjectGuid const& owner);
|
||||
|
||||
void LoadGridObjects(NGridType* grid, Cell const& cell) override;
|
||||
Garrison* GetGarrison();
|
||||
|
||||
@@ -36,9 +36,11 @@
|
||||
#include "Guild.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "InstancePackets.h"
|
||||
#include "InstanceSaveMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Language.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "MapManager.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "Object.h"
|
||||
@@ -571,7 +573,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::AreaTrigger::AreaTrigge
|
||||
bool teleported = false;
|
||||
if (player->GetMapId() != at->target_mapId)
|
||||
{
|
||||
if (Map::EnterState denyReason = sMapMgr->PlayerCannotEnter(at->target_mapId, player, false))
|
||||
if (Map::EnterState denyReason = Map::PlayerCannotEnter(at->target_mapId, player, false))
|
||||
{
|
||||
bool reviveAtTrigger = false; // should we revive the player if he is trying to enter the correct instance?
|
||||
switch (denyReason)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "InstancePackets.h"
|
||||
#include "InstanceSaveMgr.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "MapManager.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "MovementPackets.h"
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "InstanceScript.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "MapInstanced.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
@@ -607,7 +606,7 @@ void InstanceSaveManager::_ResetSave(InstanceSaveHashMap::iterator &itr)
|
||||
void InstanceSaveManager::_ResetInstance(uint32 mapid, uint32 instanceId)
|
||||
{
|
||||
TC_LOG_DEBUG("maps", "InstanceSaveMgr::_ResetInstance %u, %u", mapid, instanceId);
|
||||
Map const* map = sMapMgr->CreateBaseMap(mapid);
|
||||
MapEntry const* map = sMapStore.LookupEntry(mapid);
|
||||
if (!map->IsDungeon())
|
||||
return;
|
||||
|
||||
@@ -617,7 +616,7 @@ void InstanceSaveManager::_ResetInstance(uint32 mapid, uint32 instanceId)
|
||||
|
||||
DeleteInstanceFromDB(instanceId); // even if save not loaded
|
||||
|
||||
Map* iMap = ((MapInstanced*)map)->FindInstanceMap(instanceId);
|
||||
Map* iMap = sMapMgr->FindMap(mapid, instanceId);
|
||||
if (iMap)
|
||||
{
|
||||
((InstanceMap*)iMap)->Reset(INSTANCE_RESET_RESPAWN_DELAY);
|
||||
@@ -696,28 +695,23 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b
|
||||
}
|
||||
|
||||
// note: this isn't fast but it's meant to be executed very rarely
|
||||
Map const* map = sMapMgr->CreateBaseMap(mapid); // _not_ include difficulty
|
||||
MapInstanced::InstancedMaps &instMaps = ((MapInstanced*)map)->GetInstancedMaps();
|
||||
MapInstanced::InstancedMaps::iterator mitr;
|
||||
uint32 timeLeft;
|
||||
|
||||
for (mitr = instMaps.begin(); mitr != instMaps.end(); ++mitr)
|
||||
if (mapEntry->IsDungeon())
|
||||
{
|
||||
Map* map2 = mitr->second;
|
||||
if (!map2->IsDungeon())
|
||||
continue;
|
||||
|
||||
if (warn)
|
||||
sMapMgr->DoForAllMapsWithMapId(mapid, [=](Map* map)
|
||||
{
|
||||
if (now >= resetTime)
|
||||
timeLeft = 0;
|
||||
else
|
||||
timeLeft = uint32(resetTime - now);
|
||||
if (warn)
|
||||
{
|
||||
uint32 timeLeft;
|
||||
if (now >= resetTime)
|
||||
timeLeft = 0;
|
||||
else
|
||||
timeLeft = uint32(resetTime - now);
|
||||
|
||||
((InstanceMap*)map2)->SendResetWarnings(timeLeft);
|
||||
}
|
||||
else
|
||||
((InstanceMap*)map2)->Reset(INSTANCE_RESET_GLOBAL);
|
||||
((InstanceMap*)map)->SendResetWarnings(timeLeft);
|
||||
}
|
||||
else
|
||||
((InstanceMap*)map)->Reset(INSTANCE_RESET_GLOBAL);
|
||||
});
|
||||
}
|
||||
|
||||
/// @todo delete creature/gameobject respawn times even if the maps are not loaded
|
||||
|
||||
+163
-111
@@ -32,10 +32,10 @@
|
||||
#include "GridStates.h"
|
||||
#include "Group.h"
|
||||
#include "InstancePackets.h"
|
||||
#include "InstanceSaveMgr.h"
|
||||
#include "InstanceScenario.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Log.h"
|
||||
#include "MapInstanced.h"
|
||||
#include "MapManager.h"
|
||||
#include "Metric.h"
|
||||
#include "MiscPackets.h"
|
||||
@@ -126,7 +126,7 @@ void Map::DeleteStateMachine()
|
||||
delete si_GridStates[GRID_STATE_REMOVAL];
|
||||
}
|
||||
|
||||
Map::Map(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode, Map* /*_parent*/) :
|
||||
Map::Map(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode) :
|
||||
_creatureToMoveLock(false), _gameObjectsToMoveLock(false), _dynamicObjectsToMoveLock(false), _areaTriggersToMoveLock(false),
|
||||
i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId),
|
||||
m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE),
|
||||
@@ -309,15 +309,9 @@ void Map::DeleteFromWorld(Player* player)
|
||||
delete player;
|
||||
}
|
||||
|
||||
void Map::EnsureGridCreated(GridCoord const& p)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_gridLock);
|
||||
EnsureGridCreated_i(p);
|
||||
}
|
||||
|
||||
//Create NGrid so the object can be added to it
|
||||
//But object data is not loaded here
|
||||
void Map::EnsureGridCreated_i(GridCoord const& p)
|
||||
void Map::EnsureGridCreated(GridCoord const& p)
|
||||
{
|
||||
if (!getNGrid(p.x_coord, p.y_coord))
|
||||
{
|
||||
@@ -1760,6 +1754,86 @@ bool Map::getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, floa
|
||||
return result;
|
||||
}
|
||||
|
||||
Map::EnterState Map::PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
{
|
||||
MapEntry const* entry = sMapStore.LookupEntry(mapid);
|
||||
if (!entry)
|
||||
return CANNOT_ENTER_NO_ENTRY;
|
||||
|
||||
if (!entry->IsDungeon())
|
||||
return CAN_ENTER;
|
||||
|
||||
Difficulty targetDifficulty, requestedDifficulty;
|
||||
targetDifficulty = requestedDifficulty = player->GetDifficultyID(entry);
|
||||
// Get the highest available difficulty if current setting is higher than the instance allows
|
||||
MapDifficultyEntry const* mapDiff = sDB2Manager.GetDownscaledMapDifficultyData(mapid, targetDifficulty);
|
||||
if (!mapDiff)
|
||||
return CANNOT_ENTER_DIFFICULTY_UNAVAILABLE;
|
||||
|
||||
//Bypass checks for GMs
|
||||
if (player->IsGameMaster())
|
||||
return CAN_ENTER;
|
||||
|
||||
//Other requirements
|
||||
if (!player->Satisfy(sObjectMgr->GetAccessRequirement(mapid, targetDifficulty), mapid, true))
|
||||
return CANNOT_ENTER_UNSPECIFIED_REASON;
|
||||
|
||||
char const* mapName = entry->MapName[sWorld->GetDefaultDbcLocale()];
|
||||
|
||||
Group* group = player->GetGroup();
|
||||
if (entry->IsRaid() && entry->Expansion() >= sWorld->getIntConfig(CONFIG_EXPANSION)) // can only enter in a raid group but raids from old expansion don't need a group
|
||||
if ((!group || !group->isRaidGroup()) && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID))
|
||||
return CANNOT_ENTER_NOT_IN_RAID;
|
||||
|
||||
if (!player->IsAlive())
|
||||
{
|
||||
if (player->HasCorpse())
|
||||
{
|
||||
// let enter in ghost mode in instance that connected to inner instance with corpse
|
||||
uint32 corpseMap = player->GetCorpseLocation().GetMapId();
|
||||
do
|
||||
{
|
||||
if (corpseMap == mapid)
|
||||
break;
|
||||
|
||||
InstanceTemplate const* corpseInstance = sObjectMgr->GetInstanceTemplate(corpseMap);
|
||||
corpseMap = corpseInstance ? corpseInstance->Parent : 0;
|
||||
} while (corpseMap);
|
||||
|
||||
if (!corpseMap)
|
||||
return CANNOT_ENTER_CORPSE_IN_DIFFERENT_INSTANCE;
|
||||
|
||||
TC_LOG_DEBUG("maps", "MAP: Player '%s' has corpse in instance '%s' and can enter.", player->GetName().c_str(), mapName);
|
||||
}
|
||||
else
|
||||
TC_LOG_DEBUG("maps", "Map::CanPlayerEnter - player '%s' is dead but does not have a corpse!", player->GetName().c_str());
|
||||
}
|
||||
|
||||
//Get instance where player's group is bound & its map
|
||||
if (!loginCheck && group)
|
||||
{
|
||||
InstanceGroupBind* boundInstance = group->GetBoundInstance(entry);
|
||||
if (boundInstance && boundInstance->save)
|
||||
if (Map* boundMap = sMapMgr->FindMap(mapid, boundInstance->save->GetInstanceId()))
|
||||
if (EnterState denyReason = boundMap->CannotEnter(player))
|
||||
return denyReason;
|
||||
}
|
||||
|
||||
// players are only allowed to enter 5 instances per hour
|
||||
if (entry->IsDungeon() && (!player->GetGroup() || (player->GetGroup() && !player->GetGroup()->isLFGGroup())))
|
||||
{
|
||||
uint32 instanceIdToCheck = 0;
|
||||
if (InstanceSave* save = player->GetInstanceSave(mapid))
|
||||
instanceIdToCheck = save->GetInstanceId();
|
||||
|
||||
// instanceId can never be 0 - will not be found
|
||||
if (!player->CheckInstanceCount(instanceIdToCheck) && !player->isDead())
|
||||
return CANNOT_ENTER_TOO_MANY_INSTANCES;
|
||||
}
|
||||
|
||||
return CAN_ENTER;
|
||||
}
|
||||
|
||||
char const* Map::GetMapName() const
|
||||
{
|
||||
return i_mapEntry->MapName[sWorld->GetDefaultDbcLocale()];
|
||||
@@ -2695,8 +2769,8 @@ template TC_GAME_API void Map::RemoveFromMap(Conversation*, bool);
|
||||
|
||||
/* ******* Dungeon Instance Maps ******* */
|
||||
|
||||
InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode, Map* _parent, TeamId InstanceTeam)
|
||||
: Map(id, expiry, InstanceId, SpawnMode, _parent),
|
||||
InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode, TeamId InstanceTeam)
|
||||
: Map(id, expiry, InstanceId, SpawnMode),
|
||||
m_resetAfterUnload(false), m_unloadWhenEmpty(false),
|
||||
i_data(nullptr), i_script_id(0), i_script_team(InstanceTeam), i_scenario(nullptr)
|
||||
{
|
||||
@@ -2763,113 +2837,98 @@ Map::EnterState InstanceMap::CannotEnter(Player* player)
|
||||
*/
|
||||
bool InstanceMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
|
||||
{
|
||||
/// @todo Not sure about checking player level: already done in HandleAreaTriggerOpcode
|
||||
// GMs still can teleport player in instance.
|
||||
// Is it needed?
|
||||
Group* group = player->GetGroup();
|
||||
|
||||
// increase current instances (hourly limit)
|
||||
if (!group || !group->isLFGGroup())
|
||||
player->AddInstanceEnterTime(GetInstanceId(), GameTime::GetGameTime());
|
||||
|
||||
// get or create an instance save for the map
|
||||
InstanceSave* mapSave = sInstanceSaveMgr->GetInstanceSave(GetInstanceId());
|
||||
if (!mapSave)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mapLock);
|
||||
// Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
|
||||
//if (!CanEnter(player))
|
||||
//return false;
|
||||
TC_LOG_DEBUG("maps", "InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetDifficultyID(), GetInstanceId());
|
||||
mapSave = sInstanceSaveMgr->AddInstanceSave(GetId(), GetInstanceId(), GetDifficultyID(), 0, 0, true);
|
||||
}
|
||||
|
||||
// Dungeon only code
|
||||
if (IsDungeon())
|
||||
ASSERT(mapSave);
|
||||
|
||||
// check for existing instance binds
|
||||
InstancePlayerBind* playerBind = player->GetBoundInstance(GetId(), GetDifficultyID());
|
||||
if (playerBind && playerBind->perm)
|
||||
{
|
||||
// cannot enter other instances if bound permanently
|
||||
if (playerBind->save != mapSave)
|
||||
{
|
||||
Group* group = player->GetGroup();
|
||||
|
||||
// increase current instances (hourly limit)
|
||||
if (!group || !group->isLFGGroup())
|
||||
player->AddInstanceEnterTime(GetInstanceId(), GameTime::GetGameTime());
|
||||
|
||||
// get or create an instance save for the map
|
||||
InstanceSave* mapSave = sInstanceSaveMgr->GetInstanceSave(GetInstanceId());
|
||||
if (!mapSave)
|
||||
TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is permanently bound to instance %s %d, %d, %d, %d, %d, %d but he is being put into instance %s %d, %d, %d, %d, %d, %d", player->GetName().c_str(), player->GetGUID().ToString().c_str(), GetMapName(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficultyID()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (group)
|
||||
{
|
||||
// solo saves should have been reset when the map was loaded
|
||||
InstanceGroupBind* groupBind = group->GetBoundInstance(this);
|
||||
if (playerBind && playerBind->save != mapSave)
|
||||
{
|
||||
TC_LOG_DEBUG("maps", "InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetDifficultyID(), GetInstanceId());
|
||||
mapSave = sInstanceSaveMgr->AddInstanceSave(GetId(), GetInstanceId(), GetDifficultyID(), 0, 0, true);
|
||||
}
|
||||
|
||||
ASSERT(mapSave);
|
||||
|
||||
// check for existing instance binds
|
||||
InstancePlayerBind* playerBind = player->GetBoundInstance(GetId(), GetDifficultyID());
|
||||
if (playerBind && playerBind->perm)
|
||||
{
|
||||
// cannot enter other instances if bound permanently
|
||||
if (playerBind->save != mapSave)
|
||||
{
|
||||
TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is permanently bound to instance %s %d, %d, %d, %d, %d, %d but he is being put into instance %s %d, %d, %d, %d, %d, %d", player->GetName().c_str(), player->GetGUID().ToString().c_str(), GetMapName(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficultyID()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset());
|
||||
return false;
|
||||
}
|
||||
TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is being put into instance %s %d, %d, %d, %d, %d, %d but he is in group %s and is bound to instance %d, %d, %d, %d, %d, %d!", player->GetName().c_str(), player->GetGUID().ToString().c_str(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), group->GetLeaderGUID().ToString().c_str(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficultyID()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
|
||||
if (groupBind)
|
||||
TC_LOG_ERROR("maps", "InstanceMap::Add: the group is bound to the instance %s %d, %d, %d, %d, %d, %d", GetMapName(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficultyID()), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
|
||||
//ABORT();
|
||||
return false;
|
||||
}
|
||||
// bind to the group or keep using the group save
|
||||
if (!groupBind)
|
||||
group->BindToInstance(mapSave, false);
|
||||
else
|
||||
{
|
||||
if (group)
|
||||
// cannot jump to a different instance without resetting it
|
||||
if (groupBind->save != mapSave)
|
||||
{
|
||||
// solo saves should have been reset when the map was loaded
|
||||
InstanceGroupBind* groupBind = group->GetBoundInstance(this);
|
||||
if (playerBind && playerBind->save != mapSave)
|
||||
{
|
||||
TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is being put into instance %s %d, %d, %d, %d, %d, %d but he is in group %s and is bound to instance %d, %d, %d, %d, %d, %d!", player->GetName().c_str(), player->GetGUID().ToString().c_str(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), group->GetLeaderGUID().ToString().c_str(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficultyID()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
|
||||
if (groupBind)
|
||||
TC_LOG_ERROR("maps", "InstanceMap::Add: the group is bound to the instance %s %d, %d, %d, %d, %d, %d", GetMapName(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficultyID()), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
|
||||
//ABORT();
|
||||
return false;
|
||||
}
|
||||
// bind to the group or keep using the group save
|
||||
if (!groupBind)
|
||||
group->BindToInstance(mapSave, false);
|
||||
TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is being put into instance %d, %d, %d but he is in group %s which is bound to instance %d, %d, %d!", player->GetName().c_str(), player->GetGUID().ToString().c_str(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), group->GetLeaderGUID().ToString().c_str(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficultyID()));
|
||||
TC_LOG_ERROR("maps", "MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount());
|
||||
if (groupBind->save)
|
||||
TC_LOG_ERROR("maps", "GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
|
||||
else
|
||||
{
|
||||
// cannot jump to a different instance without resetting it
|
||||
if (groupBind->save != mapSave)
|
||||
{
|
||||
TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is being put into instance %d, %d, %d but he is in group %s which is bound to instance %d, %d, %d!", player->GetName().c_str(), player->GetGUID().ToString().c_str(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), group->GetLeaderGUID().ToString().c_str(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficultyID()));
|
||||
TC_LOG_ERROR("maps", "MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount());
|
||||
if (groupBind->save)
|
||||
TC_LOG_ERROR("maps", "GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
|
||||
else
|
||||
TC_LOG_ERROR("maps", "GroupBind save NULL");
|
||||
return false;
|
||||
}
|
||||
// if the group/leader is permanently bound to the instance
|
||||
// players also become permanently bound when they enter
|
||||
if (groupBind->perm)
|
||||
{
|
||||
WorldPackets::Instance::PendingRaidLock pendingRaidLock;
|
||||
pendingRaidLock.TimeUntilLock = 60000;
|
||||
pendingRaidLock.CompletedMask = i_data ? i_data->GetCompletedEncounterMask() : 0;
|
||||
pendingRaidLock.Extending = false;
|
||||
pendingRaidLock.WarningOnly = false; // events it throws: 1 : INSTANCE_LOCK_WARNING 0 : INSTANCE_LOCK_STOP / INSTANCE_LOCK_START
|
||||
player->SendDirectMessage(pendingRaidLock.Write());
|
||||
player->SetPendingBind(mapSave->GetInstanceId(), 60000);
|
||||
}
|
||||
}
|
||||
TC_LOG_ERROR("maps", "GroupBind save NULL");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
// if the group/leader is permanently bound to the instance
|
||||
// players also become permanently bound when they enter
|
||||
if (groupBind->perm)
|
||||
{
|
||||
// set up a solo bind or continue using it
|
||||
if (!playerBind)
|
||||
player->BindToInstance(mapSave, false);
|
||||
else
|
||||
// cannot jump to a different instance without resetting it
|
||||
ASSERT(playerBind->save == mapSave);
|
||||
WorldPackets::Instance::PendingRaidLock pendingRaidLock;
|
||||
pendingRaidLock.TimeUntilLock = 60000;
|
||||
pendingRaidLock.CompletedMask = i_data ? i_data->GetCompletedEncounterMask() : 0;
|
||||
pendingRaidLock.Extending = false;
|
||||
pendingRaidLock.WarningOnly = false; // events it throws: 1 : INSTANCE_LOCK_WARNING 0 : INSTANCE_LOCK_STOP / INSTANCE_LOCK_START
|
||||
player->SendDirectMessage(pendingRaidLock.Write());
|
||||
player->SetPendingBind(mapSave->GetInstanceId(), 60000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for normal instances cancel the reset schedule when the
|
||||
// first player enters (no players yet)
|
||||
SetResetSchedule(false);
|
||||
|
||||
TC_LOG_DEBUG("maps", "MAP: Player '%s' entered instance '%u' of map '%s'", player->GetName().c_str(), GetInstanceId(), GetMapName());
|
||||
// initialize unload state
|
||||
m_unloadTimer = 0;
|
||||
m_resetAfterUnload = false;
|
||||
m_unloadWhenEmpty = false;
|
||||
else
|
||||
{
|
||||
// set up a solo bind or continue using it
|
||||
if (!playerBind)
|
||||
player->BindToInstance(mapSave, false);
|
||||
else
|
||||
// cannot jump to a different instance without resetting it
|
||||
ASSERT(playerBind->save == mapSave);
|
||||
}
|
||||
}
|
||||
|
||||
// for normal instances cancel the reset schedule when the
|
||||
// first player enters (no players yet)
|
||||
SetResetSchedule(false);
|
||||
|
||||
TC_LOG_DEBUG("maps", "MAP: Player '%s' entered instance '%u' of map '%s'", player->GetName().c_str(), GetInstanceId(), GetMapName());
|
||||
// initialize unload state
|
||||
m_unloadTimer = 0;
|
||||
m_resetAfterUnload = false;
|
||||
m_unloadWhenEmpty = false;
|
||||
|
||||
// this will acquire the same mutex so it cannot be in the previous block
|
||||
Map::AddPlayerToMap(player, initPlayer);
|
||||
|
||||
@@ -3213,8 +3272,8 @@ uint32 InstanceMap::GetMaxResetDelay() const
|
||||
|
||||
/* ******* Battleground Instance Maps ******* */
|
||||
|
||||
BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, Difficulty spawnMode)
|
||||
: Map(id, expiry, InstanceId, spawnMode, _parent), m_bg(nullptr)
|
||||
BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Difficulty spawnMode)
|
||||
: Map(id, expiry, InstanceId, spawnMode), m_bg(nullptr)
|
||||
{
|
||||
//lets initialize visibility distance for BG/Arenas
|
||||
BattlegroundMap::InitVisibilityDistance();
|
||||
@@ -3256,14 +3315,7 @@ Map::EnterState BattlegroundMap::CannotEnter(Player* player)
|
||||
|
||||
bool BattlegroundMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mapLock);
|
||||
//Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
|
||||
//if (!CanEnter(player))
|
||||
//return false;
|
||||
// reset instance validity, battleground maps do not homebind
|
||||
player->m_InstanceValid = true;
|
||||
}
|
||||
player->m_InstanceValid = true;
|
||||
return Map::AddPlayerToMap(player, initPlayer);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ class InstanceMap;
|
||||
class InstanceSave;
|
||||
class InstanceScript;
|
||||
class InstanceScenario;
|
||||
class MapInstanced;
|
||||
class Object;
|
||||
class PhaseShift;
|
||||
class Player;
|
||||
@@ -145,7 +144,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
{
|
||||
friend class MapReference;
|
||||
public:
|
||||
Map(uint32 id, time_t, uint32 InstanceId, Difficulty SpawnMode, Map* _parent = nullptr);
|
||||
Map(uint32 id, time_t, uint32 InstanceId, Difficulty SpawnMode);
|
||||
virtual ~Map();
|
||||
|
||||
MapEntry const* GetEntry() const { return i_mapEntry; }
|
||||
@@ -274,6 +273,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
CANNOT_ENTER_ZONE_IN_COMBAT, // A boss encounter is currently in progress on the target map
|
||||
CANNOT_ENTER_UNSPECIFIED_REASON
|
||||
};
|
||||
static EnterState PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck = false);
|
||||
virtual EnterState CannotEnter(Player* /*player*/) { return CAN_ENTER; }
|
||||
char const* GetMapName() const;
|
||||
|
||||
@@ -402,9 +402,6 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MapInstanced* ToMapInstanced() { if (Instanceable()) return reinterpret_cast<MapInstanced*>(this); return nullptr; }
|
||||
MapInstanced const* ToMapInstanced() const { if (Instanceable()) return reinterpret_cast<MapInstanced const*>(this); return nullptr; }
|
||||
|
||||
InstanceMap* ToInstanceMap() { if (IsDungeon()) return reinterpret_cast<InstanceMap*>(this); else return nullptr; }
|
||||
InstanceMap const* ToInstanceMap() const { if (IsDungeon()) return reinterpret_cast<InstanceMap const*>(this); return nullptr; }
|
||||
|
||||
@@ -538,7 +535,6 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
|
||||
bool IsGridLoaded(GridCoord const&) const;
|
||||
void EnsureGridCreated(GridCoord const&);
|
||||
void EnsureGridCreated_i(GridCoord const&);
|
||||
bool EnsureGridLoaded(Cell const&);
|
||||
void EnsureGridLoadedForActiveObject(Cell const&, WorldObject const* object);
|
||||
|
||||
@@ -561,9 +557,6 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
protected:
|
||||
virtual void LoadGridObjects(NGridType* grid, Cell const& cell);
|
||||
|
||||
std::mutex _mapLock;
|
||||
std::mutex _gridLock;
|
||||
|
||||
MapEntry const* i_mapEntry;
|
||||
Difficulty i_spawnMode;
|
||||
uint32 i_InstanceId;
|
||||
@@ -803,7 +796,7 @@ enum InstanceResetMethod
|
||||
class TC_GAME_API InstanceMap : public Map
|
||||
{
|
||||
public:
|
||||
InstanceMap(uint32 id, time_t, uint32 InstanceId, Difficulty SpawnMode, Map* _parent, TeamId InstanceTeam);
|
||||
InstanceMap(uint32 id, time_t, uint32 InstanceId, Difficulty SpawnMode, TeamId InstanceTeam);
|
||||
~InstanceMap();
|
||||
bool AddPlayerToMap(Player* player, bool initPlayer = true) override;
|
||||
void RemovePlayerFromMap(Player*, bool) override;
|
||||
@@ -846,7 +839,7 @@ class TC_GAME_API InstanceMap : public Map
|
||||
class TC_GAME_API BattlegroundMap : public Map
|
||||
{
|
||||
public:
|
||||
BattlegroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent, Difficulty spawnMode);
|
||||
BattlegroundMap(uint32 id, time_t, uint32 InstanceId, Difficulty spawnMode);
|
||||
~BattlegroundMap();
|
||||
|
||||
bool AddPlayerToMap(Player* player, bool initPlayer = true) override;
|
||||
|
||||
@@ -1,311 +0,0 @@
|
||||
/*
|
||||
* 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 "MapInstanced.h"
|
||||
#include "Battleground.h"
|
||||
#include "DB2Stores.h"
|
||||
#include "GarrisonMap.h"
|
||||
#include "Group.h"
|
||||
#include "InstanceSaveMgr.h"
|
||||
#include "Log.h"
|
||||
#include "MapManager.h"
|
||||
#include "MMapFactory.h"
|
||||
#include "Player.h"
|
||||
#include "ScenarioMgr.h"
|
||||
#include "VMapFactory.h"
|
||||
#include "VMapManager2.h"
|
||||
#include "World.h"
|
||||
|
||||
MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DIFFICULTY_NORMAL)
|
||||
{
|
||||
}
|
||||
|
||||
MapInstanced::~MapInstanced() = default;
|
||||
|
||||
void MapInstanced::InitVisibilityDistance()
|
||||
{
|
||||
if (m_InstancedMaps.empty())
|
||||
return;
|
||||
//initialize visibility distances for all instance copies
|
||||
for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
|
||||
{
|
||||
(*i).second->InitVisibilityDistance();
|
||||
}
|
||||
}
|
||||
|
||||
void MapInstanced::Update(uint32 t)
|
||||
{
|
||||
// take care of loaded GridMaps (when unused, unload it!)
|
||||
Map::Update(t);
|
||||
|
||||
// update the instanced maps
|
||||
InstancedMaps::iterator i = m_InstancedMaps.begin();
|
||||
|
||||
while (i != m_InstancedMaps.end())
|
||||
{
|
||||
if (i->second->CanUnload(t))
|
||||
{
|
||||
if (!DestroyInstance(i)) // iterator incremented
|
||||
{
|
||||
//m_unloadTimer
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// update only here, because it may schedule some bad things before delete
|
||||
if (sMapMgr->GetMapUpdater()->activated())
|
||||
sMapMgr->GetMapUpdater()->schedule_update(*i->second, t);
|
||||
else
|
||||
i->second->Update(t);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MapInstanced::DelayedUpdate(uint32 diff)
|
||||
{
|
||||
for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
|
||||
i->second->DelayedUpdate(diff);
|
||||
|
||||
Map::DelayedUpdate(diff); // this may be removed
|
||||
}
|
||||
|
||||
/*
|
||||
void MapInstanced::RelocationNotify()
|
||||
{
|
||||
for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
|
||||
i->second->RelocationNotify();
|
||||
}
|
||||
*/
|
||||
|
||||
void MapInstanced::UnloadAll()
|
||||
{
|
||||
// Unload instanced maps
|
||||
for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
|
||||
i->second->UnloadAll();
|
||||
|
||||
// Delete the maps only after everything is unloaded to prevent crashes
|
||||
for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
|
||||
delete i->second;
|
||||
|
||||
m_InstancedMaps.clear();
|
||||
|
||||
// Unload own grids (just dummy(placeholder) grids, neccesary to unload GridMaps!)
|
||||
Map::UnloadAll();
|
||||
}
|
||||
|
||||
/*
|
||||
- return the right instance for the object, based on its InstanceId
|
||||
- create the instance if it's not created already
|
||||
- the player is not actually added to the instance (only in InstanceMap::Add)
|
||||
*/
|
||||
Map* MapInstanced::CreateInstanceForPlayer(uint32 mapId, Player* player, uint32 loginInstanceId /*= 0*/)
|
||||
{
|
||||
if (GetId() != mapId || !player)
|
||||
return nullptr;
|
||||
|
||||
Map* map = nullptr;
|
||||
uint32 newInstanceId = 0; // instanceId of the resulting map
|
||||
|
||||
if (IsBattlegroundOrArena())
|
||||
{
|
||||
// instantiate or find existing bg map for player
|
||||
// the instance id is set in battlegroundid
|
||||
newInstanceId = player->GetBattlegroundId();
|
||||
if (!newInstanceId)
|
||||
return nullptr;
|
||||
|
||||
map = sMapMgr->FindMap(mapId, newInstanceId);
|
||||
if (!map)
|
||||
{
|
||||
if (Battleground* bg = player->GetBattleground())
|
||||
map = CreateBattleground(newInstanceId, bg);
|
||||
else
|
||||
{
|
||||
player->TeleportToBGEntryPoint();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsDungeon())
|
||||
{
|
||||
InstancePlayerBind* pBind = player->GetBoundInstance(GetId(), player->GetDifficultyID(GetEntry()));
|
||||
InstanceSave* pSave = pBind ? pBind->save : nullptr;
|
||||
|
||||
// priority:
|
||||
// 1. player's permanent bind
|
||||
// 2. player's current instance id if this is at login
|
||||
// 3. group's current bind
|
||||
// 4. player's current bind
|
||||
if (!pBind || !pBind->perm)
|
||||
{
|
||||
if (loginInstanceId) // if the player has a saved instance id on login, we either use this instance or relocate him out (return null)
|
||||
{
|
||||
map = FindInstanceMap(loginInstanceId);
|
||||
if (!map && pSave && pSave->GetInstanceId() == loginInstanceId)
|
||||
map = CreateInstance(loginInstanceId, pSave, pSave->GetDifficultyID(), player->GetTeamId());
|
||||
return map;
|
||||
}
|
||||
|
||||
InstanceGroupBind* groupBind = nullptr;
|
||||
Group* group = player->GetGroup();
|
||||
// use the player's difficulty setting (it may not be the same as the group's)
|
||||
if (group)
|
||||
{
|
||||
groupBind = group->GetBoundInstance(this);
|
||||
if (groupBind)
|
||||
{
|
||||
// solo saves should be reset when entering a group's instance
|
||||
player->UnbindInstance(GetId(), player->GetDifficultyID(GetEntry()));
|
||||
pSave = groupBind->save;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pSave)
|
||||
{
|
||||
// solo/perm/group
|
||||
newInstanceId = pSave->GetInstanceId();
|
||||
map = FindInstanceMap(newInstanceId);
|
||||
// it is possible that the save exists but the map doesn't
|
||||
if (!map)
|
||||
map = CreateInstance(newInstanceId, pSave, pSave->GetDifficultyID(), player->GetTeamId());
|
||||
}
|
||||
else
|
||||
{
|
||||
// if no instanceId via group members or instance saves is found
|
||||
// the instance will be created for the first time
|
||||
newInstanceId = sMapMgr->GenerateInstanceId();
|
||||
|
||||
Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficultyID(GetEntry()) : player->GetDifficultyID(GetEntry());
|
||||
//Seems it is now possible, but I do not know if it should be allowed
|
||||
//ASSERT(!FindInstanceMap(NewInstanceId));
|
||||
map = FindInstanceMap(newInstanceId);
|
||||
if (!map)
|
||||
map = CreateInstance(newInstanceId, nullptr, diff, player->GetTeamId());
|
||||
}
|
||||
}
|
||||
else if (IsGarrison())
|
||||
{
|
||||
newInstanceId = player->GetGUID().GetCounter();
|
||||
map = FindInstanceMap(newInstanceId);
|
||||
if (!map)
|
||||
map = CreateGarrison(newInstanceId, player);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty, TeamId team)
|
||||
{
|
||||
// load/create a map
|
||||
std::lock_guard<std::mutex> lock(_mapLock);
|
||||
|
||||
// make sure we have a valid map id
|
||||
MapEntry const* entry = sMapStore.LookupEntry(GetId());
|
||||
if (!entry)
|
||||
{
|
||||
TC_LOG_ERROR("maps", "CreateInstance: no entry for map %d", GetId());
|
||||
ABORT();
|
||||
}
|
||||
|
||||
// some instances only have one difficulty
|
||||
sDB2Manager.GetDownscaledMapDifficultyData(GetId(), difficulty);
|
||||
|
||||
TC_LOG_DEBUG("maps", "MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %u", save ? "" : "new ", InstanceId, GetId(), static_cast<uint32>(difficulty));
|
||||
|
||||
InstanceMap* map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this, team);
|
||||
ASSERT(map->IsDungeon());
|
||||
|
||||
map->LoadRespawnTimes();
|
||||
map->LoadCorpseData();
|
||||
|
||||
bool load_data = save != nullptr;
|
||||
map->CreateInstanceData(load_data);
|
||||
if (InstanceScenario* instanceScenario = sScenarioMgr->CreateInstanceScenario(map, team))
|
||||
map->SetInstanceScenario(instanceScenario);
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_INSTANCEMAP_LOAD_GRIDS))
|
||||
map->LoadAllCells();
|
||||
|
||||
m_InstancedMaps[InstanceId] = map;
|
||||
return map;
|
||||
}
|
||||
|
||||
BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battleground* bg)
|
||||
{
|
||||
// load/create a map
|
||||
std::lock_guard<std::mutex> lock(_mapLock);
|
||||
|
||||
TC_LOG_DEBUG("maps", "MapInstanced::CreateBattleground: map bg %d for %d created.", InstanceId, GetId());
|
||||
|
||||
BattlegroundMap* map = new BattlegroundMap(GetId(), GetGridExpiry(), InstanceId, this, DIFFICULTY_NONE);
|
||||
ASSERT(map->IsBattlegroundOrArena());
|
||||
map->SetBG(bg);
|
||||
bg->SetBgMap(map);
|
||||
|
||||
m_InstancedMaps[InstanceId] = map;
|
||||
return map;
|
||||
}
|
||||
|
||||
GarrisonMap* MapInstanced::CreateGarrison(uint32 instanceId, Player* owner)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mapLock);
|
||||
|
||||
GarrisonMap* map = new GarrisonMap(GetId(), GetGridExpiry(), instanceId, this, owner->GetGUID());
|
||||
ASSERT(map->IsGarrison());
|
||||
|
||||
m_InstancedMaps[instanceId] = map;
|
||||
return map;
|
||||
}
|
||||
|
||||
// increments the iterator after erase
|
||||
bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr)
|
||||
{
|
||||
itr->second->RemoveAllPlayers();
|
||||
if (itr->second->HavePlayers())
|
||||
{
|
||||
++itr;
|
||||
return false;
|
||||
}
|
||||
|
||||
itr->second->UnloadAll();
|
||||
// should only unload VMaps if this is the last instance and grid unloading is enabled
|
||||
if (m_InstancedMaps.size() <= 1 && sWorld->getBoolConfig(CONFIG_GRID_UNLOAD))
|
||||
{
|
||||
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(itr->second->GetId());
|
||||
MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(itr->second->GetId());
|
||||
// in that case, unload grids of the base map, too
|
||||
// so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded
|
||||
Map::UnloadAll();
|
||||
}
|
||||
|
||||
// Free up the instance id and allow it to be reused for bgs and arenas (other instances are handled in the InstanceSaveMgr)
|
||||
if (itr->second->IsBattlegroundOrArena())
|
||||
sMapMgr->FreeInstanceId(itr->second->GetInstanceId());
|
||||
|
||||
// erase map
|
||||
delete itr->second;
|
||||
m_InstancedMaps.erase(itr++);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Map::EnterState MapInstanced::CannotEnter(Player* /*player*/)
|
||||
{
|
||||
//ABORT();
|
||||
return CAN_ENTER;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* 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 TRINITY_MAP_INSTANCED_H
|
||||
#define TRINITY_MAP_INSTANCED_H
|
||||
|
||||
#include "Map.h"
|
||||
#include "InstanceSaveMgr.h"
|
||||
|
||||
class GarrisonMap;
|
||||
|
||||
class TC_GAME_API MapInstanced : public Map
|
||||
{
|
||||
friend class MapManager;
|
||||
public:
|
||||
typedef std::unordered_map< uint32, Map*> InstancedMaps;
|
||||
|
||||
MapInstanced(uint32 id, time_t expiry);
|
||||
MapInstanced(MapInstanced const& right) = delete;
|
||||
MapInstanced(MapInstanced&& right) = delete;
|
||||
MapInstanced& operator=(MapInstanced const& right) = delete;
|
||||
MapInstanced& operator=(MapInstanced&& right) = delete;
|
||||
~MapInstanced();
|
||||
|
||||
// functions overwrite Map versions
|
||||
void Update(uint32 diff) override;
|
||||
void DelayedUpdate(uint32 diff) override;
|
||||
//void RelocationNotify();
|
||||
void UnloadAll() override;
|
||||
EnterState CannotEnter(Player* /*player*/) override;
|
||||
|
||||
Map* CreateInstanceForPlayer(uint32 mapId, Player* player, uint32 loginInstanceId = 0);
|
||||
Map* FindInstanceMap(uint32 instanceId) const
|
||||
{
|
||||
InstancedMaps::const_iterator i = m_InstancedMaps.find(instanceId);
|
||||
return(i == m_InstancedMaps.end() ? nullptr : i->second);
|
||||
}
|
||||
bool DestroyInstance(InstancedMaps::iterator &itr);
|
||||
|
||||
InstancedMaps &GetInstancedMaps() { return m_InstancedMaps; }
|
||||
virtual void InitVisibilityDistance() override;
|
||||
|
||||
private:
|
||||
InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty, TeamId team);
|
||||
BattlegroundMap* CreateBattleground(uint32 InstanceId, Battleground* bg);
|
||||
GarrisonMap* CreateGarrison(uint32 instanceId, Player* owner);
|
||||
|
||||
InstancedMaps m_InstancedMaps;
|
||||
};
|
||||
#endif
|
||||
+207
-165
@@ -16,22 +16,20 @@
|
||||
*/
|
||||
|
||||
#include "MapManager.h"
|
||||
#include "Config.h"
|
||||
#include "Corpse.h"
|
||||
#include "Battleground.h"
|
||||
#include "Containers.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "DB2Stores.h"
|
||||
#include "GridDefines.h"
|
||||
#include "GarrisonMap.h"
|
||||
#include "Group.h"
|
||||
#include "InstanceSaveMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Log.h"
|
||||
#include "MapInstanced.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Map.h"
|
||||
#include "Player.h"
|
||||
#include "Transport.h"
|
||||
#include "ScenarioMgr.h"
|
||||
#include "World.h"
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
#include <numeric>
|
||||
|
||||
MapManager::MapManager()
|
||||
: _freeInstanceIds(std::make_unique<InstanceIds>()), _nextInstanceId(0), _scheduledScripts(0)
|
||||
@@ -40,7 +38,7 @@ MapManager::MapManager()
|
||||
i_timer.SetInterval(sWorld->getIntConfig(CONFIG_INTERVAL_MAPUPDATE));
|
||||
}
|
||||
|
||||
MapManager::~MapManager() { }
|
||||
MapManager::~MapManager() = default;
|
||||
|
||||
void MapManager::Initialize()
|
||||
{
|
||||
@@ -64,157 +62,195 @@ MapManager* MapManager::instance()
|
||||
return &instance;
|
||||
}
|
||||
|
||||
Map* MapManager::CreateBaseMap(uint32 id)
|
||||
Map* MapManager::FindMap_i(uint32 mapId, uint32 instanceId) const
|
||||
{
|
||||
Map* map = FindBaseMap(id);
|
||||
|
||||
if (!map)
|
||||
{
|
||||
MapEntry const* entry = sMapStore.AssertEntry(id);
|
||||
if (entry->ParentMapID != -1 || entry->CosmeticParentMapID != -1)
|
||||
{
|
||||
CreateBaseMap(entry->ParentMapID != -1 ? entry->ParentMapID : entry->CosmeticParentMapID);
|
||||
|
||||
// must have been created by parent map
|
||||
map = FindBaseMap(id);
|
||||
return ASSERT_NOTNULL(map);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(_mapsLock);
|
||||
map = CreateBaseMap_i(entry);
|
||||
}
|
||||
|
||||
ASSERT(map);
|
||||
return map;
|
||||
return Trinity::Containers::MapGetValuePtr(i_maps, { mapId, instanceId });
|
||||
}
|
||||
|
||||
Map* MapManager::CreateBaseMap_i(MapEntry const* mapEntry)
|
||||
Map* MapManager::CreateWorldMap(uint32 mapId, uint32 instanceId)
|
||||
{
|
||||
Map* map;
|
||||
if (mapEntry->Instanceable())
|
||||
map = new MapInstanced(mapEntry->ID, i_gridCleanUpDelay);
|
||||
else
|
||||
map = new Map(mapEntry->ID, i_gridCleanUpDelay, 0, DIFFICULTY_NONE);
|
||||
Map* map = new Map(mapId, i_gridCleanUpDelay, instanceId, DIFFICULTY_NONE);
|
||||
map->LoadRespawnTimes();
|
||||
map->LoadCorpseData();
|
||||
|
||||
i_maps[mapEntry->ID] = map;
|
||||
|
||||
if (!mapEntry->Instanceable())
|
||||
{
|
||||
map->LoadRespawnTimes();
|
||||
map->LoadCorpseData();
|
||||
}
|
||||
if (sWorld->getBoolConfig(CONFIG_BASEMAP_LOAD_GRIDS))
|
||||
map->LoadAllCells();
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
Map* MapManager::FindBaseNonInstanceMap(uint32 mapId) const
|
||||
InstanceMap* MapManager::CreateInstance(uint32 mapId, uint32 instanceId, InstanceSave* save, Difficulty difficulty, TeamId team)
|
||||
{
|
||||
Map* map = FindBaseMap(mapId);
|
||||
if (map && map->Instanceable())
|
||||
return nullptr;
|
||||
return map;
|
||||
}
|
||||
|
||||
Map* MapManager::CreateMap(uint32 id, Player* player, uint32 loginInstanceId)
|
||||
{
|
||||
Map* m = CreateBaseMap(id);
|
||||
|
||||
if (m && m->Instanceable())
|
||||
m = ((MapInstanced*)m)->CreateInstanceForPlayer(id, player, loginInstanceId);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
Map* MapManager::FindMap(uint32 mapid, uint32 instanceId) const
|
||||
{
|
||||
Map* map = FindBaseMap(mapid);
|
||||
if (!map)
|
||||
return nullptr;
|
||||
|
||||
if (!map->Instanceable())
|
||||
return instanceId == 0 ? map : nullptr;
|
||||
|
||||
return ((MapInstanced*)map)->FindInstanceMap(instanceId);
|
||||
}
|
||||
|
||||
Map::EnterState MapManager::PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
{
|
||||
MapEntry const* entry = sMapStore.LookupEntry(mapid);
|
||||
// make sure we have a valid map id
|
||||
MapEntry const* entry = sMapStore.LookupEntry(mapId);
|
||||
if (!entry)
|
||||
return Map::CANNOT_ENTER_NO_ENTRY;
|
||||
|
||||
if (!entry->IsDungeon())
|
||||
return Map::CAN_ENTER;
|
||||
|
||||
Difficulty targetDifficulty, requestedDifficulty;
|
||||
targetDifficulty = requestedDifficulty = player->GetDifficultyID(entry);
|
||||
// Get the highest available difficulty if current setting is higher than the instance allows
|
||||
MapDifficultyEntry const* mapDiff = sDB2Manager.GetDownscaledMapDifficultyData(mapid, targetDifficulty);
|
||||
if (!mapDiff)
|
||||
return Map::CANNOT_ENTER_DIFFICULTY_UNAVAILABLE;
|
||||
|
||||
//Bypass checks for GMs
|
||||
if (player->IsGameMaster())
|
||||
return Map::CAN_ENTER;
|
||||
|
||||
//Other requirements
|
||||
if (!player->Satisfy(sObjectMgr->GetAccessRequirement(mapid, targetDifficulty), mapid, true))
|
||||
return Map::CANNOT_ENTER_UNSPECIFIED_REASON;
|
||||
|
||||
char const* mapName = entry->MapName[sWorld->GetDefaultDbcLocale()];
|
||||
|
||||
Group* group = player->GetGroup();
|
||||
if (entry->IsRaid() && entry->Expansion() >= sWorld->getIntConfig(CONFIG_EXPANSION)) // can only enter in a raid group but raids from old expansion don't need a group
|
||||
if ((!group || !group->isRaidGroup()) && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID))
|
||||
return Map::CANNOT_ENTER_NOT_IN_RAID;
|
||||
|
||||
if (!player->IsAlive())
|
||||
{
|
||||
if (player->HasCorpse())
|
||||
TC_LOG_ERROR("maps", "CreateInstance: no entry for map %d", mapId);
|
||||
ABORT();
|
||||
}
|
||||
|
||||
// some instances only have one difficulty
|
||||
sDB2Manager.GetDownscaledMapDifficultyData(mapId, difficulty);
|
||||
|
||||
TC_LOG_DEBUG("maps", "MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %u", save ? "" : "new ", instanceId, mapId, static_cast<uint32>(difficulty));
|
||||
|
||||
InstanceMap* map = new InstanceMap(mapId, i_gridCleanUpDelay, instanceId, difficulty, team);
|
||||
ASSERT(map->IsDungeon());
|
||||
|
||||
map->LoadRespawnTimes();
|
||||
map->LoadCorpseData();
|
||||
|
||||
bool load_data = save != nullptr;
|
||||
map->CreateInstanceData(load_data);
|
||||
if (InstanceScenario* instanceScenario = sScenarioMgr->CreateInstanceScenario(map, team))
|
||||
map->SetInstanceScenario(instanceScenario);
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_INSTANCEMAP_LOAD_GRIDS))
|
||||
map->LoadAllCells();
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
BattlegroundMap* MapManager::CreateBattleground(uint32 mapId, uint32 instanceId, Battleground* bg)
|
||||
{
|
||||
TC_LOG_DEBUG("maps", "MapInstanced::CreateBattleground: map bg %d for %d created.", instanceId, mapId);
|
||||
|
||||
BattlegroundMap* map = new BattlegroundMap(mapId, i_gridCleanUpDelay, instanceId, DIFFICULTY_NONE);
|
||||
ASSERT(map->IsBattlegroundOrArena());
|
||||
map->SetBG(bg);
|
||||
bg->SetBgMap(map);
|
||||
return map;
|
||||
}
|
||||
|
||||
GarrisonMap* MapManager::CreateGarrison(uint32 mapId, uint32 instanceId, Player* owner)
|
||||
{
|
||||
GarrisonMap* map = new GarrisonMap(mapId, i_gridCleanUpDelay, instanceId, owner->GetGUID());
|
||||
ASSERT(map->IsGarrison());
|
||||
return map;
|
||||
}
|
||||
|
||||
/*
|
||||
- return the right instance for the object, based on its InstanceId
|
||||
- create the instance if it's not created already
|
||||
- the player is not actually added to the instance (only in InstanceMap::Add)
|
||||
*/
|
||||
Map* MapManager::CreateMap(uint32 mapId, Player* player, uint32 loginInstanceId /*= 0*/)
|
||||
{
|
||||
if (!player)
|
||||
return nullptr;
|
||||
|
||||
MapEntry const* entry = sMapStore.LookupEntry(mapId);
|
||||
if (!entry)
|
||||
return nullptr;
|
||||
|
||||
std::unique_lock<std::shared_mutex> lock(_mapsLock);
|
||||
|
||||
Map* map = nullptr;
|
||||
uint32 newInstanceId = 0; // instanceId of the resulting map
|
||||
|
||||
if (entry->IsBattlegroundOrArena())
|
||||
{
|
||||
// instantiate or find existing bg map for player
|
||||
// the instance id is set in battlegroundid
|
||||
newInstanceId = player->GetBattlegroundId();
|
||||
if (!newInstanceId)
|
||||
return nullptr;
|
||||
|
||||
map = FindMap(mapId, newInstanceId);
|
||||
if (!map)
|
||||
{
|
||||
// let enter in ghost mode in instance that connected to inner instance with corpse
|
||||
uint32 corpseMap = player->GetCorpseLocation().GetMapId();
|
||||
do
|
||||
if (Battleground* bg = player->GetBattleground())
|
||||
map = CreateBattleground(mapId, newInstanceId, bg);
|
||||
else
|
||||
{
|
||||
if (corpseMap == mapid)
|
||||
break;
|
||||
player->TeleportToBGEntryPoint();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (entry->IsDungeon())
|
||||
{
|
||||
InstancePlayerBind* pBind = player->GetBoundInstance(mapId, player->GetDifficultyID(entry));
|
||||
InstanceSave* pSave = pBind ? pBind->save : nullptr;
|
||||
|
||||
InstanceTemplate const* corpseInstance = sObjectMgr->GetInstanceTemplate(corpseMap);
|
||||
corpseMap = corpseInstance ? corpseInstance->Parent : 0;
|
||||
} while (corpseMap);
|
||||
// priority:
|
||||
// 1. player's permanent bind
|
||||
// 2. player's current instance id if this is at login
|
||||
// 3. group's current bind
|
||||
// 4. player's current bind
|
||||
if (!pBind || !pBind->perm)
|
||||
{
|
||||
if (loginInstanceId) // if the player has a saved instance id on login, we either use this instance or relocate him out (return null)
|
||||
{
|
||||
map = FindMap_i(mapId, loginInstanceId);
|
||||
if (!map && pSave && pSave->GetInstanceId() == loginInstanceId)
|
||||
map = CreateInstance(mapId, loginInstanceId, pSave, pSave->GetDifficultyID(), player->GetTeamId());
|
||||
return map;
|
||||
}
|
||||
|
||||
if (!corpseMap)
|
||||
return Map::CANNOT_ENTER_CORPSE_IN_DIFFERENT_INSTANCE;
|
||||
|
||||
TC_LOG_DEBUG("maps", "MAP: Player '%s' has corpse in instance '%s' and can enter.", player->GetName().c_str(), mapName);
|
||||
InstanceGroupBind* groupBind = nullptr;
|
||||
Group* group = player->GetGroup();
|
||||
// use the player's difficulty setting (it may not be the same as the group's)
|
||||
if (group)
|
||||
{
|
||||
groupBind = group->GetBoundInstance(entry);
|
||||
if (groupBind)
|
||||
{
|
||||
// solo saves should be reset when entering a group's instance
|
||||
player->UnbindInstance(mapId, player->GetDifficultyID(entry));
|
||||
pSave = groupBind->save;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pSave)
|
||||
{
|
||||
// solo/perm/group
|
||||
newInstanceId = pSave->GetInstanceId();
|
||||
map = FindMap_i(mapId, newInstanceId);
|
||||
// it is possible that the save exists but the map doesn't
|
||||
if (!map)
|
||||
map = CreateInstance(mapId, newInstanceId, pSave, pSave->GetDifficultyID(), player->GetTeamId());
|
||||
}
|
||||
else
|
||||
TC_LOG_DEBUG("maps", "Map::CanPlayerEnter - player '%s' is dead but does not have a corpse!", player->GetName().c_str());
|
||||
}
|
||||
{
|
||||
Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficultyID(entry) : player->GetDifficultyID(entry);
|
||||
|
||||
//Get instance where player's group is bound & its map
|
||||
if (!loginCheck && group)
|
||||
// if no instanceId via group members or instance saves is found
|
||||
// the instance will be created for the first time
|
||||
newInstanceId = GenerateInstanceId();
|
||||
|
||||
//Seems it is now possible, but I do not know if it should be allowed
|
||||
//ASSERT(!FindInstanceMap(NewInstanceId));
|
||||
map = FindMap_i(mapId, newInstanceId);
|
||||
if (!map)
|
||||
map = CreateInstance(mapId, newInstanceId, nullptr, diff, player->GetTeamId());
|
||||
}
|
||||
}
|
||||
else if (entry->IsGarrison())
|
||||
{
|
||||
InstanceGroupBind* boundInstance = group->GetBoundInstance(entry);
|
||||
if (boundInstance && boundInstance->save)
|
||||
if (Map* boundMap = sMapMgr->FindMap(mapid, boundInstance->save->GetInstanceId()))
|
||||
if (Map::EnterState denyReason = boundMap->CannotEnter(player))
|
||||
return denyReason;
|
||||
newInstanceId = player->GetGUID().GetCounter();
|
||||
map = FindMap_i(mapId, newInstanceId);
|
||||
if (!map)
|
||||
map = CreateGarrison(mapId, newInstanceId, player);
|
||||
}
|
||||
|
||||
// players are only allowed to enter 5 instances per hour
|
||||
if (entry->IsDungeon() && (!player->GetGroup() || (player->GetGroup() && !player->GetGroup()->isLFGGroup())))
|
||||
else
|
||||
{
|
||||
uint32 instanceIdToCheck = 0;
|
||||
if (InstanceSave* save = player->GetInstanceSave(mapid))
|
||||
instanceIdToCheck = save->GetInstanceId();
|
||||
|
||||
// instanceId can never be 0 - will not be found
|
||||
if (!player->CheckInstanceCount(instanceIdToCheck) && !player->isDead())
|
||||
return Map::CANNOT_ENTER_TOO_MANY_INSTANCES;
|
||||
newInstanceId = 0;
|
||||
map = FindMap_i(mapId, newInstanceId);
|
||||
if (!map)
|
||||
map = CreateWorldMap(mapId, newInstanceId);
|
||||
}
|
||||
|
||||
return Map::CAN_ENTER;
|
||||
if (map)
|
||||
i_maps[{ map->GetId(), map->GetInstanceId() }] = map;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
Map* MapManager::FindMap(uint32 mapId, uint32 instanceId) const
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(_mapsLock);
|
||||
return FindMap_i(mapId, instanceId);
|
||||
}
|
||||
|
||||
void MapManager::Update(uint32 diff)
|
||||
@@ -224,12 +260,24 @@ void MapManager::Update(uint32 diff)
|
||||
return;
|
||||
|
||||
MapMapType::iterator iter = i_maps.begin();
|
||||
for (; iter != i_maps.end(); ++iter)
|
||||
while (iter != i_maps.end())
|
||||
{
|
||||
if (iter->second->CanUnload(diff))
|
||||
{
|
||||
if (DestroyMap(iter->second))
|
||||
iter = i_maps.erase(iter);
|
||||
else
|
||||
++iter;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_updater.activated())
|
||||
m_updater.schedule_update(*iter->second, uint32(i_timer.GetCurrent()));
|
||||
else
|
||||
iter->second->Update(uint32(i_timer.GetCurrent()));
|
||||
|
||||
++iter;
|
||||
}
|
||||
if (m_updater.activated())
|
||||
m_updater.wait();
|
||||
@@ -240,7 +288,22 @@ void MapManager::Update(uint32 diff)
|
||||
i_timer.SetCurrent(0);
|
||||
}
|
||||
|
||||
void MapManager::DoDelayedMovesAndRemoves() { }
|
||||
bool MapManager::DestroyMap(Map* map)
|
||||
{
|
||||
map->RemoveAllPlayers();
|
||||
if (map->HavePlayers())
|
||||
return false;
|
||||
|
||||
map->UnloadAll();
|
||||
|
||||
// Free up the instance id and allow it to be reused for bgs and arenas (other instances are handled in the InstanceSaveMgr)
|
||||
if (map->IsBattlegroundOrArena())
|
||||
sMapMgr->FreeInstanceId(map->GetInstanceId());
|
||||
|
||||
// erase map
|
||||
delete map;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MapManager::IsValidMAP(uint32 mapId)
|
||||
{
|
||||
@@ -265,37 +328,16 @@ void MapManager::UnloadAll()
|
||||
Map::DeleteStateMachine();
|
||||
}
|
||||
|
||||
uint32 MapManager::GetNumInstances()
|
||||
uint32 MapManager::GetNumInstances() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mapsLock);
|
||||
|
||||
uint32 ret = 0;
|
||||
for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr)
|
||||
{
|
||||
Map* map = itr->second;
|
||||
if (!map->IsDungeon())
|
||||
continue;
|
||||
MapInstanced::InstancedMaps &maps = ((MapInstanced*)map)->GetInstancedMaps();
|
||||
ret += maps.size();
|
||||
}
|
||||
return ret;
|
||||
std::shared_lock<std::shared_mutex> lock(_mapsLock);
|
||||
return std::count_if(i_maps.begin(), i_maps.end(), [](MapMapType::value_type const& value) { return value.second->IsDungeon(); });
|
||||
}
|
||||
|
||||
uint32 MapManager::GetNumPlayersInInstances()
|
||||
uint32 MapManager::GetNumPlayersInInstances() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mapsLock);
|
||||
|
||||
uint32 ret = 0;
|
||||
for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr)
|
||||
{
|
||||
Map* map = itr->second;
|
||||
if (!map->IsDungeon())
|
||||
continue;
|
||||
MapInstanced::InstancedMaps &maps = ((MapInstanced*)map)->GetInstancedMaps();
|
||||
for (MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr)
|
||||
ret += mitr->second->GetPlayers().getSize();
|
||||
}
|
||||
return ret;
|
||||
std::shared_lock<std::shared_mutex> lock(_mapsLock);
|
||||
return std::accumulate(i_maps.begin(), i_maps.end(), 0u, [](uint32 total, MapMapType::value_type const& value) { return total + (value.second->IsDungeon() ? value.second->GetPlayers().getSize() : 0); });
|
||||
}
|
||||
|
||||
void MapManager::InitInstanceIds()
|
||||
|
||||
@@ -18,27 +18,42 @@
|
||||
#ifndef TRINITY_MAPMANAGER_H
|
||||
#define TRINITY_MAPMANAGER_H
|
||||
|
||||
#include "Map.h"
|
||||
#include "MapInstanced.h"
|
||||
#include "GridStates.h"
|
||||
#include "GridDefines.h"
|
||||
#include "IteratorPair.h"
|
||||
#include "MapUpdater.h"
|
||||
#include "Position.h"
|
||||
#include "SharedDefines.h"
|
||||
#include <boost/dynamic_bitset_fwd.hpp>
|
||||
#include <map>
|
||||
#include <shared_mutex>
|
||||
|
||||
class PhaseShift;
|
||||
class Transport;
|
||||
class Battleground;
|
||||
class BattlegroundMap;
|
||||
class GarrisonMap;
|
||||
class InstanceMap;
|
||||
class InstanceSave;
|
||||
class Map;
|
||||
class Player;
|
||||
enum Difficulty : uint8;
|
||||
|
||||
class TC_GAME_API MapManager
|
||||
{
|
||||
MapManager();
|
||||
~MapManager();
|
||||
|
||||
public:
|
||||
MapManager(MapManager const&) = delete;
|
||||
MapManager(MapManager&&) = delete;
|
||||
MapManager& operator=(MapManager const&) = delete;
|
||||
MapManager& operator=(MapManager&&) = delete;
|
||||
|
||||
static MapManager* instance();
|
||||
|
||||
Map* CreateBaseMap(uint32 mapId);
|
||||
Map* FindBaseNonInstanceMap(uint32 mapId) const;
|
||||
Map* CreateMap(uint32 mapId, Player* player, uint32 loginInstanceId=0);
|
||||
Map* CreateMap(uint32 mapId, Player* player, uint32 loginInstanceId = 0);
|
||||
Map* FindMap(uint32 mapId, uint32 instanceId) const;
|
||||
|
||||
void Initialize();
|
||||
void Update(uint32);
|
||||
void Update(uint32 diff);
|
||||
|
||||
void SetGridCleanUpDelay(uint32 t)
|
||||
{
|
||||
@@ -57,7 +72,6 @@ class TC_GAME_API MapManager
|
||||
i_timer.Reset();
|
||||
}
|
||||
|
||||
//void LoadGrid(int mapid, int instId, float x, float y, WorldObject const* obj, bool no_unload = false);
|
||||
void UnloadAll();
|
||||
|
||||
static bool IsValidMAP(uint32 mapId);
|
||||
@@ -87,14 +101,11 @@ class TC_GAME_API MapManager
|
||||
return IsValidMapCoord(loc.GetMapId(), loc);
|
||||
}
|
||||
|
||||
void DoDelayedMovesAndRemoves();
|
||||
|
||||
Map::EnterState PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck = false);
|
||||
void InitializeVisibilityDistanceInfo();
|
||||
|
||||
/* statistics */
|
||||
uint32 GetNumInstances();
|
||||
uint32 GetNumPlayersInInstances();
|
||||
uint32 GetNumInstances() const;
|
||||
uint32 GetNumPlayersInInstances() const;
|
||||
|
||||
// Instance ID management
|
||||
void InitInstanceIds();
|
||||
@@ -116,24 +127,20 @@ class TC_GAME_API MapManager
|
||||
bool IsScriptScheduled() const { return _scheduledScripts > 0; }
|
||||
|
||||
private:
|
||||
typedef std::unordered_map<uint32, Map*> MapMapType;
|
||||
using MapKey = std::pair<uint32, uint32>;
|
||||
typedef std::map<MapKey, Map*> MapMapType;
|
||||
typedef boost::dynamic_bitset<size_t> InstanceIds;
|
||||
|
||||
MapManager();
|
||||
~MapManager();
|
||||
Map* FindMap_i(uint32 mapId, uint32 instanceId) const;
|
||||
|
||||
Map* FindBaseMap(uint32 mapId) const
|
||||
{
|
||||
MapMapType::const_iterator iter = i_maps.find(mapId);
|
||||
return (iter == i_maps.end() ? nullptr : iter->second);
|
||||
}
|
||||
Map* CreateWorldMap(uint32 mapId, uint32 instanceId);
|
||||
InstanceMap* CreateInstance(uint32 mapId, uint32 instanceId, InstanceSave* save, Difficulty difficulty, TeamId team);
|
||||
BattlegroundMap* CreateBattleground(uint32 mapId, uint32 instanceId, Battleground* bg);
|
||||
GarrisonMap* CreateGarrison(uint32 mapId, uint32 instanceId, Player* owner);
|
||||
|
||||
Map* CreateBaseMap_i(MapEntry const* mapEntry);
|
||||
bool DestroyMap(Map* map);
|
||||
|
||||
MapManager(MapManager const&) = delete;
|
||||
MapManager& operator=(MapManager const&) = delete;
|
||||
|
||||
std::mutex _mapsLock;
|
||||
mutable std::shared_mutex _mapsLock;
|
||||
uint32 i_gridCleanUpDelay;
|
||||
MapMapType i_maps;
|
||||
IntervalTimer i_timer;
|
||||
@@ -149,41 +156,26 @@ class TC_GAME_API MapManager
|
||||
template<typename Worker>
|
||||
void MapManager::DoForAllMaps(Worker&& worker)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mapsLock);
|
||||
std::shared_lock<std::shared_mutex> lock(_mapsLock);
|
||||
|
||||
for (auto& mapPair : i_maps)
|
||||
{
|
||||
Map* map = mapPair.second;
|
||||
if (MapInstanced* mapInstanced = map->ToMapInstanced())
|
||||
{
|
||||
MapInstanced::InstancedMaps& instances = mapInstanced->GetInstancedMaps();
|
||||
for (auto& instancePair : instances)
|
||||
worker(instancePair.second);
|
||||
}
|
||||
else
|
||||
worker(map);
|
||||
}
|
||||
for (auto const& [key, map] : i_maps)
|
||||
worker(map);
|
||||
}
|
||||
|
||||
template<typename Worker>
|
||||
inline void MapManager::DoForAllMapsWithMapId(uint32 mapId, Worker&& worker)
|
||||
void MapManager::DoForAllMapsWithMapId(uint32 mapId, Worker&& worker)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mapsLock);
|
||||
std::shared_lock<std::shared_mutex> lock(_mapsLock);
|
||||
|
||||
auto itr = i_maps.find(mapId);
|
||||
if (itr != i_maps.end())
|
||||
{
|
||||
Map* map = itr->second;
|
||||
if (MapInstanced* mapInstanced = map->ToMapInstanced())
|
||||
{
|
||||
MapInstanced::InstancedMaps& instances = mapInstanced->GetInstancedMaps();
|
||||
for (auto& p : instances)
|
||||
worker(p.second);
|
||||
}
|
||||
else
|
||||
worker(map);
|
||||
}
|
||||
auto range = Trinity::Containers::MakeIteratorPair(
|
||||
i_maps.lower_bound({ mapId, 0 }),
|
||||
i_maps.upper_bound({ mapId, std::numeric_limits<uint32>::max() })
|
||||
);
|
||||
|
||||
for (auto const& [key, map] : range)
|
||||
worker(map);
|
||||
}
|
||||
|
||||
#define sMapMgr MapManager::instance()
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,7 +35,11 @@ TerrainInfo::TerrainInfo(uint32 mapId) : _mapId(mapId), _parentTerrain(nullptr),
|
||||
{
|
||||
}
|
||||
|
||||
TerrainInfo::~TerrainInfo() = default;
|
||||
TerrainInfo::~TerrainInfo()
|
||||
{
|
||||
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId());
|
||||
MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(GetId());
|
||||
}
|
||||
|
||||
char const* TerrainInfo::GetMapName() const
|
||||
{
|
||||
@@ -69,7 +73,7 @@ void TerrainInfo::DiscoverGridMapFiles()
|
||||
|
||||
for (uint32 gx = 0; gx < MAX_NUMBER_OF_GRIDS; ++gx)
|
||||
for (uint32 gy = 0; gy < MAX_NUMBER_OF_GRIDS; ++gy)
|
||||
_gridFileExists[gx * MAX_NUMBER_OF_GRIDS + gy] = ExistMap(GetId(), gx, gy, false);
|
||||
_gridFileExists[GetBitsetIndex(gx, gy)] = ExistMap(GetId(), gx, gy, false);
|
||||
}
|
||||
|
||||
bool TerrainInfo::ExistMap(uint32 mapid, int32 gx, int32 gy, bool log /*= true*/)
|
||||
@@ -144,7 +148,7 @@ bool TerrainInfo::ExistVMap(uint32 mapid, int32 gx, int32 gy)
|
||||
bool TerrainInfo::HasChildTerrainGridFile(uint32 mapId, int32 gx, int32 gy) const
|
||||
{
|
||||
auto childMapItr = std::find_if(_childTerrain.begin(), _childTerrain.end(), [mapId](std::shared_ptr<TerrainInfo> const& childTerrain) { return childTerrain->GetId() == mapId; });
|
||||
return childMapItr != _childTerrain.end() && (*childMapItr)->_gridFileExists[gx * MAX_NUMBER_OF_GRIDS + gy];
|
||||
return childMapItr != _childTerrain.end() && (*childMapItr)->_gridFileExists[GetBitsetIndex(gx, gy)];
|
||||
}
|
||||
|
||||
void TerrainInfo::AddChildTerrain(std::shared_ptr<TerrainInfo> childTerrain)
|
||||
@@ -170,6 +174,8 @@ void TerrainInfo::LoadMapAndVMapImpl(int32 gx, int32 gy)
|
||||
|
||||
for (std::shared_ptr<TerrainInfo> const& childTerrain : _childTerrain)
|
||||
childTerrain->LoadMapAndVMapImpl(gx, gy);
|
||||
|
||||
_loadedGrids[GetBitsetIndex(gx, gy)] = true;
|
||||
}
|
||||
|
||||
void TerrainInfo::LoadMap(int32 gx, int32 gy)
|
||||
@@ -177,7 +183,7 @@ void TerrainInfo::LoadMap(int32 gx, int32 gy)
|
||||
if (_gridMap[gx][gy])
|
||||
return;
|
||||
|
||||
if (!_gridFileExists[gx * MAX_NUMBER_OF_GRIDS + gy])
|
||||
if (!_gridFileExists[GetBitsetIndex(gx, gy)])
|
||||
return;
|
||||
|
||||
// map file name
|
||||
@@ -189,7 +195,7 @@ void TerrainInfo::LoadMap(int32 gx, int32 gy)
|
||||
if (gridMapLoadResult == GridMap::LoadResult::Ok)
|
||||
_gridMap[gx][gy] = std::move(gridMap);
|
||||
else
|
||||
_gridFileExists[gx * MAX_NUMBER_OF_GRIDS + gy] = false;
|
||||
_gridFileExists[GetBitsetIndex(gx, gy)] = false;
|
||||
|
||||
if (gridMapLoadResult == GridMap::LoadResult::InvalidFile)
|
||||
TC_LOG_ERROR("maps", "Error loading map file: %s", fileName.c_str());
|
||||
@@ -206,12 +212,15 @@ void TerrainInfo::LoadVMap(int32 gx, int32 gy)
|
||||
case VMAP::LoadResult::Success:
|
||||
TC_LOG_DEBUG("maps", "VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
|
||||
break;
|
||||
default:
|
||||
case VMAP::LoadResult::VersionMismatch:
|
||||
case VMAP::LoadResult::ReadFromFileFailed:
|
||||
TC_LOG_ERROR("maps", "Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
|
||||
break;
|
||||
case VMAP::LoadResult::DisabledInConfig:
|
||||
TC_LOG_DEBUG("maps", "Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,6 +251,8 @@ void TerrainInfo::UnloadMapImpl(int32 gx, int32 gy)
|
||||
|
||||
for (std::shared_ptr<TerrainInfo> const& childTerrain : _childTerrain)
|
||||
childTerrain->UnloadMapImpl(gx, gy);
|
||||
|
||||
_loadedGrids[GetBitsetIndex(gx, gy)] = false;
|
||||
}
|
||||
|
||||
GridMap* TerrainInfo::GetGrid(uint32 mapId, float x, float y, bool loadIfMissing /*= true*/)
|
||||
@@ -251,7 +262,7 @@ GridMap* TerrainInfo::GetGrid(uint32 mapId, float x, float y, bool loadIfMissing
|
||||
int32 gy = (int)(CENTER_GRID_ID - y / SIZE_OF_GRIDS); //grid y
|
||||
|
||||
// ensure GridMap is loaded
|
||||
if (!_gridMap[gx][gy] && loadIfMissing)
|
||||
if (!_loadedGrids[GetBitsetIndex(gx, gy)] && loadIfMissing)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_loadMutex);
|
||||
LoadMapAndVMapImpl(gx, gy);
|
||||
@@ -277,7 +288,7 @@ void TerrainInfo::CleanUpGrids(uint32 diff)
|
||||
// delete those GridMap objects which have refcount = 0
|
||||
for (int32 x = 0; x < MAX_NUMBER_OF_GRIDS; ++x)
|
||||
for (int32 y = 0; y < MAX_NUMBER_OF_GRIDS; ++y)
|
||||
if (_gridMap[x][y] && !_referenceCountFromMap[x][y])
|
||||
if (_loadedGrids[GetBitsetIndex(x, y)] && !_referenceCountFromMap[x][y])
|
||||
UnloadMapImpl(x, y);
|
||||
|
||||
_cleanupTimer.Reset(CleanupInterval);
|
||||
|
||||
@@ -97,6 +97,8 @@ public:
|
||||
float GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground = nullptr, bool swim = false, float collisionHeight = 2.03128f, DynamicMapTree const* dynamicMapTree = nullptr); // DEFAULT_COLLISION_HEIGHT in Object.h
|
||||
|
||||
private:
|
||||
static constexpr int32 GetBitsetIndex(int32 gx, int32 gy) { return gx * MAX_NUMBER_OF_GRIDS + gy; }
|
||||
|
||||
uint32 _mapId;
|
||||
|
||||
TerrainInfo* _parentTerrain;
|
||||
@@ -105,6 +107,7 @@ private:
|
||||
std::mutex _loadMutex;
|
||||
std::unique_ptr<GridMap> _gridMap[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
|
||||
std::atomic<uint16> _referenceCountFromMap[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
|
||||
std::bitset<MAX_NUMBER_OF_GRIDS* MAX_NUMBER_OF_GRIDS> _loadedGrids;
|
||||
std::bitset<MAX_NUMBER_OF_GRIDS* MAX_NUMBER_OF_GRIDS> _gridFileExists; // cache what grids are available for this map (not including parent/child maps)
|
||||
|
||||
static constexpr Milliseconds CleanupInterval = 1min;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "DB2Stores.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Log.h"
|
||||
#include "MapManager.h"
|
||||
#include "Map.h"
|
||||
#include "MoveSplineInitArgs.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "DB2Stores.h"
|
||||
#include "GameEventSender.h"
|
||||
#include "Log.h"
|
||||
#include "MapManager.h"
|
||||
#include "Map.h"
|
||||
#include "MovementDefines.h"
|
||||
#include "MoveSpline.h"
|
||||
#include "MoveSplineInit.h"
|
||||
@@ -132,7 +132,7 @@ bool FlightPathMovementGenerator::DoUpdate(Player* owner, uint32 /*diff*/)
|
||||
break;
|
||||
|
||||
if (_currentNode == _preloadTargetNode)
|
||||
PreloadEndGrid();
|
||||
PreloadEndGrid(owner);
|
||||
|
||||
_currentNode += departureEvent ? 1 : 0;
|
||||
departureEvent = !departureEvent;
|
||||
@@ -284,14 +284,18 @@ void FlightPathMovementGenerator::InitEndGridInfo()
|
||||
_preloadTargetNode = 0;
|
||||
else
|
||||
_preloadTargetNode = nodeCount - 3;
|
||||
|
||||
while (_path[_preloadTargetNode]->ContinentID != _endMapId)
|
||||
++_preloadTargetNode;
|
||||
|
||||
_endGridX = _path[nodeCount - 1]->Loc.X;
|
||||
_endGridY = _path[nodeCount - 1]->Loc.Y;
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::PreloadEndGrid()
|
||||
void FlightPathMovementGenerator::PreloadEndGrid(Player* owner)
|
||||
{
|
||||
// Used to preload the final grid where the flightmaster is
|
||||
Map* endMap = sMapMgr->FindBaseNonInstanceMap(_endMapId);
|
||||
Map* endMap = owner->GetMap();
|
||||
|
||||
// Load the grid
|
||||
if (endMap)
|
||||
|
||||
@@ -54,7 +54,7 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium<Player, Fligh
|
||||
void SkipCurrentNode() { ++_currentNode; }
|
||||
void DoEventIfAny(Player* owner, TaxiPathNodeEntry const* node, bool departure);
|
||||
void InitEndGridInfo();
|
||||
void PreloadEndGrid();
|
||||
void PreloadEndGrid(Player* owner);
|
||||
|
||||
std::string GetDebugInfo() const override;
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "WaypointManager.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GridDefines.h"
|
||||
#include "MapManager.h"
|
||||
#include "Log.h"
|
||||
|
||||
void WaypointMgr::Load()
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "Group.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "OutdoorPvPMgr.h"
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
#include "LootItemStorage.h"
|
||||
#include "LootMgr.h"
|
||||
#include "M2Stores.h"
|
||||
#include "Map.h"
|
||||
#include "MapManager.h"
|
||||
#include "Metric.h"
|
||||
#include "MiscPackets.h"
|
||||
@@ -2493,19 +2494,6 @@ void World::SetInitialWorldSettings()
|
||||
TC_LOG_INFO("server.loading", "Loading phase names...");
|
||||
sObjectMgr->LoadPhaseNames();
|
||||
|
||||
// Preload all cells, if required for the base maps
|
||||
if (sWorld->getBoolConfig(CONFIG_BASEMAP_LOAD_GRIDS))
|
||||
{
|
||||
sMapMgr->DoForAllMaps([](Map* map)
|
||||
{
|
||||
if (!map->Instanceable())
|
||||
{
|
||||
TC_LOG_INFO("server.loading", "Pre-loading base map data for map %u", map->GetId());
|
||||
map->LoadAllCells();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uint32 startupDuration = GetMSTimeDiffToNow(startupBegin);
|
||||
|
||||
TC_LOG_INFO("server.worldserver", "World initialized in %u minutes %u seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000));
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "CreatureTextMgr.h"
|
||||
#include "GameObject.h"
|
||||
#include "GameTime.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
#include "Random.h"
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "GameObject.h"
|
||||
#include "GameTime.h"
|
||||
#include "Log.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
#include "Random.h"
|
||||
|
||||
@@ -37,6 +37,7 @@ EndScriptData */
|
||||
#include "DB2Stores.h"
|
||||
#include "GameTime.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "InstanceSaveMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Language.h"
|
||||
#include "Log.h"
|
||||
@@ -1233,17 +1234,26 @@ public:
|
||||
|
||||
static bool HandleDebugLoadCellsCommand(ChatHandler* handler, Optional<uint32> mapId, Optional<uint32> tileX, Optional<uint32> tileY)
|
||||
{
|
||||
Map* map = nullptr;
|
||||
if (mapId)
|
||||
{
|
||||
map = sMapMgr->FindBaseNonInstanceMap(*mapId);
|
||||
}
|
||||
else if (Player* player = handler->GetPlayer())
|
||||
{
|
||||
// Fallback to player's map if no map has been specified
|
||||
map = player->GetMap();
|
||||
sMapMgr->DoForAllMapsWithMapId(*mapId, [&](Map* map)
|
||||
{
|
||||
HandleDebugLoadCellsCommandHelper(handler, map, tileX, tileY);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Player* player = handler->GetPlayer())
|
||||
{
|
||||
// Fallback to player's map if no map has been specified
|
||||
return HandleDebugLoadCellsCommandHelper(handler, player->GetMap(), tileX, tileY);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HandleDebugLoadCellsCommandHelper(ChatHandler* handler, Map* map, Optional<uint32> tileX, Optional<uint32> tileY)
|
||||
{
|
||||
if (!map)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ EndScriptData */
|
||||
#include "GameTime.h"
|
||||
#include "Language.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
|
||||
@@ -31,6 +31,7 @@ EndScriptData */
|
||||
#include "InstanceSaveMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Language.h"
|
||||
#include "Map.h"
|
||||
#include "MapManager.h"
|
||||
#include "Player.h"
|
||||
#include "RBAC.h"
|
||||
|
||||
@@ -32,7 +32,7 @@ EndScriptData */
|
||||
#include "GameObject.h"
|
||||
#include "GameTime.h"
|
||||
#include "Language.h"
|
||||
#include "MapManager.h"
|
||||
#include "Map.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "PhasingHandler.h"
|
||||
#include "Player.h"
|
||||
@@ -120,28 +120,18 @@ public:
|
||||
bool liveFound = false;
|
||||
|
||||
// Get map (only support base map from console)
|
||||
Map* thisMap;
|
||||
Map* thisMap = nullptr;
|
||||
if (handler->GetSession())
|
||||
thisMap = handler->GetSession()->GetPlayer()->GetMap();
|
||||
else
|
||||
thisMap = sMapMgr->FindBaseNonInstanceMap(mapId);
|
||||
|
||||
// If map found, try to find active version of this creature
|
||||
if (thisMap)
|
||||
{
|
||||
auto const creBounds = thisMap->GetCreatureBySpawnIdStore().equal_range(guid);
|
||||
if (creBounds.first != creBounds.second)
|
||||
{
|
||||
for (std::unordered_multimap<ObjectGuid::LowType, Creature*>::const_iterator itr = creBounds.first; itr != creBounds.second;)
|
||||
{
|
||||
if (handler->GetSession())
|
||||
handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, std::to_string(guid).c_str(), std::to_string(guid).c_str(), cInfo->Name.c_str(), x, y, z, mapId, itr->second->GetGUID().ToString().c_str(), itr->second->IsAlive() ? "*" : " ");
|
||||
else
|
||||
handler->PSendSysMessage(LANG_CREATURE_LIST_CONSOLE, std::to_string(guid).c_str(), cInfo->Name.c_str(), x, y, z, mapId, itr->second->GetGUID().ToString().c_str(), itr->second->IsAlive() ? "*" : " ");
|
||||
++itr;
|
||||
}
|
||||
liveFound = true;
|
||||
}
|
||||
auto const creBounds = Trinity::Containers::MapEqualRange(thisMap->GetCreatureBySpawnIdStore(), guid);
|
||||
for (auto& [spawnId, creature] : creBounds)
|
||||
handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, std::to_string(guid).c_str(), std::to_string(guid).c_str(), cInfo->Name.c_str(),
|
||||
x, y, z, mapId, creature->GetGUID().ToString().c_str(), creature->IsAlive() ? "*" : " ");
|
||||
liveFound = creBounds.begin() != creBounds.end();
|
||||
}
|
||||
|
||||
if (!liveFound)
|
||||
@@ -401,28 +391,18 @@ public:
|
||||
bool liveFound = false;
|
||||
|
||||
// Get map (only support base map from console)
|
||||
Map* thisMap;
|
||||
Map* thisMap = nullptr;
|
||||
if (handler->GetSession())
|
||||
thisMap = handler->GetSession()->GetPlayer()->GetMap();
|
||||
else
|
||||
thisMap = sMapMgr->FindBaseNonInstanceMap(mapId);
|
||||
|
||||
// If map found, try to find active version of this object
|
||||
if (thisMap)
|
||||
{
|
||||
auto const goBounds = thisMap->GetGameObjectBySpawnIdStore().equal_range(guid);
|
||||
if (goBounds.first != goBounds.second)
|
||||
{
|
||||
for (std::unordered_multimap<ObjectGuid::LowType, GameObject*>::const_iterator itr = goBounds.first; itr != goBounds.second;)
|
||||
{
|
||||
if (handler->GetSession())
|
||||
handler->PSendSysMessage(LANG_GO_LIST_CHAT, std::to_string(guid).c_str(), entry, std::to_string(guid).c_str(), gInfo->name.c_str(), x, y, z, mapId, itr->second->GetGUID().ToString().c_str(), itr->second->isSpawned() ? "*" : " ");
|
||||
else
|
||||
handler->PSendSysMessage(LANG_GO_LIST_CONSOLE, std::to_string(guid).c_str(), gInfo->name.c_str(), x, y, z, mapId, itr->second->GetGUID().ToString().c_str(), itr->second->isSpawned() ? "*" : " ");
|
||||
++itr;
|
||||
}
|
||||
liveFound = true;
|
||||
}
|
||||
auto const goBounds = Trinity::Containers::MapEqualRange(thisMap->GetGameObjectBySpawnIdStore(), guid);
|
||||
for (auto& [spawnId, go] : goBounds)
|
||||
handler->PSendSysMessage(LANG_GO_LIST_CHAT, std::to_string(guid).c_str(), entry, std::to_string(guid).c_str(), gInfo->name.c_str(), x, y, z, mapId,
|
||||
go->GetGUID().ToString().c_str(), go->isSpawned() ? "*" : " ");
|
||||
liveFound = goBounds.begin() != goBounds.end();
|
||||
}
|
||||
|
||||
if (!liveFound)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "GameObject.h"
|
||||
#include "GameObjectAI.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "MapManager.h"
|
||||
#include "Map.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "PassiveAI.h"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "OutdoorPvPHP.h"
|
||||
#include "GameObject.h"
|
||||
#include "MapManager.h"
|
||||
#include "Map.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "Creature.h"
|
||||
#include "GameObject.h"
|
||||
#include "GossipDef.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
|
||||
Reference in New Issue
Block a user