[2] | 1 | /* |
---|
[44] | 2 | * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> |
---|
[2] | 3 | * |
---|
[44] | 4 | * Thanks to the original authors: MaNGOS <http://www.mangosproject.org/> |
---|
| 5 | * |
---|
[2] | 6 | * This program is free software; you can redistribute it and/or modify |
---|
| 7 | * it under the terms of the GNU General Public License as published by |
---|
| 8 | * the Free Software Foundation; either version 2 of the License, or |
---|
| 9 | * (at your option) any later version. |
---|
| 10 | * |
---|
| 11 | * This program is distributed in the hope that it will be useful, |
---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
[44] | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
[2] | 14 | * GNU General Public License for more details. |
---|
| 15 | * |
---|
| 16 | * You should have received a copy of the GNU General Public License |
---|
| 17 | * along with this program; if not, write to the Free Software |
---|
[44] | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
[2] | 19 | */ |
---|
| 20 | |
---|
| 21 | #include "MapInstanced.h" |
---|
| 22 | #include "ObjectMgr.h" |
---|
| 23 | #include "MapManager.h" |
---|
| 24 | #include "BattleGround.h" |
---|
| 25 | #include "VMapFactory.h" |
---|
| 26 | #include "InstanceSaveMgr.h" |
---|
| 27 | #include "World.h" |
---|
| 28 | |
---|
| 29 | MapInstanced::MapInstanced(uint32 id, time_t expiry, uint32 aInstanceId) : Map(id, expiry, 0, 0) |
---|
| 30 | { |
---|
| 31 | // initialize instanced maps list |
---|
| 32 | m_InstancedMaps.clear(); |
---|
| 33 | // fill with zero |
---|
| 34 | memset(&GridMapReference, 0, MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_GRIDS*sizeof(uint16)); |
---|
| 35 | } |
---|
| 36 | |
---|
| 37 | void MapInstanced::Update(const uint32& t) |
---|
| 38 | { |
---|
| 39 | // take care of loaded GridMaps (when unused, unload it!) |
---|
| 40 | Map::Update(t); |
---|
| 41 | |
---|
| 42 | // update the instanced maps |
---|
| 43 | InstancedMaps::iterator i = m_InstancedMaps.begin(); |
---|
| 44 | |
---|
| 45 | while (i != m_InstancedMaps.end()) |
---|
| 46 | { |
---|
| 47 | if(i->second->CanUnload(t)) |
---|
| 48 | { |
---|
| 49 | DestroyInstance(i); // iterator incremented |
---|
| 50 | } |
---|
| 51 | else |
---|
| 52 | { |
---|
| 53 | // update only here, because it may schedule some bad things before delete |
---|
| 54 | i->second->Update(t); |
---|
| 55 | ++i; |
---|
| 56 | } |
---|
| 57 | } |
---|
| 58 | } |
---|
| 59 | |
---|
| 60 | void MapInstanced::MoveAllCreaturesInMoveList() |
---|
| 61 | { |
---|
| 62 | for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); i++) |
---|
| 63 | { |
---|
| 64 | i->second->MoveAllCreaturesInMoveList(); |
---|
| 65 | } |
---|
| 66 | |
---|
| 67 | Map::MoveAllCreaturesInMoveList(); |
---|
| 68 | } |
---|
| 69 | |
---|
| 70 | void MapInstanced::RemoveAllObjectsInRemoveList() |
---|
| 71 | { |
---|
| 72 | for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); i++) |
---|
| 73 | { |
---|
| 74 | i->second->RemoveAllObjectsInRemoveList(); |
---|
| 75 | } |
---|
| 76 | |
---|
| 77 | Map::RemoveAllObjectsInRemoveList(); |
---|
| 78 | } |
---|
| 79 | |
---|
| 80 | bool MapInstanced::RemoveBones(uint64 guid, float x, float y) |
---|
| 81 | { |
---|
| 82 | bool remove_result = false; |
---|
| 83 | |
---|
| 84 | for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); i++) |
---|
| 85 | { |
---|
| 86 | remove_result = remove_result || i->second->RemoveBones(guid, x, y); |
---|
| 87 | } |
---|
| 88 | |
---|
| 89 | return remove_result || Map::RemoveBones(guid,x,y); |
---|
| 90 | } |
---|
| 91 | |
---|
| 92 | void MapInstanced::UnloadAll(bool pForce) |
---|
| 93 | { |
---|
| 94 | // Unload instanced maps |
---|
| 95 | for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); i++) |
---|
| 96 | i->second->UnloadAll(pForce); |
---|
| 97 | |
---|
| 98 | // Delete the maps only after everything is unloaded to prevent crashes |
---|
| 99 | for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); i++) |
---|
| 100 | delete i->second; |
---|
| 101 | |
---|
| 102 | m_InstancedMaps.clear(); |
---|
| 103 | |
---|
| 104 | // Unload own grids (just dummy(placeholder) grids, neccesary to unload GridMaps!) |
---|
| 105 | Map::UnloadAll(pForce); |
---|
| 106 | } |
---|
| 107 | |
---|
| 108 | /* |
---|
| 109 | - return the right instance for the object, based on its InstanceId |
---|
| 110 | - create the instance if it's not created already |
---|
| 111 | - the player is not actually added to the instance (only in InstanceMap::Add) |
---|
| 112 | */ |
---|
| 113 | Map* MapInstanced::GetInstance(const WorldObject* obj) |
---|
| 114 | { |
---|
| 115 | uint32 CurInstanceId = obj->GetInstanceId(); |
---|
| 116 | Map* map = NULL; |
---|
| 117 | |
---|
| 118 | if (obj->GetMapId() == GetId() && CurInstanceId != 0) |
---|
| 119 | { |
---|
| 120 | // the object wants to be put in a certain instance of this map |
---|
| 121 | map = _FindMap(CurInstanceId); |
---|
| 122 | if(!map) |
---|
| 123 | { |
---|
| 124 | // For players if the instanceId is set, it's assumed they are already in a map, |
---|
| 125 | // hence the map must be loaded. For Creatures, GameObjects etc the map must exist |
---|
| 126 | // prior to calling GetMap, they are not allowed to create maps for themselves. |
---|
| 127 | sLog.outError("GetInstance: object %s(%d), typeId %d, in world %d, should be in map %d,%d but that's not loaded yet.", obj->GetName(), obj->GetGUIDLow(), obj->GetTypeId(), obj->IsInWorld(), obj->GetMapId(), obj->GetInstanceId()); |
---|
| 128 | assert(false); |
---|
| 129 | } |
---|
| 130 | return(map); |
---|
| 131 | } |
---|
| 132 | else |
---|
| 133 | { |
---|
| 134 | // instance not specified, find an existing or create a new one |
---|
| 135 | if(obj->GetTypeId() != TYPEID_PLAYER) |
---|
| 136 | { |
---|
| 137 | sLog.outError("MAPINSTANCED: WorldObject '%u' (Entry: %u TypeID: %u) is in map %d,%d and requested base map instance of map %d, this must not happen", obj->GetGUIDLow(), obj->GetEntry(), obj->GetTypeId(), obj->GetMapId(), obj->GetInstanceId(), GetId()); |
---|
| 138 | assert(false); |
---|
| 139 | return NULL; |
---|
| 140 | } |
---|
| 141 | else |
---|
| 142 | { |
---|
| 143 | uint32 NewInstanceId = 0; // instanceId of the resulting map |
---|
| 144 | Player* player = (Player*)obj; |
---|
| 145 | |
---|
[9] | 146 | if(IsBattleGroundOrArena()) |
---|
| 147 | { |
---|
| 148 | // instantiate or find existing bg map for player |
---|
| 149 | // the instance id is set in battlegroundid |
---|
| 150 | NewInstanceId = player->GetBattleGroundId(); |
---|
| 151 | assert(NewInstanceId); |
---|
| 152 | map = _FindMap(NewInstanceId); |
---|
| 153 | if(!map) |
---|
| 154 | map = CreateBattleGround(NewInstanceId); |
---|
| 155 | return map; |
---|
| 156 | } |
---|
[2] | 157 | |
---|
| 158 | InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty()); |
---|
| 159 | InstanceSave *pSave = pBind ? pBind->save : NULL; |
---|
| 160 | |
---|
| 161 | // the player's permanet player bind is taken into consideration first |
---|
| 162 | // then the player's group bind and finally the solo bind. |
---|
| 163 | if(!pBind || !pBind->perm) |
---|
| 164 | { |
---|
| 165 | InstanceGroupBind *groupBind = NULL; |
---|
| 166 | Group *group = player->GetGroup(); |
---|
| 167 | // use the player's difficulty setting (it may not be the same as the group's) |
---|
| 168 | if(group && (groupBind = group->GetBoundInstance(GetId(), player->GetDifficulty()))) |
---|
| 169 | pSave = groupBind->save; |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | if(pSave) |
---|
| 173 | { |
---|
| 174 | // solo/perm/group |
---|
| 175 | NewInstanceId = pSave->GetInstanceId(); |
---|
| 176 | map = _FindMap(NewInstanceId); |
---|
| 177 | // it is possible that the save exists but the map doesn't |
---|
| 178 | if(!map) |
---|
| 179 | map = CreateInstance(NewInstanceId, pSave, pSave->GetDifficulty()); |
---|
| 180 | return map; |
---|
| 181 | } |
---|
| 182 | else |
---|
| 183 | { |
---|
| 184 | // if no instanceId via group members or instance saves is found |
---|
| 185 | // the instance will be created for the first time |
---|
| 186 | NewInstanceId = MapManager::Instance().GenerateInstanceId(); |
---|
| 187 | return CreateInstance(NewInstanceId, NULL, player->GetDifficulty()); |
---|
| 188 | } |
---|
| 189 | } |
---|
| 190 | } |
---|
| 191 | } |
---|
| 192 | |
---|
| 193 | InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty) |
---|
| 194 | { |
---|
| 195 | // load/create a map |
---|
| 196 | Guard guard(*this); |
---|
| 197 | |
---|
| 198 | // make sure we have a valid map id |
---|
| 199 | const MapEntry* entry = sMapStore.LookupEntry(GetId()); |
---|
| 200 | if(!entry) |
---|
| 201 | { |
---|
| 202 | sLog.outError("CreateInstance: no entry for map %d", GetId()); |
---|
| 203 | assert(false); |
---|
| 204 | } |
---|
| 205 | const InstanceTemplate * iTemplate = objmgr.GetInstanceTemplate(GetId()); |
---|
| 206 | if(!iTemplate) |
---|
| 207 | { |
---|
| 208 | sLog.outError("CreateInstance: no instance template for map %d", GetId()); |
---|
| 209 | assert(false); |
---|
| 210 | } |
---|
| 211 | |
---|
| 212 | // some instances only have one difficulty |
---|
| 213 | if(!entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL; |
---|
| 214 | |
---|
| 215 | sLog.outDebug("MapInstanced::CreateInstance: %smap instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); |
---|
| 216 | |
---|
| 217 | InstanceMap *map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty); |
---|
| 218 | assert(map->IsDungeon()); |
---|
| 219 | |
---|
| 220 | bool load_data = save != NULL; |
---|
| 221 | map->CreateInstanceData(load_data); |
---|
| 222 | |
---|
| 223 | m_InstancedMaps[InstanceId] = map; |
---|
| 224 | return map; |
---|
| 225 | } |
---|
| 226 | |
---|
| 227 | BattleGroundMap* MapInstanced::CreateBattleGround(uint32 InstanceId) |
---|
| 228 | { |
---|
| 229 | // load/create a map |
---|
| 230 | Guard guard(*this); |
---|
| 231 | |
---|
| 232 | sLog.outDebug("MapInstanced::CreateBattleGround: map bg %d for %d created.", InstanceId, GetId()); |
---|
| 233 | |
---|
| 234 | BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId); |
---|
| 235 | assert(map->IsBattleGroundOrArena()); |
---|
| 236 | |
---|
| 237 | m_InstancedMaps[InstanceId] = map; |
---|
| 238 | return map; |
---|
| 239 | } |
---|
| 240 | |
---|
| 241 | void MapInstanced::DestroyInstance(uint32 InstanceId) |
---|
| 242 | { |
---|
| 243 | InstancedMaps::iterator itr = m_InstancedMaps.find(InstanceId); |
---|
| 244 | if(itr != m_InstancedMaps.end()) |
---|
| 245 | DestroyInstance(itr); |
---|
| 246 | } |
---|
| 247 | |
---|
| 248 | // increments the iterator after erase |
---|
| 249 | void MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) |
---|
| 250 | { |
---|
| 251 | itr->second->UnloadAll(true); |
---|
| 252 | // should only unload VMaps if this is the last instance and grid unloading is enabled |
---|
| 253 | if(m_InstancedMaps.size() <= 1 && sWorld.getConfig(CONFIG_GRID_UNLOAD)) |
---|
| 254 | { |
---|
| 255 | VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(itr->second->GetId()); |
---|
| 256 | // in that case, unload grids of the base map, too |
---|
| 257 | // so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded |
---|
| 258 | Map::UnloadAll(true); |
---|
| 259 | } |
---|
| 260 | // erase map |
---|
| 261 | delete itr->second; |
---|
| 262 | m_InstancedMaps.erase(itr++); |
---|
| 263 | } |
---|
| 264 | |
---|