diff options
Diffstat (limited to '')
88 files changed, 1944 insertions, 1286 deletions
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index 5b1fea134..2252c7ded 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -18,11 +18,19 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2)); + return cItem(m_BlockType, 1, a_BlockMeta >> 2); } + + + + 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 { cWindow * Window = new cAnvilWindow(a_BlockX, a_BlockY, a_BlockZ); diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp index 6a5a9ec02..3f10a2e88 100644 --- a/src/Blocks/BlockBed.cpp +++ b/src/Blocks/BlockBed.cpp @@ -15,35 +15,33 @@ -void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockBedHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) { - Vector3i ThisPos(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(ThisPos); - Vector3i Direction = MetaDataToDirection(OldMeta & 0x3); - if (OldMeta & 0x8) + auto Direction = MetaDataToDirection(a_OldBlockMeta & 0x03); + if ((a_OldBlockMeta & 0x08) != 0) { // Was pillow - if (a_ChunkInterface.GetBlock(ThisPos - Direction) == E_BLOCK_BED) + if (a_ChunkInterface.GetBlock(a_BlockPos - Direction) == E_BLOCK_BED) { // First replace the bed with air - a_ChunkInterface.FastSetBlock(ThisPos - Direction, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockPos - 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); + Vector3i PillowPos(a_BlockPos - Direction); + a_ChunkInterface.SetBlock(PillowPos, E_BLOCK_AIR, 0); } } else { // Was foot end - if (a_ChunkInterface.GetBlock(ThisPos + Direction) == E_BLOCK_BED) + if (a_ChunkInterface.GetBlock(a_BlockPos + Direction) == E_BLOCK_BED) { // First replace the bed with air - a_ChunkInterface.FastSetBlock(ThisPos + Direction, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockPos + 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); + Vector3i FootPos(a_BlockPos + Direction); + a_ChunkInterface.SetBlock(FootPos, E_BLOCK_AIR, 0); } } } @@ -155,14 +153,12 @@ void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWor -void cBlockBedHandler::ConvertToPickups(cWorldInterface & a_WorldInterface, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ) +cItems cBlockBedHandler::ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) { - short Color = E_META_WOOL_RED; - a_WorldInterface.DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, [&](cBedEntity & a_Bed) - { - Color = a_Bed.GetColor(); - return true; - } - ); - a_Pickups.Add(cItem(E_ITEM_BED, 1, Color)); + short color = E_META_WOOL_RED; + if (a_BlockEntity != nullptr) + { + color = reinterpret_cast<cBedEntity *>(a_BlockEntity)->GetColor(); + } + return cItem(E_ITEM_BED, 1, color); } diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index c66542e7d..585067ce2 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -4,7 +4,7 @@ #pragma once #include "BlockEntity.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "ChunkInterface.h" @@ -18,24 +18,28 @@ class cWorldInterface; class cBlockBedHandler : public cMetaRotator<cBlockEntityHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true> { + using super = cMetaRotator<cBlockEntityHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>; + public: - cBlockBedHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockEntityHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType) + + cBlockBedHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override; + + + + // Overrides: + virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) 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 cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override; + virtual void OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) override; + - virtual bool IsUseable(void) override - { - return true; - } - virtual void ConvertToPickups(cItems & Pickups, NIBBLETYPE Meta) override {} - virtual void ConvertToPickups(cWorldInterface & a_WorldInterface, 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) @@ -51,18 +55,26 @@ public: return (static_cast<NIBBLETYPE>(a_Rotation + 2)) % 4; } + + + + static Vector3i MetaDataToDirection(NIBBLETYPE a_MetaData) { switch (a_MetaData) { - case 0: return Vector3i(0, 0, 1); - case 1: return Vector3i(-1, 0, 0); - case 2: return Vector3i(0, 0, -1); - case 3: return Vector3i(1, 0, 0); + case 0: return Vector3i( 0, 0, 1); + case 1: return Vector3i(-1, 0, 0); + case 2: return Vector3i( 0, 0, -1); + case 3: return Vector3i( 1, 0, 0); } return Vector3i(); } + + + + static void SetBedOccupationState(cChunkInterface & a_ChunkInterface, const Vector3i & a_BedPosition, bool a_IsOccupied) { auto Meta = a_ChunkInterface.GetBlockMeta(a_BedPosition); @@ -78,7 +90,9 @@ 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 { diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h index defe57d99..ae4b2500a 100644 --- a/src/Blocks/BlockBigFlower.h +++ b/src/Blocks/BlockBigFlower.h @@ -42,106 +42,53 @@ public: ); } - virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override - { - Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(Pos); - int AlternateY = a_BlockY; - int BottomY = a_BlockY; - if (Meta & 0x8) - { - --AlternateY; - --BottomY; - } - else - { - ++AlternateY; - } - // also destroy the other block if it has a valid height and is a big flower - if (cChunkDef::IsValidHeight(AlternateY) && a_ChunkInterface.GetBlock({Pos.x, AlternateY, Pos.z}) == E_BLOCK_BIG_FLOWER) - { - super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, BottomY, a_BlockZ, a_CanDrop); - a_ChunkInterface.FastSetBlock(a_BlockX, AlternateY, a_BlockZ, E_BLOCK_AIR, 0); - } - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { if (IsMetaTopPart(a_BlockMeta)) { - return; // No way to tell flower type + return {}; // No drops from the top part } - NIBBLETYPE Meta = a_BlockMeta & 0x7; - if (Meta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) + // With shears, drop self (even tall grass and fern): + if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS)) + { + // Bit 0x08 specifies whether this is a top part or bottom; cut it off from the pickup: + return cItem(m_BlockType, 1, a_BlockMeta & 0x07); + } + + // Tall grass drops seeds, large fern drops nothing, others drop self: + auto flowerType = a_BlockMeta & 0x07; + if (flowerType == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) { if (GetRandomProvider().RandBool(1.0 / 24.0)) { - a_Pickups.push_back(cItem(E_ITEM_SEEDS)); + return cItem(E_ITEM_SEEDS); } } - else if (Meta != E_META_BIG_FLOWER_LARGE_FERN) + else if (flowerType != E_META_BIG_FLOWER_LARGE_FERN) { - a_Pickups.push_back(cItem(E_BLOCK_BIG_FLOWER, 1, Meta)); + return cItem(m_BlockType, 1, static_cast<short>(flowerType)); } + return {}; } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - Vector3i BlockPos(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(BlockPos); - if (Meta & 0x8) - { - Meta = a_ChunkInterface.GetBlockMeta(BlockPos - Vector3i(0, 1, 0)); - } - NIBBLETYPE FlowerMeta = Meta & 0x7; - if (!a_Player.IsGameModeCreative()) - { - if ( - (a_Player.GetEquippedItem().m_ItemType == E_ITEM_SHEARS) && - ( - (FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) || - (FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN) - ) - ) - { - if (GetRandomProvider().RandBool(0.10)) - { - cItems Pickups; - if (FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) - { - Pickups.Add(E_BLOCK_TALL_GRASS, 2, 1); - } - else if (FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN) - { - Pickups.Add(E_BLOCK_TALL_GRASS, 2, 2); - } - a_WorldInterface.SpawnItemPickups(Pickups, BlockPos.x, BlockPos.y, BlockPos.z); - } - a_Player.UseEquippedItem(); - } - } - if ( - (a_Player.GetEquippedItem().m_ItemType != E_ITEM_SHEARS) && - ( - (FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) || - (FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN) - ) - ) - { - a_ChunkInterface.SetBlock(BlockPos.x, BlockPos.y, BlockPos.z, 0, 0); - a_Player.UseEquippedItem(cItemHandler::dlaBreakBlockInstant); - } - } + bool IsMetaTopPart(NIBBLETYPE a_Meta) { - return (a_Meta & 0x08) != 0; + return ((a_Meta & 0x08) != 0); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) @@ -155,31 +102,36 @@ public: return IsBlockTypeOfDirt(BlockType) || ((BlockType == E_BLOCK_BIG_FLOWER) && !IsMetaTopPart(BlockMeta)); } - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - Vector3i BlockPos(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(BlockPos); - if (OldMeta & 0x8) + + + + virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override + { + if ((a_OldBlockMeta & 0x8) != 0) { // Was upper part of flower - Vector3i LowerPart = BlockPos - Vector3i(0, 1, 0); - if (a_ChunkInterface.GetBlock(LowerPart) == m_BlockType) + auto lowerPartPos = a_BlockPos - Vector3i(0, 1, 0); + if (a_ChunkInterface.GetBlock(lowerPartPos) == a_OldBlockType) { - a_ChunkInterface.FastSetBlock(LowerPart, E_BLOCK_AIR, 0); + a_ChunkInterface.DropBlockAsPickups(lowerPartPos); } } else { // Was lower part - Vector3i UpperPart = BlockPos + Vector3i(0, 1, 0); - if (a_ChunkInterface.GetBlock(UpperPart) == m_BlockType) + auto upperPartPos = a_BlockPos + Vector3i(0, 1, 0); + if (a_ChunkInterface.GetBlock(upperPartPos) == a_OldBlockType) { - a_ChunkInterface.FastSetBlock(UpperPart, E_BLOCK_AIR, 0); + a_ChunkInterface.DropBlockAsPickups(upperPartPos); } } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockBrewingStand.h b/src/Blocks/BlockBrewingStand.h index 3445a0f5a..48158ef73 100644 --- a/src/Blocks/BlockBrewingStand.h +++ b/src/Blocks/BlockBrewingStand.h @@ -2,28 +2,27 @@ #pragma once #include "BlockEntity.h" -#include "MetaRotator.h" +#include "Mixins.h" + + class cBlockBrewingStandHandler : - public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> + public cClearMetaOnDrop<cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>> { + using super = cClearMetaOnDrop<cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>; + public: - cBlockBrewingStandHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockBrewingStandHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.push_back(cItem(E_ITEM_BREWING_STAND, 1, 0)); } - virtual bool IsUseable() override - { - return true; - } + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index f81220b36..86c7cb2c5 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -2,20 +2,27 @@ #include "BlockHandler.h" #include "../Chunk.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockButtonHandler : - public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true> + public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>> { + using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>>; + public: - cBlockButtonHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType) + + cBlockButtonHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + 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 { Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ); @@ -53,12 +60,6 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to 0 - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } - virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockCactus.h b/src/Blocks/BlockCactus.h index 371402423..f33c17153 100644 --- a/src/Blocks/BlockCactus.h +++ b/src/Blocks/BlockCactus.h @@ -8,21 +8,31 @@ class cBlockCactusHandler : - public cBlockPlant + public cBlockPlant<false> { - typedef cBlockPlant Super; + using super = cBlockPlant<false>; + public: - cBlockCactusHandler(BLOCKTYPE a_BlockType) - : Super(a_BlockType, false) + + cBlockCactusHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // Reset meta to 0 - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); + return cItem(m_BlockType, 1, 0); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) @@ -88,7 +98,7 @@ protected: auto Action = paStay; if (((a_RelY + 1) < cChunkDef::Height) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR)) { - Action = Super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); + Action = super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); } return Action; diff --git a/src/Blocks/BlockCake.h b/src/Blocks/BlockCake.h index 88125c56b..4767a5148 100644 --- a/src/Blocks/BlockCake.h +++ b/src/Blocks/BlockCake.h @@ -35,11 +35,20 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // Give nothing + return {}; } + + + + virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockCarpet.h b/src/Blocks/BlockCarpet.h index aee36d271..2b2ae2434 100644 --- a/src/Blocks/BlockCarpet.h +++ b/src/Blocks/BlockCarpet.h @@ -17,12 +17,19 @@ class cBlockCarpetHandler : public cBlockHandler { + using super = cBlockHandler; + public: + cBlockCarpetHandler(BLOCKTYPE a_BlockType) : - cBlockHandler(a_BlockType) + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -35,16 +42,19 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - a_Pickups.push_back(cItem(E_BLOCK_CARPET, 1, a_BlockMeta)); - } + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { return (a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { switch (a_Meta) diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h index 466eb6bcc..40eab2be9 100644 --- a/src/Blocks/BlockCauldron.h +++ b/src/Blocks/BlockCauldron.h @@ -8,17 +8,15 @@ class cBlockCauldronHandler : - public cBlockHandler + public cClearMetaOnDrop<cBlockHandler> { + using super = cClearMetaOnDrop<cBlockHandler>; + public: - cBlockCauldronHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockCauldronHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.push_back(cItem(E_ITEM_CAULDRON, 1, 0)); } 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 diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h index 804c3d34a..0e277532e 100644 --- a/src/Blocks/BlockChest.h +++ b/src/Blocks/BlockChest.h @@ -1,24 +1,31 @@ #pragma once -#include "BlockEntity.h" +#include "../BlockEntities/ChestEntity.h" #include "../BlockArea.h" #include "../Entities/Player.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockChestHandler : - public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> + public cMetaRotator<cContainerEntityHandler<cBlockEntityHandler>, 0x07, 0x02, 0x05, 0x03, 0x04> { + using super = cMetaRotator<cContainerEntityHandler<cBlockEntityHandler>, 0x07, 0x02, 0x05, 0x03, 0x04>; + public: - cBlockChestHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) + + cBlockChestHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -65,6 +72,10 @@ public: return true; } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; @@ -72,6 +83,10 @@ public: return CanBeAt(a_ChunkInterface, BlockX, a_RelY, BlockZ); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) { cBlockArea Area; @@ -137,6 +152,10 @@ public: return (NumChestNeighbors < 2); } + + + + /** Translates player yaw when placing a chest into the chest block metadata. Valid for single chests only */ static NIBBLETYPE PlayerYawToMetaData(double a_Yaw) { @@ -164,6 +183,10 @@ public: } } + + + + /** If there's a chest in the a_Area in the specified coords, modifies its meta to a_NewMeta and returns true. */ bool CheckAndAdjustNeighbor(cChunkInterface & a_ChunkInterface, const cBlockArea & a_Area, int a_RelX, int a_RelZ, NIBBLETYPE a_NewMeta) { @@ -175,10 +198,9 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { diff --git a/src/Blocks/BlockCobWeb.h b/src/Blocks/BlockCobWeb.h index e7dd70af4..0c80edd2d 100644 --- a/src/Blocks/BlockCobWeb.h +++ b/src/Blocks/BlockCobWeb.h @@ -18,11 +18,27 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_STRING, 1, 0)); + // Silk touch gives cobweb, anything else gives just string: + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(m_BlockType, 1, 0); + } + else + { + return cItem(E_ITEM_STRING, 1, 0); + } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockCocoaPod.h b/src/Blocks/BlockCocoaPod.h index 4a1fb8c10..2d5243995 100644 --- a/src/Blocks/BlockCocoaPod.h +++ b/src/Blocks/BlockCocoaPod.h @@ -44,12 +44,21 @@ public: } } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - int GrowState = a_BlockMeta >> 2; - a_Pickups.Add(E_ITEM_DYE, ((GrowState >= 2) ? 3 : 1), E_META_DYE_BROWN); + // If fully grown, give 3 items, otherwise just one: + auto growState = a_BlockMeta >> 2; + return cItem(E_ITEM_DYE, ((growState >= 2) ? 3 : 1), E_META_DYE_BROWN); } + + + + static eBlockFace MetaToBlockFace(NIBBLETYPE a_Meta) { switch (a_Meta & 0x3) diff --git a/src/Blocks/BlockCommandBlock.h b/src/Blocks/BlockCommandBlock.h index d1b81185f..70b98baf0 100644 --- a/src/Blocks/BlockCommandBlock.h +++ b/src/Blocks/BlockCommandBlock.h @@ -10,17 +10,29 @@ class cBlockCommandBlockHandler : public cBlockEntityHandler { + using super = cBlockEntityHandler; + public: - cBlockCommandBlockHandler(BLOCKTYPE a_BlockType) - : cBlockEntityHandler(a_BlockType) + + cBlockCommandBlockHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_BLOCK_AIR, 8, 0)); + // Don't allow as a pickup: + return {}; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h index ddbcaa0c2..4103c805e 100644 --- a/src/Blocks/BlockComparator.h +++ b/src/Blocks/BlockComparator.h @@ -3,18 +3,21 @@ #include "BlockHandler.h" #include "BlockRedstoneRepeater.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockComparatorHandler : - public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true> + public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>> { + using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>>; + public: - cBlockComparatorHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType) + + cBlockComparatorHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -32,12 +35,6 @@ public: a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to 0 - a_Pickups.push_back(cItem(E_ITEM_COMPARATOR, 1, 0)); - } - virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockConcretePowder.h b/src/Blocks/BlockConcretePowder.h index 4b2a81b2a..58dfade99 100644 --- a/src/Blocks/BlockConcretePowder.h +++ b/src/Blocks/BlockConcretePowder.h @@ -10,9 +10,12 @@ class cBlockConcretePowderHandler : public cBlockHandler { + using super = cBlockHandler; + public: + cBlockConcretePowderHandler(BLOCKTYPE a_BlockType): - cBlockHandler(a_BlockType) + super(a_BlockType) { } @@ -20,21 +23,25 @@ public: - virtual void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override + virtual void Check( + cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk + ) override { - if (GetSoaked(Vector3i(a_RelX, a_RelY, a_RelZ), a_Chunk)) + if (GetSoaked(a_RelPos, a_Chunk)) { return; } - cBlockHandler::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk); + super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk); } - /** Check blocks above and around to see if they are water. If one is, convert this into concrete block. - Returns TRUE if the block was changed. */ + /** Check blocks above and around to see if they are water. If one is, converts this into concrete block. + Returns true if the block was changed. */ bool GetSoaked(Vector3i a_Rel, cChunk & a_Chunk) { static const std::array<Vector3i, 5> WaterCheck @@ -62,7 +69,7 @@ public: { NIBBLETYPE BlockMeta; BlockMeta = a_Chunk.GetMeta(a_Rel.x, a_Rel.y, a_Rel.z); - a_Chunk.SetBlock(a_Rel.x, a_Rel.y, a_Rel.z, E_BLOCK_CONCRETE, BlockMeta); + a_Chunk.SetBlock(a_Rel, E_BLOCK_CONCRETE, BlockMeta); return true; } return false; diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h index 378505430..0d6296a33 100644 --- a/src/Blocks/BlockCrops.h +++ b/src/Blocks/BlockCrops.h @@ -10,71 +10,70 @@ /** Common class that takes care of beetroots, carrots, potatoes and wheat */ template <NIBBLETYPE RipeMeta> -class cBlockCropsHandler : - public cBlockPlant +class cBlockCropsHandler: + public cBlockPlant<true> { - typedef cBlockPlant Super; + using super = cBlockPlant<true>; public: cBlockCropsHandler(BLOCKTYPE a_BlockType): - Super(a_BlockType, true) + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { auto & rand = GetRandomProvider(); // If not fully grown, drop the "seed" of whatever is growing: - if (a_Meta < RipeMeta) + if (a_BlockMeta < RipeMeta) { switch (m_BlockType) { - case E_BLOCK_BEETROOTS: a_Pickups.push_back(cItem(E_ITEM_BEETROOT_SEEDS, 1, 0)); break; - case E_BLOCK_CROPS: a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1, 0)); break; - case E_BLOCK_CARROTS: a_Pickups.push_back(cItem(E_ITEM_CARROT, 1, 0)); break; - case E_BLOCK_POTATOES: a_Pickups.push_back(cItem(E_ITEM_POTATO, 1, 0)); break; - default: - { - ASSERT(!"Unhandled block type"); - break; - } + case E_BLOCK_BEETROOTS: return cItem(E_ITEM_BEETROOT_SEEDS, 1, 0); break; + case E_BLOCK_CROPS: return cItem(E_ITEM_SEEDS, 1, 0); break; + case E_BLOCK_CARROTS: return cItem(E_ITEM_CARROT, 1, 0); break; + case E_BLOCK_POTATOES: return cItem(E_ITEM_POTATO, 1, 0); break; } - return; + ASSERT(!"Unhandled block type"); + return {}; } // Fully grown, drop the crop's produce: + cItems res; switch (m_BlockType) { case E_BLOCK_BEETROOTS: { char SeedCount = 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2); // [1 .. 3] with high preference of 2 - a_Pickups.emplace_back(E_ITEM_BEETROOT_SEEDS, SeedCount, 0); + res.Add(E_ITEM_BEETROOT_SEEDS, SeedCount, 0); char BeetrootCount = 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2); // [1 .. 3] with high preference of 2 - a_Pickups.emplace_back(E_ITEM_BEETROOT, BeetrootCount, 0); + res.Add(E_ITEM_BEETROOT, BeetrootCount, 0); break; } case E_BLOCK_CROPS: { - a_Pickups.emplace_back(E_ITEM_WHEAT, 1, 0); - a_Pickups.emplace_back(E_ITEM_SEEDS, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2 + res.Add(E_ITEM_WHEAT, 1, 0); + res.Add(E_ITEM_SEEDS, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2 break; } case E_BLOCK_CARROTS: { - a_Pickups.emplace_back(E_ITEM_CARROT, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2 + res.Add(E_ITEM_CARROT, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2 break; } case E_BLOCK_POTATOES: { - a_Pickups.emplace_back(E_ITEM_POTATO, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2 + res.Add(E_ITEM_POTATO, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2 if (rand.RandBool(0.05)) { // With a 5% chance, drop a poisonous potato as well - a_Pickups.emplace_back(E_ITEM_POISONOUS_POTATO, 1, 0); + res.emplace_back(E_ITEM_POISONOUS_POTATO, 1, 0); } break; } @@ -84,10 +83,13 @@ public: break; } } // switch (m_BlockType) + return res; } + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); diff --git a/src/Blocks/BlockDeadBush.h b/src/Blocks/BlockDeadBush.h index 68846ff46..0b7d27e8b 100644 --- a/src/Blocks/BlockDeadBush.h +++ b/src/Blocks/BlockDeadBush.h @@ -43,57 +43,34 @@ public: } } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Drop 0-3 sticks - char chance = GetRandomProvider().RandInt<char>(3); - if (chance != 0) - { - a_Pickups.emplace_back(E_ITEM_STICK, chance, 0); - } - } - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override - { - UNUSED(a_Meta); - return 0; - } - virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - if (a_CanDrop && (a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_ItemType == E_ITEM_SHEARS)) + // If cutting down with shears, drop self: + if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS)) { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); - cItems Drops; - Drops.Add(m_BlockType, 1, Meta); + return cItem(m_BlockType, 1, a_BlockMeta); + } - // Allow plugins to modify the pickups: - a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Drops); + // Drop 0-3 sticks: + auto chance = GetRandomProvider().RandInt<char>(3); + if (chance > 0) + { + return cItem(E_ITEM_STICK, chance, 0); + } + return {}; + } - // Spawn the pickups: - if (!Drops.empty()) - { - auto & r1 = GetRandomProvider(); - // Mid-block position first - double MicroX, MicroY, MicroZ; - MicroX = a_BlockX + 0.5; - MicroY = a_BlockY + 0.5; - MicroZ = a_BlockZ + 0.5; - // Add random offset second - MicroX += r1.RandReal<double>(-0.5, 0.5); - MicroZ += r1.RandReal<double>(-0.5, 0.5); - a_WorldInterface.SpawnItemPickups(Drops, MicroX, MicroY, MicroZ); - } - return; - } - super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop); + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override + { + UNUSED(a_Meta); + return 0; } } ; - - - - diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h index 43cadf767..0d4f73212 100644 --- a/src/Blocks/BlockDirt.h +++ b/src/Blocks/BlockDirt.h @@ -20,19 +20,27 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { if (a_BlockMeta == E_META_DIRT_COARSE) { // Drop the coarse block (dirt, meta 1) - a_Pickups.Add(E_BLOCK_DIRT, 1, E_META_DIRT_COARSE); + return cItem(E_BLOCK_DIRT, 1, E_META_DIRT_COARSE); } else { - a_Pickups.Add(E_BLOCK_DIRT, 1, E_META_DIRT_NORMAL); + return cItem(E_BLOCK_DIRT, 1, E_META_DIRT_NORMAL); } } + + + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { if (m_BlockType != E_BLOCK_GRASS) diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp index fe0db26ec..d9a4f12ec 100644 --- a/src/Blocks/BlockDoor.cpp +++ b/src/Blocks/BlockDoor.cpp @@ -7,8 +7,8 @@ -cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType) - : super(a_BlockType) +cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -16,24 +16,22 @@ cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType) -void cBlockDoorHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockDoorHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) { - NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); - - if (OldMeta & 8) + if ((a_OldBlockMeta & 0x08) != 0) { // Was upper part of door - if (IsDoorBlockType(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY - 1, a_BlockZ}))) + if ((a_BlockPos.y > 0) && IsDoorBlockType(a_ChunkInterface.GetBlock(a_BlockPos.addedY(-1)))) { - a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.DropBlockAsPickups(a_BlockPos.addedY(-1)); } } else { // Was lower part - if (IsDoorBlockType(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY + 1, a_BlockZ}))) + if ((a_BlockPos.y < cChunkDef::Height - 1) && IsDoorBlockType(a_ChunkInterface.GetBlock(a_BlockPos.addedY(1)))) { - a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.DropBlockAsPickups(a_BlockPos.addedY(1)); } } } diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index 04d63141d..b1a606f67 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -4,7 +4,7 @@ #include "BlockHandler.h" #include "../Entities/Player.h" #include "../Chunk.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "ChunkInterface.h" #include "BlockSlab.h" @@ -13,11 +13,13 @@ class cBlockDoorHandler : public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> { - typedef cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super; + using super = cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true>; + public: + cBlockDoorHandler(BLOCKTYPE a_BlockType); - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) 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 void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override; @@ -54,57 +56,39 @@ public: virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) override; - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - if ((a_BlockMeta & 0x08) != 0) // is top part of door + // Top part of a door doesn't drop anything: + if ((a_BlockMeta & 0x08) != 0) { - return; + return {}; } + switch (m_BlockType) { - case E_BLOCK_OAK_DOOR: - { - a_Pickups.Add(E_ITEM_WOODEN_DOOR); - break; - } - case E_BLOCK_ACACIA_DOOR: - { - a_Pickups.Add(E_ITEM_ACACIA_DOOR); - break; - } - case E_BLOCK_BIRCH_DOOR: - { - a_Pickups.Add(E_ITEM_BIRCH_DOOR); - break; - } - case E_BLOCK_DARK_OAK_DOOR: - { - a_Pickups.Add(E_ITEM_DARK_OAK_DOOR); - break; - } - case E_BLOCK_JUNGLE_DOOR: - { - a_Pickups.Add(E_ITEM_JUNGLE_DOOR); - break; - } - case E_BLOCK_SPRUCE_DOOR: - { - a_Pickups.Add(E_ITEM_SPRUCE_DOOR); - break; - } - case E_BLOCK_IRON_DOOR: - { - a_Pickups.Add(E_ITEM_IRON_DOOR); - break; - } + case E_BLOCK_OAK_DOOR: return cItem(E_ITEM_WOODEN_DOOR); + case E_BLOCK_ACACIA_DOOR: return cItem(E_ITEM_ACACIA_DOOR); + case E_BLOCK_BIRCH_DOOR: return cItem(E_ITEM_BIRCH_DOOR); + case E_BLOCK_DARK_OAK_DOOR: return cItem(E_ITEM_DARK_OAK_DOOR); + case E_BLOCK_JUNGLE_DOOR: return cItem(E_ITEM_JUNGLE_DOOR); + case E_BLOCK_SPRUCE_DOOR: return cItem(E_ITEM_SPRUCE_DOOR); + case E_BLOCK_IRON_DOOR: return cItem(E_ITEM_IRON_DOOR); default: { ASSERT(!"Unhandled door type!"); - break; + return {}; } } } + + + + virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h index 2700b416c..ce98940d2 100644 --- a/src/Blocks/BlockDropSpenser.h +++ b/src/Blocks/BlockDropSpenser.h @@ -6,7 +6,8 @@ #pragma once #include "../Blocks/BlockPiston.h" -#include "MetaRotator.h" +#include "../BlockEntities/DropSpenserEntity.h" +#include "Mixins.h" @@ -15,12 +16,19 @@ class cBlockDropSpenserHandler : public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> { + using super = cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>; + public: - cBlockDropSpenserHandler(BLOCKTYPE a_BlockType) : - cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) + + cBlockDropSpenserHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -35,18 +43,30 @@ public: return true; } - /** Called when the drop / dispenser is convert into pickup, ignore meta data */ - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - UNUSED(a_BlockMeta); - a_Pickups.push_back(cItem(m_BlockType, 1)); + cItems res(cItem(m_BlockType, 1)); + if (a_BlockEntity != nullptr) + { + auto be = static_cast<cDropSpenserEntity *>(a_BlockEntity); + res.AddItemGrid(be->GetContents()); + } + return res; } + + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override { - // Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000 + // Bit 0x08 is a flag. Lowest three bits are position. NIBBLETYPE OtherMeta = a_Meta & 0x08; - // Mirrors defined by by a table. (Source, mincraft.gamepedia.com) 0x07 == 0111 + // Mirrors defined by a table. (Source, minecraft.gamepedia.com) switch (a_Meta & 0x07) { case 0x00: return 0x01 + OtherMeta; // Down -> Up @@ -56,6 +76,10 @@ public: return a_Meta; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockEndPortalFrame.h b/src/Blocks/BlockEndPortalFrame.h index e1741f5f6..c35d13929 100644 --- a/src/Blocks/BlockEndPortalFrame.h +++ b/src/Blocks/BlockEndPortalFrame.h @@ -76,7 +76,7 @@ public: - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override { // E_META_END_PORTAL_FRAME_EYE is the bit which signifies the eye of ender is in it. // LOG("PortalPlaced, meta %d", a_BlockMeta); @@ -84,7 +84,7 @@ public: { // LOG("Location is %d %d %d", a_BlockX, a_BlockY, a_BlockZ); // Direction is the first two bits, masked by 0x3 - FindAndSetPortal(Vector3i(a_BlockX, a_BlockY, a_BlockZ), a_BlockMeta & 3, a_ChunkInterface, a_WorldInterface); + FindAndSetPortal(a_BlockPos, a_BlockMeta & 3, a_ChunkInterface, a_WorldInterface); } } diff --git a/src/Blocks/BlockEnderchest.h b/src/Blocks/BlockEnderchest.h index 8fd5c2a89..f233468f4 100644 --- a/src/Blocks/BlockEnderchest.h +++ b/src/Blocks/BlockEnderchest.h @@ -2,7 +2,7 @@ #pragma once #include "BlockEntity.h" -#include "MetaRotator.h" +#include "Mixins.h" @@ -10,17 +10,44 @@ class cBlockEnderchestHandler : public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> { + using super = cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>; + public: - cBlockEnderchestHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) + + cBlockEnderchestHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_BLOCK_OBSIDIAN, 8, 0)); + // Only drop something when mined with a pickaxe: + if ( + (a_Tool != nullptr) && + ItemCategory::IsPickaxe(a_Tool->m_ItemType) + ) + { + // Only drop self when mined with a silk-touch pickaxe: + if (a_Tool->m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) + { + return cItem(E_BLOCK_ENDER_CHEST, 1, 0); + } + else + { + return cItem(E_BLOCK_OBSIDIAN, 8, 0); + } + } + return {}; } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, diff --git a/src/Blocks/BlockEntity.h b/src/Blocks/BlockEntity.h index 77d6a7f1e..f592dbd83 100644 --- a/src/Blocks/BlockEntity.h +++ b/src/Blocks/BlockEntity.h @@ -3,23 +3,40 @@ #include "BlockHandler.h" #include "ChunkInterface.h" +#include "../Item.h" +#include "../BlockEntities/BlockEntityWithItems.h" -class cBlockEntityHandler : public cBlockHandler + +/** Wrapper for blocks that have a cBlockEntity descendant attached to them and can be "used" by the player. +Forwards the "use" event to the block entity. */ +class cBlockEntityHandler: + public cBlockHandler { + using super = cBlockHandler; + public: - cBlockEntityHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockEntityHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + 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 { return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockX, a_BlockY, a_BlockZ); } + + + + virtual bool IsUseable() override { return true; @@ -29,3 +46,35 @@ public: + +/** Wrapper for blocks that have a cBlockEntityWithItems descendant attached to them. +When converting to pickups, drops self with meta reset to zero, and adds the container contents. */ +template <typename Base = cBlockEntityHandler> +class cContainerEntityHandler: + public Base +{ +public: + + cContainerEntityHandler(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + // Reset meta to 0 + cItems res(cItem(Base::m_BlockType, 1, 0)); + + // Drop the contents: + if (a_BlockEntity != nullptr) + { + auto container = static_cast<cBlockEntityWithItems *>(a_BlockEntity); + res.AddItemGrid(container->GetContents()); + } + return res; + } +}; diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h index 09982cd5e..219f9a654 100644 --- a/src/Blocks/BlockFarmland.h +++ b/src/Blocks/BlockFarmland.h @@ -17,15 +17,21 @@ class cBlockFarmlandHandler : - public cBlockHandler + public cClearMetaOnDrop<cBlockHandler> { + using super = cClearMetaOnDrop<cBlockHandler>; public: - cBlockFarmlandHandler(BLOCKTYPE a_BlockType) : - cBlockHandler(a_BlockType) + + cBlockFarmlandHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { NIBBLETYPE BlockMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); @@ -60,14 +66,17 @@ public: } default: { - a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, 0); + a_Chunk.SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_DIRT, 0); break; } } } - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override + + + + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override { // Don't care about any neighbor but the one above us (fix recursion loop in #2213): if (a_WhichNeighbor != BLOCK_FACE_YP) @@ -76,24 +85,21 @@ public: } // Don't care about anything if we're at the top of the world: - if (a_BlockY >= cChunkDef::Height) + if (a_BlockPos.y >= cChunkDef::Height) { return; } // Check whether we should revert to dirt: - BLOCKTYPE UpperBlock = a_ChunkInterface.GetBlock({a_BlockX, a_BlockY + 1, a_BlockZ}); - if (cBlockInfo::FullyOccupiesVoxel(UpperBlock)) + auto upperBlock = a_ChunkInterface.GetBlock(a_BlockPos.addedY(1)); + if (cBlockInfo::FullyOccupiesVoxel(upperBlock)) { - a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DIRT, 0); + a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_DIRT, 0); } } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - a_Pickups.Add(E_BLOCK_DIRT, 1, 0); // Reset meta - } + bool IsWaterInNear(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) diff --git a/src/Blocks/BlockFence.h b/src/Blocks/BlockFence.h index 6c38b7c72..96a3d8d96 100644 --- a/src/Blocks/BlockFence.h +++ b/src/Blocks/BlockFence.h @@ -122,13 +122,21 @@ public: return true; } - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - auto LeashKnot = cLeashKnot::FindKnotAtPos(a_WorldInterface, { a_BlockX, a_BlockY, a_BlockZ }); - if (LeashKnot != nullptr) + + + + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override + { + // Destroy any leash knot tied to the fence: + auto leashKnot = cLeashKnot::FindKnotAtPos(a_WorldInterface, a_BlockPos); + if (leashKnot != nullptr) { - LeashKnot->SetShouldSelfDestroy(); + leashKnot->SetShouldSelfDestroy(); } } diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h index c8fca21af..c56925633 100644 --- a/src/Blocks/BlockFenceGate.h +++ b/src/Blocks/BlockFenceGate.h @@ -2,24 +2,22 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "../EffectID.h" class cBlockFenceGateHandler : - public cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true> + public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>> { + using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>>; + public: - cBlockFenceGateHandler(BLOCKTYPE a_BlockType) : - cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockFenceGateHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.Add(m_BlockType, 1, 0); // Reset meta to zero } virtual bool GetPlacementBlockTypeMeta( diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h index ae0df0727..a4b3d3a05 100644 --- a/src/Blocks/BlockFire.h +++ b/src/Blocks/BlockFire.h @@ -18,11 +18,16 @@ public: } /** Portal boundary and direction variables */ - // 2014_03_30 _X: What are these used for? Why do we need extra variables? + // TODO: These need to be removed, BlockHandler instances are shared for all blocks in all worlds on the server + // and are not supposed to have any data in them. int XZP, XZM; NIBBLETYPE Dir; - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + + + + + virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override { /* PORTAL FINDING ALGORITH @@ -38,14 +43,23 @@ public: */ // a_BlockY - 1: Because we want the block below the fire - FindAndSetPortalFrame(a_BlockX, a_BlockY - 1, a_BlockZ, a_ChunkInterface, a_WorldInterface); + FindAndSetPortalFrame(a_BlockPos.x, a_BlockPos.y - 1, a_BlockPos.z, a_ChunkInterface, a_WorldInterface); } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // No pickups from this block + return {}; } + + + + virtual bool IsClickedThrough(void) override { return true; @@ -102,6 +116,10 @@ public: return true; } + + + + /** Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE) */ void FindAndSetPortalFrame(int X, int Y, int Z, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface) { diff --git a/src/Blocks/BlockFlower.h b/src/Blocks/BlockFlower.h index 3340b701f..d88891d75 100644 --- a/src/Blocks/BlockFlower.h +++ b/src/Blocks/BlockFlower.h @@ -16,13 +16,20 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - NIBBLETYPE Meta = a_BlockMeta & 0x7; - a_Pickups.push_back(cItem(m_BlockType, 1, Meta)); + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + NIBBLETYPE meta = a_BlockMeta & 0x7; + return cItem(m_BlockType, 1, meta); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)); diff --git a/src/Blocks/BlockFlowerPot.h b/src/Blocks/BlockFlowerPot.h index 40bad534f..36c71df5b 100644 --- a/src/Blocks/BlockFlowerPot.h +++ b/src/Blocks/BlockFlowerPot.h @@ -8,19 +8,21 @@ class cBlockFlowerPotHandler : - public cBlockEntityHandler + public cClearMetaOnDrop<cBlockEntityHandler> { + using super = cClearMetaOnDrop<cBlockEntityHandler>; + public: - cBlockFlowerPotHandler(BLOCKTYPE a_BlockType) : - cBlockEntityHandler(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockFlowerPotHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.push_back(cItem(E_ITEM_FLOWER_POT, 1, 0)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index c33427739..430940df0 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -19,34 +19,55 @@ public: } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // No pickups + return {}; } + + + + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } - virtual void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override + + + + + virtual void Check( + cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk + ) override { switch (m_BlockType) { case E_BLOCK_STATIONARY_LAVA: { - a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_LAVA, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); + a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_LAVA, a_Chunk.GetMeta(a_RelPos)); break; } case E_BLOCK_STATIONARY_WATER: { - a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_WATER, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); + a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_WATER, a_Chunk.GetMeta(a_RelPos)); break; } } - super::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk); + super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h index ea1779c41..4a0459bf0 100644 --- a/src/Blocks/BlockFurnace.h +++ b/src/Blocks/BlockFurnace.h @@ -3,25 +3,27 @@ #include "BlockEntity.h" #include "../Blocks/BlockPiston.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockFurnaceHandler : - public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> + public cClearMetaOnDrop<cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>> { + using super = cClearMetaOnDrop<cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>; + public: - cBlockFurnaceHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockFurnaceHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.push_back(cItem(E_BLOCK_FURNACE, 1, 0)); } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -37,6 +39,10 @@ public: return true; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockGlass.h b/src/Blocks/BlockGlass.h index 5b797be31..8d082a2bf 100644 --- a/src/Blocks/BlockGlass.h +++ b/src/Blocks/BlockGlass.h @@ -16,10 +16,24 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { + // Only drop self when mined with silk-touch: + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(m_BlockType, 1, a_BlockMeta); + } + return {}; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockGlowstone.h b/src/Blocks/BlockGlowstone.h index 4b0d72a93..eddbf30d9 100644 --- a/src/Blocks/BlockGlowstone.h +++ b/src/Blocks/BlockGlowstone.h @@ -16,12 +16,28 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // Add more than one dust - a_Pickups.emplace_back(E_ITEM_GLOWSTONE_DUST, GetRandomProvider().RandInt<char>(2, 4), 0); + // Drop self only when using silk-touch: + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(E_BLOCK_GLOWSTONE, 1, 0); + } + else + { + // TODO: Handle the Fortune enchantment here + return cItem(E_ITEM_GLOWSTONE_DUST, GetRandomProvider().RandInt<char>(2, 4), 0); + } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockGravel.h b/src/Blocks/BlockGravel.h index 6229d1d75..fe93dc96b 100644 --- a/src/Blocks/BlockGravel.h +++ b/src/Blocks/BlockGravel.h @@ -16,18 +16,27 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { + // TODO: Handle the Fortune and Silk touch enchantments here if (GetRandomProvider().RandBool(0.10)) { - a_Pickups.Add(E_ITEM_FLINT, 1, 0); + return cItem(E_ITEM_FLINT, 1, 0); } else { - a_Pickups.Add(E_BLOCK_GRAVEL, 1, 0); + return cItem(E_BLOCK_GRAVEL, 1, 0); } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 928fca1e9..58096f038 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -189,6 +189,7 @@ static cBlockHandler * CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_ACACIA_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType); case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType); + case E_BLOCK_AIR: return new cBlockWithNoDrops<> (a_BlockType); case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType); case E_BLOCK_BEACON: return new cBlockEntityHandler (a_BlockType); case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType); @@ -401,185 +402,72 @@ void cBlockHandler::OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface void cBlockHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) { - OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta); + OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetPos(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta); } -void cBlockHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) -{ -} - - - - - -void cBlockHandler::OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +void cBlockHandler::OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { // Notify the neighbors - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ, BLOCK_FACE_XP); - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ, BLOCK_FACE_XM); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_YP); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_YM); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1, BLOCK_FACE_ZP); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ + 1, BLOCK_FACE_ZM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedX(-1), BLOCK_FACE_XP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedX( 1), BLOCK_FACE_XM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedY(-1), BLOCK_FACE_YP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedY( 1), BLOCK_FACE_YM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ(-1), BLOCK_FACE_ZP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ( 1), BLOCK_FACE_ZM); } -void cBlockHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) { // Notify the neighbors - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ, BLOCK_FACE_XP); - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ, BLOCK_FACE_XM); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_YP); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_YM); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1, BLOCK_FACE_ZP); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ + 1, BLOCK_FACE_ZM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedX(-1), BLOCK_FACE_XP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedX( 1), BLOCK_FACE_XM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedY(-1), BLOCK_FACE_YP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedY( 1), BLOCK_FACE_YM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ(-1), BLOCK_FACE_ZP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ( 1), BLOCK_FACE_ZM); } -void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_NeighborX, int a_NeighborY, int a_NeighborZ, eBlockFace a_WhichNeighbor) +void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_NeighborPos, eBlockFace a_WhichNeighbor) { - if ((a_NeighborY >= 0) && (a_NeighborY < cChunkDef::Height)) + if (!cChunkDef::IsValidHeight(a_NeighborPos.y)) { - cBlockInfo::GetHandler(a_ChunkInterface.GetBlock({a_NeighborX, a_NeighborY, a_NeighborZ}))->OnNeighborChanged(a_ChunkInterface, a_NeighborX, a_NeighborY, a_NeighborZ, a_WhichNeighbor); + return; } -} - - - - -void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) -{ - // Setting the meta to a_BlockMeta keeps most textures. The few other blocks have to override this. - a_Pickups.push_back(cItem(m_BlockType, 1, a_BlockMeta)); + cBlockInfo::GetHandler(a_ChunkInterface.GetBlock(a_NeighborPos))->OnNeighborChanged(a_ChunkInterface, a_NeighborPos, a_WhichNeighbor); } -void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) +cItems cBlockHandler::ConvertToPickups( + NIBBLETYPE a_BlockMeta, + cBlockEntity * a_BlockEntity, + const cEntity * a_Digger, + const cItem * a_Tool +) { - cItems Pickups; - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); - - if (a_CanDrop) - { - if ((a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0)) - { - switch (m_BlockType) - { - case E_BLOCK_ACACIA_DOOR: - case E_BLOCK_ACTIVE_COMPARATOR: - case E_BLOCK_BEETROOTS: - case E_BLOCK_BIRCH_DOOR: - case E_BLOCK_BREWING_STAND: - case E_BLOCK_CAKE: - case E_BLOCK_CARROTS: - case E_BLOCK_CAULDRON: - case E_BLOCK_COCOA_POD: - case E_BLOCK_CROPS: - case E_BLOCK_DARK_OAK_DOOR: - case E_BLOCK_DEAD_BUSH: - case E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB: - case E_BLOCK_DOUBLE_STONE_SLAB: - case E_BLOCK_DOUBLE_WOODEN_SLAB: - case E_BLOCK_FIRE: - case E_BLOCK_FARMLAND: - case E_BLOCK_FLOWER_POT: - case E_BLOCK_HEAD: - case E_BLOCK_INACTIVE_COMPARATOR: - case E_BLOCK_INVERTED_DAYLIGHT_SENSOR: - case E_BLOCK_IRON_DOOR: - case E_BLOCK_JUNGLE_DOOR: - case E_BLOCK_MELON_STEM: - case E_BLOCK_MOB_SPAWNER: - case E_BLOCK_NETHER_WART: - case E_BLOCK_OAK_DOOR: - case E_BLOCK_PISTON_EXTENSION: - case E_BLOCK_POTATOES: - case E_BLOCK_PUMPKIN_STEM: - case E_BLOCK_PURPUR_DOUBLE_SLAB: - case E_BLOCK_REDSTONE_ORE_GLOWING: - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_WIRE: - case E_BLOCK_SIGN_POST: - case E_BLOCK_SNOW: - case E_BLOCK_SPRUCE_DOOR: - case E_BLOCK_STANDING_BANNER: - case E_BLOCK_SUGARCANE: - case E_BLOCK_TALL_GRASS: - case E_BLOCK_TRIPWIRE: - case E_BLOCK_WALL_BANNER: - case E_BLOCK_WALLSIGN: - { - // Silktouch can't be used for these blocks - ConvertToPickups(Pickups, Meta); - break; - } - case E_BLOCK_BED: - { - // Need to access the bed entity to get the color for the item damage - ConvertToPickups(a_WorldInterface, Pickups, Meta, a_BlockX, a_BlockY, a_BlockZ); - break; - } - case E_BLOCK_ENDER_CHEST: - { - // Reset meta to 0 - Pickups.Add(m_BlockType, 1, 0); - break; - } - case E_BLOCK_LEAVES: - case E_BLOCK_NEW_LEAVES: - { - Pickups.Add(m_BlockType, 1, Meta & 0x03); - break; - } - 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_WorldInterface, Pickups, Meta, a_BlockX, a_BlockY, a_BlockZ); - } - else - { - ConvertToPickups(Pickups, Meta); - } - } - - // Allow plugins to modify the pickups: - a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Pickups); - - if (!Pickups.empty()) - { - auto & r1 = GetRandomProvider(); - - // Mid-block position first - double MicroX, MicroY, MicroZ; - MicroX = a_BlockX + 0.5; - MicroY = a_BlockY + 0.5; - MicroZ = a_BlockZ + 0.5; - - // Add random offset second - MicroX += r1.RandReal<double>(-0.5, 0.5); - MicroZ += r1.RandReal<double>(-0.5, 0.5); - - a_WorldInterface.SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ); - } + UNUSED(a_BlockEntity); + UNUSED(a_Digger); + UNUSED(a_Tool); + + // Add self: + cItems res; + res.push_back(cItem(m_BlockType, 1, a_BlockMeta)); + return res; } @@ -655,25 +543,28 @@ cBoundingBox cBlockHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a -void cBlockHandler::Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) +void cBlockHandler::Check( + cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk +) { - if (!CanBeAt(a_ChunkInterface, a_RelX, a_RelY, a_RelZ, a_Chunk)) + if (!CanBeAt(a_ChunkInterface, a_RelPos.x, a_RelPos.y, a_RelPos.z, a_Chunk)) { if (DoesDropOnUnsuitable()) { - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ); + a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos)); + } + else + { + a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0); } - - a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); } else { // Wake up the simulators for this block: - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, &a_Chunk); + auto absPos = a_Chunk.RelativeToAbsolute(a_RelPos); + a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(absPos, &a_Chunk); } } @@ -691,6 +582,15 @@ ColourID cBlockHandler::GetMapBaseColourID(NIBBLETYPE a_Meta) +bool cBlockHandler::ToolHasSilkTouch(const cItem * a_Tool) +{ + return ((a_Tool != nullptr) && (a_Tool->m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0)); +} + + + + + cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE aBlockType) { return ::CreateBlockHandler(aBlockType); diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index d077442c9..c0a11186e 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -50,30 +50,62 @@ public: ); /** Called by cWorld::SetBlock() after the block has been set */ - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); /** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */ virtual void OnPlacedByPlayer( cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange ); - /** Called before the player has destroyed a block */ - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ); - - /** Called before a block gets destroyed / replaced with air */ - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ); + /** Called just before the player breaks the block. + The block is still valid in the world. + By default does nothing special; descendants may provide further behavior. */ + virtual void OnPlayerBreakingBlock( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + Vector3i a_BlockPos + ) {} + + /** Called just after the player breaks the block. + The block is already dug up in the world, the original block type and meta is passed in a_OldBlockType and a_OldBlockMeta. + By default does nothing special, descendants may provide further behavior. */ + virtual void OnPlayerBrokeBlock( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) {} + + /** Called before a block gets broken (replaced with air), either by player or by natural means. + If by player, it is called after the OnPlayerBreakingBlock() callback. + By default does nothing. */ + virtual void OnBreaking( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos + ) {} + + /** Called after a block gets broken (replaced with air), either by player or by natural means. + If by player, it is called before the OnPlayerBrokeBlock() callback. + The block is already dug up in the world, the original block type and meta is passed in a_OldBlockType and a_OldBlockMeta. + By default notifies all direct neighbors via their OnNeighborChanged() callbacks. */ + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ); - /** Called when a direct neighbor of this block has been changed (The position is the block's own position, not the changing neighbor's position) + /** Called when a direct neighbor of this block has been changed. + The position is the block's own position, NOT the changed neighbor's position. a_WhichNeighbor indicates which neighbor has changed. For example, BLOCK_FACE_YP meant the neighbor above has changed. BLOCK_FACE_NONE means that it is a neighbor not directly adjacent (diagonal, etc.) */ - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) {} + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) {} /** Notifies the specified neighbor that the current block has changed. - a_NeighborXYZ coords are the coords of the neighbor - a_WhichNeighbor specifies which neighbor (relative to a_NeighborXYZ) has changed. + a_NeighborPos are the coords of the neighbor to be notified + a_WhichNeighbor specifies which neighbor (relative to a_NeighborPos) has changed. For example BLOCK_FACE_YP means that the block at {a_NeighborX, a_NeighborY + 1, a_NeighborZ} has changed. BLOCK_FACE_NONE means that it is a neighbor not directly adjacent (diagonal, etc.) */ - static void NeighborChanged(cChunkInterface & a_ChunkInterface, int a_NeighborX, int a_NeighborY, int a_NeighborZ, eBlockFace a_WhichNeighbor); + static void NeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_NeighborPos, eBlockFace a_WhichNeighbor); /** Called when the player starts digging the block. */ virtual void OnDigging(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {} @@ -86,19 +118,18 @@ public: It forces the server to send the real state of a block to the client to prevent client assuming the operation is successfull */ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) {} - /** 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 world interface for blocks that needs to access the block entity, e.g. a bed. */ - virtual void ConvertToPickups(cWorldInterface & a_WorldInterface, 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 - @param a_DropVerbatim Calls ConvertToVerbatimPickups() instead of its counterpart, meaning the block itself is dropped by default (due to a speical tool or enchantment) - */ - virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop = true); + /** Returns the pickups that would result if the block was mined by a_Digger using a_Tool. + Doesn't do any actual block change / mining, only calculates the pickups. + a_BlockEntity is the block entity present at the block, if any, nullptr if none. + a_Digger is the entity that caused the conversion, usually the player digging. + a_Tool is the tool used for the digging. + The default implementation drops a single item created from m_BlockType and the current meta. */ + virtual cItems ConvertToPickups( + NIBBLETYPE a_BlockMeta, + cBlockEntity * a_BlockEntity, + const cEntity * a_Digger = nullptr, + const cItem * a_Tool = nullptr + ); /** Checks if the block can stay at the specified relative coords in the chunk */ virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk); @@ -138,9 +169,13 @@ public: virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta); /** Called when one of the neighbors gets set; equivalent to MC block update. - By default drops if position no more suitable (CanBeAt(), DoesDropOnUnsuitable(), Drop()), - and wakes up all simulators on the block. */ - virtual void Check(cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk); + By default drops (DropBlockAsPickup() / SetBlock()) if the position is no longer suitable (CanBeAt(), DoesDropOnUnsuitable()), + otherwise wakes up all simulators on the block. */ + virtual void Check( + cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk + ); /** Returns the base colour ID of the block, as will be represented on a map, as per documentation: https://minecraft.gamepedia.com/Map_item_format */ virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta); @@ -165,6 +200,11 @@ public: Returns block meta following rotation */ virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) { return a_Meta; } + /** Returns true if the specified tool is valid and has a non-zero silk-touch enchantment. + Helper used in many ConvertToPickups() implementations. */ + static bool ToolHasSilkTouch(const cItem * a_Tool); + + protected: BLOCKTYPE m_BlockType; diff --git a/src/Blocks/BlockHopper.h b/src/Blocks/BlockHopper.h index d855ed0a4..da2f7c6e1 100644 --- a/src/Blocks/BlockHopper.h +++ b/src/Blocks/BlockHopper.h @@ -3,19 +3,26 @@ // Declares the cBlockHopperHandler class representing the handler for the Hopper block -#include "MetaRotator.h" +#include "Mixins.h" class cBlockHopperHandler : - public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> + public cMetaRotator<cContainerEntityHandler<cBlockEntityHandler>, 0x07, 0x02, 0x05, 0x03, 0x04> { + using super = cMetaRotator<cContainerEntityHandler<cBlockEntityHandler>, 0x07, 0x02, 0x05, 0x03, 0x04>; + public: - cBlockHopperHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) + + cBlockHopperHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -39,6 +46,10 @@ public: return true; } + + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override { // Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000 @@ -53,11 +64,9 @@ public: return a_Meta; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to 0 - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { diff --git a/src/Blocks/BlockIce.h b/src/Blocks/BlockIce.h index 845bb423b..672288ca3 100644 --- a/src/Blocks/BlockIce.h +++ b/src/Blocks/BlockIce.h @@ -10,37 +10,58 @@ class cBlockIceHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockIceHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockIceHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // No pickups + // Only drop self when using silk-touch: + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(m_BlockType); + } + else + { + return {}; + } } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override + + + + + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override { - if (a_Player.IsGameModeCreative() || (a_BlockY <= 0)) + // If there's a solid block or a liquid underneath, convert to water, rather than air + if (a_BlockPos.y <= 0) { return; } - - cEnchantments Enchantments = a_Player.GetInventory().GetEquippedItem().m_Enchantments; - if (Enchantments.GetLevel(cEnchantments::enchSilkTouch) == 0) + auto blockTypeBelow = a_ChunkInterface.GetBlock(a_BlockPos.addedY(-1)); + if (cBlockInfo::FullyOccupiesVoxel(blockTypeBelow) || IsBlockLiquid(blockTypeBelow)) { - BLOCKTYPE BlockBelow = a_ChunkInterface.GetBlock({a_BlockX, a_BlockY - 1, a_BlockZ}); - if (!cBlockInfo::FullyOccupiesVoxel(BlockBelow) && !IsBlockLiquid(BlockBelow)) - { - return; - } - - a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WATER, 0); + a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_WATER, 0); } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockLadder.h b/src/Blocks/BlockLadder.h index 29c0cf2b7..90e2d8304 100644 --- a/src/Blocks/BlockLadder.h +++ b/src/Blocks/BlockLadder.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "ClearMetaOnDrop.h" +#include "Mixins.h" @@ -11,13 +11,19 @@ class cBlockLadderHandler : public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04> > { - typedef cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04> > super; + using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>; + public: - cBlockLadderHandler(BLOCKTYPE a_BlockType) - : super(a_BlockType) + + cBlockLadderHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -40,10 +46,9 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - a_Pickups.Add(m_BlockType, 1, 0); // Reset meta - } + + + static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) { @@ -63,6 +68,10 @@ public: UNREACHABLE("Unsupported block face"); } + + + + static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData) { switch (a_MetaData) @@ -75,6 +84,10 @@ public: } } + + + + /** Finds a suitable Direction for the Ladder. Returns BLOCK_FACE_BOTTOM on failure */ static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) { @@ -89,6 +102,10 @@ public: return BLOCK_FACE_BOTTOM; } + + + + static bool LadderCanBePlacedAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) { if ((a_BlockFace == BLOCK_FACE_BOTTOM) || (a_BlockFace == BLOCK_FACE_TOP)) @@ -101,6 +118,10 @@ public: return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ})); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { // TODO: Use AdjustCoordsByMeta(), then cChunk::UnboundedRelGetBlock() and finally some comparison @@ -110,6 +131,10 @@ public: return LadderCanBePlacedAt(a_ChunkInterface, BlockX, a_RelY, BlockZ, BlockFace); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index c1840c474..065c5ec19 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -36,13 +36,25 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - auto & rand = GetRandomProvider(); + // If breaking with shears, drop self: + if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS)) + { + return cItem(m_BlockType, a_BlockMeta & 0x03); + } + // There is a chance to drop a sapling that varies depending on the type of leaf broken. + // Note: It is possible (though very rare) for a single leaves block to drop both a sapling and an apple // TODO: Take into account fortune for sapling drops. double chance = 0.0; + auto & rand = GetRandomProvider(); + cItems res; if ((m_BlockType == E_BLOCK_LEAVES) && ((a_BlockMeta & 0x03) == E_META_LEAVES_JUNGLE)) { // Jungle leaves have a 2.5% chance of dropping a sapling. @@ -55,12 +67,10 @@ public: } if (rand.RandBool(chance)) { - a_Pickups.push_back( - cItem( - E_BLOCK_SAPLING, - 1, - (m_BlockType == E_BLOCK_LEAVES) ? (a_BlockMeta & 0x03) : static_cast<short>(4 + (a_BlockMeta & 0x01)) - ) + res.Add( + E_BLOCK_SAPLING, + 1, + (m_BlockType == E_BLOCK_LEAVES) ? (a_BlockMeta & 0x03) : static_cast<short>(4 + (a_BlockMeta & 0x01)) ); } @@ -69,22 +79,31 @@ public: { if (rand.RandBool(0.005)) { - a_Pickups.push_back(cItem(E_ITEM_RED_APPLE, 1, 0)); + res.Add(E_ITEM_RED_APPLE, 1, 0); } } + return res; } - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override + + + + + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); + auto meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); - // Set 0x8 bit so this block gets checked for decay: - if ((Meta & 0x08) == 0) + // Set bit 0x08, so this block gets checked for decay: + if ((meta & 0x08) == 0) { - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x8, true, false); + a_ChunkInterface.SetBlockMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, meta | 0x8, true, false); } } + + + + virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); @@ -119,15 +138,18 @@ public: if (HasNearLog(Area, BlockX, a_RelY, BlockZ)) { // Wood found, the leaves stay; unset the check bit - a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta ^ 0x8, true, false); + a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta ^ 0x08, true, false); return; } // Decay the leaves: - DropBlock(a_ChunkInterface, a_WorldInterface, a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ); - a_ChunkInterface.DigBlock(a_WorldInterface, BlockX, a_RelY, BlockZ); + a_ChunkInterface.DropBlockAsPickups({BlockX, a_RelY, BlockZ}); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 6cb80222e..e4b181a24 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -2,21 +2,26 @@ #include "BlockHandler.h" #include "../Chunk.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "BlockSlab.h" class cBlockLeverHandler : public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false> { - typedef cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false> super; + using super = cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>; public: + cBlockLeverHandler(BLOCKTYPE a_BlockType) : super(a_BlockType) { } + + + + 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 { Vector3i Coords(a_BlockX, a_BlockY, a_BlockZ); @@ -29,17 +34,29 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // Reset meta to 0 - a_Pickups.push_back(cItem(E_BLOCK_LEVER, 1, 0)); + // Reset meta to zero: + return cItem(E_BLOCK_LEVER, 1, 0); } + + + + virtual bool IsUseable(void) override { return true; } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -52,6 +69,10 @@ public: return true; } + + + + inline static NIBBLETYPE LeverDirectionToMetaData(eBlockFace a_Dir) { // Determine lever direction: @@ -68,6 +89,10 @@ public: UNREACHABLE("Unsupported block face"); } + + + + inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) { switch (a_Meta & 0x7) @@ -88,6 +113,10 @@ public: } } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); @@ -121,6 +150,10 @@ public: return false; } + + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override { switch (a_Meta) @@ -135,6 +168,10 @@ public: } } + + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override { switch (a_Meta) @@ -149,12 +186,20 @@ public: } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); return 0; } + + + + /** Extracts the ON bit from metadata and returns if true if it is set */ static bool IsLeverOn(NIBBLETYPE a_BlockMeta) { diff --git a/src/Blocks/BlockMelon.h b/src/Blocks/BlockMelon.h index baf3053e1..3a25a0e2d 100644 --- a/src/Blocks/BlockMelon.h +++ b/src/Blocks/BlockMelon.h @@ -10,17 +10,28 @@ class cBlockMelonHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockMelonHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockMelonHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.emplace_back(E_ITEM_MELON_SLICE, GetRandomProvider().RandInt<char>(3, 7), 0); + return cItem(E_ITEM_MELON_SLICE, GetRandomProvider().RandInt<char>(3, 7), 0); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h index 764cd7f65..cdee5c297 100644 --- a/src/Blocks/BlockMobHead.h +++ b/src/Blocks/BlockMobHead.h @@ -11,53 +11,32 @@ class cBlockMobHeadHandler : public cBlockEntityHandler { + using super = cBlockEntityHandler; + public: cBlockMobHeadHandler(BLOCKTYPE a_BlockType): - cBlockEntityHandler(a_BlockType) + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // The drop spawn is in the OnDestroyedByPlayer method - } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - if (a_Player.IsGameModeCreative()) + if ((a_BlockEntity == nullptr) || (a_BlockEntity->GetBlockType() != E_BLOCK_HEAD)) { - // No drops in creative mode - return; + return {}; } - - a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, [](cBlockEntity & a_BlockEntity) - { - if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD) - { - return false; - } - auto & MobHeadEntity = static_cast<cMobHeadEntity&>(a_BlockEntity); - - cItems Pickups; - Pickups.Add(E_ITEM_HEAD, 1, static_cast<short>(MobHeadEntity.GetType())); - auto & r1 = GetRandomProvider(); - - // Mid-block position first - double MicroX, MicroY, MicroZ; - MicroX = MobHeadEntity.GetPosX() + 0.5; - MicroY = MobHeadEntity.GetPosY() + 0.5; - MicroZ = MobHeadEntity.GetPosZ() + 0.5; - - // Add random offset second - MicroX += r1.RandReal<double>(-0.5, 0.5); - MicroZ += r1.RandReal<double>(-0.5, 0.5); - - MobHeadEntity.GetWorld()->SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ); - return false; - } - ); + auto mobHeadEntity = static_cast<cMobHeadEntity *>(a_BlockEntity); + return cItem(E_ITEM_HEAD, 1, static_cast<short>(mobHeadEntity->GetType())); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockMobSpawner.h b/src/Blocks/BlockMobSpawner.h index 7911d3398..c8a1c5696 100644 --- a/src/Blocks/BlockMobSpawner.h +++ b/src/Blocks/BlockMobSpawner.h @@ -30,22 +30,34 @@ public: } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // No pickups + return {}; } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override + + + + virtual void OnPlayerBrokeBlock( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override { - cItemHandler * Handler = a_Player.GetEquippedItem().GetHandler(); - if (a_Player.IsGameModeCreative() || !Handler->CanHarvestBlock(E_BLOCK_MOB_SPAWNER)) + auto handler = a_Player.GetEquippedItem().GetHandler(); + if (!a_Player.IsGameModeSurvival() || !handler->CanHarvestBlock(E_BLOCK_MOB_SPAWNER)) { return; } - auto & Random = GetRandomProvider(); - int Reward = 15 + Random.RandInt(14) + Random.RandInt(14); - a_WorldInterface.SpawnSplitExperienceOrbs(static_cast<double>(a_BlockX), static_cast<double>(a_BlockY + 1), static_cast<double>(a_BlockZ), Reward); + auto & random = GetRandomProvider(); + int reward = 15 + random.RandInt(14) + random.RandInt(14); + a_WorldInterface.SpawnSplitExperienceOrbs(Vector3d(0.5, 0.5, 0.5) + a_BlockPos, reward); } } ; diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h index d6b726b57..7fb397420 100644 --- a/src/Blocks/BlockMushroom.h +++ b/src/Blocks/BlockMushroom.h @@ -7,23 +7,20 @@ -class cBlockMushroomHandler : - public cBlockHandler +class cBlockMushroomHandler: + public cClearMetaOnDrop<cBlockHandler> { + using super = cClearMetaOnDrop<cBlockHandler>; + public: - cBlockMushroomHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockMushroomHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } // TODO: Add Mushroom Spread - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to 0 - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) diff --git a/src/Blocks/BlockMycelium.h b/src/Blocks/BlockMycelium.h index 1c365caa8..e91d45b98 100644 --- a/src/Blocks/BlockMycelium.h +++ b/src/Blocks/BlockMycelium.h @@ -7,22 +7,30 @@ -class cBlockMyceliumHandler : +class cBlockMyceliumHandler: public cBlockHandler { public: - cBlockMyceliumHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + cBlockMyceliumHandler(BLOCKTYPE a_BlockType): + cBlockHandler(a_BlockType) { } // TODO: Add Mycel Spread - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_BLOCK_DIRT, 1, 0)); + return cItem(E_BLOCK_DIRT, 1, 0); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h index 5732259db..6b0b394b5 100644 --- a/src/Blocks/BlockNetherWart.h +++ b/src/Blocks/BlockNetherWart.h @@ -9,30 +9,39 @@ class cBlockNetherWartHandler : - public cBlockPlant + public cBlockPlant<false> { - typedef cBlockPlant Super; + using super = cBlockPlant<false>; + public: - cBlockNetherWartHandler(BLOCKTYPE a_BlockType) - : Super(a_BlockType, false) + + cBlockNetherWartHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override - { - auto & rand = GetRandomProvider(); - if (a_Meta == 0x3) + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + if (a_BlockMeta == 0x03) { // Fully grown, drop the entire produce: - a_Pickups.emplace_back(E_ITEM_NETHER_WART, 1 + (rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2, 0); + auto & rand = GetRandomProvider(); + return cItem(E_ITEM_NETHER_WART, 1 + (rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2, 0); } else { - a_Pickups.push_back(cItem(E_ITEM_NETHER_WART)); + return cItem(E_ITEM_NETHER_WART); } } + + + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); @@ -46,12 +55,20 @@ public: } } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { // Needs to be placed on top of a Soulsand block: return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SOULSAND)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockOre.h b/src/Blocks/BlockOre.h index 0a52de3d6..70bb0515d 100644 --- a/src/Blocks/BlockOre.h +++ b/src/Blocks/BlockOre.h @@ -17,63 +17,50 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - auto & Random = GetRandomProvider(); + // If using silk-touch, drop self rather than the resource: + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(m_BlockType); + } + // TODO: Handle the Fortune enchantment here + auto & random = GetRandomProvider(); switch (m_BlockType) { - case E_BLOCK_LAPIS_ORE: - { - a_Pickups.emplace_back(E_ITEM_DYE, Random.RandInt<char>(4, 8), 4); - break; - } - case E_BLOCK_REDSTONE_ORE: - case E_BLOCK_REDSTONE_ORE_GLOWING: - { - a_Pickups.emplace_back(E_ITEM_REDSTONE_DUST, Random.RandInt<char>(4, 5), 0); - break; - } - case E_BLOCK_DIAMOND_ORE: - { - a_Pickups.push_back(cItem(E_ITEM_DIAMOND)); - break; - } - case E_BLOCK_EMERALD_ORE: - { - a_Pickups.push_back(cItem(E_ITEM_EMERALD)); - break; - } - case E_BLOCK_COAL_ORE: - { - a_Pickups.push_back(cItem(E_ITEM_COAL)); - break; - } - case E_BLOCK_NETHER_QUARTZ_ORE: - { - a_Pickups.push_back(cItem(E_ITEM_NETHER_QUARTZ)); - break; - } - case E_BLOCK_CLAY: - { - a_Pickups.push_back(cItem(E_ITEM_CLAY, 4)); - break; - } + case E_BLOCK_LAPIS_ORE: return cItem(E_ITEM_DYE, random.RandInt<char>(4, 8), 4); + case E_BLOCK_REDSTONE_ORE: return cItem(E_ITEM_REDSTONE_DUST, random.RandInt<char>(4, 5), 0); + case E_BLOCK_REDSTONE_ORE_GLOWING: return cItem(E_ITEM_REDSTONE_DUST, random.RandInt<char>(4, 5), 0); + case E_BLOCK_DIAMOND_ORE: return cItem(E_ITEM_DIAMOND); + case E_BLOCK_EMERALD_ORE: return cItem(E_ITEM_EMERALD); + case E_BLOCK_COAL_ORE: return cItem(E_ITEM_COAL); + case E_BLOCK_NETHER_QUARTZ_ORE: return cItem(E_ITEM_NETHER_QUARTZ); + case E_BLOCK_CLAY: return cItem(E_ITEM_CLAY, 4); default: { - a_Pickups.push_back(cItem(m_BlockType)); - break; + return cItem(m_BlockType); } } } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - super::OnDestroyedByPlayer(a_ChunkInterface, a_WorldInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ); - if (a_Player.IsGameModeCreative()) + + + + virtual void OnPlayerBrokeBlock( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + cPlayer & a_Player, Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override + { + if (!a_Player.IsGameModeSurvival()) { - // Don't drop XP when the player is in creative mode. + // Don't drop XP unless the player is in survival mode. return; } @@ -83,45 +70,45 @@ public: return; } - auto & Random = GetRandomProvider(); - int Reward = 0; + auto & random = GetRandomProvider(); + int reward = 0; - switch (m_BlockType) + switch (a_OldBlockType) { case E_BLOCK_NETHER_QUARTZ_ORE: case E_BLOCK_LAPIS_ORE: { // Lapis and nether quartz get 2 - 5 experience - Reward = Random.RandInt(2, 5); + reward = random.RandInt(2, 5); break; } case E_BLOCK_REDSTONE_ORE: case E_BLOCK_REDSTONE_ORE_GLOWING: { // Redstone gets 1 - 5 experience - Reward = Random.RandInt(1, 5); + reward = random.RandInt(1, 5); break; } case E_BLOCK_DIAMOND_ORE: case E_BLOCK_EMERALD_ORE: { // Diamond and emerald get 3 - 7 experience - Reward = Random.RandInt(3, 7); + reward = random.RandInt(3, 7); break; } case E_BLOCK_COAL_ORE: { // Coal gets 0 - 2 experience - Reward = Random.RandInt(2); + reward = random.RandInt(2); break; } default: break; } - if (Reward != 0) + if (reward > 0) { - a_WorldInterface.SpawnSplitExperienceOrbs(a_BlockX, a_BlockY, a_BlockZ, Reward); + a_WorldInterface.SpawnSplitExperienceOrbs(Vector3d(0.5, 0.5, 0.5) + a_BlockPos, reward); } } } ; diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index c3a90c8a5..6ebbd784d 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -16,8 +16,8 @@ -cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) +cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -25,20 +25,19 @@ cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType) -void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockPistonHandler::OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta +) { - Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ); - - NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(blockPos); // If the piston is extended, destroy the extension as well - if (IsExtended(OldMeta)) + if (IsExtended(a_OldBlockMeta)) { - // Get the position of the extension - blockPos += MetadataToOffset(OldMeta); - - if (a_ChunkInterface.GetBlock(blockPos) == E_BLOCK_PISTON_EXTENSION) + auto extPos = a_BlockPos + MetadataToOffset(a_OldBlockMeta); + if (a_ChunkInterface.GetBlock(extPos) == E_BLOCK_PISTON_EXTENSION) { - a_ChunkInterface.SetBlock(blockPos.x, blockPos.y, blockPos.z, E_BLOCK_AIR, 0); + a_ChunkInterface.DropBlockAsPickups(extPos); } } } @@ -47,16 +46,6 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld -void cBlockPistonHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) -{ - // Returning Piston Item without Direction-Metavalue - a_Pickups.push_back(cItem(m_BlockType, 1)); -} - - - - - bool cBlockPistonHandler::GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -106,7 +95,7 @@ void cBlockPistonHandler::PushBlocks( std::vector<Vector3i> sortedBlocks(a_BlocksToPush.begin(), a_BlocksToPush.end()); std::sort(sortedBlocks.begin(), sortedBlocks.end(), [a_PushDir](const Vector3i & a, const Vector3i & b) { - return a.Dot(a_PushDir) > b.Dot(a_PushDir); + return (a.Dot(a_PushDir) > b.Dot(a_PushDir)); }); // Move every block @@ -118,17 +107,8 @@ void cBlockPistonHandler::PushBlocks( if (cBlockInfo::IsPistonBreakable(moveBlock)) { - // Block is breakable, drop it - cBlockHandler * Handler = BlockHandler(moveBlock); - if (Handler->DoesDropOnUnsuitable()) - { - cChunkInterface ChunkInterface(a_World.GetChunkMap()); - cBlockInServerPluginInterface PluginInterface(a_World); - Handler->DropBlock(ChunkInterface, a_World, PluginInterface, nullptr, - moveBlockPos.x, moveBlockPos.y, moveBlockPos.z - ); - } - a_World.SetBlock(moveBlockPos.x, moveBlockPos.y, moveBlockPos.z, E_BLOCK_AIR, 0); + // Block is breakable, drop it: + a_World.DropBlockAsPickups(moveBlockPos, nullptr, nullptr); } else { @@ -357,26 +337,17 @@ cBlockPistonHeadHandler::cBlockPistonHeadHandler(void) : -void cBlockPistonHeadHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockPistonHeadHandler::OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta +) { - Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ); - - // Get the base of the piston - NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(blockPos); - blockPos -= cBlockPistonHandler::MetadataToOffset(OldMeta); - - BLOCKTYPE Block = a_ChunkInterface.GetBlock(blockPos); - if ((Block == E_BLOCK_STICKY_PISTON) || (Block == E_BLOCK_PISTON)) + // Drop the base of the piston: + auto basePos = a_BlockPos - cBlockPistonHandler::MetadataToOffset(a_OldBlockMeta); + if (cChunkDef::IsValidHeight(basePos.y)) { - a_ChunkInterface.DigBlock(a_WorldInterface, blockPos.x, blockPos.y, blockPos.z); - if (a_Player.IsGameModeCreative()) - { - return; // No pickups if creative - } - - cItems Pickups; - Pickups.push_back(cItem(Block, 1)); - a_WorldInterface.SpawnItemPickups(Pickups, blockPos.x + 0.5, blockPos.y + 0.5, blockPos.z + 0.5); + a_ChunkInterface.DropBlockAsPickups(basePos); } } diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index e604cd38e..c9e920f5b 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -2,22 +2,34 @@ #pragma once #include "BlockHandler.h" - #include <unordered_set> +#include "Mixins.h" +#include "../Item.h" + + +// fwd: class cWorld; -class cBlockPistonHandler : - public cBlockHandler + + + +class cBlockPistonHandler: + public cClearMetaOnDrop<cBlockHandler> { + using super = cClearMetaOnDrop<cBlockHandler>; + public: - cBlockPistonHandler(BLOCKTYPE a_BlockType); - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override; + cBlockPistonHandler(BLOCKTYPE a_BlockType); - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override; + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override; virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, @@ -174,23 +186,24 @@ private: -class cBlockPistonHeadHandler : +class cBlockPistonHeadHandler: public cBlockHandler { - typedef cBlockHandler super; + using super = cBlockHandler; public: cBlockPistonHeadHandler(void); - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override; - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // No pickups // Also with 1.7, the item forms of these technical blocks have been removed, so giving someone this will crash their client... + return {}; } } ; - - - - diff --git a/src/Blocks/BlockPlant.h b/src/Blocks/BlockPlant.h index bab34f798..02092fc38 100644 --- a/src/Blocks/BlockPlant.h +++ b/src/Blocks/BlockPlant.h @@ -1,25 +1,30 @@ -// BlockPlant.h - -// Base class for any growing block - +#pragma once +#include "BlockHandler.h" -#pragma once -#include "BlockHandler.h" -class cBlockPlant : public cBlockHandler +/** Base class for plants that use light values to decide whether to grow or not. */ +template <bool NeedsLightToGrow> +class cBlockPlant: + public cBlockHandler { - typedef cBlockHandler Super; - bool m_NeedLightToGrow; + using super = cBlockHandler; + public: - cBlockPlant(BLOCKTYPE a_BlockType, bool a_LightToGrow) - : Super(a_BlockType), m_NeedLightToGrow(a_LightToGrow){} + + cBlockPlant(BLOCKTYPE a_BlockType): + super(a_BlockType) + { + } + protected: + + /** The action the plant can take on an update. */ enum PlantAction { paDeath, @@ -27,6 +32,10 @@ protected: paStay }; + + + + /** Checks whether there is enough light for the plant to grow. If the plant doesn't require light to grow, then it returns paGrowth. If the plant requires light to grow and there is enough light, it returns paGrowth. @@ -37,34 +46,37 @@ protected: { // If the plant requires light to grow, check to see if there is enough light // Otherwise, return true - if (m_NeedLightToGrow) + if (!NeedsLightToGrow) { - NIBBLETYPE Blocklight = a_Chunk.GetBlockLight(a_RelX, a_RelY, a_RelZ); - NIBBLETYPE SkyLight = a_Chunk.GetSkyLight (a_RelX, a_RelY, a_RelZ); - NIBBLETYPE Light = a_Chunk.GetTimeAlteredLight(SkyLight); - - // If the amount of light provided by blocks is greater than the sky light, use it instead - if (Blocklight > Light) - { - Light = Blocklight; - } + return paGrowth; + } + NIBBLETYPE Blocklight = a_Chunk.GetBlockLight(a_RelX, a_RelY, a_RelZ); + NIBBLETYPE SkyLight = a_Chunk.GetSkyLight (a_RelX, a_RelY, a_RelZ); + NIBBLETYPE Light = a_Chunk.GetTimeAlteredLight(SkyLight); - // Based on light levels, decide between growth, stay and death: - if (Light > 8) - { - return paGrowth; - } - else if ((Blocklight < 9) && (SkyLight < 9)) - { - return paDeath; - } + // If the amount of light provided by blocks is greater than the sky light, use it instead + if (Blocklight > Light) + { + Light = Blocklight; + } - return paStay; + // Based on light levels, decide between growth, stay and death: + if (Light > 8) + { + return paGrowth; + } + else if ((Blocklight < 9) && (SkyLight < 9)) + { + return paDeath; } - return paGrowth; + return paStay; } + + + + /** Checks whether a plant can grow grow, based on what is returned from cBlockPlant::HasEnoughLight and a random check based on what is returned from cBlockPlant::GetGrowthChance. Can return three values. @@ -84,6 +96,10 @@ protected: return Action; } + + + + /** Generates a int value between 4 and 25 based on surrounding blocks that affect how quickly the plant grows. The higher the value, the less likely the plant is to grow */ virtual int GetGrowthChance(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) diff --git a/src/Blocks/BlockPluginInterface.h b/src/Blocks/BlockPluginInterface.h index d97927b36..087e86412 100644 --- a/src/Blocks/BlockPluginInterface.h +++ b/src/Blocks/BlockPluginInterface.h @@ -30,7 +30,6 @@ public: virtual ~cBlockPluginInterface() {} virtual bool CallHookBlockSpread(int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0; - virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0; virtual bool CallHookPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual bool CallHookPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; }; diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 6cebcbd37..852a231b6 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -32,11 +32,20 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // No pickups + return {}; } + + + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { if (GetRandomProvider().RandBool(0.9995)) diff --git a/src/Blocks/BlockPressurePlate.h b/src/Blocks/BlockPressurePlate.h index 7fb7585f1..7067bd2e5 100644 --- a/src/Blocks/BlockPressurePlate.h +++ b/src/Blocks/BlockPressurePlate.h @@ -7,18 +7,15 @@ class cBlockPressurePlateHandler : - public cBlockHandler + public cClearMetaOnDrop<cBlockHandler> { + using super = cClearMetaOnDrop<cBlockHandler>; + public: - cBlockPressurePlateHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockPressurePlateHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - // Reset meta to zero - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h index 9cf3c895c..29834900f 100644 --- a/src/Blocks/BlockPumpkin.h +++ b/src/Blocks/BlockPumpkin.h @@ -1,7 +1,7 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index d9bb15913..6b9ddcdd5 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -17,13 +17,14 @@ enum ENUM_PURE class cBlockRailHandler : - public cBlockHandler + public cClearMetaOnDrop<cBlockHandler> { - typedef cBlockHandler super; + using super = cClearMetaOnDrop<cBlockHandler>; public: - cBlockRailHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockRailHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -46,51 +47,69 @@ public: ); } - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + + + + + virtual void OnPlaced( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta + ) override { - super::OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); - - // Alert diagonal rails - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1, BLOCK_FACE_NONE); + super::OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_BlockType, a_BlockMeta); + + // Alert diagonal rails: + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE); } - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override + + + + + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override { - super::OnDestroyed(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ); - - // Alert diagonal rails - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1, BLOCK_FACE_NONE); + super::OnBroken(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_OldBlockType, a_OldBlockMeta); + + // Alert diagonal rails: + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE); } - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override + + + + + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override { - Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ); - auto Meta = a_ChunkInterface.GetBlockMeta(Pos); - auto NewMeta = FindMeta(a_ChunkInterface, Pos); - if (IsUnstable(a_ChunkInterface, Pos) && (Meta != NewMeta)) + auto meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); + auto newMeta = FindMeta(a_ChunkInterface, a_BlockPos); + if (IsUnstable(a_ChunkInterface, a_BlockPos) && (meta != newMeta)) { - a_ChunkInterface.FastSetBlock(Pos, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? NewMeta : NewMeta | (Meta & 0x08)); + a_ChunkInterface.FastSetBlock(a_BlockPos, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? newMeta : newMeta | (meta & 0x08)); } } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - super::ConvertToPickups(a_Pickups, 0); - } + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { diff --git a/src/Blocks/BlockRedstone.h b/src/Blocks/BlockRedstone.h index 225f1cc75..d01a40631 100644 --- a/src/Blocks/BlockRedstone.h +++ b/src/Blocks/BlockRedstone.h @@ -9,11 +9,14 @@ class cBlockRedstoneHandler : - public cBlockHandler + public cClearMetaOnDrop<cBlockHandler> { + using super = cClearMetaOnDrop<cBlockHandler>; + public: - cBlockRedstoneHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockRedstoneHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -43,12 +46,6 @@ public: return false; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to zero - a_Pickups.push_back(cItem(E_ITEM_REDSTONE_DUST, 1, 0)); - } - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockRedstoneLamp.h b/src/Blocks/BlockRedstoneLamp.h index 5ac98de87..576467c12 100644 --- a/src/Blocks/BlockRedstoneLamp.h +++ b/src/Blocks/BlockRedstoneLamp.h @@ -7,20 +7,29 @@ -class cBlockRedstoneLampHandler : +class cBlockRedstoneLampHandler: public cBlockHandler { public: - cBlockRedstoneLampHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + cBlockRedstoneLampHandler(BLOCKTYPE a_BlockType): + cBlockHandler(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_BLOCK_REDSTONE_LAMP_OFF, 1, 0)); + // Always drop the Off variant: + return(cItem(E_BLOCK_REDSTONE_LAMP_OFF, 1, 0)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 455ef1171..6e749bd57 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -2,19 +2,24 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "ChunkInterface.h" #include "BlockSlab.h" #include "../Chunk.h" -class cBlockRedstoneRepeaterHandler : - public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true> + + +class cBlockRedstoneRepeaterHandler: + public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>> { + using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>>; + public: - cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType) + + cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -42,12 +47,6 @@ public: a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to zero - a_Pickups.push_back(cItem(E_ITEM_REDSTONE_REPEATER, 1, 0)); - } - virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockRedstoneTorch.h b/src/Blocks/BlockRedstoneTorch.h index 11a42bf9f..3f065b1cb 100644 --- a/src/Blocks/BlockRedstoneTorch.h +++ b/src/Blocks/BlockRedstoneTorch.h @@ -10,18 +10,29 @@ class cBlockRedstoneTorchHandler : public cBlockTorchHandler { + using super = cBlockTorchHandler; + public: - cBlockRedstoneTorchHandler(BLOCKTYPE a_BlockType) - : cBlockTorchHandler(a_BlockType) + + cBlockRedstoneTorchHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // Always drop the ON torch, meta 0 - a_Pickups.push_back(cItem(E_BLOCK_REDSTONE_TORCH_ON, 1, 0)); + return cItem(E_BLOCK_REDSTONE_TORCH_ON, 1, 0); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockSapling.h b/src/Blocks/BlockSapling.h index 4133c5b80..f3cefd722 100644 --- a/src/Blocks/BlockSapling.h +++ b/src/Blocks/BlockSapling.h @@ -11,18 +11,29 @@ class cBlockSaplingHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockSaplingHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockSaplingHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // Only the first 2 bits contain the display information and the 4th bit is for the growth indicator, but, we use 0x07 for forward compatibility - a_Pickups.push_back(cItem(E_BLOCK_SAPLING, 1, a_BlockMeta & 0x07)); + // The low 3 bits store the sapling type; bit 0x08 is the growth timer (not used in pickups) + return cItem(m_BlockType, 1, a_BlockMeta & 0x07); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)); diff --git a/src/Blocks/BlockSeaLantern.h b/src/Blocks/BlockSeaLantern.h index 691e7de10..0d7c62b94 100644 --- a/src/Blocks/BlockSeaLantern.h +++ b/src/Blocks/BlockSeaLantern.h @@ -10,17 +10,24 @@ class cBlockSeaLanternHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockSeaLanternHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockSeaLanternHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // Reset meta to 0 - a_Pickups.emplace_back(E_ITEM_PRISMARINE_CRYSTALS, GetRandomProvider().RandInt<char>(2, 3), 0); + // TODO: Handle the Fortune enchantment + return cItem(E_ITEM_PRISMARINE_CRYSTALS, GetRandomProvider().RandInt<char>(2, 3), 0); } } ; diff --git a/src/Blocks/BlockSideways.h b/src/Blocks/BlockSideways.h index 5bc7874b4..017dc30e0 100644 --- a/src/Blocks/BlockSideways.h +++ b/src/Blocks/BlockSideways.h @@ -7,15 +7,25 @@ -class cBlockSidewaysHandler : public cBlockHandler +/** Handler for blocks that have 3 orientations (hay bale, log), specified by the upper 2 bits in meta. +Handles setting the correct orientation on placement. +Additionally supports the metadata specifying block sub-type in its lower 2 bits. */ +class cBlockSidewaysHandler: + public cBlockHandler { + using super = cBlockHandler; + public: - cBlockSidewaysHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockSidewaysHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -30,12 +40,19 @@ public: } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.Add(m_BlockType, 1, a_BlockMeta & 0x3); // Reset meta + // Reset the orientation part of meta, keep the sub-type part of meta + return cItem(m_BlockType, 1, a_BlockMeta & 0x03); } + + + inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_Meta) { switch (a_BlockFace) diff --git a/src/Blocks/BlockSignPost.h b/src/Blocks/BlockSignPost.h index fe170a675..b5ccfe5d7 100644 --- a/src/Blocks/BlockSignPost.h +++ b/src/Blocks/BlockSignPost.h @@ -8,22 +8,30 @@ -class cBlockSignPostHandler : +class cBlockSignPostHandler: public cBlockHandler { - typedef cBlockHandler super; + using super = cBlockHandler; public: - cBlockSignPostHandler(BLOCKTYPE a_BlockType) : + + cBlockSignPostHandler(BLOCKTYPE a_BlockType): super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_SIGN, 1, 0)); + return cItem(E_ITEM_SIGN, 1, 0); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index 46e0a8244..a136cd6e0 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -18,17 +18,29 @@ class cBlockSlabHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockSlabHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockSlabHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(m_BlockType, 1, a_BlockMeta & 0x7)); + // Reset the "top half" flag: + return cItem(m_BlockType, 1, a_BlockMeta & 0x07); } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -84,6 +96,10 @@ public: return true; } + + + + /** Returns true if the specified blocktype is one of the slabs handled by this handler */ static bool IsAnySlabType(BLOCKTYPE a_BlockType) { @@ -95,6 +111,10 @@ public: ); } + + + + virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override { if ((a_BlockFace == BLOCK_FACE_NONE) || (a_Player.GetEquippedItem().m_ItemType != static_cast<short>(m_BlockType))) @@ -106,6 +126,10 @@ public: a_Player.GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); } + + + + /** Converts the single-slab blocktype to its equivalent double-slab blocktype */ static BLOCKTYPE GetDoubleSlabType(BLOCKTYPE a_SingleSlabBlockType) { @@ -120,12 +144,20 @@ public: return E_BLOCK_AIR; } + + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override { // Toggle the 4th bit - up / down: return (a_Meta ^ 0x08); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { a_Meta &= 0x7; @@ -184,6 +216,10 @@ public: } } + + + + virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) override { if (a_BlockMeta & 0x8) // top half @@ -201,31 +237,46 @@ public: class cBlockDoubleSlabHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockDoubleSlabHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockDoubleSlabHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { BLOCKTYPE Block = GetSingleSlabType(m_BlockType); - a_Pickups.push_back(cItem(Block, 2, a_BlockMeta & 0x7)); + return cItem(Block, 2, a_BlockMeta & 0x7); } + + + + inline static BLOCKTYPE GetSingleSlabType(BLOCKTYPE a_BlockType) { switch (a_BlockType) { - case E_BLOCK_DOUBLE_STONE_SLAB: return E_BLOCK_STONE_SLAB; - case E_BLOCK_DOUBLE_WOODEN_SLAB: return E_BLOCK_WOODEN_SLAB; + case E_BLOCK_DOUBLE_STONE_SLAB: return E_BLOCK_STONE_SLAB; + case E_BLOCK_DOUBLE_WOODEN_SLAB: return E_BLOCK_WOODEN_SLAB; case E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB: return E_BLOCK_RED_SANDSTONE_SLAB; - case E_BLOCK_PURPUR_DOUBLE_SLAB: return E_BLOCK_PURPUR_SLAB; + case E_BLOCK_PURPUR_DOUBLE_SLAB: return E_BLOCK_PURPUR_SLAB; } ASSERT(!"Unhandled double slab type!"); return a_BlockType; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { // For doule slabs, the meta values are the same. Only the meaning of the 4th bit changes, but that's ignored in the below handler diff --git a/src/Blocks/BlockSlime.h b/src/Blocks/BlockSlime.h index 8302c0bf4..bbf28fa16 100644 --- a/src/Blocks/BlockSlime.h +++ b/src/Blocks/BlockSlime.h @@ -6,20 +6,22 @@ -class cBlockSlimeHandler : - public cBlockHandler +class cBlockSlimeHandler: + public cClearMetaOnDrop<cBlockHandler> { + using super = cClearMetaOnDrop<cBlockHandler>; + public: - cBlockSlimeHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockSlimeHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockSnow.h b/src/Blocks/BlockSnow.h index 8e4083b0e..4972e61fe 100644 --- a/src/Blocks/BlockSnow.h +++ b/src/Blocks/BlockSnow.h @@ -70,11 +70,33 @@ public: return false; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_SNOWBALL, 1, 0)); + // No drop unless dug up with a shovel + if ((a_Tool == nullptr) || !ItemCategory::IsShovel(a_Tool->m_ItemType)) + { + return {}; + } + + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(m_BlockType, 1, 0); + } + else + { + // Drop as many snowballs as there were "layers" of snow: + return cItem(E_ITEM_SNOWBALL, 1 + (a_BlockMeta & 0x07), 0); + } } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY > 0) diff --git a/src/Blocks/BlockSponge.h b/src/Blocks/BlockSponge.h index 24bc25388..7df5d69ff 100644 --- a/src/Blocks/BlockSponge.h +++ b/src/Blocks/BlockSponge.h @@ -10,9 +10,12 @@ class cBlockSpongeHandler : public cBlockHandler { + using super = cBlockHandler; + public: + cBlockSpongeHandler(BLOCKTYPE a_BlockType): - cBlockHandler(a_BlockType) + super(a_BlockType) { } @@ -20,13 +23,17 @@ public: - virtual void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override + virtual void Check( + cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk + ) override { - if (GetSoaked(Vector3i(a_RelX, a_RelY, a_RelZ), a_Chunk)) + if (GetSoaked(a_RelPos, a_Chunk)) { return; } - cBlockHandler::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk); + super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk); } @@ -115,7 +122,7 @@ public: } Seeds.pop(); } - a_Chunk.SetBlock(a_Rel.x, a_Rel.y, a_Rel.z, E_BLOCK_SPONGE, E_META_SPONGE_WET); + a_Chunk.SetBlock(a_Rel, E_BLOCK_SPONGE, E_META_SPONGE_WET); return true; } diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index 6cd05df19..4263a5b13 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -2,17 +2,20 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockStairsHandler : - public cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true> + public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>> { + using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>>; + public: - cBlockStairsHandler(BLOCKTYPE a_BlockType) : - cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>(a_BlockType) + + cBlockStairsHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -53,12 +56,6 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to zero - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } - static NIBBLETYPE RotationToMetaData(double a_Rotation) { a_Rotation += 90 + 45; // So its not aligned with axis diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h index 659df558f..132526b93 100644 --- a/src/Blocks/BlockStems.h +++ b/src/Blocks/BlockStems.h @@ -8,21 +8,31 @@ class cBlockStemsHandler : - public cBlockPlant + public cBlockPlant<true> { - typedef cBlockPlant Super; + using super = cBlockPlant<true>; + public: - cBlockStemsHandler(BLOCKTYPE a_BlockType) - : Super(a_BlockType, true) + + cBlockStemsHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - short ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS; - a_Pickups.push_back(cItem(ItemType, 1, 0)); + auto itemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS; + return cItem(itemType, 1, 0); } + + + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { auto Action = CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); diff --git a/src/Blocks/BlockStone.h b/src/Blocks/BlockStone.h index e1522a2a2..f691d4452 100644 --- a/src/Blocks/BlockStone.h +++ b/src/Blocks/BlockStone.h @@ -6,25 +6,39 @@ -class cBlockStoneHandler : +class cBlockStoneHandler: public cBlockHandler { + using super = cBlockHandler; + public: - cBlockStoneHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockStoneHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - if (a_BlockMeta == E_META_STONE_STONE) + // Convert stone to cobblestone, unless using silk-touch: + if ( + (a_BlockMeta == E_META_STONE_STONE) && + !ToolHasSilkTouch(a_Tool) + ) { - a_Pickups.push_back(cItem(E_BLOCK_COBBLESTONE, 1, 0)); - return; + return cItem(E_BLOCK_COBBLESTONE, 1, 0); } - a_Pickups.push_back(cItem(E_BLOCK_STONE, 1, a_BlockMeta)); + return cItem(m_BlockType, 1, a_BlockMeta); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockSugarcane.h b/src/Blocks/BlockSugarcane.h index 1322987f5..622f82138 100644 --- a/src/Blocks/BlockSugarcane.h +++ b/src/Blocks/BlockSugarcane.h @@ -8,20 +8,30 @@ class cBlockSugarcaneHandler : - public cBlockPlant + public cBlockPlant<false> { - typedef cBlockPlant Super; + using super = cBlockPlant<false>; + public: - cBlockSugarcaneHandler(BLOCKTYPE a_BlockType) - : Super(a_BlockType, false) + + cBlockSugarcaneHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_SUGARCANE, 1, 0)); + return cItem(E_ITEM_SUGARCANE, 1, 0); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) @@ -86,6 +96,7 @@ public: return 7; } + protected: virtual PlantAction CanGrow(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override @@ -93,7 +104,7 @@ protected: auto Action = paStay; if (((a_RelY + 1) < cChunkDef::Height) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR)) { - Action = Super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); + Action = super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); } return Action; diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h index aa369f0cf..c4b7194b5 100644 --- a/src/Blocks/BlockTallGrass.h +++ b/src/Blocks/BlockTallGrass.h @@ -8,64 +8,51 @@ -class cBlockTallGrassHandler : +class cBlockTallGrassHandler: public cBlockHandler { - typedef cBlockHandler super; + using super = cBlockHandler; + public: - cBlockTallGrassHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockTallGrassHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // Drop seeds, sometimes - if (GetRandomProvider().RandBool(0.125)) + // If using shears, drop self: + if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS)) { - a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1, 0)); + return cItem(m_BlockType, 1, a_BlockMeta); } - } - virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override - { - if (a_CanDrop && (a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_ItemType == E_ITEM_SHEARS)) + // Drop seeds, sometimes: + if (GetRandomProvider().RandBool(0.125)) { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); - cItems Drops; - Drops.Add(m_BlockType, 1, Meta); - - // Allow plugins to modify the pickups: - a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Drops); - - // Spawn the pickups: - if (!Drops.empty()) - { - auto & r1 = GetRandomProvider(); - - // Mid-block position first - double MicroX, MicroY, MicroZ; - MicroX = a_BlockX + 0.5; - MicroY = a_BlockY + 0.5; - MicroZ = a_BlockZ + 0.5; - - // Add random offset second - MicroX += r1.RandReal<double>(-0.5, 0.5); - MicroZ += r1.RandReal<double>(-0.5, 0.5); - - a_WorldInterface.SpawnItemPickups(Drops, MicroX, MicroY, MicroZ); - } - return; + return cItem(E_ITEM_SEEDS); } - - super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop); + return {}; } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) @@ -77,6 +64,10 @@ public: return IsBlockTypeOfDirt(BelowBlock); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index 8f95fa344..c5b06b18a 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -3,17 +3,20 @@ #include "BlockHandler.h" #include "../Chunk.h" #include "ChunkInterface.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockTorchHandler : - public cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2> + public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>> { + using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>>; + public: - cBlockTorchHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>(a_BlockType) + + cBlockTorchHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -182,12 +185,6 @@ public: return CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face); } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Always drop meta = 0 - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h index 8fdae6028..e5361706c 100644 --- a/src/Blocks/BlockTrapdoor.h +++ b/src/Blocks/BlockTrapdoor.h @@ -2,32 +2,36 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "../EffectID.h" class cBlockTrapdoorHandler : - public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false> + public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>> { + using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>>; + public: - cBlockTrapdoorHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockTrapdoorHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - // Reset meta to zero - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } + + + virtual bool IsUseable(void) override { return true; } + + + + 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 { if (m_BlockType == E_BLOCK_IRON_TRAPDOOR) diff --git a/src/Blocks/BlockTripwire.h b/src/Blocks/BlockTripwire.h index 19a9c4384..dbf21e318 100644 --- a/src/Blocks/BlockTripwire.h +++ b/src/Blocks/BlockTripwire.h @@ -10,17 +10,28 @@ class cBlockTripwireHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockTripwireHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockTripwireHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_STRING, 1, 0)); + return cItem(E_ITEM_STRING, 1, 0); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockTripwireHook.h b/src/Blocks/BlockTripwireHook.h index d544fff86..8537f99ce 100644 --- a/src/Blocks/BlockTripwireHook.h +++ b/src/Blocks/BlockTripwireHook.h @@ -1,21 +1,28 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockTripwireHookHandler : - public cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01> + public cMetaRotator<cClearMetaOnDrop<cBlockHandler>, 0x03, 0x02, 0x03, 0x00, 0x01> { + using super = cMetaRotator<cClearMetaOnDrop<cBlockHandler>, 0x03, 0x02, 0x03, 0x00, 0x01>; + public: - cBlockTripwireHookHandler(BLOCKTYPE a_BlockType) - : cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01>(a_BlockType) + + cBlockTripwireHookHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -29,6 +36,10 @@ public: return true; } + + + + inline static NIBBLETYPE DirectionToMetadata(eBlockFace a_Direction) { switch (a_Direction) @@ -48,6 +59,10 @@ public: UNREACHABLE("Unsupported block face"); } + + + + inline static eBlockFace MetadataToDirection(NIBBLETYPE a_Meta) { switch (a_Meta & 0x03) @@ -60,11 +75,9 @@ public: } } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to zero - a_Pickups.push_back(cItem(E_BLOCK_TRIPWIRE_HOOK, 1, 0)); - } + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { @@ -78,6 +91,10 @@ public: return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index f5716c58a..53224a5db 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -9,12 +9,19 @@ class cBlockVineHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockVineHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockVineHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -38,12 +45,24 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // Reset meta to zero - a_Pickups.push_back(cItem(E_BLOCK_VINES, 1, 0)); + // Only drops self when using shears, otherwise drops nothing: + if ((a_Tool == nullptr) || (a_Tool->m_ItemType != E_ITEM_SHEARS)) + { + return {}; + } + return cItem(E_BLOCK_VINES, 1, 0); } + + + + static NIBBLETYPE DirectionToMetaData(char a_BlockFace) { switch (a_BlockFace) @@ -56,6 +75,10 @@ public: } } + + + + static char MetaDataToDirection(NIBBLETYPE a_MetaData) { switch (a_MetaData) @@ -68,6 +91,10 @@ public: } } + + + + /** Returns true if the specified block type is good for vines to attach to */ static bool IsBlockAttachable(BLOCKTYPE a_BlockType) { @@ -94,8 +121,12 @@ public: } } + + + + /** Returns the meta that has the maximum allowable sides of the vine, given the surroundings */ - NIBBLETYPE GetMaxMeta(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) + NIBBLETYPE GetMaxMeta(cChunk & a_Chunk, Vector3i a_RelPos) { static const struct { @@ -113,8 +144,9 @@ public: { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; + auto checkPos = a_RelPos.addedXZ(Coord.x, Coord.z); if ( - a_Chunk.UnboundedRelGetBlock(a_RelX + Coord.x, a_RelY, a_RelZ + Coord.z, BlockType, BlockMeta) && + a_Chunk.UnboundedRelGetBlock(checkPos.x, checkPos.y, checkPos.z, BlockType, BlockMeta) && IsBlockAttachable(BlockType) ) { @@ -124,55 +156,71 @@ public: return res; } - void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override + + + + + virtual void Check( + cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk + ) override { - NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); - NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelX, a_RelY, a_RelZ); + NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelPos); + NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelPos); // Check if vine above us, add its meta to MaxMeta - if ((a_RelY < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == m_BlockType)) + if ((a_RelPos.y < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_RelPos.addedY(1)) == m_BlockType)) { - MaxMeta |= a_Chunk.GetMeta(a_RelX, a_RelY + 1, a_RelZ); + MaxMeta |= a_Chunk.GetMeta(a_RelPos.addedY(1)); } NIBBLETYPE Common = CurMeta & MaxMeta; // Neighbors that we have and are legal if (Common != CurMeta) { // There is a neighbor missing, need to update the meta or even destroy the block - bool HasTop = (a_RelY < cChunkDef::Height - 1) && IsBlockAttachable(a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ)); + bool HasTop = (a_RelPos.y < cChunkDef::Height - 1) && IsBlockAttachable(a_Chunk.GetBlock(a_RelPos.addedY(1))); if ((Common == 0) && !HasTop) { // The vine just lost all its support, destroy the block: if (DoesDropOnUnsuitable()) { - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ); + a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos)); } - a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); + a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0); return; } - a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, Common); + a_Chunk.SetBlock(a_RelPos, m_BlockType, Common); } else { - // Wake up the simulators for this block: - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, &a_Chunk); + auto absPos = a_Chunk.RelativeToAbsolute(a_RelPos); + a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(absPos, &a_Chunk); } } + + + + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } + + + + virtual bool DoesDropOnUnsuitable(void) override { return false; } + + + + virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { UNUSED(a_ChunkInterface); @@ -196,34 +244,53 @@ public: } } + + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override { return ((a_Meta >> 1) | (a_Meta << 3)) & 0x0f; // Rotate bits to the right } + + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override { return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left } + + + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override { // Bits 2 and 4 stay, bits 1 and 3 swap return static_cast<NIBBLETYPE>((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2)); } + + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override { // Bits 1 and 3 stay, bits 2 and 4 swap return static_cast<NIBBLETYPE>((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); return 7; } - } ; diff --git a/src/Blocks/BlockWallSign.h b/src/Blocks/BlockWallSign.h index 37ca2afae..3759b4db6 100644 --- a/src/Blocks/BlockWallSign.h +++ b/src/Blocks/BlockWallSign.h @@ -8,22 +8,31 @@ -class cBlockWallSignHandler : +class cBlockWallSignHandler: public cBlockHandler { - typedef cBlockHandler super; + using super = cBlockHandler; public: - cBlockWallSignHandler(BLOCKTYPE a_BlockType) : + + cBlockWallSignHandler(BLOCKTYPE a_BlockType): super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_SIGN, 1, 0)); + return cItem(E_ITEM_SIGN, 1, 0); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { int BlockX = (a_Chunk.GetPosX() * cChunkDef::Width) + a_RelX; @@ -34,6 +43,10 @@ public: return ((Type == E_BLOCK_WALLSIGN) || (Type == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(Type)); } + + + + static void GetBlockCoordsBehindTheSign(NIBBLETYPE a_BlockMeta, int & a_BlockX, int & a_BlockZ) { switch (a_BlockMeta) @@ -46,14 +59,18 @@ public: } } + + + + static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) { switch (a_Direction) { - case BLOCK_FACE_ZM: return 0x2; - case BLOCK_FACE_ZP: return 0x3; - case BLOCK_FACE_XM: return 0x4; - case BLOCK_FACE_XP: return 0x5; + case BLOCK_FACE_ZM: return 0x02; + case BLOCK_FACE_ZP: return 0x03; + case BLOCK_FACE_XM: return 0x04; + case BLOCK_FACE_XP: return 0x05; case BLOCK_FACE_NONE: case BLOCK_FACE_YP: case BLOCK_FACE_YM: @@ -61,9 +78,13 @@ public: break; } } - return 0x2; + return 0x02; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 4420871ae..5a637f69c 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -97,9 +97,8 @@ SET (HDRS BlockWorkbench.h BroadcastInterface.h ChunkInterface.h - ClearMetaOnDrop.h GetHandlerCompileTimeTemplate.h - MetaRotator.h + Mixins.h WorldInterface.h ) diff --git a/src/Blocks/ChunkInterface.cpp b/src/Blocks/ChunkInterface.cpp index 28dd1ac36..4d6301925 100644 --- a/src/Blocks/ChunkInterface.cpp +++ b/src/Blocks/ChunkInterface.cpp @@ -5,6 +5,7 @@ #include "BlockHandler.h" #include "WorldInterface.h" #include "../ChunkMap.h" +#include "../World.h" @@ -30,19 +31,16 @@ NIBBLETYPE cChunkInterface::GetBlockMeta(Vector3i a_Pos) bool cChunkInterface::GetBlockTypeMeta(Vector3i a_Pos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) { - return m_ChunkMap->GetBlockTypeMeta(a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta); + return m_ChunkMap->GetBlockTypeMeta(a_Pos, a_BlockType, a_BlockMeta); } -/** Sets the block at the specified coords to the specified value. -Full processing, incl. updating neighbors, is performed. -*/ -void cChunkInterface::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +void cChunkInterface::SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - m_ChunkMap->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); + m_ChunkMap->SetBlock(a_BlockPos, a_BlockType, a_BlockMeta); } @@ -106,10 +104,26 @@ bool cChunkInterface::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a -bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, int a_X, int a_Y, int a_Z) +bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos) { - cBlockHandler * Handler = cBlockInfo::GetHandler(GetBlock({a_X, a_Y, a_Z})); - Handler->OnDestroyed(*this, a_WorldInterface, a_X, a_Y, a_Z); - return m_ChunkMap->DigBlock(a_X, a_Y, a_Z); + BLOCKTYPE blockType; + NIBBLETYPE blockMeta; + GetBlockTypeMeta(a_BlockPos, blockType, blockMeta); + auto handler = cBlockInfo::GetHandler(blockType); + handler->OnBreaking(*this, a_WorldInterface, a_BlockPos); + if (!m_ChunkMap->DigBlock(a_BlockPos)) + { + return false; + } + handler->OnBroken(*this, a_WorldInterface, a_BlockPos, blockType, blockMeta); + return true; } + + + + +void cChunkInterface::DropBlockAsPickups(Vector3i a_BlockPos, const cEntity * a_Digger, const cItem * a_Tool) +{ + m_ChunkMap->GetWorld()->DropBlockAsPickups(a_BlockPos, a_Digger, a_Tool); +} diff --git a/src/Blocks/ChunkInterface.h b/src/Blocks/ChunkInterface.h index 120ccf455..6bf450748 100644 --- a/src/Blocks/ChunkInterface.h +++ b/src/Blocks/ChunkInterface.h @@ -22,9 +22,16 @@ public: bool GetBlockTypeMeta(Vector3i a_Pos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); /** Sets the block at the specified coords to the specified value. - Full processing, incl. updating neighbors, is performed. - */ - void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + Full processing, incl. updating neighbors, is performed. */ + void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + + /** OBSOLETE, use the Vector3i-based overload instead. + Sets the block at the specified coords to the specified value. + Full processing, incl. updating neighbors, is performed. */ + void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) + { + return SetBlock({a_BlockX, a_BlockY, a_BlockZ}, a_BlockType, a_BlockMeta); + } void SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData, bool a_ShouldMarkDirty = true, bool a_ShouldInformClient = true); @@ -44,7 +51,11 @@ public: virtual bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) override; - bool DigBlock(cWorldInterface & a_WorldInterface, int a_X, int a_Y, int a_Z); + bool DigBlock(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos); + + /** Digs the block and spawns the relevant pickups, as if a_Digger used a_Tool to dig the block. */ + void DropBlockAsPickups(Vector3i a_BlockPos, const cEntity * a_Digger = nullptr, const cItem * a_Tool = nullptr); + private: cChunkMap * m_ChunkMap; diff --git a/src/Blocks/ClearMetaOnDrop.h b/src/Blocks/ClearMetaOnDrop.h deleted file mode 100644 index 3a375e121..000000000 --- a/src/Blocks/ClearMetaOnDrop.h +++ /dev/null @@ -1,24 +0,0 @@ - -#pragma once - -// mixin for use to clear meta values when the block is converted to a pickup - -// Usage: inherit from this class, passing the parent class as the parameter Base -// For example to use in class Foo which should inherit Bar use -// class Foo : public cClearMetaOnDrop<Bar>; - -template <class Base> -class cClearMetaOnDrop : public Base -{ -public: - - cClearMetaOnDrop(BLOCKTYPE a_BlockType) : - Base(a_BlockType) - {} - - virtual ~cClearMetaOnDrop() override {} - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - a_Pickups.push_back(cItem(this->m_BlockType)); - } -}; diff --git a/src/Blocks/MetaRotator.h b/src/Blocks/MetaRotator.h deleted file mode 100644 index 61cd81ddc..000000000 --- a/src/Blocks/MetaRotator.h +++ /dev/null @@ -1,120 +0,0 @@ -// MetaRotator.h - -// Provides a mixin for rotations and reflections - -#pragma once - -// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it: -#ifdef _MSC_VER - #pragma warning(disable: 4127) // Conditional expression is constant -#endif - - - - - -/* -Provides a mixin for rotations and reflections following the standard pattern of apply mask then use case. - -Usage: -Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West. There is also an aptional parameter AssertIfNotMatched. Set this if it is invalid for a block to exist in any other state. -*/ - -template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched = false> -class cMetaRotator : public Base -{ -public: - - cMetaRotator(BLOCKTYPE a_BlockType) : - Base(a_BlockType) - {} - - virtual ~cMetaRotator() override {} - - virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override; - virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override; - virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override; - virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override; -}; - - - - - -template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched> -NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCW(NIBBLETYPE a_Meta) -{ - NIBBLETYPE OtherMeta = a_Meta & (~BitMask); - switch (a_Meta & BitMask) - { - case South: return West | OtherMeta; - case West: return North | OtherMeta; - case North: return East | OtherMeta; - case East: return South | OtherMeta; - } - if (AssertIfNotMatched) - { - ASSERT(!"Invalid Meta value"); - } - return a_Meta; -} - - - - - -template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched> -NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCCW(NIBBLETYPE a_Meta) -{ - NIBBLETYPE OtherMeta = a_Meta & (~BitMask); - switch (a_Meta & BitMask) - { - case South: return East | OtherMeta; - case East: return North | OtherMeta; - case North: return West | OtherMeta; - case West: return South | OtherMeta; - } - if (AssertIfNotMatched) - { - ASSERT(!"Invalid Meta value"); - } - return a_Meta; -} - - - - - -template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched> -NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorXY(NIBBLETYPE a_Meta) -{ - NIBBLETYPE OtherMeta = a_Meta & (~BitMask); - switch (a_Meta & BitMask) - { - case South: return North | OtherMeta; - case North: return South | OtherMeta; - } - // Not Facing North or South; No change. - return a_Meta; -} - - - - - -template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched> -NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorYZ(NIBBLETYPE a_Meta) -{ - NIBBLETYPE OtherMeta = a_Meta & (~BitMask); - switch (a_Meta & BitMask) - { - case West: return East | OtherMeta; - case East: return West | OtherMeta; - } - // Not Facing East or West; No change. - return a_Meta; -} - - - - diff --git a/src/Blocks/Mixins.h b/src/Blocks/Mixins.h new file mode 100644 index 000000000..a65fe7b06 --- /dev/null +++ b/src/Blocks/Mixins.h @@ -0,0 +1,166 @@ +// Mixins.h + +// Provides various mixins for easier cBlockHandler descendant implementations + +/* The general use case is to derive a handler from these mixins, providing a suitable base to them: +class cBlockAir: public cBlockWithNoDrops<cBlockHandler>; +class cBlockLadder: public cMetaRotator<cClearMetaOnDrop, ...> +*/ + +#pragma once + +#include "../Item.h" + + + + + +// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it: +#ifdef _MSC_VER + #pragma warning(disable: 4127) // Conditional expression is constant +#endif + + + + + +template <class Base = cBlockHandler> +class cBlockWithNoDrops: + public Base +{ +public: + + cBlockWithNoDrops(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + // Don't drop anything: + return {}; + } +}; + + + + + +/** Mixin to clear the block's meta value when converting to a pickup. */ +template <class Base> +class cClearMetaOnDrop: + public Base +{ +public: + + cClearMetaOnDrop(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + // Reset the meta to zero: + return cItem(this->m_BlockType); + } +}; + + + + + +/** Mixin for rotations and reflections following the standard pattern of "apply mask, then use a switch". +Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West. +There is also an aptional parameter AssertIfNotMatched, set this if it is invalid for a block to exist in any other state. */ +template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched = false> +class cMetaRotator: + public Base +{ +public: + + cMetaRotator(BLOCKTYPE a_BlockType): + Base(a_BlockType) + {} + + + + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override + { + NIBBLETYPE OtherMeta = a_Meta & (~BitMask); + switch (a_Meta & BitMask) + { + case South: return East | OtherMeta; + case East: return North | OtherMeta; + case North: return West | OtherMeta; + case West: return South | OtherMeta; + } + if (AssertIfNotMatched) + { + ASSERT(!"Invalid Meta value"); + } + return a_Meta; + } + + + + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override + { + NIBBLETYPE OtherMeta = a_Meta & (~BitMask); + switch (a_Meta & BitMask) + { + case South: return West | OtherMeta; + case West: return North | OtherMeta; + case North: return East | OtherMeta; + case East: return South | OtherMeta; + } + if (AssertIfNotMatched) + { + ASSERT(!"Invalid Meta value"); + } + return a_Meta; + } + + + + + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override + { + NIBBLETYPE OtherMeta = a_Meta & (~BitMask); + switch (a_Meta & BitMask) + { + case South: return North | OtherMeta; + case North: return South | OtherMeta; + } + // Not Facing North or South; No change. + return a_Meta; + } + + + + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override + { + NIBBLETYPE OtherMeta = a_Meta & (~BitMask); + switch (a_Meta & BitMask) + { + case West: return East | OtherMeta; + case East: return West | OtherMeta; + } + // Not Facing East or West; No change. + return a_Meta; + } +}; diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index da9075fb4..b4dcfa4a9 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -55,7 +55,7 @@ public: /** Spawns experience orbs of the specified total value at the given location. The orbs' values are split according to regular Minecraft rules. Returns an vector of UniqueID of all the orbs. */ - virtual std::vector<UInt32> SpawnSplitExperienceOrbs(double a_X, double a_Y, double a_Z, int a_Reward) = 0; + virtual std::vector<UInt32> SpawnSplitExperienceOrbs(Vector3d a_Pos, int a_Reward) = 0; /** Sends the block on those coords to the player */ virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer & a_Player) = 0; |