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, ZThread::Mutex>
35 INSTANTIATE_SINGLETON_2(MapManager
, CLASS_LOCK
);
36 INSTANTIATE_CLASS_MUTEX(MapManager
, ZThread::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::_GetBaseMap(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::GetMap(uint32 id
, const WorldObject
* obj
)
127 //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());
128 Map
*m
= _GetBaseMap(id
);
130 if (m
&& obj
&& m
->Instanceable()) m
= ((MapInstanced
*)m
)->GetInstance(obj
);
135 Map
* MapManager::FindMap(uint32 mapid
, uint32 instanceId
)
137 Map
*map
= FindMap(mapid
);
138 if(!map
) return NULL
;
139 if(!map
->Instanceable()) return instanceId
== 0 ? map
: NULL
;
140 return ((MapInstanced
*)map
)->FindMap(instanceId
);
144 checks that do not require a map to be created
145 will send transfer error messages on fail
147 bool MapManager::CanPlayerEnter(uint32 mapid
, Player
* player
)
149 const MapEntry
*entry
= sMapStore
.LookupEntry(mapid
);
150 if(!entry
) return false;
151 const char *mapName
= entry
->name
[player
->GetSession()->GetSessionDbcLocale()];
153 if(entry
->map_type
== MAP_INSTANCE
|| entry
->map_type
== MAP_RAID
)
155 if (entry
->map_type
== MAP_RAID
)
157 // GMs can avoid raid limitations
158 if(!player
->isGameMaster() && !sWorld
.getConfig(CONFIG_INSTANCE_IGNORE_RAID
))
160 // can only enter in a raid group
161 Group
* group
= player
->GetGroup();
162 if (!group
|| !group
->isRaidGroup())
164 // probably there must be special opcode, because client has this string constant in GlobalStrings.lua
165 // TODO: this is not a good place to send the message
166 player
->GetSession()->SendAreaTriggerMessage("You must be in a raid group to enter %s instance", mapName
);
167 sLog
.outDebug("MAP: Player '%s' must be in a raid group to enter instance of '%s'", player
->GetName(), mapName
);
173 //The player has a heroic mode and tries to enter into instance which has no a heroic mode
174 if (!entry
->SupportsHeroicMode() && player
->GetDifficulty() == DIFFICULTY_HEROIC
)
176 //Send aborted message
177 player
->SendTransferAborted(mapid
, TRANSFER_ABORT_DIFFICULTY
, DIFFICULTY_HEROIC
);
181 if (!player
->isAlive())
183 if(Corpse
*corpse
= player
->GetCorpse())
185 // let enter in ghost mode in instance that connected to inner instance with corpse
186 uint32 instance_map
= corpse
->GetMapId();
189 if(instance_map
==mapid
)
192 InstanceTemplate
const* instance
= objmgr
.GetInstanceTemplate(instance_map
);
193 instance_map
= instance
? instance
->parent
: 0;
195 while (instance_map
);
199 player
->GetSession()->SendAreaTriggerMessage("You cannot enter %s while in a ghost mode", mapName
);
200 sLog
.outDebug("MAP: Player '%s' doesn't has a corpse in instance '%s' and can't enter", player
->GetName(), mapName
);
203 sLog
.outDebug("MAP: Player '%s' has corpse in instance '%s' and can enter", player
->GetName(), mapName
);
207 sLog
.outDebug("Map::CanEnter - player '%s' is dead but doesn't have a corpse!", player
->GetName());
211 // TODO: move this to a map dependent location
212 /*if(i_data && i_data->IsEncounterInProgress())
214 sLog.outDebug("MAP: Player '%s' can't enter instance '%s' while an encounter is in progress.", player->GetName(), GetMapName());
215 player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
224 void MapManager::DeleteInstance(uint32 mapid
, uint32 instanceId
)
226 Map
*m
= _GetBaseMap(mapid
);
227 if (m
&& m
->Instanceable())
228 ((MapInstanced
*)m
)->DestroyInstance(instanceId
);
231 void MapManager::RemoveBonesFromMap(uint32 mapid
, uint64 guid
, float x
, float y
)
233 bool remove_result
= _GetBaseMap(mapid
)->RemoveBones(guid
, x
, y
);
237 sLog
.outDebug("Bones %u not found in world. Delete from DB also.", GUID_LOPART(guid
));
242 MapManager::Update(uint32 diff
)
244 i_timer
.Update(diff
);
245 if( !i_timer
.Passed() )
248 ObjectAccessor::Instance().UpdatePlayers(i_timer
.GetCurrent());
250 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
252 checkAndCorrectGridStatesArray(); // debugging code, should be deleted some day
253 iter
->second
->Update(i_timer
.GetCurrent());
256 ObjectAccessor::Instance().Update(i_timer
.GetCurrent());
257 for (TransportSet::iterator iter
= m_Transports
.begin(); iter
!= m_Transports
.end(); ++iter
)
258 (*iter
)->Update(i_timer
.GetCurrent());
260 i_timer
.SetCurrent(0);
263 void MapManager::DoDelayedMovesAndRemoves()
265 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
266 iter
->second
->DoDelayedMovesAndRemoves();
269 bool MapManager::ExistMapAndVMap(uint32 mapid
, float x
,float y
)
271 GridPair p
= MaNGOS::ComputeGridPair(x
,y
);
276 return Map::ExistMap(mapid
,gx
,gy
) && Map::ExistVMap(mapid
,gx
,gy
);
279 bool MapManager::IsValidMAP(uint32 mapid
)
281 MapEntry
const* mEntry
= sMapStore
.LookupEntry(mapid
);
282 return mEntry
&& (!mEntry
->IsDungeon() || objmgr
.GetInstanceTemplate(mapid
));
283 // TODO: add check for battleground template
286 void MapManager::LoadGrid(int mapid
, float x
, float y
, const WorldObject
* obj
, bool no_unload
)
288 CellPair p
= MaNGOS::ComputeCellPair(x
,y
);
290 GetMap(mapid
, obj
)->LoadGrid(cell
,no_unload
);
293 void MapManager::UnloadAll()
295 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
296 iter
->second
->UnloadAll(true);
298 while(!i_maps
.empty())
300 delete i_maps
.begin()->second
;
301 i_maps
.erase(i_maps
.begin());
305 void MapManager::InitMaxInstanceId()
309 QueryResult
*result
= CharacterDatabase
.Query( "SELECT MAX(id) FROM instance" );
312 i_MaxInstanceId
= result
->Fetch()[0].GetUInt32();
317 uint32
MapManager::GetNumInstances()
320 for(MapMapType::iterator itr
= i_maps
.begin(); itr
!= i_maps
.end(); ++itr
)
322 Map
*map
= itr
->second
;
323 if(!map
->Instanceable()) continue;
324 MapInstanced::InstancedMaps
&maps
= ((MapInstanced
*)map
)->GetInstancedMaps();
325 for(MapInstanced::InstancedMaps::iterator mitr
= maps
.begin(); mitr
!= maps
.end(); ++mitr
)
326 if(mitr
->second
->IsDungeon()) ret
++;
331 uint32
MapManager::GetNumPlayersInInstances()
334 for(MapMapType::iterator itr
= i_maps
.begin(); itr
!= i_maps
.end(); ++itr
)
336 Map
*map
= itr
->second
;
337 if(!map
->Instanceable()) continue;
338 MapInstanced::InstancedMaps
&maps
= ((MapInstanced
*)map
)->GetInstancedMaps();
339 for(MapInstanced::InstancedMaps::iterator mitr
= maps
.begin(); mitr
!= maps
.end(); ++mitr
)
340 if(mitr
->second
->IsDungeon())
341 ret
+= ((InstanceMap
*)mitr
->second
)->GetPlayers().getSize();