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:
parent
34bf5c0d9d
commit
a62b2b1be2
@ -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,
|
||||
|
@ -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__
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) ||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)) ||
|
||||