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"
24 #include "Transports.h"
25 #include "GridDefines.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
)
46 for (TransportSet::iterator i
= m_Transports
.begin(); i
!= m_Transports
.end(); ++i
)
53 MapManager::Initialize()
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
)
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());
97 const MapEntry
* entry
= sMapStore
.LookupEntry(id
);
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
);
110 // create regular non-instanceable map
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);
126 Map
* MapManager::CreateBgMap(uint32 mapid
, BattleGround
* bg
)
128 sTerrainMgr
.LoadTerrain(mapid
);
131 return CreateBattleGroundMap(mapid
, sObjectMgr
.GenerateInstanceLowGuid(), bg
);
134 Map
* MapManager::FindMap(uint32 mapid
, uint32 instanceId
) const
138 MapMapType::const_iterator iter
= i_maps
.find(MapID(mapid
, instanceId
));
139 if (iter
== i_maps
.end())
142 // this is a small workaround for transports
143 if (instanceId
== 0 && iter
->second
->Instanceable())
152 void MapManager::DeleteInstance(uint32 mapid
, uint32 instanceId
)
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())
164 pMap
->UnloadAll(true);
170 void MapManager::Update(uint32 diff
)
172 i_timer
.Update(diff
);
173 if (!i_timer
.Passed())
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);
196 i_maps
.erase(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()
245 for (MapMapType::iterator itr
= i_maps
.begin(); itr
!= i_maps
.end(); ++itr
)
247 Map
* map
= itr
->second
;
248 if (!map
->IsDungeon()) continue;
254 uint32
MapManager::GetNumPlayersInInstances()
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();
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
)
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
);
283 else if (DungeonPersistentState
* pSave
= player
->GetBoundInstanceSaveForSelfOrGroup(id
))
286 NewInstanceId
= pSave
->GetInstanceId();
287 map
= FindMap(id
, NewInstanceId
);
288 // it is possible that the save exists but the map doesn't
290 pNewMap
= CreateDungeonMap(id
, NewInstanceId
, pSave
->GetDifficulty(), pSave
);
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
305 i_maps
[MapID(id
, NewInstanceId
)] = pNewMap
;
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
);
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());
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);