2 * Copyright (C) 2005-2009 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 "InstanceSaveMgr.h"
21 #include "Policies/SingletonImp.h"
22 #include "Database/DatabaseEnv.h"
24 #include "ObjectAccessor.h"
25 #include "Transports.h"
26 #include "GridDefines.h"
27 #include "MapInstanced.h"
28 #include "DestinationHolderImp.h"
32 #include "ObjectMgr.h"
34 #define CLASS_LOCK MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex>
35 INSTANTIATE_SINGLETON_2(MapManager
, CLASS_LOCK
);
36 INSTANTIATE_CLASS_MUTEX(MapManager
, ACE_Thread_Mutex
);
38 extern GridState
* si_GridStates
[]; // debugging code, should be deleted some day
40 MapManager::MapManager() : i_gridCleanUpDelay(sWorld
.getConfig(CONFIG_INTERVAL_GRIDCLEAN
))
42 i_timer
.SetInterval(sWorld
.getConfig(CONFIG_INTERVAL_MAPUPDATE
));
45 MapManager::~MapManager()
47 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
50 for(TransportSet::iterator i
= m_Transports
.begin(); i
!= m_Transports
.end(); ++i
)
53 Map::DeleteStateMachine();
57 MapManager::Initialize()
59 Map::InitStateMachine();
61 // debugging code, should be deleted some day
63 for(int i
=0;i
<MAX_GRID_STATE
; i
++)
65 i_GridStates
[i
] = si_GridStates
[i
];
67 i_GridStateErrorCount
= 0;
73 // debugging code, should be deleted some day
74 void MapManager::checkAndCorrectGridStatesArray()
77 for(int i
=0;i
<MAX_GRID_STATE
; i
++)
79 if(i_GridStates
[i
] != si_GridStates
[i
])
81 sLog
.outError("MapManager::checkGridStates(), GridState: si_GridStates is currupt !!!");
83 si_GridStates
[i
] = i_GridStates
[i
];
86 // inner class checking only when compiled with debug
87 if(!si_GridStates
[i
]->checkMagic())
90 si_GridStates
[i
]->setMagic();
95 ++i_GridStateErrorCount
;
96 if(i_GridStateErrorCount
> 2)
97 assert(false); // force a crash. Too many errors
101 MapManager::_createBaseMap(uint32 id
)
103 Map
*m
= _findMap(id
);
109 const MapEntry
* entry
= sMapStore
.LookupEntry(id
);
110 if (entry
&& entry
->Instanceable())
112 m
= new MapInstanced(id
, i_gridCleanUpDelay
);
116 m
= new Map(id
, i_gridCleanUpDelay
, 0, 0);
125 Map
* MapManager::CreateMap(uint32 id
, const WorldObject
* obj
)
128 //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());
129 Map
*m
= _createBaseMap(id
);
131 if (m
&& (obj
->GetTypeId() == TYPEID_PLAYER
) && m
->Instanceable()) m
= ((MapInstanced
*)m
)->CreateInstance(id
, (Player
*)obj
);
136 Map
* MapManager::FindMap(uint32 mapid
, uint32 instanceId
) const
138 Map
*map
= _findMap(mapid
);
142 if(!map
->Instanceable())
143 return instanceId
== 0 ? map
: NULL
;
145 return ((MapInstanced
*)map
)->FindMap(instanceId
);
149 checks that do not require a map to be created
150 will send transfer error messages on fail
152 bool MapManager::CanPlayerEnter(uint32 mapid
, Player
* player
)
154 const MapEntry
*entry
= sMapStore
.LookupEntry(mapid
);
155 if(!entry
) return false;
156 const char *mapName
= entry
->name
[player
->GetSession()->GetSessionDbcLocale()];
158 if(entry
->map_type
== MAP_INSTANCE
|| entry
->map_type
== MAP_RAID
)
160 if (entry
->map_type
== MAP_RAID
)
162 // GMs can avoid raid limitations
163 if(!player
->isGameMaster() && !sWorld
.getConfig(CONFIG_INSTANCE_IGNORE_RAID
))
165 // can only enter in a raid group
166 Group
* group
= player
->GetGroup();
167 if (!group
|| !group
->isRaidGroup())
169 // probably there must be special opcode, because client has this string constant in GlobalStrings.lua
170 // TODO: this is not a good place to send the message
171 player
->GetSession()->SendAreaTriggerMessage("You must be in a raid group to enter %s instance", mapName
);
172 sLog
.outDebug("MAP: Player '%s' must be in a raid group to enter instance of '%s'", player
->GetName(), mapName
);
178 //The player has a heroic mode and tries to enter into instance which has no a heroic mode
179 if (!entry
->SupportsHeroicMode() && player
->GetDifficulty() == DIFFICULTY_HEROIC
)
181 //Send aborted message
182 player
->SendTransferAborted(mapid
, TRANSFER_ABORT_DIFFICULTY
, DIFFICULTY_HEROIC
);
186 if (!player
->isAlive())
188 if(Corpse
*corpse
= player
->GetCorpse())
190 // let enter in ghost mode in instance that connected to inner instance with corpse
191 uint32 instance_map
= corpse
->GetMapId();
194 if(instance_map
==mapid
)
197 InstanceTemplate
const* instance
= objmgr
.GetInstanceTemplate(instance_map
);
198 instance_map
= instance
? instance
->parent
: 0;
200 while (instance_map
);
204 player
->GetSession()->SendAreaTriggerMessage("You cannot enter %s while in a ghost mode", mapName
);
205 sLog
.outDebug("MAP: Player '%s' doesn't has a corpse in instance '%s' and can't enter", player
->GetName(), mapName
);
208 sLog
.outDebug("MAP: Player '%s' has corpse in instance '%s' and can enter", player
->GetName(), mapName
);
212 sLog
.outDebug("Map::CanEnter - player '%s' is dead but doesn't have a corpse!", player
->GetName());
216 // TODO: move this to a map dependent location
217 /*if(i_data && i_data->IsEncounterInProgress())
219 sLog.outDebug("MAP: Player '%s' can't enter instance '%s' while an encounter is in progress.", player->GetName(), GetMapName());
220 player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
229 void MapManager::DeleteInstance(uint32 mapid
, uint32 instanceId
)
231 Map
*m
= _createBaseMap(mapid
);
232 if (m
&& m
->Instanceable())
233 ((MapInstanced
*)m
)->DestroyInstance(instanceId
);
236 void MapManager::RemoveBonesFromMap(uint32 mapid
, uint64 guid
, float x
, float y
)
238 bool remove_result
= _createBaseMap(mapid
)->RemoveBones(guid
, x
, y
);
242 sLog
.outDebug("Bones %u not found in world. Delete from DB also.", GUID_LOPART(guid
));
247 MapManager::Update(uint32 diff
)
249 i_timer
.Update(diff
);
250 if( !i_timer
.Passed() )
253 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
255 checkAndCorrectGridStatesArray(); // debugging code, should be deleted some day
256 iter
->second
->Update(i_timer
.GetCurrent());
259 ObjectAccessor::Instance().Update(i_timer
.GetCurrent());
260 for (TransportSet::iterator iter
= m_Transports
.begin(); iter
!= m_Transports
.end(); ++iter
)
261 (*iter
)->Update(i_timer
.GetCurrent());
263 i_timer
.SetCurrent(0);
266 void MapManager::DoDelayedMovesAndRemoves()
268 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
269 iter
->second
->DoDelayedMovesAndRemoves();
272 bool MapManager::ExistMapAndVMap(uint32 mapid
, float x
,float y
)
274 GridPair p
= MaNGOS::ComputeGridPair(x
,y
);
279 return Map::ExistMap(mapid
,gx
,gy
) && Map::ExistVMap(mapid
,gx
,gy
);
282 bool MapManager::IsValidMAP(uint32 mapid
)
284 MapEntry
const* mEntry
= sMapStore
.LookupEntry(mapid
);
285 return mEntry
&& (!mEntry
->IsDungeon() || objmgr
.GetInstanceTemplate(mapid
));
286 // TODO: add check for battleground template
289 void MapManager::UnloadAll()
291 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
292 iter
->second
->UnloadAll(true);
294 while(!i_maps
.empty())
296 delete i_maps
.begin()->second
;
297 i_maps
.erase(i_maps
.begin());
301 void MapManager::InitMaxInstanceId()
305 QueryResult
*result
= CharacterDatabase
.Query( "SELECT MAX(id) FROM instance" );
308 i_MaxInstanceId
= result
->Fetch()[0].GetUInt32();
313 uint32
MapManager::GetNumInstances()
316 for(MapMapType::iterator itr
= i_maps
.begin(); itr
!= i_maps
.end(); ++itr
)
318 Map
*map
= itr
->second
;
319 if(!map
->Instanceable()) continue;
320 MapInstanced::InstancedMaps
&maps
= ((MapInstanced
*)map
)->GetInstancedMaps();
321 for(MapInstanced::InstancedMaps::iterator mitr
= maps
.begin(); mitr
!= maps
.end(); ++mitr
)
322 if(mitr
->second
->IsDungeon()) ret
++;
327 uint32
MapManager::GetNumPlayersInInstances()
330 for(MapMapType::iterator itr
= i_maps
.begin(); itr
!= i_maps
.end(); ++itr
)
332 Map
*map
= itr
->second
;
333 if(!map
->Instanceable()) continue;
334 MapInstanced::InstancedMaps
&maps
= ((MapInstanced
*)map
)->GetInstancedMaps();
335 for(MapInstanced::InstancedMaps::iterator mitr
= maps
.begin(); mitr
!= maps
.end(); ++mitr
)
336 if(mitr
->second
->IsDungeon())
337 ret
+= ((InstanceMap
*)mitr
->second
)->GetPlayers().getSize();