From 16aeb84cd35996a6b41f10cbc48a677eeccc911c Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 2 Jan 2021 13:50:34 +0000 Subject: [PATCH] Fix potential destruction crashes (#5095) * Fix potential destruction crashes * Fix destructors accessing destroyted objects * Fix cPlayer not destroying windows (Destroyed never called) * Tentatively fixes #4608, fixes #3236, fixes #3262 - Remove cEntity::Destroyed() and replace with cEntity::OnRemoveFromWorld() * Add missing call to OnRemoveFromWorld --- src/BlockEntities/BeaconEntity.cpp | 17 ++- src/BlockEntities/BeaconEntity.h | 1 + src/BlockEntities/BlockEntity.cpp | 141 +++++++++++++------- src/BlockEntities/BlockEntity.h | 79 +++++------ src/BlockEntities/BrewingstandEntity.cpp | 44 ++----- src/BlockEntities/BrewingstandEntity.h | 11 +- src/BlockEntities/ChestEntity.cpp | 35 +++-- src/BlockEntities/ChestEntity.h | 3 +- src/BlockEntities/DropSpenserEntity.cpp | 28 ++-- src/BlockEntities/DropSpenserEntity.h | 2 +- src/BlockEntities/EnderChestEntity.cpp | 18 +-- src/BlockEntities/EnderChestEntity.h | 2 +- src/BlockEntities/FlowerPotEntity.cpp | 13 +- src/BlockEntities/FlowerPotEntity.h | 2 +- src/BlockEntities/FurnaceEntity.cpp | 45 ++----- src/BlockEntities/FurnaceEntity.h | 7 +- src/Chunk.cpp | 9 ++ src/Entities/Entity.cpp | 71 ++++------ src/Entities/Entity.h | 9 +- src/Entities/EntityEffect.h | 2 +- src/Entities/Minecart.cpp | 161 ++++++++++++----------- src/Entities/Minecart.h | 28 ++-- src/Entities/Pawn.cpp | 29 ++-- src/Entities/Pawn.h | 7 +- src/Entities/Player.cpp | 3 +- src/Entities/Player.h | 4 +- src/Mobs/Horse.cpp | 28 ++-- src/Mobs/Horse.h | 6 +- src/Mobs/Monster.cpp | 46 ++----- src/Mobs/Monster.h | 6 +- src/Mobs/PassiveMonster.cpp | 9 -- src/Mobs/PassiveMonster.h | 6 - src/UI/Window.cpp | 1 - 33 files changed, 409 insertions(+), 464 deletions(-) diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index a7bdbca2d..e59d31f52 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -271,6 +271,20 @@ void cBeaconEntity::CopyFrom(const cBlockEntity & a_Src) +void cBeaconEntity::OnRemoveFromWorld() +{ + const auto Window = GetWindow(); + if (Window != nullptr) + { + // Tell window its owner is destroyed: + Window->OwnerDestroyed(); + } +} + + + + + void cBeaconEntity::SendTo(cClientHandle & a_Client) { a_Client.SendUpdateBlockEntity(*this); @@ -316,6 +330,3 @@ bool cBeaconEntity::UsedBy(cPlayer * a_Player) } return true; } - - - diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index 21c35610d..e5230e2cb 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -29,6 +29,7 @@ public: // tolua_export // cBlockEntity overrides: virtual void CopyFrom(const cBlockEntity & a_Src) override; + virtual void OnRemoveFromWorld() override; virtual void SendTo(cClientHandle & a_Client) override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual bool UsedBy(cPlayer * a_Player) override; diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index 44d5e2d19..a3b6b33a3 100644 --- a/src/BlockEntities/BlockEntity.cpp +++ b/src/BlockEntities/BlockEntity.cpp @@ -28,56 +28,52 @@ -void cBlockEntity::SetPos(Vector3i a_NewPos) +cBlockEntity::cBlockEntity(const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta, const Vector3i a_Pos, cWorld * const a_World) : + m_Pos(a_Pos), + m_RelX(a_Pos.x - cChunkDef::Width * FAST_FLOOR_DIV(a_Pos.x, cChunkDef::Width)), + m_RelZ(a_Pos.z - cChunkDef::Width * FAST_FLOOR_DIV(a_Pos.z, cChunkDef::Width)), + m_BlockType(a_BlockType), + m_BlockMeta(a_BlockMeta), + m_World(a_World) { - ASSERT(m_World == nullptr); // Cannot move block entities that represent world blocks (only use this for cBlockArea's BEs) - m_Pos = a_NewPos; } -bool cBlockEntity::IsBlockEntityBlockType(BLOCKTYPE a_BlockType) +OwnedBlockEntity cBlockEntity::Clone(const Vector3i a_Pos) { - switch (a_BlockType) - { - case E_BLOCK_BEACON: - case E_BLOCK_BED: - case E_BLOCK_BREWING_STAND: - case E_BLOCK_CHEST: - case E_BLOCK_COMMAND_BLOCK: - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - case E_BLOCK_ENCHANTMENT_TABLE: - case E_BLOCK_ENDER_CHEST: - case E_BLOCK_END_PORTAL: - case E_BLOCK_FLOWER_POT: - case E_BLOCK_FURNACE: - case E_BLOCK_HEAD: - case E_BLOCK_HOPPER: - case E_BLOCK_JUKEBOX: - case E_BLOCK_LIT_FURNACE: - case E_BLOCK_MOB_SPAWNER: - case E_BLOCK_NOTE_BLOCK: - case E_BLOCK_SIGN_POST: - case E_BLOCK_TRAPPED_CHEST: - case E_BLOCK_WALLSIGN: - { - return true; - } - default: - { - return false; - } - } + auto res = CreateByBlockType(m_BlockType, m_BlockMeta, a_Pos, nullptr); + res->CopyFrom(*this); + return res; } -OwnedBlockEntity cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World) +cItems cBlockEntity::ConvertToPickups() const +{ + return {}; +} + + + + + +void cBlockEntity::CopyFrom(const cBlockEntity & a_Src) +{ + // Nothing to copy, but check that we're copying the right entity: + ASSERT(m_BlockType == a_Src.m_BlockType); + ASSERT(m_BlockMeta == a_Src.m_BlockMeta); +} + + + + + +OwnedBlockEntity cBlockEntity::CreateByBlockType(const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta, const Vector3i a_Pos, cWorld * const a_World) { switch (a_BlockType) { @@ -117,29 +113,82 @@ OwnedBlockEntity cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETY -OwnedBlockEntity cBlockEntity::Clone(Vector3i a_Pos) +void cBlockEntity::Destroy() { - auto res = CreateByBlockType(m_BlockType, m_BlockMeta, a_Pos, nullptr); - res->CopyFrom(*this); - return res; } -cItems cBlockEntity::ConvertToPickups() const +bool cBlockEntity::IsBlockEntityBlockType(const BLOCKTYPE a_BlockType) { - return {}; + switch (a_BlockType) + { + case E_BLOCK_BEACON: + case E_BLOCK_BED: + case E_BLOCK_BREWING_STAND: + case E_BLOCK_CHEST: + case E_BLOCK_COMMAND_BLOCK: + case E_BLOCK_DISPENSER: + case E_BLOCK_DROPPER: + case E_BLOCK_ENCHANTMENT_TABLE: + case E_BLOCK_ENDER_CHEST: + case E_BLOCK_END_PORTAL: + case E_BLOCK_FLOWER_POT: + case E_BLOCK_FURNACE: + case E_BLOCK_HEAD: + case E_BLOCK_HOPPER: + case E_BLOCK_JUKEBOX: + case E_BLOCK_LIT_FURNACE: + case E_BLOCK_MOB_SPAWNER: + case E_BLOCK_NOTE_BLOCK: + case E_BLOCK_SIGN_POST: + case E_BLOCK_TRAPPED_CHEST: + case E_BLOCK_WALLSIGN: + { + return true; + } + default: + { + return false; + } + } } -void cBlockEntity::CopyFrom(const cBlockEntity & a_Src) +void cBlockEntity::OnRemoveFromWorld() { - // Nothing to copy, but check that we're copying the right entity: - ASSERT(m_BlockType == a_Src.m_BlockType); - ASSERT(m_BlockMeta == a_Src.m_BlockMeta); +} + + + + + +void cBlockEntity::SetPos(const Vector3i a_NewPos) +{ + ASSERT(m_World == nullptr); // Cannot move block entities that represent world blocks (only use this for cBlockArea's BEs) + m_Pos = a_NewPos; +} + + + + + +void cBlockEntity::SetWorld(cWorld * const a_World) +{ + m_World = a_World; +} + + + + + +bool cBlockEntity::Tick(const std::chrono::milliseconds a_Dt, cChunk & a_Chunk) +{ + UNUSED(a_Dt); + return false; } diff --git a/src/BlockEntities/BlockEntity.h b/src/BlockEntities/BlockEntity.h index 3355cdf44..3e9cf38e7 100644 --- a/src/BlockEntities/BlockEntity.h +++ b/src/BlockEntities/BlockEntity.h @@ -24,41 +24,14 @@ using cBlockEntities = std::unordered_map; class cBlockEntity { protected: - cBlockEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World) : - m_Pos(a_Pos), - m_RelX(a_Pos.x - cChunkDef::Width * FAST_FLOOR_DIV(a_Pos.x, cChunkDef::Width)), - m_RelZ(a_Pos.z - cChunkDef::Width * FAST_FLOOR_DIV(a_Pos.z, cChunkDef::Width)), - m_BlockType(a_BlockType), - m_BlockMeta(a_BlockMeta), - m_World(a_World) - { - } + + cBlockEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World); public: // tolua_end - virtual ~cBlockEntity() {} // force a virtual destructor in all descendants - - virtual void Destroy() {} - - void SetWorld(cWorld * a_World) - { - m_World = a_World; - } - - /** Updates the internally stored position. - Note that this should not ever be used for world-contained block entities, it is meant only for when BEs in a cBlockArea are manipulated. - Asserts that the block entity is not assigned to a world. */ - void SetPos(Vector3i a_NewPos); - - /** Returns true if the specified blocktype is supposed to have an associated block entity. */ - static bool IsBlockEntityBlockType(BLOCKTYPE a_BlockType); - - /** Creates a new block entity for the specified block type at the specified absolute pos. - If a_World is valid, then the entity is created bound to that world - Returns nullptr for unknown block types. */ - static OwnedBlockEntity CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World = nullptr); + virtual ~cBlockEntity() = default; // force a virtual destructor in all descendants /** Makes an exact copy of this block entity, except for its m_World (set to nullptr), and at a new position. Uses CopyFrom() to copy the properties. */ @@ -73,6 +46,37 @@ public: Super::CopyFrom(a_Src) to copy the common ones. */ virtual void CopyFrom(const cBlockEntity & a_Src); + /** Creates a new block entity for the specified block type at the specified absolute pos. + If a_World is valid, then the entity is created bound to that world + Returns nullptr for unknown block types. */ + static OwnedBlockEntity CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World = nullptr); + + virtual void Destroy(); + + /** Returns true if the specified blocktype is supposed to have an associated block entity. */ + static bool IsBlockEntityBlockType(BLOCKTYPE a_BlockType); + + /** Called when the block entity is removed from a world. */ + virtual void OnRemoveFromWorld(); + + /** Sends the packet defining the block entity to the client specified. + To send to all eligible clients, use cWorld::BroadcastBlockEntity() */ + virtual void SendTo(cClientHandle & a_Client) = 0; + + /** Updates the internally stored position. + Note that this should not ever be used for world-contained block entities, it is meant only for when BEs in a cBlockArea are manipulated. + Asserts that the block entity is not assigned to a world. */ + void SetPos(Vector3i a_NewPos); + + void SetWorld(cWorld * a_World); + + /** Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking. By default does nothing. */ + virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk); + + /** Called when a player uses this entity; should open the UI window. + returns true if the use was successful, return false to use the block as a "normal" block */ + virtual bool UsedBy(cPlayer * a_Player) = 0; + // tolua_begin // Position, in absolute block coordinates: @@ -95,21 +99,6 @@ public: // tolua_end - /** Called when a player uses this entity; should open the UI window. - returns true if the use was successful, return false to use the block as a "normal" block */ - virtual bool UsedBy( cPlayer * a_Player) = 0; - - /** Sends the packet defining the block entity to the client specified. - To send to all eligible clients, use cWorld::BroadcastBlockEntity() */ - virtual void SendTo(cClientHandle & a_Client) = 0; - - /** Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking. By default does nothing. */ - virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) - { - UNUSED(a_Dt); - return false; - } - protected: diff --git a/src/BlockEntities/BrewingstandEntity.cpp b/src/BlockEntities/BrewingstandEntity.cpp index 9c43f257f..44a077bc0 100644 --- a/src/BlockEntities/BrewingstandEntity.cpp +++ b/src/BlockEntities/BrewingstandEntity.cpp @@ -13,7 +13,6 @@ cBrewingstandEntity::cBrewingstandEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World): Super(a_BlockType, a_BlockMeta, a_Pos, ContentsWidth, ContentsHeight, a_World), - m_IsDestroyed(false), m_IsBrewing(false), m_TimeBrewed(0), m_RemainingFuel(0) @@ -25,30 +24,6 @@ cBrewingstandEntity::cBrewingstandEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_Blo -cBrewingstandEntity::~cBrewingstandEntity() -{ - // Tell window its owner is destroyed - cWindow * Window = GetWindow(); - if (Window != nullptr) - { - Window->OwnerDestroyed(); - } -} - - - - - -void cBrewingstandEntity::Destroy() -{ - m_IsDestroyed = true; - Super::Destroy(); -} - - - - - void cBrewingstandEntity::CopyFrom(const cBlockEntity & a_Src) { Super::CopyFrom(a_Src); @@ -70,6 +45,20 @@ void cBrewingstandEntity::CopyFrom(const cBlockEntity & a_Src) +void cBrewingstandEntity::OnRemoveFromWorld() +{ + const auto Window = GetWindow(); + if (Window != nullptr) + { + // Tell window its owner is destroyed: + Window->OwnerDestroyed(); + } +} + + + + + void cBrewingstandEntity::SendTo(cClientHandle & a_Client) { // Nothing needs to be sent @@ -206,11 +195,6 @@ void cBrewingstandEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) { Super::OnSlotChanged(a_ItemGrid, a_SlotNum); - if (m_IsDestroyed) - { - return; - } - ASSERT(a_ItemGrid == &m_Contents); // Check for fuel diff --git a/src/BlockEntities/BrewingstandEntity.h b/src/BlockEntities/BrewingstandEntity.h index 5f6822ff7..67a6da1a3 100644 --- a/src/BlockEntities/BrewingstandEntity.h +++ b/src/BlockEntities/BrewingstandEntity.h @@ -8,6 +8,7 @@ + class cClientHandle; @@ -43,11 +44,9 @@ public: /** Constructor used for normal operation */ cBrewingstandEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World); - virtual ~cBrewingstandEntity() override; - - // cBlockEntity overrides: - virtual void Destroy() override; + // cBlockEntity overrides: virtual void CopyFrom(const cBlockEntity & a_Src) override; + virtual void OnRemoveFromWorld() override; virtual void SendTo(cClientHandle & a_Client) override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual bool UsedBy(cPlayer * a_Player) override; @@ -110,12 +109,8 @@ public: /** Gets the recipes. Will be called if the brewing stand gets loaded from the world. */ void LoadRecipes(void); - protected: - /** Set to true when the brewing stand entity has been destroyed to prevent the block being set again */ - bool m_IsDestroyed; - /** Set to true if the brewing stand is brewing an item */ bool m_IsBrewing; diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp index 8c8e75b25..e225cf96e 100644 --- a/src/BlockEntities/ChestEntity.cpp +++ b/src/BlockEntities/ChestEntity.cpp @@ -32,22 +32,6 @@ cChestEntity::cChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector -cChestEntity::~cChestEntity() -{ - if (m_Neighbour != nullptr) - { - // Neighbour may share a window with us, force the window shut - m_Neighbour->DestroyWindow(); - m_Neighbour->m_Neighbour = nullptr; - } - - DestroyWindow(); -} - - - - - void cChestEntity::CopyFrom(const cBlockEntity & a_Src) { Super::CopyFrom(a_Src); @@ -63,6 +47,22 @@ void cChestEntity::CopyFrom(const cBlockEntity & a_Src) +void cChestEntity::OnRemoveFromWorld() +{ + if (m_Neighbour != nullptr) + { + // Neighbour may share a window with us, force the window shut: + m_Neighbour->DestroyWindow(); + m_Neighbour->m_Neighbour = nullptr; + } + + DestroyWindow(); +} + + + + + void cChestEntity::SendTo(cClientHandle & a_Client) { // Send a dummy "number of players with chest open" packet to make the chest visible: @@ -199,11 +199,10 @@ void cChestEntity::OpenNewWindow(void) void cChestEntity::DestroyWindow() { - cWindow * Window = GetWindow(); + const auto Window = GetWindow(); if (Window != nullptr) { Window->OwnerDestroyed(); - CloseWindow(); } } diff --git a/src/BlockEntities/ChestEntity.h b/src/BlockEntities/ChestEntity.h index 7c28214eb..ee59fa7b9 100644 --- a/src/BlockEntities/ChestEntity.h +++ b/src/BlockEntities/ChestEntity.h @@ -37,10 +37,9 @@ public: /** Constructor used for normal operation */ cChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World); - virtual ~cChestEntity() override; - // cBlockEntity overrides: virtual void CopyFrom(const cBlockEntity & a_Src) override; + virtual void OnRemoveFromWorld() override; virtual void SendTo(cClientHandle & a_Client) override; virtual bool UsedBy(cPlayer * a_Player) override; diff --git a/src/BlockEntities/DropSpenserEntity.cpp b/src/BlockEntities/DropSpenserEntity.cpp index 259cec7a3..814b0c147 100644 --- a/src/BlockEntities/DropSpenserEntity.cpp +++ b/src/BlockEntities/DropSpenserEntity.cpp @@ -26,20 +26,6 @@ cDropSpenserEntity::cDropSpenserEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_Block -cDropSpenserEntity::~cDropSpenserEntity() -{ - // Tell window its owner is destroyed - cWindow * Window = GetWindow(); - if (Window != nullptr) - { - Window->OwnerDestroyed(); - } -} - - - - - void cDropSpenserEntity::AddDropSpenserDir(Vector3i & a_RelCoord, NIBBLETYPE a_Direction) { switch (a_Direction & E_META_DROPSPENSER_FACING_MASK) @@ -132,6 +118,20 @@ void cDropSpenserEntity::CopyFrom(const cBlockEntity & a_Src) +void cDropSpenserEntity::OnRemoveFromWorld() +{ + const auto Window = GetWindow(); + if (Window != nullptr) + { + // Tell window its owner is destroyed: + Window->OwnerDestroyed(); + } +} + + + + + bool cDropSpenserEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { UNUSED(a_Dt); diff --git a/src/BlockEntities/DropSpenserEntity.h b/src/BlockEntities/DropSpenserEntity.h index e16149797..9eb3d15ea 100644 --- a/src/BlockEntities/DropSpenserEntity.h +++ b/src/BlockEntities/DropSpenserEntity.h @@ -43,10 +43,10 @@ public: // tolua_end cDropSpenserEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World); - virtual ~cDropSpenserEntity() override; // cBlockEntity overrides: virtual void CopyFrom(const cBlockEntity & a_Src) override; + virtual void OnRemoveFromWorld() override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual void SendTo(cClientHandle & a_Client) override; virtual bool UsedBy(cPlayer * a_Player) override; diff --git a/src/BlockEntities/EnderChestEntity.cpp b/src/BlockEntities/EnderChestEntity.cpp index 44bfaf7d4..c5d490766 100644 --- a/src/BlockEntities/EnderChestEntity.cpp +++ b/src/BlockEntities/EnderChestEntity.cpp @@ -25,23 +25,23 @@ cEnderChestEntity::cEnderChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMe -cEnderChestEntity::~cEnderChestEntity() +void cEnderChestEntity::SendTo(cClientHandle & a_Client) { - cWindow * Window = GetWindow(); - if (Window != nullptr) - { - Window->OwnerDestroyed(); - } + // Send a dummy "number of players with chest open" packet to make the chest visible: + a_Client.SendBlockAction(m_Pos.x, m_Pos.y, m_Pos.z, 1, 0, m_BlockType); } -void cEnderChestEntity::SendTo(cClientHandle & a_Client) +void cEnderChestEntity::OnRemoveFromWorld() { - // Send a dummy "number of players with chest open" packet to make the chest visible: - a_Client.SendBlockAction(m_Pos.x, m_Pos.y, m_Pos.z, 1, 0, m_BlockType); + const auto Window = GetWindow(); + if (Window != nullptr) + { + Window->OwnerDestroyed(); + } } diff --git a/src/BlockEntities/EnderChestEntity.h b/src/BlockEntities/EnderChestEntity.h index bb5974b15..d2fb4d67e 100644 --- a/src/BlockEntities/EnderChestEntity.h +++ b/src/BlockEntities/EnderChestEntity.h @@ -20,9 +20,9 @@ class cEnderChestEntity : public: // tolua_export cEnderChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World); - virtual ~cEnderChestEntity() override; // cBlockEntity overrides: + virtual void OnRemoveFromWorld() override; virtual bool UsedBy(cPlayer * a_Player) override; virtual void SendTo(cClientHandle & a_Client) override; diff --git a/src/BlockEntities/FlowerPotEntity.cpp b/src/BlockEntities/FlowerPotEntity.cpp index 60b2db4f5..bc936c246 100644 --- a/src/BlockEntities/FlowerPotEntity.cpp +++ b/src/BlockEntities/FlowerPotEntity.cpp @@ -23,18 +23,9 @@ cFlowerPotEntity::cFlowerPotEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta -void cFlowerPotEntity::Destroy(void) +cItems cFlowerPotEntity::ConvertToPickups() const { - // Drop the contents as pickups: - if (!m_Item.IsEmpty()) - { - ASSERT(m_World != nullptr); - cItems Pickups; - Pickups.Add(m_Item); - m_World->SpawnItemPickups(Pickups, Vector3d(0.5, 0.5, 0.5) + m_Pos); - - m_Item.Empty(); - } + return cItem(m_Item); } diff --git a/src/BlockEntities/FlowerPotEntity.h b/src/BlockEntities/FlowerPotEntity.h index c93e2f4d9..1d95ef570 100644 --- a/src/BlockEntities/FlowerPotEntity.h +++ b/src/BlockEntities/FlowerPotEntity.h @@ -43,7 +43,7 @@ public: // tolua_export // tolua_end // cBlockEntity overrides: - virtual void Destroy(void) override; + virtual cItems ConvertToPickups() const override; virtual void CopyFrom(const cBlockEntity & a_Src) override; virtual bool UsedBy(cPlayer * a_Player) override; virtual void SendTo(cClientHandle & a_Client) override; diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp index b325f4e5c..6b2e7bbac 100644 --- a/src/BlockEntities/FurnaceEntity.cpp +++ b/src/BlockEntities/FurnaceEntity.cpp @@ -25,7 +25,6 @@ enum cFurnaceEntity::cFurnaceEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World): Super(a_BlockType, a_BlockMeta, a_Pos, ContentsWidth, ContentsHeight, a_World), m_CurrentRecipe(nullptr), - m_IsDestroyed(false), m_IsCooking(a_BlockType == E_BLOCK_LIT_FURNACE), m_NeedCookTime(0), m_TimeCooked(0), @@ -41,30 +40,6 @@ cFurnaceEntity::cFurnaceEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Ve -cFurnaceEntity::~cFurnaceEntity() -{ - // Tell window its owner is destroyed - cWindow * Window = GetWindow(); - if (Window != nullptr) - { - Window->OwnerDestroyed(); - } -} - - - - - -void cFurnaceEntity::Destroy() -{ - m_IsDestroyed = true; - Super::Destroy(); -} - - - - - void cFurnaceEntity::CopyFrom(const cBlockEntity & a_Src) { Super::CopyFrom(a_Src); @@ -73,7 +48,6 @@ void cFurnaceEntity::CopyFrom(const cBlockEntity & a_Src) m_CurrentRecipe = src.m_CurrentRecipe; m_FuelBurnTime = src.m_FuelBurnTime; m_IsCooking = src.m_IsCooking; - m_IsDestroyed = src.m_IsDestroyed; m_IsLoading = src.m_IsLoading; m_LastInput = src.m_LastInput; m_NeedCookTime = src.m_NeedCookTime; @@ -85,6 +59,20 @@ void cFurnaceEntity::CopyFrom(const cBlockEntity & a_Src) +void cFurnaceEntity::OnRemoveFromWorld() +{ + const auto Window = GetWindow(); + if (Window != nullptr) + { + // Tell window its owner is destroyed: + Window->OwnerDestroyed(); + } +} + + + + + void cFurnaceEntity::SendTo(cClientHandle & a_Client) { // Nothing needs to be sent @@ -259,11 +247,6 @@ void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) { Super::OnSlotChanged(a_ItemGrid, a_SlotNum); - if (m_IsDestroyed) - { - return; - } - if (m_IsLoading) { return; diff --git a/src/BlockEntities/FurnaceEntity.h b/src/BlockEntities/FurnaceEntity.h index 079b45fef..c6b5ee09f 100644 --- a/src/BlockEntities/FurnaceEntity.h +++ b/src/BlockEntities/FurnaceEntity.h @@ -41,11 +41,9 @@ public: /** Constructor used for normal operation */ cFurnaceEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World); - virtual ~cFurnaceEntity() override; - // cBlockEntity overrides: - virtual void Destroy() override; virtual void CopyFrom(const cBlockEntity & a_Src) override; + virtual void OnRemoveFromWorld() override; virtual void SendTo(cClientHandle & a_Client) override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual bool UsedBy(cPlayer * a_Player) override; @@ -118,9 +116,6 @@ protected: /** The item that is being smelted */ cItem m_LastInput; - /** Set to true when the furnace entity has been destroyed to prevent the block being set again */ - bool m_IsDestroyed; - /** Set to true if the furnace is cooking an item */ bool m_IsCooking; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 0d0b0896a..ff5757703 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -220,6 +220,12 @@ void cChunk::OnUnload() // Notify the entity: Entity->OnRemoveFromWorld(*Entity->GetWorld()); } + + // Notify all block entities of imminent unload: + for (auto & BlockEntity : m_BlockEntities) + { + BlockEntity.second->OnRemoveFromWorld(); + } } @@ -452,6 +458,7 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock if (affectedArea.IsInside(itr->second->GetPos())) { itr->second->Destroy(); + itr->second->OnRemoveFromWorld(); itr = m_BlockEntities.erase(itr); } else @@ -760,6 +767,7 @@ void cChunk::MoveEntityToNewChunk(OwnedEntity a_Entity) if (Neighbor == nullptr) { LOGWARNING("%s: Failed to move entity, destination chunk unreachable. Entity lost", __FUNCTION__); + a_Entity->OnRemoveFromWorld(*m_World); return; } @@ -1267,6 +1275,7 @@ void cChunk::SetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_Blo if (BlockEntity != nullptr) { BlockEntity->Destroy(); + BlockEntity->OnRemoveFromWorld(); RemoveBlockEntity(BlockEntity); } diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 579541dd3..438117650 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -80,32 +80,6 @@ cEntity::cEntity(eEntityType a_EntityType, Vector3d a_Pos, double a_Width, doubl -cEntity::~cEntity() -{ - /* - // DEBUG: - FLOGD("Deleting entity {0} at pos {1:.2f} ~ [{2}, {3}]; ptr {4}", - m_UniqueID, - m_Pos, - GetChunkX(), GetChunkZ(), - static_cast(this) - ); - */ - - if (m_AttachedTo != nullptr) - { - Detach(); - } - if (m_Attachee != nullptr) - { - m_Attachee->Detach(); - } -} - - - - - const char * cEntity::GetClass(void) const { return "cEntity"; @@ -174,7 +148,22 @@ void cEntity::OnAddToWorld(cWorld & a_World) void cEntity::OnRemoveFromWorld(cWorld & a_World) { - RemoveAllLeashedMobs(); + // Remove all mobs from the leashed list of mobs: + while (!m_LeashedMobs.empty()) + { + m_LeashedMobs.front()->Unleash(false, true); + } + + if (m_AttachedTo != nullptr) + { + Detach(); + } + + if (m_Attachee != nullptr) + { + m_Attachee->Detach(); + } + a_World.BroadcastDestroyEntity(*this); } @@ -244,7 +233,6 @@ void cEntity::Destroy() // Also, not storing the returned pointer means automatic destruction VERIFY(a_World.RemoveEntity(*this)); }); - Destroyed(); } @@ -813,10 +801,17 @@ void cEntity::KilledBy(TakeDamageInfo & a_TDI) cRoot::Get()->GetPluginManager()->CallHookKilled(*this, a_TDI, emptystring); } - // Drop loot: - cItems Drops; - GetDrops(Drops, a_TDI.Attacker); - m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ()); + // Drop loot, unless the attacker was a creative mode player: + if ( + (a_TDI.Attacker == nullptr) || + !a_TDI.Attacker->IsPlayer() || + !static_cast(a_TDI.Attacker)->IsGameModeCreative() + ) + { + cItems Drops; + GetDrops(Drops, a_TDI.Attacker); + m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ()); + } m_World->BroadcastEntityStatus(*this, esGenericDead); } @@ -2328,18 +2323,6 @@ void cEntity::RemoveLeashedMob(cMonster * a_Monster) -void cEntity::RemoveAllLeashedMobs() -{ - while (!m_LeashedMobs.empty()) - { - m_LeashedMobs.front()->Unleash(false, true); - } -} - - - - - void cEntity::BroadcastLeashedMobs() { // If has any mob leashed broadcast every leashed entity to this diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 20712e7ea..85cf35661 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -169,7 +169,7 @@ public: cEntity(eEntityType a_EntityType, Vector3d a_Pos, double a_Width, double a_Height); - virtual ~cEntity(); + virtual ~cEntity() = default; /** Spawns the entity in the world; returns true if spawned, false if not (plugin disallowed). Adds the entity to the world. */ @@ -296,7 +296,7 @@ public: // tolua_end /** Destroys the entity, schedules it for memory freeing and broadcasts the DestroyEntity packet */ - virtual void Destroy(); + void Destroy(); // tolua_begin /** Makes this pawn take damage from an attack by a_Attacker. Damage values are calculated automatically and DoTakeDamage() called */ @@ -594,9 +594,6 @@ public: /** Removes a mob from the leashed list of mobs. */ void RemoveLeashedMob(cMonster * a_Monster); - /** Removes all mobs from the leashed list of mobs. */ - void RemoveAllLeashedMobs(); - /** Returs whether the entity has any mob leashed to it. */ bool HasAnyMobLeashed() const { return m_LeashedMobs.size() > 0; } @@ -723,8 +720,6 @@ protected: Should handle degenerate cases such as moving to the same world. */ virtual void DoMoveToWorld(const sWorldChangeInfo & a_WorldChangeInfo); - virtual void Destroyed(void) {} // Called after the entity has been destroyed - /** Applies friction to an entity @param a_Speed The speed vector to apply changes to @param a_SlowdownMultiplier The factor to reduce the speed by */ diff --git a/src/Entities/EntityEffect.h b/src/Entities/EntityEffect.h index eebf0e3c8..b4e01d8d9 100644 --- a/src/Entities/EntityEffect.h +++ b/src/Entities/EntityEffect.h @@ -73,7 +73,7 @@ public: @param a_OtherEffect The other effect to copy */ cEntityEffect & operator =(cEntityEffect a_OtherEffect); - virtual ~cEntityEffect(void) {} + virtual ~cEntityEffect(void) = default; /** Creates a pointer to the proper entity effect from the effect type @warning This function creates raw pointers that must be manually managed. diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 59d369c5b..fbe4f756e 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -1203,7 +1203,6 @@ bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI) { if ((TDI.Attacker != nullptr) && TDI.Attacker->IsPlayer() && static_cast(TDI.Attacker)->IsGameModeCreative()) { - Destroy(); TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative SetInvulnerableTicks(0); return Super::DoTakeDamage(TDI); // No drops for creative @@ -1217,42 +1216,6 @@ bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI) m_World->BroadcastEntityMetadata(*this); - if (GetHealth() <= 0) - { - Destroy(); - - cItems Drops; - switch (m_Payload) - { - case mpNone: - { - Drops.push_back(cItem(E_ITEM_MINECART, 1, 0)); - break; - } - case mpChest: - { - Drops.push_back(cItem(E_ITEM_CHEST_MINECART, 1, 0)); - break; - } - case mpFurnace: - { - Drops.push_back(cItem(E_ITEM_FURNACE_MINECART, 1, 0)); - break; - } - case mpTNT: - { - Drops.push_back(cItem(E_ITEM_MINECART_WITH_TNT, 1, 0)); - break; - } - case mpHopper: - { - Drops.push_back(cItem(E_ITEM_MINECART_WITH_HOPPER, 1, 0)); - break; - } - } - - m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ()); - } return true; } @@ -1260,6 +1223,31 @@ bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI) +void cMinecart::KilledBy(TakeDamageInfo & a_TDI) +{ + Super::KilledBy(a_TDI); + + Destroy(); +} + + + + + +void cMinecart::OnRemoveFromWorld(cWorld & a_World) +{ + if (m_bIsOnDetectorRail) + { + m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07); + } + + Super::OnRemoveFromWorld(a_World); +} + + + + + void cMinecart::ApplyAcceleration(Vector3d a_ForwardDirection, double a_Acceleration) { double CurSpeed = GetSpeed().Dot(a_ForwardDirection); @@ -1314,18 +1302,6 @@ void cMinecart::DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) -void cMinecart::Destroyed() -{ - if (m_bIsOnDetectorRail) - { - m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07); - } -} - - - - - //////////////////////////////////////////////////////////////////////////////// // cRideableMinecart: @@ -1340,6 +1316,15 @@ cRideableMinecart::cRideableMinecart(Vector3d a_Pos, const cItem & a_Content, in +void cRideableMinecart::GetDrops(cItems & a_Drops, cEntity * a_Killer) +{ + a_Drops.emplace_back(E_ITEM_MINECART); +} + + + + + void cRideableMinecart::OnRightClicked(cPlayer & a_Player) { Super::OnRightClicked(a_Player); @@ -1386,6 +1371,31 @@ cMinecartWithChest::cMinecartWithChest(Vector3d a_Pos): +void cMinecartWithChest::GetDrops(cItems & a_Drops, cEntity * a_Killer) +{ + m_Contents.CopyToItems(a_Drops); + a_Drops.emplace_back(E_ITEM_CHEST_MINECART); +} + + + + + +void cMinecartWithChest::OnRemoveFromWorld(cWorld & a_World) +{ + const auto Window = GetWindow(); + if (Window != nullptr) + { + Window->OwnerDestroyed(); + } + + Super::OnRemoveFromWorld(a_World); +} + + + + + void cMinecartWithChest::OnRightClicked(cPlayer & a_Player) { // If the window is not created, open it anew: @@ -1419,32 +1429,6 @@ void cMinecartWithChest::OpenNewWindow() -void cMinecartWithChest::Destroyed() -{ - if (GetWindow() != nullptr) - { - GetWindow()->OwnerDestroyed(); - } - cItems Pickups; - m_Contents.CopyToItems(Pickups); - - - // Schedule the pickups creation for the next world tick - // This avoids a deadlock when terminating the world - // Note that the scheduled task may be run when this object is no longer valid, we need to store everything in the task's captured variables - auto posX = GetPosX(); - auto posY = GetPosY() + 1; - auto posZ = GetPosZ(); - GetWorld()->ScheduleTask(1, [Pickups, posX, posY, posZ](cWorld & World) - { - World.SpawnItemPickups(Pickups, posX, posY, posZ, 4); - }); -} - - - - - //////////////////////////////////////////////////////////////////////////////// // cMinecartWithFurnace: @@ -1459,6 +1443,15 @@ cMinecartWithFurnace::cMinecartWithFurnace(Vector3d a_Pos): +void cMinecartWithFurnace::GetDrops(cItems & a_Drops, cEntity * a_Killer) +{ + a_Drops.emplace_back(E_ITEM_FURNACE_MINECART); +} + + + + + void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player) { if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_COAL) @@ -1526,6 +1519,15 @@ cMinecartWithTNT::cMinecartWithTNT(Vector3d a_Pos): +void cMinecartWithTNT::GetDrops(cItems & a_Drops, cEntity * a_Killer) +{ + a_Drops.emplace_back(E_ITEM_MINECART_WITH_TNT); +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cMinecartWithHopper: @@ -1536,3 +1538,12 @@ cMinecartWithHopper::cMinecartWithHopper(Vector3d a_Pos): // TODO: Make it suck up blocks and travel further than any other cart and physics and put and take blocks // AND AVARYTHING!! + + + + + +void cMinecartWithHopper::GetDrops(cItems & a_Drops, cEntity * a_Killer) +{ + a_Drops.emplace_back(E_ITEM_MINECART_WITH_HOPPER); +} diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h index ad3b3d40d..73011b7b5 100644 --- a/src/Entities/Minecart.h +++ b/src/Entities/Minecart.h @@ -40,12 +40,12 @@ public: virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; - virtual void Destroyed() override; + virtual void KilledBy(TakeDamageInfo & a_TDI) override; + virtual void OnRemoveFromWorld(cWorld & a_World) override; int LastDamage(void) const { return m_LastDamage; } ePayload GetPayload(void) const { return m_Payload; } - protected: ePayload m_Payload; @@ -99,7 +99,7 @@ protected: -class cRideableMinecart : +class cRideableMinecart final : public cMinecart { using Super = cMinecart; @@ -114,6 +114,7 @@ public: int GetBlockHeight(void) const {return m_Height;} // cEntity overrides: + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void OnRightClicked(cPlayer & a_Player) override; protected: @@ -127,7 +128,7 @@ protected: -class cMinecartWithChest : +class cMinecartWithChest final : public cMinecart, public cItemGrid::cListener, public cEntityWindowOwner @@ -154,7 +155,6 @@ protected: cItemGrid m_Contents; void OpenNewWindow(void); - virtual void Destroyed() override; // cItemGrid::cListener overrides: virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) override @@ -173,6 +173,8 @@ protected: } // cEntity overrides: + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; + virtual void OnRemoveFromWorld(cWorld & a_World) override; virtual void OnRightClicked(cPlayer & a_Player) override; } ; @@ -180,7 +182,7 @@ protected: -class cMinecartWithFurnace : +class cMinecartWithFurnace final : public cMinecart { using Super = cMinecart; @@ -192,6 +194,7 @@ public: cMinecartWithFurnace(Vector3d a_Pos); // cEntity overrides: + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void OnRightClicked(cPlayer & a_Player) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; @@ -213,22 +216,27 @@ private: -class cMinecartWithTNT : +class cMinecartWithTNT final : public cMinecart { using Super = cMinecart; public: + CLASS_PROTODEF(cMinecartWithTNT) cMinecartWithTNT(Vector3d a_Pos); + +private: + + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; } ; -class cMinecartWithHopper : +class cMinecartWithHopper final : public cMinecart { using Super = cMinecart; @@ -238,4 +246,8 @@ public: CLASS_PROTODEF(cMinecartWithHopper) cMinecartWithHopper(Vector3d a_Pos); + +private: + + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; } ; diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp index 9857fa29c..35efe05ce 100644 --- a/src/Entities/Pawn.cpp +++ b/src/Entities/Pawn.cpp @@ -28,25 +28,6 @@ cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height) : -cPawn::~cPawn() -{ - ASSERT(m_TargetingMe.size() == 0); -} - - - - - -void cPawn::Destroyed() -{ - StopEveryoneFromTargetingMe(); - Super::Destroyed(); -} - - - - - void cPawn::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { std::vector EffectsToTick; @@ -453,6 +434,16 @@ void cPawn::HandleFalling(void) +void cPawn::OnRemoveFromWorld(cWorld & a_World) +{ + StopEveryoneFromTargetingMe(); + Super::OnRemoveFromWorld(a_World); +} + + + + + void cPawn::StopEveryoneFromTargetingMe() { std::vector::iterator i = m_TargetingMe.begin(); diff --git a/src/Entities/Pawn.h b/src/Entities/Pawn.h index f4b1cbbbf..1a9285b77 100644 --- a/src/Entities/Pawn.h +++ b/src/Entities/Pawn.h @@ -23,8 +23,6 @@ public: CLASS_PROTODEF(cPawn) cPawn(eEntityType a_EntityType, double a_Width, double a_Height); - virtual ~cPawn() override; - virtual void Destroyed() override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual void KilledBy(TakeDamageInfo & a_TDI) override; @@ -33,6 +31,7 @@ public: virtual bool IsInvisible() const override; virtual void HandleAir(void) override; virtual void HandleFalling(void); + virtual void OnRemoveFromWorld(cWorld & a_World) override; /** Tells all pawns which are targeting us to stop targeting us. */ void StopEveryoneFromTargetingMe(); @@ -85,7 +84,3 @@ private: /** A list of all monsters that are targeting this pawn. */ std::vector m_TargetingMe; } ; // tolua_export - - - - diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index fb0cdf271..391a5ce71 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -280,10 +280,9 @@ cPlayer::~cPlayer(void) -void cPlayer::Destroyed() +void cPlayer::OnRemoveFromWorld(cWorld & a_World) { CloseWindow(false); - Super::Destroyed(); } diff --git a/src/Entities/Player.h b/src/Entities/Player.h index bdcacd608..1e7a17e4f 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -54,6 +54,8 @@ public: virtual ~cPlayer() override; + virtual void OnRemoveFromWorld(cWorld & a_World) override; + virtual void SpawnOn(cClientHandle & a_Client) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; @@ -784,8 +786,6 @@ protected: /** Sets the speed and sends it to the client, so that they are forced to move so. */ virtual void DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) override; - virtual void Destroyed(void) override; - /** Filters out damage for creative mode / friendly fire */ virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; diff --git a/src/Mobs/Horse.cpp b/src/Mobs/Horse.cpp index e42241700..d3ba066cc 100644 --- a/src/Mobs/Horse.cpp +++ b/src/Mobs/Horse.cpp @@ -32,19 +32,6 @@ cHorse::cHorse(int Type, int Color, int Style, int TameTimes) : -cHorse::~cHorse() -{ - auto Window = GetWindow(); - if (Window != nullptr) - { - Window->OwnerDestroyed(); - } -} - - - - - void cHorse::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { Super::Tick(a_Dt, a_Chunk); @@ -123,6 +110,21 @@ void cHorse::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) +void cHorse::OnRemoveFromWorld(cWorld & a_World) +{ + const auto Window = GetWindow(); + if (Window != nullptr) + { + Window->OwnerDestroyed(); + } + + Super::OnRemoveFromWorld(a_World); +} + + + + + void cHorse::OnRightClicked(cPlayer & a_Player) { Super::OnRightClicked(a_Player); diff --git a/src/Mobs/Horse.h b/src/Mobs/Horse.h index f9c236ffc..4f35071c0 100644 --- a/src/Mobs/Horse.h +++ b/src/Mobs/Horse.h @@ -17,7 +17,6 @@ class cHorse: public: cHorse(int Type, int Color, int Style, int TameTimes); - virtual ~cHorse() override; CLASS_PROTODEF(cHorse) @@ -25,6 +24,7 @@ public: virtual void InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; + virtual void OnRemoveFromWorld(cWorld & a_World) override; virtual void OnRightClicked(cPlayer & a_Player) override; bool IsSaddled (void) const {return !m_Saddle.IsEmpty(); } @@ -66,7 +66,3 @@ private: cItem m_Armor; } ; - - - - diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 048393e67..7e8e7eba3 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -135,17 +135,15 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A -cMonster::~cMonster() -{ - ASSERT(GetTarget() == nullptr); -} - - - - - void cMonster::OnRemoveFromWorld(cWorld & a_World) { + SetTarget(nullptr); // Tell them we're no longer targeting them. + + if (m_LovePartner != nullptr) + { + m_LovePartner->ResetLoveMode(); + } + if (IsLeashed()) { cEntity * LeashedTo = GetLeashedTo(); @@ -165,20 +163,6 @@ void cMonster::OnRemoveFromWorld(cWorld & a_World) -void cMonster::Destroyed() -{ - SetTarget(nullptr); // Tell them we're no longer targeting them. - if (m_LovePartner != nullptr) - { - m_LovePartner->ResetLoveMode(); - } - Super::Destroyed(); -} - - - - - void cMonster::SpawnOn(cClientHandle & a_Client) { a_Client.SendSpawnMob(*this); @@ -762,22 +746,14 @@ void cMonster::CheckEventSeePlayer(cChunk & a_Chunk) const auto MyHeadPosition = GetPosition().addedY(GetHeight()); // Enumerate all players within sight: - m_World->ForEachEntityInBox({ GetPosition(), m_SightDistance * 2.0 }, [this, &TargetPlayer, &ClosestDistance, MyHeadPosition](cEntity & a_Entity) + m_World->ForEachPlayer([this, &TargetPlayer, &ClosestDistance, MyHeadPosition](cPlayer & a_Player) { - if (!a_Entity.IsPlayer()) - { - // Continue iteration: - return false; - } - - const auto Player = static_cast(&a_Entity); - - if (!Player->CanMobsTarget()) + if (!a_Player.CanMobsTarget()) { return false; } - const auto TargetHeadPosition = a_Entity.GetPosition().addedY(a_Entity.GetHeight()); + const auto TargetHeadPosition = a_Player.GetPosition().addedY(a_Player.GetHeight()); const auto TargetDistance = (TargetHeadPosition - MyHeadPosition).SqrLength(); // TODO: Currently all mobs see through lava, but only Nether-native mobs should be able to. @@ -786,7 +762,7 @@ void cMonster::CheckEventSeePlayer(cChunk & a_Chunk) cLineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetHeadPosition, cLineBlockTracer::losAirWaterLava) ) { - TargetPlayer = Player; + TargetPlayer = &a_Player; ClosestDistance = TargetDistance; } diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index aeb8a3bf9..eb8905ae3 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -48,14 +48,10 @@ public: */ cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, const AString & a_SoundAmbient, double a_Width, double a_Height); - virtual ~cMonster() override; + CLASS_PROTODEF(cMonster) virtual void OnRemoveFromWorld(cWorld & a_World) override; - virtual void Destroyed() override; - - CLASS_PROTODEF(cMonster) - virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp index e9c4070db..90d88024d 100644 --- a/src/Mobs/PassiveMonster.cpp +++ b/src/Mobs/PassiveMonster.cpp @@ -37,15 +37,6 @@ bool cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) -void cPassiveMonster::Destroyed() -{ - Super::Destroyed(); -} - - - - - void cPassiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { Super::Tick(a_Dt, a_Chunk); diff --git a/src/Mobs/PassiveMonster.h b/src/Mobs/PassiveMonster.h index 15900a95d..400cc3885 100644 --- a/src/Mobs/PassiveMonster.h +++ b/src/Mobs/PassiveMonster.h @@ -30,10 +30,4 @@ public: /** When hit by someone, run away */ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; - - virtual void Destroyed(void) override; }; - - - - diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index 07b84916d..23661e150 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -418,7 +418,6 @@ void cWindow::SetProperty(size_t a_Property, short a_Value) void cWindow::OwnerDestroyed() { - m_Owner = nullptr; // Close window for each player. Note that the last one needs special handling while (m_OpenedBy.size() > 1) {