Core/Misc: Various dynspawn cleanup and refactors split off from pooling rewrite:

- Map::RemoveRespawnTime(SpawnObjectType, LowType, doRespawn) split into Map::Respawn and Map::RemoveRespawnTime, without the extra boolean
- Map::RemoveRespawnTime(RespawnInfo*) merged into Map::DeleteRespawnInfo(RespawnInfo*) and is now private
- Map::DeleteRespawnInfo(void) renamed to Map::UnloadAllRespawnInfos to properly describe what it does
- Map::ProcessRespawns now actually saves the delayed respawn time to DB if the respawn was delayed
- Map::AddRespawnInfo now takes const reference, and returns success as a boolean
- Map::AddRespawnInfo no longer offers an unused "replace" parameter
- Map::DeleteRespawnInfo no longer offers a variety of unused private overloads
- Map::SaveRespawnTime no longer offers a tantalizing writeDB parameter. Parameter is now called "startup" to properly describe what it does.
- Map::SaveRespawnInfoDB now takes RespawnInfo reference instead of all the various fields. Still public because compatibility mode. QQ.
- Map::GetWorldObjectBySpawnId sanitized
- Map::GetXRespawnTime methods sanitized to all go through Map::GetRespawnTime

----------

Core/DB: Unify `creature_respawn` and `gameobject_respawn` into a single `respawn` table
This commit is contained in:
Treeston authored and Ovahlord committed 2019-08-18 12:47:10 +02:00
1 parent f9184f026b
commit 90540d684b
15 files changed
+184 -236

No files matched your search

