1
0

Move item placement into item handlers (#5184)

* Move item placement into item handlers

+ Add appropriate CanBeAt checks in cPlayer::PlaceBlocks, into which all placement handlers call.
* Partly addresses #5157
* Fixes #4878
* Fixes #2919
* Fixes #4629
* Fixes #4239
* Fixes #4849

Co-authored-by: changyong guo <guo1487@163.com>
Co-authored-by: Xotheus <shady3300@outlook.com>
Co-authored-by: Krist Pregracke <krist@tiger-scm.com>

* Review fixes

* Update APIDesc.lua

* Rename

Co-authored-by: changyong guo <guo1487@163.com>
Co-authored-by: Xotheus <shady3300@outlook.com>
Co-authored-by: Krist Pregracke <krist@tiger-scm.com>
This commit is contained in:
Tiger Wang 2021-05-05 14:25:10 +01:00 committed by GitHub
parent 34bf5c0d9d
commit a62b2b1be2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
109 changed files with 2096 additions and 2686 deletions

View File

@ -222,6 +222,24 @@ return
},
Notes = "Returns how much light the specified block type consumes.",
},
IsClickedThrough =
{
IsStatic = true,
Params =
{
{
Name = "BlockType",
Type = "number",
},
},
Returns =
{
{
Type = "boolean",
},
},
Notes = "Returns true if the specified block type is ignored by the client on left and right clicks, that is, treated as if it were air.",
},
IsOneHitDig =
{
IsStatic = true,

View File

@ -715,6 +715,17 @@ bool cBlockInfo::FullyOccupiesVoxel(const BLOCKTYPE Block)
bool cBlockInfo::IsClickedThrough(const BLOCKTYPE a_Block)
{
// TODO: Nether Fire too.
return a_Block == E_BLOCK_FIRE;
}
bool cBlockInfo::IsOneHitDig(const BLOCKTYPE Block)
{
#ifdef __clang__

View File

@ -24,6 +24,10 @@ public:
/** Does this block fully occupy its voxel - is it a 'full' block? */
static bool FullyOccupiesVoxel(BLOCKTYPE Block);
/** Does the client pretend the block doesn't exist when clicking?
For example, digging a fire will hit the block below the fire, so fire is "clicked through". */
static bool IsClickedThrough(BLOCKTYPE a_Block);
/** Is a block destroyed after a single hit?
Warning: IsOneHitDig does not take into account enchantments / status effects / swim state / floating state
and therefore may be incorrect. Only use to check if hardness is 0.

View File

@ -48,28 +48,6 @@ private:
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const override
{
if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta))
{
return false;
}
a_BlockMeta = a_BlockMeta | static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage << 2);
return true;
}
virtual bool IsUseable() const override
{
return true;

View File

@ -29,14 +29,14 @@ public:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
if (a_RelPos.y < 1)
if (a_Position.y < 1)
{
return false;
}
return cBlockInfo::IsSolid(a_Chunk.GetBlock(a_RelPos.addedY(-1)));
return cBlockInfo::IsSolid(a_Chunk.GetBlock(a_Position.addedY(-1)));
}

View File

@ -9,7 +9,6 @@
#include "../World.h"
#include "../BoundingBox.h"
#include "../Mobs/Monster.h"
#include "../BlockEntities/BedEntity.h"
@ -158,21 +157,6 @@ bool cBlockBedHandler::OnUse(
void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) const
{
a_Player.GetWorld()->DoWithBlockEntityAt(a_BlockChange.GetAbsolutePos(), [&a_Player](cBlockEntity & a_BlockEntity)
{
ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_BED);
static_cast<cBedEntity &>(a_BlockEntity).SetColor(a_Player.GetEquippedItem().m_ItemDamage);
return false;
});
}
cItems cBlockBedHandler::ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const
{
// Drops handled by the block entity:

View File

@ -91,11 +91,6 @@ private:
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, const cItem * a_Tool) const override;
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player,
const sSetBlock & a_BlockChange
) const override;

View File

@ -20,14 +20,14 @@ public:
private:
virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override
virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override
{
if (IsMetaTopPart(a_Meta))
{
BLOCKTYPE BottomType;
if (
(a_Pos.y < 1) ||
!a_ChunkInterface.GetBlockTypeMeta(a_Pos - Vector3i(0, 1, 0), BottomType, a_Meta) ||
(a_Position.y < 1) ||
!a_World.GetBlockTypeMeta(a_Position - Vector3i(0, 1, 0), BottomType, a_Meta) ||
(BottomType != E_BLOCK_BIG_FLOWER)
)
{
@ -98,17 +98,13 @@ private:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
if (a_RelPos.y <= 0)
{
return false;
}
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BlockType, BlockMeta);
// CanBeAt is also called on placement, so the top part can't check for the bottom part.
// Both parts can only that they're rooted in grass.
return IsBlockTypeOfDirt(BlockType) || ((BlockType == E_BLOCK_BIG_FLOWER) && !IsMetaTopPart(BlockMeta));
const auto RootPosition = a_Position.addedY(IsMetaTopPart(a_Meta) ? -2 : -1);
return (RootPosition.y >= 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(RootPosition));
}

View File

@ -101,47 +101,6 @@ private:
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const override
{
a_BlockType = m_BlockType;
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
return true;
}
/** Converts the block face of the neighbor to which the button is attached, to the block meta for this button. */
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace)
{
switch (a_BlockFace)
{
case BLOCK_FACE_YP: return 0x5;
case BLOCK_FACE_ZM: return 0x4;
case BLOCK_FACE_ZP: return 0x3;
case BLOCK_FACE_XM: return 0x2;
case BLOCK_FACE_XP: return 0x1;
case BLOCK_FACE_YM: return 0x0;
case BLOCK_FACE_NONE:
{
break;
}
}
UNREACHABLE("Unsupported block face");
}
/** Converts the block meta of this button into a block face of the neighbor to which the button is attached. */
inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta)
{
@ -165,10 +124,9 @@ private:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
auto Meta = a_Chunk.GetMeta(a_RelPos);
auto SupportRelPos = AddFaceDirection(a_RelPos, BlockMetaDataToBlockFace(Meta), true);
auto SupportRelPos = AddFaceDirection(a_Position, BlockMetaDataToBlockFace(a_Meta), true);
if (!cChunkDef::IsValidHeight(SupportRelPos.y))
{
return false;

View File

@ -18,47 +18,13 @@ public:
private:
/** Called before a cactus block is placed by a player, overrides cItemHandler::GetPlacementBlockTypeMeta().
Calls CanBeAt function to determine if a cactus block can be placed on a given block. */
bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
if (
a_Player.GetWorld()->DoWithChunkAt(a_PlacedBlockPos,
[this, a_PlacedBlockPos, &a_ChunkInterface](cChunk & a_Chunk)
{
auto RelPos = cChunkDef::AbsoluteToRelative(a_PlacedBlockPos);
return CanBeAt(a_ChunkInterface, RelPos, a_Chunk);
}
))
{
a_BlockType = m_BlockType;
// Setting a_BlockMeta to meta copied from the lowest 4 bits of the player's equipped item's damage value.
NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage);
a_BlockMeta = Meta & 0x0f;
return true;
}
return false;
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
{
if (a_RelPos.y <= 0)
if (a_Position.y <= 0)
{
return false;
}
BLOCKTYPE Surface = a_Chunk.GetBlock(a_RelPos.addedY(-1));
BLOCKTYPE Surface = a_Chunk.GetBlock(a_Position.addedY(-1));
if ((Surface != E_BLOCK_SAND) && (Surface != E_BLOCK_CACTUS))
{
// Cactus can only be placed on sand and itself
@ -78,7 +44,7 @@ private:
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
if (
a_Chunk.UnboundedRelGetBlock(a_RelPos + Coords[i], BlockType, BlockMeta) &&
a_Chunk.UnboundedRelGetBlock(a_Position + Coords[i], BlockType, BlockMeta) &&
(
cBlockInfo::IsSolid(BlockType) ||
(BlockType == E_BLOCK_LAVA) ||

View File

@ -25,27 +25,9 @@ public:
private:
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
a_BlockType = m_BlockType;
a_BlockMeta = a_Player.GetEquippedItem().m_ItemDamage & 0x0f;
return true;
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
{
return (a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) != E_BLOCK_AIR);
return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) != E_BLOCK_AIR);
}

View File

@ -18,184 +18,6 @@ public:
using Super::Super;
/** Translates player yaw when placing a chest into the chest block metadata. Valid for single chests only */
static NIBBLETYPE PlayerYawToMetaData(double a_Yaw)
{
a_Yaw += 90 + 45; // So its not aligned with axis
if (a_Yaw > 360.f)
{
a_Yaw -= 360.f;
}
if ((a_Yaw >= 0.f) && (a_Yaw < 90.f))
{
return 0x04;
}
else if ((a_Yaw >= 180) && (a_Yaw < 270))
{
return 0x05;
}
else if ((a_Yaw >= 90) && (a_Yaw < 180))
{
return 0x02;
}
else
{
return 0x03;
}
}
private:
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const override
{
// Cannot place right next to double-chest:
if (!CanBeAt(a_ChunkInterface, a_PlacedBlockPos))
{
// Yup, cannot form a triple-chest, refuse:
return false;
}
// Try to read double-chest information:
cBlockArea Area;
if (!Area.Read(a_ChunkInterface, a_PlacedBlockPos - Vector3i(1, 0, 1), a_PlacedBlockPos + Vector3i(1, 0, 1)))
{
return false;
}
// Get meta as if this was a single-chest:
if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta))
{
return false;
}
// Check if this forms a doublechest, if so, need to adjust the meta:
double yaw = a_Player.GetYaw();
if (
(Area.GetRelBlockType(0, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(2, 0, 1) == m_BlockType)
)
{
a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3;
return true;
}
if (
(Area.GetRelBlockType(1, 0, 0) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 2) == m_BlockType)
)
{
a_BlockMeta = (yaw < 0) ? 4 : 5;
return true;
}
return true;
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
{
auto BlockPos = a_Chunk.RelativeToAbsolute(a_RelPos);
return CanBeAt(a_ChunkInterface, BlockPos);
}
bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos) const
{
cBlockArea Area;
if (!Area.Read(a_ChunkInterface, a_BlockPos - Vector3i(2, 0, 2), a_BlockPos + Vector3i(2, 0, 2)))
{
// Cannot read the surroundings, probably at the edge of loaded chunks. Disallow.
return false;
}
int NumChestNeighbors = 0;
if (Area.GetRelBlockType(1, 0, 2) == m_BlockType)
{
if (
(Area.GetRelBlockType(0, 0, 2) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 3) == m_BlockType)
)
{
// Already a doublechest neighbor, disallow:
return false;
}
NumChestNeighbors += 1;
}
if (Area.GetRelBlockType(3, 0, 2) == m_BlockType)
{
if (
(Area.GetRelBlockType(4, 0, 2) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 3) == m_BlockType)
)
{
// Already a doublechest neighbor, disallow:
return false;
}
NumChestNeighbors += 1;
}
if (Area.GetRelBlockType(2, 0, 1) == m_BlockType)
{
if (
(Area.GetRelBlockType(2, 0, 0) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 1) == m_BlockType)
)
{
// Already a doublechest neighbor, disallow:
return false;
}
NumChestNeighbors += 1;
}
if (Area.GetRelBlockType(2, 0, 3) == m_BlockType)
{
if (
(Area.GetRelBlockType(2, 0, 4) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 3) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 3) == m_BlockType)
)
{
// Already a doublechest neighbor, disallow:
return false;
}
NumChestNeighbors += 1;
}
return (NumChestNeighbors < 2);
}
/** 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) const
{
if (a_Area.GetRelBlockType(a_RelX, 0, a_RelZ) != m_BlockType)
{
return false;
}
a_ChunkInterface.SetBlockMeta(a_Area.GetOriginX() + a_RelX, a_Area.GetOriginY(), a_Area.GetOriginZ() + a_RelZ, a_NewMeta);
return true;
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
{
@ -203,7 +25,3 @@ private:
return 13;
}
} ;

View File

@ -36,11 +36,11 @@ public:
private:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
// Check that we're attached to a jungle log block:
eBlockFace BlockFace = MetaToBlockFace(a_Chunk.GetMeta(a_RelPos));
auto LogPos = AddFaceDirection(a_RelPos, BlockFace, true);
eBlockFace BlockFace = MetaToBlockFace(a_Meta);
auto LogPos = AddFaceDirection(a_Position, BlockFace, true);
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
a_Chunk.UnboundedRelGetBlock(LogPos, BlockType, BlockMeta);

View File

@ -152,16 +152,16 @@ private:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
if (a_RelPos.y <= 0)
if (a_Position.y <= 0)
{
return false;
}
BLOCKTYPE BelowBlock;
NIBBLETYPE BelowBlockMeta;
a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BelowBlock, BelowBlockMeta);
a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta);
if (cBlockInfo::FullyOccupiesVoxel(BelowBlock))
{

View File

@ -116,9 +116,9 @@ private:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
return ((a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) == E_BLOCK_FARMLAND));
return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_FARMLAND);
}

View File

@ -18,7 +18,7 @@ public:
private:
virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override
virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override
{
return true;
}
@ -27,14 +27,14 @@ private:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
if (a_RelPos.y <= 0)
if (a_Position.y <= 0)
{
return false;
}
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelPos.addedY(-1));
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_Position.addedY(-1));
switch (BelowBlock)
{
case E_BLOCK_CLAY:

View File

@ -11,6 +11,8 @@
class cBlockDoorHandler final :
public cYawRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x01, 0x02>
{
@ -43,25 +45,6 @@ public:
}
}
static bool CanReplaceBlock(BLOCKTYPE a_BlockType)
{
switch (a_BlockType)
{
case E_BLOCK_AIR:
case E_BLOCK_TALL_GRASS:
case E_BLOCK_WATER:
case E_BLOCK_STATIONARY_WATER:
case E_BLOCK_LAVA:
case E_BLOCK_STATIONARY_LAVA:
case E_BLOCK_SNOW:
case E_BLOCK_FIRE:
{
return true;
}
}
return false;
}
/** Returns a vector pointing one block in the direction the door is facing (where the outside is). */
inline static Vector3i GetRelativeDirectionToOutside(NIBBLETYPE a_BlockMeta)
{
@ -167,38 +150,6 @@ private:
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) const override;
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) const override;
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) const override;
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const override
{
// If clicking a bottom face, place the door one block lower:
auto PlacedPos = a_PlacedBlockPos;
if (a_ClickedBlockFace == BLOCK_FACE_BOTTOM)
{
PlacedPos.y--;
}
if (
!CanReplaceBlock(a_ChunkInterface.GetBlock(PlacedPos)) ||
!CanReplaceBlock(a_ChunkInterface.GetBlock(PlacedPos.addedY(1)))
)
{
return false;
}
return Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, PlacedPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta);
}
virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) const override;
@ -237,9 +188,17 @@ private:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
return ((a_RelPos.y > 0) && CanBeOn(a_Chunk.GetBlock(a_RelPos.addedY(-1)), a_Chunk.GetMeta(a_RelPos.addedY(-1))));
// 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.
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);
}

