diff options
author | megamage <none@none> | 2008-11-18 19:40:06 -0600 |
---|---|---|
committer | megamage <none@none> | 2008-11-18 19:40:06 -0600 |
commit | ea68727d27e699200236b3b7ecbe36b7f7061cfc (patch) | |
tree | efacc175380a18af301a91170bc35cb851a64701 /src/game/Map.cpp | |
parent | 78f343397c5d5e4cb99e84a9ebecc299e988e13d (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.cpp | 186 |
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); |