From 75317356695aca44709fefd0d85efb06092b0cd7 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Thu, 27 Jan 2022 14:01:49 -0500 Subject: [PATCH] Core/Phasing: Implemented db spawns in personal phases Port From (https://github.com/TrinityCore/TrinityCore/commit/8fabe5a3aacf7797f03d074ab8434f445be64955) --- Source/Game/Chat/Commands/DebugCommands.cs | 2 +- .../Game/Chat/Commands/GameObjectCommands.cs | 6 +- Source/Game/Chat/Commands/MiscCommands.cs | 4 +- Source/Game/Chat/Commands/NPCCommands.cs | 10 +- Source/Game/Entities/Creature/Creature.cs | 6 +- Source/Game/Entities/GameObject/GameObject.cs | 6 +- .../Game/Entities/Player/CinematicManager.cs | 2 +- Source/Game/Entities/Player/Player.cs | 7 + Source/Game/Entities/Unit/Unit.cs | 5 +- Source/Game/Events/GameEventManager.cs | 8 +- Source/Game/Globals/ObjectManager.cs | 179 ++++++++++---- Source/Game/Maps/Map.cs | 30 ++- Source/Game/Maps/ObjectGridLoader.cs | 137 ++++++++--- Source/Game/Maps/SpawnData.cs | 4 +- Source/Game/Phasing/PersonalPhaseTracker.cs | 220 ++++++++++++++++++ Source/Game/Phasing/PhaseShift.cs | 13 ++ Source/Game/Phasing/PhasingHandler.cs | 31 ++- Source/Game/Pools/PoolManager.cs | 8 +- 18 files changed, 555 insertions(+), 123 deletions(-) create mode 100644 Source/Game/Phasing/PersonalPhaseTracker.cs diff --git a/Source/Game/Chat/Commands/DebugCommands.cs b/Source/Game/Chat/Commands/DebugCommands.cs index d42dd2e94..75cd75012 100644 --- a/Source/Game/Chat/Commands/DebugCommands.cs +++ b/Source/Game/Chat/Commands/DebugCommands.cs @@ -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; } diff --git a/Source/Game/Chat/Commands/GameObjectCommands.cs b/Source/Game/Chat/Commands/GameObjectCommands.cs index f587f726d..6e93d91e9 100644 --- a/Source/Game/Chat/Commands/GameObjectCommands.cs +++ b/Source/Game/Chat/Commands/GameObjectCommands.cs @@ -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; } diff --git a/Source/Game/Chat/Commands/MiscCommands.cs b/Source/Game/Chat/Commands/MiscCommands.cs index f36b1eb35..449ebe8d7 100644 --- a/Source/Game/Chat/Commands/MiscCommands.cs +++ b/Source/Game/Chat/Commands/MiscCommands.cs @@ -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; diff --git a/Source/Game/Chat/Commands/NPCCommands.cs b/Source/Game/Chat/Commands/NPCCommands.cs index f9b0904c7..b46073068 100644 --- a/Source/Game/Chat/Commands/NPCCommands.cs +++ b/Source/Game/Chat/Commands/NPCCommands.cs @@ -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() { 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; } diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 81ede10d4..2fd788229 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -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 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); diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index 6900343a7..c03240d68 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -1018,7 +1018,7 @@ namespace Game.Entities return; } - SaveToDB(GetMapId(), data.spawnDifficulties); + SaveToDB(GetMapId(), data.SpawnDifficulties); } public void SaveToDB(uint mapid, List 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()); diff --git a/Source/Game/Entities/Player/CinematicManager.cs b/Source/Game/Entities/Player/CinematicManager.cs index 49b5f6723..882f3d7bb 100644 --- a/Source/Game/Entities/Player/CinematicManager.cs +++ b/Source/Game/Entities/Player/CinematicManager.cs @@ -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) { diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 68e1811c2..705c8e081 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -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) diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index dcd36e3bd..75378733e 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -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) { diff --git a/Source/Game/Events/GameEventManager.cs b/Source/Game/Events/GameEventManager.cs index ff5d24354..5c3ac8edb 100644 --- a/Source/Game/Events/GameEventManager.cs +++ b/Source/Game/Events/GameEventManager.cs @@ -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 => { diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 446ca3042..b65c67bd3 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -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(12); data.curmana = result.Read(13); data.movementType = result.Read(14); - data.spawnDifficulties = ParseSpawnDifficulties(result.Read(15), "creature", guid, data.MapId, spawnMasks.LookupByKey(data.MapId)); + data.SpawnDifficulties = ParseSpawnDifficulties(result.Read(15), "creature", guid, data.MapId, spawnMasks.LookupByKey(data.MapId)); short gameEvent = result.Read(16); uint PoolId = result.Read(17); data.npcflag = result.Read(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(14), "gameobject", guid, data.MapId, spawnMasks.LookupByKey(data.MapId)); - if (data.spawnDifficulties.Empty()) + data.SpawnDifficulties = ParseSpawnDifficulties(result.Read(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 gameTeleStorage = new(); Dictionary<(uint mapId, Difficulty difficulty), Dictionary> mapObjectGuidsStore = new(); + Dictionary<(uint mapId, Difficulty diffuculty, uint phaseId), Dictionary> mapPersonalObjectGuidsStore = new(); Dictionary instanceTemplateStorage = new(); public MultiMap GraveYardStorage = new(); List _transportMaps = new(); @@ -11064,6 +11117,32 @@ namespace Game { public SortedSet creatures = new(); public SortedSet 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 diff --git a/Source/Game/Maps/Map.cs b/Source/Game/Maps/Map.cs index 3ab10232c..71614d818 100644 --- a/Source/Game/Maps/Map.cs +++ b/Source/Game/Maps/Map.cs @@ -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 _farSpellCallbacks = new(); + + MultiPersonalPhaseTracker _multiPersonalPhaseTracker; #endregion } diff --git a/Source/Game/Maps/ObjectGridLoader.cs b/Source/Game/Maps/ObjectGridLoader.cs index d44a38096..395da0d36 100644 --- a/Source/Game/Maps/ObjectGridLoader.cs +++ b/Source/Game/Maps/ObjectGridLoader.cs @@ -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(SortedSet 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(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(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 objs) @@ -85,51 +140,57 @@ namespace Game.Maps LoadHelper(areaTriggers, cellCoord, ref i_areaTriggers, i_map); } + } - void LoadHelper(SortedSet 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 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(cell_guids.gameobjects, cellCoord, ref i_gameObjects, i_map, _phaseId, _phaseOwner); + } + + public override void Visit(IList 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(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(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(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; diff --git a/Source/Game/Maps/SpawnData.cs b/Source/Game/Maps/SpawnData.cs index 2e2c3d694..8846a5d18 100644 --- a/Source/Game/Maps/SpawnData.cs +++ b/Source/Game/Maps/SpawnData.cs @@ -38,14 +38,14 @@ namespace Game.Maps public uint PhaseGroup; public int terrainSwapMap; public int spawntimesecs; - public List spawnDifficulties; + public List SpawnDifficulties; public uint ScriptId; public SpawnData(SpawnObjectType t) : base(t) { SpawnPoint = new Position(); terrainSwapMap = -1; - spawnDifficulties = new List(); + SpawnDifficulties = new List(); } public static SpawnObjectType TypeFor() diff --git a/Source/Game/Phasing/PersonalPhaseTracker.cs b/Source/Game/Phasing/PersonalPhaseTracker.cs new file mode 100644 index 000000000..2ec50c8bf --- /dev/null +++ b/Source/Game/Phasing/PersonalPhaseTracker.cs @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2012-2020 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 . + */ + +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 Objects = new(); + public List Grids = new(); + public Optional DurationRemaining; + + public bool IsEmpty() { return Objects.Empty() && Grids.Empty(); } + } + + class PlayerPersonalPhasesTracker + { + Dictionary _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 _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); + } + } + } +} diff --git a/Source/Game/Phasing/PhaseShift.cs b/Source/Game/Phasing/PhaseShift.cs index 9668f3da4..b32ff1d7d 100644 --- a/Source/Game/Phasing/PhaseShift.cs +++ b/Source/Game/Phasing/PhaseShift.cs @@ -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 GetPhases() { return Phases; } @@ -239,6 +248,8 @@ namespace Game public bool HasUiWorldMapAreaIdSwap(uint uiWorldMapAreaId) { return UiMapPhaseIds.ContainsKey(uiWorldMapAreaId); } public Dictionary GetUiMapPhaseIds() { return UiMapPhaseIds; } + public ObjectGuid GetPersonalGuid() { return PersonalGuid; } + public PhaseShiftFlags Flags = PhaseShiftFlags.Unphased; public ObjectGuid PersonalGuid; public Dictionary 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 AreaConditions; diff --git a/Source/Game/Phasing/PhasingHandler.cs b/Source/Game/Phasing/PhasingHandler.cs index beb8b0046..5e5914d61 100644 --- a/Source/Game/Phasing/PhasingHandler.cs +++ b/Source/Game/Phasing/PhasingHandler.cs @@ -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) diff --git a/Source/Game/Pools/PoolManager.cs b/Source/Game/Pools/PoolManager.cs index 3458d36cc..f0d8e44f4 100644 --- a/Source/Game/Pools/PoolManager.cs +++ b/Source/Game/Pools/PoolManager.cs @@ -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);