diff --git a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs index b6c8de5f7..7ff6a6926 100644 --- a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs +++ b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs @@ -1020,10 +1020,7 @@ namespace Game.Entities public override bool IsNeverVisibleFor(WorldObject seer) { - if (IsServerSide()) - return true; - - return base.IsNeverVisibleFor(seer); + return base.IsNeverVisibleFor(seer) || IsServerSide(); } [System.Diagnostics.Conditional("DEBUG")] diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 14bfadc34..5ab34d0cb 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -211,7 +211,7 @@ namespace Game.Entities data.AddUpdateBlock(buffer); } - void BuildDestroyUpdateBlock(UpdateData data) + public void BuildDestroyUpdateBlock(UpdateData data) { data.AddDestroyObject(GetGUID()); } @@ -230,6 +230,16 @@ namespace Game.Entities target.SendPacket(packet); } + public void SendOutOfRangeForPlayer(Player target) + { + Cypher.Assert(target); + + UpdateData updateData = new(target.GetMapId()); + BuildOutOfRangeUpdateBlock(updateData); + updateData.BuildPacket(out UpdateObject packet); + target.SendPacket(packet); + } + public void BuildMovementUpdate(WorldPacket data, CreateObjectBits flags) { int PauseTimesCount = 0; @@ -2868,7 +2878,9 @@ namespace Game.Entities public virtual bool HasQuest(uint questId) { return false; } public virtual bool HasInvolvedQuest(uint questId) { return false; } public void SetIsNewObject(bool enable) { _isNewObject = enable; } - + public bool IsDestroyedObject() { return _isDestroyedObject; } + public void SetDestroyedObject(bool destroyed) { _isDestroyedObject = destroyed; } + public bool IsCreature() { return GetTypeId() == TypeId.Unit; } public bool IsPlayer() { return GetTypeId() == TypeId.Player; } public bool IsGameObject() { return GetTypeId() == TypeId.GameObject; } @@ -2926,7 +2938,7 @@ namespace Game.Entities public virtual float GetCollisionHeight() { return 0.0f; } public float GetMidsectionHeight() { return GetCollisionHeight() / 2.0f; } - public virtual bool IsNeverVisibleFor(WorldObject seer) { return !IsInWorld; } + public virtual bool IsNeverVisibleFor(WorldObject seer) { return !IsInWorld || IsDestroyedObject(); } public virtual bool IsAlwaysVisibleFor(WorldObject seer) { return false; } public virtual bool IsInvisibleDueToDespawn() { return false; } public virtual bool IsAlwaysDetectableFor(WorldObject seer) { return false; } @@ -3558,6 +3570,7 @@ namespace Game.Entities protected CreateObjectBits m_updateFlag; ObjectGuid m_guid; bool _isNewObject; + bool _isDestroyedObject; public UpdateFieldHolder m_values; public ObjectFieldData m_objectData; diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index b5282f1f6..e7da166f8 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -6071,7 +6071,11 @@ namespace Game.Entities if (target.IsTypeId(TypeId.Unit)) BeforeVisibilityDestroy(target.ToCreature(), this); - target.DestroyForPlayer(this); + if (!target.IsDestroyedObject()) + target.SendOutOfRangeForPlayer(this); + else + target.DestroyForPlayer(this); + m_clientGUIDs.Remove(target.GetGUID()); } } @@ -6097,7 +6101,11 @@ namespace Game.Entities { BeforeVisibilityDestroy(target, this); - target.BuildOutOfRangeUpdateBlock(data); + if (!target.IsDestroyedObject()) + target.BuildOutOfRangeUpdateBlock(data); + else + target.BuildDestroyUpdateBlock(data); + m_clientGUIDs.Remove(target.GetGUID()); } } diff --git a/Source/Game/Maps/Map.cs b/Source/Game/Maps/Map.cs index 7404d184f..9c3d493cb 100644 --- a/Source/Game/Maps/Map.cs +++ b/Source/Game/Maps/Map.cs @@ -2916,6 +2916,7 @@ namespace Game.Maps { Cypher.Assert(obj.GetMapId() == GetId() && obj.GetInstanceId() == GetInstanceId()); + obj.SetDestroyedObject(true); obj.CleanupsBeforeDelete(false); // remove or simplify at least cross referenced links i_objectsToRemove.Add(obj); diff --git a/Source/Game/Maps/ObjectGridLoader.cs b/Source/Game/Maps/ObjectGridLoader.cs index 395da0d36..fa6211cf9 100644 --- a/Source/Game/Maps/ObjectGridLoader.cs +++ b/Source/Game/Maps/ObjectGridLoader.cs @@ -286,6 +286,7 @@ namespace Game.Maps if (obj.IsTypeId(TypeId.Player)) continue; + obj.SetDestroyedObject(true); obj.CleanupsBeforeDelete(); } } diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index e08e99cbb..338becaba 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -209,7 +209,8 @@ namespace Game // the player may not be in the world when logging out // e.g if he got disconnected during a transfer to another map // calls to GetMap in this case may cause crashes - GetPlayer().CleanupsBeforeDelete(); + _player.SetDestroyedObject(true); + _player.CleanupsBeforeDelete(); Log.outInfo(LogFilter.Player, $"Account: {GetAccountId()} (IP: {GetRemoteAddress()}) Logout Character:[{_player.GetName()}] ({_player.GetGUID()}) Level: {_player.GetLevel()}, XP: {_player.GetXP()}/{_player.GetXPForNextLevel()} ({_player.GetXPForNextLevel() - _player.GetXP()} left)"); Map map = GetPlayer().GetMap();