Refactored block placement workflow.
Multi-blocks can now use the default OnPlayerPlaced() callback in cItemHandler.
This commit is contained in:
parent
4ce8bebfd8
commit
3889b2cac2
@ -25,10 +25,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnPlayerPlace(
|
virtual bool GetBlocksToPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||||
|
sSetBlockVector & a_BlocksToPlace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// Can only be placed on the floor:
|
// Can only be placed on the floor:
|
||||||
@ -36,12 +37,10 @@ public:
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
|
||||||
|
|
||||||
// The "foot" block:
|
// The "foot" block:
|
||||||
sSetBlockVector blks;
|
|
||||||
NIBBLETYPE BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player.GetYaw());
|
NIBBLETYPE BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player.GetYaw());
|
||||||
blks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BED, BlockMeta);
|
a_BlocksToPlace.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BED, BlockMeta);
|
||||||
|
|
||||||
// Check if there is empty space for the "head" block:
|
// Check if there is empty space for the "head" block:
|
||||||
// (Vanilla only allows beds to be placed into air)
|
// (Vanilla only allows beds to be placed into air)
|
||||||
@ -50,10 +49,8 @@ public:
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
blks.emplace_back(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, BlockMeta | 0x08);
|
a_BlocksToPlace.emplace_back(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, BlockMeta | 0x08);
|
||||||
|
return true;
|
||||||
// Place both bed blocks:
|
|
||||||
return a_Player.PlaceBlocks(blks);
|
|
||||||
}
|
}
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
@ -27,10 +27,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnPlayerPlace(
|
virtual bool GetBlocksToPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||||
|
sSetBlockVector & a_BlocksToSet
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// Can only be placed on the floor:
|
// Can only be placed on the floor:
|
||||||
@ -38,16 +39,14 @@ public:
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
|
||||||
|
|
||||||
// Place both blocks atomically:
|
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||||
sSetBlockVector blks;
|
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07);
|
||||||
blks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07);
|
|
||||||
if (a_BlockY < cChunkDef::Height - 1)
|
if (a_BlockY < cChunkDef::Height - 1)
|
||||||
{
|
{
|
||||||
blks.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_BIG_FLOWER, (a_EquippedItem.m_ItemDamage & 0x07) | 0x08);
|
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_BIG_FLOWER, (a_EquippedItem.m_ItemDamage & 0x07) | 0x08);
|
||||||
}
|
}
|
||||||
return a_Player.PlaceBlocks(blks);
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,6 +27,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** We need an OnPlayerPlace override because we're processing neighbor chests and changing their metas,
|
||||||
|
the parent class cannot do that. */
|
||||||
virtual bool OnPlayerPlace(
|
virtual bool OnPlayerPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||||
@ -118,34 +120,32 @@ public:
|
|||||||
} // for j
|
} // for j
|
||||||
} // for i
|
} // for i
|
||||||
|
|
||||||
// If there's no chest neighbor, place the single block chest and bail out:
|
// Get the meta of the placed chest; take existing neighbors into account:
|
||||||
BLOCKTYPE ChestBlockType = static_cast<BLOCKTYPE>(m_ItemType);
|
BLOCKTYPE ChestBlockType = static_cast<BLOCKTYPE>(m_ItemType);
|
||||||
if (NeighborIdx < 0)
|
NIBBLETYPE Meta;
|
||||||
|
auto yaw = a_Player.GetYaw();
|
||||||
|
switch (NeighborIdx)
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta = cBlockChestHandler::PlayerYawToMetaData(a_Player.GetYaw());
|
case 0:
|
||||||
return a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, ChestBlockType, Meta);
|
case 2:
|
||||||
}
|
|
||||||
|
|
||||||
// There is a neighbor to which we need to adjust
|
|
||||||
double yaw = a_Player.GetYaw();
|
|
||||||
if ((NeighborIdx == 0) || (NeighborIdx == 2))
|
|
||||||
{
|
|
||||||
// The neighbor is in the X axis, form a X-axis-aligned dblchest:
|
|
||||||
NIBBLETYPE Meta = ((yaw >= -90) && (yaw < 90)) ? E_META_CHEST_FACING_ZM : E_META_CHEST_FACING_ZP;
|
|
||||||
|
|
||||||
// Place the new chest:
|
|
||||||
if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, ChestBlockType, Meta))
|
|
||||||
{
|
{
|
||||||
return false;
|
// The neighbor is in the X axis, form a X-axis-aligned dblchest:
|
||||||
|
Meta = ((yaw >= -90) && (yaw < 90)) ? E_META_CHEST_FACING_ZM : E_META_CHEST_FACING_ZP;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case 1:
|
||||||
// Adjust the existing chest:
|
case 3:
|
||||||
a_World.FastSetBlock(a_BlockX + CrossCoords[NeighborIdx].x, a_BlockY, a_BlockZ + CrossCoords[NeighborIdx].z, ChestBlockType, Meta);
|
{
|
||||||
return true;
|
// The neighbor is in the Z axis, form a Z-axis-aligned dblchest:
|
||||||
}
|
Meta = (yaw < 0) ? E_META_CHEST_FACING_XM : E_META_CHEST_FACING_XP;
|
||||||
|
break;
|
||||||
// The neighbor is in the Z axis, form a Z-axis-aligned dblchest:
|
}
|
||||||
NIBBLETYPE Meta = (yaw < 0) ? E_META_CHEST_FACING_XM : E_META_CHEST_FACING_XP;
|
default:
|
||||||
|
{
|
||||||
|
Meta = cBlockChestHandler::PlayerYawToMetaData(yaw);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // switch (NeighborIdx)
|
||||||
|
|
||||||
// Place the new chest:
|
// Place the new chest:
|
||||||
if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, ChestBlockType, Meta))
|
if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, ChestBlockType, Meta))
|
||||||
@ -153,8 +153,31 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust the existing chest:
|
// Adjust the existing chest, if any:
|
||||||
a_World.FastSetBlock(a_BlockX + CrossCoords[NeighborIdx].x, a_BlockY, a_BlockZ + CrossCoords[NeighborIdx].z, ChestBlockType, Meta);
|
if (NeighborIdx > 0)
|
||||||
|
{
|
||||||
|
a_World.FastSetBlock(a_BlockX + CrossCoords[NeighborIdx].x, a_BlockY, a_BlockZ + CrossCoords[NeighborIdx].z, ChestBlockType, Meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play the placement sound:
|
||||||
|
AString PlaceSound = cBlockInfo::GetPlaceSound(ChestBlockType);
|
||||||
|
float Volume = 1.0f, Pitch = 0.8f;
|
||||||
|
if (PlaceSound == "dig.metal")
|
||||||
|
{
|
||||||
|
Pitch = 1.2f;
|
||||||
|
PlaceSound = "dig.stone";
|
||||||
|
}
|
||||||
|
else if (PlaceSound == "random.anvil_land")
|
||||||
|
{
|
||||||
|
Volume = 0.65f;
|
||||||
|
}
|
||||||
|
a_World.BroadcastSoundEffect(PlaceSound, a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, Volume, Pitch);
|
||||||
|
|
||||||
|
// Remove the "placed" item:
|
||||||
|
if (a_Player.IsGameModeSurvival())
|
||||||
|
{
|
||||||
|
a_Player.GetInventory().RemoveOneEquippedItem();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,10 +20,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnPlayerPlace(
|
virtual bool GetBlocksToPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||||
|
sSetBlockVector & a_BlocksToSet
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// Vanilla only allows door placement while clicking on the top face of the block below the door:
|
// Vanilla only allows door placement while clicking on the top face of the block below the door:
|
||||||
@ -107,10 +108,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the blocks:
|
// Set the blocks:
|
||||||
sSetBlockVector blks;
|
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, LowerBlockMeta);
|
||||||
blks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, LowerBlockMeta);
|
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, BlockType, UpperBlockMeta);
|
||||||
blks.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, BlockType, UpperBlockMeta);
|
return true;
|
||||||
return a_Player.PlaceBlocks(blks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -367,37 +367,51 @@ bool cItemHandler::OnPlayerPlace(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BLOCKTYPE BlockType;
|
// Get all the blocks to place:
|
||||||
NIBBLETYPE BlockMeta;
|
sSetBlockVector blocks;
|
||||||
if (!GetPlacementBlockTypeMeta(&a_World, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
|
if (!GetBlocksToPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, blocks))
|
||||||
{
|
{
|
||||||
// Handler refused the placement, send that information back to the client:
|
// Handler refused the placement, send that information back to the client:
|
||||||
|
for (const auto & blk: blocks)
|
||||||
|
{
|
||||||
|
a_World.SendBlockTo(blk.GetX(), blk.GetY(), blk.GetZ(), &a_Player);
|
||||||
|
}
|
||||||
a_World.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, &a_Player);
|
a_World.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, &a_Player);
|
||||||
a_Player.GetInventory().SendEquippedSlot();
|
a_Player.GetInventory().SendEquippedSlot();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta))
|
// Try to place the blocks:
|
||||||
|
if (!a_Player.PlaceBlocks(blocks))
|
||||||
{
|
{
|
||||||
// The placement failed, the block has already been re-sent, re-send inventory:
|
// The placement failed, the blocks have already been re-sent, re-send inventory:
|
||||||
a_Player.GetInventory().SendEquippedSlot();
|
a_Player.GetInventory().SendEquippedSlot();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AString PlaceSound = cBlockInfo::GetPlaceSound(BlockType);
|
// Play the placement sound for the main block:
|
||||||
float Volume = 1.0f, Pitch = 0.8f;
|
for (const auto & blk: blocks)
|
||||||
if (PlaceSound == "dig.metal")
|
|
||||||
{
|
{
|
||||||
Pitch = 1.2f;
|
// Find the main block by comparing the coords:
|
||||||
PlaceSound = "dig.stone";
|
if ((blk.GetX() != a_BlockX) || (blk.GetY() != a_BlockY) || (blk.GetZ() != a_BlockZ))
|
||||||
}
|
{
|
||||||
else if (PlaceSound == "random.anvil_land")
|
continue;
|
||||||
{
|
}
|
||||||
Volume = 0.65f;
|
AString PlaceSound = cBlockInfo::GetPlaceSound(blk.m_BlockType);
|
||||||
}
|
float Volume = 1.0f, Pitch = 0.8f;
|
||||||
|
if (PlaceSound == "dig.metal")
|
||||||
a_World.BroadcastSoundEffect(PlaceSound, a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, Volume, Pitch);
|
{
|
||||||
|
Pitch = 1.2f;
|
||||||
|
PlaceSound = "dig.stone";
|
||||||
|
}
|
||||||
|
else if (PlaceSound == "random.anvil_land")
|
||||||
|
{
|
||||||
|
Volume = 0.65f;
|
||||||
|
}
|
||||||
|
a_World.BroadcastSoundEffect(PlaceSound, a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, Volume, Pitch);
|
||||||
|
break;
|
||||||
|
} // for blk - blocks[]
|
||||||
|
|
||||||
// Remove the "placed" item:
|
// Remove the "placed" item:
|
||||||
if (a_Player.IsGameModeSurvival())
|
if (a_Player.IsGameModeSurvival())
|
||||||
@ -411,6 +425,27 @@ bool cItemHandler::OnPlayerPlace(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cItemHandler::GetBlocksToPlace(
|
||||||
|
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||||
|
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||||
|
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||||
|
sSetBlockVector & a_BlocksToSet
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BLOCKTYPE BlockType;
|
||||||
|
NIBBLETYPE BlockMeta;
|
||||||
|
if (!GetPlacementBlockTypeMeta(&a_World, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cItemHandler::OnItemUse(
|
bool cItemHandler::OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||||
|
@ -35,8 +35,9 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
/** Called when the player tries to place the item (right mouse button, IsPlaceable() == true).
|
/** Called when the player tries to place the item (right mouse button, IsPlaceable() == true).
|
||||||
The default handler uses GetPlacementBlockTypeMeta and places the returned block.
|
The block coords are for the block that has been clicked.
|
||||||
Override this function for advanced behavior such as placing multiple blocks.
|
The default handler uses GetBlocksToPlace() and places the returned blocks.
|
||||||
|
Override if the item needs advanced processing, such as spawning a mob based on the blocks being placed.
|
||||||
If the block placement is refused inside this call, it will automatically revert the client-side changes.
|
If the block placement is refused inside this call, it will automatically revert the client-side changes.
|
||||||
Returns true if the placement succeeded, false if the placement was aborted for any reason. */
|
Returns true if the placement succeeded, false if the placement was aborted for any reason. */
|
||||||
virtual bool OnPlayerPlace(
|
virtual bool OnPlayerPlace(
|
||||||
@ -46,7 +47,20 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/** Called when the player right-clicks with this item and IsPlaceable() == true, and OnPlace() is not overridden.
|
/** Called from OnPlayerPlace() to determine the blocks that the current placement operation should set.
|
||||||
|
The block coords are where the new (main) block should be placed.
|
||||||
|
The default handler uses GetPlacementBlockTypeMeta() and provides that as the single block at the specified coords.
|
||||||
|
Returns true if the placement succeeded, false if the placement was aborted for any reason.
|
||||||
|
If aborted, the server then sends all original blocks in the coords provided in a_BlocksToSet to the client. */
|
||||||
|
virtual bool GetBlocksToPlace(
|
||||||
|
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||||
|
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||||
|
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||||
|
sSetBlockVector & a_BlocksToSet
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/** Called when the player right-clicks with this item and IsPlaceable() == true, and OnPlayerPlace() is not overridden.
|
||||||
This function should provide the block type and meta for the placed block, or refuse the placement.
|
This function should provide the block type and meta for the placed block, or refuse the placement.
|
||||||
Returns true to allow placement, false to refuse. */
|
Returns true to allow placement, false to refuse. */
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
|
@ -12,9 +12,11 @@
|
|||||||
class cItemMobHeadHandler :
|
class cItemMobHeadHandler :
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
typedef cItemHandler super;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemMobHeadHandler(int a_ItemType) :
|
cItemMobHeadHandler(int a_ItemType) :
|
||||||
cItemHandler(a_ItemType)
|
super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,34 +32,36 @@ public:
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
auto placedX = a_BlockX, placedY = a_BlockY, placedZ = a_BlockZ;
|
||||||
|
AddFaceDirection(placedY, placedY, placedZ, a_BlockFace);
|
||||||
|
|
||||||
// If the placed head is a wither, try to spawn the wither first:
|
// If the placed head is a wither, try to spawn the wither first:
|
||||||
if (a_EquippedItem.m_ItemDamage == E_META_HEAD_WITHER)
|
if (a_EquippedItem.m_ItemDamage == E_META_HEAD_WITHER)
|
||||||
{
|
{
|
||||||
if (TrySpawnWitherAround(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ))
|
if (TrySpawnWitherAround(a_World, a_Player, placedX, placedY, placedZ))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Wither not created, proceed with regular head placement
|
// Wither not created, proceed with regular head placement
|
||||||
}
|
}
|
||||||
|
|
||||||
return PlaceRegularHead(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
cItem itemCopy(a_EquippedItem); // Make a copy in case this is the player's last head item and OnPlayerPlace removes it
|
||||||
|
if (!super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RegularHeadPlaced(a_World, a_Player, itemCopy, placedX, placedY, placedZ, a_BlockFace);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Places a regular head block with no mob spawning checking. */
|
/** Called after placing a regular head block with no mob spawning.
|
||||||
bool PlaceRegularHead(
|
Adjusts the mob head entity based on the equipped item's data. */
|
||||||
|
void RegularHeadPlaced(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Place the block:
|
|
||||||
if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_HEAD, BlockFaceToBlockMeta(a_BlockFace)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use a callback to set the properties of the mob head block entity:
|
// Use a callback to set the properties of the mob head block entity:
|
||||||
class cCallback : public cBlockEntityCallback
|
class cCallback : public cBlockEntityCallback
|
||||||
{
|
{
|
||||||
@ -71,7 +75,7 @@ public:
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
cMobHeadEntity * MobHeadEntity = static_cast<cMobHeadEntity *>(a_BlockEntity);
|
auto MobHeadEntity = static_cast<cMobHeadEntity *>(a_BlockEntity);
|
||||||
|
|
||||||
int Rotation = 0;
|
int Rotation = 0;
|
||||||
if (m_BlockMeta == 1)
|
if (m_BlockMeta == 1)
|
||||||
@ -94,7 +98,6 @@ public:
|
|||||||
};
|
};
|
||||||
cCallback Callback(a_Player, static_cast<eMobHeadType>(a_EquippedItem.m_ItemDamage), static_cast<NIBBLETYPE>(a_BlockFace));
|
cCallback Callback(a_Player, static_cast<eMobHeadType>(a_EquippedItem.m_ItemDamage), static_cast<NIBBLETYPE>(a_BlockFace));
|
||||||
a_World.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
|
a_World.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -340,7 +343,7 @@ public:
|
|||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = E_BLOCK_HEAD;
|
a_BlockType = E_BLOCK_HEAD;
|
||||||
a_BlockMeta = (NIBBLETYPE)(a_Player->GetEquippedItem().m_ItemDamage & 0x0f);
|
a_BlockMeta = BlockFaceToBlockMeta(a_BlockFace);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} ;
|
} ;
|
||||||
|
Loading…
Reference in New Issue
Block a user