OregonCore  revision 3611e8a-git
Your Favourite TBC server
MapInstanced.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "MapInstanced.h"
19 #include "ObjectMgr.h"
20 #include "MapManager.h"
21 #include "Battleground.h"
22 #include "VMapFactory.h"
23 #include "InstanceSaveMgr.h"
24 #include "World.h"
25 
26 MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DIFFICULTY_NORMAL)
27 {
28  // initialize instanced maps list
29  m_InstancedMaps.clear();
30  // fill with zero
32 }
33 
35 {
36  if (m_InstancedMaps.empty())
37  return;
38  //initialize visibility distances for all instance copies
39  for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
40  (*i).second->InitVisibilityDistance();
41 }
42 
44 {
45  // take care of loaded GridMaps (when unused, unload it!)
46  Map::Update(t);
47 
48  // update the instanced maps
49  InstancedMaps::iterator i = m_InstancedMaps.begin();
50 
51  while (i != m_InstancedMaps.end())
52  {
53  if (i->second->CanUnload(t))
54  {
55  DestroyInstance(i); // iterator incremented
56  }
57  else
58  {
59  // update only here, because it may schedule some bad things before delete
60  if (MapManager::Instance().GetMapUpdater()->activated())
62  else
63  i->second->Update(t);
64  ++i;
65  }
66  }
67 }
68 
70 {
71  for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
72  i->second->DelayedUpdate(diff);
73 
74  Map::DelayedUpdate(diff); // this may be removed
75 }
76 
78 {
79  // Unload instanced maps
80  for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
81  i->second->UnloadAll();
82 
83  // Delete the maps only after everything is unloaded to prevent crashes
84  for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
85  delete i->second;
86 
87  m_InstancedMaps.clear();
88 
89  // Unload own grids (just dummy(placeholder) grids, neccesary to unload GridMaps!)
91 }
92 
93 /*
94 - return the right instance for the object, based on its InstanceId
95 - create the instance if it's not created already
96 - the player is not actually added to the instance (only in InstanceMap::Add)
97 */
98 Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player, uint32 loginInstanceId)
99 {
100  if (GetId() != mapId || !player)
101  return nullptr;
102 
103  Map* map = nullptr;
104  uint32 newInstanceId = 0; // instanceId of the resulting map
105 
106  if (IsBattlegroundOrArena())
107  {
108  // instantiate or find existing bg map for player
109  // the instance id is set in battlegroundid
110  newInstanceId = player->GetBattlegroundId();
111  if (!newInstanceId)
112  return nullptr;
113 
114  map = MapManager::Instance().FindMap(mapId, newInstanceId);
115  if (!map)
116  {
117  if (Battleground* bg = player->GetBattleground())
118  map = CreateBattleground(newInstanceId, bg);
119  else
120  {
121  player->TeleportToBGEntryPoint();
122  return nullptr;
123  }
124  }
125  }
126  else
127  {
128  InstancePlayerBind* pBind = player->GetBoundInstance(GetId(), player->GetDifficulty());
129  InstanceSave* pSave = pBind ? pBind->save : nullptr;
130 
131  // priority:
132  // 1. player's permanent bind
133  // 2. player's current instance id if this is at login
134  // 3. group's current bind
135  // 4. player's current bind
136  if (!pBind || !pBind->perm)
137  {
138  if (loginInstanceId) // if the player has a saved instance id on login, we either use this instance or relocate him out (return null)
139  {
140  map = FindInstanceMap(loginInstanceId);
141  return (map && map->GetId() == GetId()) ? map : nullptr; // is this check necessary? or does MapInstanced only find instances of itself?
142  }
143 
144  InstanceGroupBind* groupBind = nullptr;
145  Group* group = player->GetGroup();
146  // use the player's difficulty setting (it may not be the same as the group's)
147  if (group)
148  {
149  groupBind = group->GetBoundInstance(this);
150  if (groupBind)
151  {
152  // solo saves should be reset when entering a group's instance
153  player->UnbindInstance(GetId(), player->GetDifficulty());
154  pSave = groupBind->save;
155  }
156  }
157  }
158 
159  if (pSave)
160  {
161  // solo/perm/group
162  newInstanceId = pSave->GetInstanceId();
163  map = FindInstanceMap(newInstanceId);
164  // it is possible that the save exists but the map doesn't
165  if (!map)
166  map = CreateInstance(newInstanceId, pSave, pSave->GetDifficulty());
167  }
168  else
169  {
170  // if no instanceId via group members or instance saves is found
171  // the instance will be created for the first time
172  newInstanceId = MapManager::Instance().GenerateInstanceId();
173 
174  DungeonDifficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficulty() : player->GetDifficulty();
175  //Seems it is now possible, but I do not know if it should be allowed
176  //ASSERT(!FindInstanceMap(NewInstanceId));
177  map = FindInstanceMap(newInstanceId);
178  if (!map)
179  map = CreateInstance(newInstanceId, NULL, diff);
180  }
181  }
182 
183  return map;
184 }
185 
187 {
188  // load/create a map
189  Guard guard(*this);
190 
191  // make sure we have a valid map id
192  const MapEntry* entry = sMapStore.LookupEntry(GetId());
193  if (!entry)
194  {
195  sLog.outError("CreateInstance: no entry for map %d", GetId());
196  ASSERT(false);
197  }
198  const InstanceTemplate* iTemplate = sObjectMgr.GetInstanceTemplate(GetId());
199  if (!iTemplate)
200  {
201  sLog.outError("CreateInstance: no instance template for map %d", GetId());
202  ASSERT(false);
203  }
204 
205  // some instances only have one difficulty
206  if (entry && !entry->SupportsHeroicMode())
207  difficulty = DIFFICULTY_NORMAL;
208 
209  sLog.outDebug("MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save ? "" : "new ", InstanceId, GetId(), difficulty ? "heroic" : "normal");
210 
211  InstanceMap* map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this);
212  ASSERT(map->IsDungeon());
213 
214  bool load_data = save != NULL;
215  map->CreateInstanceData(load_data);
216 
217  m_InstancedMaps[InstanceId] = map;
218  return map;
219 }
220 
222 {
223  // load/create a map
224  Guard guard(*this);
225 
226  sLog.outDebug("MapInstanced::CreateBattleground: map bg %d for %d created.", InstanceId, GetId());
227 
228  BattlegroundMap* map = new BattlegroundMap(GetId(), GetGridExpiry(), InstanceId, this);
230  map->SetBG(bg);
231  bg->SetBgMap(map);
232 
233  m_InstancedMaps[InstanceId] = map;
234  return map;
235 }
236 
237 // increments the iterator after erase
238 bool MapInstanced::DestroyInstance(InstancedMaps::iterator& itr)
239 {
240  itr->second->RemoveAllPlayers();
241  if (itr->second->HavePlayers())
242  {
243  ++itr;
244  return false;
245  }
246 
247  itr->second->UnloadAll();
248  // should only unload VMaps if this is the last instance and grid unloading is enabled
249  if (m_InstancedMaps.size() <= 1 && sWorld.getConfig(CONFIG_GRID_UNLOAD))
250  {
251  VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(itr->second->GetId());
252  // in that case, unload grids of the base map, too
253  // so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded
254  Map::UnloadAll();
255  }
256 
257  // erase map
258  delete itr->second;
259  m_InstancedMaps.erase(itr++);
260 
261  return true;
262 }
263 
265 {
266  //ASSERT(false);
267  return CAN_ENTER;
268 }
269 
InstanceSave * save
Definition: Group.h:145
bool IsBattlegroundOrArena() const
Definition: Map.h:447
virtual void unloadMap(unsigned int pMapId, int x, int y)=0
Group * GetGroup()
Definition: Player.h:2589
MapInstanced(uint32 id, time_t expiry)
Battleground * GetBattleground() const
Definition: Player.cpp:19386
DungeonDifficulty GetDifficulty()
InstanceMap * CreateInstance(uint32 InstanceId, InstanceSave *save, DungeonDifficulty difficulty)
virtual void InitVisibilityDistance()
void SetBG(Battleground *bg)
Definition: Map.h:737
#define sLog
Log class singleton.
Definition: Log.h:187
uint16 GridMapReference[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]
Definition: MapInstanced.h:74
Map * CreateInstanceForPlayer(const uint32 mapId, Player *player, uint32 loginInstanceId=0)
#define MAX_NUMBER_OF_GRIDS
Definition: GridDefines.h:33
int schedule_update(Map &map, ACE_UINT32 diff)
Definition: MapUpdater.cpp:109
bool IsDungeon() const
Definition: Map.h:427
bool TeleportToBGEntryPoint()
Definition: Player.cpp:1831
DungeonDifficulty GetDifficulty()
Definition: Player.h:1884
DungeonDifficulty
#define sObjectMgr
Definition: ObjectMgr.h:1285
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
InstanceSave * save
Definition: Player.h:746
uint32 GetId(void) const
Definition: Map.h:333
void CreateInstanceData(bool load)
Definition: Map.cpp:2419
bool DestroyInstance(InstancedMaps::iterator &itr)
uint32 GetInstanceId()
virtual void Update(const uint32 &)
Definition: Map.cpp:493
uint32 GenerateInstanceId()
Definition: MapManager.h:133
BattlegroundMap * CreateBattleground(uint32 InstanceId, Battleground *bg)
void SetBgMap(BattlegroundMap *map)
Definition: Battleground.h:545
InstancePlayerBind * GetBoundInstance(uint32 mapid, uint8 difficulty)
Definition: Player.cpp:15838
DungeonDifficulty GetDifficulty()
Definition: Group.h:361
Definition: Map.h:266
Map * FindMap(uint32 mapid, uint32 instanceId=0) const
Definition: MapManager.cpp:137
void UnloadAll()
virtual void UnloadAll()
Definition: Map.cpp:995
uint32 GetBattlegroundId() const
Definition: Player.h:2212
virtual void DelayedUpdate(const uint32 diff)
Definition: Map.cpp:2018
Map * FindInstanceMap(uint32 InstanceId) const
Definition: MapInstanced.h:41
static IVMapManager * createOrGetVMapManager()
EnterState CannotEnter(Player *) override
#define ASSERT
Definition: Errors.h:33
InstancedMaps m_InstancedMaps
Definition: MapInstanced.h:72
void Update(const uint32 &)
void DelayedUpdate(const uint32 diff)
EnterState
Definition: Map.h:399
#define sWorld
Definition: World.h:860
MapUpdater * GetMapUpdater()
Definition: MapManager.h:144
InstanceGroupBind * GetBoundInstance(Player *player)
Definition: Group.cpp:1591
ACE_UINT16 uint16
Definition: Define.h:72
void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload=false)
Definition: Player.cpp:15863
ACE_UINT32 uint32
Definition: Define.h:71
time_t GetGridExpiry(void) const
Definition: Map.h:329
bool SupportsHeroicMode() const
Definition: DBCStructure.h:574
Definition: Player.h:922
Definition: Group.h:154