summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/AllToLua.pkg1
-rw-r--r--src/Bindings/CMakeLists.txt1
-rw-r--r--src/Bindings/ManualBindings_World.cpp1
-rw-r--r--src/BlockEntities/BedEntity.cpp56
-rw-r--r--src/BlockEntities/BedEntity.h45
-rw-r--r--src/BlockEntities/BlockEntity.cpp3
-rw-r--r--src/BlockEntities/CMakeLists.txt2
-rw-r--r--src/Blocks/BlockBed.cpp62
-rw-r--r--src/Blocks/BlockBed.h21
-rw-r--r--src/Blocks/BlockEntity.h2
-rw-r--r--src/Blocks/BlockHandler.cpp11
-rw-r--r--src/Blocks/BlockHandler.h4
-rw-r--r--src/Chunk.cpp12
-rw-r--r--src/Chunk.h5
-rw-r--r--src/ChunkMap.cpp18
-rw-r--r--src/ChunkMap.h6
-rw-r--r--src/Protocol/Protocol_1_11.cpp12
-rw-r--r--src/Protocol/Protocol_1_12.cpp27
-rw-r--r--src/Protocol/Protocol_1_12.h1
-rw-r--r--src/World.cpp9
-rw-r--r--src/World.h3
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp14
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h2
-rwxr-xr-xsrc/WorldStorage/WSSAnvil.cpp28
-rwxr-xr-xsrc/WorldStorage/WSSAnvil.h1
25 files changed, 335 insertions, 12 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index b59af7374..31c914bcd 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -100,6 +100,7 @@ $cfile "../Mobs/Monster.h"
// Block entities:
$cfile "../BlockEntities/BlockEntity.h"
$cfile "../BlockEntities/BeaconEntity.h"
+$cfile "../BlockEntities/BedEntity.h"
$cfile "../BlockEntities/BlockEntityWithItems.h"
$cfile "../BlockEntities/BrewingstandEntity.h"
$cfile "../BlockEntities/ChestEntity.h"
diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt
index 64db464f2..e50db12c3 100644
--- a/src/Bindings/CMakeLists.txt
+++ b/src/Bindings/CMakeLists.txt
@@ -66,6 +66,7 @@ set(BINDING_DEPENDENCIES
../BiomeDef.h
../BlockArea.h
../BlockEntities/BeaconEntity.h
+ ../BlockEntities/BedEntity.h
../BlockEntities/BlockEntity.h
../BlockEntities/BlockEntityWithItems.h
../BlockEntities/BrewingstandEntity.h
diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp
index f24e5ac34..7bf4d3f80 100644
--- a/src/Bindings/ManualBindings_World.cpp
+++ b/src/Bindings/ManualBindings_World.cpp
@@ -639,6 +639,7 @@ void cManualBindings::BindWorld(lua_State * tolua_S)
tolua_function(tolua_S, "ChunkStay", tolua_cWorld_ChunkStay);
tolua_function(tolua_S, "DoExplosionAt", tolua_cWorld_DoExplosionAt);
tolua_function(tolua_S, "DoWithBeaconAt", DoWithXYZ<cWorld, cBeaconEntity, &cWorld::DoWithBeaconAt>);
+ tolua_function(tolua_S, "DoWithBedAt", DoWithXYZ<cWorld, cBedEntity, &cWorld::DoWithBedAt>);
tolua_function(tolua_S, "DoWithBlockEntityAt", DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>);
tolua_function(tolua_S, "DoWithBrewingstandAt", DoWithXYZ<cWorld, cBrewingstandEntity, &cWorld::DoWithBrewingstandAt>);
tolua_function(tolua_S, "DoWithChestAt", DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>);
diff --git a/src/BlockEntities/BedEntity.cpp b/src/BlockEntities/BedEntity.cpp
new file mode 100644
index 000000000..b8f61c049
--- /dev/null
+++ b/src/BlockEntities/BedEntity.cpp
@@ -0,0 +1,56 @@
+
+// BedEntity.cpp
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "BedEntity.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+#include "../ClientHandle.h"
+#include "../Blocks/BlockBed.h"
+
+cBedEntity::cBedEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, short a_Color):
+ Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World),
+ m_Color(a_Color)
+{
+ ASSERT(a_BlockType == E_BLOCK_BED);
+}
+
+
+
+
+
+void cBedEntity::CopyFrom(const cBlockEntity & a_Src)
+{
+ Super::CopyFrom(a_Src);
+ auto & src = reinterpret_cast<const cBedEntity &>(a_Src);
+ m_Color = src.m_Color;
+}
+
+
+
+
+
+void cBedEntity::SendTo(cClientHandle & a_Client)
+{
+ a_Client.SendUpdateBlockEntity(*this);
+}
+
+
+
+
+
+void cBedEntity::SetColor(short a_Color)
+{
+ m_Color = a_Color;
+ int posX = m_PosX;
+ int posY = m_PosY;
+ int posZ = m_PosZ;
+
+ // If the bed entity is send immediately, the client (maybe) still has not the bed.
+ // Fix that by delaying the broadcast of the bed entity by a tick:
+ m_World->ScheduleTask(1, [posX, posY, posZ](cWorld & a_World)
+ {
+ a_World.BroadcastBlockEntity(posX, posY, posZ);
+ });
+}
diff --git a/src/BlockEntities/BedEntity.h b/src/BlockEntities/BedEntity.h
new file mode 100644
index 000000000..8caa205c4
--- /dev/null
+++ b/src/BlockEntities/BedEntity.h
@@ -0,0 +1,45 @@
+
+// BedEntity.h
+
+#pragma once
+
+#include "BlockEntity.h"
+
+
+
+
+
+// tolua_begin
+
+class cBedEntity :
+ public cBlockEntity
+{
+ typedef cBlockEntity Super;
+public:
+ // tolua_end
+
+ BLOCKENTITY_PROTODEF(cBedEntity)
+
+ cBedEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, short a_Color = E_META_WOOL_RED);
+
+ // tolua_begin
+
+ /** Returns the color of the bed */
+ short GetColor(void) const { return m_Color; }
+
+ /** Set the color of the bed. */
+ void SetColor(short a_Color);
+
+ /** Returns true if this is the pillow block, it has then the meta 8. */
+ bool IsPillowBlock(void) { return ((m_BlockMeta & 0x08) == 0x08); }
+
+ // tolua_end
+
+ // cBlockEntity overrides:
+ virtual void CopyFrom(const cBlockEntity & a_Src) override;
+ virtual bool UsedBy(cPlayer * a_Player) override { return false; }
+ virtual void SendTo(cClientHandle & a_Client) override;
+
+private:
+ short m_Color;
+}; // tolua_export
diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp
index f60eb5622..f2380734a 100644
--- a/src/BlockEntities/BlockEntity.cpp
+++ b/src/BlockEntities/BlockEntity.cpp
@@ -5,6 +5,7 @@
#include "Globals.h"
#include "BeaconEntity.h"
+#include "BedEntity.h"
#include "BlockEntity.h"
#include "BrewingstandEntity.h"
#include "ChestEntity.h"
@@ -42,6 +43,7 @@ bool cBlockEntity::IsBlockEntityBlockType(BLOCKTYPE a_BlockType)
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:
@@ -75,6 +77,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
switch (a_BlockType)
{
case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
+ case E_BLOCK_BED: return new cBedEntity (a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, 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_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_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, a_World);
diff --git a/src/BlockEntities/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt
index d6bf6355c..93033931c 100644
--- a/src/BlockEntities/CMakeLists.txt
+++ b/src/BlockEntities/CMakeLists.txt
@@ -4,6 +4,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
SET (SRCS
BeaconEntity.cpp
+ BedEntity.cpp
BlockEntity.cpp
BlockEntityWithItems.cpp
BrewingstandEntity.cpp
@@ -25,6 +26,7 @@ SET (SRCS
SET (HDRS
BeaconEntity.h
+ BedEntity.h
BlockEntity.h
BlockEntityWithItems.h
BrewingstandEntity.h
diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp
index adc01c158..d6112f853 100644
--- a/src/Blocks/BlockBed.cpp
+++ b/src/Blocks/BlockBed.cpp
@@ -1,3 +1,6 @@
+
+// BlockBed.cpp
+
#include "Globals.h"
#include "BlockBed.h"
@@ -7,6 +10,7 @@
#include "../BoundingBox.h"
#include "../Mobs/Monster.h"
#include "../Entities/Entity.h"
+#include "../BlockEntities/BedEntity.h"
@@ -16,14 +20,19 @@ void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInt
{
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
- Vector3i ThisPos( a_BlockX, a_BlockY, a_BlockZ);
- Vector3i Direction = MetaDataToDirection( OldMeta & 0x3);
+ Vector3i ThisPos(a_BlockX, a_BlockY, a_BlockZ);
+ Vector3i Direction = MetaDataToDirection(OldMeta & 0x3);
if (OldMeta & 0x8)
{
// Was pillow
if (a_ChunkInterface.GetBlock(ThisPos - Direction) == E_BLOCK_BED)
{
+ // First replace the bed with air
a_ChunkInterface.FastSetBlock(ThisPos - Direction, E_BLOCK_AIR, 0);
+
+ // Then destroy the bed entity
+ Vector3i PillowPos(ThisPos - Direction);
+ a_ChunkInterface.SetBlock(PillowPos.x, PillowPos.y, PillowPos.z, E_BLOCK_AIR, 0);
}
}
else
@@ -31,7 +40,12 @@ void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInt
// Was foot end
if (a_ChunkInterface.GetBlock(ThisPos + Direction) == E_BLOCK_BED)
{
+ // First replace the bed with air
a_ChunkInterface.FastSetBlock(ThisPos + Direction, E_BLOCK_AIR, 0);
+
+ // Then destroy the bed entity
+ Vector3i FootPos(ThisPos + Direction);
+ a_ChunkInterface.SetBlock(FootPos.x, FootPos.y, FootPos.z, E_BLOCK_AIR, 0);
}
}
}
@@ -169,4 +183,48 @@ bool cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
+void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, const sSetBlock & a_BlockChange)
+{
+ class cBedColor :
+ public cBedCallback
+ {
+ public:
+ short m_Color;
+ cBedColor(short a_Color) :
+ m_Color(a_Color)
+ {
+ }
+
+ virtual bool Item(cBedEntity * a_Bed) override
+ {
+ a_Bed->SetColor(m_Color);
+ return true;
+ }
+ };
+ cBedColor BedCallback(a_Player->GetEquippedItem().m_ItemDamage);
+ a_Player->GetWorld()->DoWithBedAt(a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(), BedCallback);
+}
+
+
+
+
+
+void cBlockBedHandler::ConvertToPickups(cEntity * a_Digger, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ class cBedColor :
+ public cBedCallback
+ {
+ public:
+ short m_Color = E_META_WOOL_RED;
+
+ virtual bool Item(cBedEntity * a_Bed) override
+ {
+ m_Color = a_Bed->GetColor();
+ return true;
+ }
+ };
+ cBedColor BedCallback;
+ a_Digger->GetWorld()->DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, BedCallback);
+ a_Pickups.Add(cItem(E_ITEM_BED, 1, BedCallback.m_Color));
+}
diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h
index cfb02ceeb..a9a3d0e20 100644
--- a/src/Blocks/BlockBed.h
+++ b/src/Blocks/BlockBed.h
@@ -1,10 +1,14 @@
+// BlockBed.h
+
#pragma once
+#include "BlockEntity.h"
#include "BlockHandler.h"
#include "MetaRotator.h"
-#include "Item.h"
#include "ChunkInterface.h"
+#include "../World.h"
+#include "../Entities/Entity.h"
class cPlayer;
@@ -14,15 +18,16 @@ class cWorldInterface;
class cBlockBedHandler :
- public cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>
+ public cMetaRotator<cBlockEntityHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>
{
public:
cBlockBedHandler(BLOCKTYPE a_BlockType)
- : cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
+ : cMetaRotator<cBlockEntityHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
{
}
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
+
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
virtual bool IsUseable(void) override
@@ -30,11 +35,9 @@ public:
return true;
}
- virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
- {
- // Reset meta to zero
- a_Pickups.push_back(cItem(E_ITEM_BED, 1, 0));
- }
+ virtual void ConvertToPickups(cItems & Pickups, NIBBLETYPE Meta) override {}
+
+ virtual void ConvertToPickups(cEntity * a_Digger, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ) override;
// Bed specific helper functions
static NIBBLETYPE RotationToMetaData(double a_Rotation)
@@ -77,6 +80,8 @@ public:
a_ChunkInterface.SetBlockMeta(a_BedPosition.x, a_BedPosition.y, a_BedPosition.z, Meta);
}
+ virtual void OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, const sSetBlock & a_BlockChange) override;
+
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);
diff --git a/src/Blocks/BlockEntity.h b/src/Blocks/BlockEntity.h
index 06cd860c5..5b1267ec9 100644
--- a/src/Blocks/BlockEntity.h
+++ b/src/Blocks/BlockEntity.h
@@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
-
+#include "ChunkInterface.h"
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 36b20088c..41e3561d1 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -463,7 +463,6 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac
{
case E_BLOCK_ACACIA_DOOR:
case E_BLOCK_ACTIVE_COMPARATOR:
- case E_BLOCK_BED:
case E_BLOCK_BEETROOTS:
case E_BLOCK_BIRCH_DOOR:
case E_BLOCK_BREWING_STAND:
@@ -512,9 +511,19 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac
ConvertToPickups(Pickups, Meta);
break;
}
+ case E_BLOCK_BED:
+ {
+ // Need to access the bed entity to get the color for the item damage
+ ConvertToPickups(a_Digger, Pickups, Meta, a_BlockX, a_BlockY, a_BlockZ);
+ }
default: Pickups.Add(m_BlockType, 1, Meta); break;
}
}
+ else if (m_BlockType == E_BLOCK_BED)
+ {
+ // Need to access the bed entity to get the color for the item damage
+ ConvertToPickups(a_Digger, Pickups, Meta, a_BlockX, a_BlockY, a_BlockZ);
+ }
else
{
ConvertToPickups(Pickups, Meta);
diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h
index 24552fb46..625def7d8 100644
--- a/src/Blocks/BlockHandler.h
+++ b/src/Blocks/BlockHandler.h
@@ -80,6 +80,10 @@ public:
/** Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents */
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta);
+ /** Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents.
+ Overloaded method with coords and digger, for blocks that needs to access the block entity, e.g. a bed */
+ virtual void ConvertToPickups(cEntity * a_Digger, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ) {}
+
/** Handles the dropping, but not destruction, of a block based on what ConvertTo(Verbatim)Pickups() returns, including the spawning of pickups and alertion of plugins
@param a_Digger The entity causing the drop; it may be nullptr
@param a_CanDrop Informs the handler whether the block should be dropped at all. One example when this is false is when stone is destroyed by hand
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 99f643437..8a13fd20e 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -13,6 +13,7 @@
#include "zlib/zlib.h"
#include "Defines.h"
#include "BlockEntities/BeaconEntity.h"
+#include "BlockEntities/BedEntity.h"
#include "BlockEntities/BrewingstandEntity.h"
#include "BlockEntities/ChestEntity.h"
#include "BlockEntities/CommandBlockEntity.h"
@@ -1404,6 +1405,7 @@ void cChunk::CreateBlockEntities(void)
switch (BlockType)
{
case E_BLOCK_BEACON:
+ case E_BLOCK_BED:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
@@ -1537,6 +1539,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
switch (a_BlockType)
{
case E_BLOCK_BEACON:
+ case E_BLOCK_BED:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
@@ -2265,6 +2268,15 @@ bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCal
+bool cChunk::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback)
+{
+ return GenericDoWithBlockEntityAt<cBedEntity,
+ E_BLOCK_BED
+ >(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+}
+
+
+
bool cChunk::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback)
{
diff --git a/src/Chunk.h b/src/Chunk.h
index 3a0d37768..b5dcd7b91 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -30,6 +30,7 @@ class cServer;
class cPlayer;
class cChunkMap;
class cBeaconEntity;
+class cBedEntity;
class cBrewingstandEntity;
class cBoundingBox;
class cChestEntity;
@@ -53,6 +54,7 @@ class cSetChunkData;
typedef std::list<cClientHandle *> cClientHandleList;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cBeaconEntity> cBeaconCallback;
+typedef cItemCallback<cBedEntity> cBedCallback;
typedef cItemCallback<cBrewingstandEntity> cBrewingstandCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
@@ -317,6 +319,9 @@ public:
/** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */
bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback); // Lua-acessible
+ /** Calls the callback for the bed at the specified coords; returns false if there's no bed at those coords, true if found */
+ bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback); // Lua-acessible
+
/** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */
bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 019746b9d..f04af4340 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -2042,6 +2042,24 @@ bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeacon
+bool cChunkMap::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback)
+{
+ int ChunkX, ChunkZ;
+ int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
+ cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
+ cCSLock Lock(m_CSChunks);
+ cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ);
+ if ((Chunk == nullptr) || !Chunk->IsValid())
+ {
+ return false;
+ }
+ return Chunk->DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+}
+
+
+
+
+
bool cChunkMap::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback)
{
int ChunkX, ChunkZ;
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index e7694e907..7c57f9669 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -19,6 +19,7 @@ class cChunkStay;
class cChunk;
class cPlayer;
class cBeaconEntity;
+class cBedEntity;
class cBrewingstandEntity;
class cChestEntity;
class cDispenserEntity;
@@ -44,6 +45,7 @@ typedef cChunk * cChunkPtr;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cBlockEntity> cBlockEntityCallback;
typedef cItemCallback<cBeaconEntity> cBeaconCallback;
+typedef cItemCallback<cBedEntity> cBedCallback;
typedef cItemCallback<cBrewingstandEntity> cBrewingstandCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
@@ -277,6 +279,10 @@ public:
Returns false if there's no beacon at those coords, true if found. */
bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible
+ /** Calls the callback for the bed at the specified coords.
+ Returns false if there's no bed at those coords, true if found. */
+ bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback); // Lua-acessible
+
/** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */
bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback); // Lua-acessible
diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp
index 8f9a0b0b9..e4aaa8f6f 100644
--- a/src/Protocol/Protocol_1_11.cpp
+++ b/src/Protocol/Protocol_1_11.cpp
@@ -30,6 +30,7 @@ Implements the 1.11 protocol classes:
#include "../Mobs/IncludeAllMonsters.h"
#include "../BlockEntities/BeaconEntity.h"
+#include "../BlockEntities/BedEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/MobSpawnerEntity.h"
@@ -421,6 +422,17 @@ void cProtocol_1_11_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity
break;
}
+ case E_BLOCK_BED:
+ {
+ auto & BedEntity = reinterpret_cast<const cBedEntity &>(a_BlockEntity);
+ Writer.AddInt("x", BedEntity.GetPosX());
+ Writer.AddInt("y", BedEntity.GetPosY());
+ Writer.AddInt("z", BedEntity.GetPosZ());
+ Writer.AddInt("color", BedEntity.GetColor());
+ Writer.AddString("id", "Bed"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
+ break;
+ }
+
case E_BLOCK_COMMAND_BLOCK:
{
auto & CommandBlockEntity = reinterpret_cast<const cCommandBlockEntity &>(a_BlockEntity);
diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp
index a0f2b9aa7..904b31ca0 100644
--- a/src/Protocol/Protocol_1_12.cpp
+++ b/src/Protocol/Protocol_1_12.cpp
@@ -1269,6 +1269,33 @@ void cProtocol_1_12::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
+void cProtocol_1_12::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x09); // Update tile entity packet
+ Pkt.WritePosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ());
+
+ Byte Action = 0;
+ switch (a_BlockEntity.GetBlockType())
+ {
+ case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing
+ case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text
+ case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity
+ case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity
+ case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot
+ case E_BLOCK_BED: Action = 11; break; // Update bed color
+ default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break;
+ }
+ Pkt.WriteBEUInt8(Action);
+
+ WriteBlockEntity(Pkt, a_BlockEntity);
+}
+
+
+
+
+
void cProtocol_1_12::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
{
ASSERT(m_State == 3); // In game mode?
diff --git a/src/Protocol/Protocol_1_12.h b/src/Protocol/Protocol_1_12.h
index f61b713ae..814932e79 100644
--- a/src/Protocol/Protocol_1_12.h
+++ b/src/Protocol/Protocol_1_12.h
@@ -59,6 +59,7 @@ public:
virtual void SendTeleportEntity(const cEntity & a_Entity) override;
virtual void SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
virtual void SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override;
+ virtual void SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) override;
protected:
virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) override;
virtual void HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer) override;
diff --git a/src/World.cpp b/src/World.cpp
index da41b22db..fa2116597 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1439,6 +1439,15 @@ bool cWorld::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCal
+bool cWorld::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback)
+{
+ return m_ChunkMap->DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+}
+
+
+
+
+
bool cWorld::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback)
{
return m_ChunkMap->DoWithBrewingstandAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
diff --git a/src/World.h b/src/World.h
index 3af766166..bae7adbb9 100644
--- a/src/World.h
+++ b/src/World.h
@@ -536,6 +536,9 @@ public:
/** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */
bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Exported in ManualBindings.cpp
+ /** Calls the callback for the bed at the specified coords; returns false if there's no bed at those coords, true if found */
+ bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback); // Exported in ManualBindings.cpp
+
/** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */
bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback); // Lua-acessible
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index d98fc7bb5..d61e61879 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -11,6 +11,7 @@
#include "FastNBT.h"
#include "../BlockEntities/BeaconEntity.h"
+#include "../BlockEntities/BedEntity.h"
#include "../BlockEntities/BrewingstandEntity.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
@@ -197,6 +198,18 @@ void cNBTChunkSerializer::AddBeaconEntity(cBeaconEntity * a_Entity)
+void cNBTChunkSerializer::AddBedEntity(cBedEntity * a_Entity)
+{
+ m_Writer.BeginCompound("");
+ AddBasicTileEntity(a_Entity, "Bed");
+ m_Writer.AddInt("color", a_Entity->GetColor());
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddBrewingstandEntity(cBrewingstandEntity * a_Brewingstand)
{
m_Writer.BeginCompound("");
@@ -970,6 +983,7 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
switch (a_Entity->GetBlockType())
{
case E_BLOCK_BEACON: AddBeaconEntity (reinterpret_cast<cBeaconEntity *> (a_Entity)); break;
+ case E_BLOCK_BED: AddBedEntity (reinterpret_cast<cBedEntity *> (a_Entity)); break;
case E_BLOCK_BREWING_STAND: AddBrewingstandEntity(reinterpret_cast<cBrewingstandEntity *>(a_Entity)); break;
case E_BLOCK_CHEST: AddChestEntity (reinterpret_cast<cChestEntity *> (a_Entity), a_Entity->GetBlockType()); break;
case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity(reinterpret_cast<cCommandBlockEntity *>(a_Entity)); break;
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 08433c3ec..087d17277 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -21,6 +21,7 @@ class cEntity;
class cBlockEntity;
class cBoat;
class cBeaconEntity;
+class cBedEntity;
class cBrewingstandEntity;
class cChestEntity;
class cCommandBlockEntity;
@@ -98,6 +99,7 @@ protected:
// Block entities:
void AddBasicTileEntity (cBlockEntity * a_Entity, const char * a_EntityTypeID);
void AddBeaconEntity (cBeaconEntity * a_Entity);
+ void AddBedEntity (cBedEntity * a_Entity);
void AddBrewingstandEntity(cBrewingstandEntity * a_Brewingstand);
void AddChestEntity (cChestEntity * a_Entity, BLOCKTYPE a_ChestType);
void AddDispenserEntity (cDispenserEntity * a_Entity);
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index d5ae388bb..8b8a0482e 100755
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -19,6 +19,7 @@
#include "../Root.h"
#include "../BlockEntities/BeaconEntity.h"
+#include "../BlockEntities/BedEntity.h"
#include "../BlockEntities/BrewingstandEntity.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
@@ -694,6 +695,7 @@ cBlockEntity * cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a
{
// Specific entity loaders:
case E_BLOCK_BEACON: return LoadBeaconFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
+ case E_BLOCK_BED: return LoadBedFromNBT (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_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
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_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ);
@@ -976,6 +978,32 @@ cBlockEntity * cWSSAnvil::LoadBeaconFromNBT(const cParsedNBT & a_NBT, int a_TagI
+cBlockEntity * cWSSAnvil::LoadBedFromNBT(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:
+ static const AStringVector expectedTypes({ "Bed", "minecraft:bed" });
+ if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_BlockX, a_BlockY, a_BlockZ))
+ {
+ return nullptr;
+ }
+
+ // Use color red as default
+ short Color = E_META_WOOL_RED;
+
+ int ColorIDx = a_NBT.FindChildByName(a_TagIdx, "color");
+ if (ColorIDx >= 0)
+ {
+ Color = static_cast<short>(a_NBT.GetInt(ColorIDx));
+ }
+
+ auto Bed = cpp14::make_unique<cBedEntity>(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, m_World, Color);
+ return Bed.release();
+}
+
+
+
+
+
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:
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index b8d2d8508..12acbbcff 100755
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -156,6 +156,7 @@ protected:
bool CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, const AStringVector & a_ExpectedTypes, 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 * LoadBedFromNBT (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, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);
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, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ);