2019-10-16 04:06:34 -04:00
|
|
|
// Mixins.h
|
|
|
|
|
|
|
|
// Provides various mixins for easier cBlockHandler descendant implementations
|
|
|
|
|
|
|
|
/* The general use case is to derive a handler from these mixins, providing a suitable base to them:
|
|
|
|
class cBlockAir: public cBlockWithNoDrops<cBlockHandler>;
|
|
|
|
class cBlockLadder: public cMetaRotator<cClearMetaOnDrop, ...>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "../Item.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it:
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(disable: 4127) // Conditional expression is constant
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Mixin to clear the block's meta value when converting to a pickup. */
|
|
|
|
template <class Base>
|
2020-10-05 06:27:14 -04:00
|
|
|
class cClearMetaOnDrop :
|
2019-10-16 04:06:34 -04:00
|
|
|
public Base
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
constexpr cClearMetaOnDrop(BLOCKTYPE a_BlockType):
|
2019-10-16 04:06:34 -04:00
|
|
|
Base(a_BlockType)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-10-05 06:27:14 -04:00
|
|
|
protected:
|
|
|
|
|
|
|
|
~cClearMetaOnDrop() = default;
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
private:
|
2019-10-16 04:06:34 -04:00
|
|
|
|
2021-03-28 09:41:34 -04:00
|
|
|
virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override
|
2019-10-16 04:06:34 -04:00
|
|
|
{
|
|
|
|
// Reset the meta to zero:
|
|
|
|
return cItem(this->m_BlockType);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Mixin for rotations and reflections following the standard pattern of "apply mask, then use a switch".
|
|
|
|
Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West.
|
|
|
|
There is also an aptional parameter AssertIfNotMatched, set this if it is invalid for a block to exist in any other state. */
|
|
|
|
template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched = false>
|
2020-10-05 06:27:14 -04:00
|
|
|
class cMetaRotator :
|
2019-10-16 04:06:34 -04:00
|
|
|
public Base
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
constexpr cMetaRotator(BLOCKTYPE a_BlockType):
|
2019-10-16 04:06:34 -04:00
|
|
|
Base(a_BlockType)
|
2020-09-20 09:50:52 -04:00
|
|
|
{
|
|
|
|
}
|
2019-10-16 04:06:34 -04:00
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
protected:
|
2019-10-16 04:06:34 -04:00
|
|
|
|
2020-10-05 06:27:14 -04:00
|
|
|
~cMetaRotator() = default;
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) const override
|
2019-10-16 04:06:34 -04:00
|
|
|
{
|
|
|
|
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
|
|
|
|
switch (a_Meta & BitMask)
|
|
|
|
{
|
|
|
|
case South: return East | OtherMeta;
|
|
|
|
case East: return North | OtherMeta;
|
|
|
|
case North: return West | OtherMeta;
|
|
|
|
case West: return South | OtherMeta;
|
|
|
|
}
|
|
|
|
if (AssertIfNotMatched)
|
|
|
|
{
|
|
|
|
ASSERT(!"Invalid Meta value");
|
|
|
|
}
|
|
|
|
return a_Meta;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) const override
|
2019-10-16 04:06:34 -04:00
|
|
|
{
|
|
|
|
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
|
|
|
|
switch (a_Meta & BitMask)
|
|
|
|
{
|
|
|
|
case South: return West | OtherMeta;
|
|
|
|
case West: return North | OtherMeta;
|
|
|
|
case North: return East | OtherMeta;
|
|
|
|
case East: return South | OtherMeta;
|
|
|
|
}
|
|
|
|
if (AssertIfNotMatched)
|
|
|
|
{
|
|
|
|
ASSERT(!"Invalid Meta value");
|
|
|
|
}
|
|
|
|
return a_Meta;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) const override
|
2019-10-16 04:06:34 -04:00
|
|
|
{
|
|
|
|
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
|
|
|
|
switch (a_Meta & BitMask)
|
|
|
|
{
|
|
|
|
case South: return North | OtherMeta;
|
|
|
|
case North: return South | OtherMeta;
|
|
|
|
}
|
|
|
|
// Not Facing North or South; No change.
|
|
|
|
return a_Meta;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) const override
|
2019-10-16 04:06:34 -04:00
|
|
|
{
|
|
|
|
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
|
|
|
|
switch (a_Meta & BitMask)
|
|
|
|
{
|
|
|
|
case West: return East | OtherMeta;
|
|
|
|
case East: return West | OtherMeta;
|
|
|
|
}
|
|
|
|
// Not Facing East or West; No change.
|
|
|
|
return a_Meta;
|
|
|
|
}
|
|
|
|
};
|
2020-04-08 16:35:08 -04:00
|
|
|
|
|
|
|
|
2020-04-09 17:49:10 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
2020-04-09 16:18:45 -04:00
|
|
|
/** Mixin for blocks whose meta on placement depends on the yaw of the player placing the block. BitMask
|
|
|
|
selects the direction bits from the block's meta values. */
|
2020-04-09 17:52:41 -04:00
|
|
|
template <
|
|
|
|
class Base,
|
2020-04-10 07:25:36 -04:00
|
|
|
NIBBLETYPE BitMask = 0x07,
|
|
|
|
NIBBLETYPE North = 0x02,
|
|
|
|
NIBBLETYPE East = 0x05,
|
|
|
|
NIBBLETYPE South = 0x03,
|
|
|
|
NIBBLETYPE West = 0x04,
|
2020-04-09 17:52:41 -04:00
|
|
|
bool AssertIfNotMatched = false
|
|
|
|
>
|
2020-10-05 06:27:14 -04:00
|
|
|
class cYawRotator :
|
2020-04-08 16:35:08 -04:00
|
|
|
public cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>
|
|
|
|
{
|
2020-04-13 12:38:06 -04:00
|
|
|
using Super = cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>;
|
2020-04-08 16:35:08 -04:00
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
public:
|
2020-04-08 16:35:08 -04:00
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
using Super::Super;
|
2020-04-08 16:35:08 -04:00
|
|
|
|
2020-04-09 17:49:10 -04:00
|
|
|
|
2020-04-09 17:47:47 -04:00
|
|
|
/** Converts the rotation value as returned by cPlayer::GetYaw() to the appropriate metadata
|
2021-05-14 05:42:08 -04:00
|
|
|
value for a block placed by a player facing that way. */
|
2020-04-08 16:35:08 -04:00
|
|
|
static NIBBLETYPE YawToMetaData(double a_Rotation)
|
|
|
|
{
|
2020-04-10 12:52:59 -04:00
|
|
|
if ((a_Rotation >= -135) && (a_Rotation < -45))
|
2020-04-08 16:35:08 -04:00
|
|
|
{
|
2020-04-10 12:52:59 -04:00
|
|
|
return East;
|
2020-04-08 16:35:08 -04:00
|
|
|
}
|
2020-04-10 12:52:59 -04:00
|
|
|
else if ((a_Rotation >= -45) && (a_Rotation < 45))
|
2020-04-08 16:35:08 -04:00
|
|
|
{
|
2020-04-10 12:52:59 -04:00
|
|
|
return South;
|
2020-04-08 16:35:08 -04:00
|
|
|
}
|
2020-04-10 12:52:59 -04:00
|
|
|
else if ((a_Rotation >= 45) && (a_Rotation < 135))
|
2020-04-08 16:35:08 -04:00
|
|
|
{
|
2020-04-10 12:52:59 -04:00
|
|
|
return West;
|
2020-04-08 16:35:08 -04:00
|
|
|
}
|
2020-04-10 12:52:59 -04:00
|
|
|
else // degrees jumping from 180 to -180
|
2020-04-08 16:35:08 -04:00
|
|
|
{
|
2020-04-10 12:52:59 -04:00
|
|
|
return North;
|
2020-04-08 16:35:08 -04:00
|
|
|
}
|
|
|
|
}
|
2020-10-05 06:27:14 -04:00
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
~cYawRotator() = default;
|
2020-04-08 16:35:08 -04:00
|
|
|
};
|
|
|
|
|
2020-04-09 17:49:10 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-05-14 05:42:08 -04:00
|
|
|
/** Mixin for blocks whose meta on placement depends on the relative position of the player to the block in
|
|
|
|
addition to the yaw of the player placing the block. BitMask selects the direction bits from the block's meta values. */
|
2020-04-09 17:52:41 -04:00
|
|
|
template <
|
|
|
|
class Base,
|
2020-04-10 07:25:36 -04:00
|
|
|
NIBBLETYPE BitMask = 0x07,
|
|
|
|
NIBBLETYPE North = 0x02,
|
|
|
|
NIBBLETYPE East = 0x05,
|
|
|
|
NIBBLETYPE South = 0x03,
|
|
|
|
NIBBLETYPE West = 0x04,
|
2020-04-10 19:20:51 -04:00
|
|
|
NIBBLETYPE Up = 0x00,
|
|
|
|
NIBBLETYPE Down = 0x01
|
2020-04-09 17:52:41 -04:00
|
|
|
>
|
2021-05-14 05:42:08 -04:00
|
|
|
class cDisplacementYawRotator:
|
2020-04-08 16:35:08 -04:00
|
|
|
public cYawRotator<Base, BitMask, North, East, South, West>
|
|
|
|
{
|
2020-04-13 12:38:06 -04:00
|
|
|
using Super = cYawRotator<Base, BitMask, North, East, South, West>;
|
2020-04-21 16:19:22 -04:00
|
|
|
|
2020-04-08 16:35:08 -04:00
|
|
|
public:
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
using Super::Super;
|
2020-04-08 16:35:08 -04:00
|
|
|
|
2020-10-05 06:27:14 -04:00
|
|
|
|
2021-05-14 05:42:08 -04:00
|
|
|
/** Converts the placement position, eye position as returned by cPlayer::GetEyePosition(), and
|
|
|
|
rotation value as returned by cPlayer::GetYaw() to the appropriate metadata value for a block placed by a player facing that way. */
|
|
|
|
static NIBBLETYPE DisplacementYawToMetaData(const Vector3d a_PlacePosition, const Vector3d a_EyePosition, const double a_Rotation)
|
2020-04-08 16:35:08 -04:00
|
|
|
{
|
2021-05-14 05:42:08 -04:00
|
|
|
if (
|
|
|
|
const auto Displacement = a_EyePosition - a_PlacePosition.addedXZ(0.5, 0.5);
|
|
|
|
(std::abs(Displacement.x) < 2) && (std::abs(Displacement.z) < 2)
|
|
|
|
)
|
2021-05-05 09:25:10 -04:00
|
|
|
{
|
2021-05-14 05:42:08 -04:00
|
|
|
if (Displacement.y > 2)
|
|
|
|
{
|
|
|
|
return Up;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Displacement.y < 0)
|
|
|
|
{
|
|
|
|
return Down;
|
|
|
|
}
|
2020-04-10 19:20:51 -04:00
|
|
|
}
|
2020-04-08 16:35:08 -04:00
|
|
|
|
2021-05-05 09:25:10 -04:00
|
|
|
return Super::YawToMetaData(a_Rotation);
|
2020-04-08 16:35:08 -04:00
|
|
|
}
|
|
|
|
|
2021-05-05 09:25:10 -04:00
|
|
|
protected:
|
2020-04-08 16:35:08 -04:00
|
|
|
|
2021-05-14 05:42:08 -04:00
|
|
|
~cDisplacementYawRotator() = default;
|
2020-04-08 16:35:08 -04:00
|
|
|
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) const override
|
2020-04-08 16:35:08 -04:00
|
|
|
{
|
|
|
|
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
|
|
|
|
switch (a_Meta & BitMask)
|
|
|
|
{
|
|
|
|
case Down: return Up | OtherMeta; // Down -> Up
|
|
|
|
case Up: return Down | OtherMeta; // Up -> Down
|
|
|
|
}
|
|
|
|
// Not Facing Up or Down; No change.
|
|
|
|
return a_Meta;
|
|
|
|
}
|
|
|
|
};
|