Core/Spawn: Move spawn group state management from sObjectMgr to the Map object, which makes it actually function as intended with instances.
Port From (https://github.com/TrinityCore/TrinityCore/commit/27806eeac9d2588d2f7a3b8a0852d45b15a6a241)
This commit is contained in:
@@ -243,13 +243,13 @@ namespace Game.Maps
|
||||
{
|
||||
uint groupId = pair.Key;
|
||||
bool doSpawn = pair.Value == states.Spawn;
|
||||
if (Global.ObjectMgr.IsSpawnGroupActive(groupId) == doSpawn)
|
||||
if (instance.IsSpawnGroupActive(groupId) == doSpawn)
|
||||
continue; // nothing to do here
|
||||
// if we should spawn group, then spawn it...
|
||||
if (doSpawn)
|
||||
Global.ObjectMgr.SpawnGroupSpawn(groupId, instance);
|
||||
instance.SpawnGroupSpawn(groupId, instance);
|
||||
else // otherwise, set it as inactive so it no longer respawns (but don't despawn it)
|
||||
Global.ObjectMgr.SetSpawnGroupActive(groupId, false);
|
||||
instance.SetSpawnGroupActive(groupId, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ namespace Game.Maps
|
||||
if (bossInfo.state == EncounterState.ToBeDecided) // loading
|
||||
{
|
||||
bossInfo.state = state;
|
||||
Log.outDebug(LogFilter.Scripts, $"InstanceScript: Inialize boss {id} state as {state}.");
|
||||
Log.outDebug(LogFilter.Scripts, $"InstanceScript: Initialize boss {id} state as {state} (map {instance.GetId()}, {instance.GetInstanceId()}).");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -339,6 +339,12 @@ namespace Game.Maps
|
||||
if (bossInfo.state == state)
|
||||
return false;
|
||||
|
||||
if (bossInfo.state == EncounterState.Done)
|
||||
{
|
||||
Log.outError(LogFilter.Maps, $"InstanceScript: Tried to set instance state from {bossInfo.state} back to {state} for map {instance.GetId()}, instance id {instance.GetInstanceId()}. Blocked!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state == EncounterState.Done)
|
||||
{
|
||||
foreach (var guid in bossInfo.minion)
|
||||
|
||||
@@ -2788,6 +2788,153 @@ namespace Game.Maps
|
||||
respawnDelay = (uint)Math.Max(Math.Ceiling(respawnDelay * adjustFactor), timeMinimum);
|
||||
}
|
||||
|
||||
SpawnGroupTemplateData GetSpawnGroupData(uint groupId)
|
||||
{
|
||||
SpawnGroupTemplateData data = Global.ObjectMgr.GetSpawnGroupData(groupId);
|
||||
if (data != null && data.mapId == GetId())
|
||||
return data;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool SpawnGroupSpawn(uint groupId, bool ignoreRespawn = false, bool force = false, List<WorldObject> spawnedObjects = null)
|
||||
{
|
||||
var groupData = GetSpawnGroupData(groupId);
|
||||
if (groupData == null || groupData.flags.HasAnyFlag(SpawnGroupFlags.System))
|
||||
{
|
||||
Log.outError(LogFilter.Maps, $"Tried to spawn non-existing (or system) spawn group {groupId}. on map {GetId()} Blocked.");
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var data in Global.ObjectMgr.GetSpawnDataForGroup(groupId))
|
||||
{
|
||||
Cypher.Assert(groupData.mapId == data.spawnPoint.GetMapId());
|
||||
// Check if there's already an instance spawned
|
||||
if (!force)
|
||||
{
|
||||
WorldObject obj = GetWorldObjectBySpawnId(data.type, data.spawnId);
|
||||
if (obj != null)
|
||||
if ((data.type != SpawnObjectType.Creature) || obj.ToCreature().IsAlive())
|
||||
continue;
|
||||
}
|
||||
|
||||
long respawnTime = GetRespawnTime(data.type, data.spawnId);
|
||||
if (respawnTime != 0 && respawnTime > Time.UnixTime)
|
||||
{
|
||||
if (!force && !ignoreRespawn)
|
||||
continue;
|
||||
|
||||
// we need to remove the respawn time, otherwise we'd end up double spawning
|
||||
RemoveRespawnTime(data.type, data.spawnId, false);
|
||||
}
|
||||
|
||||
// don't spawn if the grid isn't loaded (will be handled in grid loader)
|
||||
if (!IsGridLoaded(data.spawnPoint))
|
||||
continue;
|
||||
|
||||
// Everything OK, now do the actual (re)spawn
|
||||
switch (data.type)
|
||||
{
|
||||
case SpawnObjectType.Creature:
|
||||
{
|
||||
Creature creature = new Creature();
|
||||
if (!creature.LoadFromDB(data.spawnId, this, true, force))
|
||||
creature.Dispose();
|
||||
else if (spawnedObjects != null)
|
||||
spawnedObjects.Add(creature);
|
||||
break;
|
||||
}
|
||||
case SpawnObjectType.GameObject:
|
||||
{
|
||||
GameObject gameobject = new GameObject();
|
||||
if (!gameobject.LoadFromDB(data.spawnId, this, true))
|
||||
gameobject.Dispose();
|
||||
else if (spawnedObjects != null)
|
||||
spawnedObjects.Add(gameobject);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Cypher.Assert(false, $"Invalid spawn type {data.type} with spawnId {data.spawnId}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SetSpawnGroupActive(groupId, true); // start processing respawns for the group
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SpawnGroupDespawn(uint groupId, bool deleteRespawnTimes)
|
||||
{
|
||||
SpawnGroupTemplateData groupData = GetSpawnGroupData(groupId);
|
||||
if (groupData == null || groupData.flags.HasAnyFlag(SpawnGroupFlags.System))
|
||||
{
|
||||
Log.outError(LogFilter.Maps, $"Tried to despawn non-existing (or system) spawn group {groupId} on map {GetId()}. Blocked.");
|
||||
return false;
|
||||
}
|
||||
|
||||
List<WorldObject> toUnload = new List<WorldObject>(); // unload after iterating, otherwise iterator invalidation
|
||||
foreach (var data in Global.ObjectMgr.GetSpawnDataForGroup(groupId))
|
||||
{
|
||||
if (deleteRespawnTimes)
|
||||
RemoveRespawnTime(data.type, data.spawnId);
|
||||
switch (data.type)
|
||||
{
|
||||
case SpawnObjectType.Creature:
|
||||
{
|
||||
var bounds = GetCreatureBySpawnIdStore().LookupByKey(data.spawnId);
|
||||
foreach (var creature in bounds)
|
||||
toUnload.Add(creature);
|
||||
break;
|
||||
}
|
||||
case SpawnObjectType.GameObject:
|
||||
{
|
||||
var bounds = GetGameObjectBySpawnIdStore().LookupByKey(data.spawnId);
|
||||
foreach (var go in bounds)
|
||||
toUnload.Add(go);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Cypher.Assert(false, $"Invalid spawn type {data.type} in spawn data with spawnId {data.spawnId}.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// now do the actual despawning
|
||||
foreach (WorldObject obj in toUnload)
|
||||
obj.AddObjectToRemoveList();
|
||||
|
||||
SetSpawnGroupActive(groupId, false); // stop processing respawns for the group, too
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetSpawnGroupActive(uint groupId, bool state)
|
||||
{
|
||||
SpawnGroupTemplateData data = GetSpawnGroupData(groupId);
|
||||
if (data == null || data.flags.HasAnyFlag(SpawnGroupFlags.System))
|
||||
{
|
||||
Log.outError(LogFilter.Maps, $"Tried to set non-existing (or system) spawn group {groupId} to {(state ? "active" : "inactive")} on map {GetId()}. Blocked.");
|
||||
return;
|
||||
}
|
||||
if (state != !data.flags.HasAnyFlag(SpawnGroupFlags.ManualSpawn)) // toggled
|
||||
_toggledSpawnGroupIds.Add(groupId);
|
||||
else
|
||||
_toggledSpawnGroupIds.Remove(groupId);
|
||||
}
|
||||
|
||||
public bool IsSpawnGroupActive(uint groupId)
|
||||
{
|
||||
SpawnGroupTemplateData data = GetSpawnGroupData(groupId);
|
||||
if (data == null)
|
||||
{
|
||||
Log.outWarn(LogFilter.Maps, $"Tried to query state of non-existing spawn group {groupId} on map {GetId()}.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.flags.HasAnyFlag(SpawnGroupFlags.System))
|
||||
return true;
|
||||
|
||||
return _toggledSpawnGroupIds.Contains(groupId) != !data.flags.HasAnyFlag(SpawnGroupFlags.ManualSpawn);
|
||||
}
|
||||
|
||||
public virtual void DelayedUpdate(uint diff)
|
||||
{
|
||||
for (var i = 0; i < _transports.Count; ++i)
|
||||
@@ -4863,6 +5010,7 @@ namespace Game.Maps
|
||||
SortedSet<RespawnInfo> _respawnTimes = new SortedSet<RespawnInfo>(new CompareRespawnInfo());
|
||||
Dictionary<ulong, RespawnInfo> _creatureRespawnTimesBySpawnId = new Dictionary<ulong, RespawnInfo>();
|
||||
Dictionary<ulong, RespawnInfo> _gameObjectRespawnTimesBySpawnId = new Dictionary<ulong, RespawnInfo>();
|
||||
List<uint> _toggledSpawnGroupIds = new List<uint>();
|
||||
uint _respawnCheckTimer;
|
||||
Dictionary<uint, uint> _zonePlayerCountMap = new Dictionary<uint, uint>();
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Maps
|
||||
@@ -91,13 +92,20 @@ namespace Game.Maps
|
||||
|
||||
SpawnGroupTemplateData group = cdata.spawnGroupData;
|
||||
// If creature in manual spawn group, don't spawn here, unless group is already active.
|
||||
if (group.flags.HasFlag(SpawnGroupFlags.ManualSpawn) && !group.isActive)
|
||||
continue;
|
||||
if (!group.flags.HasAnyFlag(SpawnGroupFlags.System))
|
||||
{
|
||||
if (!map.IsSpawnGroupActive(group.groupId))
|
||||
{
|
||||
obj.Dispose();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If script is blocking spawn, don't spawn but queue for a re-check in a little bit
|
||||
if (!group.flags.HasFlag(SpawnGroupFlags.CompatibilityMode) && !Global.ScriptMgr.CanSpawn(guid, cdata.Id, cdata, map))
|
||||
{
|
||||
map.SaveRespawnTime(SpawnObjectType.Creature, guid, cdata.Id, Time.UnixTime + RandomHelper.URand(4, 7), map.GetZoneId(PhasingHandler.EmptyPhaseShift, cdata.spawnPoint), GridDefines.ComputeGridCoord(cdata.spawnPoint.GetPositionX(), cdata.spawnPoint.GetPositionY()).GetId(), false);
|
||||
obj.Dispose();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -107,8 +115,14 @@ namespace Game.Maps
|
||||
GameObjectData godata = Global.ObjectMgr.GetGameObjectData(guid);
|
||||
Cypher.Assert(godata != null, $"Tried to load gameobject with spawnId {guid}, but no such object exists.");
|
||||
|
||||
if (godata.spawnGroupData.flags.HasFlag(SpawnGroupFlags.ManualSpawn) && !godata.spawnGroupData.isActive)
|
||||
continue;
|
||||
if (!godata.spawnGroupData.flags.HasAnyFlag(SpawnGroupFlags.System))
|
||||
{
|
||||
if (!map.IsSpawnGroupActive(godata.spawnGroupData.groupId))
|
||||
{
|
||||
obj.Dispose();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!obj.LoadFromDB(guid, map, false, false))
|
||||
@@ -128,15 +142,10 @@ namespace Game.Maps
|
||||
var cell = new Cell(cellCoord);
|
||||
map.AddToGrid(obj, cell);
|
||||
obj.AddToWorld();
|
||||
++count;
|
||||
}
|
||||
|
||||
void AddObjectHelper(CellCoord cellCoord, ref uint count, Map map, Creature obj)
|
||||
{
|
||||
map.AddToGrid(obj, new Cell(cellCoord));
|
||||
obj.AddToWorld();
|
||||
if (obj.IsActiveObject())
|
||||
map.AddToActive(obj);
|
||||
if (obj.IsCreature())
|
||||
if (obj.IsActiveObject())
|
||||
map.AddToActive(obj);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ namespace Game.Maps
|
||||
public string name;
|
||||
public uint mapId;
|
||||
public SpawnGroupFlags flags;
|
||||
public bool isActive;
|
||||
}
|
||||
|
||||
public class SpawnData
|
||||
|
||||
Reference in New Issue
Block a user