aboutsummaryrefslogtreecommitdiff
path: root/src/game/Map.cpp
diff options
context:
space:
mode:
authormegamage <none@none>2008-11-18 19:40:06 -0600
committermegamage <none@none>2008-11-18 19:40:06 -0600
commitea68727d27e699200236b3b7ecbe36b7f7061cfc (patch)
treeefacc175380a18af301a91170bc35cb851a64701 /src/game/Map.cpp
parent78f343397c5d5e4cb99e84a9ebecc299e988e13d (diff)
*Merge from Mangos. Add MapReference. Author: hunuza.
*Also re-commit the patches reverted in 255. --HG-- branch : trunk
Diffstat (limited to 'src/game/Map.cpp')
-rw-r--r--src/game/Map.cpp186
1 files changed, 129 insertions, 57 deletions
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index 7b3e40c00b3..ba72775b5cf 100644
--- a/src/game/Map.cpp
+++ b/src/game/Map.cpp
@@ -35,6 +35,7 @@
#include "World.h"
#include "ScriptCalls.h"
#include "Group.h"
+#include "MapRefManager.h"
#include "MapInstanced.h"
#include "InstanceSaveMgr.h"
@@ -449,6 +450,8 @@ Map::LoadGrid(const Cell& cell, bool no_unload)
bool Map::Add(Player *player)
{
+ player->GetMapRef().link(this, player);
+
player->SetInstanceId(GetInstanceId());
// update player state for other player and visa-versa
@@ -593,6 +596,55 @@ bool Map::loaded(const GridPair &p) const
void Map::Update(const uint32 &t_diff)
{
+ resetMarkedCells();
+
+ Trinity::ObjectUpdater updater(t_diff);
+ // for creature
+ TypeContainerVisitor<Trinity::ObjectUpdater, GridTypeMapContainer > grid_object_update(updater);
+ // for pets
+ TypeContainerVisitor<Trinity::ObjectUpdater, WorldTypeMapContainer > world_object_update(updater);
+
+ for(MapRefManager::iterator iter = m_mapRefManager.begin(); iter != m_mapRefManager.end(); ++iter)
+ {
+ Player* plr = iter->getSource();
+ if(!plr->IsInWorld())
+ continue;
+
+ CellPair standing_cell(Trinity::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY()));
+
+ // Check for correctness of standing_cell, it also avoids problems with update_cell
+ if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+ continue;
+
+ // the overloaded operators handle range checking
+ // so ther's no need for range checking inside the loop
+ CellPair begin_cell(standing_cell), end_cell(standing_cell);
+ begin_cell << 1; begin_cell -= 1; // upper left
+ end_cell >> 1; end_cell += 1; // lower right
+
+ for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
+ {
+ for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
+ {
+ // marked cells are those that have been visited
+ // don't visit the same cell twice
+ uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+ if(!isCellMarked(cell_id))
+ {
+ markCell(cell_id);
+ CellPair pair(x,y);
+ Cell cell(pair);
+ cell.data.Part.reserved = CENTER_DISTRICT;
+ cell.SetNoCreate();
+ CellLock<NullGuard> cell_lock(cell, pair);
+ cell_lock->Visit(cell_lock, grid_object_update, *this);
+ cell_lock->Visit(cell_lock, world_object_update, *this);
+ }
+ }
+ }
+ }
+
+
// Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !
// This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
if (IsBattleGroundOrArena())
@@ -610,6 +662,7 @@ void Map::Update(const uint32 &t_diff)
void Map::Remove(Player *player, bool remove)
{
+ player->GetMapRef().unlink();
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
{
@@ -909,7 +962,7 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool pForce)
assert( grid != NULL);
{
- if(!pForce && ObjectAccessor::Instance().ActiveObjectsNearGrid(x, y, i_id, i_InstanceId) )
+ if(!pForce && PlayersNearGrid(x, y) )
return false;
DEBUG_LOG("Unloading grid[%u,%u] for map %u", x,y, i_id);
@@ -1418,6 +1471,43 @@ bool Map::CanUnload(const uint32 &diff)
return false;
}
+uint32 Map::GetPlayersCountExceptGMs() const
+{
+ uint32 count = 0;
+ for(MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
+ if(!itr->getSource()->isGameMaster())
+ ++count;
+ return count;
+}
+
+void Map::SendToPlayers(WorldPacket const* data) const
+{
+ for(MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
+ itr->getSource()->GetSession()->SendPacket(data);
+}
+
+bool Map::PlayersNearGrid(uint32 x, uint32 y) const
+{
+ CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS);
+ CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
+ cell_min << 2;
+ cell_min -= 2;
+ cell_max >> 2;
+ cell_max += 2;
+
+ for(MapRefManager::const_iterator iter = m_mapRefManager.begin(); iter != m_mapRefManager.end(); ++iter)
+ {
+ Player* plr = iter->getSource();
+
+ CellPair p = Trinity::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY());
+ if( (cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
+ (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord) )
+ return true;
+ }
+
+ return false;
+}
+
template void Map::Add(Corpse *);
template void Map::Add(Creature *);
template void Map::Add(GameObject *);
@@ -1453,7 +1543,7 @@ InstanceMap::~InstanceMap()
*/
bool InstanceMap::CanEnter(Player *player)
{
- if(std::find(i_Players.begin(),i_Players.end(),player)!=i_Players.end())
+ if(player->GetMapRef().getTarget() == this)
{
sLog.outError("InstanceMap::CanEnter - player %s(%u) already in map %d,%d,%d!", player->GetName(), player->GetGUIDLow(), GetId(), GetInstanceId(), GetSpawnMode());
assert(false);
@@ -1570,7 +1660,6 @@ bool InstanceMap::Add(Player *player)
if(i_data) i_data->OnPlayerEnter(player);
SetResetSchedule(false);
- i_Players.push_back(player);
player->SendInitWorldStates();
sLog.outDetail("MAP: Player '%s' entered the instance '%u' of map '%s'", player->GetName(), GetInstanceId(), GetMapName());
// initialize unload state
@@ -1595,9 +1684,9 @@ void InstanceMap::Update(const uint32& t_diff)
void InstanceMap::Remove(Player *player, bool remove)
{
sLog.outDetail("MAP: Removing player '%s' from instance '%u' of map '%s' before relocating to other map", player->GetName(), GetInstanceId(), GetMapName());
- i_Players.remove(player);
SetResetSchedule(true);
- if(!m_unloadTimer && i_Players.empty())
+ //if last player set unload timer
+ if(!m_unloadTimer && m_mapRefManager.getSize() == 1)
m_unloadTimer = m_unloadWhenEmpty ? MIN_UNLOAD_DELAY : std::max(sWorld.getConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY);
Map::Remove(player, remove);
}
@@ -1662,21 +1751,21 @@ bool InstanceMap::Reset(uint8 method)
// note: since the map may not be loaded when the instance needs to be reset
// the instance must be deleted from the DB by InstanceSaveManager
- if(!i_Players.empty())
+ if(HavePlayers())
{
if(method == INSTANCE_RESET_ALL)
{
// notify the players to leave the instance so it can be reset
- for(PlayerList::iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr)
- (*itr)->SendResetFailedNotify(GetId());
+ for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
+ itr->getSource()->SendResetFailedNotify(GetId());
}
else
{
if(method == INSTANCE_RESET_GLOBAL)
{
// set the homebind timer for players inside (1 minute)
- for(PlayerList::iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr)
- (*itr)->m_InstanceValid = false;
+ for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
+ itr->getSource()->m_InstanceValid = false;
}
// the unload timer is not started
@@ -1692,16 +1781,7 @@ bool InstanceMap::Reset(uint8 method)
m_resetAfterUnload = true;
}
- return i_Players.empty();
-}
-
-uint32 InstanceMap::GetPlayersCountExceptGMs() const
-{
- uint32 count = 0;
- for(PlayerList::const_iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr)
- if(!(*itr)->isGameMaster())
- ++count;
- return count;
+ return m_mapRefManager.isEmpty();
}
void InstanceMap::PermBindAllPlayers(Player *player)
@@ -1715,25 +1795,23 @@ void InstanceMap::PermBindAllPlayers(Player *player)
Group *group = player->GetGroup();
// group members outside the instance group don't get bound
- for(PlayerList::iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr)
+ for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
{
- if(*itr)
+ Player* plr = itr->getSource();
+ // players inside an instance cannot be bound to other instances
+ // some players may already be permanently bound, in this case nothing happens
+ InstancePlayerBind *bind = plr->GetBoundInstance(save->GetMapId(), save->GetDifficulty());
+ if(!bind || !bind->perm)
{
- // players inside an instance cannot be bound to other instances
- // some players may already be permanently bound, in this case nothing happens
- InstancePlayerBind *bind = (*itr)->GetBoundInstance(save->GetMapId(), save->GetDifficulty());
- if(!bind || !bind->perm)
- {
- (*itr)->BindToInstance(save, true);
- WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
- data << uint32(0);
- (*itr)->GetSession()->SendPacket(&data);
- }
-
- // if the leader is not in the instance the group will not get a perm bind
- if(group && group->GetLeaderGUID() == (*itr)->GetGUID())
- group->BindToInstance(save, true);
+ plr->BindToInstance(save, true);
+ WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
+ data << uint32(0);
+ plr->GetSession()->SendPacket(&data);
}
+
+ // if the leader is not in the instance the group will not get a perm bind
+ if(group && group->GetLeaderGUID() == plr->GetGUID())
+ group->BindToInstance(save, true);
}
}
@@ -1745,11 +1823,14 @@ time_t InstanceMap::GetResetTime()
void InstanceMap::UnloadAll(bool pForce)
{
- if(!i_Players.empty())
+ if(HavePlayers())
{
sLog.outError("InstanceMap::UnloadAll: there are still players in the instance at unload, should not happen!");
- for(PlayerList::iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr)
- if(*itr) (*itr)->TeleportTo((*itr)->m_homebindMapId, (*itr)->m_homebindX, (*itr)->m_homebindY, (*itr)->m_homebindZ, (*itr)->GetOrientation());
+ for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
+ {
+ Player* plr = itr->getSource();
+ plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
+ }
}
if(m_resetAfterUnload == true)
@@ -1758,10 +1839,10 @@ void InstanceMap::UnloadAll(bool pForce)
Map::UnloadAll(pForce);
}
-void InstanceMap::SendResetWarnings(uint32 timeLeft)
+void InstanceMap::SendResetWarnings(uint32 timeLeft) const
{
- for(PlayerList::iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr)
- (*itr)->SendInstanceResetWarning(GetId(), timeLeft);
+ for(MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
+ itr->getSource()->SendInstanceResetWarning(GetId(), timeLeft);
}
void InstanceMap::SetResetSchedule(bool on)
@@ -1769,7 +1850,7 @@ void InstanceMap::SetResetSchedule(bool on)
// only for normal instances
// the reset time is only scheduled when there are no payers inside
// it is assumed that the reset time will rarely (if ever) change while the reset is scheduled
- if(i_Players.empty() && !IsRaid() && !IsHeroic())
+ if(!HavePlayers() && !IsRaid() && !IsHeroic())
{
InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
if(!save) sLog.outError("InstanceMap::SetResetSchedule: cannot turn schedule %s, no save available for instance %d of %d", on ? "on" : "off", GetInstanceId(), GetId());
@@ -1777,12 +1858,6 @@ void InstanceMap::SetResetSchedule(bool on)
}
}
-void InstanceMap::SendToPlayers(WorldPacket const* data) const
-{
- for(PlayerList::const_iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr)
- (*itr)->GetSession()->SendPacket(data);
-}
-
/* ******* Battleground Instance Maps ******* */
BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId)
@@ -1796,7 +1871,7 @@ BattleGroundMap::~BattleGroundMap()
bool BattleGroundMap::CanEnter(Player * player)
{
- if(std::find(i_Players.begin(),i_Players.end(),player)!=i_Players.end())
+ if(player->GetMapRef().getTarget() == this)
{
sLog.outError("BGMap::CanEnter - player %u already in map!", player->GetGUIDLow());
assert(false);
@@ -1817,7 +1892,6 @@ bool BattleGroundMap::Add(Player * player)
Guard guard(*this);
if(!CanEnter(player))
return false;
- i_Players.push_back(player);
// reset instance validity, battleground maps do not homebind
player->m_InstanceValid = true;
}
@@ -1827,7 +1901,6 @@ bool BattleGroundMap::Add(Player * player)
void BattleGroundMap::Remove(Player *player, bool remove)
{
sLog.outDetail("MAP: Removing player '%s' from bg '%u' of map '%s' before relocating to other map", player->GetName(), GetInstanceId(), GetMapName());
- i_Players.remove(player);
Map::Remove(player, remove);
}
@@ -1838,15 +1911,14 @@ void BattleGroundMap::SetUnload()
void BattleGroundMap::UnloadAll(bool pForce)
{
- while(!i_Players.empty())
+ while(HavePlayers())
{
- PlayerList::iterator itr = i_Players.begin();
- Player * plr = *itr;
- if(plr) (plr)->TeleportTo((*itr)->m_homebindMapId, (*itr)->m_homebindX, (*itr)->m_homebindY, (*itr)->m_homebindZ, (*itr)->GetOrientation());
+ Player * plr = m_mapRefManager.getFirst()->getSource();
+ if(plr) (plr)->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
// TeleportTo removes the player from this map (if the map exists) -> calls BattleGroundMap::Remove -> invalidates the iterator.
// just in case, remove the player from the list explicitly here as well to prevent a possible infinite loop
// note that this remove is not needed if the code works well in other places
- i_Players.remove(plr);
+ plr->GetMapRef().unlink();
}
Map::UnloadAll(pForce);