Updated Copyright year to 2013
[getmangos.git] / src / game / MapManager.cpp
blob57dba457471a4b60ad304c4ed95c17495983babe
1 /*
2 * Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "MapManager.h"
20 #include "MapPersistentStateMgr.h"
21 #include "Policies/SingletonImp.h"
22 #include "Database/DatabaseEnv.h"
23 #include "Log.h"
24 #include "Transports.h"
25 #include "GridDefines.h"
26 #include "World.h"
27 #include "CellImpl.h"
28 #include "Corpse.h"
29 #include "ObjectMgr.h"
31 #define CLASS_LOCK MaNGOS::ClassLevelLockable<MapManager, ACE_Recursive_Thread_Mutex>
32 INSTANTIATE_SINGLETON_2(MapManager, CLASS_LOCK);
33 INSTANTIATE_CLASS_MUTEX(MapManager, ACE_Recursive_Thread_Mutex);
35 MapManager::MapManager()
36 : i_gridCleanUpDelay(sWorld.getConfig(CONFIG_UINT32_INTERVAL_GRIDCLEAN))
38 i_timer.SetInterval(sWorld.getConfig(CONFIG_UINT32_INTERVAL_MAPUPDATE));
41 MapManager::~MapManager()
43 for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end(); ++iter)
44 delete iter->second;
46 for (TransportSet::iterator i = m_Transports.begin(); i != m_Transports.end(); ++i)
47 delete *i;
49 DeleteStateMachine();
52 void
53 MapManager::Initialize()
55 InitStateMachine();
58 void MapManager::InitStateMachine()
60 si_GridStates[GRID_STATE_INVALID] = new InvalidState;
61 si_GridStates[GRID_STATE_ACTIVE] = new ActiveState;
62 si_GridStates[GRID_STATE_IDLE] = new IdleState;
63 si_GridStates[GRID_STATE_REMOVAL] = new RemovalState;
66 void MapManager::DeleteStateMachine()
68 delete si_GridStates[GRID_STATE_INVALID];
69 delete si_GridStates[GRID_STATE_ACTIVE];
70 delete si_GridStates[GRID_STATE_IDLE];
71 delete si_GridStates[GRID_STATE_REMOVAL];
74 void MapManager::UpdateGridState(grid_state_t state, Map& map, NGridType& ngrid, GridInfo& ginfo, const uint32& x, const uint32& y, const uint32& t_diff)
76 // TODO: The grid state array itself is static and therefore 100% safe, however, the data
77 // the state classes in it accesses is not, since grids are shared across maps (for example
78 // in instances), so some sort of locking will be necessary later.
80 si_GridStates[state]->Update(map, ngrid, ginfo, x, y, t_diff);
83 void MapManager::InitializeVisibilityDistanceInfo()
85 for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end(); ++iter)
86 (*iter).second->InitVisibilityDistance();
89 Map* MapManager::CreateMap(uint32 id, const WorldObject* obj)
91 MANGOS_ASSERT(obj);
92 // if(!obj->IsInWorld()) sLog.outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId());
93 Guard _guard(*this);
95 Map* m = NULL;
97 const MapEntry* entry = sMapStore.LookupEntry(id);
98 if (!entry)
99 return NULL;
101 if (entry->Instanceable())
103 MANGOS_ASSERT(obj->GetTypeId() == TYPEID_PLAYER);
104 // create DungeonMap object
105 if (obj->GetTypeId() == TYPEID_PLAYER)
106 m = CreateInstance(id, (Player*)obj);
108 else
110 // create regular non-instanceable map
111 m = FindMap(id);
112 if (m == NULL)
114 m = new WorldMap(id, i_gridCleanUpDelay);
115 // add map into container
116 i_maps[MapID(id)] = m;
118 // non-instanceable maps always expected have saved state
119 m->CreateInstanceData(true);
123 return m;
126 Map* MapManager::CreateBgMap(uint32 mapid, BattleGround* bg)
128 sTerrainMgr.LoadTerrain(mapid);
130 Guard _guard(*this);
131 return CreateBattleGroundMap(mapid, sObjectMgr.GenerateInstanceLowGuid(), bg);
134 Map* MapManager::FindMap(uint32 mapid, uint32 instanceId) const
136 Guard guard(*this);
138 MapMapType::const_iterator iter = i_maps.find(MapID(mapid, instanceId));
139 if (iter == i_maps.end())
140 return NULL;
142 // this is a small workaround for transports
143 if (instanceId == 0 && iter->second->Instanceable())
145 assert(false);
146 return NULL;
149 return iter->second;
152 void MapManager::DeleteInstance(uint32 mapid, uint32 instanceId)
154 Guard _guard(*this);
156 MapMapType::iterator iter = i_maps.find(MapID(mapid, instanceId));
157 if (iter != i_maps.end())
159 Map* pMap = iter->second;
160 if (pMap->Instanceable())
162 i_maps.erase(iter);
164 pMap->UnloadAll(true);
165 delete pMap;
170 void MapManager::Update(uint32 diff)
172 i_timer.Update(diff);
173 if (!i_timer.Passed())
174 return;
176 for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end(); ++iter)
177 iter->second->Update((uint32)i_timer.GetCurrent());
179 for (TransportSet::iterator iter = m_Transports.begin(); iter != m_Transports.end(); ++iter)
181 WorldObject::UpdateHelper helper((*iter));
182 helper.Update((uint32)i_timer.GetCurrent());
185 // remove all maps which can be unloaded
186 MapMapType::iterator iter = i_maps.begin();
187 while (iter != i_maps.end())
189 Map* pMap = iter->second;
190 // check if map can be unloaded
191 if (pMap->CanUnload((uint32)i_timer.GetCurrent()))
193 pMap->UnloadAll(true);
194 delete pMap;
196 i_maps.erase(iter++);
198 else
199 ++iter;
202 i_timer.SetCurrent(0);
205 void MapManager::RemoveAllObjectsInRemoveList()
207 for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end(); ++iter)
208 iter->second->RemoveAllObjectsInRemoveList();
211 bool MapManager::ExistMapAndVMap(uint32 mapid, float x, float y)
213 GridPair p = MaNGOS::ComputeGridPair(x, y);
215 int gx = 63 - p.x_coord;
216 int gy = 63 - p.y_coord;
218 return GridMap::ExistMap(mapid, gx, gy) && GridMap::ExistVMap(mapid, gx, gy);
221 bool MapManager::IsValidMAP(uint32 mapid)
223 MapEntry const* mEntry = sMapStore.LookupEntry(mapid);
224 return mEntry && (!mEntry->IsDungeon() || ObjectMgr::GetInstanceTemplate(mapid));
225 // TODO: add check for battleground template
228 void MapManager::UnloadAll()
230 for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end(); ++iter)
231 iter->second->UnloadAll(true);
233 while (!i_maps.empty())
235 delete i_maps.begin()->second;
236 i_maps.erase(i_maps.begin());
239 TerrainManager::Instance().UnloadAll();
242 uint32 MapManager::GetNumInstances()
244 uint32 ret = 0;
245 for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr)
247 Map* map = itr->second;
248 if (!map->IsDungeon()) continue;
249 ret += 1;
251 return ret;
254 uint32 MapManager::GetNumPlayersInInstances()
256 uint32 ret = 0;
257 for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr)
259 Map* map = itr->second;
260 if (!map->IsDungeon()) continue;
261 ret += map->GetPlayers().getSize();
263 return ret;
266 ///// returns a new or existing Instance
267 ///// in case of battlegrounds it will only return an existing map, those maps are created by bg-system
268 Map* MapManager::CreateInstance(uint32 id, Player* player)
270 Map* map = NULL;
271 Map* pNewMap = NULL;
272 uint32 NewInstanceId = 0; // instanceId of the resulting map
273 const MapEntry* entry = sMapStore.LookupEntry(id);
275 if (entry->IsBattleGroundOrArena())
277 // find existing bg map for player
278 NewInstanceId = player->GetBattleGroundId();
279 MANGOS_ASSERT(NewInstanceId);
280 map = FindMap(id, NewInstanceId);
281 MANGOS_ASSERT(map);
283 else if (DungeonPersistentState* pSave = player->GetBoundInstanceSaveForSelfOrGroup(id))
285 // solo/perm/group
286 NewInstanceId = pSave->GetInstanceId();
287 map = FindMap(id, NewInstanceId);
288 // it is possible that the save exists but the map doesn't
289 if (!map)
290 pNewMap = CreateDungeonMap(id, NewInstanceId, pSave->GetDifficulty(), pSave);
292 else
294 // if no instanceId via group members or instance saves is found
295 // the instance will be created for the first time
296 NewInstanceId = sObjectMgr.GenerateInstanceLowGuid();
298 Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficulty(entry->IsRaid()) : player->GetDifficulty(entry->IsRaid());
299 pNewMap = CreateDungeonMap(id, NewInstanceId, diff);
302 // add a new map object into the registry
303 if (pNewMap)
305 i_maps[MapID(id, NewInstanceId)] = pNewMap;
306 map = pNewMap;
309 return map;
312 DungeonMap* MapManager::CreateDungeonMap(uint32 id, uint32 InstanceId, Difficulty difficulty, DungeonPersistentState* save)
314 // make sure we have a valid map id
315 if (!sMapStore.LookupEntry(id))
317 sLog.outError("CreateDungeonMap: no entry for map %d", id);
318 MANGOS_ASSERT(false);
320 if (!ObjectMgr::GetInstanceTemplate(id))
322 sLog.outError("CreateDungeonMap: no instance template for map %d", id);
323 MANGOS_ASSERT(false);
326 // some instances only have one difficulty
327 if (!GetMapDifficultyData(id, difficulty))
328 difficulty = DUNGEON_DIFFICULTY_NORMAL;
330 DEBUG_LOG("MapInstanced::CreateDungeonMap: %s map instance %d for %d created with difficulty %d", save ? "" : "new ", InstanceId, id, difficulty);
332 DungeonMap* map = new DungeonMap(id, i_gridCleanUpDelay, InstanceId, difficulty);
334 // Dungeons can have saved instance data
335 bool load_data = save != NULL;
336 map->CreateInstanceData(load_data);
338 return map;
341 BattleGroundMap* MapManager::CreateBattleGroundMap(uint32 id, uint32 InstanceId, BattleGround* bg)
343 DEBUG_LOG("MapInstanced::CreateBattleGroundMap: instance:%d for map:%d and bgType:%d created.", InstanceId, id, bg->GetTypeID());
345 PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), bg->GetMinLevel());
347 uint8 spawnMode = bracketEntry ? bracketEntry->difficulty : uint8(REGULAR_DIFFICULTY);
349 BattleGroundMap* map = new BattleGroundMap(id, i_gridCleanUpDelay, InstanceId, spawnMode);
350 MANGOS_ASSERT(map->IsBattleGroundOrArena());
351 map->SetBG(bg);
352 bg->SetBgMap(map);
354 // add map into map container
355 i_maps[MapID(id, InstanceId)] = map;
357 // BGs/Arenas not have saved instance data
358 map->CreateInstanceData(false);
360 return map;