TrinityCore
Loading...
Searching...
No Matches
MapManager.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore 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 "MapManager.h"
19#include "InstanceSaveMgr.h"
20#include "DatabaseEnv.h"
21#include "Log.h"
22#include "ObjectAccessor.h"
23#include "Transport.h"
24#include "GridDefines.h"
25#include "MapInstanced.h"
26#include "InstanceScript.h"
27#include "Config.h"
28#include "World.h"
29#include "Corpse.h"
30#include "ObjectMgr.h"
31#include "WorldPacket.h"
32#include "Group.h"
33#include "Player.h"
34#include "WorldSession.h"
35#include "Opcodes.h"
36#include "ScriptMgr.h"
37#include <numeric>
38
40 : _nextInstanceId(0), _scheduledScripts(0)
41{
44}
45
47
49{
51
52 int num_threads(sWorld->getIntConfig(CONFIG_NUMTHREADS));
53 // Start mtmaps if needed.
54 if (num_threads > 0)
55 m_updater.activate(num_threads);
56}
57
59{
60 for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end(); ++iter)
61 (*iter).second->InitVisibilityDistance();
62}
63
69
71{
72 Map* map = FindBaseMap(id);
73
74 if (map == nullptr)
75 {
76 std::lock_guard<std::mutex> lock(_mapsLock);
77
78 MapEntry const* entry = sMapStore.LookupEntry(id);
79 ASSERT(entry);
80
81 if (entry->Instanceable())
82 map = new MapInstanced(id, i_gridCleanUpDelay);
83 else
84 {
85 map = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY);
86 map->LoadRespawnTimes();
87 map->LoadCorpseData();
88 }
89
91 ptr.reset(map);
92 map->SetWeakPtr(ptr);
93
94 sScriptMgr->OnCreateMap(map);
95 }
96
97 ASSERT(map);
98 return map;
99}
100
102{
103 Map* map = FindBaseMap(mapId);
104 if (map && map->Instanceable())
105 return nullptr;
106 return map;
107}
108
109Map* MapManager::CreateMap(uint32 id, Player* player, uint32 loginInstanceId)
110{
111 Map* m = CreateBaseMap(id);
112
113 if (m && m->Instanceable())
114 m = ((MapInstanced*)m)->CreateInstanceForPlayer(id, player, loginInstanceId);
115
116 return m;
117}
118
119Map* MapManager::FindMap(uint32 mapid, uint32 instanceId) const
120{
121 Map* map = FindBaseMap(mapid);
122 if (!map)
123 return nullptr;
124
125 if (!map->Instanceable())
126 return instanceId == 0 ? map : nullptr;
127
128 return ((MapInstanced*)map)->FindInstanceMap(instanceId);
129}
130
132{
133 MapEntry const* entry = sMapStore.LookupEntry(mapid);
134 if (!entry)
136
137 if (!entry->IsDungeon())
138 return Map::CAN_ENTER;
139
140 InstanceTemplate const* instance = sObjectMgr->GetInstanceTemplate(mapid);
141 if (!instance)
143
144 Difficulty targetDifficulty, requestedDifficulty;
145 targetDifficulty = requestedDifficulty = player->GetDifficulty(entry->IsRaid());
146 // Get the highest available difficulty if current setting is higher than the instance allows
147 MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(entry->ID, targetDifficulty);
148 if (!mapDiff)
150
151 //Bypass checks for GMs
152 if (player->IsGameMaster())
153 return Map::CAN_ENTER;
154
155 char const* mapName = entry->MapName[player->GetSession()->GetSessionDbcLocale()];
156
157 Group* group = player->GetGroup();
158 if (entry->IsRaid()) // can only enter in a raid group
159 if ((!group || !group->isRaidGroup()) && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID))
161
162 if (!player->IsAlive())
163 {
164 if (player->HasCorpse())
165 {
166 // let enter in ghost mode in instance that connected to inner instance with corpse
167 uint32 corpseMap = player->GetCorpseLocation().GetMapId();
168 do
169 {
170 if (corpseMap == mapid)
171 break;
172
173 InstanceTemplate const* corpseInstance = sObjectMgr->GetInstanceTemplate(corpseMap);
174 corpseMap = corpseInstance ? corpseInstance->Parent : 0;
175 } while (corpseMap);
176
177 if (!corpseMap)
179
180 TC_LOG_DEBUG("maps", "MAP: Player '{}' has corpse in instance '{}' and can enter.", player->GetName(), mapName);
181 }
182 else
183 {
184 TC_LOG_DEBUG("maps", "Map::CanPlayerEnter - player '{}' is dead but does not have a corpse!", player->GetName());
186 }
187 }
188
189 //Get instance where player's group is bound & its map
190 if (!loginCheck && group)
191 {
192 InstanceGroupBind* boundInstance = group->GetBoundInstance(entry);
193 if (boundInstance && boundInstance->save)
194 if (Map* boundMap = sMapMgr->FindMap(mapid, boundInstance->save->GetInstanceId()))
195 if (Map::EnterState denyReason = boundMap->CannotEnter(player))
196 return denyReason;
197 }
198
199 // players are only allowed to enter 5 instances per hour
200 if (entry->IsDungeon() && (!player->GetGroup() || (player->GetGroup() && !player->GetGroup()->isLFGGroup())))
201 {
202 uint32 instanceIdToCheck = 0;
203 if (InstanceSave* save = player->GetInstanceSave(mapid, entry->IsRaid()))
204 instanceIdToCheck = save->GetInstanceId();
205
206 // instanceId can never be 0 - will not be found
207 if (!player->GetSession()->UpdateAndCheckInstanceCount(instanceIdToCheck) && !player->isDead())
209 }
210
211 //Other requirements
212 if (!player->Satisfy(sObjectMgr->GetAccessRequirement(mapid, targetDifficulty), mapid, true))
214
215 return Map::CAN_ENTER;
216}
217
219{
220 i_timer.Update(diff);
221 if (!i_timer.Passed())
222 return;
223
224 MapMapType::iterator iter = i_maps.begin();
225 for (; iter != i_maps.end(); ++iter)
226 {
227 if (m_updater.activated())
229 else
230 iter->second->Update(uint32(i_timer.GetCurrent()));
231 }
232 if (m_updater.activated())
233 m_updater.wait();
234
235 for (iter = i_maps.begin(); iter != i_maps.end(); ++iter)
236 iter->second->DelayedUpdate(uint32(i_timer.GetCurrent()));
237
239}
240
242
243bool MapManager::ExistMapAndVMap(uint32 mapid, float x, float y)
244{
246
247 int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord;
248 int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord;
249
250 return Map::ExistMap(mapid, gx, gy) && Map::ExistVMap(mapid, gx, gy);
251}
252
253bool MapManager::IsValidMAP(uint32 mapid, bool startUp)
254{
255 MapEntry const* mEntry = sMapStore.LookupEntry(mapid);
256
257 if (startUp)
258 return mEntry ? true : false;
259 else
260 return mEntry && (!mEntry->IsDungeon() || sObjectMgr->GetInstanceTemplate(mapid));
261
263}
264
266{
267 // first unload maps
268 for (auto iter = i_maps.begin(); iter != i_maps.end(); ++iter)
269 {
270 iter->second->UnloadAll();
271
272 sScriptMgr->OnDestroyMap(iter->second.get());
273 }
274
275 // then delete them
276 i_maps.clear();
277
278 if (m_updater.activated())
280
282}
283
285{
286 std::lock_guard<std::mutex> lock(_mapsLock);
287
288 uint32 ret = 0;
289 for (auto const& [_, map] : i_maps)
290 {
291 MapInstanced* mapInstanced = map->ToMapInstanced();
292 if (!mapInstanced)
293 continue;
294 ret += mapInstanced->GetInstancedMaps().size();
295 }
296 return ret;
297}
298
300{
301 std::lock_guard<std::mutex> lock(_mapsLock);
302
303 uint32 ret = 0;
304 for (auto& [_, map] : i_maps)
305 {
306 MapInstanced* mapInstanced = map->ToMapInstanced();
307 if (!mapInstanced)
308 continue;
309 MapInstanced::InstancedMaps& maps = mapInstanced->GetInstancedMaps();
310 ret += std::accumulate(maps.begin(), maps.end(), 0u, [](uint32 total, MapInstanced::InstancedMaps::value_type const& value) { return total + value.second->GetPlayers().getSize(); });
311 }
312 return ret;
313}
314
316{
317 _nextInstanceId = 1;
318
319 if (QueryResult result = CharacterDatabase.Query("SELECT IFNULL(MAX(id), 0) FROM instance"))
320 _freeInstanceIds.resize((*result)[0].GetUInt64() + 2, true); // make space for one extra to be able to access [_nextInstanceId] index in case all slots are taken
321 else
322 _freeInstanceIds.resize(_nextInstanceId + 1, true);
323
324 // never allow 0 id
325 _freeInstanceIds[0] = false;
326}
327
329{
330 // Allocation and sizing was done in InitInstanceIds()
331 _freeInstanceIds[instanceId] = false;
332
333 // Instances are pulled in ascending order from db and nextInstanceId is initialized with 1,
334 // so if the instance id is used, increment until we find the first unused one for a potential new instance
335 if (_nextInstanceId == instanceId)
337}
338
340{
341 if (_nextInstanceId == 0xFFFFFFFF)
342 {
343 TC_LOG_ERROR("maps", "Instance ID overflow!! Can't continue, shutting down server. ");
345 return _nextInstanceId;
346 }
347
348 uint32 newInstanceId = _nextInstanceId;
349 ASSERT(newInstanceId < _freeInstanceIds.size());
350 _freeInstanceIds[newInstanceId] = false;
351
352 // Find the lowest available id starting from the current NextInstanceId (which should be the lowest according to the logic in FreeInstanceId())
353 size_t nextFreedId = _freeInstanceIds.find_next(_nextInstanceId++);
354 if (nextFreedId == InstanceIds::npos)
355 {
357 _freeInstanceIds.push_back(true);
358 }
359 else
360 _nextInstanceId = uint32(nextFreedId);
361
362 return newInstanceId;
363}
364
366{
367 // If freed instance id is lower than the next id available for new instances, use the freed one instead
368 _nextInstanceId = std::min(instanceId, _nextInstanceId);
369 _freeInstanceIds[instanceId] = true;
370}
Difficulty
Definition DBCEnums.h:279
@ REGULAR_DIFFICULTY
Definition DBCEnums.h:280
MapDifficulty const * GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty)
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint32_t uint32
Definition Define.h:133
#define ASSERT
Definition Errors.h:68
#define MAX_NUMBER_OF_GRIDS
Definition GridDefines.h:36
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define sMapMgr
Definition MapManager.h:211
#define sObjectMgr
Definition ObjectMgr.h:1721
#define sScriptMgr
Definition ScriptMgr.h:1168
Definition Group.h:165
bool isLFGGroup() const
Definition Group.cpp:2443
InstanceGroupBind * GetBoundInstance(Player *player)
Definition Group.cpp:2286
bool isRaidGroup() const
Definition Group.cpp:2448
uint32 GetInstanceId() const
std::unordered_map< uint32, Trinity::unique_trackable_ptr< Map > > InstancedMaps
InstancedMaps & GetInstancedMaps()
void RegisterInstanceId(uint32 instanceId)
Map * FindBaseNonInstanceMap(uint32 mapId) const
Map * CreateMap(uint32 mapId, Player *player, uint32 loginInstanceId=0)
uint32 GetNumPlayersInInstances()
static bool ExistMapAndVMap(uint32 mapid, float x, float y)
MapUpdater m_updater
Definition MapManager.h:166
static MapManager * instance()
Map * FindBaseMap(uint32 mapId) const
Definition MapManager.h:150
uint32 i_gridCleanUpDelay
Definition MapManager.h:160
void Initialize(void)
void Update(uint32)
void DoDelayedMovesAndRemoves()
Map * FindMap(uint32 mapId, uint32 instanceId) const
void InitializeVisibilityDistanceInfo()
void UnloadAll()
uint32 GetNumInstances()
std::mutex _mapsLock
Definition MapManager.h:159
uint32 _nextInstanceId
Definition MapManager.h:165
MapMapType i_maps
Definition MapManager.h:161
void InitInstanceIds()
Map * CreateBaseMap(uint32 mapId)
static bool IsValidMAP(uint32 mapid, bool startUp)
uint32 GenerateInstanceId()
IntervalTimer i_timer
Definition MapManager.h:162
void FreeInstanceId(uint32 instanceId)
InstanceIds _freeInstanceIds
Definition MapManager.h:164
Map::EnterState PlayerCannotEnter(uint32 mapid, Player *player, bool loginCheck=false)
void schedule_update(Map &map, uint32 diff)
void activate(size_t num_threads)
void wait()
bool activated()
void deactivate()
Definition Map.h:281
void SetWeakPtr(Trinity::unique_weak_ptr< Map > weakRef)
Definition Map.h:391
void LoadRespawnTimes()
Definition Map.cpp:4504
static void DeleteStateMachine()
Definition Map.cpp:264
void LoadCorpseData()
Definition Map.cpp:4558
bool Instanceable() const
Definition Map.cpp:4226
static void InitStateMachine()
Definition Map.cpp:256
MapInstanced * ToMapInstanced()
Definition Map.h:517
static bool ExistVMap(uint32 mapid, int gx, int gy)
Definition Map.cpp:138
EnterState
Definition Map.h:394
@ CANNOT_ENTER_CORPSE_IN_DIFFERENT_INSTANCE
Definition Map.h:401
@ CANNOT_ENTER_TOO_MANY_INSTANCES
Definition Map.h:403
@ CAN_ENTER
Definition Map.h:395
@ CANNOT_ENTER_UNSPECIFIED_REASON
Definition Map.h:406
@ CANNOT_ENTER_NO_ENTRY
Definition Map.h:397
@ CANNOT_ENTER_DIFFICULTY_UNAVAILABLE
Definition Map.h:399
@ CANNOT_ENTER_UNINSTANCED_DUNGEON
Definition Map.h:398
@ CANNOT_ENTER_NOT_IN_RAID
Definition Map.h:400
static bool ExistMap(uint32 mapid, int gx, int gy)
Definition Map.cpp:109
WorldLocation const & GetCorpseLocation() const
Definition Player.h:1758
InstanceSave * GetInstanceSave(uint32 mapid, bool raid)
Definition Player.cpp:18578
Difficulty GetDifficulty(bool isRaid) const
Definition Player.h:1634
bool HasCorpse() const
Definition Player.h:1757
WorldSession * GetSession() const
Definition Player.h:1719
bool Satisfy(AccessRequirement const *ar, uint32 target_map, bool report=false)
Definition Player.cpp:18784
Group * GetGroup()
Definition Player.h:2171
bool IsGameMaster() const
Definition Player.h:998
Specialized variant of std::shared_ptr that enforces unique ownership and/or std::unique_ptr with std...
bool IsAlive() const
Definition Unit.h:1234
bool isDead() const
Definition Unit.h:1236
uint32 GetMapId() const
Definition Position.h:193
std::string const & GetName() const
Definition Object.h:382
LocaleConstant GetSessionDbcLocale() const
bool UpdateAndCheckInstanceCount(uint32 instanceId)
static void StopNow(uint8 exitcode)
Definition World.h:673
#define sWorld
Definition World.h:900
@ CONFIG_INTERVAL_GRIDCLEAN
Definition World.h:213
@ CONFIG_INTERVAL_MAPUPDATE
Definition World.h:214
@ CONFIG_NUMTHREADS
Definition World.h:334
@ CONFIG_INSTANCE_IGNORE_RAID
Definition World.h:105
@ ERROR_EXIT_CODE
Definition World.h:64
GridCoord ComputeGridCoord(float x, float y)
uint32 x_coord
uint32 y_coord
InstanceSave * save
Definition Group.h:155
void SetInterval(time_t interval)
Definition Timer.h:94
time_t GetCurrent() const
Definition Timer.h:104
bool Passed()
Definition Timer.h:78
void Update(time_t diff)
Definition Timer.h:71
void SetCurrent(time_t current)
Definition Timer.h:89
char const * MapName[16]
bool IsDungeon() const
bool IsRaid() const
bool Instanceable() const