aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp25
-rw-r--r--src/server/game/Grids/ObjectGridLoader.cpp8
-rw-r--r--src/server/game/Instances/InstanceScript.cpp2
-rw-r--r--src/server/game/Maps/Map.cpp32
-rw-r--r--src/server/game/Maps/Map.h15
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp38
-rw-r--r--src/server/game/Scripting/ScriptMgr.h4
7 files changed, 44 insertions, 80 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 9dfff1fad98..3c98d58eba2 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -698,11 +698,16 @@ void Creature::Update(uint32 diff)
break;
case DEAD:
{
+ if (!m_respawnCompatibilityMode)
+ {
+ TC_LOG_ERROR("entities.unit", "Creature (GUID: " UI64FMTD " 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
@@ -1749,7 +1754,7 @@ bool Creature::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap,
CreatureData const* data = sObjectMgr->GetCreatureData(spawnId);
if (!data)
{
- TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") not found in table `creature`, can't load. ", spawnId);
+ TC_LOG_ERROR("sql.sql", "Creature (SpawnID " UI64FMTD ") not found in table `creature`, can't load. ", spawnId);
return false;
}
@@ -1760,13 +1765,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::Creature>(), map, data->id, data->spawnPoint, data, 0U , !m_respawnCompatibilityMode))
return false;
@@ -1778,8 +1776,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 " UI64FMTD ") 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
{
diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp
index aafe9b65d58..39f3bf9dc47 100644
--- a/src/server/game/Grids/ObjectGridLoader.cpp
+++ b/src/server/game/Grids/ObjectGridLoader.cpp
@@ -145,14 +145,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(PhasingHandler::GetEmptyPhaseShift(), cdata->spawnPoint), Trinity::ComputeGridCoord(cdata->spawnPoint.GetPositionX(), cdata->spawnPoint.GetPositionY()).GetId(), false);
- delete obj;
- continue;
- }
}
else if (obj->GetTypeId() == TYPEID_GAMEOBJECT)
{
diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp
index 32317dff54a..0df55ede4ab 100644
--- a/src/server/game/Instances/InstanceScript.cpp
+++ b/src/server/game/Instances/InstanceScript.cpp
@@ -271,7 +271,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);
}
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 856b5a4185c..8c1d6aae417 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -3062,10 +3062,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 " UI64FMTD " 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)
{
@@ -3075,11 +3089,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)
@@ -3143,15 +3153,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;
}
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index fbd2478adb7..419073adf19 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -760,10 +760,19 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
}
SpawnGroupTemplateData const* GetSpawnGroupData(uint32 groupId) const;
+
+ 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);
- void SetSpawnGroupActive(uint32 groupId, bool state);
- bool IsSpawnGroupActive(uint32 groupId) const;
+
+ // 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
@@ -799,6 +808,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;
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index de42459a367..8df91f40ff5 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -1599,44 +1599,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 = nullptr;
- DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(map->GetDifficultyID());
- while (!actTemplate && difficultyEntry)
- {
- int32 idx = CreatureTemplate::DifficultyIDToDifficultyEntryIndex(difficultyEntry->ID);
- if (idx == -1)
- break;
-
- if (baseTemplate->DifficultyEntry[idx])
- {
- actTemplate = sObjectMgr->GetCreatureTemplate(baseTemplate->DifficultyEntry[idx]);
- break;
- }
-
- if (!difficultyEntry->FallbackDifficultyID)
- break;
-
- difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID);
- }
-
- if (!actTemplate)
- actTemplate = baseTemplate;
-
- 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);
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index cf02fcad7a8..bd3e383572c 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -420,9 +420,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;
};
@@ -989,7 +986,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 */