+13 -44
View File
@@ -1659,32 +1659,26 @@ LOCK TABLES `corpse_phases` WRITE;
/*!40000 ALTER TABLE `corpse_phases` DISABLE KEYS */;
/*!40000 ALTER TABLE `corpse_phases` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `creature_respawn`
-- Table structure for table `respawn`
--
DROP TABLE IF EXISTS `creature_respawn`;
DROP TABLE IF EXISTS `respawn`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `creature_respawn` (
`guid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
`respawnTime` bigint(20) unsigned NOT NULL DEFAULT '0',
`mapId` smallint(10) unsigned NOT NULL DEFAULT '0',
`instanceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Instance Identifier',
PRIMARY KEY (`guid`,`instanceId`),
CREATE TABLE `respawn` (
`type` smallint(10) unsigned NOT NULL,
`spawnId` int(10) unsigned NOT NULL,
`respawnTime` bigint(20) unsigned NOT NULL,
`mapId` smallint(10) unsigned NOT NULL,
`instanceId` int(10) unsigned NOT NULL,
PRIMARY KEY (`type`,`spawnId`,`instanceId`),
KEY `idx_instance` (`instanceId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Grid Loading System';
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Stored respawn times';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `creature_respawn`
--
LOCK TABLES `creature_respawn` WRITE;
/*!40000 ALTER TABLE `creature_respawn` DISABLE KEYS */;
/*!40000 ALTER TABLE `creature_respawn` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `game_event_condition_save`
--
@@ -1733,32 +1727,6 @@ LOCK TABLES `game_event_save` WRITE;
/*!40000 ALTER TABLE `game_event_save` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `gameobject_respawn`
--
DROP TABLE IF EXISTS `gameobject_respawn`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `gameobject_respawn` (
`guid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
`respawnTime` bigint(20) unsigned NOT NULL DEFAULT '0',
`mapId` smallint(10) unsigned NOT NULL DEFAULT '0',
`instanceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Instance Identifier',
PRIMARY KEY (`guid`,`instanceId`),
KEY `idx_instance` (`instanceId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Grid Loading System';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `gameobject_respawn`
--
LOCK TABLES `gameobject_respawn` WRITE;
/*!40000 ALTER TABLE `gameobject_respawn` DISABLE KEYS */;
/*!40000 ALTER TABLE `gameobject_respawn` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `gm_subsurvey`
--
@@ -2999,7 +2967,8 @@ INSERT INTO `updates` VALUES
('2018_07_09_00_characters.sql','6F3EA22DD5E4CD9F9C60C4332B147E3DBF2E8A44','ARCHIVED','2018-07-09 18:19:18',0),
('2018_07_15_00_characters.sql','1EB34168BC396A8264C7467AACD1F0A3B036B22D','ARCHIVED','2018-07-15 00:00:00',0),
('2018_08_15_00_characters.sql','592D9F32E96E1A14C8F340E8D085F8F5105B063F','ARCHIVED','2018-08-15 00:00:00',0),
('2018_09_15_00_characters.sql','FDC0AF579D140BE377482B115EE07DC43F870C98','ARCHIVED','2018-08-15 00:00:00',0);
('2018_09_15_00_characters.sql','FDC0AF579D140BE377482B115EE07DC43F870C98','ARCHIVED','2018-08-15 00:00:00',0),
('2019_07_14_00_characters.sql','A141F4F15BDF0320483921429871D4C572BD7E2D','ARCHIVED','2019-07-04 00:00:00',0);
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES;
@@ -0,0 +1,20 @@
--
DROP TABLE IF EXISTS `respawn`;
CREATE TABLE `respawn` (
`type` smallint(10) unsigned NOT NULL,
`spawnId` int(10) unsigned NOT NULL,
`respawnTime` bigint(20) unsigned NOT NULL,
`mapId` smallint(10) unsigned NOT NULL,
`instanceId` int(10) unsigned NOT NULL,
PRIMARY KEY (`type`,`spawnId`,`instanceId`),
KEY `idx_instance` (`instanceId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Stored respawn times';
INSERT INTO `respawn` (`type`,`spawnId`,`respawnTime`,`mapId`,`instanceId`)
SELECT 0 as `type`,`guid`,`respawnTime`,`mapId`,`instanceId` FROM `creature_respawn`;
INSERT INTO `respawn` (`type`,`spawnId`,`respawnTime`,`mapId`,`instanceId`)
SELECT 1 as `type`,`guid`,`respawnTime`,`mapId`,`instanceId` FROM `gameobject_respawn`;
DROP TABLE `creature_respawn`;
DROP TABLE `gameobject_respawn`;
@@ -353,17 +353,11 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_CORPSE_PHASES, "DELETE FROM corpse_phases WHERE OwnerGuid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CORPSE_LOCATION, "SELECT mapId, posX, posY, posZ, orientation FROM corpse WHERE guid = ?", CONNECTION_ASYNC);
// Creature respawn
PrepareStatement(CHAR_SEL_CREATURE_RESPAWNS, "SELECT guid, respawnTime FROM creature_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_REP_CREATURE_RESPAWN, "REPLACE INTO creature_respawn (guid, respawnTime, mapId, instanceId) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CREATURE_RESPAWN, "DELETE FROM creature_respawn WHERE guid = ? AND mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CREATURE_RESPAWN_BY_INSTANCE, "DELETE FROM creature_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
// Gameobject respawn
PrepareStatement(CHAR_SEL_GO_RESPAWNS, "SELECT guid, respawnTime FROM gameobject_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_REP_GO_RESPAWN, "REPLACE INTO gameobject_respawn (guid, respawnTime, mapId, instanceId) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GO_RESPAWN, "DELETE FROM gameobject_respawn WHERE guid = ? AND mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GO_RESPAWN_BY_INSTANCE, "DELETE FROM gameobject_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
// Respawns
PrepareStatement(CHAR_SEL_RESPAWNS, "SELECT type, spawnId, respawnTime FROM respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_REP_RESPAWN, "REPLACE INTO respawn (type, spawnId, respawnTime, mapId, instanceId) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_RESPAWN, "DELETE FROM respawn WHERE type = ? AND spawnId = ? AND mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ALL_RESPAWNS, "DELETE FROM respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
// GM Tickets
PrepareStatement(CHAR_SEL_GM_TICKETS, "SELECT id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp FROM gm_ticket", CONNECTION_SYNCH);
@@ -298,15 +298,10 @@ enum CharacterDatabaseStatements : uint32
CHAR_DEL_CORPSE_PHASES,
CHAR_SEL_CORPSE_LOCATION,
CHAR_SEL_CREATURE_RESPAWNS,
CHAR_REP_CREATURE_RESPAWN,
CHAR_DEL_CREATURE_RESPAWN,
CHAR_DEL_CREATURE_RESPAWN_BY_INSTANCE,
CHAR_SEL_GO_RESPAWNS,
CHAR_REP_GO_RESPAWN,
CHAR_DEL_GO_RESPAWN,
CHAR_DEL_GO_RESPAWN_BY_INSTANCE,
CHAR_SEL_RESPAWNS,
CHAR_REP_RESPAWN,
CHAR_DEL_RESPAWN,
CHAR_DEL_ALL_RESPAWNS,
CHAR_SEL_GM_TICKETS,
CHAR_REP_GM_TICKET,
@@ -242,7 +242,7 @@ void EscortAI::UpdateAI(uint32 diff)
if (_instantRespawn && !isEscort)
me->DespawnOrUnsummon(0, Seconds(1));
else if (_instantRespawn && isEscort)
me->GetMap()->RemoveRespawnTime(SPAWN_TYPE_CREATURE, me->GetSpawnId(), true);
me->GetMap()->Respawn(SPAWN_TYPE_CREATURE, me->GetSpawnId());
else
me->DespawnOrUnsummon();
@@ -2380,7 +2380,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
map = targets.front()->GetMap();
if (map)
map->RemoveRespawnTime(SpawnObjectType(e.action.respawnData.spawnType), e.action.respawnData.spawnId, true);
map->Respawn(SpawnObjectType(e.action.respawnData.spawnType), e.action.respawnData.spawnId);
else
TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry %d SourceType %u, Event %u - tries to respawn by spawnId but does not provide a map", e.entryOrGuid, e.GetScriptType(), e.event_id);
break;
@@ -1665,7 +1665,7 @@ bool Creature::hasInvolvedQuest(uint32 quest_id) const
toUnload.push_back(pair.second);
for (Creature* creature : toUnload)
map->AddObjectToRemoveList(creature);
map->RemoveRespawnTime(SPAWN_TYPE_CREATURE, spawnId, false, trans);
map->RemoveRespawnTime(SPAWN_TYPE_CREATURE, spawnId, trans);
}
);
@@ -1942,9 +1942,6 @@ void Creature::Respawn(bool force)
if (getDeathState() == DEAD)
{
if (m_spawnId)
GetMap()->RemoveRespawnTime(SPAWN_TYPE_CREATURE, m_spawnId);
TC_LOG_DEBUG("entities.unit", "Respawning creature %s (%s)", GetName().c_str(), GetGUID().ToString().c_str());
m_respawnTime = 0;
ResetPickPocketRefillTimer();
@@ -1982,7 +1979,7 @@ void Creature::Respawn(bool force)
else
{
if (m_spawnId)
GetMap()->RemoveRespawnTime(SPAWN_TYPE_CREATURE, m_spawnId, true);
GetMap()->Respawn(SPAWN_TYPE_CREATURE, m_spawnId);
}
TC_LOG_DEBUG("entities.unit", "Respawning creature %s (%s)",
@@ -2394,12 +2391,15 @@ void Creature::SaveRespawnTime(uint32 forceDelay, bool savetodb)
if (m_respawnCompatibilityMode)
{
GetMap()->SaveRespawnTimeDB(SPAWN_TYPE_CREATURE, m_spawnId, m_respawnTime);
return;
RespawnInfo ri;
ri.type = SPAWN_TYPE_CREATURE;
ri.spawnId = m_spawnId;
ri.respawnTime = m_respawnTime;
GetMap()->SaveRespawnInfoDB(ri);
}
time_t thisRespawnTime = forceDelay ? GameTime::GetGameTime() + forceDelay : m_respawnTime;
GetMap()->SaveRespawnTime(SPAWN_TYPE_CREATURE, m_spawnId, GetEntry(), thisRespawnTime, Trinity::ComputeGridCoord(GetHomePosition().GetPositionX(), GetHomePosition().GetPositionY()).GetId(), savetodb && m_creatureData && m_creatureData->dbData);
GetMap()->SaveRespawnTime(SPAWN_TYPE_CREATURE, m_spawnId, GetEntry(), thisRespawnTime, Trinity::ComputeGridCoord(GetHomePosition().GetPositionX(), GetHomePosition().GetPositionY()).GetId());
}
// this should not be called by petAI or
@@ -1004,7 +1004,7 @@ bool GameObject::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap
toUnload.push_back(pair.second);
for (GameObject* obj : toUnload)
map->AddObjectToRemoveList(obj);
map->RemoveRespawnTime(SPAWN_TYPE_GAMEOBJECT, spawnId, false, trans);
map->RemoveRespawnTime(SPAWN_TYPE_GAMEOBJECT, spawnId, trans);
}
);
@@ -1094,12 +1094,16 @@ void GameObject::SaveRespawnTime(uint32 forceDelay, bool savetodb)
{
if (m_respawnCompatibilityMode)
{
GetMap()->SaveRespawnTimeDB(SPAWN_TYPE_GAMEOBJECT, m_spawnId, m_respawnTime);
RespawnInfo ri;
ri.type = SPAWN_TYPE_GAMEOBJECT;
ri.spawnId = m_spawnId;
ri.respawnTime = m_respawnTime;
GetMap()->SaveRespawnInfoDB(ri);
return;
}
uint32 thisRespawnTime = forceDelay ? time(nullptr) + forceDelay : m_respawnTime;
GetMap()->SaveRespawnTime(SPAWN_TYPE_GAMEOBJECT, m_spawnId, GetEntry(), thisRespawnTime, Trinity::ComputeGridCoord(GetPositionX(), GetPositionY()).GetId(), m_goData->dbData ? savetodb : false);
GetMap()->SaveRespawnTime(SPAWN_TYPE_GAMEOBJECT, m_spawnId, GetEntry(), thisRespawnTime, Trinity::ComputeGridCoord(GetPositionX(), GetPositionY()).GetId());
}
}
@@ -1182,7 +1186,7 @@ void GameObject::Respawn()
if (m_spawnedByDefault && m_respawnTime > 0)
{
m_respawnTime = time(nullptr);
GetMap()->RemoveRespawnTime(SPAWN_TYPE_GAMEOBJECT, m_spawnId, true);
GetMap()->Respawn(SPAWN_TYPE_GAMEOBJECT, m_spawnId);
}
}
@@ -279,8 +279,7 @@ void InstanceSaveManager::LoadInstances()
CharacterDatabase.DirectExecute("DELETE i.* FROM instance AS i LEFT JOIN character_instance AS ci ON i.id = ci.instance LEFT JOIN group_instance AS gi ON i.id = gi.instance WHERE ci.guid IS NULL AND gi.guid IS NULL");
// Delete invalid references to instance
CharacterDatabase.DirectExecute("DELETE FROM creature_respawn WHERE instanceId > 0 AND instanceId NOT IN (SELECT id FROM instance)");
CharacterDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE instanceId > 0 AND instanceId NOT IN (SELECT id FROM instance)");
CharacterDatabase.DirectExecute("DELETE FROM respawn WHERE instanceId > 0 AND instanceId NOT IN (SELECT id FROM instance)");
CharacterDatabase.DirectExecute("DELETE tmp.* FROM character_instance AS tmp LEFT JOIN instance ON tmp.instance = instance.id WHERE tmp.instance > 0 AND instance.id IS NULL");
CharacterDatabase.DirectExecute("DELETE tmp.* FROM group_instance AS tmp LEFT JOIN instance ON tmp.instance = instance.id WHERE tmp.instance > 0 AND instance.id IS NULL");
+63 -102
View File
@@ -76,7 +76,7 @@ Map::~Map()
// Delete all waiting spawns, else there will be a memory leak
// This doesn't delete from database.
DeleteRespawnInfo();
UnloadAllRespawnInfos();
while (!i_worldObjects.empty())
{
@@ -3178,9 +3178,12 @@ void Map::Respawn(RespawnInfo* info, SQLTransaction dbTrans)
if (!CheckRespawn(info))
{
if (info->respawnTime)
SaveRespawnTime(info->type, info->spawnId, info->entry, info->respawnTime, info->gridId, true, true, dbTrans);
{
_respawnTimes.decrease(info->handle);
SaveRespawnInfoDB(*info, dbTrans);
}
else
RemoveRespawnTime(info);
DeleteRespawnInfo(info, dbTrans);
return;
}
@@ -3188,23 +3191,13 @@ void Map::Respawn(RespawnInfo* info, SQLTransaction dbTrans)
SpawnObjectType const type = info->type;
uint32 const gridId = info->gridId;
ObjectGuid::LowType const spawnId = info->spawnId;
RemoveRespawnTime(info);
DeleteRespawnInfo(info, dbTrans);
DoRespawn(type, spawnId, gridId);
}
void Map::Respawn(std::vector<RespawnInfo*>& respawnData, SQLTransaction dbTrans)
bool Map::AddRespawnInfo(RespawnInfo const& info)
{
SQLTransaction trans = dbTrans ? dbTrans : CharacterDatabase.BeginTransaction();
for (RespawnInfo* info : respawnData)
Respawn(info, trans);
if (!dbTrans)
CharacterDatabase.CommitTransaction(trans);
}
void Map::AddRespawnInfo(RespawnInfo& info, bool replace)
{
if (!info.spawnId)
return;
ASSERT(info.spawnId, "Attempt to schedule respawn with zero spawnid (type %u)", uint32(info.type));
RespawnInfoMap& bySpawnIdMap = GetRespawnMapForType(info.type);
@@ -3212,13 +3205,10 @@ void Map::AddRespawnInfo(RespawnInfo& info, bool replace)
if (it != bySpawnIdMap.end()) // spawnid already has a respawn scheduled
{
RespawnInfo* const existing = it->second;
if (replace || info.respawnTime < existing->respawnTime) // delete existing in this case
if (info.respawnTime < existing->respawnTime) // delete existing in this case
DeleteRespawnInfo(existing);
else // don't delete existing, instead replace respawn time so caller saves the correct time
{
info.respawnTime = existing->respawnTime;
return;
}
else
return false;
}
// if we get to this point, we should insert the respawninfo (there either was no prior entry, or it was deleted already)
@@ -3226,6 +3216,7 @@ void Map::AddRespawnInfo(RespawnInfo& info, bool replace)
ri->handle = _respawnTimes.push(ri);
bool success = bySpawnIdMap.emplace(ri->spawnId, ri).second;
ASSERT(success, "Insertion of respawn info with id (%u,%u) into spawn id map failed - state desync.", uint32(ri->type), ri->spawnId);
return true;
}
static void PushRespawnInfoFrom(std::vector<RespawnInfo*>& data, RespawnInfoMap const& map)
@@ -3252,7 +3243,7 @@ RespawnInfo* Map::GetRespawnInfo(SpawnObjectType type, ObjectGuid::LowType spawn
return it->second;
}
void Map::DeleteRespawnInfo() // delete everything
void Map::UnloadAllRespawnInfos() // delete everything from memory
{
for (RespawnInfo* info : _respawnTimes)
delete info;
@@ -3261,7 +3252,7 @@ void Map::DeleteRespawnInfo() // delete everything
_gameObjectRespawnTimesBySpawnId.clear();
}
void Map::DeleteRespawnInfo(RespawnInfo* info)
void Map::DeleteRespawnInfo(RespawnInfo* info, SQLTransaction dbTrans)
{
// Delete from all relevant containers to ensure consistency
ASSERT(info);
@@ -3270,48 +3261,21 @@ void Map::DeleteRespawnInfo(RespawnInfo* info)
size_t const n = GetRespawnMapForType(info->type).erase(info->spawnId);
ASSERT(n == 1, "Respawn stores inconsistent for map %u, spawnid %u (type %u)", GetId(), info->spawnId, uint32(info->type));
//respawn heap
// respawn heap
_respawnTimes.erase(info->handle);
// database
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESPAWN);
stmt->setUInt16(0, info->type);
stmt->setUInt32(1, info->spawnId);
stmt->setUInt16(2, GetId());
stmt->setUInt32(3, GetInstanceId());
CharacterDatabase.ExecuteOrAppend(dbTrans, stmt);
// then cleanup the object
delete info;
}
void Map::RemoveRespawnTime(RespawnInfo* info, bool doRespawn, SQLTransaction dbTrans)
{
PreparedStatement* stmt;
switch (info->type)
{
case SPAWN_TYPE_CREATURE:
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CREATURE_RESPAWN);
break;
case SPAWN_TYPE_GAMEOBJECT:
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GO_RESPAWN);
break;
default:
ASSERT(false, "Invalid respawninfo type %u for spawnid %u map %u", uint32(info->type), info->spawnId, GetId());
return;
}
stmt->setUInt32(0, info->spawnId);
stmt->setUInt16(1, GetId());
stmt->setUInt32(2, GetInstanceId());
CharacterDatabase.ExecuteOrAppend(dbTrans, stmt);
if (doRespawn)
Respawn(info);
else
DeleteRespawnInfo(info);
}
void Map::RemoveRespawnTime(std::vector<RespawnInfo*>& respawnData, bool doRespawn, SQLTransaction dbTrans)
{
SQLTransaction trans = dbTrans ? dbTrans : CharacterDatabase.BeginTransaction();
for (RespawnInfo* info : respawnData)
RemoveRespawnTime(info, doRespawn, trans);
if (!dbTrans)
CharacterDatabase.CommitTransaction(trans);
}
void Map::ProcessRespawns()
{
time_t now = time(nullptr);
@@ -3338,6 +3302,7 @@ void Map::ProcessRespawns()
{
ASSERT(now < next->respawnTime); // infinite loop guard
_respawnTimes.decrease(next->handle);
SaveRespawnInfoDB(*next);
}
}
}
@@ -3418,7 +3383,7 @@ bool Map::SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn, bool force, std::v
continue;
// we need to remove the respawn time, otherwise we'd end up double spawning
RemoveRespawnTime(data->type, data->spawnId, false);
RemoveRespawnTime(data->type, data->spawnId);
}
// don't spawn if the grid isn't loaded (will be handled in grid loader)
@@ -4436,12 +4401,15 @@ void Map::UpdateIteratorBack(Player* player)
m_mapRefIter = m_mapRefIter->nocheck_prev();
}
void Map::SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, bool writeDB, bool replace, SQLTransaction dbTrans)
void Map::SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, SQLTransaction dbTrans, bool startup)
{
if (!spawnId)
return;
if (!respawnTime)
{
// Delete only
RemoveRespawnTime(type, spawnId, false, dbTrans);
RemoveRespawnTime(type, spawnId, dbTrans);
return;
}
@@ -4451,26 +4419,31 @@ void Map::SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uin
ri.entry = entry;
ri.respawnTime = respawnTime;
ri.gridId = gridId;
AddRespawnInfo(ri, replace);
bool success = AddRespawnInfo(ri);
if (writeDB)
SaveRespawnTimeDB(type, spawnId, ri.respawnTime, dbTrans); // might be different from original respawn time if we didn't replace
if (startup)
{
if (!success)
TC_LOG_ERROR("maps", "Attempt to load saved respawn %" PRIu64 " for (%u,%u) failed - duplicate respawn? Skipped.", respawnTime, uint32(type), spawnId);
}
else if (success)
SaveRespawnInfoDB(ri, dbTrans);
}
void Map::SaveRespawnTimeDB(SpawnObjectType type, ObjectGuid::LowType spawnId, time_t respawnTime, SQLTransaction dbTrans)
void Map::SaveRespawnInfoDB(RespawnInfo const& info, SQLTransaction dbTrans)
{
// Just here for support of compatibility mode
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement((type == SPAWN_TYPE_GAMEOBJECT) ? CHAR_REP_GO_RESPAWN : CHAR_REP_CREATURE_RESPAWN);
stmt->setUInt32(0, spawnId);
stmt->setUInt64(1, uint64(respawnTime));
stmt->setUInt16(2, GetId());
stmt->setUInt32(3, GetInstanceId());
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_RESPAWN);
stmt->setUInt16(0, info.type);
stmt->setUInt32(1, info.spawnId);
stmt->setUInt64(2, uint64(info.respawnTime));
stmt->setUInt16(3, GetId());
stmt->setUInt32(4, GetInstanceId());
CharacterDatabase.ExecuteOrAppend(dbTrans, stmt);
}
void Map::LoadRespawnTimes()
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CREATURE_RESPAWNS);
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_RESPAWNS);
stmt->setUInt16(0, GetId());
stmt->setUInt32(1, GetInstanceId());
if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
@@ -4478,41 +4451,29 @@ void Map::LoadRespawnTimes()
do
{
Field* fields = result->Fetch();
ObjectGuid::LowType loguid = fields[0].GetUInt32();
uint64 respawnTime = fields[1].GetUInt64();
SpawnObjectType type = SpawnObjectType(fields[0].GetUInt16());
ObjectGuid::LowType spawnId = fields[1].GetUInt32();
uint64 respawnTime = fields[2].GetUInt64();
if (CreatureData const* cdata = sObjectMgr->GetCreatureData(loguid))
SaveRespawnTime(SPAWN_TYPE_CREATURE, loguid, cdata->id, time_t(respawnTime), Trinity::ComputeGridCoord(cdata->spawnPoint.GetPositionX(), cdata->spawnPoint.GetPositionY()).GetId(), false);
} while (result->NextRow());
}
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GO_RESPAWNS);
stmt->setUInt16(0, GetId());
stmt->setUInt32(1, GetInstanceId());
if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
{
do
{
Field* fields = result->Fetch();
ObjectGuid::LowType loguid = fields[0].GetUInt32();
uint64 respawnTime = fields[1].GetUInt64();
if (GameObjectData const* godata = sObjectMgr->GetGameObjectData(loguid))
SaveRespawnTime(SPAWN_TYPE_GAMEOBJECT, loguid, godata->id, time_t(respawnTime), GetZoneId(PhasingHandler::GetEmptyPhaseShift(), godata->spawnPoint), Trinity::ComputeGridCoord(godata->spawnPoint.GetPositionX(), godata->spawnPoint.GetPositionY()).GetId(), false);
if (type < SPAWN_TYPE_MAX)
{
if (SpawnData const* data = sObjectMgr->GetSpawnData(type, spawnId))
SaveRespawnTime(type, spawnId, data->id, time_t(respawnTime), Trinity::ComputeGridCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()).GetId(), nullptr, true);
else
TC_LOG_ERROR("maps", "Loading saved respawn time of %" PRIu64 " for spawnid (%u,%u) - spawn does not exist, ignoring", respawnTime, uint32(type), spawnId);
}
else
{
TC_LOG_ERROR("maps", "Loading saved respawn time of %" PRIu64 " for spawnid (%u,%u) - invalid spawn type, ignoring", respawnTime, uint32(type), spawnId);
}
} while (result->NextRow());
}
}
void Map::DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId)
/*static*/ void Map::DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId)
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CREATURE_RESPAWN_BY_INSTANCE);
stmt->setUInt16(0, mapId);
stmt->setUInt32(1, instanceId);
CharacterDatabase.Execute(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GO_RESPAWN_BY_INSTANCE);
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_RESPAWNS);
stmt->setUInt16(0, mapId);
stmt->setUInt32(1, instanceId);
CharacterDatabase.Execute(stmt);
+55 -50
View File
@@ -526,7 +526,18 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
GameObject* GetGameObject(ObjectGuid const& guid);
Creature* GetCreatureBySpawnId(ObjectGuid::LowType spawnId) const;
GameObject* GetGameObjectBySpawnId(ObjectGuid::LowType spawnId) const;
WorldObject* GetWorldObjectBySpawnId(SpawnObjectType type, ObjectGuid::LowType spawnId) const { return (type == SPAWN_TYPE_GAMEOBJECT) ? reinterpret_cast<WorldObject*>(GetGameObjectBySpawnId(spawnId)) : reinterpret_cast<WorldObject*>(GetCreatureBySpawnId(spawnId)); }
WorldObject* GetWorldObjectBySpawnId(SpawnObjectType type, ObjectGuid::LowType spawnId) const
{
switch (type)
{
case SPAWN_TYPE_CREATURE:
return reinterpret_cast<WorldObject*>(GetCreatureBySpawnId(spawnId));
case SPAWN_TYPE_GAMEOBJECT:
return reinterpret_cast<WorldObject*>(GetGameObjectBySpawnId(spawnId));
default:
return nullptr;
}
}
Pet* GetPet(ObjectGuid const& guid);
Transport* GetTransport(ObjectGuid const& guid);
MapTransport* GetMapTransport(ObjectGuid const& guid);
@@ -590,26 +601,21 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
RESPAWN TIMES
*/
time_t GetLinkedRespawnTime(ObjectGuid guid) const;
time_t GetCreatureRespawnTime(ObjectGuid::LowType dbGuid) const
time_t GetRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId) const
{
RespawnInfoMap::const_iterator itr = _creatureRespawnTimesBySpawnId.find(dbGuid);
return itr != _creatureRespawnTimesBySpawnId.end() ? itr->second->respawnTime : 0;
auto const& map = GetRespawnMapForType(type);
auto it = map.find(spawnId);
return (it == map.end()) ? 0 : it->second->respawnTime;
}
time_t GetGORespawnTime(ObjectGuid::LowType dbGuid) const
{
RespawnInfoMap::const_iterator itr = _gameObjectRespawnTimesBySpawnId.find(dbGuid);
return itr != _gameObjectRespawnTimesBySpawnId.end() ? itr->second->respawnTime : 0;
}
time_t GetRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId) const { return (type == SPAWN_TYPE_GAMEOBJECT) ? GetGORespawnTime(spawnId) : GetCreatureRespawnTime(spawnId); }
time_t GetCreatureRespawnTime(ObjectGuid::LowType spawnId) const { return GetRespawnTime(SPAWN_TYPE_CREATURE, spawnId); }
time_t GetGORespawnTime(ObjectGuid::LowType spawnId) const { return GetRespawnTime(SPAWN_TYPE_GAMEOBJECT, spawnId); }
void UpdatePlayerZoneStats(uint32 oldZone, uint32 newZone);
void SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId = 0, bool writeDB = true, bool replace = false, SQLTransaction dbTrans = nullptr);
void SaveRespawnTimeDB(SpawnObjectType type, ObjectGuid::LowType spawnId, time_t respawnTime, SQLTransaction dbTrans = nullptr);
void SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, SQLTransaction dbTrans = nullptr, bool startup = false);
void SaveRespawnInfoDB(RespawnInfo const& info, SQLTransaction dbTrans = nullptr);
void LoadRespawnTimes();
void DeleteRespawnTimes() { DeleteRespawnInfo(); DeleteRespawnTimesInDB(GetId(), GetInstanceId()); }
void DeleteRespawnTimes() { UnloadAllRespawnInfos(); DeleteRespawnTimesInDB(GetId(), GetInstanceId()); }
void LoadCorpseData();
void DeleteCorpseData();
@@ -789,45 +795,22 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
bool CheckRespawn(RespawnInfo* info);
void DoRespawn(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 gridId);
void Respawn(RespawnInfo* info, SQLTransaction dbTrans = nullptr);
void Respawn(std::vector<RespawnInfo*>& respawnData, SQLTransaction dbTrans = nullptr);
void AddRespawnInfo(RespawnInfo& info, bool replace = false);
void DeleteRespawnInfo();
void DeleteRespawnInfo(RespawnInfo* info);
void DeleteRespawnInfo(std::vector<RespawnInfo*>& toDelete)
{
for (RespawnInfo* info : toDelete)
DeleteRespawnInfo(info);
toDelete.clear();
}
void DeleteRespawnInfo(SpawnObjectTypeMask types)
{
std::vector<RespawnInfo*> v;
GetRespawnInfo(v, types);
if (!v.empty())
DeleteRespawnInfo(v);
}
void DeleteRespawnInfo(SpawnObjectType type, ObjectGuid::LowType spawnId)
{
if (RespawnInfo* info = GetRespawnInfo(type, spawnId))
DeleteRespawnInfo(info);
}
bool AddRespawnInfo(RespawnInfo const& info);
void UnloadAllRespawnInfos();
void DeleteRespawnInfo(RespawnInfo* info, SQLTransaction dbTrans = nullptr);
public:
void GetRespawnInfo(std::vector<RespawnInfo*>& respawnData, SpawnObjectTypeMask types) const;
RespawnInfo* GetRespawnInfo(SpawnObjectType type, ObjectGuid::LowType spawnId) const;
void RemoveRespawnTime(RespawnInfo* info, bool doRespawn = false, SQLTransaction dbTrans = nullptr);
void RemoveRespawnTime(std::vector<RespawnInfo*>& respawnData, bool doRespawn = false, SQLTransaction dbTrans = nullptr);
void RemoveRespawnTime(SpawnObjectTypeMask types = SPAWN_TYPEMASK_ALL, bool doRespawn = false, SQLTransaction dbTrans = nullptr)
{
std::vector<RespawnInfo*> v;
GetRespawnInfo(v, types);
if (!v.empty())
RemoveRespawnTime(v, doRespawn, dbTrans);
}
void RemoveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, bool doRespawn = false, SQLTransaction dbTrans = nullptr)
void Respawn(SpawnObjectType type, ObjectGuid::LowType spawnId, SQLTransaction dbTrans = nullptr)
{
if (RespawnInfo* info = GetRespawnInfo(type, spawnId))
RemoveRespawnTime(info, doRespawn, dbTrans);
Respawn(info, dbTrans);
}
void RemoveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId,SQLTransaction dbTrans = nullptr)
{
if (RespawnInfo* info = GetRespawnInfo(type, spawnId))
DeleteRespawnInfo(info, dbTrans);
}
SpawnGroupTemplateData const* GetSpawnGroupData(uint32 groupId) const;
@@ -878,8 +861,30 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
RespawnListContainer _respawnTimes;
RespawnInfoMap _creatureRespawnTimesBySpawnId;
RespawnInfoMap _gameObjectRespawnTimesBySpawnId;
RespawnInfoMap& GetRespawnMapForType(SpawnObjectType type) { return (type == SPAWN_TYPE_GAMEOBJECT) ? _gameObjectRespawnTimesBySpawnId : _creatureRespawnTimesBySpawnId; }
RespawnInfoMap const& GetRespawnMapForType(SpawnObjectType type) const { return (type == SPAWN_TYPE_GAMEOBJECT) ? _gameObjectRespawnTimesBySpawnId : _creatureRespawnTimesBySpawnId; }
RespawnInfoMap& GetRespawnMapForType(SpawnObjectType type)
{
switch (type)
{
default:
ASSERT(false);
case SPAWN_TYPE_CREATURE:
return _creatureRespawnTimesBySpawnId;
case SPAWN_TYPE_GAMEOBJECT:
return _gameObjectRespawnTimesBySpawnId;
}
}
RespawnInfoMap const& GetRespawnMapForType(SpawnObjectType type) const
{
switch (type)
{
default:
ASSERT(false);
case SPAWN_TYPE_CREATURE:
return _creatureRespawnTimesBySpawnId;
case SPAWN_TYPE_GAMEOBJECT:
return _gameObjectRespawnTimesBySpawnId;
}
}
void SetSpawnGroupActive(uint32 groupId, bool state);
std::unordered_set<uint32> _toggledSpawnGroupIds;
+1 -1
View File
@@ -1686,7 +1686,7 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Instance Template...");
sObjectMgr->LoadInstanceTemplate();
// Must be called before `creature_respawn`/`gameobject_respawn` tables
// Must be called before `respawn` data
TC_LOG_INFO("server.loading", "Loading instances...");
sInstanceSaveMgr->LoadInstances();
@@ -27,6 +27,7 @@ EndScriptData */
#include "DatabaseEnv.h"
#include "DBCStores.h"
#include "GameEventMgr.h"
#include "GameObject.h"
#include "Language.h"
#include "Log.h"
#include "MapManager.h"
+1 -1
View File
@@ -1918,7 +1918,7 @@ public:
uint32 const gridId = Trinity::ComputeGridCoord(player->GetPositionX(), player->GetPositionY()).GetId();
for (RespawnInfo* info : data)
if (info->gridId == gridId)
player->GetMap()->RemoveRespawnTime(info, true);
player->GetMap()->Respawn(info->type, info->spawnId);
}
return true;
@@ -341,8 +341,8 @@ public:
me->SetReactState(REACT_PASSIVE);
// @todo these guys should really be moved to a summon group - this is merely a hack to make them work in dynamic_spawning
instance->instance->RemoveRespawnTime(SPAWN_TYPE_CREATURE, 130958, true); // Stalagg
instance->instance->RemoveRespawnTime(SPAWN_TYPE_CREATURE, 130959, true); // Feugen
instance->instance->Respawn(SPAWN_TYPE_CREATURE, 130958); // Stalagg
instance->instance->Respawn(SPAWN_TYPE_CREATURE, 130959); // Feugen
}
void UpdateAI(uint32 diff) override