1
0
Fork 0

BlockEntities: Support cloning self.

This commit is contained in:
Mattes D 2017-06-15 15:32:33 +02:00 committed by Lukas Pioch
parent 49e015b8de
commit 0dd1cd750b
41 changed files with 640 additions and 309 deletions

View File

@ -11,13 +11,14 @@
cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World): cBeaconEntity::cBeaconEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, 1, 1, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, 1, 1, a_World),
m_IsActive(false), m_IsActive(false),
m_BeaconLevel(0), m_BeaconLevel(0),
m_PrimaryEffect(cEntityEffect::effNoEffect), m_PrimaryEffect(cEntityEffect::effNoEffect),
m_SecondaryEffect(cEntityEffect::effNoEffect) m_SecondaryEffect(cEntityEffect::effNoEffect)
{ {
ASSERT(a_BlockType == E_BLOCK_BEACON);
UpdateBeacon(); UpdateBeacon();
} }
@ -268,6 +269,30 @@ void cBeaconEntity::GiveEffects(void)
void cBeaconEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cBeaconEntity &>(a_Src);
m_BeaconLevel = src.m_BeaconLevel;
m_Contents.CopyFrom(src.m_Contents);
m_IsActive = src.m_IsActive;
m_PrimaryEffect = src.m_PrimaryEffect;
m_SecondaryEffect = src.m_SecondaryEffect;
}
void cBeaconEntity::SendTo(cClientHandle & a_Client)
{
a_Client.SendUpdateBlockEntity(*this);
}
bool cBeaconEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) bool cBeaconEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
// Update the beacon every 4 seconds // Update the beacon every 4 seconds
@ -306,12 +331,3 @@ bool cBeaconEntity::UsedBy(cPlayer * a_Player)
void cBeaconEntity::SendTo(cClientHandle & a_Client)
{
a_Client.SendUpdateBlockEntity(*this);
}

View File

@ -19,16 +19,17 @@
class cBeaconEntity : class cBeaconEntity :
public cBlockEntityWithItems public cBlockEntityWithItems
{ {
typedef cBlockEntityWithItems super; typedef cBlockEntityWithItems Super;
public: public:
// tolua_end // tolua_end
BLOCKENTITY_PROTODEF(cBeaconEntity) BLOCKENTITY_PROTODEF(cBeaconEntity)
cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cBeaconEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
// cBlockEntity overrides: // cBlockEntity overrides:
virtual void CopyFrom(const cBlockEntity & a_Src) 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;

View File

@ -29,24 +29,24 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
{ {
switch (a_BlockType) switch (a_BlockType)
{ {
case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World, a_BlockType); case E_BLOCK_CHEST: return new cChestEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_BREWING_STAND: return new cBrewingstandEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); case E_BLOCK_BREWING_STAND: return new cBrewingstandEntity(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_MOB_SPAWNER: return new cMobSpawnerEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_MOB_SPAWNER: return new cMobSpawnerEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_TRAPPED_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World, a_BlockType); case E_BLOCK_TRAPPED_CHEST: return new cChestEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
} }
LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)", LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)",
__FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str() __FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str()
@ -58,3 +58,25 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
cBlockEntity * cBlockEntity::Clone(int a_BlockX, int a_BlockY, int a_BlockZ)
{
auto res = std::unique_ptr<cBlockEntity>(CreateByBlockType(m_BlockType, m_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, nullptr));
res->CopyFrom(*this);
return res.release();
}
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);
}

View File

