Core/Phasing: Implemented db spawns in personal phases
Port From (https://github.com/TrinityCore/TrinityCore/commit/8fabe5a3aacf7797f03d074ab8434f445be64955)
This commit is contained in:
@@ -770,7 +770,7 @@ namespace Game.Chat
|
||||
else if (target.GetDBPhase() < 0)
|
||||
handler.SendSysMessage($"Target creature's PhaseGroup in DB: {Math.Abs(target.GetDBPhase())}");
|
||||
|
||||
PhasingHandler.PrintToChat(handler, target.GetPhaseShift());
|
||||
PhasingHandler.PrintToChat(handler, target);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -282,9 +282,9 @@ namespace Game.Chat
|
||||
obj.Relocate(x, y, z, obj.GetOrientation());
|
||||
|
||||
// update which cell has this gameobject registered for loading
|
||||
Global.ObjectMgr.RemoveGameObjectFromGrid(guidLow, obj.GetGameObjectData());
|
||||
Global.ObjectMgr.RemoveGameObjectFromGrid(obj.GetGameObjectData());
|
||||
obj.SaveToDB();
|
||||
Global.ObjectMgr.AddGameObjectToGrid(guidLow, obj.GetGameObjectData());
|
||||
Global.ObjectMgr.AddGameObjectToGrid(obj.GetGameObjectData());
|
||||
|
||||
// Generate a completely new spawn with new guid
|
||||
// client caches recently deleted objects and brings them back to life
|
||||
@@ -627,7 +627,7 @@ namespace Game.Chat
|
||||
return false;
|
||||
|
||||
// TODO: is it really necessary to add both the real and DB table guid here ?
|
||||
Global.ObjectMgr.AddGameObjectToGrid(spawnId, Global.ObjectMgr.GetGameObjectData(spawnId));
|
||||
Global.ObjectMgr.AddGameObjectToGrid(Global.ObjectMgr.GetGameObjectData(spawnId));
|
||||
handler.SendSysMessage(CypherStrings.GameobjectAdd, objectId, objectInfo.name, spawnId, player.GetPositionX(), player.GetPositionY(), player.GetPositionZ());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -981,7 +981,7 @@ namespace Game.Chat
|
||||
if (liquidStatus != null)
|
||||
handler.SendSysMessage(CypherStrings.LiquidStatus, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, liquidStatus.type_flags, status);
|
||||
|
||||
PhasingHandler.PrintToChat(handler, obj.GetPhaseShift());
|
||||
PhasingHandler.PrintToChat(handler, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1774,7 +1774,7 @@ namespace Game.Chat
|
||||
|
||||
// Output XIII. phases
|
||||
if (target)
|
||||
PhasingHandler.PrintToChat(handler, target.GetPhaseShift());
|
||||
PhasingHandler.PrintToChat(handler, target);
|
||||
|
||||
// Output XIV. LANG_PINFO_CHR_MONEY
|
||||
ulong gold = money / MoneyConstants.Gold;
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Game.Chat
|
||||
if (data != null)
|
||||
handler.SendSysMessage(CypherStrings.NpcinfoPhases, data.PhaseId, data.PhaseGroup);
|
||||
|
||||
PhasingHandler.PrintToChat(handler, target.GetPhaseShift());
|
||||
PhasingHandler.PrintToChat(handler, target);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.NpcinfoArmor, target.GetArmor());
|
||||
handler.SendSysMessage(CypherStrings.NpcinfoPosition, target.GetPositionX(), target.GetPositionY(), target.GetPositionZ());
|
||||
@@ -239,9 +239,9 @@ namespace Game.Chat
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.ObjectMgr.RemoveCreatureFromGrid(lowguid, data);
|
||||
Global.ObjectMgr.RemoveCreatureFromGrid(data);
|
||||
data.SpawnPoint.Relocate(player);
|
||||
Global.ObjectMgr.AddCreatureToGrid(lowguid, data);
|
||||
Global.ObjectMgr.AddCreatureToGrid(data);
|
||||
|
||||
// update position in DB
|
||||
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.UPD_CREATURE_POSITION);
|
||||
@@ -668,7 +668,7 @@ namespace Game.Chat
|
||||
if (creaturePassenger != null)
|
||||
{
|
||||
creaturePassenger.SaveToDB((uint)trans.GetGoInfo().MoTransport.SpawnMap, new List<Difficulty>() { map.GetDifficultyID() });
|
||||
Global.ObjectMgr.AddCreatureToGrid(guid, data);
|
||||
Global.ObjectMgr.AddCreatureToGrid(data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -689,7 +689,7 @@ namespace Game.Chat
|
||||
if (!creature)
|
||||
return false;
|
||||
|
||||
Global.ObjectMgr.AddCreatureToGrid(db_guid, Global.ObjectMgr.GetCreatureData(db_guid));
|
||||
Global.ObjectMgr.AddCreatureToGrid(Global.ObjectMgr.GetCreatureData(db_guid));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1204,7 +1204,7 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
uint mapId = GetTransport() ? (uint)GetTransport().GetGoInfo().MoTransport.SpawnMap : GetMapId();
|
||||
SaveToDB(mapId, data.spawnDifficulties);
|
||||
SaveToDB(mapId, data.SpawnDifficulties);
|
||||
}
|
||||
|
||||
public virtual void SaveToDB(uint mapid, List<Difficulty> spawnDifficulties)
|
||||
@@ -1274,7 +1274,7 @@ namespace Game.Entities
|
||||
// prevent add data integrity problems
|
||||
data.movementType = (byte)(m_wanderDistance == 0 && GetDefaultMovementType() == MovementGeneratorType.Random
|
||||
? MovementGeneratorType.Idle : GetDefaultMovementType());
|
||||
data.spawnDifficulties = spawnDifficulties;
|
||||
data.SpawnDifficulties = spawnDifficulties;
|
||||
data.npcflag = npcflag;
|
||||
data.unit_flags = unitFlags;
|
||||
data.unit_flags2 = unitFlags2;
|
||||
@@ -1299,7 +1299,7 @@ namespace Game.Entities
|
||||
stmt.AddValue(index++, m_spawnId);
|
||||
stmt.AddValue(index++, GetEntry());
|
||||
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.PhaseGroup);
|
||||
stmt.AddValue(index++, displayId);
|
||||
|
||||
@@ -1018,7 +1018,7 @@ namespace Game.Entities
|
||||
return;
|
||||
}
|
||||
|
||||
SaveToDB(GetMapId(), data.spawnDifficulties);
|
||||
SaveToDB(GetMapId(), data.SpawnDifficulties);
|
||||
}
|
||||
|
||||
public void SaveToDB(uint mapid, List<Difficulty> spawnDifficulties)
|
||||
@@ -1045,7 +1045,7 @@ namespace Game.Entities
|
||||
data.spawntimesecs = (int)(m_spawnedByDefault ? m_respawnDelayTime : -m_respawnDelayTime);
|
||||
data.animprogress = GetGoAnimProgress();
|
||||
data.goState = GetGoState();
|
||||
data.spawnDifficulties = spawnDifficulties;
|
||||
data.SpawnDifficulties = spawnDifficulties;
|
||||
data.artKit = (byte)GetGoArtKit();
|
||||
if (data.spawnGroupData == null)
|
||||
data.spawnGroupData = Global.ObjectMgr.GetDefaultSpawnGroup();
|
||||
@@ -1063,7 +1063,7 @@ namespace Game.Entities
|
||||
stmt.AddValue(index++, m_spawnId);
|
||||
stmt.AddValue(index++, GetEntry());
|
||||
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.PhaseGroup);
|
||||
stmt.AddValue(index++, GetPositionX());
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace Game.Entities
|
||||
if (!pos.IsPositionValid())
|
||||
return;
|
||||
|
||||
player.GetMap().LoadGrid(firstCamera.locations.X, firstCamera.locations.Y);
|
||||
player.GetMap().LoadGridForActiveObject(pos.GetPositionX(), pos.GetPositionY(), player);
|
||||
m_CinematicObject = player.SummonCreature(1, pos.posX, pos.posY, pos.posZ, 0.0f, TempSummonType.TimedDespawn, 5 * Time.Minute * Time.InMilliseconds);
|
||||
if (m_CinematicObject)
|
||||
{
|
||||
|
||||
@@ -2153,6 +2153,13 @@ namespace Game.Entities
|
||||
TeleportTo(m_summon_location);
|
||||
}
|
||||
|
||||
public override void OnPhaseChange()
|
||||
{
|
||||
base.OnPhaseChange();
|
||||
|
||||
GetMap().UpdatePersonalPhasesForPlayer(this);
|
||||
}
|
||||
|
||||
//GM
|
||||
public bool IsAcceptWhispers() { return m_ExtraFlags.HasAnyFlag(PlayerExtraFlags.AcceptWhispers); }
|
||||
public void SetAcceptWhispers(bool on)
|
||||
|
||||
@@ -1222,10 +1222,7 @@ namespace Game.Entities
|
||||
|
||||
public bool IsPossessed() { return HasUnitState(UnitState.Possessed); }
|
||||
|
||||
public void OnPhaseChange()
|
||||
{
|
||||
|
||||
}
|
||||
public virtual void OnPhaseChange() { }
|
||||
|
||||
public uint GetModelForForm(ShapeShiftForm form, uint spellId)
|
||||
{
|
||||
|
||||
@@ -1188,7 +1188,7 @@ namespace Game
|
||||
CreatureData data = Global.ObjectMgr.GetCreatureData(guid);
|
||||
if (data != null)
|
||||
{
|
||||
Global.ObjectMgr.AddCreatureToGrid(guid, data);
|
||||
Global.ObjectMgr.AddCreatureToGrid(data);
|
||||
|
||||
// Spawn if necessary (loaded grids only)
|
||||
Map map = Global.MapMgr.CreateBaseMap(data.MapId);
|
||||
@@ -1212,7 +1212,7 @@ namespace Game
|
||||
GameObjectData data = Global.ObjectMgr.GetGameObjectData(guid);
|
||||
if (data != null)
|
||||
{
|
||||
Global.ObjectMgr.AddGameObjectToGrid(guid, data);
|
||||
Global.ObjectMgr.AddGameObjectToGrid(data);
|
||||
// Spawn if necessary (loaded grids only)
|
||||
// this base map checked as non-instanced and then only existed
|
||||
Map map = Global.MapMgr.CreateBaseMap(data.MapId);
|
||||
@@ -1264,7 +1264,7 @@ namespace Game
|
||||
CreatureData data = Global.ObjectMgr.GetCreatureData(guid);
|
||||
if (data != null)
|
||||
{
|
||||
Global.ObjectMgr.RemoveCreatureFromGrid(guid, data);
|
||||
Global.ObjectMgr.RemoveCreatureFromGrid(data);
|
||||
|
||||
Global.MapMgr.DoForAllMapsWithMapId(data.MapId, map =>
|
||||
{
|
||||
@@ -1292,7 +1292,7 @@ namespace Game
|
||||
GameObjectData data = Global.ObjectMgr.GetGameObjectData(guid);
|
||||
if (data != null)
|
||||
{
|
||||
Global.ObjectMgr.RemoveGameObjectFromGrid(guid, data);
|
||||
Global.ObjectMgr.RemoveGameObjectFromGrid(data);
|
||||
|
||||
Global.MapMgr.DoForAllMapsWithMapId(data.MapId, map =>
|
||||
{
|
||||
|
||||
@@ -2901,7 +2901,7 @@ namespace Game
|
||||
}
|
||||
|
||||
// they must have a possibility to meet (normal/heroic difficulty)
|
||||
if (!master.spawnDifficulties.Intersect(slave.spawnDifficulties).Any())
|
||||
if (!master.SpawnDifficulties.Intersect(slave.SpawnDifficulties).Any())
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "LinkedRespawn: Creature '{0}' linking to '{1}' with not corresponding spawnMask", guidLow, linkedGuidLow);
|
||||
error = true;
|
||||
@@ -2939,7 +2939,7 @@ namespace Game
|
||||
}
|
||||
|
||||
// they must have a possibility to meet (normal/heroic difficulty)
|
||||
if (!master.spawnDifficulties.Intersect(slave.spawnDifficulties).Any())
|
||||
if (!master.SpawnDifficulties.Intersect(slave.SpawnDifficulties).Any())
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "LinkedRespawn: Creature '{0}' linking to '{1}' with not corresponding spawnMask", guidLow, linkedGuidLow);
|
||||
error = true;
|
||||
@@ -2977,7 +2977,7 @@ namespace Game
|
||||
}
|
||||
|
||||
// they must have a possibility to meet (normal/heroic difficulty)
|
||||
if (!master.spawnDifficulties.Intersect(slave.spawnDifficulties).Any())
|
||||
if (!master.SpawnDifficulties.Intersect(slave.SpawnDifficulties).Any())
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "LinkedRespawn: Creature '{0}' linking to '{1}' with not corresponding spawnMask", guidLow, linkedGuidLow);
|
||||
error = true;
|
||||
@@ -3015,7 +3015,7 @@ namespace Game
|
||||
}
|
||||
|
||||
// they must have a possibility to meet (normal/heroic difficulty)
|
||||
if (!master.spawnDifficulties.Intersect(slave.spawnDifficulties).Any())
|
||||
if (!master.SpawnDifficulties.Intersect(slave.SpawnDifficulties).Any())
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "LinkedRespawn: Creature '{0}' linking to '{1}' with not corresponding spawnMask", guidLow, linkedGuidLow);
|
||||
error = true;
|
||||
@@ -3420,7 +3420,7 @@ namespace Game
|
||||
data.curhealth = result.Read<uint>(12);
|
||||
data.curmana = result.Read<uint>(13);
|
||||
data.movementType = result.Read<byte>(14);
|
||||
data.spawnDifficulties = ParseSpawnDifficulties(result.Read<string>(15), "creature", guid, data.MapId, spawnMasks.LookupByKey(data.MapId));
|
||||
data.SpawnDifficulties = ParseSpawnDifficulties(result.Read<string>(15), "creature", guid, data.MapId, spawnMasks.LookupByKey(data.MapId));
|
||||
short gameEvent = result.Read<short>(16);
|
||||
uint PoolId = result.Read<uint>(17);
|
||||
data.npcflag = result.Read<ulong>(18);
|
||||
@@ -3442,7 +3442,7 @@ namespace Game
|
||||
continue;
|
||||
}
|
||||
|
||||
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.");
|
||||
continue;
|
||||
@@ -3566,7 +3566,7 @@ namespace Game
|
||||
|
||||
// Add to grid if not managed by the game event or pool system
|
||||
if (gameEvent == 0 && PoolId == 0)
|
||||
AddCreatureToGrid(guid, data);
|
||||
AddCreatureToGrid(data);
|
||||
|
||||
creatureDataStorage[guid] = data;
|
||||
count++;
|
||||
@@ -3575,27 +3575,92 @@ namespace Game
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} creatures in {1} ms", count, Time.GetMSTimeDiffToNow(time));
|
||||
}
|
||||
|
||||
public void AddCreatureToGrid(ulong guid, CreatureData data)
|
||||
public bool HasPersonalSpawns(uint mapid, Difficulty spawnMode, uint phaseId)
|
||||
{
|
||||
foreach (Difficulty difficulty in data.spawnDifficulties)
|
||||
{
|
||||
CellCoord cellCoord = GridDefines.ComputeCellCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY());
|
||||
var cellguids = CreateCellObjectGuids(data.MapId, difficulty, cellCoord.GetId());
|
||||
cellguids.creatures.Add(guid);
|
||||
}
|
||||
return mapPersonalObjectGuidsStore.ContainsKey((mapid, spawnMode, phaseId));
|
||||
}
|
||||
public void RemoveCreatureFromGrid(ulong guid, CreatureData data)
|
||||
{
|
||||
foreach (Difficulty difficulty in data.spawnDifficulties)
|
||||
{
|
||||
CellCoord cellCoord = GridDefines.ComputeCellCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY());
|
||||
CellObjectGuids cellguids = GetCellObjectGuids(data.MapId, difficulty, cellCoord.GetId());
|
||||
if (cellguids == null)
|
||||
return;
|
||||
|
||||
cellguids.creatures.Remove(guid);
|
||||
public CellObjectGuids GetCellPersonalObjectGuids(uint mapid, Difficulty spawnMode, uint phaseId, uint cell_id)
|
||||
{
|
||||
var guids = mapPersonalObjectGuidsStore.LookupByKey((mapid, spawnMode, phaseId));
|
||||
if (guids != null)
|
||||
return guids.LookupByKey(cell_id);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void AddSpawnDataToGrid(SpawnData data)
|
||||
{
|
||||
uint cellId = GridDefines.ComputeCellCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY()).GetId();
|
||||
bool isPersonalPhase = PhasingHandler.IsPersonalPhase(data.PhaseId);
|
||||
if (!isPersonalPhase)
|
||||
{
|
||||
foreach (Difficulty difficulty in data.SpawnDifficulties)
|
||||
{
|
||||
var key = (data.MapId, difficulty);
|
||||
if (!mapObjectGuidsStore.ContainsKey(key))
|
||||
mapObjectGuidsStore[key] = new();
|
||||
|
||||
if (!mapObjectGuidsStore[key].ContainsKey(cellId))
|
||||
mapObjectGuidsStore[key][cellId] = new();
|
||||
|
||||
mapObjectGuidsStore[key][cellId].AddSpawn(data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Difficulty difficulty in data.SpawnDifficulties)
|
||||
{
|
||||
var key = (data.MapId, difficulty, data.PhaseId);
|
||||
if (!mapPersonalObjectGuidsStore.ContainsKey(key))
|
||||
mapPersonalObjectGuidsStore[key] = new();
|
||||
|
||||
if (!mapPersonalObjectGuidsStore[key].ContainsKey(cellId))
|
||||
mapPersonalObjectGuidsStore[key][cellId] = new();
|
||||
|
||||
mapPersonalObjectGuidsStore[key][cellId].AddSpawn(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveSpawnDataFromGrid(SpawnData data)
|
||||
{
|
||||
uint cellId = GridDefines.ComputeCellCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY()).GetId();
|
||||
bool isPersonalPhase = PhasingHandler.IsPersonalPhase(data.PhaseId);
|
||||
if (!isPersonalPhase)
|
||||
{
|
||||
foreach (Difficulty difficulty in data.SpawnDifficulties)
|
||||
{
|
||||
var key = (data.MapId, difficulty);
|
||||
if (!mapObjectGuidsStore.ContainsKey(key) || !mapObjectGuidsStore[key].ContainsKey(cellId))
|
||||
continue;
|
||||
|
||||
mapObjectGuidsStore[(data.MapId, difficulty)][cellId].RemoveSpawn(data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Difficulty difficulty in data.SpawnDifficulties)
|
||||
{
|
||||
var key = (data.MapId, difficulty, data.PhaseId);
|
||||
if (!mapPersonalObjectGuidsStore.ContainsKey(key) || !mapPersonalObjectGuidsStore[key].ContainsKey(cellId))
|
||||
continue;
|
||||
|
||||
mapPersonalObjectGuidsStore[key][cellId].RemoveSpawn(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddCreatureToGrid(CreatureData data)
|
||||
{
|
||||
AddSpawnDataToGrid(data);
|
||||
}
|
||||
|
||||
public void RemoveCreatureFromGrid(CreatureData data)
|
||||
{
|
||||
RemoveSpawnDataFromGrid(data);
|
||||
}
|
||||
|
||||
public ulong AddCreatureData(uint entry, uint mapId, Position pos, uint spawntimedelay)
|
||||
{
|
||||
CreatureTemplate cInfo = GetCreatureTemplate(entry);
|
||||
@@ -3625,14 +3690,14 @@ namespace Game
|
||||
data.curhealth = (uint)(Global.DB2Mgr.EvaluateExpectedStat(ExpectedStatType.CreatureHealth, level, cInfo.HealthScalingExpansion, scaling.ContentTuningID, (Class)cInfo.UnitClass) * cInfo.ModHealth * cInfo.ModHealthExtra);
|
||||
data.curmana = stats.GenerateMana(cInfo);
|
||||
data.movementType = (byte)cInfo.MovementType;
|
||||
data.spawnDifficulties.Add(Difficulty.None);
|
||||
data.SpawnDifficulties.Add(Difficulty.None);
|
||||
data.dbData = false;
|
||||
data.npcflag = (uint)cInfo.Npcflag;
|
||||
data.unit_flags = (uint)cInfo.UnitFlags;
|
||||
data.dynamicflags = cInfo.DynamicFlags;
|
||||
data.spawnGroupData = GetLegacySpawnGroup();
|
||||
|
||||
AddCreatureToGrid(spawnId, data);
|
||||
AddCreatureToGrid(data);
|
||||
|
||||
// We use spawn coords to spawn
|
||||
if (!map.Instanceable() && !map.IsRemovalGrid(data.SpawnPoint))
|
||||
@@ -3721,7 +3786,7 @@ namespace Game
|
||||
}
|
||||
|
||||
// they must have a possibility to meet (normal/heroic difficulty)
|
||||
if (!master.spawnDifficulties.Intersect(slave.spawnDifficulties).Any())
|
||||
if (!master.SpawnDifficulties.Intersect(slave.SpawnDifficulties).Any())
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "LinkedRespawn: Creature '{0}' linking to '{1}' with not corresponding spawnMask", guidLow, linkedGuidLow);
|
||||
return false;
|
||||
@@ -3748,7 +3813,7 @@ namespace Game
|
||||
CreatureData data = GetCreatureData(spawnId);
|
||||
if (data != null)
|
||||
{
|
||||
RemoveCreatureFromGrid(spawnId, data);
|
||||
RemoveCreatureFromGrid(data);
|
||||
OnDeleteSpawnData(data);
|
||||
}
|
||||
|
||||
@@ -4207,8 +4272,8 @@ namespace Game
|
||||
}
|
||||
data.goState = (GameObjectState)gostate;
|
||||
|
||||
data.spawnDifficulties = ParseSpawnDifficulties(result.Read<string>(14), "gameobject", guid, data.MapId, spawnMasks.LookupByKey(data.MapId));
|
||||
if (data.spawnDifficulties.Empty())
|
||||
data.SpawnDifficulties = ParseSpawnDifficulties(result.Read<string>(14), "gameobject", guid, data.MapId, spawnMasks.LookupByKey(data.MapId));
|
||||
if (data.SpawnDifficulties.Empty())
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `creature` has creature (GUID: {guid}) that is not spawned in any difficulty, skipped.");
|
||||
continue;
|
||||
@@ -4324,7 +4389,7 @@ namespace Game
|
||||
}
|
||||
|
||||
if (gameEvent == 0 && PoolId == 0) // if not this is to be managed by GameEvent System or Pool system
|
||||
AddGameObjectToGrid(guid, data);
|
||||
AddGameObjectToGrid(data);
|
||||
|
||||
gameObjectDataStorage[guid] = data;
|
||||
++count;
|
||||
@@ -4498,26 +4563,13 @@ namespace Game
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} GameObjects for quests in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
public void AddGameObjectToGrid(ulong guid, GameObjectData data)
|
||||
public void AddGameObjectToGrid(GameObjectData data)
|
||||
{
|
||||
foreach (Difficulty difficulty in data.spawnDifficulties)
|
||||
{
|
||||
CellCoord cellCoord = GridDefines.ComputeCellCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY());
|
||||
var cellguids = CreateCellObjectGuids(data.MapId, difficulty, cellCoord.GetId());
|
||||
cellguids.gameobjects.Add(guid);
|
||||
}
|
||||
AddSpawnDataToGrid(data);
|
||||
}
|
||||
public void RemoveGameObjectFromGrid(ulong guid, GameObjectData data)
|
||||
public void RemoveGameObjectFromGrid(GameObjectData data)
|
||||
{
|
||||
foreach (Difficulty difficulty in data.spawnDifficulties)
|
||||
{
|
||||
CellCoord cellCoord = GridDefines.ComputeCellCoord(data.SpawnPoint.GetPositionX(), data.SpawnPoint.GetPositionY());
|
||||
CellObjectGuids cellguids = GetCellObjectGuids(data.MapId, difficulty, cellCoord.GetId());
|
||||
if (cellguids == null)
|
||||
return;
|
||||
|
||||
cellguids.gameobjects.Remove(guid);
|
||||
}
|
||||
RemoveSpawnDataFromGrid(data);
|
||||
}
|
||||
public ulong AddGameObjectData(uint entry, uint mapId, Position pos, Quaternion rot, uint spawntimedelay)
|
||||
{
|
||||
@@ -4538,13 +4590,13 @@ namespace Game
|
||||
data.rotation = rot;
|
||||
data.spawntimesecs = (int)spawntimedelay;
|
||||
data.animprogress = 100;
|
||||
data.spawnDifficulties.Add(Difficulty.None);
|
||||
data.SpawnDifficulties.Add(Difficulty.None);
|
||||
data.goState = GameObjectState.Ready;
|
||||
data.artKit = (byte)(goinfo.type == GameObjectTypes.ControlZone ? 21 : 0);
|
||||
data.dbData = false;
|
||||
data.spawnGroupData = GetLegacySpawnGroup();
|
||||
|
||||
AddGameObjectToGrid(spawnId, data);
|
||||
AddGameObjectToGrid(data);
|
||||
|
||||
// Spawn if necessary (loaded grids only)
|
||||
// We use spawn coords to spawn
|
||||
@@ -4582,7 +4634,7 @@ namespace Game
|
||||
GameObjectData data = GetGameObjectData(spawnId);
|
||||
if (data != null)
|
||||
{
|
||||
RemoveGameObjectFromGrid(spawnId, data);
|
||||
RemoveGameObjectFromGrid(data);
|
||||
OnDeleteSpawnData(data);
|
||||
}
|
||||
|
||||
@@ -10666,6 +10718,7 @@ namespace Game
|
||||
//Maps
|
||||
public Dictionary<uint, GameTele> gameTeleStorage = new();
|
||||
Dictionary<(uint mapId, Difficulty difficulty), Dictionary<uint, CellObjectGuids>> mapObjectGuidsStore = new();
|
||||
Dictionary<(uint mapId, Difficulty diffuculty, uint phaseId), Dictionary<uint, CellObjectGuids>> mapPersonalObjectGuidsStore = new();
|
||||
Dictionary<uint, InstanceTemplate> instanceTemplateStorage = new();
|
||||
public MultiMap<uint, GraveYardData> GraveYardStorage = new();
|
||||
List<ushort> _transportMaps = new();
|
||||
@@ -11064,6 +11117,32 @@ namespace Game
|
||||
{
|
||||
public SortedSet<ulong> creatures = new();
|
||||
public SortedSet<ulong> gameobjects = new();
|
||||
|
||||
public void AddSpawn(SpawnData data)
|
||||
{
|
||||
switch (data.type)
|
||||
{
|
||||
case SpawnObjectType.Creature:
|
||||
creatures.Add(data.SpawnId);
|
||||
break;
|
||||
case SpawnObjectType.GameObject:
|
||||
gameobjects.Add(data.SpawnId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveSpawn(SpawnData data)
|
||||
{
|
||||
switch (data.type)
|
||||
{
|
||||
case SpawnObjectType.Creature:
|
||||
creatures.Remove(data.SpawnId);
|
||||
break;
|
||||
case SpawnObjectType.GameObject:
|
||||
gameobjects.Remove(data.SpawnId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class GameTele
|
||||
|
||||
+29
-1
@@ -461,6 +461,9 @@ namespace Game.Maps
|
||||
EnsureGridLoaded(cell);
|
||||
Grid grid = GetGrid(cell.GetGridX(), cell.GetGridY());
|
||||
|
||||
if (obj.IsPlayer())
|
||||
GetMultiPersonalPhaseTracker().LoadGrid(obj.GetPhaseShift(), grid, this, cell);
|
||||
|
||||
// refresh grid state & timer
|
||||
if (grid.GetGridState() != GridState.Active)
|
||||
{
|
||||
@@ -526,6 +529,11 @@ namespace Game.Maps
|
||||
EnsureGridLoaded(new Cell(x, y));
|
||||
}
|
||||
|
||||
public void LoadGridForActiveObject(float x, float y, WorldObject obj)
|
||||
{
|
||||
EnsureGridLoadedForActiveObject(new Cell(x, y), obj);
|
||||
}
|
||||
|
||||
public virtual bool AddPlayerToMap(Player player, bool initPlayer = true)
|
||||
{
|
||||
CellCoord cellCoord = GridDefines.ComputeCellCoord(player.GetPositionX(), player.GetPositionY());
|
||||
@@ -563,6 +571,12 @@ namespace Game.Maps
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UpdatePersonalPhasesForPlayer(Player player)
|
||||
{
|
||||
Cell cell = new(player.GetPositionX(), player.GetPositionY());
|
||||
GetMultiPersonalPhaseTracker().OnOwnerPhaseChanged(player, GetGrid(cell.GetGridX(), cell.GetGridY()), this, cell);
|
||||
}
|
||||
|
||||
void InitializeObject(WorldObject obj)
|
||||
{
|
||||
if (!obj.IsTypeId(TypeId.Unit) || !obj.IsTypeId(TypeId.GameObject))
|
||||
@@ -823,6 +837,9 @@ namespace Game.Maps
|
||||
_weatherUpdateTimer.Reset();
|
||||
}
|
||||
|
||||
// update phase shift objects
|
||||
GetMultiPersonalPhaseTracker().Update(this, diff);
|
||||
|
||||
MoveAllCreaturesInMoveList();
|
||||
MoveAllGameObjectsInMoveList();
|
||||
MoveAllAreaTriggersInMoveList();
|
||||
@@ -930,6 +947,8 @@ namespace Game.Maps
|
||||
player.UpdateZone(MapConst.InvalidZone, 0);
|
||||
Global.ScriptMgr.OnPlayerLeaveMap(this, player);
|
||||
|
||||
GetMultiPersonalPhaseTracker().MarkAllPhasesForDeletion(player.GetGUID());
|
||||
|
||||
player.CombatStop();
|
||||
|
||||
bool inWorld = player.IsInWorld;
|
||||
@@ -955,6 +974,8 @@ namespace Game.Maps
|
||||
if (obj.IsActiveObject())
|
||||
RemoveFromActive(obj);
|
||||
|
||||
GetMultiPersonalPhaseTracker().UnregisterTrackedObject(obj);
|
||||
|
||||
if (!inWorld) // if was in world, RemoveFromWorld() called DestroyForNearbyPlayers()
|
||||
obj.DestroyForNearbyPlayers(); // previous obj.UpdateObjectVisibility(true)
|
||||
|
||||
@@ -1575,6 +1596,9 @@ namespace Game.Maps
|
||||
|
||||
RemoveAllObjectsInRemoveList();
|
||||
|
||||
// After removing all objects from the map, purge empty tracked phases
|
||||
GetMultiPersonalPhaseTracker().UnloadGrid(grid);
|
||||
|
||||
{
|
||||
ObjectGridUnloader worker = new();
|
||||
var visitor = new Visitor(worker, GridMapTypeMask.AllGrid);
|
||||
@@ -3789,7 +3813,7 @@ namespace Game.Maps
|
||||
public InstanceMap ToInstanceMap() { return IsDungeon() ? (this as InstanceMap) : null; }
|
||||
public BattlegroundMap ToBattlegroundMap() { return IsBattlegroundOrArena() ? (this as BattlegroundMap) : null; }
|
||||
|
||||
void Balance()
|
||||
public void Balance()
|
||||
{
|
||||
_dynamicTree.Balance();
|
||||
}
|
||||
@@ -4118,6 +4142,8 @@ namespace Game.Maps
|
||||
return map != null;
|
||||
}
|
||||
|
||||
public MultiPersonalPhaseTracker GetMultiPersonalPhaseTracker() { return _multiPersonalPhaseTracker; }
|
||||
|
||||
#region Scripts
|
||||
|
||||
// Put scripts in the execution queue
|
||||
@@ -5086,6 +5112,8 @@ namespace Game.Maps
|
||||
|
||||
public delegate void FarSpellCallback(Map map);
|
||||
Queue<FarSpellCallback> _farSpellCallbacks = new();
|
||||
|
||||
MultiPersonalPhaseTracker _multiPersonalPhaseTracker;
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
@@ -22,16 +22,71 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Game.Maps
|
||||
{
|
||||
class ObjectGridLoader : Notifier
|
||||
class ObjectGridLoaderBase : Notifier
|
||||
{
|
||||
public ObjectGridLoader(Grid grid, Map map, Cell cell)
|
||||
internal Cell i_cell;
|
||||
internal Grid i_grid;
|
||||
internal Map i_map;
|
||||
internal uint i_gameObjects;
|
||||
internal uint i_creatures;
|
||||
internal uint i_corpses;
|
||||
internal uint i_areaTriggers;
|
||||
|
||||
public ObjectGridLoaderBase(Grid grid, Map map, Cell cell)
|
||||
{
|
||||
i_cell = new Cell(cell);
|
||||
|
||||
i_grid = grid;
|
||||
i_map = map;
|
||||
}
|
||||
|
||||
public uint GetLoadedCreatures() { return i_creatures; }
|
||||
public uint GetLoadedGameObjects() { return i_gameObjects; }
|
||||
public uint GetLoadedCorpses() { return i_corpses; }
|
||||
public uint GetLoadedAreaTriggers() { return i_areaTriggers; }
|
||||
|
||||
internal void LoadHelper<T>(SortedSet<ulong> guid_set, CellCoord cell, ref uint count, Map map, uint phaseId = 0, ObjectGuid? phaseOwner = null) where T : WorldObject, new()
|
||||
{
|
||||
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();
|
||||
if (!obj.LoadFromDB(guid, map, false, phaseOwner.HasValue /*allowDuplicate*/))
|
||||
{
|
||||
obj.Dispose();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (phaseOwner.HasValue)
|
||||
{
|
||||
PhasingHandler.InitDbPersonalOwnership(obj.GetPhaseShift(), phaseOwner.Value);
|
||||
map.GetMultiPersonalPhaseTracker().RegisterTrackedObject(phaseId, phaseOwner.Value, obj);
|
||||
}
|
||||
|
||||
AddObjectHelper(cell, ref count, map, obj);
|
||||
}
|
||||
}
|
||||
|
||||
void AddObjectHelper<T>(CellCoord cellCoord, ref uint count, Map map, T obj) where T : WorldObject
|
||||
{
|
||||
var cell = new Cell(cellCoord);
|
||||
map.AddToGrid(obj, cell);
|
||||
obj.AddToWorld();
|
||||
|
||||
if (obj.IsCreature())
|
||||
if (obj.IsActiveObject())
|
||||
map.AddToActive(obj);
|
||||
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectGridLoader : ObjectGridLoaderBase
|
||||
{
|
||||
public ObjectGridLoader(Grid grid, Map map, Cell cell) : base(grid, map, cell) { }
|
||||
|
||||
public void LoadN()
|
||||
{
|
||||
i_creatures = 0;
|
||||
@@ -53,7 +108,7 @@ namespace Game.Maps
|
||||
i_grid.VisitGrid(x, y, visitor);
|
||||
}
|
||||
}
|
||||
Log.outDebug(LogFilter.Maps, "{0} GameObjects, {1} Creatures, and {2} Corpses/Bones loaded for grid {3} on map {4}", i_gameObjects, i_creatures, i_corpses, i_grid.GetGridId(), i_map.GetId());
|
||||
Log.outDebug(LogFilter.Maps, $"{i_gameObjects} GameObjects, {i_creatures} Creatures, {i_areaTriggers} AreaTrriggers and {i_corpses} Corpses/Bones loaded for grid {i_grid.GetGridId()} on map {i_map.GetId()}");
|
||||
}
|
||||
|
||||
public override void Visit(IList<GameObject> objs)
|
||||
@@ -85,51 +140,57 @@ namespace Game.Maps
|
||||
|
||||
LoadHelper<AreaTrigger>(areaTriggers, cellCoord, ref i_areaTriggers, i_map);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadHelper<T>(SortedSet<ulong> guid_set, CellCoord cell, ref uint count, Map map) where T : WorldObject, new()
|
||||
class PersonalPhaseGridLoader : ObjectGridLoaderBase
|
||||
{
|
||||
uint _phaseId;
|
||||
ObjectGuid _phaseOwner;
|
||||
|
||||
public PersonalPhaseGridLoader(Grid grid, Map map, Cell cell, ObjectGuid phaseOwner) : base(grid, map, cell)
|
||||
{
|
||||
foreach (var guid in guid_set)
|
||||
_phaseId = 0;
|
||||
_phaseOwner = phaseOwner;
|
||||
}
|
||||
|
||||
public override void Visit(IList<GameObject> objs)
|
||||
{
|
||||
CellCoord cellCoord = i_cell.GetCellCoord();
|
||||
CellObjectGuids cell_guids = Global.ObjectMgr.GetCellPersonalObjectGuids(i_map.GetId(), i_map.GetDifficultyID(), _phaseId, cellCoord.GetId());
|
||||
if (cell_guids != null)
|
||||
LoadHelper<GameObject>(cell_guids.gameobjects, cellCoord, ref i_gameObjects, i_map, _phaseId, _phaseOwner);
|
||||
}
|
||||
|
||||
public override void Visit(IList<Creature> objs)
|
||||
{
|
||||
CellCoord cellCoord = i_cell.GetCellCoord();
|
||||
CellObjectGuids cell_guids = Global.ObjectMgr.GetCellPersonalObjectGuids(i_map.GetId(), i_map.GetDifficultyID(), _phaseId, cellCoord.GetId());
|
||||
if (cell_guids != null)
|
||||
LoadHelper<Creature>(cell_guids.creatures, cellCoord, ref i_creatures, i_map, _phaseId, _phaseOwner);
|
||||
}
|
||||
|
||||
public void Load(uint phaseId)
|
||||
{
|
||||
_phaseId = phaseId;
|
||||
i_cell.data.cell_y = 0;
|
||||
for (uint x = 0; x < MapConst.MaxCells; ++x)
|
||||
{
|
||||
// Don't spawn at all if there's a respawn timer
|
||||
if (!map.ShouldBeSpawnedOnGridLoad<T>(guid))
|
||||
continue;
|
||||
|
||||
T obj = new();
|
||||
if (!obj.LoadFromDB(guid, map, false, false))
|
||||
i_cell.data.cell_x = x;
|
||||
for (uint y = 0; y < MapConst.MaxCells; ++y)
|
||||
{
|
||||
obj.Dispose();
|
||||
continue;
|
||||
}
|
||||
i_cell.data.cell_y = y;
|
||||
|
||||
AddObjectHelper(cell, ref count, map, obj);
|
||||
//Load creatures and game objects
|
||||
var visitor = new Visitor(this, GridMapTypeMask.AllGrid);
|
||||
i_grid.VisitGrid(x, y, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddObjectHelper<T>(CellCoord cellCoord, ref uint count, Map map, T obj) where T : WorldObject
|
||||
{
|
||||
var cell = new Cell(cellCoord);
|
||||
map.AddToGrid(obj, cell);
|
||||
obj.AddToWorld();
|
||||
|
||||
if (obj.IsCreature())
|
||||
if (obj.IsActiveObject())
|
||||
map.AddToActive(obj);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
public Cell i_cell;
|
||||
public Grid i_grid;
|
||||
public Map i_map;
|
||||
uint i_gameObjects;
|
||||
uint i_creatures;
|
||||
public uint i_corpses;
|
||||
uint i_areaTriggers;
|
||||
}
|
||||
|
||||
class ObjectWorldLoader : Notifier
|
||||
{
|
||||
public ObjectWorldLoader(ObjectGridLoader gloader)
|
||||
public ObjectWorldLoader(ObjectGridLoaderBase gloader)
|
||||
{
|
||||
i_cell = gloader.i_cell;
|
||||
i_map = gloader.i_map;
|
||||
|
||||
@@ -38,14 +38,14 @@ namespace Game.Maps
|
||||
public uint PhaseGroup;
|
||||
public int terrainSwapMap;
|
||||
public int spawntimesecs;
|
||||
public List<Difficulty> spawnDifficulties;
|
||||
public List<Difficulty> SpawnDifficulties;
|
||||
public uint ScriptId;
|
||||
|
||||
public SpawnData(SpawnObjectType t) : base(t)
|
||||
{
|
||||
SpawnPoint = new Position();
|
||||
terrainSwapMap = -1;
|
||||
spawnDifficulties = new List<Difficulty>();
|
||||
SpawnDifficulties = new List<Difficulty>();
|
||||
}
|
||||
|
||||
public static SpawnObjectType TypeFor<T>()
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Dynamic;
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
class PersonalPhaseSpawns
|
||||
{
|
||||
public static TimeSpan DELETE_TIME_DEFAULT = TimeSpan.FromMinutes(1);
|
||||
|
||||
public List<WorldObject> Objects = new();
|
||||
public List<ushort> Grids = new();
|
||||
public Optional<TimeSpan> DurationRemaining;
|
||||
|
||||
public bool IsEmpty() { return Objects.Empty() && Grids.Empty(); }
|
||||
}
|
||||
|
||||
class PlayerPersonalPhasesTracker
|
||||
{
|
||||
Dictionary<uint, PersonalPhaseSpawns> _spawns = new();
|
||||
|
||||
public void RegisterTrackedObject(uint phaseId, WorldObject obj)
|
||||
{
|
||||
_spawns[phaseId].Objects.Add(obj);
|
||||
}
|
||||
|
||||
public void UnregisterTrackedObject(WorldObject obj)
|
||||
{
|
||||
foreach (var spawns in _spawns.Values)
|
||||
spawns.Objects.Remove(obj);
|
||||
}
|
||||
|
||||
public void OnOwnerPhasesChanged(WorldObject owner)
|
||||
{
|
||||
PhaseShift phaseShift = owner.GetPhaseShift();
|
||||
|
||||
// Loop over all our tracked phases. If any don't exist - delete them
|
||||
foreach (var (phaseId, spawns) in _spawns)
|
||||
if (!spawns.DurationRemaining.HasValue && !phaseShift.HasPhase(phaseId))
|
||||
spawns.DurationRemaining.Set(PersonalPhaseSpawns.DELETE_TIME_DEFAULT);
|
||||
|
||||
// loop over all owner phases. If any exist and marked for deletion - reset delete
|
||||
foreach (var phaseRef in phaseShift.GetPhases())
|
||||
{
|
||||
PersonalPhaseSpawns spawns = _spawns.LookupByKey(phaseRef.Key);
|
||||
if (spawns != null)
|
||||
spawns.DurationRemaining.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkAllPhasesForDeletion()
|
||||
{
|
||||
foreach (var spawns in _spawns.Values)
|
||||
spawns.DurationRemaining.Set(PersonalPhaseSpawns.DELETE_TIME_DEFAULT);
|
||||
}
|
||||
|
||||
public void Update(Map map, uint diff)
|
||||
{
|
||||
foreach (var itr in _spawns.ToList())
|
||||
{
|
||||
if (itr.Value.DurationRemaining.HasValue)
|
||||
{
|
||||
itr.Value.DurationRemaining.Value = itr.Value.DurationRemaining.Value - TimeSpan.FromMilliseconds(diff);
|
||||
if (itr.Value.DurationRemaining.Value <= TimeSpan.Zero)
|
||||
{
|
||||
DespawnPhase(map, itr.Value);
|
||||
_spawns.Remove(itr.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsGridLoadedForPhase(uint gridId, uint phaseId)
|
||||
{
|
||||
PersonalPhaseSpawns spawns = _spawns.LookupByKey(phaseId);
|
||||
if (spawns != null)
|
||||
return spawns.Grids.Contains((ushort)gridId);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetGridLoadedForPhase(uint gridId, uint phaseId)
|
||||
{
|
||||
if (!_spawns.ContainsKey(phaseId))
|
||||
_spawns[phaseId] = new();
|
||||
|
||||
PersonalPhaseSpawns group = _spawns[phaseId];
|
||||
group.Grids.Add((ushort)gridId);
|
||||
}
|
||||
|
||||
public void SetGridUnloaded(uint gridId)
|
||||
{
|
||||
foreach (var itr in _spawns.ToList())
|
||||
{
|
||||
itr.Value.Grids.Remove((ushort)gridId);
|
||||
if (itr.Value.IsEmpty())
|
||||
_spawns.Remove(itr.Key);
|
||||
}
|
||||
}
|
||||
|
||||
void DespawnPhase(Map map, PersonalPhaseSpawns spawns)
|
||||
{
|
||||
foreach (var obj in spawns.Objects)
|
||||
map.AddObjectToRemoveList(obj);
|
||||
|
||||
spawns.Objects.Clear();
|
||||
spawns.Grids.Clear();
|
||||
}
|
||||
|
||||
public bool IsEmpty() { return _spawns.Empty(); }
|
||||
}
|
||||
|
||||
public class MultiPersonalPhaseTracker
|
||||
{
|
||||
Dictionary<ObjectGuid, PlayerPersonalPhasesTracker> _playerData = new();
|
||||
|
||||
public void LoadGrid(PhaseShift phaseShift, Grid grid, Map map, Cell cell)
|
||||
{
|
||||
if (!phaseShift.HasPersonalPhase())
|
||||
return;
|
||||
|
||||
PersonalPhaseGridLoader loader = new(grid, map, cell, phaseShift.GetPersonalGuid());
|
||||
PlayerPersonalPhasesTracker playerTracker = _playerData[phaseShift.GetPersonalGuid()];
|
||||
|
||||
foreach (var phaseRef in phaseShift.GetPhases())
|
||||
{
|
||||
if (!phaseRef.Value.IsPersonal())
|
||||
continue;
|
||||
|
||||
if (!Global.ObjectMgr.HasPersonalSpawns(map.GetId(), map.GetDifficultyID(), phaseRef.Key))
|
||||
continue;
|
||||
|
||||
if (playerTracker.IsGridLoadedForPhase(grid.GetGridId(), phaseRef.Key))
|
||||
continue;
|
||||
|
||||
Log.outDebug(LogFilter.Maps, $"Loading personal phase objects (phase {phaseRef.Key}) in {cell} for map {map.GetId()} instance {map.GetInstanceId()}");
|
||||
|
||||
loader.Load(phaseRef.Key);
|
||||
|
||||
playerTracker.SetGridLoadedForPhase(grid.GetGridId(), phaseRef.Key);
|
||||
}
|
||||
|
||||
if (loader.GetLoadedGameObjects() != 0)
|
||||
map.Balance();
|
||||
}
|
||||
|
||||
public void UnloadGrid(Grid grid)
|
||||
{
|
||||
foreach (var itr in _playerData.ToList())
|
||||
{
|
||||
itr.Value.SetGridUnloaded(grid.GetGridId());
|
||||
if (itr.Value.IsEmpty())
|
||||
_playerData.Remove(itr.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterTrackedObject(uint phaseId, ObjectGuid phaseOwner, WorldObject obj)
|
||||
{
|
||||
Cypher.Assert(phaseId != 0);
|
||||
Cypher.Assert(!phaseOwner.IsEmpty());
|
||||
Cypher.Assert(obj != null);
|
||||
|
||||
_playerData[phaseOwner].RegisterTrackedObject(phaseId, obj);
|
||||
}
|
||||
|
||||
public void UnregisterTrackedObject(WorldObject obj)
|
||||
{
|
||||
PlayerPersonalPhasesTracker playerTracker = _playerData.LookupByKey(obj.GetPhaseShift().GetPersonalGuid());
|
||||
if (playerTracker != null)
|
||||
playerTracker.UnregisterTrackedObject(obj);
|
||||
}
|
||||
|
||||
public void OnOwnerPhaseChanged(WorldObject phaseOwner, Grid grid, Map map, Cell cell)
|
||||
{
|
||||
PlayerPersonalPhasesTracker playerTracker = _playerData.LookupByKey(phaseOwner.GetGUID());
|
||||
if (playerTracker != null)
|
||||
playerTracker.OnOwnerPhasesChanged(phaseOwner);
|
||||
|
||||
if (grid != null)
|
||||
LoadGrid(phaseOwner.GetPhaseShift(), grid, map, cell);
|
||||
}
|
||||
|
||||
public void MarkAllPhasesForDeletion(ObjectGuid phaseOwner)
|
||||
{
|
||||
PlayerPersonalPhasesTracker playerTracker = _playerData.LookupByKey(phaseOwner);
|
||||
if (playerTracker != null)
|
||||
playerTracker.MarkAllPhasesForDeletion();
|
||||
}
|
||||
|
||||
public void Update(Map map, uint diff)
|
||||
{
|
||||
foreach (var itr in _playerData.ToList())
|
||||
{
|
||||
itr.Value.Update(map, diff);
|
||||
if (itr.Value.IsEmpty())
|
||||
_playerData.Remove(itr.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,6 +230,15 @@ namespace Game
|
||||
PersonalGuid.Clear();
|
||||
}
|
||||
|
||||
public bool HasPersonalPhase()
|
||||
{
|
||||
foreach (PhaseRef phaseRef in GetPhases().Values)
|
||||
if (phaseRef.IsPersonal())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool HasPhase(uint phaseId) { return Phases.ContainsKey(phaseId); }
|
||||
public Dictionary<uint, PhaseRef> GetPhases() { return Phases; }
|
||||
|
||||
@@ -239,6 +248,8 @@ namespace Game
|
||||
public bool HasUiWorldMapAreaIdSwap(uint uiWorldMapAreaId) { return UiMapPhaseIds.ContainsKey(uiWorldMapAreaId); }
|
||||
public Dictionary<uint, UiMapPhaseIdRef> GetUiMapPhaseIds() { return UiMapPhaseIds; }
|
||||
|
||||
public ObjectGuid GetPersonalGuid() { return PersonalGuid; }
|
||||
|
||||
public PhaseShiftFlags Flags = PhaseShiftFlags.Unphased;
|
||||
public ObjectGuid PersonalGuid;
|
||||
public Dictionary<uint, PhaseRef> Phases = new();
|
||||
@@ -261,6 +272,8 @@ namespace Game
|
||||
AreaConditions = conditions;
|
||||
}
|
||||
|
||||
public bool IsPersonal() { return Flags.HasFlag(PhaseFlags.Personal); }
|
||||
|
||||
public PhaseFlags Flags;
|
||||
public int References;
|
||||
public List<Condition> AreaConditions;
|
||||
|
||||
@@ -487,6 +487,13 @@ namespace Game
|
||||
phaseShift.Flags = flags;
|
||||
}
|
||||
|
||||
public static void InitDbPersonalOwnership(PhaseShift phaseShift, ObjectGuid personalGuid)
|
||||
{
|
||||
Cypher.Assert(phaseShift.IsDbPhaseShift);
|
||||
Cypher.Assert(phaseShift.HasPersonalPhase());
|
||||
phaseShift.PersonalGuid = personalGuid;
|
||||
}
|
||||
|
||||
public static void InitDbVisibleMapId(PhaseShift phaseShift, int visibleMapId)
|
||||
{
|
||||
phaseShift.VisibleMapIds.Clear();
|
||||
@@ -542,9 +549,20 @@ namespace Game
|
||||
UpdateVisibilityIfNeeded(obj, updateVisibility, true);
|
||||
}
|
||||
|
||||
public static void PrintToChat(CommandHandler chat, PhaseShift phaseShift)
|
||||
public static void PrintToChat(CommandHandler chat, WorldObject target)
|
||||
{
|
||||
chat.SendSysMessage(CypherStrings.PhaseshiftStatus, phaseShift.Flags, phaseShift.PersonalGuid.ToString());
|
||||
PhaseShift phaseShift = target.GetPhaseShift();
|
||||
|
||||
string phaseOwnerName = "N/A";
|
||||
if (phaseShift.HasPersonalPhase())
|
||||
{
|
||||
WorldObject personalGuid = Global.ObjAccessor.GetWorldObject(target, phaseShift.PersonalGuid);
|
||||
if (personalGuid != null)
|
||||
phaseOwnerName = personalGuid.GetName();
|
||||
}
|
||||
|
||||
chat.SendSysMessage(CypherStrings.PhaseshiftStatus, phaseShift.Flags, phaseShift.PersonalGuid.ToString(), phaseOwnerName);
|
||||
|
||||
if (!phaseShift.Phases.Empty())
|
||||
{
|
||||
StringBuilder phases = new();
|
||||
@@ -592,6 +610,15 @@ namespace Game
|
||||
return phases.ToString();
|
||||
}
|
||||
|
||||
public static bool IsPersonalPhase(uint phaseId)
|
||||
{
|
||||
var phase = CliDB.PhaseStorage.LookupByKey(phaseId);
|
||||
if (phase != null)
|
||||
return phase.Flags.HasFlag(PhaseEntryFlags.Personal);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void UpdateVisibilityIfNeeded(WorldObject obj, bool updateVisibility, bool changed)
|
||||
{
|
||||
if (changed && obj.IsInWorld)
|
||||
|
||||
@@ -482,7 +482,7 @@ namespace Game
|
||||
var data = Global.ObjectMgr.GetCreatureData(guid);
|
||||
if (data != null)
|
||||
{
|
||||
Global.ObjectMgr.RemoveCreatureFromGrid(guid, data);
|
||||
Global.ObjectMgr.RemoveCreatureFromGrid(data);
|
||||
Map map = Global.MapMgr.FindMap(data.MapId, 0);
|
||||
if (map != null && !map.Instanceable())
|
||||
{
|
||||
@@ -504,7 +504,7 @@ namespace Game
|
||||
var data = Global.ObjectMgr.GetGameObjectData(guid);
|
||||
if (data != null)
|
||||
{
|
||||
Global.ObjectMgr.RemoveGameObjectFromGrid(guid, data);
|
||||
Global.ObjectMgr.RemoveGameObjectFromGrid(data);
|
||||
Map map = Global.MapMgr.FindMap(data.MapId, 0);
|
||||
if (map != null && !map.Instanceable())
|
||||
{
|
||||
@@ -619,7 +619,7 @@ namespace Game
|
||||
CreatureData data = Global.ObjectMgr.GetCreatureData(obj.guid);
|
||||
if (data != null)
|
||||
{
|
||||
Global.ObjectMgr.AddCreatureToGrid(obj.guid, data);
|
||||
Global.ObjectMgr.AddCreatureToGrid(data);
|
||||
|
||||
// Spawn if necessary (loaded grids only)
|
||||
Map map = Global.MapMgr.FindMap(data.MapId, 0);
|
||||
@@ -634,7 +634,7 @@ namespace Game
|
||||
GameObjectData data = Global.ObjectMgr.GetGameObjectData(obj.guid);
|
||||
if (data != null)
|
||||
{
|
||||
Global.ObjectMgr.AddGameObjectToGrid(obj.guid, data);
|
||||
Global.ObjectMgr.AddGameObjectToGrid(data);
|
||||
// Spawn if necessary (loaded grids only)
|
||||
// this base map checked as non-instanced and then only existed
|
||||
Map map = Global.MapMgr.FindMap(data.MapId, 0);
|
||||
|
||||
Reference in New Issue
Block a user