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.
This commit is contained in:
Alexander Harkness 2024-11-07 20:03:21 +00:00 committed by GitHub
parent a99c3ec2b8
commit ab62fc3988
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 264 additions and 290 deletions

View File

@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"
#include "../Entities/Player.h"
#include "../UI/AnvilWindow.h"

View File

@ -6,7 +6,7 @@
#include "BlockEntity.h"
#include "ChunkInterface.h"
#include "Entities/Player.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -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));
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -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"

View File

@ -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);
}

View File

@ -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);
}

View File

@ -3,7 +3,7 @@
#include "../BlockArea.h"
#include "../Entities/Player.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -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));
}

View File

@ -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<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>
public cSolidSurfaceUnderneath<cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>>
{
using Super = cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>;
using Super = cSolidSurfaceUnderneath<cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>>;
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);

View File

@ -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;
}

View File

@ -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:

View File

@ -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<NIBBLETYPE>((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<NIBBLETYPE>(Meta | (UpMeta << 4));
}
// This is the bottom part of the door at the topmost layer of the world, there's no top:

View File

@ -5,7 +5,7 @@
#pragma once
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -1,7 +1,7 @@
#pragma once
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"
#include "../EffectID.h"

View File

@ -2,15 +2,16 @@
#pragma once
#include "BlockHandler.h"
#include "Mixins/DirtLikeUnderneath.h"
class cBlockFlowerHandler final :
public cBlockHandler
public cDirtLikeUnderneath<cBlockHandler>
{
using Super = cBlockHandler;
using Super = cDirtLikeUnderneath<cBlockHandler>;
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);

View File

@ -1,7 +1,7 @@
#pragma once
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -1,7 +1,7 @@
#pragma once
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -3,7 +3,7 @@
// Declares the cBlockHopperHandler class representing the handler for the Hopper block
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -2,7 +2,7 @@
#pragma once
#include "BlockEntity.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -3,7 +3,7 @@
#include "BlockHandler.h"
#include "BlockInfo.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -5,7 +5,7 @@
#include "Blocks/BlockStairs.h"
#include "ChunkDef.h"
#include "Defines.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"
#include "BlockSlab.h"

View File

@ -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:

View File

@ -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);
}

View File

@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"
class cBlockObserverHandler final :

View File

@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"
#include "../Item.h"

View File

@ -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)

View File

@ -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))

View File

@ -1,7 +1,7 @@
#pragma once
#include "BlockHandler.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -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<cBlockHandler>
public cSolidSurfaceUnderneath<cClearMetaOnDrop<cBlockHandler>>
{
using Super = cClearMetaOnDrop<cBlockHandler>;
using Super = cSolidSurfaceUnderneath<cClearMetaOnDrop<cBlockHandler>>;
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;
}

View File

@ -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<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>
public cSolidSurfaceUnderneath<cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>>
{
using Super = cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>;
using Super = cSolidSurfaceUnderneath<cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>>;
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);

View File

@ -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<cBlockHandler>
{
using Super = cBlockHandler;
using Super = cSolidSurfaceUnderneath<cBlockHandler>;
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);

View File

@ -3,15 +3,16 @@
#include "BlockHandler.h"
#include "../FastRandom.h"
#include "Mixins/DirtLikeUnderneath.h"
class cBlockSaplingHandler final :
public cBlockHandler
public cDirtLikeUnderneath<cBlockHandler>
{
using Super = cBlockHandler;
using Super = cDirtLikeUnderneath<cBlockHandler>;
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,

View File

@ -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);
}

View File

@ -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);

View File

@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -5,15 +5,16 @@
#include "../BlockInfo.h"
#include "BlockEntity.h"
#include "Mixins/SolidSurfaceUnderneath.h"
class cBlockStandingBannerHandler final :
public cBlockEntityHandler
public cSolidSurfaceUnderneath<cBlockEntityHandler>
{
using Super = cBlockEntityHandler;
using Super = cSolidSurfaceUnderneath<cBlockEntityHandler>;
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);

View File

@ -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);
}

View File

@ -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
{

View File

@ -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<cBlockHandler>
{
using Super = cBlockHandler;
using Super = cDirtLikeUnderneath<cBlockHandler>;
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;
}

View File

@ -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;
}

View File

@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"
#include "../EffectID.h"

View File

@ -1,7 +1,7 @@
#pragma once
#include "BlockHandler.h"
#include "Mixins.h"
#include "Mixins/Mixins.h"

View File

@ -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;

View File

@ -110,6 +110,6 @@ target_sources(
BroadcastInterface.h
ChunkInterface.h
GetHandlerCompileTimeTemplate.h
Mixins.h
Mixins/Mixins.h
WorldInterface.h
)

View File

@ -0,0 +1,42 @@
#pragma once
#include "../../Chunk.h"
/** Mixin to ensure the block has a dirt-like block underneath. */
template <class Base>
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));
}
};

View File

@ -9,7 +9,7 @@ class cBlockLadder: public cMetaRotator<cClearMetaOnDrop, ...>
#pragma once
#include "../Item.h"
#include "../../Item.h"

View File

@ -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 Base>
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;
}
};