Core/Misc: Some refactoring

Port From (https://github.com/TrinityCore/TrinityCore/commit/94a79bac7a06aa0f931e9d651928de7eea0a8b5c)
This commit is contained in:
hondacrx
2022-01-06 20:07:26 -05:00
parent e51b775636
commit d2ba807c20
19 changed files with 585 additions and 477 deletions
+6 -2
View File
@@ -205,16 +205,20 @@ namespace Framework.Constants
{ {
Creature = 0, Creature = 0,
GameObject = 1, GameObject = 1,
AreaTrigger = 2,
Max NumSpawnTypesWithData,
NumSpawnTypes
} }
public enum SpawnObjectTypeMask public enum SpawnObjectTypeMask
{ {
Creature = (1 << SpawnObjectType.Creature), Creature = (1 << SpawnObjectType.Creature),
GameObject = (1 << SpawnObjectType.GameObject), GameObject = (1 << SpawnObjectType.GameObject),
AreaTrigger = (1 << SpawnObjectType.AreaTrigger),
All = (1 << SpawnObjectType.Max) - 1 WithData = (1 << SpawnObjectType.NumSpawnTypesWithData) - 1,
All = (1 << SpawnObjectType.NumSpawnTypes) - 1
} }
[Flags] [Flags]
-19
View File
@@ -866,25 +866,6 @@ namespace Framework.Constants
DisplayMythic = 0x80 // Controls icon displayed on minimap when inside the instance DisplayMythic = 0x80 // Controls icon displayed on minimap when inside the instance
} }
public enum SpawnMask
{
Continent = (1 << Difficulty.None), // Any Maps Without Spawn Modes
DungeonNormal = (1 << Difficulty.Normal),
DungeonHeroic = (1 << Difficulty.Heroic),
DungeonAll = (DungeonNormal | DungeonHeroic),
Raid10Normal = (1 << Difficulty.Raid10N),
Raid25Normal = (1 << Difficulty.Raid25N),
RaidNormalAll = (Raid10Normal | Raid25Normal),
Raid10Heroic = (1 << Difficulty.Raid10HC),
Raid25Heroic = (1 << Difficulty.Raid25HC),
RaidHeroicAll = (Raid10Heroic | Raid25Heroic),
RaidAll = (RaidNormalAll | RaidHeroicAll)
}
public enum MapFlags public enum MapFlags
{ {
CanToggleDifficulty = 0x0100, CanToggleDifficulty = 0x0100,
@@ -209,7 +209,7 @@ namespace Game.Chat
if (data != null) if (data != null)
{ {
data.rotation.toEulerAnglesZYX(out float yaw, out float pitch, out float roll); data.rotation.toEulerAnglesZYX(out float yaw, out float pitch, out float roll);
handler.SendSysMessage(CypherStrings.SpawninfoSpawnidLocation, data.spawnId, data.spawnPoint.GetPositionX(), data.spawnPoint.GetPositionY(), data.spawnPoint.GetPositionZ()); handler.SendSysMessage(CypherStrings.SpawninfoSpawnidLocation, data.SpawnId, data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY(), data.SpawnPoint.GetPositionZ());
handler.SendSysMessage(CypherStrings.SpawninfoRotation, yaw, pitch, roll); handler.SendSysMessage(CypherStrings.SpawninfoRotation, yaw, pitch, roll);
} }
+3 -3
View File
@@ -645,9 +645,9 @@ namespace Game.Chat.Commands
return false; return false;
} }
if (!GridDefines.IsValidMapCoord(goData.spawnPoint) || Global.ObjectMgr.IsTransportMap(goData.spawnPoint.GetMapId())) if (!GridDefines.IsValidMapCoord(goData.MapId, goData.SpawnPoint) || Global.ObjectMgr.IsTransportMap(goData.MapId))
{ {
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, goData.spawnPoint.GetPositionX(), goData.spawnPoint.GetPositionY(), goData.spawnPoint.GetMapId()); handler.SendSysMessage(CypherStrings.InvalidTargetCoord, goData.SpawnPoint.GetPositionX(), goData.SpawnPoint.GetPositionY(), goData.MapId);
return false; return false;
} }
@@ -657,7 +657,7 @@ namespace Game.Chat.Commands
else else
player.SaveRecallPosition(); // save only in non-flight case player.SaveRecallPosition(); // save only in non-flight case
player.TeleportTo(goData.spawnPoint); player.TeleportTo(new WorldLocation(goData.MapId, goData.SpawnPoint));
return true; return true;
} }
+23 -17
View File
@@ -580,31 +580,37 @@ namespace Game.Chat.Commands
uint zoneId = player.GetZoneId(); uint zoneId = player.GetZoneId();
string zoneName = GetZoneName(zoneId, locale); string zoneName = GetZoneName(zoneId, locale);
for (SpawnObjectType type = 0; type < SpawnObjectType.Max; type++) for (SpawnObjectType type = 0; type < SpawnObjectType.NumSpawnTypes; type++)
{ {
if (range != 0) if (range != 0)
handler.SendSysMessage(CypherStrings.ListRespawnsRange, type, range); handler.SendSysMessage(CypherStrings.ListRespawnsRange, type, range);
else else
handler.SendSysMessage(CypherStrings.ListRespawnsZone, type, zoneName, zoneId); handler.SendSysMessage(CypherStrings.ListRespawnsZone, type, zoneName, zoneId);
handler.SendSysMessage(CypherStrings.ListRespawnsListheader); handler.SendSysMessage(CypherStrings.ListRespawnsListheader);
List<RespawnInfo> respawns = new(); List<RespawnInfo> respawns = new();
map.GetRespawnInfo(respawns, (SpawnObjectTypeMask)(1 << (int)type)); map.GetRespawnInfo(respawns, (SpawnObjectTypeMask)(1 << (int)type));
foreach (RespawnInfo ri in respawns) foreach (RespawnInfo ri in respawns)
{ {
SpawnData data = Global.ObjectMgr.GetSpawnData(ri.type, ri.spawnId); SpawnMetadata data = Global.ObjectMgr.GetSpawnMetadata(ri.type, ri.spawnId);
if (data == null) if (data == null)
continue; continue;
uint respawnZoneId = map.GetZoneId(PhasingHandler.EmptyPhaseShift, data.spawnPoint); uint respawnZoneId = 0;
if (range != 0) SpawnData edata = data.ToSpawnData();
if (edata != null)
{ {
if (!player.IsInDist(data.spawnPoint, range)) respawnZoneId = map.GetZoneId(PhasingHandler.EmptyPhaseShift, edata.SpawnPoint);
continue; if (range != 0)
} {
else if (!player.IsInDist(edata.SpawnPoint, range))
{ continue;
if (zoneId != respawnZoneId) }
continue; else
{
if (zoneId != respawnZoneId)
continue;
}
} }
uint gridY = ri.gridId / MapConst.MaxGrids; uint gridY = ri.gridId / MapConst.MaxGrids;
@@ -652,28 +658,28 @@ namespace Game.Chat.Commands
foreach (var pair in Global.ObjectMgr.GetAllCreatureData()) foreach (var pair in Global.ObjectMgr.GetAllCreatureData())
{ {
SpawnData data = pair.Value; SpawnData data = pair.Value;
if (data.spawnPoint.GetMapId() != mapId) if (data.MapId != mapId)
continue; continue;
CreatureTemplate cTemp = Global.ObjectMgr.GetCreatureTemplate(data.Id); CreatureTemplate cTemp = Global.ObjectMgr.GetCreatureTemplate(data.Id);
if (cTemp == null) if (cTemp == null)
continue; continue;
if (showAll || data.spawnPoint.IsInDist2d(player, 5000.0f)) if (showAll || data.SpawnPoint.IsInDist2d(player, 5000.0f))
handler.SendSysMessage($"Type: {data.type} | SpawnId: {data.spawnId} | Entry: {data.Id} ({cTemp.Name}) | X: {data.spawnPoint.GetPositionX():3} | Y: {data.spawnPoint.GetPositionY():3} | Z: {data.spawnPoint.GetPositionZ():3}"); handler.SendSysMessage($"Type: {data.type} | SpawnId: {data.SpawnId} | Entry: {data.Id} ({cTemp.Name}) | X: {data.SpawnPoint.GetPositionX():3} | Y: {data.SpawnPoint.GetPositionY():3} | Z: {data.SpawnPoint.GetPositionZ():3}");
} }
foreach (var pair in Global.ObjectMgr.GetAllGameObjectData()) foreach (var pair in Global.ObjectMgr.GetAllGameObjectData())
{ {
SpawnData data = pair.Value; SpawnData data = pair.Value;
if (data.spawnPoint.GetMapId() != mapId) if (data.MapId != mapId)
continue; continue;
GameObjectTemplate goTemp = Global.ObjectMgr.GetGameObjectTemplate(data.Id); GameObjectTemplate goTemp = Global.ObjectMgr.GetGameObjectTemplate(data.Id);
if (goTemp == null) if (goTemp == null)
continue; continue;
if (showAll || data.spawnPoint.IsInDist2d(player, 5000.0f)) if (showAll || data.SpawnPoint.IsInDist2d(player, 5000.0f))
handler.SendSysMessage($"Type: {data.type} | SpawnId: {data.spawnId} | Entry: {data.Id} ({goTemp.name}) | X: {data.spawnPoint.GetPositionX():3} | Y: {data.spawnPoint.GetPositionY():3} | Z: {data.spawnPoint.GetPositionZ():3}"); handler.SendSysMessage($"Type: {data.type} | SpawnId: {data.SpawnId} | Entry: {data.Id} ({goTemp.name}) | X: {data.SpawnPoint.GetPositionX():3} | Y: {data.SpawnPoint.GetPositionY():3} | Z: {data.SpawnPoint.GetPositionZ():3}");
} }
return true; return true;
} }
+5 -5
View File
@@ -172,7 +172,7 @@ namespace Game.Chat
CreatureData data = Global.ObjectMgr.GetCreatureData(target.GetSpawnId()); CreatureData data = Global.ObjectMgr.GetCreatureData(target.GetSpawnId());
if (data != null) if (data != null)
handler.SendSysMessage(CypherStrings.NpcinfoPhases, data.phaseId, data.phaseGroup); handler.SendSysMessage(CypherStrings.NpcinfoPhases, data.PhaseId, data.PhaseGroup);
PhasingHandler.PrintToChat(handler, target.GetPhaseShift()); PhasingHandler.PrintToChat(handler, target.GetPhaseShift());
@@ -233,14 +233,14 @@ namespace Game.Chat
return false; return false;
} }
if (player.GetMapId() != data.spawnPoint.GetMapId()) if (player.GetMapId() != data.MapId)
{ {
handler.SendSysMessage(CypherStrings.CommandCreatureatsamemap, lowguid); handler.SendSysMessage(CypherStrings.CommandCreatureatsamemap, lowguid);
return false; return false;
} }
Global.ObjectMgr.RemoveCreatureFromGrid(lowguid, data); Global.ObjectMgr.RemoveCreatureFromGrid(lowguid, data);
data.spawnPoint.Relocate(player); data.SpawnPoint.Relocate(player);
Global.ObjectMgr.AddCreatureToGrid(lowguid, data); Global.ObjectMgr.AddCreatureToGrid(lowguid, data);
// update position in DB // update position in DB
@@ -659,9 +659,9 @@ namespace Game.Chat
{ {
ulong guid = map.GenerateLowGuid(HighGuid.Creature); ulong guid = map.GenerateLowGuid(HighGuid.Creature);
CreatureData data = Global.ObjectMgr.NewOrExistCreatureData(guid); CreatureData data = Global.ObjectMgr.NewOrExistCreatureData(guid);
data.spawnId = guid; data.SpawnId = guid;
data.Id = id; data.Id = id;
data.spawnPoint.Relocate(chr.GetTransOffsetX(), chr.GetTransOffsetY(), chr.GetTransOffsetZ(), chr.GetTransOffsetO()); data.SpawnPoint.Relocate(chr.GetTransOffsetX(), chr.GetTransOffsetY(), chr.GetTransOffsetZ(), chr.GetTransOffsetO());
data.spawnGroupData = new(); data.spawnGroupData = new();
Creature creaturePassenger = trans.CreateNPCPassenger(guid, data); Creature creaturePassenger = trans.CreateNPCPassenger(guid, data);
@@ -319,10 +319,11 @@ namespace Game.DataStorage
AreaTriggerSpawn spawn = new(); AreaTriggerSpawn spawn = new();
spawn.SpawnId = spawnId; spawn.SpawnId = spawnId;
spawn.Id = areaTriggerId; spawn.MapId = location.GetMapId();
spawn.Location = new WorldLocation(location); spawn.TriggerId = areaTriggerId;
spawn.SpawnPoint = new Position(location);
spawn.PhaseUseFlags = templates.Read<byte>(8); spawn.PhaseUseFlags = (PhaseUseFlagsValues)templates.Read<byte>(8);
spawn.PhaseId = templates.Read<uint>(9); spawn.PhaseId = templates.Read<uint>(9);
spawn.PhaseGroup = templates.Read<uint>(10); spawn.PhaseGroup = templates.Read<uint>(10);
@@ -334,13 +335,14 @@ namespace Game.DataStorage
} }
spawn.ScriptId = Global.ObjectMgr.GetScriptId(templates.Read<string>(18)); spawn.ScriptId = Global.ObjectMgr.GetScriptId(templates.Read<string>(18));
spawn.spawnGroupData = Global.ObjectMgr.GetLegacySpawnGroup();
// Add the trigger to a map::cell map, which is later used by GridLoader to query // Add the trigger to a map::cell map, which is later used by GridLoader to query
CellCoord cellCoord = GridDefines.ComputeCellCoord(spawn.Location.GetPositionX(), spawn.Location.GetPositionY()); CellCoord cellCoord = GridDefines.ComputeCellCoord(spawn.SpawnPoint.GetPositionX(), spawn.SpawnPoint.GetPositionY());
if (!_areaTriggerSpawnsByLocation.ContainsKey((spawn.Location.GetMapId(), cellCoord.GetId()))) if (!_areaTriggerSpawnsByLocation.ContainsKey((spawn.MapId, cellCoord.GetId())))
_areaTriggerSpawnsByLocation[(spawn.Location.GetMapId(), cellCoord.GetId())] = new SortedSet<ulong>(); _areaTriggerSpawnsByLocation[(spawn.MapId, cellCoord.GetId())] = new SortedSet<ulong>();
_areaTriggerSpawnsByLocation[(spawn.Location.GetMapId(), cellCoord.GetId())].Add(spawnId); _areaTriggerSpawnsByLocation[(spawn.MapId, cellCoord.GetId())].Add(spawnId);
// add the position to the map // add the position to the map
_areaTriggerSpawnsBySpawnId[spawnId] = spawn; _areaTriggerSpawnsBySpawnId[spawnId] = spawn;
@@ -53,6 +53,9 @@ namespace Game.Entities
if (!IsInWorld) if (!IsInWorld)
{ {
GetMap().GetObjectsStore().Add(GetGUID(), this); GetMap().GetObjectsStore().Add(GetGUID(), this);
if (_spawnId != 0)
GetMap().GetAreaTriggerBySpawnIdStore().Add(_spawnId, this);
base.AddToWorld(); base.AddToWorld();
} }
} }
@@ -74,6 +77,9 @@ namespace Game.Entities
_ai.OnRemove(); _ai.OnRemove();
base.RemoveFromWorld(); base.RemoveFromWorld();
if (_spawnId != 0)
GetMap().GetAreaTriggerBySpawnIdStore().Remove(_spawnId, this);
GetMap().GetObjectsStore().Remove(GetGUID()); GetMap().GetObjectsStore().Remove(GetGUID());
} }
} }
@@ -236,7 +242,7 @@ namespace Game.Entities
if (position == null) if (position == null)
return false; return false;
AreaTriggerTemplate areaTriggerTemplate = Global.AreaTriggerDataStorage.GetAreaTriggerTemplate(position.Id); AreaTriggerTemplate areaTriggerTemplate = Global.AreaTriggerDataStorage.GetAreaTriggerTemplate(position.TriggerId);
if (areaTriggerTemplate == null) if (areaTriggerTemplate == null)
return false; return false;
@@ -246,7 +252,7 @@ namespace Game.Entities
bool CreateServer(Map map, AreaTriggerTemplate areaTriggerTemplate, AreaTriggerSpawn position) bool CreateServer(Map map, AreaTriggerTemplate areaTriggerTemplate, AreaTriggerSpawn position)
{ {
SetMap(map); SetMap(map);
Relocate(position.Location); Relocate(position.SpawnPoint);
if (!IsPositionValid()) if (!IsPositionValid())
{ {
Log.outError(LogFilter.AreaTrigger, $"AreaTriggerServer (id {areaTriggerTemplate.Id}) not created. Invalid coordinates (X: {GetPositionX()} Y: {GetPositionY()})"); Log.outError(LogFilter.AreaTrigger, $"AreaTriggerServer (id {areaTriggerTemplate.Id}) not created. Invalid coordinates (X: {GetPositionX()} Y: {GetPositionY()})");
@@ -17,6 +17,7 @@
using Framework.Constants; using Framework.Constants;
using Framework.Dynamic; using Framework.Dynamic;
using Game.Maps;
using Game.Networking; using Game.Networking;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -319,18 +320,12 @@ namespace Game.Entities
public uint ScriptId; public uint ScriptId;
} }
public class AreaTriggerSpawn public class AreaTriggerSpawn : SpawnData
{ {
public ulong SpawnId; public AreaTriggerId TriggerId;
public AreaTriggerId Id;
public WorldLocation Location;
public uint PhaseId;
public uint PhaseGroup;
public byte PhaseUseFlags;
public AreaTriggerShapeInfo Shape = new(); public AreaTriggerShapeInfo Shape = new();
public uint ScriptId; public AreaTriggerSpawn() : base(SpawnObjectType.AreaTrigger) { }
} }
public struct AreaTriggerAction public struct AreaTriggerAction
+23 -17
View File
@@ -793,7 +793,7 @@ namespace Game.Entities
if (data != null) if (data != null)
{ {
PhasingHandler.InitDbPhaseShift(GetPhaseShift(), data.phaseUseFlags, data.phaseId, data.phaseGroup); PhasingHandler.InitDbPhaseShift(GetPhaseShift(), data.PhaseUseFlags, data.PhaseId, data.PhaseGroup);
PhasingHandler.InitDbVisibleMapId(GetPhaseShift(), data.terrainSwapMap); PhasingHandler.InitDbVisibleMapId(GetPhaseShift(), data.terrainSwapMap);
} }
@@ -1246,18 +1246,24 @@ namespace Game.Entities
dynamicflags = 0; dynamicflags = 0;
} }
if (data.spawnId == 0) if (data.SpawnId == 0)
data.spawnId = m_spawnId; data.SpawnId = m_spawnId;
Cypher.Assert(data.spawnId == m_spawnId); Cypher.Assert(data.SpawnId == m_spawnId);
data.Id = GetEntry(); data.Id = GetEntry();
data.displayid = displayId; data.displayid = displayId;
data.equipmentId = (sbyte)GetCurrentEquipmentId(); data.equipmentId = (sbyte)GetCurrentEquipmentId();
if (GetTransport() == null) if (GetTransport() == null)
data.spawnPoint.WorldRelocate(this); {
data.MapId = GetMapId();
data.SpawnPoint.Relocate(this);
}
else else
data.spawnPoint.WorldRelocate(mapid, GetTransOffsetX(), GetTransOffsetY(), GetTransOffsetZ(), GetTransOffsetO()); {
data.MapId = mapid;
data.SpawnPoint.Relocate(GetTransOffsetX(), GetTransOffsetY(), GetTransOffsetZ(), GetTransOffsetO());
}
data.spawntimesecs = (int)m_respawnDelay; data.spawntimesecs = (int)m_respawnDelay;
// prevent add data integrity problems // prevent add data integrity problems
@@ -1277,8 +1283,8 @@ namespace Game.Entities
if (data.spawnGroupData == null) if (data.spawnGroupData == null)
data.spawnGroupData = Global.ObjectMgr.GetDefaultSpawnGroup(); data.spawnGroupData = Global.ObjectMgr.GetDefaultSpawnGroup();
data.phaseId = GetDBPhase() > 0 ? (uint)GetDBPhase() : data.phaseId; data.PhaseId = GetDBPhase() > 0 ? (uint)GetDBPhase() : data.PhaseId;
data.phaseGroup = GetDBPhase() < 0 ? (uint)-GetDBPhase() : data.phaseGroup; data.PhaseGroup = GetDBPhase() < 0 ? (uint)-GetDBPhase() : data.PhaseGroup;
// update in DB // update in DB
SQLTransaction trans = new(); SQLTransaction trans = new();
@@ -1294,8 +1300,8 @@ namespace Game.Entities
stmt.AddValue(index++, GetEntry()); stmt.AddValue(index++, GetEntry());
stmt.AddValue(index++, mapid); stmt.AddValue(index++, mapid);
stmt.AddValue(index++, data.spawnDifficulties.Empty() ? "" : string.Join(',', data.spawnDifficulties)); stmt.AddValue(index++, data.spawnDifficulties.Empty() ? "" : string.Join(',', data.spawnDifficulties));
stmt.AddValue(index++, data.phaseId); stmt.AddValue(index++, data.PhaseId);
stmt.AddValue(index++, data.phaseGroup); stmt.AddValue(index++, data.PhaseGroup);
stmt.AddValue(index++, displayId); stmt.AddValue(index++, displayId);
stmt.AddValue(index++, GetCurrentEquipmentId()); stmt.AddValue(index++, GetCurrentEquipmentId());
stmt.AddValue(index++, GetPositionX()); stmt.AddValue(index++, GetPositionX());
@@ -1610,7 +1616,7 @@ namespace Game.Entities
SQLTransaction trans = new(); SQLTransaction trans = new();
Global.MapMgr.DoForAllMapsWithMapId(data.spawnPoint.GetMapId(), map => Global.MapMgr.DoForAllMapsWithMapId(data.MapId, map =>
{ {
// despawn all active creatures, and remove their respawns // despawn all active creatures, and remove their respawns
List<Creature> toUnload = new(); List<Creature> toUnload = new();
@@ -2448,7 +2454,7 @@ namespace Game.Entities
{ {
if (m_creatureData != null) if (m_creatureData != null)
{ {
m_creatureData.spawnPoint.GetPosition(out x, out y, out z, out ori); m_creatureData.SpawnPoint.GetPosition(out x, out y, out z, out ori);
dist = m_creatureData.spawndist; dist = m_creatureData.spawndist;
} }
else else
@@ -2459,7 +2465,7 @@ namespace Game.Entities
} }
} }
bool IsSpawnedOnTransport() { return m_creatureData != null && m_creatureData.spawnPoint.GetMapId() != GetMapId(); } bool IsSpawnedOnTransport() { return m_creatureData != null && m_creatureData.MapId != GetMapId(); }
void InitializeMovementFlags() void InitializeMovementFlags()
{ {
@@ -3157,7 +3163,7 @@ namespace Game.Entities
m_respawnradius = data.spawndist; m_respawnradius = data.spawndist;
m_respawnDelay = (uint)data.spawntimesecs; m_respawnDelay = (uint)data.spawntimesecs;
if (!Create(map.GenerateLowGuid(HighGuid.Creature), map, data.Id, data.spawnPoint, data, 0, !m_respawnCompatibilityMode)) if (!Create(map.GenerateLowGuid(HighGuid.Creature), map, data.Id, data.SpawnPoint, data, 0, !m_respawnCompatibilityMode))
return false; return false;
//We should set first home position, because then AI calls home movement //We should set first home position, because then AI calls home movement
@@ -3198,9 +3204,9 @@ namespace Game.Entities
m_deathState = DeathState.Dead; m_deathState = DeathState.Dead;
if (CanFly()) if (CanFly())
{ {
float tz = map.GetHeight(GetPhaseShift(), data.spawnPoint, true, MapConst.MaxFallDistance); float tz = map.GetHeight(GetPhaseShift(), data.SpawnPoint, true, MapConst.MaxFallDistance);
if (data.spawnPoint.GetPositionZ() - tz > 0.1f && GridDefines.IsValidMapCoord(tz)) if (data.SpawnPoint.GetPositionZ() - tz > 0.1f && GridDefines.IsValidMapCoord(tz))
Relocate(data.spawnPoint.GetPositionX(), data.spawnPoint.GetPositionY(), tz); Relocate(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY(), tz);
} }
} }
+13 -12
View File
@@ -1034,12 +1034,13 @@ namespace Game.Entities
// update in loaded data (changing data only in this place) // update in loaded data (changing data only in this place)
GameObjectData data = Global.ObjectMgr.NewOrExistGameObjectData(m_spawnId); GameObjectData data = Global.ObjectMgr.NewOrExistGameObjectData(m_spawnId);
if (data.spawnId == 0) if (data.SpawnId == 0)
data.spawnId = m_spawnId; data.SpawnId = m_spawnId;
Cypher.Assert(data.spawnId == m_spawnId); Cypher.Assert(data.SpawnId == m_spawnId);
data.Id = GetEntry(); data.Id = GetEntry();
data.spawnPoint.WorldRelocate(this); data.MapId = GetMapId();
data.SpawnPoint.Relocate(this);
data.rotation = m_localRotation; data.rotation = m_localRotation;
data.spawntimesecs = (int)(m_spawnedByDefault ? m_respawnDelayTime : -m_respawnDelayTime); data.spawntimesecs = (int)(m_spawnedByDefault ? m_respawnDelayTime : -m_respawnDelayTime);
data.animprogress = GetGoAnimProgress(); data.animprogress = GetGoAnimProgress();
@@ -1049,8 +1050,8 @@ namespace Game.Entities
if (data.spawnGroupData == null) if (data.spawnGroupData == null)
data.spawnGroupData = Global.ObjectMgr.GetDefaultSpawnGroup(); data.spawnGroupData = Global.ObjectMgr.GetDefaultSpawnGroup();
data.phaseId = GetDBPhase() > 0 ? (uint)GetDBPhase() : data.phaseId; data.PhaseId = GetDBPhase() > 0 ? (uint)GetDBPhase() : data.PhaseId;
data.phaseGroup = GetDBPhase() < 0 ? (uint)-GetDBPhase() : data.phaseGroup; data.PhaseGroup = GetDBPhase() < 0 ? (uint)-GetDBPhase() : data.PhaseGroup;
// Update in DB // Update in DB
byte index = 0; byte index = 0;
@@ -1063,8 +1064,8 @@ namespace Game.Entities
stmt.AddValue(index++, GetEntry()); stmt.AddValue(index++, GetEntry());
stmt.AddValue(index++, mapid); stmt.AddValue(index++, mapid);
stmt.AddValue(index++, data.spawnDifficulties.Empty() ? "" : string.Join(",", data.spawnDifficulties)); stmt.AddValue(index++, data.spawnDifficulties.Empty() ? "" : string.Join(",", data.spawnDifficulties));
stmt.AddValue(index++, data.phaseId); stmt.AddValue(index++, data.PhaseId);
stmt.AddValue(index++, data.phaseGroup); stmt.AddValue(index++, data.PhaseGroup);
stmt.AddValue(index++, GetPositionX()); stmt.AddValue(index++, GetPositionX());
stmt.AddValue(index++, GetPositionY()); stmt.AddValue(index++, GetPositionY());
stmt.AddValue(index++, GetPositionZ()); stmt.AddValue(index++, GetPositionZ());
@@ -1096,10 +1097,10 @@ namespace Game.Entities
m_spawnId = spawnId; m_spawnId = spawnId;
m_respawnCompatibilityMode = ((data.spawnGroupData.flags & SpawnGroupFlags.CompatibilityMode) != 0); m_respawnCompatibilityMode = ((data.spawnGroupData.flags & SpawnGroupFlags.CompatibilityMode) != 0);
if (!Create(entry, map, data.spawnPoint, data.rotation, animprogress, go_state, artKit, !m_respawnCompatibilityMode, spawnId)) if (!Create(entry, map, data.SpawnPoint, data.rotation, animprogress, go_state, artKit, !m_respawnCompatibilityMode, spawnId))
return false; return false;
PhasingHandler.InitDbPhaseShift(GetPhaseShift(), data.phaseUseFlags, data.phaseId, data.phaseGroup); PhasingHandler.InitDbPhaseShift(GetPhaseShift(), data.PhaseUseFlags, data.PhaseId, data.PhaseGroup);
PhasingHandler.InitDbVisibleMapId(GetPhaseShift(), data.terrainSwapMap); PhasingHandler.InitDbVisibleMapId(GetPhaseShift(), data.terrainSwapMap);
if (data.spawntimesecs >= 0) if (data.spawntimesecs >= 0)
@@ -1154,7 +1155,7 @@ namespace Game.Entities
SQLTransaction trans = new(); SQLTransaction trans = new();
Global.MapMgr.DoForAllMapsWithMapId(data.spawnPoint.GetMapId(), map => Global.MapMgr.DoForAllMapsWithMapId(data.MapId, map =>
{ {
// despawn all active objects, and remove their respawns // despawn all active objects, and remove their respawns
List<GameObject> toUnload = new(); List<GameObject> toUnload = new();
@@ -2805,7 +2806,7 @@ namespace Game.Entities
public void GetRespawnPosition(out float x, out float y, out float z, out float ori) public void GetRespawnPosition(out float x, out float y, out float z, out float ori)
{ {
if (m_goData != null) if (m_goData != null)
m_goData.spawnPoint.GetPosition(out x, out y, out z, out ori); m_goData.SpawnPoint.GetPosition(out x, out y, out z, out ori);
else else
GetPosition(out x, out y, out z, out ori); GetPosition(out x, out y, out z, out ori);
} }
+4 -4
View File
@@ -326,7 +326,7 @@ namespace Game.Entities
return null; return null;
float x, y, z, o; float x, y, z, o;
data.spawnPoint.GetPosition(out x, out y, out z, out o); data.SpawnPoint.GetPosition(out x, out y, out z, out o);
creature.SetTransport(this); creature.SetTransport(this);
creature.m_movementInfo.transport.guid = GetGUID(); creature.m_movementInfo.transport.guid = GetGUID();
@@ -347,7 +347,7 @@ namespace Game.Entities
return null; return null;
} }
PhasingHandler.InitDbPhaseShift(creature.GetPhaseShift(), data.phaseUseFlags, data.phaseId, data.phaseGroup); PhasingHandler.InitDbPhaseShift(creature.GetPhaseShift(), data.PhaseUseFlags, data.PhaseId, data.PhaseGroup);
PhasingHandler.InitDbVisibleMapId(creature.GetPhaseShift(), data.terrainSwapMap); PhasingHandler.InitDbVisibleMapId(creature.GetPhaseShift(), data.terrainSwapMap);
if (!map.AddToMap(creature)) if (!map.AddToMap(creature))
@@ -369,7 +369,7 @@ namespace Game.Entities
return null; return null;
float x, y, z, o; float x, y, z, o;
data.spawnPoint.GetPosition(out x, out y, out z, out o); data.SpawnPoint.GetPosition(out x, out y, out z, out o);
go.SetTransport(this); go.SetTransport(this);
go.m_movementInfo.transport.guid = GetGUID(); go.m_movementInfo.transport.guid = GetGUID();
@@ -385,7 +385,7 @@ namespace Game.Entities
return null; return null;
} }
PhasingHandler.InitDbPhaseShift(go.GetPhaseShift(), data.phaseUseFlags, data.phaseId, data.phaseGroup); PhasingHandler.InitDbPhaseShift(go.GetPhaseShift(), data.PhaseUseFlags, data.PhaseId, data.PhaseGroup);
PhasingHandler.InitDbVisibleMapId(go.GetPhaseShift(), data.terrainSwapMap); PhasingHandler.InitDbVisibleMapId(go.GetPhaseShift(), data.terrainSwapMap);
if (!map.AddToMap(go)) if (!map.AddToMap(go))
+8 -8
View File
@@ -1124,7 +1124,7 @@ namespace Game
// get the creature data from the low guid to get the entry, to be able to find out the whole guid // get the creature data from the low guid to get the entry, to be able to find out the whole guid
CreatureData data = Global.ObjectMgr.GetCreatureData(guid); CreatureData data = Global.ObjectMgr.GetCreatureData(guid);
if (data != null) if (data != null)
creaturesByMap.Add(data.spawnPoint.GetMapId(), guid); creaturesByMap.Add(data.MapId, guid);
} }
foreach (var key in creaturesByMap.Keys) foreach (var key in creaturesByMap.Keys)
@@ -1191,10 +1191,10 @@ namespace Game
Global.ObjectMgr.AddCreatureToGrid(guid, data); Global.ObjectMgr.AddCreatureToGrid(guid, data);
// Spawn if necessary (loaded grids only) // Spawn if necessary (loaded grids only)
Map map = Global.MapMgr.CreateBaseMap(data.spawnPoint.GetMapId()); Map map = Global.MapMgr.CreateBaseMap(data.MapId);
map.RemoveRespawnTime(SpawnObjectType.Creature, guid); map.RemoveRespawnTime(SpawnObjectType.Creature, guid);
// We use spawn coords to spawn // We use spawn coords to spawn
if (map != null && !map.Instanceable() && map.IsGridLoaded(data.spawnPoint)) if (map != null && !map.Instanceable() && map.IsGridLoaded(data.SpawnPoint))
Creature.CreateCreatureFromDB(guid, map); Creature.CreateCreatureFromDB(guid, map);
} }
} }
@@ -1215,10 +1215,10 @@ namespace Game
Global.ObjectMgr.AddGameObjectToGrid(guid, data); Global.ObjectMgr.AddGameObjectToGrid(guid, data);
// Spawn if necessary (loaded grids only) // Spawn if necessary (loaded grids only)
// this base map checked as non-instanced and then only existed // this base map checked as non-instanced and then only existed
Map map = Global.MapMgr.CreateBaseMap(data.spawnPoint.GetMapId()); Map map = Global.MapMgr.CreateBaseMap(data.MapId);
map.RemoveRespawnTime(SpawnObjectType.GameObject, guid); map.RemoveRespawnTime(SpawnObjectType.GameObject, guid);
// We use current coords to unspawn, not spawn coords since creature can have changed grid // We use current coords to unspawn, not spawn coords since creature can have changed grid
if (map != null && !map.Instanceable() && map.IsGridLoaded(data.spawnPoint)) if (map != null && !map.Instanceable() && map.IsGridLoaded(data.SpawnPoint))
{ {
GameObject pGameobject = GameObject.CreateGameObjectFromDB(guid, map, false); GameObject pGameobject = GameObject.CreateGameObjectFromDB(guid, map, false);
// @todo find out when it is add to map // @todo find out when it is add to map
@@ -1266,7 +1266,7 @@ namespace Game
{ {
Global.ObjectMgr.RemoveCreatureFromGrid(guid, data); Global.ObjectMgr.RemoveCreatureFromGrid(guid, data);
Global.MapMgr.DoForAllMapsWithMapId(data.spawnPoint.GetMapId(), map => Global.MapMgr.DoForAllMapsWithMapId(data.MapId, map =>
{ {
map.RemoveRespawnTime(SpawnObjectType.Creature, guid); map.RemoveRespawnTime(SpawnObjectType.Creature, guid);
var creatureBounds = map.GetCreatureBySpawnIdStore().LookupByKey(guid); var creatureBounds = map.GetCreatureBySpawnIdStore().LookupByKey(guid);
@@ -1294,7 +1294,7 @@ namespace Game
{ {
Global.ObjectMgr.RemoveGameObjectFromGrid(guid, data); Global.ObjectMgr.RemoveGameObjectFromGrid(guid, data);
Global.MapMgr.DoForAllMapsWithMapId(data.spawnPoint.GetMapId(), map => Global.MapMgr.DoForAllMapsWithMapId(data.MapId, map =>
{ {
map.RemoveRespawnTime(SpawnObjectType.GameObject, guid); map.RemoveRespawnTime(SpawnObjectType.GameObject, guid);
var gameobjectBounds = map.GetGameObjectBySpawnIdStore().LookupByKey(guid); var gameobjectBounds = map.GetGameObjectBySpawnIdStore().LookupByKey(guid);
@@ -1325,7 +1325,7 @@ namespace Game
continue; continue;
// Update if spawned // Update if spawned
Global.MapMgr.DoForAllMapsWithMapId(data.spawnPoint.GetMapId(), map => Global.MapMgr.DoForAllMapsWithMapId(data.MapId, map =>
{ {
var creatureBounds = map.GetCreatureBySpawnIdStore().LookupByKey(tuple.Item1); var creatureBounds = map.GetCreatureBySpawnIdStore().LookupByKey(tuple.Item1);
foreach (var creature in creatureBounds) foreach (var creature in creatureBounds)
+148 -125
View File
@@ -2892,8 +2892,8 @@ namespace Game
break; break;
} }
MapRecord map = CliDB.MapStorage.LookupByKey(master.spawnPoint.GetMapId()); MapRecord map = CliDB.MapStorage.LookupByKey(master.MapId);
if (map == null || !map.Instanceable() || (master.spawnPoint.GetMapId() != slave.spawnPoint.GetMapId())) if (map == null || !map.Instanceable() || (master.MapId != slave.MapId))
{ {
Log.outError(LogFilter.Sql, "Creature '{0}' linking to '{1}' on an unpermitted map.", guidLow, linkedGuidLow); Log.outError(LogFilter.Sql, "Creature '{0}' linking to '{1}' on an unpermitted map.", guidLow, linkedGuidLow);
error = true; error = true;
@@ -2908,8 +2908,8 @@ namespace Game
break; break;
} }
guid = ObjectGuid.Create(HighGuid.Creature, slave.spawnPoint.GetMapId(), slave.Id, guidLow); guid = ObjectGuid.Create(HighGuid.Creature, slave.MapId, slave.Id, guidLow);
linkedGuid = ObjectGuid.Create(HighGuid.Creature, master.spawnPoint.GetMapId(), master.Id, linkedGuidLow); linkedGuid = ObjectGuid.Create(HighGuid.Creature, master.MapId, master.Id, linkedGuidLow);
break; break;
} }
case CreatureLinkedRespawnType.CreatureToGO: case CreatureLinkedRespawnType.CreatureToGO:
@@ -2930,8 +2930,8 @@ namespace Game
break; break;
} }
MapRecord map = CliDB.MapStorage.LookupByKey(master.spawnPoint.GetMapId()); MapRecord map = CliDB.MapStorage.LookupByKey(master.MapId);
if (map == null || !map.Instanceable() || (master.spawnPoint.GetMapId() != slave.spawnPoint.GetMapId())) if (map == null || !map.Instanceable() || (master.MapId != slave.MapId))
{ {
Log.outError(LogFilter.Sql, "Creature '{0}' linking to '{1}' on an unpermitted map.", guidLow, linkedGuidLow); Log.outError(LogFilter.Sql, "Creature '{0}' linking to '{1}' on an unpermitted map.", guidLow, linkedGuidLow);
error = true; error = true;
@@ -2946,8 +2946,8 @@ namespace Game
break; break;
} }
guid = ObjectGuid.Create(HighGuid.Creature, slave.spawnPoint.GetMapId(), slave.Id, guidLow); guid = ObjectGuid.Create(HighGuid.Creature, slave.MapId, slave.Id, guidLow);
linkedGuid = ObjectGuid.Create(HighGuid.GameObject, master.spawnPoint.GetMapId(), master.Id, linkedGuidLow); linkedGuid = ObjectGuid.Create(HighGuid.GameObject, master.MapId, master.Id, linkedGuidLow);
break; break;
} }
case CreatureLinkedRespawnType.GOToGO: case CreatureLinkedRespawnType.GOToGO:
@@ -2968,8 +2968,8 @@ namespace Game
break; break;
} }
MapRecord map = CliDB.MapStorage.LookupByKey(master.spawnPoint.GetMapId()); MapRecord map = CliDB.MapStorage.LookupByKey(master.MapId);
if (map == null || !map.Instanceable() || (master.spawnPoint.GetMapId() != slave.spawnPoint.GetMapId())) if (map == null || !map.Instanceable() || (master.MapId != slave.MapId))
{ {
Log.outError(LogFilter.Sql, "Creature '{0}' linking to '{1}' on an unpermitted map.", guidLow, linkedGuidLow); Log.outError(LogFilter.Sql, "Creature '{0}' linking to '{1}' on an unpermitted map.", guidLow, linkedGuidLow);
error = true; error = true;
@@ -2984,8 +2984,8 @@ namespace Game
break; break;
} }
guid = ObjectGuid.Create(HighGuid.GameObject, slave.spawnPoint.GetMapId(), slave.Id, guidLow); guid = ObjectGuid.Create(HighGuid.GameObject, slave.MapId, slave.Id, guidLow);
linkedGuid = ObjectGuid.Create(HighGuid.GameObject, master.spawnPoint.GetMapId(), master.Id, linkedGuidLow); linkedGuid = ObjectGuid.Create(HighGuid.GameObject, master.MapId, master.Id, linkedGuidLow);
break; break;
} }
case CreatureLinkedRespawnType.GOToCreature: case CreatureLinkedRespawnType.GOToCreature:
@@ -3006,8 +3006,8 @@ namespace Game
break; break;
} }
MapRecord map = CliDB.MapStorage.LookupByKey(master.spawnPoint.GetMapId()); MapRecord map = CliDB.MapStorage.LookupByKey(master.MapId);
if (map == null || !map.Instanceable() || (master.spawnPoint.GetMapId() != slave.spawnPoint.GetMapId())) if (map == null || !map.Instanceable() || (master.MapId != slave.MapId))
{ {
Log.outError(LogFilter.Sql, "Creature '{0}' linking to '{1}' on an unpermitted map.", guidLow, linkedGuidLow); Log.outError(LogFilter.Sql, "Creature '{0}' linking to '{1}' on an unpermitted map.", guidLow, linkedGuidLow);
error = true; error = true;
@@ -3022,8 +3022,8 @@ namespace Game
break; break;
} }
guid = ObjectGuid.Create(HighGuid.GameObject, slave.spawnPoint.GetMapId(), slave.Id, guidLow); guid = ObjectGuid.Create(HighGuid.GameObject, slave.MapId, slave.Id, guidLow);
linkedGuid = ObjectGuid.Create(HighGuid.Creature, master.spawnPoint.GetMapId(), master.Id, linkedGuidLow); linkedGuid = ObjectGuid.Create(HighGuid.Creature, master.MapId, master.Id, linkedGuidLow);
break; break;
} }
@@ -3408,9 +3408,10 @@ namespace Game
} }
CreatureData data = new(); CreatureData data = new();
data.spawnId = guid; data.SpawnId = guid;
data.Id = entry; data.Id = entry;
data.spawnPoint = new WorldLocation(result.Read<ushort>(2), result.Read<float>(3), result.Read<float>(4), result.Read<float>(5), result.Read<float>(6)); data.MapId = result.Read<ushort>(2);
data.SpawnPoint = new Position(result.Read<float>(3), result.Read<float>(4), result.Read<float>(5), result.Read<float>(6));
data.displayid = result.Read<uint>(7); data.displayid = result.Read<uint>(7);
data.equipmentId = result.Read<sbyte>(8); data.equipmentId = result.Read<sbyte>(8);
data.spawntimesecs = result.Read<int>(9); data.spawntimesecs = result.Read<int>(9);
@@ -3419,7 +3420,7 @@ namespace Game
data.curhealth = result.Read<uint>(12); data.curhealth = result.Read<uint>(12);
data.curmana = result.Read<uint>(13); data.curmana = result.Read<uint>(13);
data.movementType = result.Read<byte>(14); data.movementType = result.Read<byte>(14);
data.spawnDifficulties = ParseSpawnDifficulties(result.Read<string>(15), "creature", guid, data.spawnPoint.GetMapId(), spawnMasks.LookupByKey(data.spawnPoint.GetMapId())); data.spawnDifficulties = ParseSpawnDifficulties(result.Read<string>(15), "creature", guid, data.MapId, spawnMasks.LookupByKey(data.MapId));
short gameEvent = result.Read<short>(16); short gameEvent = result.Read<short>(16);
uint PoolId = result.Read<uint>(17); uint PoolId = result.Read<uint>(17);
data.npcflag = result.Read<ulong>(18); data.npcflag = result.Read<ulong>(18);
@@ -3427,17 +3428,17 @@ namespace Game
data.unit_flags2 = result.Read<uint>(20); data.unit_flags2 = result.Read<uint>(20);
data.unit_flags3 = result.Read<uint>(21); data.unit_flags3 = result.Read<uint>(21);
data.dynamicflags = result.Read<uint>(22); data.dynamicflags = result.Read<uint>(22);
data.phaseUseFlags = (PhaseUseFlagsValues)result.Read<byte>(23); data.PhaseUseFlags = (PhaseUseFlagsValues)result.Read<byte>(23);
data.phaseId = result.Read<uint>(24); data.PhaseId = result.Read<uint>(24);
data.phaseGroup = result.Read<uint>(25); data.PhaseGroup = result.Read<uint>(25);
data.terrainSwapMap = result.Read<int>(26); data.terrainSwapMap = result.Read<int>(26);
data.ScriptId = GetScriptId(result.Read<string>(27)); data.ScriptId = GetScriptId(result.Read<string>(27));
data.spawnGroupData = _spawnGroupDataStorage[IsTransportMap(data.spawnPoint.GetMapId()) ? 1 : 0u]; // transport spawns default to compatibility group data.spawnGroupData = _spawnGroupDataStorage[IsTransportMap(data.MapId) ? 1 : 0u]; // transport spawns default to compatibility group
var mapEntry = CliDB.MapStorage.LookupByKey(data.spawnPoint.GetMapId()); var mapEntry = CliDB.MapStorage.LookupByKey(data.MapId);
if (mapEntry == null) if (mapEntry == null)
{ {
Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0}) that spawned at not existed map (Id: {1}), skipped.", guid, data.spawnPoint.GetMapId()); Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0}) that spawned at not existed map (Id: {1}), skipped.", guid, data.MapId);
continue; continue;
} }
@@ -3498,40 +3499,40 @@ namespace Game
} }
} }
if (Convert.ToBoolean(data.phaseUseFlags & ~PhaseUseFlagsValues.All)) if (Convert.ToBoolean(data.PhaseUseFlags & ~PhaseUseFlagsValues.All))
{ {
Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) has unknown `phaseUseFlags` set, removed unknown value.", guid, data.Id); Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) has unknown `phaseUseFlags` set, removed unknown value.", guid, data.Id);
data.phaseUseFlags &= PhaseUseFlagsValues.All; data.PhaseUseFlags &= PhaseUseFlagsValues.All;
} }
if (data.phaseUseFlags.HasAnyFlag(PhaseUseFlagsValues.AlwaysVisible) && data.phaseUseFlags.HasAnyFlag(PhaseUseFlagsValues.Inverse)) if (data.PhaseUseFlags.HasAnyFlag(PhaseUseFlagsValues.AlwaysVisible) && data.PhaseUseFlags.HasAnyFlag(PhaseUseFlagsValues.Inverse))
{ {
Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE," + Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE," +
" removing PHASE_USE_FLAGS_INVERSE.", guid, data.Id); " removing PHASE_USE_FLAGS_INVERSE.", guid, data.Id);
data.phaseUseFlags &= ~PhaseUseFlagsValues.Inverse; data.PhaseUseFlags &= ~PhaseUseFlagsValues.Inverse;
} }
if (data.phaseGroup != 0 && data.phaseId != 0) if (data.PhaseGroup != 0 && data.PhaseId != 0)
{ {
Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.Id); Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.Id);
data.phaseGroup = 0; data.PhaseGroup = 0;
} }
if (data.phaseId != 0) if (data.PhaseId != 0)
{ {
if (!CliDB.PhaseStorage.ContainsKey(data.phaseId)) if (!CliDB.PhaseStorage.ContainsKey(data.PhaseId))
{ {
Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) with `phaseid` {2} does not exist, set to 0", guid, data.Id, data.phaseId); Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) with `phaseid` {2} does not exist, set to 0", guid, data.Id, data.PhaseId);
data.phaseId = 0; data.PhaseId = 0;
} }
} }
if (data.phaseGroup != 0) if (data.PhaseGroup != 0)
{ {
if (Global.DB2Mgr.GetPhasesForGroup(data.phaseGroup).Empty()) if (Global.DB2Mgr.GetPhasesForGroup(data.PhaseGroup).Empty())
{ {
Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) with `phasegroup` {2} does not exist, set to 0", guid, data.Id, data.phaseGroup); Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) with `phasegroup` {2} does not exist, set to 0", guid, data.Id, data.PhaseGroup);
data.phaseGroup = 0; data.PhaseGroup = 0;
} }
} }
@@ -3543,7 +3544,7 @@ namespace Game
Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) with `terrainSwapMap` {2} does not exist, set to -1", guid, data.Id, data.terrainSwapMap); Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) with `terrainSwapMap` {2} does not exist, set to -1", guid, data.Id, data.terrainSwapMap);
data.terrainSwapMap = -1; data.terrainSwapMap = -1;
} }
else if (terrainSwapEntry.ParentMapID != data.spawnPoint.GetMapId()) else if (terrainSwapEntry.ParentMapID != data.MapId)
{ {
Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) with `terrainSwapMap` {2} which cannot be used on spawn map, set to -1", guid, data.Id, data.terrainSwapMap); Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0} Entry: {1}) with `terrainSwapMap` {2} which cannot be used on spawn map, set to -1", guid, data.Id, data.terrainSwapMap);
data.terrainSwapMap = -1; data.terrainSwapMap = -1;
@@ -3553,7 +3554,7 @@ namespace Game
if (WorldConfig.GetBoolValue(WorldCfg.CalculateCreatureZoneAreaData)) if (WorldConfig.GetBoolValue(WorldCfg.CalculateCreatureZoneAreaData))
{ {
PhasingHandler.InitDbVisibleMapId(phaseShift, data.terrainSwapMap); PhasingHandler.InitDbVisibleMapId(phaseShift, data.terrainSwapMap);
Global.MapMgr.GetZoneAndAreaId(phaseShift, out uint zoneId, out uint areaId, data.spawnPoint); Global.MapMgr.GetZoneAndAreaId(phaseShift, out uint zoneId, out uint areaId, data.MapId, data.SpawnPoint);
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.UPD_CREATURE_ZONE_AREA_DATA); PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.UPD_CREATURE_ZONE_AREA_DATA);
stmt.AddValue(0, zoneId); stmt.AddValue(0, zoneId);
@@ -3578,8 +3579,8 @@ namespace Game
{ {
foreach (Difficulty difficulty in data.spawnDifficulties) foreach (Difficulty difficulty in data.spawnDifficulties)
{ {
CellCoord cellCoord = GridDefines.ComputeCellCoord(data.spawnPoint.GetPositionX(), data.spawnPoint.GetPositionY()); CellCoord cellCoord = GridDefines.ComputeCellCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY());
var cellguids = CreateCellObjectGuids(data.spawnPoint.GetMapId(), difficulty, cellCoord.GetId()); var cellguids = CreateCellObjectGuids(data.MapId, difficulty, cellCoord.GetId());
cellguids.creatures.Add(guid); cellguids.creatures.Add(guid);
} }
} }
@@ -3587,8 +3588,8 @@ namespace Game
{ {
foreach (Difficulty difficulty in data.spawnDifficulties) foreach (Difficulty difficulty in data.spawnDifficulties)
{ {
CellCoord cellCoord = GridDefines.ComputeCellCoord(data.spawnPoint.GetPositionX(), data.spawnPoint.GetPositionY()); CellCoord cellCoord = GridDefines.ComputeCellCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY());
CellObjectGuids cellguids = GetCellObjectGuids(data.spawnPoint.GetMapId(), difficulty, cellCoord.GetId()); CellObjectGuids cellguids = GetCellObjectGuids(data.MapId, difficulty, cellCoord.GetId());
if (cellguids == null) if (cellguids == null)
return; return;
@@ -3611,9 +3612,10 @@ namespace Game
ulong spawnId = GenerateCreatureSpawnId(); ulong spawnId = GenerateCreatureSpawnId();
CreatureData data = NewOrExistCreatureData(spawnId); CreatureData data = NewOrExistCreatureData(spawnId);
data.spawnId = spawnId; data.SpawnId = spawnId;
data.Id = entry; data.Id = entry;
data.spawnPoint.WorldRelocate(mapId, pos); data.MapId = mapId;
data.SpawnPoint.Relocate(pos);
data.displayid = 0; data.displayid = 0;
data.equipmentId = 0; data.equipmentId = 0;
@@ -3633,7 +3635,7 @@ namespace Game
AddCreatureToGrid(spawnId, data); AddCreatureToGrid(spawnId, data);
// We use spawn coords to spawn // We use spawn coords to spawn
if (!map.Instanceable() && !map.IsRemovalGrid(data.spawnPoint)) if (!map.Instanceable() && !map.IsRemovalGrid(data.SpawnPoint))
{ {
Creature creature = Creature.CreateCreatureFromDB(spawnId, map, true, true); Creature creature = Creature.CreateCreatureFromDB(spawnId, map, true, true);
if (!creature) if (!creature)
@@ -3674,13 +3676,13 @@ namespace Game
return creatureTemplateStorage; return creatureTemplateStorage;
} }
public Dictionary<ulong, CreatureData> GetAllCreatureData() { return creatureDataStorage; } public Dictionary<ulong, CreatureData> GetAllCreatureData() { return creatureDataStorage; }
public CreatureData GetCreatureData(ulong guid) public CreatureData GetCreatureData(ulong spawnId)
{ {
return creatureDataStorage.LookupByKey(guid); return creatureDataStorage.LookupByKey(spawnId);
} }
public ObjectGuid GetLinkedRespawnGuid(ObjectGuid guid) public ObjectGuid GetLinkedRespawnGuid(ObjectGuid spawnId)
{ {
var retGuid = linkedRespawnStorage.LookupByKey(guid); var retGuid = linkedRespawnStorage.LookupByKey(spawnId);
if (retGuid.IsEmpty()) if (retGuid.IsEmpty())
return ObjectGuid.Empty; return ObjectGuid.Empty;
return retGuid; return retGuid;
@@ -3691,7 +3693,7 @@ namespace Game
return false; return false;
CreatureData master = GetCreatureData(guidLow); CreatureData master = GetCreatureData(guidLow);
ObjectGuid guid = ObjectGuid.Create(HighGuid.Creature, master.spawnPoint.GetMapId(), master.Id, guidLow); ObjectGuid guid = ObjectGuid.Create(HighGuid.Creature, master.MapId, master.Id, guidLow);
PreparedStatement stmt; PreparedStatement stmt;
if (linkedGuidLow == 0) // we're removing the linking if (linkedGuidLow == 0) // we're removing the linking
@@ -3711,8 +3713,8 @@ namespace Game
return false; return false;
} }
MapRecord map = CliDB.MapStorage.LookupByKey(master.spawnPoint.GetMapId()); MapRecord map = CliDB.MapStorage.LookupByKey(master.MapId);
if (map == null || !map.Instanceable() || (master.spawnPoint.GetMapId() != slave.spawnPoint.GetMapId())) if (map == null || !map.Instanceable() || (master.MapId != slave.MapId))
{ {
Log.outError(LogFilter.Sql, "Creature '{0}' linking to '{1}' on an unpermitted map.", guidLow, linkedGuidLow); Log.outError(LogFilter.Sql, "Creature '{0}' linking to '{1}' on an unpermitted map.", guidLow, linkedGuidLow);
return false; return false;
@@ -3725,7 +3727,7 @@ namespace Game
return false; return false;
} }
ObjectGuid linkedGuid = ObjectGuid.Create(HighGuid.Creature, slave.spawnPoint.GetMapId(), slave.Id, linkedGuidLow); ObjectGuid linkedGuid = ObjectGuid.Create(HighGuid.Creature, slave.MapId, slave.Id, linkedGuidLow);
linkedRespawnStorage[guid] = linkedGuid; linkedRespawnStorage[guid] = linkedGuid;
stmt = DB.World.GetPreparedStatement(WorldStatements.REP_LINKED_RESPAWN); stmt = DB.World.GetPreparedStatement(WorldStatements.REP_LINKED_RESPAWN);
@@ -3735,22 +3737,22 @@ namespace Game
DB.World.Execute(stmt); DB.World.Execute(stmt);
return true; return true;
} }
public CreatureData NewOrExistCreatureData(ulong guid) public CreatureData NewOrExistCreatureData(ulong spawnId)
{ {
if (!creatureDataStorage.ContainsKey(guid)) if (!creatureDataStorage.ContainsKey(spawnId))
creatureDataStorage[guid] = new CreatureData(); creatureDataStorage[spawnId] = new CreatureData();
return creatureDataStorage[guid]; return creatureDataStorage[spawnId];
} }
public void DeleteCreatureData(ulong guid) public void DeleteCreatureData(ulong spawnId)
{ {
CreatureData data = GetCreatureData(guid); CreatureData data = GetCreatureData(spawnId);
if (data != null) if (data != null)
{ {
RemoveCreatureFromGrid(guid, data); RemoveCreatureFromGrid(spawnId, data);
OnDeleteSpawnData(data); OnDeleteSpawnData(data);
} }
creatureDataStorage.Remove(guid); creatureDataStorage.Remove(spawnId);
} }
public CreatureBaseStats GetCreatureBaseStats(uint level, uint unitClass) public CreatureBaseStats GetCreatureBaseStats(uint level, uint unitClass)
{ {
@@ -4168,20 +4170,21 @@ namespace Game
} }
GameObjectData data = new(); GameObjectData data = new();
data.spawnId = guid; data.SpawnId = guid;
data.Id = entry; data.Id = entry;
data.spawnPoint = new WorldLocation(result.Read<ushort>(2), result.Read<float>(3), result.Read<float>(4), result.Read<float>(5), result.Read<float>(6)); data.MapId = result.Read<ushort>(2);
data.SpawnPoint = new Position(result.Read<float>(3), result.Read<float>(4), result.Read<float>(5), result.Read<float>(6));
data.rotation.X = result.Read<float>(7); data.rotation.X = result.Read<float>(7);
data.rotation.Y = result.Read<float>(8); data.rotation.Y = result.Read<float>(8);
data.rotation.Z = result.Read<float>(9); data.rotation.Z = result.Read<float>(9);
data.rotation.W = result.Read<float>(10); data.rotation.W = result.Read<float>(10);
data.spawntimesecs = result.Read<int>(11); data.spawntimesecs = result.Read<int>(11);
data.spawnGroupData = _spawnGroupDataStorage[IsTransportMap(data.spawnPoint.GetMapId()) ? 1 : 0u]; // transport spawns default to compatibility group data.spawnGroupData = IsTransportMap(data.MapId) ? GetLegacySpawnGroup() : GetDefaultSpawnGroup(); // transport spawns default to compatibility group
var mapEntry = CliDB.MapStorage.LookupByKey(data.spawnPoint.GetMapId()); var mapEntry = CliDB.MapStorage.LookupByKey(data.MapId);
if (mapEntry == null) if (mapEntry == null)
{ {
Log.outError(LogFilter.Sql, "Table `gameobject` has gameobject (GUID: {0} Entry: {1}) spawned on a non-existed map (Id: {2}), skip", guid, data.Id, data.spawnPoint.GetMapId()); Log.outError(LogFilter.Sql, "Table `gameobject` has gameobject (GUID: {0} Entry: {1}) spawned on a non-existed map (Id: {2}), skip", guid, data.Id, data.MapId);
continue; continue;
} }
@@ -4204,7 +4207,7 @@ namespace Game
} }
data.goState = (GameObjectState)gostate; data.goState = (GameObjectState)gostate;
data.spawnDifficulties = ParseSpawnDifficulties(result.Read<string>(14), "gameobject", guid, data.spawnPoint.GetMapId(), spawnMasks.LookupByKey(data.spawnPoint.GetMapId())); data.spawnDifficulties = ParseSpawnDifficulties(result.Read<string>(14), "gameobject", guid, data.MapId, spawnMasks.LookupByKey(data.MapId));
if (data.spawnDifficulties.Empty()) if (data.spawnDifficulties.Empty())
{ {
Log.outError(LogFilter.Sql, $"Table `creature` has creature (GUID: {guid}) that is not spawned in any difficulty, skipped."); Log.outError(LogFilter.Sql, $"Table `creature` has creature (GUID: {guid}) that is not spawned in any difficulty, skipped.");
@@ -4213,44 +4216,44 @@ namespace Game
short gameEvent = result.Read<sbyte>(15); short gameEvent = result.Read<sbyte>(15);
uint PoolId = result.Read<uint>(16); uint PoolId = result.Read<uint>(16);
data.phaseUseFlags = (PhaseUseFlagsValues)result.Read<byte>(17); data.PhaseUseFlags = (PhaseUseFlagsValues)result.Read<byte>(17);
data.phaseId = result.Read<uint>(18); data.PhaseId = result.Read<uint>(18);
data.phaseGroup = result.Read<uint>(19); data.PhaseGroup = result.Read<uint>(19);
if (Convert.ToBoolean(data.phaseUseFlags & ~PhaseUseFlagsValues.All)) if (Convert.ToBoolean(data.PhaseUseFlags & ~PhaseUseFlagsValues.All))
{ {
Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) has unknown `phaseUseFlags` set, removed unknown value.", guid, data.Id); Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) has unknown `phaseUseFlags` set, removed unknown value.", guid, data.Id);
data.phaseUseFlags &= PhaseUseFlagsValues.All; data.PhaseUseFlags &= PhaseUseFlagsValues.All;
} }
if (data.phaseUseFlags.HasAnyFlag(PhaseUseFlagsValues.AlwaysVisible) && data.phaseUseFlags.HasAnyFlag(PhaseUseFlagsValues.Inverse)) if (data.PhaseUseFlags.HasAnyFlag(PhaseUseFlagsValues.AlwaysVisible) && data.PhaseUseFlags.HasAnyFlag(PhaseUseFlagsValues.Inverse))
{ {
Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE," + Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE," +
" removing PHASE_USE_FLAGS_INVERSE.", guid, data.Id); " removing PHASE_USE_FLAGS_INVERSE.", guid, data.Id);
data.phaseUseFlags &= ~PhaseUseFlagsValues.Inverse; data.PhaseUseFlags &= ~PhaseUseFlagsValues.Inverse;
} }
if (data.phaseGroup != 0 && data.phaseId != 0) if (data.PhaseGroup != 0 && data.PhaseId != 0)
{ {
Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.Id); Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.Id);
data.phaseGroup = 0; data.PhaseGroup = 0;
} }
if (data.phaseId != 0) if (data.PhaseId != 0)
{ {
if (!CliDB.PhaseStorage.ContainsKey(data.phaseId)) if (!CliDB.PhaseStorage.ContainsKey(data.PhaseId))
{ {
Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) with `phaseid` {2} does not exist, set to 0", guid, data.Id, data.phaseId); Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) with `phaseid` {2} does not exist, set to 0", guid, data.Id, data.PhaseId);
data.phaseId = 0; data.PhaseId = 0;
} }
} }
if (data.phaseGroup != 0) if (data.PhaseGroup != 0)
{ {
if (Global.DB2Mgr.GetPhasesForGroup(data.phaseGroup).Empty()) if (Global.DB2Mgr.GetPhasesForGroup(data.PhaseGroup).Empty())
{ {
Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) with `phaseGroup` {2} does not exist, set to 0", guid, data.Id, data.phaseGroup); Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) with `phaseGroup` {2} does not exist, set to 0", guid, data.Id, data.PhaseGroup);
data.phaseGroup = 0; data.PhaseGroup = 0;
} }
} }
@@ -4263,7 +4266,7 @@ namespace Game
Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) with `terrainSwapMap` {2} does not exist, set to -1", guid, data.Id, data.terrainSwapMap); Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) with `terrainSwapMap` {2} does not exist, set to -1", guid, data.Id, data.terrainSwapMap);
data.terrainSwapMap = -1; data.terrainSwapMap = -1;
} }
else if (terrainSwapEntry.ParentMapID != data.spawnPoint.GetMapId()) else if (terrainSwapEntry.ParentMapID != data.MapId)
{ {
Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) with `terrainSwapMap` {2} which cannot be used on spawn map, set to -1", guid, data.Id, data.terrainSwapMap); Log.outError(LogFilter.Sql, "Table `gameobject` have gameobject (GUID: {0} Entry: {1}) with `terrainSwapMap` {2} which cannot be used on spawn map, set to -1", guid, data.Id, data.terrainSwapMap);
data.terrainSwapMap = -1; data.terrainSwapMap = -1;
@@ -4296,7 +4299,7 @@ namespace Game
continue; continue;
} }
if (!GridDefines.IsValidMapCoord(data.spawnPoint)) if (!GridDefines.IsValidMapCoord(data.MapId, data.SpawnPoint))
{ {
Log.outError(LogFilter.Sql, "Table `gameobject` has gameobject (GUID: {0} Entry: {1}) with invalid coordinates, skip", guid, data.Id); Log.outError(LogFilter.Sql, "Table `gameobject` has gameobject (GUID: {0} Entry: {1}) with invalid coordinates, skip", guid, data.Id);
continue; continue;
@@ -4305,13 +4308,13 @@ namespace Game
if (!(Math.Abs(Quaternion.Dot(data.rotation, data.rotation) - 1) < 1e-5)) if (!(Math.Abs(Quaternion.Dot(data.rotation, data.rotation) - 1) < 1e-5))
{ {
Log.outError(LogFilter.Sql, $"Table `gameobject` has gameobject (GUID: {guid} Entry: {data.Id}) with invalid rotation quaternion (non-unit), defaulting to orientation on Z axis only"); Log.outError(LogFilter.Sql, $"Table `gameobject` has gameobject (GUID: {guid} Entry: {data.Id}) with invalid rotation quaternion (non-unit), defaulting to orientation on Z axis only");
data.rotation = Quaternion.CreateFromRotationMatrix(Extensions.fromEulerAnglesZYX(data.spawnPoint.GetOrientation(), 0f, 0f)); data.rotation = Quaternion.CreateFromRotationMatrix(Extensions.fromEulerAnglesZYX(data.SpawnPoint.GetOrientation(), 0f, 0f));
} }
if (WorldConfig.GetBoolValue(WorldCfg.CalculateGameobjectZoneAreaData)) if (WorldConfig.GetBoolValue(WorldCfg.CalculateGameobjectZoneAreaData))
{ {
PhasingHandler.InitDbVisibleMapId(phaseShift, data.terrainSwapMap); PhasingHandler.InitDbVisibleMapId(phaseShift, data.terrainSwapMap);
Global.MapMgr.GetZoneAndAreaId(phaseShift, out uint zoneId, out uint areaId, data.spawnPoint); Global.MapMgr.GetZoneAndAreaId(phaseShift, out uint zoneId, out uint areaId, data.MapId, data.SpawnPoint);
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.UPD_GAMEOBJECT_ZONE_AREA_DATA); PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.UPD_GAMEOBJECT_ZONE_AREA_DATA);
stmt.AddValue(0, zoneId); stmt.AddValue(0, zoneId);
@@ -4499,8 +4502,8 @@ namespace Game
{ {
foreach (Difficulty difficulty in data.spawnDifficulties) foreach (Difficulty difficulty in data.spawnDifficulties)
{ {
CellCoord cellCoord = GridDefines.ComputeCellCoord(data.spawnPoint.GetPositionX(), data.spawnPoint.GetPositionY()); CellCoord cellCoord = GridDefines.ComputeCellCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY());
var cellguids = CreateCellObjectGuids(data.spawnPoint.GetMapId(), difficulty, cellCoord.GetId()); var cellguids = CreateCellObjectGuids(data.MapId, difficulty, cellCoord.GetId());
cellguids.gameobjects.Add(guid); cellguids.gameobjects.Add(guid);
} }
} }
@@ -4508,8 +4511,8 @@ namespace Game
{ {
foreach (Difficulty difficulty in data.spawnDifficulties) foreach (Difficulty difficulty in data.spawnDifficulties)
{ {
CellCoord cellCoord = GridDefines.ComputeCellCoord(data.spawnPoint.GetPositionX(), data.spawnPoint.GetPositionY()); CellCoord cellCoord = GridDefines.ComputeCellCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY());
CellObjectGuids cellguids = GetCellObjectGuids(data.spawnPoint.GetMapId(), difficulty, cellCoord.GetId()); CellObjectGuids cellguids = GetCellObjectGuids(data.MapId, difficulty, cellCoord.GetId());
if (cellguids == null) if (cellguids == null)
return; return;
@@ -4528,9 +4531,10 @@ namespace Game
ulong spawnId = GenerateGameObjectSpawnId(); ulong spawnId = GenerateGameObjectSpawnId();
GameObjectData data = NewOrExistGameObjectData(spawnId); GameObjectData data = NewOrExistGameObjectData(spawnId);
data.spawnId = spawnId; data.SpawnId = spawnId;
data.Id = entry; data.Id = entry;
data.spawnPoint.WorldRelocate(mapId, pos); data.MapId = mapId;
data.SpawnPoint.Relocate(pos);
data.rotation = rot; data.rotation = rot;
data.spawntimesecs = (int)spawntimedelay; data.spawntimesecs = (int)spawntimedelay;
data.animprogress = 100; data.animprogress = 100;
@@ -4544,7 +4548,7 @@ namespace Game
// Spawn if necessary (loaded grids only) // Spawn if necessary (loaded grids only)
// We use spawn coords to spawn // We use spawn coords to spawn
if (!map.Instanceable() && map.IsGridLoaded(data.spawnPoint)) if (!map.Instanceable() && map.IsGridLoaded(data.SpawnPoint))
{ {
GameObject go = GameObject.CreateGameObjectFromDB(spawnId, map); GameObject go = GameObject.CreateGameObjectFromDB(spawnId, map);
if (!go) if (!go)
@@ -4554,7 +4558,7 @@ namespace Game
} }
} }
Log.outDebug(LogFilter.Maps, $"AddGameObjectData: dbguid:{spawnId} entry:{entry} map:{mapId} pos:{data.spawnPoint}"); Log.outDebug(LogFilter.Maps, $"AddGameObjectData: dbguid:{spawnId} entry:{entry} map:{mapId} pos:{data.SpawnPoint}");
return spawnId; return spawnId;
} }
@@ -4569,27 +4573,27 @@ namespace Game
} }
MultiMap<uint, uint> GetGameObjectQuestItemMap() { return _gameObjectQuestItemStorage; } MultiMap<uint, uint> GetGameObjectQuestItemMap() { return _gameObjectQuestItemStorage; }
public Dictionary<ulong, GameObjectData> GetAllGameObjectData() { return gameObjectDataStorage; } public Dictionary<ulong, GameObjectData> GetAllGameObjectData() { return gameObjectDataStorage; }
public GameObjectData GetGameObjectData(ulong guid) public GameObjectData GetGameObjectData(ulong spawnId)
{ {
return gameObjectDataStorage.LookupByKey(guid); return gameObjectDataStorage.LookupByKey(spawnId);
} }
public void DeleteGameObjectData(ulong guid) public void DeleteGameObjectData(ulong spawnId)
{ {
GameObjectData data = GetGameObjectData(guid); GameObjectData data = GetGameObjectData(spawnId);
if (data != null) if (data != null)
{ {
RemoveGameObjectFromGrid(guid, data); RemoveGameObjectFromGrid(spawnId, data);
OnDeleteSpawnData(data); OnDeleteSpawnData(data);
} }
gameObjectDataStorage.Remove(guid); gameObjectDataStorage.Remove(spawnId);
} }
public GameObjectData NewOrExistGameObjectData(ulong guid) public GameObjectData NewOrExistGameObjectData(ulong spawnId)
{ {
if (!gameObjectDataStorage.ContainsKey(guid)) if (!gameObjectDataStorage.ContainsKey(spawnId))
gameObjectDataStorage[guid] = new GameObjectData(); gameObjectDataStorage[spawnId] = new GameObjectData();
return gameObjectDataStorage[guid]; return gameObjectDataStorage[spawnId];
} }
public GameObjectTemplate GetGameObjectTemplate(uint entry) public GameObjectTemplate GetGameObjectTemplate(uint entry)
{ {
@@ -5509,14 +5513,14 @@ namespace Game
{ {
uint groupId = result.Read<uint>(0); uint groupId = result.Read<uint>(0);
SpawnObjectType spawnType = (SpawnObjectType)result.Read<byte>(1); SpawnObjectType spawnType = (SpawnObjectType)result.Read<byte>(1);
if (spawnType >= SpawnObjectType.Max) if (!SpawnData.TypeIsValid(spawnType))
{ {
Log.outError(LogFilter.Sql, $"Spawn data with invalid type {spawnType} listed for spawn group {groupId}. Skipped."); Log.outError(LogFilter.Sql, $"Spawn data with invalid type {spawnType} listed for spawn group {groupId}. Skipped.");
continue; continue;
} }
ulong spawnId = result.Read<ulong>(2); ulong spawnId = result.Read<ulong>(2);
SpawnData data = GetSpawnData(spawnType, spawnId); SpawnMetadata data = GetSpawnMetadata(spawnType, spawnId);
if (data == null) if (data == null)
{ {
Log.outError(LogFilter.Sql, $"Spawn data with ID ({spawnType},{spawnId}) not found, but is listed as a member of spawn group {groupId}!"); Log.outError(LogFilter.Sql, $"Spawn data with ID ({spawnType},{spawnId}) not found, but is listed as a member of spawn group {groupId}!");
@@ -5536,10 +5540,10 @@ namespace Game
else else
{ {
if (groupTemplate.mapId == 0xFFFFFFFF) if (groupTemplate.mapId == 0xFFFFFFFF)
groupTemplate.mapId = data.spawnPoint.GetMapId(); groupTemplate.mapId = data.MapId;
else if (groupTemplate.mapId != data.spawnPoint.GetMapId() && !groupTemplate.flags.HasAnyFlag(SpawnGroupFlags.System)) else if (groupTemplate.mapId != data.MapId && !groupTemplate.flags.HasAnyFlag(SpawnGroupFlags.System))
{ {
Log.outError(LogFilter.Sql, $"Spawn group {groupId} has map ID {groupTemplate.mapId}, but spawn ({spawnType},{spawnId}) has map id {data.spawnPoint.GetMapId()} - spawn NOT added to group!"); Log.outError(LogFilter.Sql, $"Spawn group {groupId} has map ID {groupTemplate.mapId}, but spawn ({spawnType},{spawnId}) has map id {data.MapId} - spawn NOT added to group!");
continue; continue;
} }
data.spawnGroupData = groupTemplate; data.spawnGroupData = groupTemplate;
@@ -5609,7 +5613,7 @@ namespace Game
void OnDeleteSpawnData(SpawnData data) void OnDeleteSpawnData(SpawnData data)
{ {
var templateIt = _spawnGroupDataStorage.LookupByKey(data.spawnGroupData.groupId); var templateIt = _spawnGroupDataStorage.LookupByKey(data.spawnGroupData.groupId);
Cypher.Assert(templateIt != null, $"Creature data for ({data.type},{data.spawnId}) is being deleted and has invalid spawn group index {data.spawnGroupData.groupId}!"); Cypher.Assert(templateIt != null, $"Creature data for ({data.type},{data.SpawnId}) is being deleted and has invalid spawn group index {data.spawnGroupData.groupId}!");
if (templateIt.flags.HasAnyFlag(SpawnGroupFlags.System)) // system groups don't store their members in the map if (templateIt.flags.HasAnyFlag(SpawnGroupFlags.System)) // system groups don't store their members in the map
return; return;
@@ -5623,7 +5627,7 @@ namespace Game
return; return;
} }
Cypher.Assert(false, $"Spawn data ({data.type},{data.spawnId}) being removed is member of spawn group {data.spawnGroupData.groupId}, but not actually listed in the lookup table for that group!"); Cypher.Assert(false, $"Spawn data ({data.type},{data.SpawnId}) being removed is member of spawn group {data.spawnGroupData.groupId}, but not actually listed in the lookup table for that group!");
} }
public Dictionary<uint, InstanceTemplate> GetInstanceTemplates() { return instanceTemplateStorage; } public Dictionary<uint, InstanceTemplate> GetInstanceTemplates() { return instanceTemplateStorage; }
@@ -5691,19 +5695,38 @@ namespace Game
} }
public bool IsTransportMap(uint mapId) { return _transportMaps.Contains((ushort)mapId); } public bool IsTransportMap(uint mapId) { return _transportMaps.Contains((ushort)mapId); }
public SpawnGroupTemplateData GetSpawnGroupData(uint groupId) { return _spawnGroupDataStorage.LookupByKey(groupId); } public SpawnGroupTemplateData GetSpawnGroupData(uint groupId) { return _spawnGroupDataStorage.LookupByKey(groupId); }
public SpawnGroupTemplateData GetSpawnGroupData(SpawnObjectType type, ulong spawnId)
{
SpawnMetadata data = GetSpawnMetadata(type, spawnId);
return data != null ? data.spawnGroupData : null;
}
public SpawnGroupTemplateData GetDefaultSpawnGroup() { return _spawnGroupDataStorage.ElementAt(0).Value; } public SpawnGroupTemplateData GetDefaultSpawnGroup() { return _spawnGroupDataStorage.ElementAt(0).Value; }
public SpawnGroupTemplateData GetLegacySpawnGroup() { return _spawnGroupDataStorage.ElementAt(1).Value; } public SpawnGroupTemplateData GetLegacySpawnGroup() { return _spawnGroupDataStorage.ElementAt(1).Value; }
public List<SpawnData> GetSpawnDataForGroup(uint groupId) { return _spawnGroupMapStorage.LookupByKey(groupId); } public List<SpawnMetadata> GetSpawnMetadataForGroup(uint groupId) { return _spawnGroupMapStorage.LookupByKey(groupId); }
public SpawnData GetSpawnData(SpawnObjectType type, ulong guid) public SpawnMetadata GetSpawnMetadata(SpawnObjectType type, ulong spawnId)
{ {
if (type == SpawnObjectType.Creature) if (SpawnData.TypeHasData(type))
return GetCreatureData(guid); return GetSpawnData(type, spawnId);
else if (type == SpawnObjectType.GameObject)
return GetGameObjectData(guid);
else else
Cypher.Assert(false, $"Invalid spawn object type {type}"); return null;
}
public SpawnData GetSpawnData(SpawnObjectType type, ulong spawnId)
{
if (!SpawnData.TypeHasData(type))
return null;
return null; switch (type)
{
case SpawnObjectType.Creature:
return GetCreatureData(spawnId);
case SpawnObjectType.GameObject:
return GetGameObjectData(spawnId);
case SpawnObjectType.AreaTrigger:
return Global.AreaTriggerDataStorage.GetAreaTriggerSpawn(spawnId);
default:
Cypher.Assert(false, $"Invalid spawn object type {type}");
return null;
}
} }
public List<InstanceSpawnGroupInfo> GetSpawnGroupsForInstance(uint instanceId) { return _instanceSpawnGroupStorage.LookupByKey(instanceId); } public List<InstanceSpawnGroupInfo> GetSpawnGroupsForInstance(uint instanceId) { return _instanceSpawnGroupStorage.LookupByKey(instanceId); }
@@ -10593,7 +10616,7 @@ namespace Game
public MultiMap<uint, GraveYardData> GraveYardStorage = new(); public MultiMap<uint, GraveYardData> GraveYardStorage = new();
List<ushort> _transportMaps = new(); List<ushort> _transportMaps = new();
Dictionary<uint, SpawnGroupTemplateData> _spawnGroupDataStorage = new(); Dictionary<uint, SpawnGroupTemplateData> _spawnGroupDataStorage = new();
MultiMap<uint, SpawnData> _spawnGroupMapStorage = new(); MultiMap<uint, SpawnMetadata> _spawnGroupMapStorage = new();
MultiMap<ushort, InstanceSpawnGroupInfo> _instanceSpawnGroupStorage = new(); MultiMap<ushort, InstanceSpawnGroupInfo> _instanceSpawnGroupStorage = new();
//Spells /Skills / Phases //Spells /Skills / Phases
+7 -2
View File
@@ -42,7 +42,7 @@ namespace Game.Maps
{ {
return IsValidMapCoord(x, y, z) && float.IsFinite(o); return IsValidMapCoord(x, y, z) && float.IsFinite(o);
} }
public static bool IsValidMapCoord(uint mapid, float x, float y) public static bool IsValidMapCoord(uint mapid, float x, float y)
{ {
return Global.MapMgr.IsValidMAP(mapid, false) && IsValidMapCoord(x, y); return Global.MapMgr.IsValidMAP(mapid, false) && IsValidMapCoord(x, y);
@@ -58,9 +58,14 @@ namespace Game.Maps
return Global.MapMgr.IsValidMAP(mapid, false) && IsValidMapCoord(x, y, z, o); return Global.MapMgr.IsValidMAP(mapid, false) && IsValidMapCoord(x, y, z, o);
} }
public static bool IsValidMapCoord(uint mapid, Position pos)
{
return IsValidMapCoord(mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation());
}
public static bool IsValidMapCoord(WorldLocation loc) public static bool IsValidMapCoord(WorldLocation loc)
{ {
return IsValidMapCoord(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation()); return IsValidMapCoord(loc.GetMapId(), loc);
} }
public static void NormalizeMapCoord(ref float c) public static void NormalizeMapCoord(ref float c)
+264 -182
View File
@@ -2411,6 +2411,159 @@ namespace Game.Maps
return true; return true;
} }
public void Respawn(SpawnObjectType type, ulong spawnId, SQLTransaction dbTrans = null)
{
RespawnInfo info = GetRespawnInfo(type, spawnId);
if (info != null)
Respawn(info, dbTrans);
}
public void Respawn(RespawnInfo info, SQLTransaction dbTrans = null)
{
info.respawnTime = GameTime.GetGameTime();
SaveRespawnInfoDB(info, dbTrans);
}
public void RemoveRespawnTime(SpawnObjectType type, ulong spawnId, SQLTransaction dbTrans = null)
{
RespawnInfo info = GetRespawnInfo(type, spawnId);
if (info != null)
DeleteRespawnInfo(info, dbTrans);
}
int DespawnAll(SpawnObjectType type, ulong spawnId)
{
List<WorldObject> toUnload = new();
switch (type)
{
case SpawnObjectType.Creature:
foreach (var creature in GetCreatureBySpawnIdStore().LookupByKey(spawnId))
toUnload.Add(creature);
break;
case SpawnObjectType.GameObject:
foreach (var obj in GetGameObjectBySpawnIdStore().LookupByKey(spawnId))
toUnload.Add(obj);
break;
default:
break;
}
foreach (WorldObject o in toUnload)
AddObjectToRemoveList(o);
return toUnload.Count;
}
bool AddRespawnInfo(RespawnInfo info)
{
if (info.spawnId == 0)
{
Log.outError(LogFilter.Maps, $"Attempt to insert respawn info for zero spawn id (type {info.type})");
return false;
}
var bySpawnIdMap = GetRespawnMapForType(info.type);
if (bySpawnIdMap == null)
return false;
// check if we already have the maximum possible number of respawns scheduled
if (SpawnData.TypeHasData(info.type))
{
var existing = bySpawnIdMap.LookupByKey(info.spawnId);
if (existing != null) // spawnid already has a respawn scheduled
{
if (info.respawnTime <= existing.respawnTime) // delete existing in this case
DeleteRespawnInfo(existing);
else
return false;
}
Cypher.Assert(!bySpawnIdMap.ContainsKey(info.spawnId), $"Insertion of respawn info with id ({info.type},{info.spawnId}) into spawn id map failed - state desync.");
}
else
Cypher.Assert(false, $"Invalid respawn info for spawn id ({info.type},{info.spawnId}) being inserted");
RespawnInfo ri = new(info);
_respawnTimes.Add(ri);
bySpawnIdMap.Add(ri.spawnId, ri);
return true;
}
static void PushRespawnInfoFrom(List<RespawnInfo> data, Dictionary<ulong, RespawnInfo> map)
{
foreach (var pair in map)
data.Add(pair.Value);
}
public void GetRespawnInfo(List<RespawnInfo> respawnData, SpawnObjectTypeMask types)
{
if ((types & SpawnObjectTypeMask.Creature) != 0)
PushRespawnInfoFrom(respawnData, _creatureRespawnTimesBySpawnId);
if ((types & SpawnObjectTypeMask.GameObject) != 0)
PushRespawnInfoFrom(respawnData, _gameObjectRespawnTimesBySpawnId);
}
public RespawnInfo GetRespawnInfo(SpawnObjectType type, ulong spawnId)
{
var map = GetRespawnMapForType(type);
if (map == null)
return null;
var respawnInfo = map.LookupByKey(spawnId);
if (respawnInfo == null)
return null;
return respawnInfo;
}
Dictionary<ulong, RespawnInfo> GetRespawnMapForType(SpawnObjectType type)
{
switch (type)
{
case SpawnObjectType.Creature:
return _creatureRespawnTimesBySpawnId;
case SpawnObjectType.GameObject:
return _gameObjectRespawnTimesBySpawnId;
case SpawnObjectType.AreaTrigger:
return null;
default:
Cypher.Assert(false);
return null;
}
}
void UnloadAllRespawnInfos() // delete everything from memory
{
_respawnTimes.Clear();
_creatureRespawnTimesBySpawnId.Clear();
_gameObjectRespawnTimesBySpawnId.Clear();
}
void DeleteRespawnInfo(RespawnInfo info, SQLTransaction dbTrans = null)
{
// Delete from all relevant containers to ensure consistency
Cypher.Assert(info != null);
// spawnid store
var spawnMap = GetRespawnMapForType(info.type);
if (spawnMap == null)
return;
var respawnInfo = spawnMap.LookupByKey(info.spawnId);
Cypher.Assert(respawnInfo != info, $"Respawn stores inconsistent for map {GetId()}, spawnid {info.spawnId} (type {info.type})");
spawnMap.Remove(info.spawnId);
// respawn heap
_respawnTimes.Remove(info);
// database
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESPAWN);
stmt.AddValue(0, (ushort)info.type);
stmt.AddValue(1, info.spawnId);
stmt.AddValue(2, GetId());
stmt.AddValue(3, GetInstanceId());
DB.Characters.ExecuteOrAppend(dbTrans, stmt);
}
void DoRespawn(SpawnObjectType type, ulong spawnId, uint gridId) void DoRespawn(SpawnObjectType type, ulong spawnId, uint gridId)
{ {
if (!IsGridLoaded(gridId)) // if grid isn't loaded, this will be processed in grid load handler if (!IsGridLoaded(gridId)) // if grid isn't loaded, this will be processed in grid load handler
@@ -2438,120 +2591,6 @@ namespace Game.Maps
} }
} }
public void Respawn(SpawnObjectType type, ulong spawnId, SQLTransaction dbTrans = null)
{
RespawnInfo info = GetRespawnInfo(type, spawnId);
if (info != null)
Respawn(info, dbTrans);
}
public void Respawn(RespawnInfo info, SQLTransaction dbTrans = null)
{
if (!CheckRespawn(info))
{
if (info.respawnTime != 0)
{
//_respawnTimes.decrease(info);
SaveRespawnInfoDB(info, dbTrans);
}
else
DeleteRespawnInfo(info, dbTrans);
return;
}
// remove the actual respawn record first - since this deletes it, we save what we need
SpawnObjectType type = info.type;
uint gridId = info.gridId;
ulong spawnId = info.spawnId;
DeleteRespawnInfo(info, dbTrans);
DoRespawn(type, spawnId, gridId);
}
bool AddRespawnInfo(RespawnInfo info)
{
Cypher.Assert(info.spawnId != 0, $"Attempt to schedule respawn with zero spawnid (type {info.type})");
var bySpawnIdMap = GetRespawnMapForType(info.type);
var existing = bySpawnIdMap.LookupByKey(info.spawnId);
if (existing != null) // spawnid already has a respawn scheduled
{
if (info.respawnTime < existing.respawnTime) // delete existing in this case
DeleteRespawnInfo(existing);
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)
RespawnInfo ri = new(info);
_respawnTimes.Add(ri);
bool success = bySpawnIdMap.TryAdd(ri.spawnId, ri);
Cypher.Assert(success, $"Insertion of respawn info with id ({ri.type},{ri.spawnId}) into spawn id map failed - state desync.");
return true;
}
static void PushRespawnInfoFrom(List<RespawnInfo> data, Dictionary<ulong, RespawnInfo> map)
{
foreach (var pair in map)
data.Add(pair.Value);
}
public void GetRespawnInfo(List<RespawnInfo> respawnData, SpawnObjectTypeMask types)
{
if (types.HasAnyFlag(SpawnObjectTypeMask.Creature))
PushRespawnInfoFrom(respawnData, _creatureRespawnTimesBySpawnId);
if (types.HasAnyFlag(SpawnObjectTypeMask.GameObject))
PushRespawnInfoFrom(respawnData, _gameObjectRespawnTimesBySpawnId);
}
RespawnInfo GetRespawnInfo(SpawnObjectType type, ulong spawnId)
{
var map = GetRespawnMapForType(type);
var respawnInfo = map.LookupByKey(spawnId);
if (respawnInfo == null)
return null;
return respawnInfo;
}
Dictionary<ulong, RespawnInfo> GetRespawnMapForType(SpawnObjectType type) { return (type == SpawnObjectType.GameObject) ? _gameObjectRespawnTimesBySpawnId : _creatureRespawnTimesBySpawnId; }
void UnloadAllRespawnInfos() // delete everything from memory
{
_respawnTimes.Clear();
_creatureRespawnTimesBySpawnId.Clear();
_gameObjectRespawnTimesBySpawnId.Clear();
}
void DeleteRespawnInfo(RespawnInfo info, SQLTransaction dbTrans = null)
{
// Delete from all relevant containers to ensure consistency
Cypher.Assert(info != null);
// spawnid store
bool removed = GetRespawnMapForType(info.type).Remove(info.spawnId);
Cypher.Assert(removed, $"Respawn stores inconsistent for map {GetId()}, spawnid {info.spawnId} (type {info.type})");
// respawn heap
_respawnTimes.Remove(info);
// database
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESPAWN);
stmt.AddValue(0, (ushort)info.type);
stmt.AddValue(1, info.spawnId);
stmt.AddValue(2, GetId());
stmt.AddValue(3, GetInstanceId());
DB.Characters.ExecuteOrAppend(dbTrans, stmt);
}
public void RemoveRespawnTime(SpawnObjectType type, ulong spawnId, SQLTransaction dbTrans = null)
{
RespawnInfo info = GetRespawnInfo(type, spawnId);
if (info != null)
DeleteRespawnInfo(info, dbTrans);
}
void ProcessRespawns() void ProcessRespawns()
{ {
long now = GameTime.GetGameTime(); long now = GameTime.GetGameTime();
@@ -2603,8 +2642,11 @@ namespace Game.Maps
return; return;
} }
SpawnData data = Global.ObjectMgr.GetSpawnData(type, spawnId); SpawnMetadata data = Global.ObjectMgr.GetSpawnMetadata(type, spawnId);
if (data == null || data.spawnGroupData == null || !!data.spawnGroupData.flags.HasAnyFlag(SpawnGroupFlags.DynamicSpawnRate)) if (data == null)
return;
if (!data.spawnGroupData.flags.HasFlag(SpawnGroupFlags.DynamicSpawnRate))
return; return;
if (!_zonePlayerCountMap.ContainsKey(obj.GetZoneId())) if (!_zonePlayerCountMap.ContainsKey(obj.GetZoneId()))
@@ -2625,6 +2667,25 @@ namespace Game.Maps
respawnDelay = (uint)Math.Max(Math.Ceiling(respawnDelay * adjustFactor), timeMinimum); respawnDelay = (uint)Math.Max(Math.Ceiling(respawnDelay * adjustFactor), timeMinimum);
} }
public bool ShouldBeSpawnedOnGridLoad<T>(ulong spawnId) { return ShouldBeSpawnedOnGridLoad(SpawnData.TypeFor<T>(), spawnId); }
bool ShouldBeSpawnedOnGridLoad(SpawnObjectType type, ulong spawnId)
{
Cypher.Assert(SpawnData.TypeHasData(type));
// check if the object is on its respawn timer
if (GetRespawnTime(type, spawnId) != 0)
return false;
SpawnMetadata spawnData = Global.ObjectMgr.GetSpawnMetadata(type, spawnId);
// check if the object is part of a spawn group
SpawnGroupTemplateData spawnGroup = spawnData.spawnGroupData;
if (!spawnGroup.flags.HasFlag(SpawnGroupFlags.System))
if (!IsSpawnGroupActive(spawnGroup.groupId))
return false;
return true;
}
SpawnGroupTemplateData GetSpawnGroupData(uint groupId) SpawnGroupTemplateData GetSpawnGroupData(uint groupId)
{ {
SpawnGroupTemplateData data = Global.ObjectMgr.GetSpawnGroupData(groupId); SpawnGroupTemplateData data = Global.ObjectMgr.GetSpawnGroupData(groupId);
@@ -2644,39 +2705,52 @@ namespace Game.Maps
} }
SetSpawnGroupActive(groupId, true); // start processing respawns for the group SetSpawnGroupActive(groupId, true); // start processing respawns for the group
foreach (var data in Global.ObjectMgr.GetSpawnDataForGroup(groupId))
List<SpawnData> toSpawn = new();
foreach (var data in Global.ObjectMgr.GetSpawnMetadataForGroup(groupId))
{ {
Cypher.Assert(groupData.mapId == data.spawnPoint.GetMapId()); Cypher.Assert(groupData.mapId == data.MapId);
// 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); var respawnMap = GetRespawnMapForType(data.type);
if (respawnTime != 0) if (respawnMap == null)
{
if (!force && !ignoreRespawn && respawnTime > GameTime.GetGameTime())
continue;
// we need to remove the respawn time, otherwise we'd end up double spawning
RemoveRespawnTime(data.type, data.spawnId);
}
// don't spawn if the grid isn't loaded (will be handled in grid loader)
if (!IsGridLoaded(data.spawnPoint))
continue; continue;
// Everything OK, now do the actual (re)spawn if (force || ignoreRespawn)
RemoveRespawnTime(data.type, data.SpawnId);
bool hasRespawnTimer = respawnMap.ContainsKey(data.SpawnId);
if (SpawnData.TypeHasData(data.type))
{
// has a respawn timer
if (hasRespawnTimer)
continue;
// has a spawn already active
if (!force)
{
WorldObject obj = GetWorldObjectBySpawnId(data.type, data.SpawnId);
if (obj != null)
if ((data.type != SpawnObjectType.Creature) || obj.ToCreature().IsAlive())
continue;
}
toSpawn.Add(data.ToSpawnData());
}
}
foreach (SpawnData data in toSpawn)
{
// don't spawn if the grid isn't loaded (will be handled in grid loader)
if (!IsGridLoaded(data.SpawnPoint))
continue;
// now do the actual (re)spawn
switch (data.type) switch (data.type)
{ {
case SpawnObjectType.Creature: case SpawnObjectType.Creature:
{ {
Creature creature = new(); Creature creature = new();
if (!creature.LoadFromDB(data.spawnId, this, true, force)) if (!creature.LoadFromDB(data.SpawnId, this, true, force))
creature.Dispose(); creature.Dispose();
else if (spawnedObjects != null) else if (spawnedObjects != null)
spawnedObjects.Add(creature); spawnedObjects.Add(creature);
@@ -2685,14 +2759,23 @@ namespace Game.Maps
case SpawnObjectType.GameObject: case SpawnObjectType.GameObject:
{ {
GameObject gameobject = new(); GameObject gameobject = new();
if (!gameobject.LoadFromDB(data.spawnId, this, true)) if (!gameobject.LoadFromDB(data.SpawnId, this, true))
gameobject.Dispose(); gameobject.Dispose();
else if (spawnedObjects != null) else if (spawnedObjects != null)
spawnedObjects.Add(gameobject); spawnedObjects.Add(gameobject);
break; break;
} }
case SpawnObjectType.AreaTrigger:
{
AreaTrigger areaTrigger = new AreaTrigger();
if (!areaTrigger.LoadFromDB(data.SpawnId, this, true, false))
areaTrigger.Dispose();
else if (spawnedObjects != null)
spawnedObjects.Add(areaTrigger);
break;
}
default: default:
Cypher.Assert(false, $"Invalid spawn type {data.type} with spawnId {data.spawnId}"); Cypher.Assert(false, $"Invalid spawn type {data.type} with spawnId {data.SpawnId}");
return false; return false;
} }
} }
@@ -2704,6 +2787,7 @@ namespace Game.Maps
{ {
return SpawnGroupDespawn(groupId, deleteRespawnTimes, out _); return SpawnGroupDespawn(groupId, deleteRespawnTimes, out _);
} }
public bool SpawnGroupDespawn(uint groupId, bool deleteRespawnTimes, out int count) public bool SpawnGroupDespawn(uint groupId, bool deleteRespawnTimes, out int count)
{ {
count = 0; count = 0;
@@ -2714,39 +2798,14 @@ namespace Game.Maps
return false; return false;
} }
List<WorldObject> toUnload = new(); // unload after iterating, otherwise iterator invalidation foreach (var data in Global.ObjectMgr.GetSpawnMetadataForGroup(groupId))
foreach (var data in Global.ObjectMgr.GetSpawnDataForGroup(groupId))
{ {
Cypher.Assert(groupData.mapId == data.MapId);
if (deleteRespawnTimes) if (deleteRespawnTimes)
RemoveRespawnTime(data.type, data.spawnId); RemoveRespawnTime(data.type, data.SpawnId);
switch (data.type) count += DespawnAll(data.type, data.SpawnId);
{
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;
}
} }
count = toUnload.Count;
// now do the actual despawning
foreach (WorldObject obj in toUnload)
obj.AddObjectToRemoveList();
SetSpawnGroupActive(groupId, false); // stop processing respawns for the group, too SetSpawnGroupActive(groupId, false); // stop processing respawns for the group, too
return true; return true;
} }
@@ -3030,19 +3089,23 @@ namespace Game.Maps
public void SaveRespawnTime(SpawnObjectType type, ulong spawnId, uint entry, long respawnTime, uint gridId = 0, SQLTransaction dbTrans = null, bool startup = false) public void SaveRespawnTime(SpawnObjectType type, ulong spawnId, uint entry, long respawnTime, uint gridId = 0, SQLTransaction dbTrans = null, bool startup = false)
{ {
if (spawnId == 0) SpawnMetadata data = Global.ObjectMgr.GetSpawnMetadata(type, spawnId);
if (data == null)
{
Log.outError(LogFilter.Maps, $"Map {GetId()} attempt to save respawn time for nonexistant spawnid ({type},{spawnId}).");
return; return;
}
if (respawnTime == 0) if (respawnTime == 0)
{ {
// Delete only // Delete only
RemoveRespawnTime(type, spawnId, dbTrans); RemoveRespawnTime(data.type, data.SpawnId, dbTrans);
return; return;
} }
RespawnInfo ri = new(); RespawnInfo ri = new();
ri.type = type; ri.type = data.type;
ri.spawnId = spawnId; ri.spawnId = data.SpawnId;
ri.entry = entry; ri.entry = entry;
ri.respawnTime = respawnTime; ri.respawnTime = respawnTime;
ri.gridId = gridId; ri.gridId = gridId;
@@ -3083,11 +3146,11 @@ namespace Game.Maps
var spawnId = result.Read<ulong>(1); var spawnId = result.Read<ulong>(1);
var respawnTime = result.Read<long>(2); var respawnTime = result.Read<long>(2);
if (type < SpawnObjectType.Max) if (SpawnData.TypeHasData(type))
{ {
SpawnData data = Global.ObjectMgr.GetSpawnData(type, spawnId); SpawnData data = Global.ObjectMgr.GetSpawnData(type, spawnId);
if (data != null) if (data != null)
SaveRespawnTime(type, spawnId, data.Id, respawnTime, GridDefines.ComputeGridCoord(data.spawnPoint.GetPositionX(), data.spawnPoint.GetPositionY()).GetId(), null, true); SaveRespawnTime(type, spawnId, data.Id, respawnTime, GridDefines.ComputeGridCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY()).GetId(), null, true);
else else
Log.outError(LogFilter.Maps, $"Loading saved respawn time of {respawnTime} for spawnid ({type},{spawnId}) - spawn does not exist, ignoring"); Log.outError(LogFilter.Maps, $"Loading saved respawn time of {respawnTime} for spawnid ({type},{spawnId}) - spawn does not exist, ignoring");
} }
@@ -3702,6 +3765,8 @@ namespace Game.Maps
public MultiMap<ulong, GameObject> GetGameObjectBySpawnIdStore() { return _gameobjectBySpawnIdStore; } public MultiMap<ulong, GameObject> GetGameObjectBySpawnIdStore() { return _gameobjectBySpawnIdStore; }
public MultiMap<ulong, AreaTrigger> GetAreaTriggerBySpawnIdStore() { return _areaTriggerBySpawnIdStore; }
public List<Corpse> GetCorpsesInCell(uint cellId) public List<Corpse> GetCorpsesInCell(uint cellId)
{ {
return _corpsesByCell.LookupByKey(cellId); return _corpsesByCell.LookupByKey(cellId);
@@ -3748,12 +3813,17 @@ namespace Game.Maps
public long GetRespawnTime(SpawnObjectType type, ulong spawnId) public long GetRespawnTime(SpawnObjectType type, ulong spawnId)
{ {
var respawnDic = GetRespawnMapForType(type); var map = GetRespawnMapForType(type);
var respawnInfo = respawnDic.LookupByKey(spawnId); if (map != null)
return (respawnInfo == null) ? 0 : respawnInfo.respawnTime; {
var respawnInfo = map.LookupByKey(spawnId);
return (respawnInfo == null) ? 0 : respawnInfo.respawnTime;
}
return 0;
} }
public long GetCreatureRespawnTime(ulong spawnId) { return GetRespawnTime(SpawnObjectType.Creature, spawnId); } public long GetCreatureRespawnTime(ulong spawnId) { return GetRespawnTime(SpawnObjectType.Creature, spawnId); }
public long GetGORespawnTime(ulong spawnId) { return GetRespawnTime(SpawnObjectType.GameObject, spawnId); } public long GetGORespawnTime(ulong spawnId) { return GetRespawnTime(SpawnObjectType.GameObject, spawnId); }
void SetTimer(uint t) void SetTimer(uint t)
@@ -3851,7 +3921,7 @@ namespace Game.Maps
return go ? go.ToTransport() : null; return go ? go.ToTransport() : null;
} }
Creature GetCreatureBySpawnId(ulong spawnId) public Creature GetCreatureBySpawnId(ulong spawnId)
{ {
var bounds = GetCreatureBySpawnIdStore().LookupByKey(spawnId); var bounds = GetCreatureBySpawnIdStore().LookupByKey(spawnId);
if (bounds.Empty()) if (bounds.Empty())
@@ -3862,7 +3932,7 @@ namespace Game.Maps
return foundCreature != null ? foundCreature : bounds[0]; return foundCreature != null ? foundCreature : bounds[0];
} }
GameObject GetGameObjectBySpawnId(ulong spawnId) public GameObject GetGameObjectBySpawnId(ulong spawnId)
{ {
var bounds = GetGameObjectBySpawnIdStore().LookupByKey(spawnId); var bounds = GetGameObjectBySpawnIdStore().LookupByKey(spawnId);
if (bounds.Empty()) if (bounds.Empty())
@@ -3873,6 +3943,15 @@ namespace Game.Maps
return foundGameObject != null ? foundGameObject : bounds[0]; return foundGameObject != null ? foundGameObject : bounds[0];
} }
public AreaTrigger GetAreaTriggerBySpawnId(ulong spawnId)
{
var bounds = GetAreaTriggerBySpawnIdStore().LookupByKey(spawnId);
if (bounds.Empty())
return null;
return bounds.FirstOrDefault();
}
public WorldObject GetWorldObjectBySpawnId(SpawnObjectType type, ulong spawnId) public WorldObject GetWorldObjectBySpawnId(SpawnObjectType type, ulong spawnId)
{ {
switch (type) switch (type)
@@ -3881,6 +3960,8 @@ namespace Game.Maps
return GetCreatureBySpawnId(spawnId); return GetCreatureBySpawnId(spawnId);
case SpawnObjectType.GameObject: case SpawnObjectType.GameObject:
return GetGameObjectBySpawnId(spawnId); return GetGameObjectBySpawnId(spawnId);
case SpawnObjectType.AreaTrigger:
return GetAreaTriggerBySpawnId(spawnId);
default: default:
return null; return null;
} }
@@ -4986,6 +5067,7 @@ namespace Game.Maps
Dictionary<ObjectGuid, WorldObject> _objectsStore = new(); Dictionary<ObjectGuid, WorldObject> _objectsStore = new();
MultiMap<ulong, Creature> _creatureBySpawnIdStore = new(); MultiMap<ulong, Creature> _creatureBySpawnIdStore = new();
MultiMap<ulong, GameObject> _gameobjectBySpawnIdStore = new(); MultiMap<ulong, GameObject> _gameobjectBySpawnIdStore = new();
MultiMap<ulong, AreaTrigger> _areaTriggerBySpawnIdStore = new();
MultiMap<uint, Corpse> _corpsesByCell = new(); MultiMap<uint, Corpse> _corpsesByCell = new();
Dictionary<ObjectGuid, Corpse> _corpsesByPlayer = new(); Dictionary<ObjectGuid, Corpse> _corpsesByPlayer = new();
List<Corpse> _corpseBones = new(); List<Corpse> _corpseBones = new();
+9 -43
View File
@@ -90,52 +90,18 @@ namespace Game.Maps
{ {
foreach (var guid in guid_set) foreach (var guid in guid_set)
{ {
// Don't spawn at all if there's a respawn timer
if (!map.ShouldBeSpawnedOnGridLoad<T>(guid))
continue;
T obj = new(); T obj = new();
// Don't spawn at all if there's a respawn time if (!obj.LoadFromDB(guid, map, false, false))
if ((obj.IsTypeId(TypeId.Unit) && map.GetCreatureRespawnTime(guid) == 0) || (obj.IsTypeId(TypeId.GameObject) && map.GetGORespawnTime(guid) == 0) || obj.IsTypeId(TypeId.AreaTrigger))
{ {
//TC_LOG_INFO("misc", "DEBUG: LoadHelper from table: %s for (guid: %u) Loading", table, guid);
if (obj.IsTypeId(TypeId.Unit))
{
CreatureData cdata = Global.ObjectMgr.GetCreatureData(guid);
Cypher.Assert(cdata != null, $"Tried to load creature with spawnId {guid}, but no such creature exists.");
SpawnGroupTemplateData group = cdata.spawnGroupData;
// If creature in manual spawn group, don't spawn here, unless group is already active.
if (!group.flags.HasAnyFlag(SpawnGroupFlags.System))
{
if (!map.IsSpawnGroupActive(group.groupId))
{
obj.Dispose();
continue;
}
}
}
else if (obj.IsTypeId(TypeId.GameObject))
{
// If gameobject in manual spawn group, don't spawn here, unless group is already active.
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.HasAnyFlag(SpawnGroupFlags.System))
{
if (!map.IsSpawnGroupActive(godata.spawnGroupData.groupId))
{
obj.Dispose();
continue;
}
}
}
if (!obj.LoadFromDB(guid, map, false, false))
{
obj.Dispose();
continue;
}
AddObjectHelper(cell, ref count, map, obj);
}
else
obj.Dispose(); obj.Dispose();
continue;
}
AddObjectHelper(cell, ref count, map, obj);
} }
} }
+42 -13
View File
@@ -29,29 +29,58 @@ namespace Game.Maps
public SpawnGroupFlags flags; public SpawnGroupFlags flags;
} }
public class SpawnData public class SpawnData : SpawnMetadata
{ {
public SpawnObjectType type;
public ulong spawnId;
public uint Id; // entry in respective _template table public uint Id; // entry in respective _template table
public WorldLocation spawnPoint; public Position SpawnPoint;
public PhaseUseFlagsValues phaseUseFlags; public PhaseUseFlagsValues PhaseUseFlags;
public uint phaseId; public uint PhaseId;
public uint phaseGroup; public uint PhaseGroup;
public int terrainSwapMap; public int terrainSwapMap;
public int spawntimesecs; public int spawntimesecs;
public List<Difficulty> spawnDifficulties; public List<Difficulty> spawnDifficulties;
public SpawnGroupTemplateData spawnGroupData;
public uint ScriptId; public uint ScriptId;
public bool dbData;
public SpawnData(SpawnObjectType t) public SpawnData(SpawnObjectType t) : base(t)
{ {
type = t; SpawnPoint = new Position();
spawnPoint = new WorldLocation();
terrainSwapMap = -1; terrainSwapMap = -1;
spawnDifficulties = new List<Difficulty>(); spawnDifficulties = new List<Difficulty>();
dbData = true; }
public static SpawnObjectType TypeFor<T>()
{
switch (typeof(T).Name)
{
case nameof(Creature):
return SpawnObjectType.Creature;
case nameof(GameObject):
return SpawnObjectType.GameObject;
case nameof(AreaTrigger):
return SpawnObjectType.AreaTrigger;
default:
return SpawnObjectType.NumSpawnTypes;
}
} }
} }
public class SpawnMetadata
{
public SpawnObjectType type;
public ulong SpawnId;
public uint MapId = 0xFFFFFFFF;
public bool dbData = true;
public SpawnGroupTemplateData spawnGroupData = null;
public static bool TypeInMask(SpawnObjectType type, SpawnObjectTypeMask mask) { return ((1 << (int)type) & (int)mask) != 0; }
public static bool TypeHasData(SpawnObjectType type) { return type < SpawnObjectType.NumSpawnTypesWithData; }
public static bool TypeIsValid(SpawnObjectType type) { return type < SpawnObjectType.NumSpawnTypes; }
public SpawnMetadata(SpawnObjectType t)
{
type = t;
}
public SpawnData ToSpawnData() { return TypeHasData(type) ? (SpawnData)this : null; }
}
} }
+8 -6
View File
@@ -383,6 +383,8 @@ namespace Game
return IsPartOfAPool<Creature>(spawnId); return IsPartOfAPool<Creature>(spawnId);
case SpawnObjectType.GameObject: case SpawnObjectType.GameObject:
return IsPartOfAPool<GameObject>(spawnId); return IsPartOfAPool<GameObject>(spawnId);
case SpawnObjectType.AreaTrigger:
return 0;
default: default:
Cypher.Assert(false, $"Invalid spawn type {type} passed to PoolMgr.IsPartOfPool (with spawnId {spawnId})"); Cypher.Assert(false, $"Invalid spawn type {type} passed to PoolMgr.IsPartOfPool (with spawnId {spawnId})");
return 0; return 0;
@@ -481,7 +483,7 @@ namespace Game
if (data != null) if (data != null)
{ {
Global.ObjectMgr.RemoveCreatureFromGrid(guid, data); Global.ObjectMgr.RemoveCreatureFromGrid(guid, data);
Map map = Global.MapMgr.FindMap(data.spawnPoint.GetMapId(), 0); Map map = Global.MapMgr.FindMap(data.MapId, 0);
if (map != null && !map.Instanceable()) if (map != null && !map.Instanceable())
{ {
var creatureBounds = map.GetCreatureBySpawnIdStore().LookupByKey(guid); var creatureBounds = map.GetCreatureBySpawnIdStore().LookupByKey(guid);
@@ -503,7 +505,7 @@ namespace Game
if (data != null) if (data != null)
{ {
Global.ObjectMgr.RemoveGameObjectFromGrid(guid, data); Global.ObjectMgr.RemoveGameObjectFromGrid(guid, data);
Map map = Global.MapMgr.FindMap(data.spawnPoint.GetMapId(), 0); Map map = Global.MapMgr.FindMap(data.MapId, 0);
if (map != null && !map.Instanceable()) if (map != null && !map.Instanceable())
{ {
var gameobjectBounds = map.GetGameObjectBySpawnIdStore().LookupByKey(guid); var gameobjectBounds = map.GetGameObjectBySpawnIdStore().LookupByKey(guid);
@@ -620,9 +622,9 @@ namespace Game
Global.ObjectMgr.AddCreatureToGrid(obj.guid, data); Global.ObjectMgr.AddCreatureToGrid(obj.guid, data);
// Spawn if necessary (loaded grids only) // Spawn if necessary (loaded grids only)
Map map = Global.MapMgr.FindMap(data.spawnPoint.GetMapId(), 0); Map map = Global.MapMgr.FindMap(data.MapId, 0);
// We use spawn coords to spawn // We use spawn coords to spawn
if (map != null && !map.Instanceable() && map.IsGridLoaded(data.spawnPoint)) if (map != null && !map.Instanceable() && map.IsGridLoaded(data.SpawnPoint))
Creature.CreateCreatureFromDB(obj.guid, map); Creature.CreateCreatureFromDB(obj.guid, map);
} }
} }
@@ -635,9 +637,9 @@ namespace Game
Global.ObjectMgr.AddGameObjectToGrid(obj.guid, data); Global.ObjectMgr.AddGameObjectToGrid(obj.guid, data);
// Spawn if necessary (loaded grids only) // Spawn if necessary (loaded grids only)
// this base map checked as non-instanced and then only existed // this base map checked as non-instanced and then only existed
Map map = Global.MapMgr.FindMap(data.spawnPoint.GetMapId(), 0); Map map = Global.MapMgr.FindMap(data.MapId, 0);
// We use current coords to unspawn, not spawn coords since creature can have changed grid // We use current coords to unspawn, not spawn coords since creature can have changed grid
if (map != null && !map.Instanceable() && map.IsGridLoaded(data.spawnPoint)) if (map != null && !map.Instanceable() && map.IsGridLoaded(data.SpawnPoint))
{ {
GameObject go = GameObject.CreateGameObjectFromDB(obj.guid, map, false); GameObject go = GameObject.CreateGameObjectFromDB(obj.guid, map, false);
if (go) if (go)