32 : _mapId(mapId), _difficultyId(difficultyId), _instanceId(instanceId), _expiryTime(expiryTime), _extended(false),
33 _isInUse(false), _isNew(false)
69 std::shared_ptr<SharedInstanceLockData> sharedData)
70 :
InstanceLock(mapId, difficultyId, expiryTime, instanceId), _sharedData(
std::move(sharedData))
80 :
Map(map), MapDifficulty(mapDifficulty)
104 std::unordered_map<uint32, std::shared_ptr<SharedInstanceLockData>> instanceLockDataById;
111 Field* fields = result->Fetch();
114 std::shared_ptr<SharedInstanceLockData> data = std::make_shared<SharedInstanceLockData>();
116 data->CompletedEncountersMask = fields[2].
GetUInt32();
117 data->InstanceId = instanceId;
119 instanceLockDataById[instanceId] = std::move(data);
121 }
while (result->NextRow());
126 if (
QueryResult result =
CharacterDatabase.Query(
"SELECT guid, mapId, lockId, instanceId, difficulty, data, completedEncountersMask, expiryTime, extended FROM character_instance_lock ORDER BY instanceId"))
130 Field* fields = result->Fetch();
132 ObjectGuid playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt64());
137 InstanceResetTimePoint expiryTime = std::chrono::system_clock::from_time_t(time_t(fields[7].GetUInt64()));
140 sMapMgr->RegisterInstanceId(instanceId);
145 auto sharedDataItr = instanceLockDataById.find(instanceId);
146 if (sharedDataItr == instanceLockDataById.end())
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);
153 instanceLock =
new SharedInstanceLock(mapId, difficulty, expiryTime, instanceId, sharedDataItr->second);
154 _instanceLockDataById[instanceId] = sharedDataItr->second;
157 instanceLock =
new InstanceLock(mapId, difficulty, expiryTime, instanceId);
163 _instanceLocksByPlayer[playerGuid][
InstanceLockKey{ mapId, lockId }].reset(instanceLock);
165 }
while (result->NextRow());
179 if (!playerInstanceLock)
199 auto playerLocksItr = locks.find(playerGuid);
200 if (playerLocksItr == locks.end())
203 auto lockItr = playerLocksItr->second.find(entries.
GetKey());
204 if (lockItr == playerLocksItr->second.end())
207 return lockItr->second.get();
220 std::shared_lock<std::shared_mutex> guard(
_locksMutex);
237 std::vector<InstanceLock const*> locks;
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(); });
258 std::shared_ptr<SharedInstanceLockData> sharedData = std::make_shared<SharedInstanceLockData>();
270 TC_LOG_DEBUG(
"instance.locks",
"[{}-{} | {}-{}] Created new temporary instance lock for {} in instance {}",
283 std::unique_lock<std::shared_mutex> guard(
_locksMutex);
291 auto lockItr = playerLocksItr->second.find(entries.
GetKey());
292 if (lockItr != playerLocksItr->second.end())
294 instanceLock = lockItr->second.release();
297 playerLocksItr->second.erase(lockItr);
298 if (playerLocksItr->second.empty())
301 TC_LOG_DEBUG(
"instance.locks",
"[{}-{} | {}-{}] Promoting temporary lock to permanent for {} in instance {}",
304 playerGuid.
ToString(), updateEvent.InstanceId);
315 ASSERT(!sharedDataItr->second.expired());
318 GetNextResetTime(entries), updateEvent.InstanceId, sharedDataItr->second.lock());
326 std::unique_lock<std::shared_mutex> guard(
_locksMutex);
331 TC_LOG_DEBUG(
"instance.locks",
"[{}-{} | {}-{}] Created new instance lock for {} in instance {}",
334 playerGuid.
ToString(), updateEvent.InstanceId);
350 instanceLock->
GetData()->
Data = std::move(updateEvent.NewData);
351 if (updateEvent.CompletedEncounter)
354 TC_LOG_DEBUG(
"instance.locks",
"[{}-{} | {}-{}] Instance lock for {} in instance {} gains completed encounter [{}-{}]",
357 playerGuid.
ToString(), updateEvent.InstanceId,
358 updateEvent.CompletedEncounter->ID, updateEvent.CompletedEncounter->Name[
sWorld->GetDefaultDbcLocale()]);
365 if (updateEvent.EntranceWorldSafeLocId)
372 TC_LOG_DEBUG(
"instance.locks",
"[{}-{} | {}-{}] Expired instance lock for {} in instance {} is now active",
375 playerGuid.
ToString(), updateEvent.InstanceId);
404 std::shared_ptr<SharedInstanceLockData> sharedData = sharedDataItr->second.lock();
406 ASSERT(!sharedData->InstanceId || sharedData->InstanceId == updateEvent.InstanceId);
407 sharedData->Data = std::move(updateEvent.NewData);
408 sharedData->InstanceId = updateEvent.InstanceId;
409 if (updateEvent.CompletedEncounter)
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()]);
416 if (updateEvent.EntranceWorldSafeLocId)
417 sharedData->EntranceWorldSafeLocId = *updateEvent.EntranceWorldSafeLocId;
420 stmt->
setUInt32(0, sharedData->InstanceId);
424 stmt->
setUInt32(0, sharedData->InstanceId);
426 stmt->
setUInt32(2, sharedData->CompletedEncountersMask);
427 stmt->
setUInt32(3, sharedData->EntranceWorldSafeLocId);
441 if (!itr->second.expired())
448 TC_LOG_DEBUG(
"instance.locks",
"Deleting instance {} as it is no longer referenced by any player", instanceId);
457 instanceLock->SetExtended(extended);
460 stmt->
setUInt8(0, extended ? 1 : 0);
466 TC_LOG_DEBUG(
"instance.locks",
"[{}-{} | {}-{}] Instance lock for {} is {} extended",
469 playerGuid.
ToString(), extended ?
"now" :
"no longer");
471 return { oldExpiryTime, instanceLock->GetEffectiveExpiryTime() };
474 return { InstanceResetTimePoint::min(), InstanceResetTimePoint::min() };
478 std::vector<InstanceLock const*>* locksReset, std::vector<InstanceLock const*>* locksFailedToReset)
484 for (PlayerLockMap::value_type
const& playerLockPair : playerLocksItr->second)
486 if (playerLockPair.second->IsInUse())
488 locksFailedToReset->push_back(playerLockPair.second.get());
492 if (mapId && *mapId != playerLockPair.second->GetMapId())
495 if (difficulty && *difficulty != playerLockPair.second->GetDifficultyId())
498 if (playerLockPair.second->IsExpired())
501 locksReset->push_back(playerLockPair.second.get());
504 if (!locksReset->empty())
509 MapDb2Entries entries(instanceLock->GetMapId(), instanceLock->GetDifficultyId());
512 const_cast<InstanceLock*
>(instanceLock)->SetExpiryTime(newExpiryTime);
513 const_cast<InstanceLock*
>(instanceLock)->SetExtended(
false);
516 stmt->
setUInt64(0,
uint64(std::chrono::system_clock::to_time_t(newExpiryTime)));
544 if (dateTime.tm_hour >= resetHour)
547 dateTime.tm_hour = resetHour;
553 int32 daysAdjust = resetDay - dateTime.tm_wday;
554 if (dateTime.tm_wday > resetDay || (dateTime.tm_wday == resetDay && dateTime.tm_hour >= resetHour))
557 dateTime.tm_hour = resetHour;
558 dateTime.tm_mday += daysAdjust;
565 return std::chrono::system_clock::from_time_t(mktime(&dateTime));
@ CHAR_INS_CHARACTER_INSTANCE_LOCK
@ CHAR_DEL_CHARACTER_INSTANCE_LOCK
@ CHAR_UPD_CHARACTER_INSTANCE_LOCK_FORCE_EXPIRE
@ CHAR_UPD_CHARACTER_INSTANCE_LOCK_EXTENSION
DB2Storage< DifficultyEntry > sDifficultyStore("Difficulty.db2", &DifficultyLoadInfo::Instance)
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
@ MAP_DIFFICULTY_RESET_WEEKLY
@ MAP_DIFFICULTY_RESET_DAILY
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
std::chrono::seconds Seconds
Seconds shorthand typedef.
#define ASSERT_NOTNULL(pointer)
std::chrono::system_clock::time_point InstanceResetTimePoint
std::pair< uint32, uint32 > InstanceLockKey
#define TC_LOG_DEBUG(filterType__,...)
#define TC_LOG_ERROR(filterType__,...)
@ TRANSFER_ABORT_ALREADY_COMPLETED_ENCOUNTER
@ TRANSFER_ABORT_LOCKED_TO_DIFFERENT_INSTANCE
std::optional< T > Optional
Optional helper class to wrap optional values within.
Class used to access individual fields of database query result.
std::string GetString() const
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)
std::chrono::system_clock::time_point _expiryTime
void SetExtended(bool extended)
InstanceResetTimePoint GetExpiryTime() const
InstanceLock(uint32 mapId, Difficulty difficultyId, InstanceResetTimePoint expiryTime, uint32 instanceId)
void SetIsNew(bool isNew)
void SetExpiryTime(InstanceResetTimePoint expiryTime)
InstanceResetTimePoint GetEffectiveExpiryTime() const
InstanceLockData * GetData()
uint32 GetInstanceId() const
LowType GetCounter() const
std::string ToString() const
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()
@ CONFIG_RESET_SCHEDULE_WEEK_DAY
@ CONFIG_RESET_SCHEDULE_HOUR
SystemTimePoint GetSystemTime()
Current chrono system_clock time point.
tm const * GetDateAndTime()
uint32 EntranceWorldSafeLocId
uint32 CompletedEncountersMask
virtual ~InstanceLockData()
InstanceLockUpdateEvent(uint32 instanceId, std::string newData, uint32 instanceCompletedEncountersMask, DungeonEncounterEntry const *completedEncounter, Optional< uint32 > entranceWorldSafeLocId)
InstanceLockUpdateEvent & operator=(InstanceLockUpdateEvent const &)=delete
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
~SharedInstanceLockData()