View File

@ -8,19 +8,19 @@
class cBlockEndPortalFrameHandler final :
public cMetaRotator<cBlockHandler, 0x03,
E_META_END_PORTAL_FRAME_ZM,
E_META_END_PORTAL_FRAME_XP,
public cYawRotator<cBlockHandler, 0x03,
E_META_END_PORTAL_FRAME_ZP,
E_META_END_PORTAL_FRAME_XM
E_META_END_PORTAL_FRAME_XM,
E_META_END_PORTAL_FRAME_ZM,
E_META_END_PORTAL_FRAME_XP
>
{
using Super = cMetaRotator<
using Super = cYawRotator<
cBlockHandler, 0x03,
E_META_END_PORTAL_FRAME_ZM,
E_META_END_PORTAL_FRAME_XP,
E_META_END_PORTAL_FRAME_ZP,
E_META_END_PORTAL_FRAME_XM
E_META_END_PORTAL_FRAME_XM,
E_META_END_PORTAL_FRAME_ZM,
E_META_END_PORTAL_FRAME_XP
>;
public:
@ -29,54 +29,6 @@ public:
private:
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const override
{
a_BlockType = m_BlockType;
a_BlockMeta = YawToMetaData(a_Player.GetYaw());
return true;
}
inline static NIBBLETYPE YawToMetaData(double a_Rotation)
{
a_Rotation += 90 + 45; // So its not aligned with axis
if (a_Rotation > 360)
{
a_Rotation -= 360;
}
if ((a_Rotation >= 0) && (a_Rotation < 90))
{
return E_META_END_PORTAL_FRAME_XM;
}
else if ((a_Rotation >= 180) && (a_Rotation < 270))
{
return E_META_END_PORTAL_FRAME_XP;
}
else if ((a_Rotation >= 90) && (a_Rotation < 180))
{
return E_META_END_PORTAL_FRAME_ZM;
}
else
{
return E_META_END_PORTAL_FRAME_ZP;
}
}
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) const override
{
// E_META_END_PORTAL_FRAME_EYE is the bit which signifies the eye of ender is in it.
@ -237,16 +189,6 @@ private:
virtual bool IsClickedThrough(void) const override
{
// TODO: Colision
return true;
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
{
UNUSED(a_Meta);

View File

@ -65,14 +65,6 @@ private:
}
virtual bool IsClickedThrough(void) const override
{
return true;
}
/** Traces along YP until it finds an obsidian block, returns Y difference or 0 if no portal, and -1 for border
Takes the X, Y, and Z of the base block; with an optional MaxY for portal border finding */
static int FindObsidianCeiling(int X, int Y, int Z, cChunkInterface & a_ChunkInterface, int MaxY = 0)
@ -256,7 +248,7 @@ private:
return (FoundFrameZP && FoundFrameZM);
}
virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override
virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override
{
return true;
}

View File

@ -28,9 +28,9 @@ private:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
return ((a_RelPos.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelPos.addedY(-1))));
return (a_Position.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_Position.addedY(-1)));
}

