Cuberite
A lightweight, fast and extensible game server for Minecraft
ItemDye.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "ItemHandler.h"
5 #include "../World.h"
6 #include "../Entities/Player.h"
7 #include "../Blocks/BlockCocoaPod.h"
8 
9 
10 
11 
12 
13 class cItemDyeHandler final :
14  public cItemHandler
15 {
17 
18 public:
19  using Super::Super;
20 
21 
22 
23 
24 
25  virtual bool OnItemUse(
26  cWorld * a_World,
27  cPlayer * a_Player,
28  cBlockPluginInterface & a_PluginInterface,
29  const cItem & a_HeldItem,
30  const Vector3i a_ClickedBlockPos,
31  eBlockFace a_ClickedBlockFace
32  ) const override
33  {
34  if ((a_HeldItem.m_ItemDamage == E_META_DYE_WHITE) && (a_ClickedBlockFace != BLOCK_FACE_NONE))
35  {
36  // Bonemeal (white dye) is used to fertilize plants:
37  if (FertilizePlant(*a_World, a_ClickedBlockPos))
38  {
39  if (a_Player->IsGameModeSurvival())
40  {
41  a_Player->GetInventory().RemoveOneEquippedItem();
42  return true;
43  }
44  }
45  }
46  else if ((a_HeldItem.m_ItemDamage == E_META_DYE_BROWN) && (a_ClickedBlockFace >= BLOCK_FACE_ZM) && (a_ClickedBlockFace <= BLOCK_FACE_XP))
47  {
48  // Players can't place blocks while in adventure mode.
49  if (a_Player->IsGameModeAdventure())
50  {
51  return false;
52  }
53 
54  // Cocoa (brown dye) can be planted on jungle logs:
56  NIBBLETYPE BlockMeta;
57  a_World->GetBlockTypeMeta(a_ClickedBlockPos, BlockType, BlockMeta);
58 
59  // Check if the block that the player clicked is a jungle log.
60  if ((BlockType != E_BLOCK_LOG) || ((BlockMeta & 0x03) != E_META_LOG_JUNGLE))
61  {
62  return false;
63  }
64 
65  // Get the location from the new cocoa pod.
66  auto CocoaPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace, false);
67  BlockMeta = cBlockCocoaPodHandler::BlockFaceToMeta(a_ClickedBlockFace);
68 
69  // Place the cocoa pod:
70  if (a_World->GetBlock(CocoaPos) != E_BLOCK_AIR)
71  {
72  return false;
73  }
74  if (a_Player->PlaceBlock(CocoaPos, E_BLOCK_COCOA_POD, BlockMeta))
75  {
76  if (a_Player->IsGameModeSurvival())
77  {
78  a_Player->GetInventory().RemoveOneEquippedItem();
79  }
80  return true;
81  }
82  }
83  return false;
84  }
85 
86 
87 
88 
89 
100  static bool FertilizePlant(cWorld & a_World, Vector3i a_BlockPos)
101  {
103  NIBBLETYPE BlockMeta;
104  if (!a_World.GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta))
105  {
106  return false;
107  }
108  switch (BlockType)
109  {
110  case E_BLOCK_WHEAT:
111  case E_BLOCK_CARROTS:
112  case E_BLOCK_POTATOES:
113  case E_BLOCK_MELON_STEM:
115  {
116  // Grow by 2 - 5 stages:
117  auto NumStages = GetRandomProvider().RandInt(2, 5);
118  if (a_World.GrowPlantAt(a_BlockPos, NumStages) <= 0)
119  {
120  return false;
121  }
123  return true;
124  } // case wheat, carrots, potatoes, melon stem, pumpkin stem
125 
126  case E_BLOCK_BEETROOTS:
127  {
128  // Fix GH #4805.
129  // Bonemeal should only advance growth, not spawn produce, and should not be consumed if plant at maturity:
130  if (a_World.GrowPlantAt(a_BlockPos, 1) <= 0)
131  {
132  return false;
133  }
135  if (GetRandomProvider().RandBool(0.25))
136  {
137  // 75% chance of 1-stage growth, but we hit the 25%, rollback:
138  a_World.GrowPlantAt(a_BlockPos, -1);
139  }
140  return true;
141  } // case beetroots
142 
143  case E_BLOCK_SAPLING:
144  {
145  // 45% chance of growing to the next stage / full tree:
146  if (GetRandomProvider().RandBool(0.45))
147  {
148  a_World.GrowPlantAt(a_BlockPos, 1);
149  }
151  return true;
152  } // case sapling
153 
154  case E_BLOCK_BIG_FLOWER:
155  {
156  // Drop the corresponding flower item without destroying the block:
157  cItems Pickups;
158  switch (BlockMeta)
159  {
164  }
165  // TODO: Should we call any hook for this?
166  a_World.SpawnItemPickups(Pickups, a_BlockPos);
167  return true;
168  } // big flower
169 
170  case E_BLOCK_TALL_GRASS:
171  case E_BLOCK_COCOA_POD:
172  {
173  // Always try to grow 1 stage:
174  if (a_World.GrowPlantAt(a_BlockPos, 1) <= 0)
175  {
176  return false;
177  }
179  return true;
180  } // case tall grass
181 
184  {
185  // 40% chance of growing into a large mushroom:
186  if (GetRandomProvider().RandBool(0.6))
187  {
188  return false;
189  }
190  if (a_World.GrowPlantAt(a_BlockPos, 1) <= 0)
191  {
192  return false;
193  }
195  return true;
196  } // case red or brown mushroom
197 
198  case E_BLOCK_GRASS:
199  {
200  GrowPlantsAround(a_World, a_BlockPos);
201  return true;
202  }
203 
204  // TODO: case E_BLOCK_SWEET_BERRY_BUSH:
205  // TODO: case E_BLOCK_SEA_PICKLE:
206  // TODO: case E_BLOCK_KELP:
207  // TODO: case E_BLOCK_BAMBOO:
208  } // switch (blockType)
209  return false;
210  }
211 
212 
213 
214 
215 
223  static void GrowPlantsAround(cWorld & a_World, const Vector3i a_Position)
224  {
225  auto & Random = GetRandomProvider();
226 
227  auto DoubleGrassCount = Random.RandInt(8U);
228  auto GrassCount = Random.RandInt(8U, 24U);
229  auto FlowerCount = Random.RandInt(8U);
230 
231  // Do a round-robin placement:
232  while ((DoubleGrassCount > 0) || (GrassCount > 0) || (FlowerCount > 0))
233  {
234  // place the big grass:
235  if (DoubleGrassCount != 0)
236  {
237  FindAdjacentGrassAnd<&GrowDoubleTallGrass>(a_World, a_Position);
238  DoubleGrassCount--;
239  }
240 
241  // place the tall grass:
242  if (GrassCount != 0)
243  {
244  FindAdjacentGrassAnd<&GrowTallGrass>(a_World, a_Position);
245  GrassCount--;
246  }
247 
248  // place the flowers
249  if (FlowerCount != 0)
250  {
251  FindAdjacentGrassAnd<&GrowFlower>(a_World, a_Position);
252  FlowerCount--;
253  }
254  }
255  }
256 
257  static void GrowDoubleTallGrass(cWorld & a_World, const Vector3i a_Position)
258  {
261 
262  const auto Above = a_Position.addedY(1);
265  }
266 
267  static void GrowTallGrass(cWorld & a_World, const Vector3i a_Position)
268  {
271  }
272 
274  static void GrowFlower(cWorld & a_World, const Vector3i a_Position)
275  {
276  auto & Random = GetRandomProvider();
277  switch (a_World.GetBiomeAt(a_Position.x, a_Position.z))
278  {
279  case biPlains:
280  case biSunflowerPlains:
281  {
282  switch (Random.RandInt(8))
283  {
284  case 0: a_World.SetBlock(a_Position, E_BLOCK_DANDELION, 0); break;
285  case 1: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_POPPY); break;
286  case 2: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_ALLIUM); break;
287  case 3: a_World.SetBlock(a_Position, E_BLOCK_RED_ROSE, 0); break; // was renamed to Azure Bluet later
288  case 4: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_RED_TULIP); break;
289  case 5: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_PINK_TULIP); break;
290  case 6: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_WHITE_TULIP); break;
291  case 7: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_ORANGE_TULIP); break;
292  case 8: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_OXEYE_DAISY); break;
293  // TODO: Add cornflower
294  }
295  break;
296  }
297  case biSwampland:
298  case biSwamplandM:
299  {
300  a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_BLUE_ORCHID);
301  break;
302  }
303  case biFlowerForest:
304  {
305  switch (Random.RandInt(8))
306  {
307  case 0: a_World.SetBlock(a_Position, E_BLOCK_DANDELION, 0); break;
308  case 1: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_POPPY); break;
309  case 2: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_ALLIUM); break;
310  case 3: a_World.SetBlock(a_Position, E_BLOCK_RED_ROSE, 0); break; // was renamed to Azure Bluet later
311  case 4: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_RED_TULIP); break;
312  case 5: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_PINK_TULIP); break;
313  case 6: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_WHITE_TULIP); break;
314  case 7: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_ORANGE_TULIP); break;
315  case 8: a_World.SetBlock(a_Position, E_BLOCK_FLOWER, E_META_FLOWER_OXEYE_DAISY); break;
316  // TODO: Add cornflower, lily of the valley
317  }
318  break;
319  }
320  case biMesa:
321  case biMesaBryce:
322  case biMesaPlateau:
323  case biMesaPlateauF:
324  case biMesaPlateauM:
325  case biMesaPlateauFM:
326  case biMushroomIsland:
327  case biMushroomShore:
328  case biNether:
329  case biEnd:
330  {
331  break;
332  }
333  default:
334  {
335  switch (Random.RandInt(1))
336  {
337  case 0: a_World.SetBlock(a_Position, E_BLOCK_DANDELION, 0); break;
338  case 1: a_World.SetBlock(a_Position, E_BLOCK_RED_ROSE, 0); break;
339  }
340  break;
341  }
342  }
343  }
344 
347  template <auto Planter>
348  static void FindAdjacentGrassAnd(cWorld & a_World, const Vector3i a_Position)
349  {
350  auto & Random = GetRandomProvider();
351  auto Position = a_Position;
352 
353  // Maximum 7 taxicab distance away from centre:
354  for (
355  int Tries = 0;
356  Tries != 8;
357  Tries++,
358 
359  // Get the adjacent block to visit this iteration:
360  Position += Vector3i(
361  Random.RandInt(-1, 1),
362  Random.RandInt(-1, 1) * (Random.RandInt(2) / 2), // Y offset, with discouragement to values that aren't zero
363  Random.RandInt(-1, 1)
364  )
365  )
366  {
367  if (
368  !cChunkDef::IsValidHeight(Position) ||
369  (a_World.GetBlock(Position) != E_BLOCK_GRASS) // Are we looking at grass?
370  )
371  {
372  // Not grass or invalid height, restart random walk and bail:
373  Position = a_Position;
374  continue;
375  }
376 
377  if (Planter == GrowDoubleTallGrass)
378  {
379  const auto TwoAbove = Position.addedY(2);
380  if ((TwoAbove.y >= cChunkDef::Height) || (a_World.GetBlock(TwoAbove) != E_BLOCK_AIR))
381  {
382  // Insufficient space for tall grass:
383  continue;
384  }
385  }
386 
387  const auto PlantBase = Position.addedY(1);
388  if ((PlantBase.y >= cChunkDef::Height) || (a_World.GetBlock(PlantBase) != E_BLOCK_AIR))
389  {
390  // Insufficient space:
391  continue;
392  }
393 
394  Planter(a_World, PlantBase);
395  return;
396  }
397  }
398 } ;
399 
400 
401 
402 
@ biMesa
Definition: BiomeDef.h:64
@ biMesaPlateau
Definition: BiomeDef.h:66
@ biNether
Definition: BiomeDef.h:31
@ biMesaPlateauF
Definition: BiomeDef.h:65
@ biSunflowerPlains
Definition: BiomeDef.h:77
@ biFlowerForest
Definition: BiomeDef.h:80
@ biMushroomShore
Definition: BiomeDef.h:40
@ biMesaPlateauFM
Definition: BiomeDef.h:96
@ biMushroomIsland
Definition: BiomeDef.h:39
@ biMesaBryce
Definition: BiomeDef.h:95
@ biPlains
Definition: BiomeDef.h:23
@ biSwamplandM
Definition: BiomeDef.h:82
@ biEnd
Definition: BiomeDef.h:33
@ biMesaPlateauM
Definition: BiomeDef.h:97
@ biSwampland
Definition: BiomeDef.h:28
@ E_META_LOG_JUNGLE
Definition: BlockType.h:742
@ E_META_TALL_GRASS_GRASS
Definition: BlockType.h:931
@ E_META_BIG_FLOWER_TOP
Definition: BlockType.h:562
@ E_META_FLOWER_RED_TULIP
Definition: BlockType.h:683
@ E_META_BIG_FLOWER_ROSE_BUSH
Definition: BlockType.h:559
@ E_META_FLOWER_OXEYE_DAISY
Definition: BlockType.h:687
@ E_META_BIG_FLOWER_SUNFLOWER
Definition: BlockType.h:555
@ E_META_BIG_FLOWER_DOUBLE_TALL_GRASS
Definition: BlockType.h:557
@ E_META_FLOWER_POPPY
Definition: BlockType.h:680
@ E_META_FLOWER_PINK_TULIP
Definition: BlockType.h:686
@ E_META_FLOWER_ALLIUM
Definition: BlockType.h:682
@ E_META_FLOWER_WHITE_TULIP
Definition: BlockType.h:685
@ E_META_BIG_FLOWER_LILAC
Definition: BlockType.h:556
@ E_META_FLOWER_ORANGE_TULIP
Definition: BlockType.h:684
@ E_META_FLOWER_BLUE_ORCHID
Definition: BlockType.h:681
@ E_META_BIG_FLOWER_PEONY
Definition: BlockType.h:560
@ E_BLOCK_CARROTS
Definition: BlockType.h:156
@ E_BLOCK_POTATOES
Definition: BlockType.h:157
@ E_BLOCK_MELON_STEM
Definition: BlockType.h:120
@ E_BLOCK_COCOA_POD
Definition: BlockType.h:142
@ E_BLOCK_FLOWER
Definition: BlockType.h:48
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_GRASS
Definition: BlockType.h:12
@ E_BLOCK_BEETROOTS
Definition: BlockType.h:226
@ E_BLOCK_DANDELION
Definition: BlockType.h:47
@ E_BLOCK_WHEAT
Definition: BlockType.h:70
@ E_BLOCK_BROWN_MUSHROOM
Definition: BlockType.h:49
@ E_BLOCK_BIG_FLOWER
Definition: BlockType.h:194
@ E_BLOCK_RED_ROSE
Definition: BlockType.h:284
@ E_BLOCK_RED_MUSHROOM
Definition: BlockType.h:50
@ E_BLOCK_LOG
Definition: BlockType.h:27
@ E_BLOCK_SAPLING
Definition: BlockType.h:16
@ E_BLOCK_PUMPKIN_STEM
Definition: BlockType.h:119
@ E_BLOCK_TALL_GRASS
Definition: BlockType.h:41
@ E_META_DYE_WHITE
Definition: BlockType.h:1060
@ E_META_DYE_BROWN
Definition: BlockType.h:1048
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
void AddFaceDirection(int &a_BlockX, int &a_BlockY, int &a_BlockZ, eBlockFace a_BlockFace, bool a_bInverse)
Modifies the specified coords so that they point to the block adjacent to the one specified through i...
Definition: Defines.cpp:378
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc.
Definition: Defines.h:38
@ BLOCK_FACE_XP
Definition: Defines.h:41
@ BLOCK_FACE_ZM
Definition: Defines.h:44
@ BLOCK_FACE_NONE
Definition: Defines.h:39
@ PARTICLE_HAPPY_VILLAGER
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
BlockType
Definition: BlockTypes.h:4
Vector3< int > Vector3i
Definition: Vector3.h:487
static NIBBLETYPE BlockFaceToMeta(eBlockFace a_BlockFace)
Definition: BlockCocoaPod.h:19
This interface is used to decouple block handlers from the cPluginManager dependency through cWorld.
static bool IsValidHeight(Vector3i a_BlockPosition)
Validates a height-coordinate.
Definition: ChunkDef.h:185
static const int Height
Definition: ChunkDef.h:125
Definition: Player.h:29
bool IsGameModeSurvival(void) const
Returns true if the player is in Survival mode, either explicitly, or by inheriting from current worl...
Definition: Player.cpp:1034
cInventory & GetInventory(void)
Definition: Player.h:156
bool IsGameModeAdventure(void) const
Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current wor...
Definition: Player.cpp:1043
bool PlaceBlock(Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Attempts to place the block in the world with a call to PlaceBlocks.
Definition: Player.cpp:2440
IntType RandInt(IntType a_Min, IntType a_Max)
Return a random IntType in the range [a_Min, a_Max].
Definition: FastRandom.h:78
bool RemoveOneEquippedItem(void)
Removes one item out of the currently equipped item stack, returns true if successful,...
Definition: Inventory.cpp:232
Definition: Item.h:37
short m_ItemDamage
Definition: Item.h:165
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
void Add(const cItem &a_Item)
Definition: Item.h:233
static void GrowDoubleTallGrass(cWorld &a_World, const Vector3i a_Position)
Definition: ItemDye.h:257
static void GrowFlower(cWorld &a_World, const Vector3i a_Position)
Grows a biome-dependent flower according to https://minecraft.wiki/w/Flower#Flower_biomes.
Definition: ItemDye.h:274
virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, cBlockPluginInterface &a_PluginInterface, const cItem &a_HeldItem, const Vector3i a_ClickedBlockPos, eBlockFace a_ClickedBlockFace) const override
Called when the player tries to use the item (right mouse button).
Definition: ItemDye.h:25
static void GrowPlantsAround(cWorld &a_World, const Vector3i a_Position)
Grows new plants around the specified block.
Definition: ItemDye.h:223
static void FindAdjacentGrassAnd(cWorld &a_World, const Vector3i a_Position)
Walks adjacent grass blocks up to 7 taxicab distance away from a_Position and calls the Planter funct...
Definition: ItemDye.h:348
static bool FertilizePlant(cWorld &a_World, Vector3i a_BlockPos)
Attempts to use the bonemeal on the plant at the specified (absolute) position.
Definition: ItemDye.h:100
static void GrowTallGrass(cWorld &a_World, const Vector3i a_Position)
Definition: ItemDye.h:267
constexpr cItemHandler(int a_ItemType)
Definition: ItemHandler.h:37
Vector3< T > addedY(T a_AddY) const
Returns a copy of this vector moved by the specified amount on the y axis.
Definition: Vector3.h:314
T x
Definition: Vector3.h:17
T z
Definition: Vector3.h:17
Definition: World.h:53
int GrowPlantAt(Vector3i a_BlockPos, int a_NumStages=1)
Grows the plant at the specified position by at most a_NumStages.
Definition: World.cpp:1676
BLOCKTYPE GetBlock(Vector3i a_BlockPos) const
Returns the block type at the specified position.
Definition: World.h:363
bool GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Retrieves the block type and meta at the specified coords.
Definition: World.cpp:1779
virtual void BroadcastSoundParticleEffect(const EffectID a_EffectID, Vector3i a_SrcPos, int a_Data, const cClientHandle *a_Exclude=nullptr) override
void SpawnItemPickups(const cItems &a_Pickups, Vector3i a_BlockPos, double a_FlyAwaySpeed=1.0, bool a_IsPlayerCreated=false)
Spawns item pickups for each item in the list.
Definition: World.cpp:1806
EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ)
Returns the biome at the specified coords.
Definition: World.cpp:1694
void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
Definition: World.cpp:1743