mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Core/Spawning: Actually check spawn group state before processing a respawn. It feels like that is something that should've been noticed at some point.
Also remove CreatureScript::CanSpawn since nobody uses it, and spawn groups do the same thing.
This commit is contained in:
@@ -644,12 +644,16 @@ void Creature::Update(uint32 diff)
|
||||
break;
|
||||
case DEAD:
|
||||
{
|
||||
if (!m_respawnCompatibilityMode)
|
||||
{
|
||||
TC_LOG_ERROR("entities.unit", "Creature (GUID: %u Entry: %u) in wrong state: DEAD (3)", GetGUID().GetCounter(), GetEntry());
|
||||
break;
|
||||
}
|
||||
time_t now = GameTime::GetGameTime();
|
||||
if (m_respawnTime <= now)
|
||||
{
|
||||
|
||||
// First check if there are any scripts that object to us respawning
|
||||
if (!sScriptMgr->CanSpawn(GetSpawnId(), GetEntry(), GetCreatureData(), GetMap()))
|
||||
// Delay respawn if spawn group is not active
|
||||
if (m_creatureData && !GetMap()->IsSpawnGroupActive(m_creatureData->spawnGroupData->groupId))
|
||||
{
|
||||
m_respawnTime = now + urand(4,7);
|
||||
break; // Will be rechecked on next Update call after delay expires
|
||||
@@ -1608,7 +1612,7 @@ bool Creature::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap,
|
||||
|
||||
if (!data)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) not found in table `creature`, can't load. ", spawnId);
|
||||
TC_LOG_ERROR("sql.sql", "Creature (SpawnID %u) not found in table `creature`, can't load. ", spawnId);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1619,13 +1623,6 @@ bool Creature::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap,
|
||||
m_respawnradius = data->spawndist;
|
||||
m_respawnDelay = data->spawntimesecs;
|
||||
|
||||
// Is the creature script objecting to us spawning? If yes, delay by a little bit (then re-check in ::Update)
|
||||
if (!m_respawnCompatibilityMode && !m_respawnTime && !sScriptMgr->CanSpawn(spawnId, data->id, data, map))
|
||||
{
|
||||
SaveRespawnTime(urand(4,7));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Create(map->GenerateLowGuid<HighGuid::Unit>(), map, data->phaseMask, data->id, data->spawnPoint, data, 0U , !m_respawnCompatibilityMode))
|
||||
return false;
|
||||
|
||||
@@ -1637,8 +1634,11 @@ bool Creature::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap,
|
||||
m_respawnTime = GetMap()->GetCreatureRespawnTime(m_spawnId);
|
||||
|
||||
// Is the creature script objecting to us spawning? If yes, delay by a little bit (then re-check in ::Update)
|
||||
if (m_respawnCompatibilityMode && !m_respawnTime && !sScriptMgr->CanSpawn(spawnId, GetEntry(), GetCreatureData(), map))
|
||||
m_respawnTime = GameTime::GetGameTime() + urand(4,7);
|
||||
if (!m_respawnTime && !map->IsSpawnGroupActive(data->spawnGroupData->groupId))
|
||||
{
|
||||
ASSERT(m_respawnCompatibilityMode, "Creature (SpawnID %u) trying to load in inactive spawn group %s.", spawnId, data->spawnGroupData->name.c_str());
|
||||
m_respawnTime = GameTime::GetGameTime() + urand(4, 7);
|
||||
}
|
||||
|
||||
if (m_respawnTime) // respawn on Update
|
||||
{
|
||||
|
||||
@@ -140,14 +140,6 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord &cell, GridRefManager<T>
|
||||
delete obj;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If script is blocking spawn, don't spawn but queue for a re-check in a little bit
|
||||
if (!(group->flags & SPAWNGROUP_FLAG_COMPATIBILITY_MODE) && !sScriptMgr->CanSpawn(guid, cdata->id, cdata, map))
|
||||
{
|
||||
map->SaveRespawnTime(SPAWN_TYPE_CREATURE, guid, cdata->id, GameTime::GetGameTime() + urand(4,7), map->GetZoneId(cdata->spawnPoint), Trinity::ComputeGridCoord(cdata->spawnPoint.GetPositionX(), cdata->spawnPoint.GetPositionY()).GetId(), false);
|
||||
delete obj;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (obj->GetTypeId() == TYPEID_GAMEOBJECT)
|
||||
{
|
||||
|
||||
@@ -265,7 +265,7 @@ void InstanceScript::UpdateSpawnGroups()
|
||||
if (doSpawn)
|
||||
instance->SpawnGroupSpawn(groupId);
|
||||
else // otherwise, set it as inactive so it no longer respawns (but don't despawn it)
|
||||
instance->SetSpawnGroupActive(groupId, false);
|
||||
instance->SetSpawnGroupInactive(groupId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2924,10 +2924,24 @@ void Map::SendObjectUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
// CheckRespawn MUST do one of the following:
|
||||
// -) return true
|
||||
// -) set info->respawnTime to zero, which indicates the respawn time should be deleted (and will never be processed again without outside intervention)
|
||||
// -) set info->respawnTime to a new respawn time, which must be strictly GREATER than the current time (GameTime::GetGameTime())
|
||||
bool Map::CheckRespawn(RespawnInfo* info)
|
||||
{
|
||||
SpawnData const* data = sObjectMgr->GetSpawnData(info->type, info->spawnId);
|
||||
ASSERT(data, "Invalid respawn info with type %u, spawnID %u in respawn queue.", info->type, info->spawnId);
|
||||
|
||||
// First, check if this creature's spawn group is inactive
|
||||
if (!IsSpawnGroupActive(data->spawnGroupData->groupId))
|
||||
{
|
||||
info->respawnTime = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 poolId = info->spawnId ? sPoolMgr->IsPartOfAPool(info->type, info->spawnId) : 0;
|
||||
// First, check if there's already an instance of this object that would block the respawn
|
||||
// Next, check if there's already an instance of this object that would block the respawn
|
||||
// Only do this for unpooled spawns
|
||||
if (!poolId)
|
||||
{
|
||||
@@ -2937,11 +2951,7 @@ bool Map::CheckRespawn(RespawnInfo* info)
|
||||
case SPAWN_TYPE_CREATURE:
|
||||
{
|
||||
// escort check for creatures only (if the world config boolean is set)
|
||||
bool isEscort = false;
|
||||
if (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && info->type == SPAWN_TYPE_CREATURE)
|
||||
if (CreatureData const* cdata = sObjectMgr->GetCreatureData(info->spawnId))
|
||||
if (cdata->spawnGroupData->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC)
|
||||
isEscort = true;
|
||||
bool const isEscort = (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && data->spawnGroupData->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC);
|
||||
|
||||
auto range = _creatureBySpawnIdStore.equal_range(info->spawnId);
|
||||
for (auto it = range.first; it != range.second; ++it)
|
||||
@@ -3003,15 +3013,7 @@ bool Map::CheckRespawn(RespawnInfo* info)
|
||||
return false;
|
||||
}
|
||||
|
||||
// if we're a creature, see if the script objects to us spawning
|
||||
if (info->type == SPAWN_TYPE_CREATURE)
|
||||
{
|
||||
if (!sScriptMgr->CanSpawn(info->spawnId, info->entry, sObjectMgr->GetCreatureData(info->spawnId), this))
|
||||
{ // if a script blocks our respawn, schedule next check in a little bit
|
||||
info->respawnTime = GameTime::GetGameTime() + urand(4, 7);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// everything ok, let's spawn
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -838,11 +838,20 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
}
|
||||
|
||||
SpawnGroupTemplateData const* GetSpawnGroupData(uint32 groupId) const;
|
||||
bool SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn = false, bool force = false, std::vector<WorldObject*>* spawnedObjects = nullptr);
|
||||
bool SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes = false, size_t* count = nullptr);
|
||||
void SetSpawnGroupActive(uint32 groupId, bool state);
|
||||
|
||||
bool IsSpawnGroupActive(uint32 groupId) const;
|
||||
|
||||
// Enable the spawn group, which causes all creatures in it to respawn (unless they have a respawn timer)
|
||||
// The force flag can be used to force spawning additional copies even if old copies are still around from a previous spawn
|
||||
bool SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn = false, bool force = false, std::vector<WorldObject*>* spawnedObjects = nullptr);
|
||||
|
||||
// Despawn all creatures in the spawn group if spawned, optionally delete their respawn timer, and disable the group
|
||||
bool SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes = false, size_t* count = nullptr);
|
||||
|
||||
// Disable the spawn group, which prevents any creatures in the group from respawning until re-enabled
|
||||
// This will not affect any already-present creatures in the group
|
||||
void SetSpawnGroupInactive(uint32 groupId) { SetSpawnGroupActive(groupId, false); }
|
||||
|
||||
private:
|
||||
// Type specific code for add/remove to/from grid
|
||||
template<class T>
|
||||
@@ -877,6 +886,8 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
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; }
|
||||
|
||||
void SetSpawnGroupActive(uint32 groupId, bool state);
|
||||
std::unordered_set<uint32> _toggledSpawnGroupIds;
|
||||
|
||||
uint32 _respawnCheckTimer;
|
||||
|
||||
@@ -1565,36 +1565,6 @@ bool ScriptMgr::OnCastItemCombatSpell(Player* player, Unit* victim, SpellInfo co
|
||||
return tmpscript->OnCastItemCombatSpell(player, victim, spellInfo, item);
|
||||
}
|
||||
|
||||
bool ScriptMgr::CanSpawn(ObjectGuid::LowType spawnId, uint32 entry, CreatureData const* cData, Map const* map)
|
||||
{
|
||||
ASSERT(map);
|
||||
CreatureTemplate const* baseTemplate = sObjectMgr->GetCreatureTemplate(entry);
|
||||
ASSERT(baseTemplate);
|
||||
|
||||
// find out which template we'd be using
|
||||
CreatureTemplate const* actTemplate = baseTemplate;
|
||||
for (uint8 diff = uint8(map->GetSpawnMode()); diff > 0;)
|
||||
{
|
||||
if (uint32 diffEntry = baseTemplate->DifficultyEntry[diff - 1])
|
||||
if (CreatureTemplate const* diffTemplate = sObjectMgr->GetCreatureTemplate(diffEntry))
|
||||
{
|
||||
actTemplate = diffTemplate;
|
||||
break;
|
||||
}
|
||||
if (diff >= RAID_DIFFICULTY_10MAN_HEROIC && map->IsRaid())
|
||||
diff -= 2;
|
||||
else
|
||||
diff -= 1;
|
||||
}
|
||||
|
||||
uint32 scriptId = baseTemplate->ScriptID;
|
||||
if (cData && cData->scriptId)
|
||||
scriptId = cData->scriptId;
|
||||
|
||||
GET_SCRIPT_RET(CreatureScript, scriptId, tmpscript, true);
|
||||
return tmpscript->CanSpawn(spawnId, entry, baseTemplate, actTemplate, cData, map);
|
||||
}
|
||||
|
||||
CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature)
|
||||
{
|
||||
ASSERT(creature);
|
||||
|
||||
@@ -417,9 +417,6 @@ class TC_GAME_API CreatureScript : public UnitScript
|
||||
|
||||
public:
|
||||
|
||||
// Called when the creature tries to spawn. Return false to block spawn and re-evaluate on next tick.
|
||||
virtual bool CanSpawn(ObjectGuid::LowType /*spawnId*/, uint32 /*entry*/, CreatureTemplate const* /*baseTemplate*/, CreatureTemplate const* /*actTemplate*/, CreatureData const* /*cData*/, Map const* /*map*/) const { return true; }
|
||||
|
||||
// Called when a CreatureAI object is needed for the creature.
|
||||
virtual CreatureAI* GetAI(Creature* /*creature*/) const = 0;
|
||||
};
|
||||
@@ -920,7 +917,6 @@ class TC_GAME_API ScriptMgr
|
||||
|
||||
public: /* CreatureScript */
|
||||
|
||||
bool CanSpawn(ObjectGuid::LowType spawnId, uint32 entry, CreatureData const* cData, Map const* map);
|
||||
CreatureAI* GetCreatureAI(Creature* creature);
|
||||
|
||||
public: /* GameObjectScript */
|
||||
|
||||
Reference in New Issue
Block a user