From ab62fc398818d717b54110b13e1b3af48e07b686 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Thu, 7 Nov 2024 20:03:21 +0000 Subject: Clean up CanBeAt Functions (#5587) * Use cChunkDef::IsValidHeight for CanBeAt functions, and related helpers. * Add mixins for SolidSurfaceUnderneat and DirtLikeUnderneath * Minor fixes after change review. --- src/Blocks/BlockAnvil.h | 2 +- src/Blocks/BlockBed.h | 2 +- src/Blocks/BlockBigFlower.h | 7 +- src/Blocks/BlockBrewingStand.h | 2 +- src/Blocks/BlockButton.h | 2 +- src/Blocks/BlockCactus.h | 36 ++-- src/Blocks/BlockCarpet.h | 3 +- src/Blocks/BlockChest.h | 2 +- src/Blocks/BlockCocoaPod.h | 7 +- src/Blocks/BlockComparator.h | 43 +---- src/Blocks/BlockCrops.h | 9 +- src/Blocks/BlockDeadBush.h | 5 +- src/Blocks/BlockDoor.h | 22 ++- src/Blocks/BlockDropSpenser.h | 2 +- src/Blocks/BlockEnderChest.h | 2 +- src/Blocks/BlockFenceGate.h | 2 +- src/Blocks/BlockFlower.h | 14 +- src/Blocks/BlockFurnace.h | 2 +- src/Blocks/BlockGlazedTerracotta.h | 2 +- src/Blocks/BlockHopper.h | 2 +- src/Blocks/BlockJukebox.h | 2 +- src/Blocks/BlockLadder.h | 2 +- src/Blocks/BlockLever.h | 2 +- src/Blocks/BlockMushroom.h | 5 +- src/Blocks/BlockNetherWart.h | 3 +- src/Blocks/BlockObserver.h | 2 +- src/Blocks/BlockPiston.h | 2 +- src/Blocks/BlockPortal.h | 4 +- src/Blocks/BlockPressurePlate.h | 5 +- src/Blocks/BlockPumpkin.h | 2 +- src/Blocks/BlockRail.h | 28 +-- src/Blocks/BlockRedstoneRepeater.h | 44 +---- src/Blocks/BlockRedstoneWire.h | 43 +---- src/Blocks/BlockSapling.h | 14 +- src/Blocks/BlockSignPost.h | 5 +- src/Blocks/BlockSnow.h | 4 +- src/Blocks/BlockStairs.h | 2 +- src/Blocks/BlockStandingBanner.h | 19 +-- src/Blocks/BlockStems.h | 3 +- src/Blocks/BlockSugarCane.h | 44 ++--- src/Blocks/BlockTallGrass.h | 25 +-- src/Blocks/BlockTorch.h | 4 +- src/Blocks/BlockTrapdoor.h | 2 +- src/Blocks/BlockTripwireHook.h | 2 +- src/Blocks/BlockVines.h | 7 +- src/Blocks/CMakeLists.txt | 2 +- src/Blocks/Mixins.h | 262 ----------------------------- src/Blocks/Mixins/DirtLikeUnderneath.h | 42 +++++ src/Blocks/Mixins/Mixins.h | 262 +++++++++++++++++++++++++++++ src/Blocks/Mixins/SolidSurfaceUnderneath.h | 65 +++++++ 50 files changed, 525 insertions(+), 551 deletions(-) delete mode 100644 src/Blocks/Mixins.h create mode 100644 src/Blocks/Mixins/DirtLikeUnderneath.h create mode 100644 src/Blocks/Mixins/Mixins.h create mode 100644 src/Blocks/Mixins/SolidSurfaceUnderneath.h diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index bc031216a..eb8053af1 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "../Entities/Player.h" #include "../UI/AnvilWindow.h" diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index a6b2814b9..fcf7d58a0 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -6,7 +6,7 @@ #include "BlockEntity.h" #include "ChunkInterface.h" #include "Entities/Player.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h index 1b2c0d735..d8270dc6c 100644 --- a/src/Blocks/BlockBigFlower.h +++ b/src/Blocks/BlockBigFlower.h @@ -25,9 +25,10 @@ private: if (IsMetaTopPart(a_Meta)) { BLOCKTYPE BottomType; + const auto BottomPosition = a_Position.addedY(-1); if ( - (a_Position.y < 1) || - !a_World.GetBlockTypeMeta(a_Position - Vector3i(0, 1, 0), BottomType, a_Meta) || + !cChunkDef::IsValidHeight(BottomPosition) || + !a_World.GetBlockTypeMeta(BottomPosition, BottomType, a_Meta) || (BottomType != E_BLOCK_BIG_FLOWER) ) { @@ -104,7 +105,7 @@ private: // Both parts can only that they're rooted in grass. const auto RootPosition = a_Position.addedY(IsMetaTopPart(a_Meta) ? -2 : -1); - return (RootPosition.y >= 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(RootPosition)); + return cChunkDef::IsValidHeight(RootPosition) && IsBlockTypeOfDirt(a_Chunk.GetBlock(RootPosition)); } diff --git a/src/Blocks/BlockBrewingStand.h b/src/Blocks/BlockBrewingStand.h index d1595c690..5f41525d7 100644 --- a/src/Blocks/BlockBrewingStand.h +++ b/src/Blocks/BlockBrewingStand.h @@ -1,7 +1,7 @@ #pragma once -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index 1a141eff3..e8affb290 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -7,7 +7,7 @@ #include "../Chunk.h" #include "Defines.h" #include "Entities/Player.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "ChunkInterface.h" #include "World.h" diff --git a/src/Blocks/BlockCactus.h b/src/Blocks/BlockCactus.h index 23c4d3421..9b1461cb8 100644 --- a/src/Blocks/BlockCactus.h +++ b/src/Blocks/BlockCactus.h @@ -20,11 +20,12 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto SurfacePosition = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(SurfacePosition)) { return false; } - BLOCKTYPE Surface = a_Chunk.GetBlock(a_Position.addedY(-1)); + BLOCKTYPE Surface = a_Chunk.GetBlock(SurfacePosition); if ((Surface != E_BLOCK_SAND) && (Surface != E_BLOCK_CACTUS)) { // Cactus can only be placed on sand and itself @@ -75,25 +76,25 @@ private: virtual int Grow(cChunk & a_Chunk, Vector3i a_RelPos, int a_NumStages = 1) const override { // Check the total height of the cacti blocks here: - int top = a_RelPos.y + 1; + auto Top = a_RelPos.addedY(1); while ( - (top < cChunkDef::Height) && - (a_Chunk.GetBlock({a_RelPos.x, top, a_RelPos.z}) == E_BLOCK_CACTUS) + cChunkDef::IsValidHeight(Top) && + (a_Chunk.GetBlock(Top) == E_BLOCK_CACTUS) ) { - ++top; + Top.y++; } - int bottom = a_RelPos.y - 1; + auto Bottom = a_RelPos.addedY(-1); while ( - (bottom > 0) && - (a_Chunk.GetBlock({a_RelPos.x, bottom, a_RelPos.z}) == E_BLOCK_CACTUS) + cChunkDef::IsValidHeight(Bottom) && + (a_Chunk.GetBlock(Bottom) == E_BLOCK_CACTUS) ) { - --bottom; + --Bottom.y; } // Refuse if already too high: - auto numToGrow = std::min(a_NumStages, a_Chunk.GetWorld()->GetMaxCactusHeight() + 1 - (top - bottom)); + auto numToGrow = std::min(a_NumStages, a_Chunk.GetWorld()->GetMaxCactusHeight() + 1 - (Top.y - Bottom.y)); if (numToGrow <= 0) { return 0; @@ -102,14 +103,14 @@ private: BLOCKTYPE blockType; for (int i = 0; i < numToGrow; ++i) { - Vector3i pos(a_RelPos.x, top + i, a_RelPos.z); - if (!a_Chunk.UnboundedRelGetBlockType(pos, blockType) || (blockType != E_BLOCK_AIR)) + auto NewTop = Top.addedY(i); + if (!a_Chunk.UnboundedRelGetBlockType(NewTop, blockType) || (blockType != E_BLOCK_AIR)) { // Cannot grow there return i; } - a_Chunk.UnboundedRelFastSetBlock(pos, E_BLOCK_CACTUS, 0); + a_Chunk.UnboundedRelFastSetBlock(NewTop, E_BLOCK_CACTUS, 0); // Check surroundings. Cacti may ONLY be surrounded by non-solid blocks; if they aren't, drop as pickup and bail out the growing static const Vector3i neighborOffsets[] = @@ -122,7 +123,7 @@ private: for (const auto & ofs: neighborOffsets) { if ( - a_Chunk.UnboundedRelGetBlockType(pos + ofs, blockType) && + a_Chunk.UnboundedRelGetBlockType(NewTop + ofs, blockType) && ( cBlockInfo::IsSolid(blockType) || (blockType == E_BLOCK_LAVA) || @@ -131,7 +132,7 @@ private: ) { // Remove the cactus - auto absPos = a_Chunk.RelativeToAbsolute(pos); + auto absPos = a_Chunk.RelativeToAbsolute(NewTop); a_Chunk.GetWorld()->DropBlockAsPickups(absPos); return i + 1; } @@ -143,7 +144,8 @@ private: virtual PlantAction CanGrow(cChunk & a_Chunk, Vector3i a_RelPos) const override { // Only allow growing if there's an air block above: - if (((a_RelPos.y + 1) < cChunkDef::Height) && (a_Chunk.GetBlock(a_RelPos.addedY(1)) == E_BLOCK_AIR)) + const auto RelPosAbove = a_RelPos.addedY(1); + if (cChunkDef::IsValidHeight(RelPosAbove) && (a_Chunk.GetBlock(RelPosAbove) == E_BLOCK_AIR)) { return Super::CanGrow(a_Chunk, a_RelPos); } diff --git a/src/Blocks/BlockCarpet.h b/src/Blocks/BlockCarpet.h index 841e94b11..2477ee344 100644 --- a/src/Blocks/BlockCarpet.h +++ b/src/Blocks/BlockCarpet.h @@ -27,7 +27,8 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) != E_BLOCK_AIR); + const auto PosBelow = a_Position.addedY(-1); + return cChunkDef::IsValidHeight(PosBelow) && (a_Chunk.GetBlock(PosBelow) != E_BLOCK_AIR); } diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h index 119216d00..99a95e692 100644 --- a/src/Blocks/BlockChest.h +++ b/src/Blocks/BlockChest.h @@ -3,7 +3,7 @@ #include "../BlockArea.h" #include "../Entities/Player.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockCocoaPod.h b/src/Blocks/BlockCocoaPod.h index e018388c5..7906a1888 100644 --- a/src/Blocks/BlockCocoaPod.h +++ b/src/Blocks/BlockCocoaPod.h @@ -43,7 +43,12 @@ private: auto LogPos = AddFaceDirection(a_Position, BlockFace, true); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - a_Chunk.UnboundedRelGetBlock(LogPos, BlockType, BlockMeta); + if (!a_Chunk.UnboundedRelGetBlock(LogPos, BlockType, BlockMeta)) + { + // Don't pop if chunk not loaded. + return true; + } + return ((BlockType == E_BLOCK_LOG) && ((BlockMeta & 0x03) == E_META_LOG_JUNGLE)); } diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h index 18aa2a8b9..9ce9d3dbd 100644 --- a/src/Blocks/BlockComparator.h +++ b/src/Blocks/BlockComparator.h @@ -2,17 +2,17 @@ #pragma once #include "BlockHandler.h" -#include "BlockRedstoneRepeater.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" +#include "Mixins/SolidSurfaceUnderneath.h" class cBlockComparatorHandler final : - public cYawRotator + public cSolidSurfaceUnderneath> { - using Super = cYawRotator; + using Super = cSolidSurfaceUnderneath>; public: @@ -152,41 +152,6 @@ private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - if (a_Position.y <= 0) - { - return false; - } - - BLOCKTYPE BelowBlock; - NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); - - if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) - { - return true; - } - - // upside down slabs - if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) - { - return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN; - } - - // upside down stairs - if (cBlockStairsHandler::IsAnyStairType(BelowBlock)) - { - return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN; - } - - return false; - } - - - - - virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override { return cItem(E_ITEM_COMPARATOR, 1, 0); diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h index b323ace10..59413ba08 100644 --- a/src/Blocks/BlockCrops.h +++ b/src/Blocks/BlockCrops.h @@ -118,7 +118,14 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_FARMLAND); + const auto BlockBelow = a_Position.addedY(-1); + + if (!cChunkDef::IsValidHeight(BlockBelow)) + { + return false; + } + + return a_Chunk.GetBlock(BlockBelow) == E_BLOCK_FARMLAND; } diff --git a/src/Blocks/BlockDeadBush.h b/src/Blocks/BlockDeadBush.h index 080dd150c..884b6f686 100644 --- a/src/Blocks/BlockDeadBush.h +++ b/src/Blocks/BlockDeadBush.h @@ -29,12 +29,13 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto PosBelow = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(PosBelow)) { return false; } - BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_Position.addedY(-1)); + BLOCKTYPE BelowBlock = a_Chunk.GetBlock(PosBelow); switch (BelowBlock) { case E_BLOCK_CLAY: diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index 1b5c33d46..c394bda39 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -5,7 +5,7 @@ #include "../BlockInfo.h" #include "../Entities/Player.h" #include "../Chunk.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "ChunkInterface.h" #include "BlockSlab.h" @@ -191,14 +191,18 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { // CanBeAt is also called on placement, so the top part can't check for the bottom part. - // Both parts can only that their base is a valid block. + // Both parts can only check that the base of the door (i.e. -2 for a door top) is a valid block. + const auto BasePosition = a_Position.addedY(((a_Meta & 0x8) == 0x8) ? -2 : -1); + if (!cChunkDef::IsValidHeight(BasePosition)) + { + return false; + } BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - const auto BasePosition = a_Position.addedY(((a_Meta & 0x8) == 0x8) ? -2 : -1); a_Chunk.GetBlockTypeMeta(BasePosition, BlockType, BlockMeta); - return (BasePosition.y >= 0) && CanBeOn(BlockType, BlockMeta); + return CanBeOn(BlockType, BlockMeta); } @@ -216,9 +220,10 @@ private: if ((Meta & 0x08) != 0) { // The coords are pointing at the top part of the door - if (a_BlockPos.y > 0) + const auto BottomPos = a_BlockPos.addedY(-1); + if (cChunkDef::IsValidHeight(BottomPos)) { - NIBBLETYPE DownMeta = a_ChunkInterface.GetBlockMeta(a_BlockPos.addedY(-1)); + NIBBLETYPE DownMeta = a_ChunkInterface.GetBlockMeta(BottomPos); return static_cast((DownMeta & 0x07) | 0x08 | (Meta << 4)); } // This is the top part of the door at the bottommost layer of the world, there's no bottom: @@ -227,9 +232,10 @@ private: else { // The coords are pointing at the bottom part of the door - if (a_BlockPos.y < cChunkDef::Height - 1) + const auto TopPos = a_BlockPos.addedY(1); + if (cChunkDef::IsValidHeight(TopPos)) { - NIBBLETYPE UpMeta = a_ChunkInterface.GetBlockMeta(a_BlockPos.addedY(1)); + NIBBLETYPE UpMeta = a_ChunkInterface.GetBlockMeta(TopPos); return static_cast(Meta | (UpMeta << 4)); } // This is the bottom part of the door at the topmost layer of the world, there's no top: diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h index 050adf0f1..7b18eb8da 100644 --- a/src/Blocks/BlockDropSpenser.h +++ b/src/Blocks/BlockDropSpenser.h @@ -5,7 +5,7 @@ #pragma once -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockEnderChest.h b/src/Blocks/BlockEnderChest.h index 2e0da0f17..a944ab263 100644 --- a/src/Blocks/BlockEnderChest.h +++ b/src/Blocks/BlockEnderChest.h @@ -1,7 +1,7 @@ #pragma once -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h index f52d8df9c..75a0ded06 100644 --- a/src/Blocks/BlockFenceGate.h +++ b/src/Blocks/BlockFenceGate.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "../EffectID.h" diff --git a/src/Blocks/BlockFlower.h b/src/Blocks/BlockFlower.h index 023ba4a37..aaa532c0c 100644 --- a/src/Blocks/BlockFlower.h +++ b/src/Blocks/BlockFlower.h @@ -2,15 +2,16 @@ #pragma once #include "BlockHandler.h" +#include "Mixins/DirtLikeUnderneath.h" class cBlockFlowerHandler final : - public cBlockHandler + public cDirtLikeUnderneath { - using Super = cBlockHandler; + using Super = cDirtLikeUnderneath; public: @@ -28,15 +29,6 @@ private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - return (a_Position.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_Position.addedY(-1))); - } - - - - - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h index 8cdc9489a..968ea398c 100644 --- a/src/Blocks/BlockFurnace.h +++ b/src/Blocks/BlockFurnace.h @@ -1,7 +1,7 @@ #pragma once -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockGlazedTerracotta.h b/src/Blocks/BlockGlazedTerracotta.h index 0975f1ecd..21206ab77 100644 --- a/src/Blocks/BlockGlazedTerracotta.h +++ b/src/Blocks/BlockGlazedTerracotta.h @@ -1,7 +1,7 @@ #pragma once -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockHopper.h b/src/Blocks/BlockHopper.h index 930f1e0bc..91ad91bff 100644 --- a/src/Blocks/BlockHopper.h +++ b/src/Blocks/BlockHopper.h @@ -3,7 +3,7 @@ // Declares the cBlockHopperHandler class representing the handler for the Hopper block -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockJukebox.h b/src/Blocks/BlockJukebox.h index 970f10fc1..79475d30b 100644 --- a/src/Blocks/BlockJukebox.h +++ b/src/Blocks/BlockJukebox.h @@ -2,7 +2,7 @@ #pragma once #include "BlockEntity.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockLadder.h b/src/Blocks/BlockLadder.h index bab51b2d3..4bca19930 100644 --- a/src/Blocks/BlockLadder.h +++ b/src/Blocks/BlockLadder.h @@ -3,7 +3,7 @@ #include "BlockHandler.h" #include "BlockInfo.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 60db4ddee..2a676ce00 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -5,7 +5,7 @@ #include "Blocks/BlockStairs.h" #include "ChunkDef.h" #include "Defines.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "BlockSlab.h" diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h index bed16c557..9e4378d4e 100644 --- a/src/Blocks/BlockMushroom.h +++ b/src/Blocks/BlockMushroom.h @@ -23,14 +23,15 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto BasePos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BasePos)) { return false; } // TODO: Cannot be at too much daylight - switch (a_Chunk.GetBlock(a_Position.addedY(-1))) + switch (a_Chunk.GetBlock(BasePos)) { case E_BLOCK_GLASS: case E_BLOCK_CACTUS: diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h index 43081d511..c0686afc6 100644 --- a/src/Blocks/BlockNetherWart.h +++ b/src/Blocks/BlockNetherWart.h @@ -60,7 +60,8 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { // Needs to be placed on top of a Soulsand block: - return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_SOULSAND); + const auto BasePos = a_Position.addedY(-1); + return cChunkDef::IsValidHeight(BasePos) && (a_Chunk.GetBlock(BasePos) == E_BLOCK_SOULSAND); } diff --git a/src/Blocks/BlockObserver.h b/src/Blocks/BlockObserver.h index 13ffa4631..c2cab3068 100644 --- a/src/Blocks/BlockObserver.h +++ b/src/Blocks/BlockObserver.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" class cBlockObserverHandler final : diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index 4afeb4767..275214036 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "../Item.h" diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 05daa9337..f4b5a50bd 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -51,9 +51,9 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if ((a_Position.y <= 0) || (a_Position.y >= cChunkDef::Height - 1)) + if (!cChunkDef::IsValidHeight(a_Position.addedY(-1)) || !cChunkDef::IsValidHeight(a_Position.addedY(1))) { - return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1. + return false; // Must be 1 away from the boundary, there will always be another portal or an obsidian between the portal block and the boundary. } switch (a_Meta) diff --git a/src/Blocks/BlockPressurePlate.h b/src/Blocks/BlockPressurePlate.h index 6d852bfc0..d69234cee 100644 --- a/src/Blocks/BlockPressurePlate.h +++ b/src/Blocks/BlockPressurePlate.h @@ -22,14 +22,15 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto PosBelow = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(PosBelow)) { return false; } BLOCKTYPE Block; NIBBLETYPE BlockMeta; - a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), Block, BlockMeta); + a_Chunk.GetBlockTypeMeta(PosBelow, Block, BlockMeta); // upside down slabs if (cBlockSlabHandler::IsAnySlabType(Block)) diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h index e627eeaee..fa73db56a 100644 --- a/src/Blocks/BlockPumpkin.h +++ b/src/Blocks/BlockPumpkin.h @@ -1,7 +1,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index 4e2e6211f..dea84296f 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -1,10 +1,9 @@ #pragma once #include "BlockHandler.h" -#include "BlockSlab.h" -#include "BlockStairs.h" #include "BlockType.h" -#include "Blocks/Mixins.h" +#include "Mixins/Mixins.h" +#include "Mixins/SolidSurfaceUnderneath.h" #include "../BlockInfo.h" #include "../Chunk.h" #include "ChunkDef.h" @@ -25,9 +24,9 @@ enum ENUM_PURE class cBlockRailHandler final : - public cClearMetaOnDrop + public cSolidSurfaceUnderneath> { - using Super = cClearMetaOnDrop; + using Super = cSolidSurfaceUnderneath>; public: @@ -162,26 +161,9 @@ public: private: - static bool CanBeSupportedBy(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) - { - if (cBlockSlabHandler::IsAnySlabType(a_BlockType)) - { - return (a_BlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN); - } - else if (cBlockStairsHandler::IsAnyStairType(a_BlockType)) - { - return (a_BlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN); - } - return cBlockInfo::FullyOccupiesVoxel(a_BlockType); - } - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, NIBBLETYPE a_Meta) const override { - BLOCKTYPE BelowBlock; - NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); - - if ((a_Position.y <= 0) || !CanBeSupportedBy(BelowBlock, BelowBlockMeta)) + if (!Super::CanBeAt(a_Chunk, a_Position, a_Meta)) { return false; } diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 893691d7b..92b4b3917 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -3,10 +3,9 @@ #include "BlockHandler.h" #include "BlockType.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" +#include "Mixins/SolidSurfaceUnderneath.h" #include "ChunkInterface.h" -#include "BlockSlab.h" -#include "BlockStairs.h" #include "../Chunk.h" @@ -14,9 +13,9 @@ class cBlockRedstoneRepeaterHandler final : - public cYawRotator + public cSolidSurfaceUnderneath> { - using Super = cYawRotator; + using Super = cSolidSurfaceUnderneath>; public: @@ -107,41 +106,6 @@ private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - if (a_Position.y <= 0) - { - return false; - } - - BLOCKTYPE BelowBlock; - NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); - - if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) - { - return true; - } - - // upside down slabs - if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) - { - return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN; - } - - // upside down stairs - if (cBlockStairsHandler::IsAnyStairType(BelowBlock)) - { - return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN; - } - - return false; - } - - - - - virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override { return cItem(E_ITEM_REDSTONE_REPEATER, 1, 0); diff --git a/src/Blocks/BlockRedstoneWire.h b/src/Blocks/BlockRedstoneWire.h index de8e59a40..edea704f4 100644 --- a/src/Blocks/BlockRedstoneWire.h +++ b/src/Blocks/BlockRedstoneWire.h @@ -2,17 +2,15 @@ #pragma once #include "BlockHandler.h" -#include "BlockSlab.h" -#include "BlockStairs.h" -#include "../Chunk.h" +#include "Mixins/SolidSurfaceUnderneath.h" class cBlockRedstoneWireHandler final : - public cBlockHandler + public cSolidSurfaceUnderneath { - using Super = cBlockHandler; + using Super = cSolidSurfaceUnderneath; public: @@ -20,41 +18,6 @@ public: private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - if (a_Position.y <= 0) - { - return false; - } - - BLOCKTYPE BelowBlock; - NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); - - if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) - { - return true; - } - - // upside down slabs - if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) - { - return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN; - } - - // upside down stairs - if (cBlockStairsHandler::IsAnyStairType(BelowBlock)) - { - return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN; - } - - return false; - } - - - - - virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override { return cItem(E_ITEM_REDSTONE_DUST, 1, 0); diff --git a/src/Blocks/BlockSapling.h b/src/Blocks/BlockSapling.h index d32b9b449..db953946a 100644 --- a/src/Blocks/BlockSapling.h +++ b/src/Blocks/BlockSapling.h @@ -3,15 +3,16 @@ #include "BlockHandler.h" #include "../FastRandom.h" +#include "Mixins/DirtLikeUnderneath.h" class cBlockSaplingHandler final : - public cBlockHandler + public cDirtLikeUnderneath { - using Super = cBlockHandler; + using Super = cDirtLikeUnderneath; public: @@ -29,15 +30,6 @@ private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - return (a_Position.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_Position.addedY(-1))); - } - - - - - virtual void OnUpdate( cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, diff --git a/src/Blocks/BlockSignPost.h b/src/Blocks/BlockSignPost.h index b96498cbd..89da77fbb 100644 --- a/src/Blocks/BlockSignPost.h +++ b/src/Blocks/BlockSignPost.h @@ -30,12 +30,13 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto BelowPos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BelowPos)) { return false; } - BLOCKTYPE Type = a_Chunk.GetBlock(a_Position.addedY(-1)); + BLOCKTYPE Type = a_Chunk.GetBlock(BelowPos); return (Type == E_BLOCK_SIGN_POST) || (Type == E_BLOCK_WALLSIGN) || cBlockInfo::IsSolid(Type); } diff --git a/src/Blocks/BlockSnow.h b/src/Blocks/BlockSnow.h index f3fa87a1b..51361ce17 100644 --- a/src/Blocks/BlockSnow.h +++ b/src/Blocks/BlockSnow.h @@ -69,11 +69,11 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto BelowPos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BelowPos)) { return false; } - auto BelowPos = a_Position.addedY(-1); auto BlockBelow = a_Chunk.GetBlock(BelowPos); auto MetaBelow = a_Chunk.GetMeta(BelowPos); return CanBeOn(BlockBelow, MetaBelow); diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index 76614bb62..6c37a8464 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockStandingBanner.h b/src/Blocks/BlockStandingBanner.h index 391b7fde7..0cc7c28eb 100644 --- a/src/Blocks/BlockStandingBanner.h +++ b/src/Blocks/BlockStandingBanner.h @@ -5,15 +5,16 @@ #include "../BlockInfo.h" #include "BlockEntity.h" +#include "Mixins/SolidSurfaceUnderneath.h" class cBlockStandingBannerHandler final : - public cBlockEntityHandler + public cSolidSurfaceUnderneath { - using Super = cBlockEntityHandler; + using Super = cSolidSurfaceUnderneath; public: @@ -29,20 +30,6 @@ public: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - if (a_Position.y < 1) - { - return false; - } - - return cBlockInfo::IsSolid(a_Chunk.GetBlock(a_Position.addedY(-1))); - } - - - - - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h index 11cd83967..9d598003d 100644 --- a/src/Blocks/BlockStems.h +++ b/src/Blocks/BlockStems.h @@ -58,7 +58,8 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_FARMLAND); + const auto BelowPos = a_Position.addedY(-1); + return cChunkDef::IsValidHeight(BelowPos) && (a_Chunk.GetBlock(BelowPos) == E_BLOCK_FARMLAND); } diff --git a/src/Blocks/BlockSugarCane.h b/src/Blocks/BlockSugarCane.h index cffe667e5..1f6c8a8fa 100644 --- a/src/Blocks/BlockSugarCane.h +++ b/src/Blocks/BlockSugarCane.h @@ -29,12 +29,13 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto BelowPos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BelowPos)) { return false; } - switch (a_Chunk.GetBlock(a_Position.addedY(-1))) + switch (a_Chunk.GetBlock(BelowPos)) { case E_BLOCK_DIRT: case E_BLOCK_GRASS: @@ -43,16 +44,16 @@ private: { static const Vector3i Coords[] = { - {-1, -1, 0}, - { 1, -1, 0}, - { 0, -1, -1}, - { 0, -1, 1}, + {-1, 0, 0}, + { 1, 0, 0}, + { 0, 0, -1}, + { 0, 0, 1}, } ; for (size_t i = 0; i < ARRAYCOUNT(Coords); i++) { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - if (!a_Chunk.UnboundedRelGetBlock(a_Position + Coords[i], BlockType, BlockMeta)) + if (!a_Chunk.UnboundedRelGetBlock(BelowPos + Coords[i], BlockType, BlockMeta)) { // Too close to the edge, cannot simulate return true; @@ -90,31 +91,36 @@ private: virtual int Grow(cChunk & a_Chunk, Vector3i a_RelPos, int a_NumStages = 1) const override { // Check the total height of the sugarcane blocks here: - int top = a_RelPos.y + 1; + auto top = a_RelPos.addedY(1); while ( - (top < cChunkDef::Height) && - (a_Chunk.GetBlock({a_RelPos.x, top, a_RelPos.z}) == E_BLOCK_SUGARCANE) + cChunkDef::IsValidHeight(top) && + (a_Chunk.GetBlock(top) == E_BLOCK_SUGARCANE) ) { - ++top; + ++top.y; } - int bottom = a_RelPos.y - 1; + auto bottom = a_RelPos.addedY(-1); while ( - (bottom > 0) && - (a_Chunk.GetBlock({a_RelPos.x, bottom, a_RelPos.z}) == E_BLOCK_SUGARCANE) + cChunkDef::IsValidHeight(bottom) && + (a_Chunk.GetBlock(bottom) == E_BLOCK_SUGARCANE) ) { - --bottom; + --bottom.y; } // Grow by at most a_NumStages, but no more than max height: - auto toGrow = std::min(a_NumStages, a_Chunk.GetWorld()->GetMaxSugarcaneHeight() + 1 - (top - bottom)); - Vector3i topPos(a_RelPos.x, top, a_RelPos.z); + auto toGrow = std::min(a_NumStages, a_Chunk.GetWorld()->GetMaxSugarcaneHeight() + 1 - (top.y - bottom.y)); for (int i = 0; i < toGrow; i++) { - if (a_Chunk.GetBlock(topPos.addedY(i)) == E_BLOCK_AIR) + const auto NewTop = top.addedY(i); + if (!cChunkDef::IsValidHeight(NewTop)) { - a_Chunk.SetBlock(topPos.addedY(i), E_BLOCK_SUGARCANE, 0); + return i; + } + + if (a_Chunk.GetBlock(NewTop) == E_BLOCK_AIR) + { + a_Chunk.SetBlock(NewTop, E_BLOCK_SUGARCANE, 0); } else { diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h index ea638c878..47ad2f93d 100644 --- a/src/Blocks/BlockTallGrass.h +++ b/src/Blocks/BlockTallGrass.h @@ -2,6 +2,7 @@ #pragma once #include "BlockHandler.h" +#include "Mixins/DirtLikeUnderneath.h" #include "ChunkInterface.h" @@ -10,9 +11,9 @@ /** Handles the grass that is 1 block tall */ class cBlockTallGrassHandler final : - public cBlockHandler + public cDirtLikeUnderneath { - using Super = cBlockHandler; + using Super = cDirtLikeUnderneath; public: @@ -52,25 +53,11 @@ private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - if (a_Position.y <= 0) - { - return false; - } - - BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_Position.addedY(-1)); - return IsBlockTypeOfDirt(BelowBlock); - } - - - - - /** Growing a tall grass produces a big flower (2-block high fern or double-tall grass). */ virtual int Grow(cChunk & a_Chunk, Vector3i a_RelPos, int a_NumStages = 1) const override { - if (a_RelPos.y > (cChunkDef::Height - 2)) + const auto TopPos = a_RelPos.addedY(1); + if (!cChunkDef::IsValidHeight(TopPos)) { return 0; } @@ -83,7 +70,7 @@ private: default: return 0; } a_Chunk.SetBlock(a_RelPos, E_BLOCK_BIG_FLOWER, largeFlowerMeta); - a_Chunk.SetBlock(a_RelPos.addedY(1), E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP); + a_Chunk.SetBlock(TopPos, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP); return 1; } diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index ad69cf5eb..99f685cb6 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -7,7 +7,7 @@ #include "BlockType.h" #include "ChunkInterface.h" #include "Defines.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" @@ -126,7 +126,7 @@ private: NIBBLETYPE NeighborBlockMeta; if (!a_Chunk.UnboundedRelGetBlock(NeighborRelPos, NeighborBlockType, NeighborBlockMeta)) { - // Neighbor in an unloaded chunk, bail out without changint this. + // Neighbor in an unloaded chunk, bail out without changing this. return false; } diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h index 7f6f70e1e..3fb4f4ca3 100644 --- a/src/Blocks/BlockTrapdoor.h +++ b/src/Blocks/BlockTrapdoor.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "../EffectID.h" diff --git a/src/Blocks/BlockTripwireHook.h b/src/Blocks/BlockTripwireHook.h index ae553d66f..ede6ca311 100644 --- a/src/Blocks/BlockTripwireHook.h +++ b/src/Blocks/BlockTripwireHook.h @@ -1,7 +1,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockVines.h b/src/Blocks/BlockVines.h index a23ba1489..edbd30f36 100644 --- a/src/Blocks/BlockVines.h +++ b/src/Blocks/BlockVines.h @@ -119,15 +119,16 @@ private: } // Check if vine above us, add its meta to MaxMeta: - if ((a_Position.y < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_Position.addedY(1)) == E_BLOCK_VINES)) + const auto AbovePos = a_Position.addedY(1); + if (cChunkDef::IsValidHeight(AbovePos) && (a_Chunk.GetBlock(AbovePos) == E_BLOCK_VINES)) { - MaxMeta |= a_Chunk.GetMeta(a_Position.addedY(1)); + MaxMeta |= a_Chunk.GetMeta(AbovePos); } NIBBLETYPE Common = a_CurrentMeta & MaxMeta; // Neighbors that we have and are legal. if (Common != a_CurrentMeta) { - bool HasTop = (a_Position.y < (cChunkDef::Height - 1)) && IsBlockAttachable(a_Chunk.GetBlock(a_Position.addedY(1))); + bool HasTop = cChunkDef::IsValidHeight(AbovePos) && IsBlockAttachable(a_Chunk.GetBlock(AbovePos)); if ((Common == 0) && !HasTop) // Meta equals 0 also means top. Make a last-ditch attempt to save the vine. { return VINE_LOST_SUPPORT; diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 38a60d5b7..7e3047451 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -110,6 +110,6 @@ target_sources( BroadcastInterface.h ChunkInterface.h GetHandlerCompileTimeTemplate.h - Mixins.h + Mixins/Mixins.h WorldInterface.h ) diff --git a/src/Blocks/Mixins.h b/src/Blocks/Mixins.h deleted file mode 100644 index fa8985737..000000000 --- a/src/Blocks/Mixins.h +++ /dev/null @@ -1,262 +0,0 @@ -// 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; -class cBlockLadder: public cMetaRotator -*/ - -#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 - - - - - -/** Mixin to clear the block's meta value when converting to a pickup. */ -template -class cClearMetaOnDrop : - public Base -{ -public: - - constexpr cClearMetaOnDrop(BLOCKTYPE a_BlockType): - Base(a_BlockType) - { - } - -protected: - - ~cClearMetaOnDrop() = default; - -private: - - virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const 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 cMetaRotator : - public Base -{ -public: - - constexpr cMetaRotator(BLOCKTYPE a_BlockType): - Base(a_BlockType) - { - } - -protected: - - ~cMetaRotator() = default; - - virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) const 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) const 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) const 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) const 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; - } -}; - - - - - -/** Mixin for blocks whose meta on placement depends on the yaw of the player placing the block. BitMask -selects the direction bits from the block's meta values. */ -template < - class Base, - NIBBLETYPE BitMask = 0x07, - NIBBLETYPE North = 0x02, - NIBBLETYPE East = 0x05, - NIBBLETYPE South = 0x03, - NIBBLETYPE West = 0x04, - bool AssertIfNotMatched = false -> -class cYawRotator : - public cMetaRotator -{ - using Super = cMetaRotator; - -public: - - using Super::Super; - - - /** Converts the rotation value as returned by cPlayer::GetYaw() to the appropriate metadata - value for a block placed by a player facing that way. */ - static NIBBLETYPE YawToMetaData(double a_Rotation) - { - if ((a_Rotation >= -135) && (a_Rotation < -45)) - { - return East; - } - else if ((a_Rotation >= -45) && (a_Rotation < 45)) - { - return South; - } - else if ((a_Rotation >= 45) && (a_Rotation < 135)) - { - return West; - } - else // degrees jumping from 180 to -180 - { - return North; - } - } - -protected: - - ~cYawRotator() = default; -}; - - - - - -/** Mixin for blocks whose meta on placement depends on the relative position of the player to the block in -addition to the yaw of the player placing the block. BitMask selects the direction bits from the block's meta values. */ -template < - class Base, - NIBBLETYPE BitMask = 0x07, - NIBBLETYPE North = 0x02, - NIBBLETYPE East = 0x05, - NIBBLETYPE South = 0x03, - NIBBLETYPE West = 0x04, - NIBBLETYPE Up = 0x00, - NIBBLETYPE Down = 0x01 -> -class cDisplacementYawRotator: - public cYawRotator -{ - using Super = cYawRotator; - -public: - - using Super::Super; - - - /** Converts the placement position, eye position as returned by cPlayer::GetEyePosition(), and - rotation value as returned by cPlayer::GetYaw() to the appropriate metadata value for a block placed by a player facing that way. */ - static NIBBLETYPE DisplacementYawToMetaData(const Vector3d a_PlacePosition, const Vector3d a_EyePosition, const double a_Rotation) - { - if ( - const auto Displacement = a_EyePosition - a_PlacePosition.addedXZ(0.5, 0.5); - (std::abs(Displacement.x) < 2) && (std::abs(Displacement.z) < 2) - ) - { - if (Displacement.y > 2) - { - return Up; - } - - if (Displacement.y < 0) - { - return Down; - } - } - - return Super::YawToMetaData(a_Rotation); - } - -protected: - - ~cDisplacementYawRotator() = default; - - - virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) const override - { - NIBBLETYPE OtherMeta = a_Meta & (~BitMask); - switch (a_Meta & BitMask) - { - case Down: return Up | OtherMeta; // Down -> Up - case Up: return Down | OtherMeta; // Up -> Down - } - // Not Facing Up or Down; No change. - return a_Meta; - } -}; diff --git a/src/Blocks/Mixins/DirtLikeUnderneath.h b/src/Blocks/Mixins/DirtLikeUnderneath.h new file mode 100644 index 000000000..909f1601e --- /dev/null +++ b/src/Blocks/Mixins/DirtLikeUnderneath.h @@ -0,0 +1,42 @@ + +#pragma once + +#include "../../Chunk.h" + +/** Mixin to ensure the block has a dirt-like block underneath. */ +template +class cDirtLikeUnderneath : + public Base +{ + using Super = Base; +public: + + using Super::Super; + + constexpr cDirtLikeUnderneath(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + +protected: + + ~cDirtLikeUnderneath() = default; + +protected: + + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override + { + if (!Super::CanBeAt(a_Chunk, a_Position, a_Meta)) + { + return false; + } + + const auto BelowPos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BelowPos)) + { + return false; + } + + return IsBlockTypeOfDirt(a_Chunk.GetBlock(BelowPos)); + } +}; diff --git a/src/Blocks/Mixins/Mixins.h b/src/Blocks/Mixins/Mixins.h new file mode 100644 index 000000000..d9a233bad --- /dev/null +++ b/src/Blocks/Mixins/Mixins.h @@ -0,0 +1,262 @@ +// 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; +class cBlockLadder: public cMetaRotator +*/ + +#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 + + + + + +/** Mixin to clear the block's meta value when converting to a pickup. */ +template +class cClearMetaOnDrop : + public Base +{ +public: + + constexpr cClearMetaOnDrop(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + +protected: + + ~cClearMetaOnDrop() = default; + +private: + + virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const 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 cMetaRotator : + public Base +{ +public: + + constexpr cMetaRotator(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + +protected: + + ~cMetaRotator() = default; + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) const 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) const 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) const 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) const 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; + } +}; + + + + + +/** Mixin for blocks whose meta on placement depends on the yaw of the player placing the block. BitMask +selects the direction bits from the block's meta values. */ +template < + class Base, + NIBBLETYPE BitMask = 0x07, + NIBBLETYPE North = 0x02, + NIBBLETYPE East = 0x05, + NIBBLETYPE South = 0x03, + NIBBLETYPE West = 0x04, + bool AssertIfNotMatched = false +> +class cYawRotator : + public cMetaRotator +{ + using Super = cMetaRotator; + +public: + + using Super::Super; + + + /** Converts the rotation value as returned by cPlayer::GetYaw() to the appropriate metadata + value for a block placed by a player facing that way. */ + static NIBBLETYPE YawToMetaData(double a_Rotation) + { + if ((a_Rotation >= -135) && (a_Rotation < -45)) + { + return East; + } + else if ((a_Rotation >= -45) && (a_Rotation < 45)) + { + return South; + } + else if ((a_Rotation >= 45) && (a_Rotation < 135)) + { + return West; + } + else // degrees jumping from 180 to -180 + { + return North; + } + } + +protected: + + ~cYawRotator() = default; +}; + + + + + +/** Mixin for blocks whose meta on placement depends on the relative position of the player to the block in +addition to the yaw of the player placing the block. BitMask selects the direction bits from the block's meta values. */ +template < + class Base, + NIBBLETYPE BitMask = 0x07, + NIBBLETYPE North = 0x02, + NIBBLETYPE East = 0x05, + NIBBLETYPE South = 0x03, + NIBBLETYPE West = 0x04, + NIBBLETYPE Up = 0x00, + NIBBLETYPE Down = 0x01 +> +class cDisplacementYawRotator: + public cYawRotator +{ + using Super = cYawRotator; + +public: + + using Super::Super; + + + /** Converts the placement position, eye position as returned by cPlayer::GetEyePosition(), and + rotation value as returned by cPlayer::GetYaw() to the appropriate metadata value for a block placed by a player facing that way. */ + static NIBBLETYPE DisplacementYawToMetaData(const Vector3d a_PlacePosition, const Vector3d a_EyePosition, const double a_Rotation) + { + if ( + const auto Displacement = a_EyePosition - a_PlacePosition.addedXZ(0.5, 0.5); + (std::abs(Displacement.x) < 2) && (std::abs(Displacement.z) < 2) + ) + { + if (Displacement.y > 2) + { + return Up; + } + + if (Displacement.y < 0) + { + return Down; + } + } + + return Super::YawToMetaData(a_Rotation); + } + +protected: + + ~cDisplacementYawRotator() = default; + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) const override + { + NIBBLETYPE OtherMeta = a_Meta & (~BitMask); + switch (a_Meta & BitMask) + { + case Down: return Up | OtherMeta; // Down -> Up + case Up: return Down | OtherMeta; // Up -> Down + } + // Not Facing Up or Down; No change. + return a_Meta; + } +}; diff --git a/src/Blocks/Mixins/SolidSurfaceUnderneath.h b/src/Blocks/Mixins/SolidSurfaceUnderneath.h new file mode 100644 index 000000000..c54c064d6 --- /dev/null +++ b/src/Blocks/Mixins/SolidSurfaceUnderneath.h @@ -0,0 +1,65 @@ + +#pragma once + +#include "../../Chunk.h" +#include "../BlockSlab.h" +#include "../BlockStairs.h" + +/** Mixin to ensure the block has a solid surface underneath. */ +template +class cSolidSurfaceUnderneath : + public Base +{ + using Super = Base; +public: + + using Super::Super; + + constexpr cSolidSurfaceUnderneath(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + +protected: + + ~cSolidSurfaceUnderneath() = default; + +protected: + + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override + { + if (!Super::CanBeAt(a_Chunk, a_Position, a_Meta)) + { + return false; + } + + const auto BelowPos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BelowPos)) + { + return false; + } + + BLOCKTYPE BelowBlock; + NIBBLETYPE BelowBlockMeta; + a_Chunk.GetBlockTypeMeta(BelowPos, BelowBlock, BelowBlockMeta); + + if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) + { + return true; + } + + // upside down slabs + if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) + { + return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN; + } + + // upside down stairs + if (cBlockStairsHandler::IsAnyStairType(BelowBlock)) + { + return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN; + } + + return false; + } +}; -- cgit v1.2.3