View File

@ -32,7 +32,7 @@ private:
virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override
virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override
{
return true;
}

View File

@ -456,24 +456,6 @@ namespace
////////////////////////////////////////////////////////////////////////////////
// cBlockHandler:
bool cBlockHandler::GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
const Vector3i a_ClickedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const
{
// By default, all blocks can be placed and the meta is copied over from the item's damage value:
a_BlockType = m_BlockType;
a_BlockMeta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage & 0x0f);
return true;
}
void cBlockHandler::OnUpdate(
cChunkInterface & a_ChunkInterface,
cWorldInterface & a_WorldInterface,
@ -490,7 +472,7 @@ void cBlockHandler::OnUpdate(
void cBlockHandler::OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) const
{
if (a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk) { return CanBeAt(a_ChunkInterface, cChunkDef::AbsoluteToRelative(a_BlockPos), a_Chunk); }))
if (a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk) { return CanBeAt(a_Chunk, cChunkDef::AbsoluteToRelative(a_BlockPos), a_Chunk.GetMeta(cChunkDef::AbsoluteToRelative(a_BlockPos))); }))
{
return;
}
@ -528,7 +510,7 @@ cItems cBlockHandler::ConvertToPickups(NIBBLETYPE a_BlockMeta, const cItem * con
bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const
bool cBlockHandler::CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const
{
return true;
}
@ -546,18 +528,9 @@ bool cBlockHandler::IsUseable() const
bool cBlockHandler::IsClickedThrough(void) const
bool cBlockHandler::DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const
{
return false;
}
bool cBlockHandler::DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const
{
return (m_BlockType == E_BLOCK_AIR);
return m_BlockType == E_BLOCK_AIR;
}

View File

@ -14,6 +14,7 @@ class cPlayer;
class cChunk;
class cBlockPluginInterface;
class cChunkInterface;
class cWorld;
class cWorldInterface;
class cItems;
@ -45,22 +46,6 @@ public:
blocktype of the minus-X neighbor, the positive-X neighbor, etc. */
virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) const;
/** Called before a block is placed into a world by player, by cItemHandler::GetPlacementBlockTypeMeta().
The handler should return true to allow placement, false to refuse.
a_PlacedBlockPos is the coords of the block being placed
a_ClickedBlockFace is the face of the neighbor block clicked by the client to place this block.
a_CursorPos is the position of the cursor within the neighbor's face
The descendant handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block.
The default handler uses the stored block type and meta copied from the lowest 4 bits of the player's equipped item's damage value. */
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const;
/** Called by cWorld::SetBlock() after the block has been set */
virtual void OnPlaced(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
@ -68,11 +53,6 @@ public:
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) const {}
/** 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
) const {}
/** Called after a block gets broken (replaced with air), by natural means.
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.
@ -142,11 +122,7 @@ public:
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, const cItem * a_Tool = nullptr) const;
/** Checks if the block can stay at the specified relative coords in the chunk */
virtual bool CanBeAt(
cChunkInterface & a_ChunkInterface,
const Vector3i a_RelPos,
const cChunk & a_Chunk
) const;
virtual bool CanBeAt(const cChunk & a_Chunk, Vector3i a_Position, NIBBLETYPE a_Meta) const;
/** Checks whether the block has an effect on growing the plant */
virtual bool CanSustainPlant(BLOCKTYPE a_Plant) const { return false; }
@ -155,16 +131,12 @@ public:
If it returns true, OnUse() is called */
virtual bool IsUseable(void) const;
/** Indicates whether the client will click through this block.
For example digging a fire will hit the block below the fire so fire is clicked through. */
virtual bool IsClickedThrough(void) const;
/** Checks if the player can build "inside" this block.
For example blocks placed "on" snow will be placed at the same position. So: Snow ignores Build collision
@param a_Pos Position of the block
@param a_Player Player trying to build on the block
@param a_Meta Meta value of the block currently at a_Pos */
virtual bool DoesIgnoreBuildCollision(cChunkInterface & ChunkInterface, const Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const;
virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, Vector3i a_Position, NIBBLETYPE a_Meta, eBlockFace a_ClickedBlockFace, bool a_ClickedDirectly) const;
/** Tests if a_RelPosition is inside the block, where a_RelPosition is relative to the origin of the block.
Coords in a_RelPosition are guaranteed to be in the [0..1] range. */