@ -9,7 +9,7 @@
#define BLOCKENTITY_PROTODEF(classname) \ #define BLOCKENTITY_PROTODEF(classname) \
virtual bool IsA(const char * a_ClassName) const override \ virtual bool IsA(const char * a_ClassName) const override \
{ \ { \
return ((a_ClassName != nullptr) && ((strcmp(a_ClassName, #classname) == 0) || super::IsA(a_ClassName))); \ return ((a_ClassName != nullptr) && ((strcmp(a_ClassName, #classname) == 0) || Super::IsA(a_ClassName))); \
} \ } \
virtual const char * GetClass(void) const override \ virtual const char * GetClass(void) const override \
{ \ { \
@ -21,7 +21,7 @@
} \ } \
virtual const char * GetParentClass(void) const override \ virtual const char * GetParentClass(void) const override \
{ \ { \
return super::GetClass(); \ return Super::GetClass(); \
} }
@ -40,13 +40,14 @@ class cWorld;
class cBlockEntity class cBlockEntity
{ {
protected: protected:
cBlockEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cBlockEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
m_PosX(a_BlockX), m_PosX(a_BlockX),
m_PosY(a_BlockY), m_PosY(a_BlockY),
m_PosZ(a_BlockZ), m_PosZ(a_BlockZ),
m_RelX(a_BlockX - cChunkDef::Width * FAST_FLOOR_DIV(a_BlockX, cChunkDef::Width)), m_RelX(a_BlockX - cChunkDef::Width * FAST_FLOOR_DIV(a_BlockX, cChunkDef::Width)),
m_RelZ(a_BlockZ - cChunkDef::Width * FAST_FLOOR_DIV(a_BlockZ, cChunkDef::Width)), m_RelZ(a_BlockZ - cChunkDef::Width * FAST_FLOOR_DIV(a_BlockZ, cChunkDef::Width)),
m_BlockType(a_BlockType), m_BlockType(a_BlockType),
m_BlockMeta(a_BlockMeta),
m_World(a_World) m_World(a_World)
{ {
} }
@ -68,6 +69,15 @@ public:
Returns nullptr for unknown block types. */ Returns nullptr for unknown block types. */
static cBlockEntity * CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World = nullptr); static cBlockEntity * CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, 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.
Uses CopyFrom() to copy the properties. */
cBlockEntity * Clone(int a_BlockX, int a_BlockY, int a_BlockZ);
/** Copies all properties of a_Src into this entity, except for its m_World and location.
Each non-abstract descendant should override to copy its specific properties, and call
Super::CopyFrom(a_Src) to copy the common ones. */
virtual void CopyFrom(const cBlockEntity & a_Src);
static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates
{ {
return "cBlockEntity"; return "cBlockEntity";
@ -124,8 +134,14 @@ protected:
/** Position relative to the chunk, used to speed up ticking */ /** Position relative to the chunk, used to speed up ticking */
int m_RelX, m_RelZ; int m_RelX, m_RelZ;
/** The blocktype representing this particular instance in the world.
Mainly used for multi-block-type entities, such as furnaces / lit furnaces. */
BLOCKTYPE m_BlockType; BLOCKTYPE m_BlockType;
/** The block meta representing this particular instance in the world
Mainly used for directional entities, such as dispensers. */
NIBBLETYPE m_BlockMeta;
cWorld * m_World; cWorld * m_World;
} ; // tolua_export } ; // tolua_export

View File

@ -0,0 +1,72 @@
// BlockEntityWithItems.cpp
// Implements the cBlockEntityWithItems class representing a common ancestor for all block entities that have an ItemGrid
#include "Globals.h"
#include "BlockEntityWithItems.h"
cBlockEntityWithItems::cBlockEntityWithItems(
BLOCKTYPE a_BlockType,
NIBBLETYPE a_BlockMeta,
int a_BlockX, int a_BlockY, int a_BlockZ,
int a_ItemGridWidth, int a_ItemGridHeight,
cWorld * a_World
):
Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World),
cBlockEntityWindowOwner(this),
m_Contents(a_ItemGridWidth, a_ItemGridHeight)
{
m_Contents.AddListener(*this);
}
void cBlockEntityWithItems::Destroy(void)
{
// Drop the contents as pickups:
ASSERT(m_World != nullptr);
cItems Pickups;
m_Contents.CopyToItems(Pickups);
m_Contents.Clear();
m_World->SpawnItemPickups(Pickups, m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5); // Spawn in centre of block
}
void cBlockEntityWithItems::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cBlockEntityWithItems &>(a_Src);
m_Contents.CopyFrom(src.m_Contents);
}
void cBlockEntityWithItems::OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum)
{
UNUSED(a_SlotNum);
ASSERT(a_Grid == &m_Contents);
if (m_World != nullptr)
{
if (GetWindow() != nullptr)
{
GetWindow()->BroadcastWholeWindow();
}
m_World->MarkChunkDirty(GetChunkX(), GetChunkZ());
}
}

View File

@ -26,35 +26,25 @@ class cBlockEntityWithItems :
// tolua_begin // tolua_begin
public cBlockEntityWindowOwner public cBlockEntityWindowOwner
{ {
typedef cBlockEntity super; typedef cBlockEntity Super;
public: public:
// tolua_end // tolua_end
BLOCKENTITY_PROTODEF(cBlockEntityWithItems) BLOCKENTITY_PROTODEF(cBlockEntityWithItems)
cBlockEntityWithItems( cBlockEntityWithItems(
BLOCKTYPE a_BlockType, // Type of the block that the entity represents BLOCKTYPE a_BlockType, // Type of the block that the entity represents
NIBBLETYPE a_BlockMeta, // Meta of the block that the entity represents
int a_BlockX, int a_BlockY, int a_BlockZ, // Position of the block entity int a_BlockX, int a_BlockY, int a_BlockZ, // Position of the block entity
int a_ItemGridWidth, int a_ItemGridHeight, // Dimensions of the ItemGrid int a_ItemGridWidth, int a_ItemGridHeight, // Dimensions of the ItemGrid
cWorld * a_World // Optional world to assign to the entity cWorld * a_World // Optional world to assign to the entity
) : );
super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World),
cBlockEntityWindowOwner(this),
m_Contents(a_ItemGridWidth, a_ItemGridHeight)
{
m_Contents.AddListener(*this);
}
virtual void Destroy(void) override // cBlockEntity overrides:
{ virtual void Destroy(void) override;
// Drop the contents as pickups: virtual void CopyFrom(const cBlockEntity & a_Src) override;
ASSERT(m_World != nullptr);
cItems Pickups;
m_Contents.CopyToItems(Pickups);
m_Contents.Clear();
m_World->SpawnItemPickups(Pickups, m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5); // Spawn in centre of block
}
// tolua_begin // tolua_begin
@ -76,20 +66,7 @@ protected:
cItemGrid m_Contents; cItemGrid m_Contents;
// 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;
{
UNUSED(a_SlotNum);
ASSERT(a_Grid == &m_Contents);
if (m_World != nullptr)
{
if (GetWindow() != nullptr)
{
GetWindow()->BroadcastWholeWindow();
}
m_World->MarkChunkDirty(GetChunkX(), GetChunkZ());
}
}
} ; // tolua_export } ; // tolua_export

View File

@ -19,19 +19,14 @@
cBrewingstandEntity::cBrewingstandEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World) : cBrewingstandEntity::cBrewingstandEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_BlockMeta(a_BlockMeta),
m_IsDestroyed(false), m_IsDestroyed(false),
m_IsBrewing(false), m_IsBrewing(false),
m_TimeBrewed(0), m_TimeBrewed(0),
m_RemainingFuel(0) m_RemainingFuel(0)
{ {
m_Contents.AddListener(*this); m_Contents.AddListener(*this);
for (int i = 0; i < 3; i++)
{
m_Results[i] = cItem{};
}
} }
@ -52,33 +47,41 @@ cBrewingstandEntity::~cBrewingstandEntity()
bool cBrewingstandEntity::UsedBy(cPlayer * a_Player) void cBrewingstandEntity::Destroy()
{ {
cWindow * Window = GetWindow(); m_IsDestroyed = true;
if (Window == nullptr) Super::Destroy();
{ }
OpenWindow(new cBrewingstandWindow(m_PosX, m_PosY, m_PosZ, this));
Window = GetWindow();
}
if (Window != nullptr)
{
if (a_Player->GetWindow() != Window)
{
a_Player->OpenWindow(*Window);
}
}
if (m_IsBrewing)
void cBrewingstandEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cBrewingstandEntity &>(a_Src);
m_IsBrewing = src.m_IsBrewing;
for (size_t i = 0; i < ARRAYCOUNT(m_CurrentBrewingRecipes); ++i)
{ {
BroadcastProgress(0, m_NeedBrewingTime - m_TimeBrewed); m_CurrentBrewingRecipes[i] = src.m_CurrentBrewingRecipes[i];
} }
else for (size_t i = 0; i < ARRAYCOUNT(m_Results); ++i)
{ {
BroadcastProgress(0, 0); m_Results[i] = src.m_Results[i];
} }
BroadcastProgress(1, m_RemainingFuel); m_TimeBrewed = src.m_TimeBrewed;
return true; m_RemainingFuel = src.m_RemainingFuel;
}
void cBrewingstandEntity::SendTo(cClientHandle & a_Client)
{
// Nothing needs to be sent
UNUSED(a_Client);
} }
@ -159,10 +162,33 @@ bool cBrewingstandEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
void cBrewingstandEntity::SendTo(cClientHandle & a_Client) bool cBrewingstandEntity::UsedBy(cPlayer * a_Player)
{ {
// Nothing needs to be sent cWindow * Window = GetWindow();
UNUSED(a_Client); if (Window == nullptr)
{
OpenWindow(new cBrewingstandWindow(m_PosX, m_PosY, m_PosZ, this));
Window = GetWindow();
}
if (Window != nullptr)
{
if (a_Player->GetWindow() != Window)
{
a_Player->OpenWindow(*Window);
}
}
if (m_IsBrewing)
{
BroadcastProgress(0, m_NeedBrewingTime - m_TimeBrewed);
}
else
{
BroadcastProgress(0, 0);
}
BroadcastProgress(1, m_RemainingFuel);
return true;
} }
@ -185,7 +211,7 @@ void cBrewingstandEntity::BroadcastProgress(short a_ProgressbarID, short a_Value
void cBrewingstandEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) void cBrewingstandEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
{ {
super::OnSlotChanged(a_ItemGrid, a_SlotNum); Super::OnSlotChanged(a_ItemGrid, a_SlotNum);
if (m_IsDestroyed) if (m_IsDestroyed)
{ {

View File

@ -18,7 +18,7 @@ class cClientHandle;
class cBrewingstandEntity : class cBrewingstandEntity :
public cBlockEntityWithItems public cBlockEntityWithItems
{ {
typedef cBlockEntityWithItems super; typedef cBlockEntityWithItems Super;
public: public:
enum enum
@ -38,19 +38,16 @@ public:
BLOCKENTITY_PROTODEF(cBrewingstandEntity) BLOCKENTITY_PROTODEF(cBrewingstandEntity)
/** Constructor used for normal operation */ /** Constructor used for normal operation */
cBrewingstandEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World); cBrewingstandEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cBrewingstandEntity() override; virtual ~cBrewingstandEntity() override;
// cBlockEntity overrides: // cBlockEntity overrides:
virtual void Destroy() override;
virtual void CopyFrom(const cBlockEntity & a_Src) 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;
virtual void Destroy() override
{
m_IsDestroyed = true;
super::Destroy();
}
// tolua_begin // tolua_begin
@ -109,10 +106,9 @@ 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:
/** Block meta of the block currently represented by this entity */
NIBBLETYPE m_BlockMeta; protected:
/** Set to true when the brewing stand entity has been destroyed to prevent the block being set again */ /** Set to true when the brewing stand entity has been destroyed to prevent the block being set again */
bool m_IsDestroyed; bool m_IsDestroyed;
@ -127,7 +123,7 @@ protected:
const cBrewingRecipes::cRecipe * m_CurrentBrewingRecipes[3] = {}; const cBrewingRecipes::cRecipe * m_CurrentBrewingRecipes[3] = {};
/** Result items for the bottle inputs */ /** Result items for the bottle inputs */
cItem m_Results[3] = {}; cItem m_Results[3];
/** Amount of ticks that the current item has been brewed */ /** Amount of ticks that the current item has been brewed */
short m_TimeBrewed; short m_TimeBrewed;

View File

@ -5,6 +5,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
SET (SRCS SET (SRCS
BeaconEntity.cpp BeaconEntity.cpp
BlockEntity.cpp BlockEntity.cpp
BlockEntityWithItems.cpp
BrewingstandEntity.cpp BrewingstandEntity.cpp
ChestEntity.cpp ChestEntity.cpp
CommandBlockEntity.cpp CommandBlockEntity.cpp

View File

@ -11,8 +11,8 @@
cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type) : cChestEntity::cChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(a_Type, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_NumActivePlayers(0), m_NumActivePlayers(0),
m_Neighbour(nullptr) m_Neighbour(nullptr)
{ {
@ -46,6 +46,21 @@ cChestEntity::~cChestEntity()
void cChestEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cChestEntity &>(a_Src);
m_Contents.CopyFrom(src.m_Contents);
// Reset the neighbor and player count, there's no sense in copying these:
m_Neighbour = nullptr;
m_NumActivePlayers = 0;
}
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:

View File

@ -17,7 +17,7 @@ class cClientHandle;
class cChestEntity : class cChestEntity :
public cBlockEntityWithItems public cBlockEntityWithItems
{ {
typedef cBlockEntityWithItems super; typedef cBlockEntityWithItems Super;
public: public:
enum enum
@ -31,11 +31,12 @@ public:
BLOCKENTITY_PROTODEF(cChestEntity) BLOCKENTITY_PROTODEF(cChestEntity)
/** Constructor used for normal operation */ /** Constructor used for normal operation */
cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type); cChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cChestEntity() override; virtual ~cChestEntity() override;
// cBlockEntity overrides: // cBlockEntity overrides:
virtual void CopyFrom(const cBlockEntity & a_Src) 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;

View File

@ -17,11 +17,13 @@
cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) : cCommandBlockEntity::cCommandBlockEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World),
m_ShouldExecute(false), m_ShouldExecute(false),
m_Result(0) m_Result(0)
{} {
ASSERT(a_BlockType == E_BLOCK_COMMAND_BLOCK);
}
@ -112,6 +114,20 @@ void cCommandBlockEntity::Activate(void)
void cCommandBlockEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cCommandBlockEntity &>(a_Src);
m_Command = src.m_Command;
m_LastOutput = src.m_LastOutput;
m_Result = src.m_Result;
m_ShouldExecute = src.m_ShouldExecute;
}
bool cCommandBlockEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) bool cCommandBlockEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
UNUSED(a_Dt); UNUSED(a_Dt);

View File

@ -20,7 +20,7 @@
class cCommandBlockEntity : class cCommandBlockEntity :
public cBlockEntity public cBlockEntity
{ {
typedef cBlockEntity super; typedef cBlockEntity Super;
public: public:
@ -29,8 +29,10 @@ public:
BLOCKENTITY_PROTODEF(cCommandBlockEntity) BLOCKENTITY_PROTODEF(cCommandBlockEntity)
/** Creates a new empty command block entity */ /** Creates a new empty command block entity */
cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World); cCommandBlockEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
// cBlockEntity overrides:
virtual void CopyFrom(const cBlockEntity & a_Src) 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;

View File

@ -13,9 +13,10 @@
cDispenserEntity::cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cDispenserEntity::cDispenserEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(E_BLOCK_DISPENSER, a_BlockX, a_BlockY, a_BlockZ, a_World) Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World)
{ {
ASSERT(a_BlockType == E_BLOCK_DISPENSER);
} }
@ -309,9 +310,9 @@ Vector3d cDispenserEntity::GetShootVector(NIBBLETYPE a_Meta)
bool cDispenserEntity::ScoopUpLiquid(int a_SlotNum, short a_BucketItemType) bool cDispenserEntity::ScoopUpLiquid(int a_SlotNum, short a_ResultingBucketItemType)
{ {
cItem LiquidBucket(a_BucketItemType, 1); cItem LiquidBucket(a_ResultingBucketItemType, 1);
if (m_Contents.GetSlot(a_SlotNum).m_ItemCount == 1) if (m_Contents.GetSlot(a_SlotNum).m_ItemCount == 1)
{ {
// Special case: replacing one empty bucket with one full bucket // Special case: replacing one empty bucket with one full bucket

View File

@ -11,7 +11,7 @@
class cDispenserEntity : class cDispenserEntity :
public cDropSpenserEntity public cDropSpenserEntity
{ {
typedef cDropSpenserEntity super; typedef cDropSpenserEntity Super;
public: public:
@ -20,7 +20,7 @@ public:
BLOCKENTITY_PROTODEF(cDispenserEntity) BLOCKENTITY_PROTODEF(cDispenserEntity)
/** Constructor used for normal operation */ /** Constructor used for normal operation */
cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cDispenserEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
// tolua_begin // tolua_begin
@ -38,7 +38,7 @@ private:
virtual void DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) override; virtual void DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) override;
/** If such a bucket can fit, adds it to m_Contents and returns true */ /** If such a bucket can fit, adds it to m_Contents and returns true */
bool ScoopUpLiquid(int a_SlotNum, short a_BucketItemType); bool ScoopUpLiquid(int a_SlotNum, short a_ResultingBucketItemType);
/** If the a_BlockInFront can be washed away by liquid and the empty bucket can fit, /** If the a_BlockInFront can be washed away by liquid and the empty bucket can fit,
does the m_Contents processing and returns true. Returns false otherwise. */ does the m_Contents processing and returns true. Returns false otherwise. */

View File

@ -15,8 +15,8 @@
cDropSpenserEntity::cDropSpenserEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cDropSpenserEntity::cDropSpenserEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_ShouldDropSpense(false) m_ShouldDropSpense(false)
{ {
} }
@ -113,6 +113,18 @@ void cDropSpenserEntity::Activate(void)
void cDropSpenserEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cDropSpenserEntity &>(a_Src);
m_Contents.CopyFrom(src.m_Contents);
m_ShouldDropSpense = src.m_ShouldDropSpense;
}
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);

View File

@ -26,7 +26,7 @@ class cClientHandle;
class cDropSpenserEntity : class cDropSpenserEntity :
public cBlockEntityWithItems public cBlockEntityWithItems
{ {
typedef cBlockEntityWithItems super; typedef cBlockEntityWithItems Super;
public: public:
enum enum
@ -39,10 +39,11 @@ public:
BLOCKENTITY_PROTODEF(cDropSpenserEntity) BLOCKENTITY_PROTODEF(cDropSpenserEntity)
cDropSpenserEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cDropSpenserEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cDropSpenserEntity() override; virtual ~cDropSpenserEntity() override;
// cBlockEntity overrides: // cBlockEntity overrides:
virtual void CopyFrom(const cBlockEntity & a_Src);
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;

View File

@ -10,9 +10,10 @@
cDropperEntity::cDropperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cDropperEntity::cDropperEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(E_BLOCK_DROPPER, a_BlockX, a_BlockY, a_BlockZ, a_World) Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World)
{ {
ASSERT(a_BlockType == E_BLOCK_DROPPER);
} }

View File

@ -19,7 +19,7 @@
class cDropperEntity : class cDropperEntity :
public cDropSpenserEntity public cDropSpenserEntity
{ {
typedef cDropSpenserEntity super; typedef cDropSpenserEntity Super;
public: public:
@ -28,7 +28,7 @@ public:
BLOCKENTITY_PROTODEF(cDropperEntity) BLOCKENTITY_PROTODEF(cDropperEntity)
/** Constructor used for normal operation */ /** Constructor used for normal operation */
cDropperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cDropperEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
protected: protected:
// cDropSpenserEntity overrides: // cDropSpenserEntity overrides:

View File

@ -12,10 +12,11 @@
cEnderChestEntity::cEnderChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cEnderChestEntity::cEnderChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(E_BLOCK_ENDER_CHEST, a_BlockX, a_BlockY, a_BlockZ, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World),
cBlockEntityWindowOwner(this) cBlockEntityWindowOwner(this)
{ {
ASSERT(a_BlockType == E_BLOCK_ENDER_CHEST);
} }

View File

@ -13,14 +13,14 @@ class cEnderChestEntity :
public cBlockEntity, public cBlockEntity,
public cBlockEntityWindowOwner public cBlockEntityWindowOwner
{ {
typedef cBlockEntity super; typedef cBlockEntity Super;
public: public:
// tolua_end // tolua_end
BLOCKENTITY_PROTODEF(cEnderChestEntity) BLOCKENTITY_PROTODEF(cEnderChestEntity)
cEnderChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cEnderChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cEnderChestEntity() override; virtual ~cEnderChestEntity() override;
// cBlockEntity overrides: // cBlockEntity overrides:

View File

@ -13,16 +13,45 @@
cFlowerPotEntity::cFlowerPotEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cFlowerPotEntity::cFlowerPotEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(E_BLOCK_FLOWER_POT, a_BlockX, a_BlockY, a_BlockZ, a_World) Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World)
{ {
ASSERT(a_BlockType == E_BLOCK_FLOWER_POT);
}
void cFlowerPotEntity::Destroy(void)
{
// Drop the contents as pickups:
if (!m_Item.IsEmpty())
{
ASSERT(m_World != nullptr);
cItems Pickups;
Pickups.Add(m_Item);
m_World->SpawnItemPickups(Pickups, m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5);
m_Item.Empty();
}
}
void cFlowerPotEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cFlowerPotEntity &>(a_Src);
m_Item = src.m_Item;
} }
// It don't do anything when 'used'
bool cFlowerPotEntity::UsedBy(cPlayer * a_Player) bool cFlowerPotEntity::UsedBy(cPlayer * a_Player)
{ {
if (IsItemInPot()) if (IsItemInPot())
@ -56,24 +85,6 @@ void cFlowerPotEntity::SendTo(cClientHandle & a_Client)
void cFlowerPotEntity::Destroy(void)
{
// Drop the contents as pickups:
if (!m_Item.IsEmpty())
{
ASSERT(m_World != nullptr);
cItems Pickups;
Pickups.Add(m_Item);
m_World->SpawnItemPickups(Pickups, m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5);
m_Item.Empty();
}
}
bool cFlowerPotEntity::IsFlower(short m_ItemType, short m_ItemData) bool cFlowerPotEntity::IsFlower(short m_ItemType, short m_ItemData)
{ {
switch (m_ItemType) switch (m_ItemType)

View File

@ -20,7 +20,7 @@
class cFlowerPotEntity : class cFlowerPotEntity :
public cBlockEntity public cBlockEntity
{ {
typedef cBlockEntity super; typedef cBlockEntity Super;
public: public:
@ -29,9 +29,8 @@ public:
BLOCKENTITY_PROTODEF(cFlowerPotEntity) BLOCKENTITY_PROTODEF(cFlowerPotEntity)
/** Creates a new flowerpot entity at the specified block coords. a_World may be nullptr */ /** Creates a new flowerpot entity at the specified block coords. a_World may be nullptr */
cFlowerPotEntity(int a_BlocX, int a_BlockY, int a_BlockZ, cWorld * a_World); cFlowerPotEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual void Destroy(void) override;
// tolua_begin // tolua_begin
@ -46,7 +45,9 @@ public:
// tolua_end // tolua_end
/** Called when the player is using the entity; returns true if it was a successful use, return false if it should be treated as a normal block */ // cBlockEntity overrides:
virtual void Destroy(void) 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;

View File

@ -23,9 +23,8 @@ enum
cFurnaceEntity::cFurnaceEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World) : cFurnaceEntity::cFurnaceEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_BlockMeta(a_BlockMeta),
m_CurrentRecipe(nullptr), m_CurrentRecipe(nullptr),
m_IsDestroyed(false), m_IsDestroyed(false),
m_IsCooking(a_BlockType == E_BLOCK_LIT_FURNACE), m_IsCooking(a_BlockType == E_BLOCK_LIT_FURNACE),
@ -56,36 +55,40 @@ cFurnaceEntity::~cFurnaceEntity()
bool cFurnaceEntity::UsedBy(cPlayer * a_Player) void cFurnaceEntity::Destroy()
{ {
cWindow * Window = GetWindow(); m_IsDestroyed = true;
if (Window == nullptr) Super::Destroy();
{
OpenWindow(new cFurnaceWindow(m_PosX, m_PosY, m_PosZ, this));
Window = GetWindow();
}
if (Window != nullptr)
{
if (a_Player->GetWindow() != Window)
{
a_Player->OpenWindow(*Window);
}
}
UpdateProgressBars(true);
return true;
} }
bool cFurnaceEntity::ContinueCooking(void) void cFurnaceEntity::CopyFrom(const cBlockEntity & a_Src)
{ {
UpdateInput(); Super::CopyFrom(a_Src);
UpdateFuel(); auto & src = reinterpret_cast<const cFurnaceEntity &>(a_Src);
return m_IsCooking; m_Contents.CopyFrom(src.m_Contents);
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;
m_TimeBurned = src.m_TimeBurned;
m_TimeCooked = src.m_TimeCooked;
}
void cFurnaceEntity::SendTo(cClientHandle & a_Client)
{
// Nothing needs to be sent
UNUSED(a_Client);
} }
@ -134,10 +137,36 @@ bool cFurnaceEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
void cFurnaceEntity::SendTo(cClientHandle & a_Client) bool cFurnaceEntity::UsedBy(cPlayer * a_Player)
{ {
// Nothing needs to be sent cWindow * Window = GetWindow();
UNUSED(a_Client); if (Window == nullptr)
{
OpenWindow(new cFurnaceWindow(m_PosX, m_PosY, m_PosZ, this));
Window = GetWindow();
}
if (Window != nullptr)
{
if (a_Player->GetWindow() != Window)
{
a_Player->OpenWindow(*Window);
}
}
UpdateProgressBars(true);
return true;
}
bool cFurnaceEntity::ContinueCooking(void)
{
UpdateInput();
UpdateFuel();
return m_IsCooking;
} }
@ -208,7 +237,7 @@ void cFurnaceEntity::BurnNewFuel(void)
void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
{ {
super::OnSlotChanged(a_ItemGrid, a_SlotNum); Super::OnSlotChanged(a_ItemGrid, a_SlotNum);
if (m_IsDestroyed) if (m_IsDestroyed)
{ {

View File

@ -18,7 +18,7 @@ class cClientHandle;
class cFurnaceEntity : class cFurnaceEntity :
public cBlockEntityWithItems public cBlockEntityWithItems
{ {
typedef cBlockEntityWithItems super; typedef cBlockEntityWithItems Super;
public: public:
enum enum
@ -36,19 +36,16 @@ public:
BLOCKENTITY_PROTODEF(cFurnaceEntity) BLOCKENTITY_PROTODEF(cFurnaceEntity)
/** Constructor used for normal operation */ /** Constructor used for normal operation */
cFurnaceEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World); cFurnaceEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cFurnaceEntity() override; virtual ~cFurnaceEntity() override;
// cBlockEntity overrides: // cBlockEntity overrides:
virtual void Destroy() override;
virtual void CopyFrom(const cBlockEntity & a_Src) 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;
virtual void Destroy() override
{
m_IsDestroyed = true;
super::Destroy();
}
/** Restarts cooking /** Restarts cooking
Used after the furnace is loaded from storage to set up the internal variables so that cooking continues, if it was active Used after the furnace is loaded from storage to set up the internal variables so that cooking continues, if it was active
@ -106,10 +103,8 @@ public:
m_IsLoading = a_IsLoading; m_IsLoading = a_IsLoading;
} }
protected:
/** Block meta of the block currently represented by this entity */ protected:
NIBBLETYPE m_BlockMeta;
/** The recipe for the current input slot */ /** The recipe for the current input slot */
const cFurnaceRecipe::cRecipe * m_CurrentRecipe; const cFurnaceRecipe::cRecipe * m_CurrentRecipe;

View File

@ -17,11 +17,12 @@
cHopperEntity::cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cHopperEntity::cHopperEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(E_BLOCK_HOPPER, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_LastMoveItemsInTick(0), m_LastMoveItemsInTick(0),
m_LastMoveItemsOutTick(0) m_LastMoveItemsOutTick(0)
{ {
ASSERT(a_BlockType == E_BLOCK_HOPPER);
} }
@ -52,16 +53,28 @@ bool cHopperEntity::GetOutputBlockPos(NIBBLETYPE a_BlockMeta, int & a_OutputX, i
void cHopperEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cHopperEntity &>(a_Src);
m_LastMoveItemsInTick = src.m_LastMoveItemsInTick;
m_LastMoveItemsOutTick = src.m_LastMoveItemsOutTick;
}
bool cHopperEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) bool cHopperEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
UNUSED(a_Dt); UNUSED(a_Dt);
Int64 CurrentTick = a_Chunk.GetWorld()->GetWorldAge(); Int64 CurrentTick = a_Chunk.GetWorld()->GetWorldAge();
bool res = false; bool isDirty = false;
res = MoveItemsIn (a_Chunk, CurrentTick) || res; isDirty = MoveItemsIn (a_Chunk, CurrentTick) || isDirty;
res = MovePickupsIn(a_Chunk, CurrentTick) || res; isDirty = MovePickupsIn(a_Chunk, CurrentTick) || isDirty;
res = MoveItemsOut (a_Chunk, CurrentTick) || res; isDirty = MoveItemsOut (a_Chunk, CurrentTick) || isDirty;
return res; return isDirty;
} }

View File

@ -19,7 +19,7 @@
class cHopperEntity : class cHopperEntity :
public cBlockEntityWithItems public cBlockEntityWithItems
{ {
typedef cBlockEntityWithItems super; typedef cBlockEntityWithItems Super;
public: public:
enum enum
@ -34,7 +34,7 @@ public:
BLOCKENTITY_PROTODEF(cHopperEntity) BLOCKENTITY_PROTODEF(cHopperEntity)
/** Constructor used for normal operation */ /** Constructor used for normal operation */
cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cHopperEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
/** Returns the block coords of the block receiving the output items, based on the meta /** Returns the block coords of the block receiving the output items, based on the meta
Returns false if unattached. Returns false if unattached.
@ -47,6 +47,7 @@ protected:
Int64 m_LastMoveItemsOutTick; Int64 m_LastMoveItemsOutTick;
// cBlockEntity overrides: // cBlockEntity overrides:
virtual void CopyFrom(const cBlockEntity & a_Src) 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;

View File

@ -10,10 +10,11 @@
cJukeboxEntity::cJukeboxEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cJukeboxEntity::cJukeboxEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(E_BLOCK_JUKEBOX, a_BlockX, a_BlockY, a_BlockZ, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World),
m_Record(0) m_Record(0)
{ {
ASSERT(a_BlockType == E_BLOCK_JUKEBOX);
} }
@ -28,6 +29,17 @@ cJukeboxEntity::~cJukeboxEntity()
void cJukeboxEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cJukeboxEntity &>(a_Src);
m_Record = src.m_Record;
}
bool cJukeboxEntity::UsedBy(cPlayer * a_Player) bool cJukeboxEntity::UsedBy(cPlayer * a_Player)
{ {
if (IsPlayingRecord()) if (IsPlayingRecord())

View File

@ -12,14 +12,15 @@
class cJukeboxEntity : class cJukeboxEntity :
public cBlockEntity public cBlockEntity
{ {
typedef cBlockEntity super; typedef cBlockEntity Super;
public: public:
// tolua_end // tolua_end
BLOCKENTITY_PROTODEF(cJukeboxEntity) BLOCKENTITY_PROTODEF(cJukeboxEntity)
cJukeboxEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cJukeboxEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cJukeboxEntity() override; virtual ~cJukeboxEntity() override;
// tolua_begin // tolua_begin
@ -44,6 +45,8 @@ public:
// tolua_end // tolua_end
// cBlockEntity overrides:
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 &) override {} virtual void SendTo(cClientHandle &) override {}

View File

@ -13,17 +13,33 @@
cMobHeadEntity::cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cMobHeadEntity::cMobHeadEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(E_BLOCK_HEAD, a_BlockX, a_BlockY, a_BlockZ, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World),
m_Type(SKULL_TYPE_SKELETON), m_Type(SKULL_TYPE_SKELETON),
m_Rotation(SKULL_ROTATION_NORTH) m_Rotation(SKULL_ROTATION_NORTH)
{ {
ASSERT(a_BlockType == E_BLOCK_HEAD);
} }
void cMobHeadEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cMobHeadEntity &>(a_Src);
m_OwnerName = src.m_OwnerName;
m_OwnerTexture = src.m_OwnerTexture;
m_OwnerTextureSignature = src.m_OwnerTextureSignature;
m_OwnerUUID = src.m_OwnerUUID;
m_Rotation = src.m_Rotation;
m_Type = src.m_Type;
}
bool cMobHeadEntity::UsedBy(cPlayer * a_Player) bool cMobHeadEntity::UsedBy(cPlayer * a_Player)
{ {
UNUSED(a_Player); UNUSED(a_Player);

View File

@ -20,7 +20,7 @@
class cMobHeadEntity : class cMobHeadEntity :
public cBlockEntity public cBlockEntity
{ {
typedef cBlockEntity super; typedef cBlockEntity Super;
public: public:
@ -29,7 +29,7 @@ public:
BLOCKENTITY_PROTODEF(cMobHeadEntity) BLOCKENTITY_PROTODEF(cMobHeadEntity)
/** Creates a new mob head entity at the specified block coords. a_World may be nullptr */ /** Creates a new mob head entity at the specified block coords. a_World may be nullptr */
cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cMobHeadEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
// tolua_begin // tolua_begin
@ -65,6 +65,8 @@ public:
// tolua_end // tolua_end
// cBlockEntity overrides:
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;

View File

@ -13,12 +13,26 @@
cMobSpawnerEntity::cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) cMobSpawnerEntity::cMobSpawnerEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
: super(E_BLOCK_MOB_SPAWNER, a_BlockX, a_BlockY, a_BlockZ, a_World) Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World),
, m_Entity(mtPig) m_Entity(mtPig),
, m_SpawnDelay(100) m_SpawnDelay(100),
, m_IsActive(false) m_IsActive(false)
{ {
ASSERT(a_BlockType == E_BLOCK_MOB_SPAWNER);
}
void cMobSpawnerEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cMobSpawnerEntity &>(a_Src);
m_Entity = src.m_Entity;
m_IsActive = src.m_IsActive;
m_SpawnDelay = src.m_SpawnDelay;
} }

View File

@ -20,13 +20,15 @@
class cMobSpawnerEntity : class cMobSpawnerEntity :
public cBlockEntity public cBlockEntity
{ {
typedef cBlockEntity super; typedef cBlockEntity Super;
public: public:
// tolua_end // tolua_end
cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cMobSpawnerEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
// cBlockEntity overrides:
virtual void CopyFrom(const cBlockEntity & a_Src) 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;
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;

View File

@ -9,10 +9,22 @@
cNoteEntity::cNoteEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cNoteEntity::cNoteEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(E_BLOCK_NOTE_BLOCK, a_BlockX, a_BlockY, a_BlockZ, a_World), Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World),
m_Pitch(0) m_Pitch(0)
{ {
ASSERT(a_BlockType == E_BLOCK_NOTE_BLOCK);
}
void cNoteEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cNoteEntity &>(a_Src);
m_Pitch = src.m_Pitch;
} }

View File

@ -25,7 +25,7 @@ enum ENUM_NOTE_INSTRUMENTS
class cNoteEntity : class cNoteEntity :
public cBlockEntity public cBlockEntity
{ {
typedef cBlockEntity super; typedef cBlockEntity Super;
public: public:
// tolua_end // tolua_end
@ -33,7 +33,7 @@ public:
BLOCKENTITY_PROTODEF(cNoteEntity) BLOCKENTITY_PROTODEF(cNoteEntity)
/** Creates a new note entity. a_World may be nullptr */ /** Creates a new note entity. a_World may be nullptr */
cNoteEntity(int a_X, int a_Y, int a_Z, cWorld * a_World); cNoteEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cNoteEntity() override {} virtual ~cNoteEntity() override {}
// tolua_begin // tolua_begin
@ -45,6 +45,8 @@ public:
// tolua_end // tolua_end
// cBlockEntity overrides:
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 &) override {} virtual void SendTo(cClientHandle &) override {}

View File

@ -12,10 +12,25 @@
cSignEntity::cSignEntity(BLOCKTYPE a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World) : cSignEntity::cSignEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
super(a_BlockType, a_X, a_Y, a_Z, a_World) Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World)
{ {
ASSERT((a_Y >= 0) && (a_Y < cChunkDef::Height)); ASSERT((a_BlockType == E_BLOCK_WALLSIGN) || (a_BlockType == E_BLOCK_SIGN_POST));
ASSERT(cChunkDef::IsValidHeight(a_BlockY));
}
void cSignEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cSignEntity &>(a_Src);
for (size_t i = 0; i < ARRAYCOUNT(m_Line); ++i)
{
m_Line[i] = src.m_Line[i];
}
} }

View File

@ -19,7 +19,7 @@
class cSignEntity : class cSignEntity :
public cBlockEntity public cBlockEntity
{ {
typedef cBlockEntity super; typedef cBlockEntity Super;
public: public:
@ -28,7 +28,7 @@ public:
BLOCKENTITY_PROTODEF(cSignEntity) BLOCKENTITY_PROTODEF(cSignEntity)
/** Creates a new empty sign entity at the specified block coords and block type (wall or standing). a_World may be nullptr */ /** Creates a new empty sign entity at the specified block coords and block type (wall or standing). a_World may be nullptr */
cSignEntity(BLOCKTYPE a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World); cSignEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
// tolua_begin // tolua_begin
@ -43,6 +43,8 @@ public:
// tolua_end // tolua_end
// cBlockEntity overrides:
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;

View File

@ -73,6 +73,22 @@ void cItemGrid::GetSlotCoords(int a_SlotNum, int & a_X, int & a_Y) const
void cItemGrid::CopyFrom(const cItemGrid & a_Src)
{
ASSERT(m_Width == a_Src.m_Width);
ASSERT(m_Height == a_Src.m_Height);
for (int i = m_NumSlots - 1; i >= 0; --i)
{
m_Slots[i] = a_Src.m_Slots[i];
}
// The listeners are not copied
}
const cItem & cItemGrid::GetSlot(int a_X, int a_Y) const const cItem & cItemGrid::GetSlot(int a_X, int a_Y) const
{ {
return GetSlot(GetSlotNum(a_X, a_Y)); return GetSlot(GetSlotNum(a_X, a_Y));

View File

@ -48,6 +48,11 @@ public:
/** Converts slot number into XY coords; sets coords to -1 on invalid slot number. Exported in ManualBindings.cpp */ /** Converts slot number into XY coords; sets coords to -1 on invalid slot number. Exported in ManualBindings.cpp */
void GetSlotCoords(int a_SlotNum, int & a_X, int & a_Y) const; void GetSlotCoords(int a_SlotNum, int & a_X, int & a_Y) const;
/** Copies all items from a_Src to this grid.
Both grids must be the same size (asserts).
Doesn't copy the listeners. */
void CopyFrom(const cItemGrid & a_Src);
// tolua_begin // tolua_begin
// Retrieve slots by coords or slot number; Logs warning and returns the first slot on invalid coords / slotnum // Retrieve slots by coords or slot number; Logs warning and returns the first slot on invalid coords / slotnum

View File

@ -692,23 +692,23 @@ cBlockEntity * cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a
switch (a_BlockType) switch (a_BlockType)
{ {
// Specific entity loaders: // Specific entity loaders:
case E_BLOCK_BEACON: return LoadBeaconFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_BEACON: return LoadBeaconFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_BREWING_STAND: return LoadBrewingstandFromNBT(a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BREWING_STAND, a_BlockMeta); case E_BLOCK_BREWING_STAND: return LoadBrewingstandFromNBT(a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_CHEST); case E_BLOCK_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_COMMAND_BLOCK: return LoadCommandBlockFromNBT(a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_COMMAND_BLOCK: return LoadCommandBlockFromNBT(a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_DISPENSER: return LoadDispenserFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_DISPENSER: return LoadDispenserFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_DROPPER: return LoadDropperFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_DROPPER: return LoadDropperFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_FLOWER_POT: return LoadFlowerPotFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_FLOWER_POT: return LoadFlowerPotFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FURNACE, a_BlockMeta); case E_BLOCK_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_HEAD: return LoadMobHeadFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_HEAD: return LoadMobHeadFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_HOPPER: return LoadHopperFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_HOPPER: return LoadHopperFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_JUKEBOX: return LoadJukeboxFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_JUKEBOX: return LoadJukeboxFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_LIT_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LIT_FURNACE, a_BlockMeta); case E_BLOCK_LIT_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_MOB_SPAWNER: return LoadMobSpawnerFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_MOB_SPAWNER: return LoadMobSpawnerFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_NOTE_BLOCK: return LoadNoteBlockFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_NOTE_BLOCK: return LoadNoteBlockFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_SIGN_POST: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SIGN_POST); case E_BLOCK_SIGN_POST: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_TRAPPED_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_TRAPPED_CHEST); case E_BLOCK_TRAPPED_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
case E_BLOCK_WALLSIGN: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WALLSIGN); case E_BLOCK_WALLSIGN: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
// Blocktypes that have block entities but don't load their contents from disk: // Blocktypes that have block entities but don't load their contents from disk:
case E_BLOCK_ENDER_CHEST: return nullptr; case E_BLOCK_ENDER_CHEST: return nullptr;
@ -858,7 +858,7 @@ void cWSSAnvil::LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a
bool cWSSAnvil::CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, const char * a_ExpectedType) bool cWSSAnvil::CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, const char * a_ExpectedType, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the given tag is a compound: // Check if the given tag is a compound:
if (a_NBT.GetType(a_TagIdx) != TAG_Compound) if (a_NBT.GetType(a_TagIdx) != TAG_Compound)
@ -878,9 +878,10 @@ bool cWSSAnvil::CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, con
{ {
return true; return true;
} }
LOGWARNING("Block entity type mismatch: exp \"%s\", got \"%s\".", LOGWARNING("Block entity type mismatch: exp \"%s\", got \"%s\". The block entity at {%d, %d, %d} will lose all its properties.",
a_ExpectedType, a_ExpectedType,
AString(a_NBT.GetData(TagID), static_cast<size_t>(a_NBT.GetDataLength(TagID))).c_str() AString(a_NBT.GetData(TagID), static_cast<size_t>(a_NBT.GetDataLength(TagID))).c_str(),
a_BlockX, a_BlockY, a_BlockZ
); );
return false; return false;
} }
@ -889,15 +890,15 @@ bool cWSSAnvil::CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, con
cBlockEntity * cWSSAnvil::LoadBeaconFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) cBlockEntity * cWSSAnvil::LoadBeaconFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Beacon")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Beacon", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
std::unique_ptr<cBeaconEntity> Beacon = cpp14::make_unique<cBeaconEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World); auto Beacon = cpp14::make_unique<cBeaconEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Levels"); int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Levels");
if (CurrentLine >= 0) if (CurrentLine >= 0)
@ -931,10 +932,10 @@ cBlockEntity * cWSSAnvil::LoadBeaconFromNBT(const cParsedNBT & a_NBT, int a_TagI
cBlockEntity * cWSSAnvil::LoadBrewingstandFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) cBlockEntity * cWSSAnvil::LoadBrewingstandFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Brewingstand")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Brewingstand", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
@ -945,7 +946,7 @@ cBlockEntity * cWSSAnvil::LoadBrewingstandFromNBT(const cParsedNBT & a_NBT, int
return nullptr; // Make it an empty brewingstand - the chunk loader will provide an empty cBrewingstandEntity for this return nullptr; // Make it an empty brewingstand - the chunk loader will provide an empty cBrewingstandEntity for this
} }
std::unique_ptr<cBrewingstandEntity> Brewingstand(new cBrewingstandEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, m_World)); auto Brewingstand = cpp14::make_unique<cBrewingstandEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
// Fuel has to be loaded at first, because of slot events: // Fuel has to be loaded at first, because of slot events:
int Fuel = a_NBT.FindChildByName(a_TagIdx, "Fuel"); int Fuel = a_NBT.FindChildByName(a_TagIdx, "Fuel");
@ -988,7 +989,7 @@ cBlockEntity * cWSSAnvil::LoadBrewingstandFromNBT(const cParsedNBT & a_NBT, int
cBlockEntity * cWSSAnvil::LoadChestFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_ChestBlockType) cBlockEntity * cWSSAnvil::LoadChestFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
// Note that older Cuberite code used "TrappedChest" for trapped chests; new code mimics vanilla and uses "Chest" throughout, but we allow migration here: // Note that older Cuberite code used "TrappedChest" for trapped chests; new code mimics vanilla and uses "Chest" throughout, but we allow migration here:
@ -1015,7 +1016,7 @@ cBlockEntity * cWSSAnvil::LoadChestFromNBT(const cParsedNBT & a_NBT, int a_TagId
{ {
return nullptr; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this return nullptr; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
} }
std::unique_ptr<cChestEntity> Chest = cpp14::make_unique<cChestEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World, a_ChestBlockType); auto Chest = cpp14::make_unique<cChestEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items); LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items);
return Chest.release(); return Chest.release();
} }
@ -1024,15 +1025,15 @@ cBlockEntity * cWSSAnvil::LoadChestFromNBT(const cParsedNBT & a_NBT, int a_TagId
cBlockEntity * cWSSAnvil::LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) cBlockEntity * cWSSAnvil::LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Control")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Control", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
std::unique_ptr<cCommandBlockEntity> CmdBlock = cpp14::make_unique<cCommandBlockEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World); auto CmdBlock = cpp14::make_unique<cCommandBlockEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command"); int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command");
if (currentLine >= 0) if (currentLine >= 0)
@ -1061,10 +1062,10 @@ cBlockEntity * cWSSAnvil::LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int
cBlockEntity * cWSSAnvil::LoadDispenserFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) cBlockEntity * cWSSAnvil::LoadDispenserFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Trap")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Trap", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
@ -1074,7 +1075,7 @@ cBlockEntity * cWSSAnvil::LoadDispenserFromNBT(const cParsedNBT & a_NBT, int a_T
{ {
return nullptr; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this return nullptr; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this
} }
std::unique_ptr<cDispenserEntity> Dispenser = cpp14::make_unique<cDispenserEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World); auto Dispenser = cpp14::make_unique<cDispenserEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
LoadItemGridFromNBT(Dispenser->GetContents(), a_NBT, Items); LoadItemGridFromNBT(Dispenser->GetContents(), a_NBT, Items);
return Dispenser.release(); return Dispenser.release();
} }
@ -1083,10 +1084,10 @@ cBlockEntity * cWSSAnvil::LoadDispenserFromNBT(const cParsedNBT & a_NBT, int a_T
cBlockEntity * cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) cBlockEntity * cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Dropper")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Dropper", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
@ -1096,7 +1097,7 @@ cBlockEntity * cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_Tag
{ {
return nullptr; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this return nullptr; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this
} }
std::unique_ptr<cDropperEntity> Dropper = cpp14::make_unique<cDropperEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World); auto Dropper = cpp14::make_unique<cDropperEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items); LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items);
return Dropper.release(); return Dropper.release();
} }
@ -1105,15 +1106,15 @@ cBlockEntity * cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_Tag
cBlockEntity * cWSSAnvil::LoadFlowerPotFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) cBlockEntity * cWSSAnvil::LoadFlowerPotFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "FlowerPot")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "FlowerPot", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
std::unique_ptr<cFlowerPotEntity> FlowerPot = cpp14::make_unique<cFlowerPotEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World); auto FlowerPot = cpp14::make_unique<cFlowerPotEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
cItem Item; cItem Item;
int currentLine = a_NBT.FindChildByName(a_TagIdx, "Item"); int currentLine = a_NBT.FindChildByName(a_TagIdx, "Item");
@ -1143,10 +1144,10 @@ cBlockEntity * cWSSAnvil::LoadFlowerPotFromNBT(const cParsedNBT & a_NBT, int a_T
cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Furnace")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Furnace", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
@ -1157,7 +1158,7 @@ cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_Tag
return nullptr; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this return nullptr; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this
} }
std::unique_ptr<cFurnaceEntity> Furnace = cpp14::make_unique<cFurnaceEntity>(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, m_World); auto Furnace = cpp14::make_unique<cFurnaceEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
Furnace->SetLoading(true); Furnace->SetLoading(true);
// Load slots: // Load slots:
@ -1202,15 +1203,15 @@ cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_Tag
cBlockEntity * cWSSAnvil::LoadMobSpawnerFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) cBlockEntity * cWSSAnvil::LoadMobSpawnerFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "MobSpawner")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "MobSpawner", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
std::unique_ptr<cMobSpawnerEntity> MobSpawner = cpp14::make_unique<cMobSpawnerEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World); auto MobSpawner = cpp14::make_unique<cMobSpawnerEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
// Load entity (Cuberite worlds): // Load entity (Cuberite worlds):
int Type = a_NBT.FindChildByName(a_TagIdx, "Entity"); int Type = a_NBT.FindChildByName(a_TagIdx, "Entity");
@ -1250,10 +1251,10 @@ cBlockEntity * cWSSAnvil::LoadMobSpawnerFromNBT(const cParsedNBT & a_NBT, int a_
cBlockEntity * cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) cBlockEntity * cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Hopper")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Hopper", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
@ -1263,7 +1264,7 @@ cBlockEntity * cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagI
{ {
return nullptr; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this return nullptr; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this
} }
std::unique_ptr<cHopperEntity> Hopper = cpp14::make_unique<cHopperEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World); auto Hopper = cpp14::make_unique<cHopperEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
LoadItemGridFromNBT(Hopper->GetContents(), a_NBT, Items); LoadItemGridFromNBT(Hopper->GetContents(), a_NBT, Items);
return Hopper.release(); return Hopper.release();
} }
@ -1272,15 +1273,15 @@ cBlockEntity * cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagI
cBlockEntity * cWSSAnvil::LoadJukeboxFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) cBlockEntity * cWSSAnvil::LoadJukeboxFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "RecordPlayer")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "RecordPlayer", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
std::unique_ptr<cJukeboxEntity> Jukebox = cpp14::make_unique<cJukeboxEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World); auto Jukebox = cpp14::make_unique<cJukeboxEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
int Record = a_NBT.FindChildByName(a_TagIdx, "Record"); int Record = a_NBT.FindChildByName(a_TagIdx, "Record");
if (Record >= 0) if (Record >= 0)
{ {
@ -1293,15 +1294,15 @@ cBlockEntity * cWSSAnvil::LoadJukeboxFromNBT(const cParsedNBT & a_NBT, int a_Tag
cBlockEntity * cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) cBlockEntity * cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Skull")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Skull", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
std::unique_ptr<cMobHeadEntity> MobHead = cpp14::make_unique<cMobHeadEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World); auto MobHead = cpp14::make_unique<cMobHeadEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
int currentLine = a_NBT.FindChildByName(a_TagIdx, "SkullType"); int currentLine = a_NBT.FindChildByName(a_TagIdx, "SkullType");
if (currentLine >= 0) if (currentLine >= 0)
@ -1365,15 +1366,15 @@ cBlockEntity * cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_Tag
cBlockEntity * cWSSAnvil::LoadNoteBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) cBlockEntity * cWSSAnvil::LoadNoteBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Music")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Music", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
std::unique_ptr<cNoteEntity> NoteBlock = cpp14::make_unique<cNoteEntity>(a_BlockX, a_BlockY, a_BlockZ, m_World); auto NoteBlock = cpp14::make_unique<cNoteEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
int note = a_NBT.FindChildByName(a_TagIdx, "note"); int note = a_NBT.FindChildByName(a_TagIdx, "note");
if (note >= 0) if (note >= 0)
{ {
@ -1386,15 +1387,15 @@ cBlockEntity * cWSSAnvil::LoadNoteBlockFromNBT(const cParsedNBT & a_NBT, int a_T
cBlockEntity * cWSSAnvil::LoadSignFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType) cBlockEntity * cWSSAnvil::LoadSignFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
// Check if the data has a proper type: // Check if the data has a proper type:
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Sign")) if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Sign", a_BlockX, a_BlockY, a_BlockZ))
{ {
return nullptr; return nullptr;
} }
std::unique_ptr<cSignEntity> Sign = cpp14::make_unique<cSignEntity>(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, m_World); auto Sign = cpp14::make_unique<cSignEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World);
int currentLine = a_NBT.FindChildByName(a_TagIdx, "Text1"); int currentLine = a_NBT.FindChildByName(a_TagIdx, "Text1");
if (currentLine >= 0) if (currentLine >= 0)

View File

@ -145,23 +145,25 @@ protected:
Slots outside the ItemGrid range are ignored */ Slots outside the ItemGrid range are ignored */
void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0); void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0);
/** Returns true iff the "id" child tag inside the specified tag equals the specified expected type. */ /** Returns true iff the "id" child tag inside the specified tag equals the specified expected type.
bool CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, const char * a_ExpectedType); Logs a warning to the console on mismatch.
The coordinates are used only for the log message. */
bool CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, const char * a_ExpectedType, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadBeaconFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadBeaconFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadBrewingstandFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); cBlockEntity * LoadBrewingstandFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadChestFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_ChestBlockType); cBlockEntity * LoadChestFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadDispenserFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadDispenserFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadDropperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadDropperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadFlowerPotFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadFlowerPotFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadFurnaceFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); cBlockEntity * LoadFurnaceFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadMobSpawnerFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadMobSpawnerFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadHopperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadHopperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadJukeboxFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadJukeboxFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadMobHeadFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadMobHeadFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadNoteBlockFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadNoteBlockFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * LoadSignFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SignBlockType); cBlockEntity * LoadSignFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength); void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength);