TrinityCore
InstanceLockMgr.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 "InstanceLockMgr.h"
19#include "DatabaseEnv.h"
20#include "DB2Stores.h"
21#include "Errors.h"
22#include "GameTime.h"
23#include "Log.h"
24#include "Map.h" // for TransferAbortReason
25#include "MapManager.h"
26#include "World.h"
27
30
31InstanceLock::InstanceLock(uint32 mapId, Difficulty difficultyId, InstanceResetTimePoint expiryTime, uint32 instanceId)
32 : _mapId(mapId), _difficultyId(difficultyId), _instanceId(instanceId), _expiryTime(expiryTime), _extended(false),
33 _isInUse(false), _isNew(false)
34{
35}
36
38
40{
42}
43
45{
46 if (!IsExtended())
47 return GetExpiryTime();
48
50
51 // return next reset time
52 if (IsExpired())
53 return sInstanceLockMgr.GetNextResetTime(entries);
54
55 // if not expired, return expiration time + 1 reset period
56 return GetExpiryTime() + Seconds(entries.MapDifficulty->GetRaidDuration());
57}
58
60
62{
63 // Cleanup database
64 if (InstanceId)
65 sInstanceLockMgr.OnSharedInstanceLockDataDelete(InstanceId);
66}
67
69 std::shared_ptr<SharedInstanceLockData> sharedData)
70 : InstanceLock(mapId, difficultyId, expiryTime, instanceId), _sharedData(std::move(sharedData))
71{
72}
73
75 : Map(sMapStore.AssertEntry(mapId)), MapDifficulty(ASSERT_NOTNULL(sDB2Manager.GetMapDifficultyData(mapId, difficulty)))
76{
77}
78
80 : Map(map), MapDifficulty(mapDifficulty)
81{
82}
83
85{
87}
88
90{
91 return !Map->IsFlexLocking() && !MapDifficulty->IsUsingEncounterLocks();
92}
93
97
99
100InstanceLockMgr::~InstanceLockMgr() = default;
101
103{
104 std::unordered_map<uint32, std::shared_ptr<SharedInstanceLockData>> instanceLockDataById;
105
106 // 0 1 2
107 if (QueryResult result = CharacterDatabase.Query("SELECT instanceId, data, completedEncountersMask FROM instance"))
108 {
109 do
110 {
111 Field* fields = result->Fetch();
112 uint32 instanceId = fields[0].GetUInt32();
113
114 std::shared_ptr<SharedInstanceLockData> data = std::make_shared<SharedInstanceLockData>();
115 data->Data = fields[1].GetString();
116 data->CompletedEncountersMask = fields[2].GetUInt32();
117 data->InstanceId = instanceId;
118
119 instanceLockDataById[instanceId] = std::move(data);
120
121 } while (result->NextRow());
122 }
123
124 // ORDER BY required by MapManager::RegisterInstanceId
125 // 0 1 2 3 4 5 6 7 8
126 if (QueryResult result = CharacterDatabase.Query("SELECT guid, mapId, lockId, instanceId, difficulty, data, completedEncountersMask, expiryTime, extended FROM character_instance_lock ORDER BY instanceId"))
127 {
128 do
129 {
130 Field* fields = result->Fetch();
131
132 ObjectGuid playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt64());
133 uint32 mapId = fields[1].GetUInt32();
134 uint32 lockId = fields[2].GetUInt32();
135 uint32 instanceId = fields[3].GetUInt32();
136 Difficulty difficulty = Difficulty(fields[4].GetUInt8());
137 InstanceResetTimePoint expiryTime = std::chrono::system_clock::from_time_t(time_t(fields[7].GetUInt64()));
138
139 // Mark instance id as being used
140 sMapMgr->RegisterInstanceId(instanceId);
141
142 InstanceLock* instanceLock;
143 if (MapDb2Entries{ mapId, difficulty }.IsInstanceIdBound())
144 {
145 auto sharedDataItr = instanceLockDataById.find(instanceId);
146 if (sharedDataItr == instanceLockDataById.end())
147 {
148 TC_LOG_ERROR("instance.locks", "Missing instance data for instance id based lock (id {})", instanceId);
149 CharacterDatabase.PExecute("DELETE FROM character_instance_lock WHERE instanceId = {}", instanceId);
150 continue;
151 }
152
153 instanceLock = new SharedInstanceLock(mapId, difficulty, expiryTime, instanceId, sharedDataItr->second);
154 _instanceLockDataById[instanceId] = sharedDataItr->second;
155 }
156 else
157 instanceLock = new InstanceLock(mapId, difficulty, expiryTime, instanceId);
158
159 instanceLock->GetData()->Data = fields[5].GetString();
160 instanceLock->GetData()->CompletedEncountersMask = fields[6].GetUInt32();
161 instanceLock->SetExtended(fields[8].GetBool());
162
163 _instanceLocksByPlayer[playerGuid][InstanceLockKey{ mapId, lockId }].reset(instanceLock);
164
165 } while (result->NextRow());
166 }
167}
168
170{
171 _unloading = true;
173 _instanceLockDataById.clear();
174}
175
176TransferAbortReason InstanceLockMgr::CanJoinInstanceLock(ObjectGuid const& playerGuid, MapDb2Entries const& entries, InstanceLock const* instanceLock) const
177{
178 InstanceLock const* playerInstanceLock = FindActiveInstanceLock(playerGuid, entries);
179 if (!playerInstanceLock)
180 return TRANSFER_ABORT_NONE;
181
182 if (entries.Map->IsFlexLocking())
183 {
184 // compare completed encounters - if instance has any encounters unkilled in players lock then cannot enter
185 if (playerInstanceLock->GetData()->CompletedEncountersMask & ~instanceLock->GetData()->CompletedEncountersMask)
187
188 return TRANSFER_ABORT_NONE;
189 }
190
191 if (!entries.MapDifficulty->IsUsingEncounterLocks() && !playerInstanceLock->IsNew() && playerInstanceLock->GetInstanceId() != instanceLock->GetInstanceId())
193
194 return TRANSFER_ABORT_NONE;
195}
196
197InstanceLock* InstanceLockMgr::FindInstanceLock(LockMap const& locks, ObjectGuid const& playerGuid, MapDb2Entries const& entries)
198{
199 auto playerLocksItr = locks.find(playerGuid);
200 if (playerLocksItr == locks.end())
201 return nullptr;
202
203 auto lockItr = playerLocksItr->second.find(entries.GetKey());
204 if (lockItr == playerLocksItr->second.end())
205 return nullptr;
206
207 return lockItr->second.get();
208}
209
211{
212 return FindActiveInstanceLock(playerGuid, entries, false, true);
213}
214
215InstanceLock* InstanceLockMgr::FindActiveInstanceLock(ObjectGuid const& playerGuid, MapDb2Entries const& entries, bool ignoreTemporary, bool ignoreExpired) const
216{
217 if (!entries.MapDifficulty->HasResetSchedule())
218 return nullptr;
219
220 std::shared_lock<std::shared_mutex> guard(_locksMutex);
221
222 InstanceLock* lock = FindInstanceLock(_instanceLocksByPlayer, playerGuid, entries);
223
224 // Ignore expired and not extended locks
225 if (lock && (!lock->IsExpired() || lock->IsExtended() || !ignoreExpired))
226 return lock;
227
228 if (ignoreTemporary)
229 return nullptr;
230
231 return FindInstanceLock(_temporaryInstanceLocksByPlayer, playerGuid, entries);
232}
233
234// used in world update thread (THREADUNSAFE packets) - no locking neccessary
235std::vector<InstanceLock const*> InstanceLockMgr::GetInstanceLocksForPlayer(ObjectGuid const& playerGuid) const
236{
237 std::vector<InstanceLock const*> locks;
238 auto playerLocksItr = _instanceLocksByPlayer.find(playerGuid);
239 if (playerLocksItr != _instanceLocksByPlayer.end())
240 {
241 locks.reserve(playerLocksItr->second.size());
242 std::transform(playerLocksItr->second.begin(), playerLocksItr->second.end(), std::back_inserter(locks),
243 [](PlayerLockMap::value_type const& p) { return p.second.get(); });
244 }
245
246 return locks;
247}
248
249// used in world update thread (cross map teleportation) - no locking neccessary
251{
252 if (!entries.MapDifficulty->HasResetSchedule())
253 return nullptr;
254
255 InstanceLock* instanceLock;
256 if (entries.IsInstanceIdBound())
257 {
258 std::shared_ptr<SharedInstanceLockData> sharedData = std::make_shared<SharedInstanceLockData>();
259 _instanceLockDataById[instanceId] = sharedData;
260 instanceLock = new SharedInstanceLock(entries.MapDifficulty->MapID, Difficulty(entries.MapDifficulty->DifficultyID),
261 GetNextResetTime(entries), instanceId, std::move(sharedData));
262 }
263 else
264 instanceLock = new InstanceLock(entries.MapDifficulty->MapID, Difficulty(entries.MapDifficulty->DifficultyID),
265 GetNextResetTime(entries), instanceId);
266
267 instanceLock->SetIsNew(true);
268
269 _temporaryInstanceLocksByPlayer[playerGuid][entries.GetKey()].reset(instanceLock);
270 TC_LOG_DEBUG("instance.locks", "[{}-{} | {}-{}] Created new temporary instance lock for {} in instance {}",
271 entries.Map->ID, entries.Map->MapName[sWorld->GetDefaultDbcLocale()],
272 uint32(entries.MapDifficulty->DifficultyID), sDifficultyStore.AssertEntry(entries.MapDifficulty->DifficultyID)->Name[sWorld->GetDefaultDbcLocale()],
273 playerGuid.ToString(), instanceId);
274 return instanceLock;
275}
276
278 MapDb2Entries const& entries, InstanceLockUpdateEvent&& updateEvent)
279{
280 InstanceLock* instanceLock = FindActiveInstanceLock(playerGuid, entries, true, true);
281 if (!instanceLock)
282 {
283 std::unique_lock<std::shared_mutex> guard(_locksMutex);
284
285 // Move lock from temporary storage if it exists there
286 // This is to avoid destroying expired locks before any boss is killed in a fresh lock
287 // player can still change his mind, exit instance and reactivate old lock
288 auto playerLocksItr = _temporaryInstanceLocksByPlayer.find(playerGuid);
289 if (playerLocksItr != _temporaryInstanceLocksByPlayer.end())
290 {
291 auto lockItr = playerLocksItr->second.find(entries.GetKey());
292 if (lockItr != playerLocksItr->second.end())
293 {
294 instanceLock = lockItr->second.release();
295 _instanceLocksByPlayer[playerGuid][entries.GetKey()].reset(instanceLock);
296
297 playerLocksItr->second.erase(lockItr);
298 if (playerLocksItr->second.empty())
299 _temporaryInstanceLocksByPlayer.erase(playerLocksItr);
300
301 TC_LOG_DEBUG("instance.locks", "[{}-{} | {}-{}] Promoting temporary lock to permanent for {} in instance {}",
302 entries.Map->ID, entries.Map->MapName[sWorld->GetDefaultDbcLocale()],
303 uint32(entries.MapDifficulty->DifficultyID), sDifficultyStore.AssertEntry(entries.MapDifficulty->DifficultyID)->Name[sWorld->GetDefaultDbcLocale()],
304 playerGuid.ToString(), updateEvent.InstanceId);
305 }
306 }
307 }
308
309 if (!instanceLock)
310 {
311 if (entries.IsInstanceIdBound())
312 {
313 auto sharedDataItr = _instanceLockDataById.find(updateEvent.InstanceId);
314 ASSERT(sharedDataItr != _instanceLockDataById.end());
315 ASSERT(!sharedDataItr->second.expired());
316
317 instanceLock = new SharedInstanceLock(entries.MapDifficulty->MapID, Difficulty(entries.MapDifficulty->DifficultyID),
318 GetNextResetTime(entries), updateEvent.InstanceId, sharedDataItr->second.lock());
319 ASSERT(static_cast<SharedInstanceLock*>(instanceLock)->GetSharedData()->InstanceId == updateEvent.InstanceId);
320 }
321 else
322 instanceLock = new InstanceLock(entries.MapDifficulty->MapID, Difficulty(entries.MapDifficulty->DifficultyID),
323 GetNextResetTime(entries), updateEvent.InstanceId);
324
325 {
326 std::unique_lock<std::shared_mutex> guard(_locksMutex);
327
328 _instanceLocksByPlayer[playerGuid][entries.GetKey()].reset(instanceLock);
329 }
330
331 TC_LOG_DEBUG("instance.locks", "[{}-{} | {}-{}] Created new instance lock for {} in instance {}",
332 entries.Map->ID, entries.Map->MapName[sWorld->GetDefaultDbcLocale()],
333 uint32(entries.MapDifficulty->DifficultyID), sDifficultyStore.AssertEntry(entries.MapDifficulty->DifficultyID)->Name[sWorld->GetDefaultDbcLocale()],
334 playerGuid.ToString(), updateEvent.InstanceId);
335 }
336 else
337 {
338 if (entries.IsInstanceIdBound())
339 {
340 ASSERT(instanceLock->GetInstanceId() == updateEvent.InstanceId);
341 auto sharedDataItr = _instanceLockDataById.find(updateEvent.InstanceId);
342 ASSERT(sharedDataItr != _instanceLockDataById.end());
343 ASSERT(sharedDataItr->second.lock().get() == static_cast<SharedInstanceLock*>(instanceLock)->GetSharedData());
344 }
345
346 instanceLock->SetInstanceId(updateEvent.InstanceId);
347 }
348
349 instanceLock->SetIsNew(false);
350 instanceLock->GetData()->Data = std::move(updateEvent.NewData);
351 if (updateEvent.CompletedEncounter)
352 {
353 instanceLock->GetData()->CompletedEncountersMask |= 1u << updateEvent.CompletedEncounter->Bit;
354 TC_LOG_DEBUG("instance.locks", "[{}-{} | {}-{}] Instance lock for {} in instance {} gains completed encounter [{}-{}]",
355 entries.Map->ID, entries.Map->MapName[sWorld->GetDefaultDbcLocale()],
356 uint32(entries.MapDifficulty->DifficultyID), sDifficultyStore.AssertEntry(entries.MapDifficulty->DifficultyID)->Name[sWorld->GetDefaultDbcLocale()],
357 playerGuid.ToString(), updateEvent.InstanceId,
358 updateEvent.CompletedEncounter->ID, updateEvent.CompletedEncounter->Name[sWorld->GetDefaultDbcLocale()]);
359 }
360
361 // Synchronize map completed encounters into players completed encounters for UI
362 if (!entries.MapDifficulty->IsUsingEncounterLocks())
363 instanceLock->GetData()->CompletedEncountersMask |= updateEvent.InstanceCompletedEncountersMask;
364
365 if (updateEvent.EntranceWorldSafeLocId)
366 instanceLock->GetData()->EntranceWorldSafeLocId = *updateEvent.EntranceWorldSafeLocId;
367
368 if (instanceLock->IsExpired())
369 {
370 instanceLock->SetExpiryTime(GetNextResetTime(entries));
371 instanceLock->SetExtended(false);
372 TC_LOG_DEBUG("instance.locks", "[{}-{} | {}-{}] Expired instance lock for {} in instance {} is now active",
373 entries.Map->ID, entries.Map->MapName[sWorld->GetDefaultDbcLocale()],
374 uint32(entries.MapDifficulty->DifficultyID), sDifficultyStore.AssertEntry(entries.MapDifficulty->DifficultyID)->Name[sWorld->GetDefaultDbcLocale()],
375 playerGuid.ToString(), updateEvent.InstanceId);
376 }
377
379 stmt->setUInt64(0, playerGuid.GetCounter());
380 stmt->setUInt32(1, entries.MapDifficulty->MapID);
381 stmt->setUInt32(2, entries.MapDifficulty->LockID);
382 trans->Append(stmt);
383
384 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_INSTANCE_LOCK);
385 stmt->setUInt64(0, playerGuid.GetCounter());
386 stmt->setUInt32(1, entries.MapDifficulty->MapID);
387 stmt->setUInt32(2, entries.MapDifficulty->LockID);
388 stmt->setUInt32(3, instanceLock->GetInstanceId());
389 stmt->setUInt8(4, entries.MapDifficulty->DifficultyID);
390 stmt->setString(5, instanceLock->GetData()->Data);
391 stmt->setUInt32(6, instanceLock->GetData()->CompletedEncountersMask);
392 stmt->setUInt32(7, instanceLock->GetData()->EntranceWorldSafeLocId);
393 stmt->setUInt64(8, uint64(std::chrono::system_clock::to_time_t(instanceLock->GetExpiryTime())));
394 stmt->setUInt8(9, instanceLock->IsExtended() ? 1 : 0);
395 trans->Append(stmt);
396
397 return instanceLock;
398}
399
401{
402 auto sharedDataItr = _instanceLockDataById.find(updateEvent.InstanceId);
403 ASSERT(sharedDataItr != _instanceLockDataById.end());
404 std::shared_ptr<SharedInstanceLockData> sharedData = sharedDataItr->second.lock();
405 ASSERT(sharedData);
406 ASSERT(!sharedData->InstanceId || sharedData->InstanceId == updateEvent.InstanceId);
407 sharedData->Data = std::move(updateEvent.NewData);
408 sharedData->InstanceId = updateEvent.InstanceId;
409 if (updateEvent.CompletedEncounter)
410 {
411 sharedData->CompletedEncountersMask |= 1u << updateEvent.CompletedEncounter->Bit;
412 TC_LOG_DEBUG("instance.locks", "Instance {} gains completed encounter [{}-{}]",
413 updateEvent.InstanceId, updateEvent.CompletedEncounter->ID, updateEvent.CompletedEncounter->Name[sWorld->GetDefaultDbcLocale()]);
414 }
415
416 if (updateEvent.EntranceWorldSafeLocId)
417 sharedData->EntranceWorldSafeLocId = *updateEvent.EntranceWorldSafeLocId;
418
420 stmt->setUInt32(0, sharedData->InstanceId);
421 trans->Append(stmt);
422
423 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_INSTANCE);
424 stmt->setUInt32(0, sharedData->InstanceId);
425 stmt->setString(1, sharedData->Data);
426 stmt->setUInt32(2, sharedData->CompletedEncountersMask);
427 stmt->setUInt32(3, sharedData->EntranceWorldSafeLocId);
428 trans->Append(stmt);
429}
430
432{
433 if (_unloading)
434 return;
435
436 auto itr = _instanceLockDataById.find(instanceId);
437 if (itr == _instanceLockDataById.end())
438 return;
439
440 // weak_ptr state must be checked as well, it might be pointing to a different and valid lock data
441 if (!itr->second.expired())
442 return;
443
444 _instanceLockDataById.erase(itr);
446 stmt->setUInt32(0, instanceId);
447 CharacterDatabase.Execute(stmt);
448 TC_LOG_DEBUG("instance.locks", "Deleting instance {} as it is no longer referenced by any player", instanceId);
449}
450
451std::pair<InstanceResetTimePoint, InstanceResetTimePoint> InstanceLockMgr::UpdateInstanceLockExtensionForPlayer(ObjectGuid const& playerGuid,
452 MapDb2Entries const& entries, bool extended)
453{
454 if (InstanceLock* instanceLock = FindActiveInstanceLock(playerGuid, entries, true, false))
455 {
456 InstanceResetTimePoint oldExpiryTime = instanceLock->GetEffectiveExpiryTime();
457 instanceLock->SetExtended(extended);
458
460 stmt->setUInt8(0, extended ? 1 : 0);
461 stmt->setUInt64(1, playerGuid.GetCounter());
462 stmt->setUInt32(2, entries.MapDifficulty->MapID);
463 stmt->setUInt32(3, entries.MapDifficulty->LockID);
464 CharacterDatabase.Execute(stmt);
465
466 TC_LOG_DEBUG("instance.locks", "[{}-{} | {}-{}] Instance lock for {} is {} extended",
467 entries.Map->ID, entries.Map->MapName[sWorld->GetDefaultDbcLocale()],
468 uint32(entries.MapDifficulty->DifficultyID), sDifficultyStore.AssertEntry(entries.MapDifficulty->DifficultyID)->Name[sWorld->GetDefaultDbcLocale()],
469 playerGuid.ToString(), extended ? "now" : "no longer");
470
471 return { oldExpiryTime, instanceLock->GetEffectiveExpiryTime() };
472 }
473
474 return { InstanceResetTimePoint::min(), InstanceResetTimePoint::min() };
475}
476
478 std::vector<InstanceLock const*>* locksReset, std::vector<InstanceLock const*>* locksFailedToReset)
479{
480 auto playerLocksItr = _instanceLocksByPlayer.find(playerGuid);
481 if (playerLocksItr == _instanceLocksByPlayer.end())
482 return;
483
484 for (PlayerLockMap::value_type const& playerLockPair : playerLocksItr->second)
485 {
486 if (playerLockPair.second->IsInUse())
487 {
488 locksFailedToReset->push_back(playerLockPair.second.get());
489 continue;
490 }
491
492 if (mapId && *mapId != playerLockPair.second->GetMapId())
493 continue;
494
495 if (difficulty && *difficulty != playerLockPair.second->GetDifficultyId())
496 continue;
497
498 if (playerLockPair.second->IsExpired())
499 continue;
500
501 locksReset->push_back(playerLockPair.second.get());
502 }
503
504 if (!locksReset->empty())
505 {
506 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
507 for (InstanceLock const* instanceLock : *locksReset)
508 {
509 MapDb2Entries entries(instanceLock->GetMapId(), instanceLock->GetDifficultyId());
510 InstanceResetTimePoint newExpiryTime = GetNextResetTime(entries) - Seconds(entries.MapDifficulty->GetRaidDuration());
511 // set reset time to last reset time
512 const_cast<InstanceLock*>(instanceLock)->SetExpiryTime(newExpiryTime);
513 const_cast<InstanceLock*>(instanceLock)->SetExtended(false);
514
516 stmt->setUInt64(0, uint64(std::chrono::system_clock::to_time_t(newExpiryTime)));
517 stmt->setUInt64(1, playerGuid.GetCounter());
518 stmt->setUInt32(2, entries.MapDifficulty->MapID);
519 stmt->setUInt32(3, entries.MapDifficulty->LockID);
520 trans->Append(stmt);
521 }
522 CharacterDatabase.CommitTransaction(trans);
523 }
524}
525
527{
528 InstanceLocksStatistics statistics;
529 statistics.InstanceCount = _instanceLockDataById.size();
530 statistics.PlayerCount = _instanceLocksByPlayer.size();
531 return statistics;
532}
533
535{
536 tm dateTime = *GameTime::GetDateAndTime();
537 dateTime.tm_sec = 0;
538 dateTime.tm_min = 0;
539 int32 resetHour = sWorld->getIntConfig(CONFIG_RESET_SCHEDULE_HOUR);
540 switch (entries.MapDifficulty->ResetInterval)
541 {
543 {
544 if (dateTime.tm_hour >= resetHour)
545 ++dateTime.tm_mday;
546
547 dateTime.tm_hour = resetHour;
548 break;
549 }
551 {
552 int32 resetDay = sWorld->getIntConfig(CONFIG_RESET_SCHEDULE_WEEK_DAY);
553 int32 daysAdjust = resetDay - dateTime.tm_wday;
554 if (dateTime.tm_wday > resetDay || (dateTime.tm_wday == resetDay && dateTime.tm_hour >= resetHour))
555 daysAdjust += 7; // passed it for current week, grab time from next week
556
557 dateTime.tm_hour = resetHour;
558 dateTime.tm_mday += daysAdjust;
559 break;
560 }
561 default:
562 break;
563 }
564
565 return std::chrono::system_clock::from_time_t(mktime(&dateTime));
566}
567
569{
570 static InstanceLockMgr instance;
571 return instance;
572}
@ CHAR_INS_CHARACTER_INSTANCE_LOCK
@ CHAR_DEL_CHARACTER_INSTANCE_LOCK
@ CHAR_INS_INSTANCE
@ CHAR_UPD_CHARACTER_INSTANCE_LOCK_FORCE_EXPIRE
@ CHAR_UPD_CHARACTER_INSTANCE_LOCK_EXTENSION
@ CHAR_DEL_INSTANCE
DB2Storage< DifficultyEntry > sDifficultyStore("Difficulty.db2", &DifficultyLoadInfo::Instance)
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
#define sDB2Manager
Definition: DB2Stores.h:538
@ MAP_DIFFICULTY_RESET_WEEKLY
Definition: DBCEnums.h:1316
@ MAP_DIFFICULTY_RESET_DAILY
Definition: DBCEnums.h:1315
Difficulty
Definition: DBCEnums.h:873
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
uint32_t uint32
Definition: Define.h:142
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition: Duration.h:32
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
#define ASSERT
Definition: Errors.h:68
std::chrono::system_clock::time_point InstanceResetTimePoint
#define sInstanceLockMgr
std::pair< uint32, uint32 > InstanceLockKey
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define sMapMgr
Definition: MapManager.h:184
TransferAbortReason
Definition: Map.h:86
@ TRANSFER_ABORT_NONE
Definition: Map.h:87
@ TRANSFER_ABORT_ALREADY_COMPLETED_ENCOUNTER
Definition: Map.h:104
@ TRANSFER_ABORT_LOCKED_TO_DIFFERENT_INSTANCE
Definition: Map.h:103
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
Class used to access individual fields of database query result.
Definition: Field.h:90
std::string GetString() const
Definition: Field.cpp:118
uint32 GetUInt32() const
Definition: Field.cpp:62
LockMap _temporaryInstanceLocksByPlayer
LockMap _instanceLocksByPlayer
InstanceLocksStatistics GetStatistics() const
Retrieves instance lock statistics - for use in GM commands.
InstanceLock * CreateInstanceLockForNewInstance(ObjectGuid const &playerGuid, MapDb2Entries const &entries, uint32 instanceId)
Creates new InstanceLock when instance map is created.
std::unordered_map< uint32, std::weak_ptr< SharedInstanceLockData > > _instanceLockDataById
static InstanceLock * FindInstanceLock(LockMap const &locks, ObjectGuid const &playerGuid, MapDb2Entries const &entries)
InstanceLock * UpdateInstanceLockForPlayer(CharacterDatabaseTransaction trans, ObjectGuid const &playerGuid, MapDb2Entries const &entries, InstanceLockUpdateEvent &&updateEvent)
Updates existing instance lock for player with new completed encounter and instance state.
static InstanceResetTimePoint GetNextResetTime(MapDb2Entries const &entries)
static InstanceLockMgr & Instance()
void UpdateSharedInstanceLock(CharacterDatabaseTransaction trans, InstanceLockUpdateEvent &&updateEvent)
Updates existing instance id based lock shared state with new completed encounter and instance state.
std::unordered_map< ObjectGuid, PlayerLockMap > LockMap
InstanceLock * FindActiveInstanceLock(ObjectGuid const &playerGuid, MapDb2Entries const &entries) const
Attempts to find InstanceLock for given instance owner. This will also find expired but extended lock...
std::vector< InstanceLock const * > GetInstanceLocksForPlayer(ObjectGuid const &playerGuid) const
Retrieves all existing instance locks for a player.
TransferAbortReason CanJoinInstanceLock(ObjectGuid const &playerGuid, MapDb2Entries const &entries, InstanceLock const *instanceLock) const
Checks if player is allowed to enter instance map.
std::pair< InstanceResetTimePoint, InstanceResetTimePoint > UpdateInstanceLockExtensionForPlayer(ObjectGuid const &playerGuid, MapDb2Entries const &entries, bool extended)
Updates existing instance lock for player with requested extension state.
void ResetInstanceLocksForPlayer(ObjectGuid const &playerGuid, Optional< uint32 > mapId, Optional< Difficulty > difficulty, std::vector< InstanceLock const * > *locksReset, std::vector< InstanceLock const * > *locksFailedToReset)
Resets instances that match given filter - for use in GM commands.
std::shared_mutex _locksMutex
void OnSharedInstanceLockDataDelete(uint32 instanceId)
Handles last reference to shared instance state being removed to clean up leftover database data.
void SetInstanceId(uint32 instanceId)
virtual ~InstanceLock()
std::chrono::system_clock::time_point _expiryTime
bool IsExtended() const
void SetExtended(bool extended)
Difficulty _difficultyId
InstanceResetTimePoint GetExpiryTime() const
InstanceLock(uint32 mapId, Difficulty difficultyId, InstanceResetTimePoint expiryTime, uint32 instanceId)
void SetIsNew(bool isNew)
void SetExpiryTime(InstanceResetTimePoint expiryTime)
bool IsNew() const
InstanceResetTimePoint GetEffectiveExpiryTime() const
bool IsExpired() const
InstanceLockData * GetData()
uint32 GetInstanceId() const
Definition: Map.h:189
LowType GetCounter() const
Definition: ObjectGuid.h:293
std::string ToString() const
Definition: ObjectGuid.cpp:554
void setUInt8(const uint8 index, const uint8 value)
void setUInt32(const uint8 index, const uint32 value)
void setString(const uint8 index, const std::string &value)
void setUInt64(const uint8 index, const uint64 value)
SharedInstanceLock(uint32 mapId, Difficulty difficultyId, InstanceResetTimePoint expiryTime, uint32 instanceId, std::shared_ptr< SharedInstanceLockData > sharedData)
SharedInstanceLockData * GetSharedData()
#define sWorld
Definition: World.h:931
@ CONFIG_RESET_SCHEDULE_WEEK_DAY
Definition: World.h:276
@ CONFIG_RESET_SCHEDULE_HOUR
Definition: World.h:277
SystemTimePoint GetSystemTime()
Current chrono system_clock time point.
Definition: GameTime.cpp:54
tm const * GetDateAndTime()
Definition: GameTime.cpp:87
STL namespace.
uint32 EntranceWorldSafeLocId
std::string Data
uint32 CompletedEncountersMask
virtual ~InstanceLockData()
InstanceLockUpdateEvent(uint32 instanceId, std::string newData, uint32 instanceCompletedEncountersMask, DungeonEncounterEntry const *completedEncounter, Optional< uint32 > entranceWorldSafeLocId)
InstanceLockUpdateEvent & operator=(InstanceLockUpdateEvent const &)=delete
MapEntry const * Map
bool IsInstanceIdBound() const
MapDifficultyEntry const * MapDifficulty
InstanceLockKey GetKey() const
MapDb2Entries(uint32 mapId, Difficulty difficulty)
uint32 GetRaidDuration() const
bool IsUsingEncounterLocks() const
bool HasResetSchedule() const
bool IsFlexLocking() const
LocalizedString MapName
uint32 ID