Cuberite
A lightweight, fast and extensible game server for Minecraft
ItemMobHead.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "ItemHandler.h"
5 #include "../World.h"
6 #include "../BlockEntities/MobHeadEntity.h"
7 
8 
9 
10 
11 
13  public cItemHandler
14 {
16 
17 public:
18  cItemMobHeadHandler(int a_ItemType) :
19  super(a_ItemType)
20  {
21  }
22 
23 
24  virtual bool OnPlayerPlace(
25  cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
26  int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
27  int a_CursorX, int a_CursorY, int a_CursorZ
28  ) override
29  {
30  // Cannot place a head at "no face" and from the bottom:
31  if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockFace == BLOCK_FACE_BOTTOM))
32  {
33  return true;
34  }
35  auto placedX = a_BlockX, placedY = a_BlockY, placedZ = a_BlockZ;
36  AddFaceDirection(placedY, placedY, placedZ, a_BlockFace);
37 
38  // If the placed head is a wither, try to spawn the wither first:
39  if (a_EquippedItem.m_ItemDamage == E_META_HEAD_WITHER)
40  {
41  if (TrySpawnWitherAround(a_World, a_Player, {placedX, placedY, placedZ}))
42  {
43  return true;
44  }
45  // Wither not created, proceed with regular head placement
46  }
47 
48  cItem itemCopy(a_EquippedItem); // Make a copy in case this is the player's last head item and OnPlayerPlace removes it
49  if (!super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
50  {
51  return false;
52  }
53  RegularHeadPlaced(a_World, a_Player, itemCopy, placedX, placedY, placedZ, a_BlockFace);
54  return true;
55  }
56 
57 
61  cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
62  int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
63  )
64  {
65  auto HeadType = static_cast<eMobHeadType>(a_EquippedItem.m_ItemDamage);
66  auto BlockMeta = static_cast<NIBBLETYPE>(a_BlockFace);
67 
68  // Use a callback to set the properties of the mob head block entity:
69  a_World.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, [&](cBlockEntity & a_BlockEntity)
70  {
71  if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD)
72  {
73  return false;
74  }
75  auto & MobHeadEntity = static_cast<cMobHeadEntity &>(a_BlockEntity);
76 
77  int Rotation = 0;
78  if (BlockMeta == 1)
79  {
80  Rotation = FloorC(a_Player.GetYaw() * 16.0f / 360.0f + 0.5f) & 0x0f;
81  }
82 
83  MobHeadEntity.SetType(HeadType);
84  MobHeadEntity.SetRotation(static_cast<eMobHeadRotation>(Rotation));
85  MobHeadEntity.GetWorld()->BroadcastBlockEntity(MobHeadEntity.GetPos());
86  return false;
87  }
88  );
89  }
90 
91 
95  cWorld & a_World, cPlayer & a_Player,
96  Vector3i a_BlockPos
97  )
98  {
99  // No wither can be created at Y < 2 - not enough space for the formula:
100  if (a_BlockPos.y < 2)
101  {
102  return false;
103  }
104 
105  // Check for all relevant wither locations:
106  static const Vector3i RelCoords[] =
107  {
108  { 0, 0, 0},
109  { 1, 0, 0},
110  {-1, 0, 0},
111  { 0, 0, 1},
112  { 0, 0, -1},
113  };
114  for (auto & RelCoord : RelCoords)
115  {
116  if (TrySpawnWitherAt(
117  a_World, a_Player,
118  a_BlockPos,
119  RelCoord.x, RelCoord.z
120  ))
121  {
122  return true;
123  }
124  } // for i - RelCoords[]
125 
126  return false;
127  }
128 
129 
136  cWorld & a_World, cPlayer & a_Player,
137  Vector3i a_PlacedHeadPos,
138  int a_OffsetX, int a_OffsetZ
139  )
140  {
141  // Image for the wither at the X axis:
142  static const sSetBlock ImageWitherX[] =
143  {
144  {-1, 0, 0, E_BLOCK_HEAD, 0},
145  { 0, 0, 0, E_BLOCK_HEAD, 0},
146  { 1, 0, 0, E_BLOCK_HEAD, 0},
147  {-1, -1, 0, E_BLOCK_SOULSAND, 0},
148  { 0, -1, 0, E_BLOCK_SOULSAND, 0},
149  { 1, -1, 0, E_BLOCK_SOULSAND, 0},
150  {-1, -2, 0, E_BLOCK_AIR, 0},
151  { 0, -2, 0, E_BLOCK_SOULSAND, 0},
152  { 1, -2, 0, E_BLOCK_AIR, 0},
153  };
154 
155  // Image for the wither at the Z axis:
156  static const sSetBlock ImageWitherZ[] =
157  {
158  { 0, 0, -1, E_BLOCK_HEAD, 0},
159  { 0, 0, 0, E_BLOCK_HEAD, 0},
160  { 0, 0, 1, E_BLOCK_HEAD, 0},
161  { 0, -1, -1, E_BLOCK_SOULSAND, 0},
162  { 0, -1, 0, E_BLOCK_SOULSAND, 0},
163  { 0, -1, 1, E_BLOCK_SOULSAND, 0},
164  { 0, -2, -1, E_BLOCK_AIR, 0},
165  { 0, -2, 0, E_BLOCK_SOULSAND, 0},
166  { 0, -2, 1, E_BLOCK_AIR, 0},
167  };
168 
169  // Try to spawn the wither from each image:
170  return (
172  a_World, a_Player, ImageWitherX, ARRAYCOUNT(ImageWitherX),
173  a_PlacedHeadPos,
174  a_OffsetX, a_OffsetZ
175  ) ||
177  a_World, a_Player, ImageWitherZ, ARRAYCOUNT(ImageWitherZ),
178  a_PlacedHeadPos,
179  a_OffsetX, a_OffsetZ
180  )
181  );
182  }
183 
184 
191  cWorld & a_World, cPlayer & a_Player, const sSetBlock * a_Image, size_t a_ImageCount,
192  Vector3i a_PlacedHeadPos,
193  int a_OffsetX, int a_OffsetZ
194  )
195  {
196  // Check each block individually; simultaneously build the SetBlockVector for clearing the blocks:
197  sSetBlockVector AirBlocks;
198  AirBlocks.reserve(a_ImageCount);
199  for (size_t i = 0; i < a_ImageCount; i++)
200  {
201  // Get the absolute coords of the image:
202  int BlockX = a_PlacedHeadPos.x + a_OffsetX + a_Image[i].GetX();
203  int BlockY = a_PlacedHeadPos.y + a_Image[i].GetY();
204  int BlockZ = a_PlacedHeadPos.z + a_OffsetZ + a_Image[i].GetZ();
205 
206  // If the query is for the placed head, short-circuit-evaluate it:
207  if ((BlockX == a_PlacedHeadPos.x) && (BlockY == a_PlacedHeadPos.y) && (BlockZ == a_PlacedHeadPos.z))
208  {
209  if (a_Image[i].m_BlockType != E_BLOCK_HEAD)
210  {
211  return false; // Didn't match
212  }
213  continue; // Matched, continue checking the rest of the image
214  }
215 
216  // Query the world block:
217  BLOCKTYPE BlockType;
218  NIBBLETYPE BlockMeta;
219  if (!a_World.GetBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta))
220  {
221  // Cannot query block, assume unloaded chunk, fail to spawn the wither
222  return false;
223  }
224 
225  // Compare the world block:
226  if (BlockType != a_Image[i].m_BlockType)
227  {
228  return false;
229  }
230 
231  // If it is a mob head, check the correct head type using the block entity:
232  if (BlockType == E_BLOCK_HEAD)
233  {
234  bool IsWitherHead = false;
235  a_World.DoWithBlockEntityAt(BlockX, BlockY, BlockZ, [&](cBlockEntity & a_Entity)
236  {
237  ASSERT(a_Entity.GetBlockType() == E_BLOCK_HEAD);
238  auto & MobHead = static_cast<cMobHeadEntity &>(a_Entity);
239  IsWitherHead = (MobHead.GetType() == SKULL_TYPE_WITHER);
240  return true;
241  }
242  );
243  if (!IsWitherHead)
244  {
245  return false;
246  }
247  }
248  // Matched, continue checking
249  AirBlocks.emplace_back(BlockX, BlockY, BlockZ, E_BLOCK_AIR, 0);
250  } // for i - a_Image
251 
252  // All image blocks matched, try replace the image with air blocks:
253  if (!a_Player.PlaceBlocks(AirBlocks))
254  {
255  return false;
256  }
257 
258  // Spawn the wither:
259  int BlockX = a_PlacedHeadPos.x + a_OffsetX;
260  int BlockZ = a_PlacedHeadPos.z + a_OffsetZ;
261  a_World.SpawnMob(static_cast<double>(BlockX) + 0.5, a_PlacedHeadPos.y - 2, static_cast<double>(BlockZ) + 0.5, mtWither, false);
262  AwardSpawnWitherAchievement(a_World, {BlockX, a_PlacedHeadPos.y - 2, BlockZ});
263  return true;
264  }
265 
266 
268  void AwardSpawnWitherAchievement(cWorld & a_World, Vector3i a_BlockPos)
269  {
270  Vector3f Pos(a_BlockPos);
271  a_World.ForEachPlayer([=](cPlayer & a_Player)
272  {
273  // If player is close, award achievement:
274  double Dist = (a_Player.GetPosition() - Pos).Length();
275  if (Dist < 50.0)
276  {
278  }
279  return false;
280  }
281  );
282  }
283 
284 
287  static NIBBLETYPE BlockFaceToBlockMeta(int a_BlockFace)
288  {
289  switch (a_BlockFace)
290  {
291  case BLOCK_FACE_TOP: return 0x01; // On ground (rotation provided in block entity)
292  case BLOCK_FACE_XM: return 0x04; // west wall, facing east
293  case BLOCK_FACE_XP: return 0x05; // east wall, facing west
294  case BLOCK_FACE_ZM: return 0x02; // north wall, facing south
295  case BLOCK_FACE_ZP: return 0x03; // south wall, facing north
296  default:
297  {
298  ASSERT(!"Unhandled block face");
299  return 0;
300  }
301  }
302  }
303 
304 
305  virtual bool IsPlaceable(void) override
306  {
307  return true;
308  }
309 
310 
312  cWorld * a_World, cPlayer * a_Player,
313  int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
314  int a_CursorX, int a_CursorY, int a_CursorZ,
315  BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
316  ) override
317  {
318  a_BlockType = E_BLOCK_HEAD;
319  a_BlockMeta = BlockFaceToBlockMeta(a_BlockFace);
320  return true;
321  }
322 } ;
323 
324 
325 
326 
virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby=false) override
Spawns a mob of the specified type.
Definition: World.cpp:3190
T x
Definition: Vector3.h:17
void AwardSpawnWitherAchievement(cWorld &a_World, Vector3i a_BlockPos)
Awards the achievement to all players close to the specified point.
Definition: ItemMobHead.h:268
virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback a_Callback) override
Calls the callback for the block entity at the specified coords; returns false if there&#39;s no block en...
Definition: World.cpp:1432
BLOCKTYPE GetBlockType() const
Definition: BlockEntity.h:111
short m_ItemDamage
Definition: Item.h:211
unsigned int AwardAchievement(const eStatistic a_Ach)
Awards the player an achievement.
Definition: Player.cpp:1605
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:42
int GetY(void) const
Returns the absolute Y coord of the stored block.
Definition: ChunkDef.h:554
Definition: Player.h:27
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:45
int GetZ(void) const
Returns the absolute Z coord of the stored block.
Definition: ChunkDef.h:557
bool TrySpawnWitherFromImage(cWorld &a_World, cPlayer &a_Player, const sSetBlock *a_Image, size_t a_ImageCount, Vector3i a_PlacedHeadPos, int a_OffsetX, int a_OffsetZ)
Tries to spawn a wither from the specified image at the specified offset from the placed head block...
Definition: ItemMobHead.h:190
static NIBBLETYPE BlockFaceToBlockMeta(int a_BlockFace)
Converts the block face of the placement (which face of the block was clicked to place the head) into...
Definition: ItemMobHead.h:287
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17
bool PlaceBlocks(const sSetBlockVector &a_Blocks)
Calls the block placement hooks and places the blocks in the world.
Definition: Player.cpp:2788
int GetX(void) const
Returns the absolute X coord of the stored block.
Definition: ChunkDef.h:550
void AddFaceDirection(int &a_BlockX, int &a_BlockY, int &a_BlockZ, eBlockFace a_BlockFace, bool a_bInverse=false)
Definition: Defines.h:859
bool GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta)
Retrieves the block type and meta at the specified coords.
Definition: World.cpp:1909
Definition: World.h:65
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)
Called when the player tries to place the item (right mouse button, IsPlaceable() == true)...
cItemMobHeadHandler(int a_ItemType)
Definition: ItemMobHead.h:18
eMobHeadType
Definition: Defines.h:168
#define ASSERT(x)
Definition: Globals.h:335
bool TrySpawnWitherAt(cWorld &a_World, cPlayer &a_Player, Vector3i a_PlacedHeadPos, int a_OffsetX, int a_OffsetZ)
Tries to spawn a wither at the specified offset from the placed head block.
Definition: ItemMobHead.h:135
double GetYaw(void) const
Definition: Entity.h:209
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc...
Definition: Defines.h:29
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
Called when the player tries to place the item (right mouse button, IsPlaceable() == true)...
Definition: ItemMobHead.h:24
virtual bool GetPlacementBlockTypeMeta(cWorld *a_World, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) override
Called when the player right-clicks with this item and IsPlaceable() == true, and OnPlayerPlace() is ...
Definition: ItemMobHead.h:311
void RegularHeadPlaced(cWorld &a_World, cPlayer &a_Player, const cItem &a_EquippedItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
Called after placing a regular head block with no mob spawning.
Definition: ItemMobHead.h:60
const Vector3d & GetPosition(void) const
Exported in ManualBindings.
Definition: Entity.h:307
cItemHandler super
Definition: ItemMobHead.h:15
virtual bool IsPlaceable(void) override
Blocks simply get placed.
Definition: ItemMobHead.h:305
bool TrySpawnWitherAround(cWorld &a_World, cPlayer &a_Player, Vector3i a_BlockPos)
Spawns a wither if the wither skull placed at the specified coords completes wither&#39;s spawning formul...
Definition: ItemMobHead.h:94
std::enable_if< std::is_arithmetic< T >::value, C >::type FloorC(T a_Value)
Floors a value, then casts it to C (an int by default)
Definition: Globals.h:362
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:290
Definition: Item.h:36
std::vector< sSetBlock > sSetBlockVector
Definition: ChunkDef.h:564
virtual bool ForEachPlayer(cPlayerListCallback a_Callback) override
Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true.
Definition: World.cpp:2549