View File

@ -8,9 +8,9 @@
class cBlockHopperHandler final :
public cPitchYawRotator<cClearMetaOnDrop<cBlockEntityHandler>>
public cClearMetaOnDrop<cMetaRotator<cBlockEntityHandler, 0x7, E_META_HOPPER_FACING_ZP, E_META_HOPPER_FACING_XM, E_META_HOPPER_FACING_ZM, E_META_HOPPER_FACING_XP>>
{
using Super = cPitchYawRotator<cClearMetaOnDrop<cBlockEntityHandler>>;
using Super = cClearMetaOnDrop<cMetaRotator<cBlockEntityHandler, 0x7, E_META_HOPPER_FACING_ZP, E_META_HOPPER_FACING_XM, E_META_HOPPER_FACING_ZM, E_META_HOPPER_FACING_XP>>;
public:
@ -18,42 +18,9 @@ public:
private:
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const override
{
a_BlockType = m_BlockType;
// Convert the blockface into meta:
switch (a_ClickedBlockFace)
{
case BLOCK_FACE_BOTTOM: a_BlockMeta = E_META_HOPPER_FACING_YM; break;
case BLOCK_FACE_TOP: a_BlockMeta = E_META_HOPPER_FACING_YM; break;
case BLOCK_FACE_EAST: a_BlockMeta = E_META_HOPPER_FACING_XM; break;
case BLOCK_FACE_NORTH: a_BlockMeta = E_META_HOPPER_FACING_ZP; break;
case BLOCK_FACE_SOUTH: a_BlockMeta = E_META_HOPPER_FACING_ZM; break;
case BLOCK_FACE_WEST: a_BlockMeta = E_META_HOPPER_FACING_XP; break;
case BLOCK_FACE_NONE: a_BlockMeta = E_META_HOPPER_UNATTACHED; break;
}
return true;
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
{
UNUSED(a_Meta);
return 11;
}
} ;

View File

@ -2,6 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "BlockInfo.h"
#include "Mixins.h"
@ -17,59 +18,24 @@ public:
using Super::Super;
/** Returns true if the ladder will be supported by the block through the given blockface. */
static bool CanBePlacedOn(const BLOCKTYPE a_BlockType, const eBlockFace a_BlockFace)
{
if (
(a_BlockFace == BLOCK_FACE_NONE) ||
(a_BlockFace == BLOCK_FACE_BOTTOM) ||
(a_BlockFace == BLOCK_FACE_TOP)
)
{
return false;
}
return cBlockInfo::IsSolid(a_BlockType);
}
private:
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const override
{
// Try finding a suitable neighbor block face for the ladder; start with the given one.
if (!LadderCanBePlacedAt(a_ChunkInterface, a_PlacedBlockPos, a_ClickedBlockFace))
{
a_ClickedBlockFace = FindSuitableBlockFace(a_ChunkInterface, a_PlacedBlockPos);
if (a_ClickedBlockFace == BLOCK_FACE_NONE)
{
return false;
}
}
a_BlockType = m_BlockType;
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
return true;
}
/** Converts the block face of the neighbor to which the ladder is attached to the ladder block's meta. */
static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace)
{
switch (a_NeighborBlockFace)
{
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_NONE:
case BLOCK_FACE_YM:
case BLOCK_FACE_YP:
{
return 0x2;
}
}
UNREACHABLE("Unsupported neighbor block face");
}
/** Converts the ladder block's meta to the block face of the neighbor to which the ladder is attached. */
static eBlockFace MetaDataToBlockFace(NIBBLETYPE a_MetaData)
{
@ -87,51 +53,13 @@ private:
/** Finds a suitable block face value for the Ladder.
The returned value is the block face of the neighbor of the specified block to which a ladder at a_LadderPos can be attached.
Returns BLOCK_FACE_NONE if no valid location is found */
static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, const Vector3i a_LadderPos)
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
for (int FaceInt = BLOCK_FACE_ZM; FaceInt <= BLOCK_FACE_XP; FaceInt++)
{
eBlockFace Face = static_cast<eBlockFace>(FaceInt);
if (LadderCanBePlacedAt(a_ChunkInterface, a_LadderPos, Face))
{
return Face;
}
}
return BLOCK_FACE_NONE;
}
/** Returns true if the ladder in the specified position will be supported by its neghbor through the specified neighbor's blockface. */
static bool LadderCanBePlacedAt(cChunkInterface & a_ChunkInterface, const Vector3i a_LadderPos, eBlockFace a_NeighborBlockFace)
{
if (
(a_NeighborBlockFace == BLOCK_FACE_NONE) ||
(a_NeighborBlockFace == BLOCK_FACE_BOTTOM) ||
(a_NeighborBlockFace == BLOCK_FACE_TOP)
)
{
return false;
}
auto NeighborPos = AddFaceDirection(a_LadderPos, a_NeighborBlockFace, true);
return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock(NeighborPos));
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
{
auto NeighborBlockFace = MetaDataToBlockFace(a_Chunk.GetMeta(a_RelPos));
auto LadderAbsPos = a_Chunk.RelativeToAbsolute(a_RelPos);
return LadderCanBePlacedAt(a_ChunkInterface, LadderAbsPos, NeighborBlockFace);
auto Face = MetaDataToBlockFace(a_Meta);
auto NeighborRelPos = AddFaceDirection(a_Position, Face, true);
BLOCKTYPE NeighborBlockType;
a_Chunk.UnboundedRelGetBlockType(NeighborRelPos, NeighborBlockType);
return CanBePlacedOn(NeighborBlockType, Face);
}

