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
This commit is contained in:
parent
4656f7486d
commit
16aeb84cd3
@ -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)
|
void cBeaconEntity::SendTo(cClientHandle & a_Client)
|
||||||
{
|
{
|
||||||
a_Client.SendUpdateBlockEntity(*this);
|
a_Client.SendUpdateBlockEntity(*this);
|
||||||
@ -316,6 +330,3 @@ bool cBeaconEntity::UsedBy(cPlayer * a_Player)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ public: // tolua_export
|
|||||||
|
|
||||||
// cBlockEntity overrides:
|
// cBlockEntity overrides:
|
||||||
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
||||||
|
virtual void OnRemoveFromWorld() override;
|
||||||
virtual void SendTo(cClientHandle & a_Client) override;
|
virtual void SendTo(cClientHandle & a_Client) override;
|
||||||
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual bool UsedBy(cPlayer * a_Player) override;
|
virtual bool UsedBy(cPlayer * a_Player) override;
|
||||||
|
@ -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)
|
auto res = CreateByBlockType(m_BlockType, m_BlockMeta, a_Pos, nullptr);
|
||||||
{
|
res->CopyFrom(*this);
|
||||||
case E_BLOCK_BEACON:
|
return res;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
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;
|
||||||
}
|
}
|
||||||
|
@ -24,41 +24,14 @@ using cBlockEntities = std::unordered_map<size_t, OwnedBlockEntity>;
|
|||||||
class cBlockEntity
|
class cBlockEntity
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
cBlockEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World) :
|
|
||||||
m_Pos(a_Pos),
|
cBlockEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
||||||
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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
virtual ~cBlockEntity() {} // force a virtual destructor in all descendants
|
virtual ~cBlockEntity() = default; // 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);
|
|
||||||
|
|
||||||
/** Makes an exact copy of this block entity, except for its m_World (set to nullptr), and at a new position.
|
/** 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. */
|
Uses CopyFrom() to copy the properties. */
|
||||||
@ -73,6 +46,37 @@ public:
|
|||||||
Super::CopyFrom(a_Src) to copy the common ones. */
|
Super::CopyFrom(a_Src) to copy the common ones. */
|
||||||
virtual void CopyFrom(const cBlockEntity & a_Src);
|
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
|
// tolua_begin
|
||||||
|
|
||||||
// Position, in absolute block coordinates:
|
// Position, in absolute block coordinates:
|
||||||
@ -95,21 +99,6 @@ public:
|
|||||||
|
|
||||||
// tolua_end
|
// 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:
|
protected:
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
cBrewingstandEntity::cBrewingstandEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World):
|
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),
|
Super(a_BlockType, a_BlockMeta, a_Pos, ContentsWidth, ContentsHeight, a_World),
|
||||||
m_IsDestroyed(false),
|
|
||||||
m_IsBrewing(false),
|
m_IsBrewing(false),
|
||||||
m_TimeBrewed(0),
|
m_TimeBrewed(0),
|
||||||
m_RemainingFuel(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)
|
void cBrewingstandEntity::CopyFrom(const cBlockEntity & a_Src)
|
||||||
{
|
{
|
||||||
Super::CopyFrom(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)
|
void cBrewingstandEntity::SendTo(cClientHandle & a_Client)
|
||||||
{
|
{
|
||||||
// Nothing needs to be sent
|
// Nothing needs to be sent
|
||||||
@ -206,11 +195,6 @@ void cBrewingstandEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
|
|||||||
{
|
{
|
||||||
Super::OnSlotChanged(a_ItemGrid, a_SlotNum);
|
Super::OnSlotChanged(a_ItemGrid, a_SlotNum);
|
||||||
|
|
||||||
if (m_IsDestroyed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(a_ItemGrid == &m_Contents);
|
ASSERT(a_ItemGrid == &m_Contents);
|
||||||
|
|
||||||
// Check for fuel
|
// Check for fuel
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cClientHandle;
|
class cClientHandle;
|
||||||
|
|
||||||
|
|
||||||
@ -43,11 +44,9 @@ public:
|
|||||||
/** Constructor used for normal operation */
|
/** Constructor used for normal operation */
|
||||||
cBrewingstandEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
cBrewingstandEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
||||||
|
|
||||||
virtual ~cBrewingstandEntity() override;
|
// cBlockEntity overrides:
|
||||||
|
|
||||||
// cBlockEntity overrides:
|
|
||||||
virtual void Destroy() override;
|
|
||||||
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
||||||
|
virtual void OnRemoveFromWorld() override;
|
||||||
virtual void SendTo(cClientHandle & a_Client) override;
|
virtual void SendTo(cClientHandle & a_Client) override;
|
||||||
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual bool UsedBy(cPlayer * a_Player) 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. */
|
/** Gets the recipes. Will be called if the brewing stand gets loaded from the world. */
|
||||||
void LoadRecipes(void);
|
void LoadRecipes(void);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
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 */
|
/** Set to true if the brewing stand is brewing an item */
|
||||||
bool m_IsBrewing;
|
bool m_IsBrewing;
|
||||||
|
|
||||||
|
@ -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)
|
void cChestEntity::CopyFrom(const cBlockEntity & a_Src)
|
||||||
{
|
{
|
||||||
Super::CopyFrom(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)
|
void cChestEntity::SendTo(cClientHandle & a_Client)
|
||||||
{
|
{
|
||||||
// Send a dummy "number of players with chest open" packet to make the chest visible:
|
// 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()
|
void cChestEntity::DestroyWindow()
|
||||||
{
|
{
|
||||||
cWindow * Window = GetWindow();
|
const auto Window = GetWindow();
|
||||||
if (Window != nullptr)
|
if (Window != nullptr)
|
||||||
{
|
{
|
||||||
Window->OwnerDestroyed();
|
Window->OwnerDestroyed();
|
||||||
CloseWindow();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,10 +37,9 @@ public:
|
|||||||
/** Constructor used for normal operation */
|
/** Constructor used for normal operation */
|
||||||
cChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
cChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
||||||
|
|
||||||
virtual ~cChestEntity() override;
|
|
||||||
|
|
||||||
// cBlockEntity overrides:
|
// cBlockEntity overrides:
|
||||||
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
||||||
|
virtual void OnRemoveFromWorld() override;
|
||||||
virtual void SendTo(cClientHandle & a_Client) override;
|
virtual void SendTo(cClientHandle & a_Client) override;
|
||||||
virtual bool UsedBy(cPlayer * a_Player) override;
|
virtual bool UsedBy(cPlayer * a_Player) override;
|
||||||
|
|
||||||
|
@ -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)
|
void cDropSpenserEntity::AddDropSpenserDir(Vector3i & a_RelCoord, NIBBLETYPE a_Direction)
|
||||||
{
|
{
|
||||||
switch (a_Direction & E_META_DROPSPENSER_FACING_MASK)
|
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)
|
bool cDropSpenserEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||||
{
|
{
|
||||||
UNUSED(a_Dt);
|
UNUSED(a_Dt);
|
||||||
|
@ -43,10 +43,10 @@ public:
|
|||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
cDropSpenserEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
cDropSpenserEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
||||||
virtual ~cDropSpenserEntity() override;
|
|
||||||
|
|
||||||
// cBlockEntity overrides:
|
// cBlockEntity overrides:
|
||||||
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
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 bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual void SendTo(cClientHandle & a_Client) override;
|
virtual void SendTo(cClientHandle & a_Client) override;
|
||||||
virtual bool UsedBy(cPlayer * a_Player) override;
|
virtual bool UsedBy(cPlayer * a_Player) override;
|
||||||
|
@ -25,23 +25,23 @@ cEnderChestEntity::cEnderChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMe
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
cEnderChestEntity::~cEnderChestEntity()
|
void cEnderChestEntity::SendTo(cClientHandle & a_Client)
|
||||||
{
|
{
|
||||||
cWindow * Window = GetWindow();
|
// Send a dummy "number of players with chest open" packet to make the chest visible:
|
||||||
if (Window != nullptr)
|
a_Client.SendBlockAction(m_Pos.x, m_Pos.y, m_Pos.z, 1, 0, m_BlockType);
|
||||||
{
|
|
||||||
Window->OwnerDestroyed();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cEnderChestEntity::SendTo(cClientHandle & a_Client)
|
void cEnderChestEntity::OnRemoveFromWorld()
|
||||||
{
|
{
|
||||||
// Send a dummy "number of players with chest open" packet to make the chest visible:
|
const auto Window = GetWindow();
|
||||||
a_Client.SendBlockAction(m_Pos.x, m_Pos.y, m_Pos.z, 1, 0, m_BlockType);
|
if (Window != nullptr)
|
||||||
|
{
|
||||||
|
Window->OwnerDestroyed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,9 +20,9 @@ class cEnderChestEntity :
|
|||||||
public: // tolua_export
|
public: // tolua_export
|
||||||
|
|
||||||
cEnderChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
cEnderChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
||||||
virtual ~cEnderChestEntity() override;
|
|
||||||
|
|
||||||
// cBlockEntity overrides:
|
// cBlockEntity overrides:
|
||||||
|
virtual void OnRemoveFromWorld() override;
|
||||||
virtual bool UsedBy(cPlayer * a_Player) override;
|
virtual bool UsedBy(cPlayer * a_Player) override;
|
||||||
virtual void SendTo(cClientHandle & a_Client) override;
|
virtual void SendTo(cClientHandle & a_Client) override;
|
||||||
|
|
||||||
|
@ -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:
|
return cItem(m_Item);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public: // tolua_export
|
|||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
// cBlockEntity overrides:
|
// cBlockEntity overrides:
|
||||||
virtual void Destroy(void) override;
|
virtual cItems ConvertToPickups() const override;
|
||||||
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
||||||
virtual bool UsedBy(cPlayer * a_Player) override;
|
virtual bool UsedBy(cPlayer * a_Player) override;
|
||||||
virtual void SendTo(cClientHandle & a_Client) override;
|
virtual void SendTo(cClientHandle & a_Client) override;
|
||||||
|
@ -25,7 +25,6 @@ enum
|
|||||||
cFurnaceEntity::cFurnaceEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World):
|
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),
|
Super(a_BlockType, a_BlockMeta, a_Pos, ContentsWidth, ContentsHeight, a_World),
|
||||||
m_CurrentRecipe(nullptr),
|
m_CurrentRecipe(nullptr),
|
||||||
m_IsDestroyed(false),
|
|
||||||
m_IsCooking(a_BlockType == E_BLOCK_LIT_FURNACE),
|
m_IsCooking(a_BlockType == E_BLOCK_LIT_FURNACE),
|
||||||
m_NeedCookTime(0),
|
m_NeedCookTime(0),
|
||||||
m_TimeCooked(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)
|
void cFurnaceEntity::CopyFrom(const cBlockEntity & a_Src)
|
||||||
{
|
{
|
||||||
Super::CopyFrom(a_Src);
|
Super::CopyFrom(a_Src);
|
||||||
@ -73,7 +48,6 @@ void cFurnaceEntity::CopyFrom(const cBlockEntity & a_Src)
|
|||||||
m_CurrentRecipe = src.m_CurrentRecipe;
|
m_CurrentRecipe = src.m_CurrentRecipe;
|
||||||
m_FuelBurnTime = src.m_FuelBurnTime;
|
m_FuelBurnTime = src.m_FuelBurnTime;
|
||||||
m_IsCooking = src.m_IsCooking;
|
m_IsCooking = src.m_IsCooking;
|
||||||
m_IsDestroyed = src.m_IsDestroyed;
|
|
||||||
m_IsLoading = src.m_IsLoading;
|
m_IsLoading = src.m_IsLoading;
|
||||||
m_LastInput = src.m_LastInput;
|
m_LastInput = src.m_LastInput;
|
||||||
m_NeedCookTime = src.m_NeedCookTime;
|
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)
|
void cFurnaceEntity::SendTo(cClientHandle & a_Client)
|
||||||
{
|
{
|
||||||
// Nothing needs to be sent
|
// Nothing needs to be sent
|
||||||
@ -259,11 +247,6 @@ void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
|
|||||||
{
|
{
|
||||||
Super::OnSlotChanged(a_ItemGrid, a_SlotNum);
|
Super::OnSlotChanged(a_ItemGrid, a_SlotNum);
|
||||||
|
|
||||||
if (m_IsDestroyed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_IsLoading)
|
if (m_IsLoading)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -41,11 +41,9 @@ public:
|
|||||||
/** Constructor used for normal operation */
|
/** Constructor used for normal operation */
|
||||||
cFurnaceEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
cFurnaceEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World);
|
||||||
|
|
||||||
virtual ~cFurnaceEntity() override;
|
|
||||||
|
|
||||||
// cBlockEntity overrides:
|
// cBlockEntity overrides:
|
||||||
virtual void Destroy() override;
|
|
||||||
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
virtual void CopyFrom(const cBlockEntity & a_Src) override;
|
||||||
|
virtual void OnRemoveFromWorld() override;
|
||||||
virtual void SendTo(cClientHandle & a_Client) override;
|
virtual void SendTo(cClientHandle & a_Client) override;
|
||||||
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual bool UsedBy(cPlayer * a_Player) override;
|
virtual bool UsedBy(cPlayer * a_Player) override;
|
||||||
@ -118,9 +116,6 @@ protected:
|
|||||||
/** The item that is being smelted */
|
/** The item that is being smelted */
|
||||||
cItem m_LastInput;
|
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 */
|
/** Set to true if the furnace is cooking an item */
|
||||||
bool m_IsCooking;
|
bool m_IsCooking;
|
||||||
|
|
||||||
|
@ -220,6 +220,12 @@ void cChunk::OnUnload()
|
|||||||
// Notify the entity:
|
// Notify the entity:
|
||||||
Entity->OnRemoveFromWorld(*Entity->GetWorld());
|
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()))
|
if (affectedArea.IsInside(itr->second->GetPos()))
|
||||||
{
|
{
|
||||||
itr->second->Destroy();
|
itr->second->Destroy();
|
||||||
|
itr->second->OnRemoveFromWorld();
|
||||||
itr = m_BlockEntities.erase(itr);
|
itr = m_BlockEntities.erase(itr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -760,6 +767,7 @@ void cChunk::MoveEntityToNewChunk(OwnedEntity a_Entity)
|
|||||||
if (Neighbor == nullptr)
|
if (Neighbor == nullptr)
|
||||||
{
|
{
|
||||||
LOGWARNING("%s: Failed to move entity, destination chunk unreachable. Entity lost", __FUNCTION__);
|
LOGWARNING("%s: Failed to move entity, destination chunk unreachable. Entity lost", __FUNCTION__);
|
||||||
|
a_Entity->OnRemoveFromWorld(*m_World);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1267,6 +1275,7 @@ void cChunk::SetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_Blo
|
|||||||
if (BlockEntity != nullptr)
|
if (BlockEntity != nullptr)
|
||||||
{
|
{
|
||||||
BlockEntity->Destroy();
|
BlockEntity->Destroy();
|
||||||
|
BlockEntity->OnRemoveFromWorld();
|
||||||
RemoveBlockEntity(BlockEntity);
|
RemoveBlockEntity(BlockEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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<void *>(this)
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (m_AttachedTo != nullptr)
|
|
||||||
{
|
|
||||||
Detach();
|
|
||||||
}
|
|
||||||
if (m_Attachee != nullptr)
|
|
||||||
{
|
|
||||||
m_Attachee->Detach();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char * cEntity::GetClass(void) const
|
const char * cEntity::GetClass(void) const
|
||||||
{
|
{
|
||||||
return "cEntity";
|
return "cEntity";
|
||||||
@ -174,7 +148,22 @@ void cEntity::OnAddToWorld(cWorld & a_World)
|
|||||||
|
|
||||||
void cEntity::OnRemoveFromWorld(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);
|
a_World.BroadcastDestroyEntity(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +233,6 @@ void cEntity::Destroy()
|
|||||||
// Also, not storing the returned pointer means automatic destruction
|
// Also, not storing the returned pointer means automatic destruction
|
||||||
VERIFY(a_World.RemoveEntity(*this));
|
VERIFY(a_World.RemoveEntity(*this));
|
||||||
});
|
});
|
||||||
Destroyed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -813,10 +801,17 @@ void cEntity::KilledBy(TakeDamageInfo & a_TDI)
|
|||||||
cRoot::Get()->GetPluginManager()->CallHookKilled(*this, a_TDI, emptystring);
|
cRoot::Get()->GetPluginManager()->CallHookKilled(*this, a_TDI, emptystring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop loot:
|
// Drop loot, unless the attacker was a creative mode player:
|
||||||
cItems Drops;
|
if (
|
||||||
GetDrops(Drops, a_TDI.Attacker);
|
(a_TDI.Attacker == nullptr) ||
|
||||||
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
|
!a_TDI.Attacker->IsPlayer() ||
|
||||||
|
!static_cast<cPlayer *>(a_TDI.Attacker)->IsGameModeCreative()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
cItems Drops;
|
||||||
|
GetDrops(Drops, a_TDI.Attacker);
|
||||||
|
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
|
||||||
|
}
|
||||||
|
|
||||||
m_World->BroadcastEntityStatus(*this, esGenericDead);
|
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()
|
void cEntity::BroadcastLeashedMobs()
|
||||||
{
|
{
|
||||||
// If has any mob leashed broadcast every leashed entity to this
|
// If has any mob leashed broadcast every leashed entity to this
|
||||||
|
@ -169,7 +169,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
cEntity(eEntityType a_EntityType, Vector3d a_Pos, double a_Width, double a_Height);
|
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).
|
/** Spawns the entity in the world; returns true if spawned, false if not (plugin disallowed).
|
||||||
Adds the entity to the world. */
|
Adds the entity to the world. */
|
||||||
@ -296,7 +296,7 @@ public:
|
|||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
/** Destroys the entity, schedules it for memory freeing and broadcasts the DestroyEntity packet */
|
/** Destroys the entity, schedules it for memory freeing and broadcasts the DestroyEntity packet */
|
||||||
virtual void Destroy();
|
void Destroy();
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
|
|
||||||
/** Makes this pawn take damage from an attack by a_Attacker. Damage values are calculated automatically and DoTakeDamage() called */
|
/** 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. */
|
/** Removes a mob from the leashed list of mobs. */
|
||||||
void RemoveLeashedMob(cMonster * a_Monster);
|
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. */
|
/** Returs whether the entity has any mob leashed to it. */
|
||||||
bool HasAnyMobLeashed() const { return m_LeashedMobs.size() > 0; }
|
bool HasAnyMobLeashed() const { return m_LeashedMobs.size() > 0; }
|
||||||
|
|
||||||
@ -723,8 +720,6 @@ protected:
|
|||||||
Should handle degenerate cases such as moving to the same world. */
|
Should handle degenerate cases such as moving to the same world. */
|
||||||
virtual void DoMoveToWorld(const sWorldChangeInfo & a_WorldChangeInfo);
|
virtual void DoMoveToWorld(const sWorldChangeInfo & a_WorldChangeInfo);
|
||||||
|
|
||||||
virtual void Destroyed(void) {} // Called after the entity has been destroyed
|
|
||||||
|
|
||||||
/** Applies friction to an entity
|
/** Applies friction to an entity
|
||||||
@param a_Speed The speed vector to apply changes to
|
@param a_Speed The speed vector to apply changes to
|
||||||
@param a_SlowdownMultiplier The factor to reduce the speed by */
|
@param a_SlowdownMultiplier The factor to reduce the speed by */
|
||||||
|
@ -73,7 +73,7 @@ public:
|
|||||||
@param a_OtherEffect The other effect to copy */
|
@param a_OtherEffect The other effect to copy */
|
||||||
cEntityEffect & operator =(cEntityEffect a_OtherEffect);
|
cEntityEffect & operator =(cEntityEffect a_OtherEffect);
|
||||||
|
|
||||||
virtual ~cEntityEffect(void) {}
|
virtual ~cEntityEffect(void) = default;
|
||||||
|
|
||||||
/** Creates a pointer to the proper entity effect from the effect type
|
/** Creates a pointer to the proper entity effect from the effect type
|
||||||
@warning This function creates raw pointers that must be manually managed.
|
@warning This function creates raw pointers that must be manually managed.
|
||||||
|
@ -1203,7 +1203,6 @@ bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
|
|||||||
{
|
{
|
||||||
if ((TDI.Attacker != nullptr) && TDI.Attacker->IsPlayer() && static_cast<cPlayer *>(TDI.Attacker)->IsGameModeCreative())
|
if ((TDI.Attacker != nullptr) && TDI.Attacker->IsPlayer() && static_cast<cPlayer *>(TDI.Attacker)->IsGameModeCreative())
|
||||||
{
|
{
|
||||||
Destroy();
|
|
||||||
TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
|
TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
|
||||||
SetInvulnerableTicks(0);
|
SetInvulnerableTicks(0);
|
||||||
return Super::DoTakeDamage(TDI); // No drops for creative
|
return Super::DoTakeDamage(TDI); // No drops for creative
|
||||||
@ -1217,42 +1216,6 @@ bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
|
|||||||
|
|
||||||
m_World->BroadcastEntityMetadata(*this);
|
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;
|
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)
|
void cMinecart::ApplyAcceleration(Vector3d a_ForwardDirection, double a_Acceleration)
|
||||||
{
|
{
|
||||||
double CurSpeed = GetSpeed().Dot(a_ForwardDirection);
|
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:
|
// 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)
|
void cRideableMinecart::OnRightClicked(cPlayer & a_Player)
|
||||||
{
|
{
|
||||||
Super::OnRightClicked(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)
|
void cMinecartWithChest::OnRightClicked(cPlayer & a_Player)
|
||||||
{
|
{
|
||||||
// If the window is not created, open it anew:
|
// 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:
|
// 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)
|
void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player)
|
||||||
{
|
{
|
||||||
if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_COAL)
|
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:
|
// 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
|
// TODO: Make it suck up blocks and travel further than any other cart and physics and put and take blocks
|
||||||
// AND AVARYTHING!!
|
// AND AVARYTHING!!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMinecartWithHopper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
||||||
|
{
|
||||||
|
a_Drops.emplace_back(E_ITEM_MINECART_WITH_HOPPER);
|
||||||
|
}
|
||||||
|
@ -40,12 +40,12 @@ public:
|
|||||||
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
||||||
virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual bool DoTakeDamage(TakeDamageInfo & TDI) 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; }
|
int LastDamage(void) const { return m_LastDamage; }
|
||||||
ePayload GetPayload(void) const { return m_Payload; }
|
ePayload GetPayload(void) const { return m_Payload; }
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
ePayload m_Payload;
|
ePayload m_Payload;
|
||||||
@ -99,7 +99,7 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cRideableMinecart :
|
class cRideableMinecart final :
|
||||||
public cMinecart
|
public cMinecart
|
||||||
{
|
{
|
||||||
using Super = cMinecart;
|
using Super = cMinecart;
|
||||||
@ -114,6 +114,7 @@ public:
|
|||||||
int GetBlockHeight(void) const {return m_Height;}
|
int GetBlockHeight(void) const {return m_Height;}
|
||||||
|
|
||||||
// cEntity overrides:
|
// cEntity overrides:
|
||||||
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
|
||||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -127,7 +128,7 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cMinecartWithChest :
|
class cMinecartWithChest final :
|
||||||
public cMinecart,
|
public cMinecart,
|
||||||
public cItemGrid::cListener,
|
public cItemGrid::cListener,
|
||||||
public cEntityWindowOwner
|
public cEntityWindowOwner
|
||||||
@ -154,7 +155,6 @@ protected:
|
|||||||
|
|
||||||
cItemGrid m_Contents;
|
cItemGrid m_Contents;
|
||||||
void OpenNewWindow(void);
|
void OpenNewWindow(void);
|
||||||
virtual void Destroyed() override;
|
|
||||||
|
|
||||||
// cItemGrid::cListener overrides:
|
// cItemGrid::cListener overrides:
|
||||||
virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) override
|
virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) override
|
||||||
@ -173,6 +173,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cEntity overrides:
|
// 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;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
@ -180,7 +182,7 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cMinecartWithFurnace :
|
class cMinecartWithFurnace final :
|
||||||
public cMinecart
|
public cMinecart
|
||||||
{
|
{
|
||||||
using Super = cMinecart;
|
using Super = cMinecart;
|
||||||
@ -192,6 +194,7 @@ public:
|
|||||||
cMinecartWithFurnace(Vector3d a_Pos);
|
cMinecartWithFurnace(Vector3d a_Pos);
|
||||||
|
|
||||||
// cEntity overrides:
|
// cEntity overrides:
|
||||||
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
|
||||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) 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
|
public cMinecart
|
||||||
{
|
{
|
||||||
using Super = cMinecart;
|
using Super = cMinecart;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CLASS_PROTODEF(cMinecartWithTNT)
|
CLASS_PROTODEF(cMinecartWithTNT)
|
||||||
|
|
||||||
cMinecartWithTNT(Vector3d a_Pos);
|
cMinecartWithTNT(Vector3d a_Pos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cMinecartWithHopper :
|
class cMinecartWithHopper final :
|
||||||
public cMinecart
|
public cMinecart
|
||||||
{
|
{
|
||||||
using Super = cMinecart;
|
using Super = cMinecart;
|
||||||
@ -238,4 +246,8 @@ public:
|
|||||||
CLASS_PROTODEF(cMinecartWithHopper)
|
CLASS_PROTODEF(cMinecartWithHopper)
|
||||||
|
|
||||||
cMinecartWithHopper(Vector3d a_Pos);
|
cMinecartWithHopper(Vector3d a_Pos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
|
||||||
} ;
|
} ;
|
||||||
|
@ -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)
|
void cPawn::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||||
{
|
{
|
||||||
std::vector<cEntityEffect *> EffectsToTick;
|
std::vector<cEntityEffect *> EffectsToTick;
|
||||||
@ -453,6 +434,16 @@ void cPawn::HandleFalling(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cPawn::OnRemoveFromWorld(cWorld & a_World)
|
||||||
|
{
|
||||||
|
StopEveryoneFromTargetingMe();
|
||||||
|
Super::OnRemoveFromWorld(a_World);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPawn::StopEveryoneFromTargetingMe()
|
void cPawn::StopEveryoneFromTargetingMe()
|
||||||
{
|
{
|
||||||
std::vector<cMonster*>::iterator i = m_TargetingMe.begin();
|
std::vector<cMonster*>::iterator i = m_TargetingMe.begin();
|
||||||
|
@ -23,8 +23,6 @@ public:
|
|||||||
CLASS_PROTODEF(cPawn)
|
CLASS_PROTODEF(cPawn)
|
||||||
|
|
||||||
cPawn(eEntityType a_EntityType, double a_Width, double a_Height);
|
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 Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual void KilledBy(TakeDamageInfo & a_TDI) override;
|
virtual void KilledBy(TakeDamageInfo & a_TDI) override;
|
||||||
@ -33,6 +31,7 @@ public:
|
|||||||
virtual bool IsInvisible() const override;
|
virtual bool IsInvisible() const override;
|
||||||
virtual void HandleAir(void) override;
|
virtual void HandleAir(void) override;
|
||||||
virtual void HandleFalling(void);
|
virtual void HandleFalling(void);
|
||||||
|
virtual void OnRemoveFromWorld(cWorld & a_World) override;
|
||||||
|
|
||||||
/** Tells all pawns which are targeting us to stop targeting us. */
|
/** Tells all pawns which are targeting us to stop targeting us. */
|
||||||
void StopEveryoneFromTargetingMe();
|
void StopEveryoneFromTargetingMe();
|
||||||
@ -85,7 +84,3 @@ private:
|
|||||||
/** A list of all monsters that are targeting this pawn. */
|
/** A list of all monsters that are targeting this pawn. */
|
||||||
std::vector<cMonster*> m_TargetingMe;
|
std::vector<cMonster*> m_TargetingMe;
|
||||||
} ; // tolua_export
|
} ; // tolua_export
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -280,10 +280,9 @@ cPlayer::~cPlayer(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPlayer::Destroyed()
|
void cPlayer::OnRemoveFromWorld(cWorld & a_World)
|
||||||
{
|
{
|
||||||
CloseWindow(false);
|
CloseWindow(false);
|
||||||
Super::Destroyed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ public:
|
|||||||
|
|
||||||
virtual ~cPlayer() override;
|
virtual ~cPlayer() override;
|
||||||
|
|
||||||
|
virtual void OnRemoveFromWorld(cWorld & a_World) override;
|
||||||
|
|
||||||
virtual void SpawnOn(cClientHandle & a_Client) override;
|
virtual void SpawnOn(cClientHandle & a_Client) override;
|
||||||
|
|
||||||
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) 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. */
|
/** 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 DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) override;
|
||||||
|
|
||||||
virtual void Destroyed(void) override;
|
|
||||||
|
|
||||||
/** Filters out damage for creative mode / friendly fire */
|
/** Filters out damage for creative mode / friendly fire */
|
||||||
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||||
|
|
||||||
|
@ -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)
|
void cHorse::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||||
{
|
{
|
||||||
Super::Tick(a_Dt, 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)
|
void cHorse::OnRightClicked(cPlayer & a_Player)
|
||||||
{
|
{
|
||||||
Super::OnRightClicked(a_Player);
|
Super::OnRightClicked(a_Player);
|
||||||
|
@ -17,7 +17,6 @@ class cHorse:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
cHorse(int Type, int Color, int Style, int TameTimes);
|
cHorse(int Type, int Color, int Style, int TameTimes);
|
||||||
virtual ~cHorse() override;
|
|
||||||
|
|
||||||
CLASS_PROTODEF(cHorse)
|
CLASS_PROTODEF(cHorse)
|
||||||
|
|
||||||
@ -25,6 +24,7 @@ public:
|
|||||||
virtual void InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
virtual void InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) 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 Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||||
|
virtual void OnRemoveFromWorld(cWorld & a_World) override;
|
||||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
|
|
||||||
bool IsSaddled (void) const {return !m_Saddle.IsEmpty(); }
|
bool IsSaddled (void) const {return !m_Saddle.IsEmpty(); }
|
||||||
@ -66,7 +66,3 @@ private:
|
|||||||
cItem m_Armor;
|
cItem m_Armor;
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
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())
|
if (IsLeashed())
|
||||||
{
|
{
|
||||||
cEntity * LeashedTo = GetLeashedTo();
|
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)
|
void cMonster::SpawnOn(cClientHandle & a_Client)
|
||||||
{
|
{
|
||||||
a_Client.SendSpawnMob(*this);
|
a_Client.SendSpawnMob(*this);
|
||||||
@ -762,22 +746,14 @@ void cMonster::CheckEventSeePlayer(cChunk & a_Chunk)
|
|||||||
const auto MyHeadPosition = GetPosition().addedY(GetHeight());
|
const auto MyHeadPosition = GetPosition().addedY(GetHeight());
|
||||||
|
|
||||||
// Enumerate all players within sight:
|
// 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())
|
if (!a_Player.CanMobsTarget())
|
||||||
{
|
|
||||||
// Continue iteration:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto Player = static_cast<cPlayer *>(&a_Entity);
|
|
||||||
|
|
||||||
if (!Player->CanMobsTarget())
|
|
||||||
{
|
{
|
||||||
return false;
|
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();
|
const auto TargetDistance = (TargetHeadPosition - MyHeadPosition).SqrLength();
|
||||||
|
|
||||||
// TODO: Currently all mobs see through lava, but only Nether-native mobs should be able to.
|
// 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)
|
cLineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetHeadPosition, cLineBlockTracer::losAirWaterLava)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
TargetPlayer = Player;
|
TargetPlayer = &a_Player;
|
||||||
ClosestDistance = TargetDistance;
|
ClosestDistance = TargetDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
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 OnRemoveFromWorld(cWorld & a_World) override;
|
||||||
|
|
||||||
virtual void Destroyed() override;
|
|
||||||
|
|
||||||
CLASS_PROTODEF(cMonster)
|
|
||||||
|
|
||||||
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
||||||
|
|
||||||
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||||
|
@ -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)
|
void cPassiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||||
{
|
{
|
||||||
Super::Tick(a_Dt, a_Chunk);
|
Super::Tick(a_Dt, a_Chunk);
|
||||||
|
@ -30,10 +30,4 @@ public:
|
|||||||
|
|
||||||
/** When hit by someone, run away */
|
/** When hit by someone, run away */
|
||||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||||
|
|
||||||
virtual void Destroyed(void) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -418,7 +418,6 @@ void cWindow::SetProperty(size_t a_Property, short a_Value)
|
|||||||
|
|
||||||
void cWindow::OwnerDestroyed()
|
void cWindow::OwnerDestroyed()
|
||||||
{
|
{
|
||||||
m_Owner = nullptr;
|
|
||||||
// Close window for each player. Note that the last one needs special handling
|
// Close window for each player. Note that the last one needs special handling
|
||||||
while (m_OpenedBy.size() > 1)
|
while (m_OpenedBy.size() > 1)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user