1
0
cuberite-2a/src/Items/ItemChest.h
Mattes D 01b8ed5295
Pulled the BlockID and BlockInfo headers from Globals.h. (#4591)
The BlockID.h file was removed from Globals.h and renamed to BlockType.h (main change)
The BlockInfo.h file was removed from Globals.h (main change)
The ENUM_BLOCK_ID and ENUM_ITEM_ID enum names were replaced with ENUM_BLOCK_TYPE and ENUM_ITEM_TYPE (cosmetics)
The various enums, such as eDimension, eDamageType and eExplosionSource were moved from BlockType.h to Defines.h, together with the helper functions for converting between them and strings (StringToDimension et al.) (minor)
Many inline functions were moved from headers to their respective cpp files, so that BlockType.h could be included only into the cpp file, rather than the header.
That broke our tests a bit, since they pick bits and pieces out of the main code and provide stubs for the rest; they had to be re-stubbed and re-verified.
eMonsterType values are no longer tied to E_ITEM_SPAWN_EGG_META_* values
2020-04-03 08:57:01 +02:00

162 lines
4.4 KiB
C++

#pragma once
#include "ItemHandler.h"
#include "../BlockInfo.h"
#include "../Blocks/BlockChest.h"
class cItemChestHandler:
public cItemHandler
{
typedef cItemHandler super;
public:
cItemChestHandler(int a_ItemType):
super(a_ItemType)
{
}
/** We need an OnPlayerPlace override because we're processing neighbor chests and changing their metas,
the parent class cannot do that. */
virtual bool OnPlayerPlace(
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
) override
{
if (a_BlockFace < 0)
{
// Clicked in air
return false;
}
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
{
// The clicked block is outside the world, ignore this call altogether (#128)
return false;
}
// Check if the block ignores build collision (water, grass etc.):
BLOCKTYPE clickedBlock;
NIBBLETYPE clickedBlockMeta;
Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ);
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, clickedBlock, clickedBlockMeta);
cChunkInterface ChunkInterface(a_World.GetChunkMap());
auto blockHandler = BlockHandler(clickedBlock);
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta))
{
blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, blockPos);
}
else
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
{
// The block is being placed outside the world, ignore this packet altogether (#128)
return false;
}
NIBBLETYPE PlaceMeta;
BLOCKTYPE PlaceBlock;
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlock, PlaceMeta);
// Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed.
// No need to do combinability (dblslab) checks, client will do that here.
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta))
{
// Tried to place a block into another?
// Happens when you place a block aiming at side of block with a torch on it or stem beside it
return false;
}
}
// Check that there is at most one single neighbor of the same chest type:
static const Vector3i CrossCoords[] =
{
{-1, 0, 0},
{ 0, 0, -1},
{ 1, 0, 0},
{ 0, 0, 1},
};
int NeighborIdx = -1;
for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++)
{
if (a_World.GetBlock(a_BlockX + CrossCoords[i].x, a_BlockY, a_BlockZ + CrossCoords[i].z) != m_ItemType)
{
continue;
}
if (NeighborIdx >= 0)
{
// Can't place here, there are already two neighbors, this would form a 3-block chest
return false;
}
NeighborIdx = static_cast<int>(i);
// Check that this neighbor is a single chest:
int bx = a_BlockX + CrossCoords[i].x;
int bz = a_BlockZ + CrossCoords[i].z;
for (size_t j = 0; j < ARRAYCOUNT(CrossCoords); j++)
{
if (a_World.GetBlock(bx + CrossCoords[j].x, a_BlockY, bz + CrossCoords[j].z) == m_ItemType)
{
return false;
}
} // for j
} // for i
// Get the meta of the placed chest; take existing neighbors into account:
BLOCKTYPE ChestBlockType = static_cast<BLOCKTYPE>(m_ItemType);
NIBBLETYPE Meta;
auto yaw = a_Player.GetYaw();
switch (NeighborIdx)
{
case 0:
case 2:
{
// 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:
case 3:
{
// 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;
}
default:
{
Meta = cBlockChestHandler::PlayerYawToMetaData(yaw);
break;
}
} // switch (NeighborIdx)
// Place the new chest:
if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, ChestBlockType, Meta))
{
return false;
}
// Adjust the existing chest, if any:
if (NeighborIdx != -1)
{
a_World.FastSetBlock(a_BlockX + CrossCoords[NeighborIdx].x, a_BlockY, a_BlockZ + CrossCoords[NeighborIdx].z, ChestBlockType, Meta);
}
// Remove the "placed" item:
if (a_Player.IsGameModeSurvival())
{
a_Player.GetInventory().RemoveOneEquippedItem();
}
return true;
}
private:
cItemChestHandler(const cItemChestHandler &) = delete;
};