View File

@ -64,45 +64,6 @@ private:
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface,
cPlayer & a_Player,
const Vector3i a_PlacedBlockPos,
eBlockFace a_ClickedBlockFace,
const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) const override
{
a_BlockType = m_BlockType;
a_BlockMeta = LeverDirectionToMetaData(a_ClickedBlockFace);
return true;
}
/** Converts the block face of the neighbor to which the lever is attached to the lever block's meta. */
inline static NIBBLETYPE LeverDirectionToMetaData(eBlockFace a_Dir)
{
// Determine lever direction:
switch (a_Dir)
{
case BLOCK_FACE_YP: return 0x6;
case BLOCK_FACE_XP: return 0x1;
case BLOCK_FACE_XM: return 0x2;
case BLOCK_FACE_ZP: return 0x3;
case BLOCK_FACE_ZM: return 0x4;
case BLOCK_FACE_YM: return 0x0;
case BLOCK_FACE_NONE: return 0x6;
}
UNREACHABLE("Unsupported block face");
}
/** Converts the leve block's meta to the block face of the neighbor to which the lever is attached. */
inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta)
{
@ -128,18 +89,18 @@ private:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
{
// Find the type of block the lever is attached to:
auto Meta = a_Chunk.GetMeta(a_RelPos);
auto NeighborFace = BlockMetaDataToBlockFace(Meta);
auto NeighborPos = AddFaceDirection(a_RelPos, NeighborFace, true);
auto NeighborFace = BlockMetaDataToBlockFace(a_Meta);
auto NeighborPos = AddFaceDirection(a_Position, NeighborFace, true);
if (!cChunkDef::IsValidHeight(NeighborPos.y))
{
return false;
}
BLOCKTYPE NeighborBlockType;
if (!a_Chunk.UnboundedRelGetBlock(NeighborPos, NeighborBlockType, Meta))
NIBBLETYPE NeighborMeta;
if (!a_Chunk.UnboundedRelGetBlock(NeighborPos, NeighborBlockType, NeighborMeta))
{
return false;
}
@ -152,8 +113,8 @@ private:
else if (cBlockSlabHandler::IsAnySlabType(NeighborBlockType))
{
return (
(((Meta & 0x08) == 0x08) && (NeighborFace == BLOCK_FACE_TOP)) ||
</