Cuberite
A lightweight, fast and extensible game server for Minecraft
BlockFarmland.h
Go to the documentation of this file.
1 
2 // BlockFarmland.h
3 
4 // Declares the cBlcokFarmlandHandler representing the block handler for farmland
5 
6 
7 
8 
9 
10 #pragma once
11 
12 #include "BlockHandler.h"
13 #include "ChunkInterface.h"
14 #include "../BlockArea.h"
15 #include "../Chunk.h"
16 #include "../ClientHandle.h"
17 
18 
19 
20 
21 
22 class cBlockFarmlandHandler final :
23  public cBlockHandler
24 {
26 
27 public:
28 
29  using Super::Super;
30 
34  static void TurnToDirt(cChunk & a_Chunk, Vector3i a_AbsPos)
35  {
36  auto RelPos = cChunkDef::AbsoluteToRelative(a_AbsPos);
37  TurnToDirt(a_Chunk, a_AbsPos, RelPos);
38  }
39 
40 
41 
42 
43 
47  static void TurnToDirt(cChunk & a_Chunk, const Vector3i a_AbsPos, const Vector3i a_RelPos)
48  {
49  // Use cBlockInfo::GetBlockHeight when it doesn't break trampling for
50  // mobs and older clients anymore
51  static const auto FarmlandHeight = 0.9375;
52  static const auto FullHeightDelta = 0.0625;
53 
54  a_Chunk.ForEachEntityInBox(
55  cBoundingBox(Vector3d(0.5, FarmlandHeight, 0.5) + a_AbsPos, 0.5, FullHeightDelta),
56  [&](cEntity & Entity)
57  {
58  const auto GroundHeight = a_AbsPos.y + 1;
59 
60  // A simple IsOnGround isn't enough. It will return true when
61  // e.g. a piston pushes a farmland block into an entity's head.
62  // Maybe it's also possible than an entity is falling, it's
63  // still not on the ground, but it's less than 0.0625 blocks
64  // higher than the farmland block
65  if ((Entity.GetPosY() < a_AbsPos.y + FarmlandHeight) || (Entity.GetPosY() >= GroundHeight))
66  {
67  return false;
68  }
69 
70  // Players need a packet that will update their position
71  if (Entity.IsPlayer())
72  {
73  const auto HeightIncrease = GroundHeight - Entity.GetPosY();
74  const auto Player = static_cast<const cPlayer *>(&Entity);
75 
76  Player->GetClientHandle()->SendPlayerMoveLook(Vector3d(0.0, HeightIncrease, 0.0), 0.0f, 0.0f, true);
77  }
78 
79  Entity.SetPosY(GroundHeight);
80 
81  return false;
82  });
83 
84  a_Chunk.SetBlock(a_RelPos, E_BLOCK_DIRT, 0);
85  }
86 
87 
88 
89 
90 
91 private:
92 
93  virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override
94  {
95  return cItem(E_BLOCK_DIRT, 1, 0);
96  }
97 
98 
99 
100 
101 
102  virtual void OnUpdate(
103  cChunkInterface & a_ChunkInterface,
104  cWorldInterface & a_WorldInterface,
105  cBlockPluginInterface & a_PluginInterface,
106  cChunk & a_Chunk,
107  const Vector3i a_RelPos
108  ) const override
109  {
110  auto BlockMeta = a_Chunk.GetMeta(a_RelPos);
111 
112  if (IsWaterInNear(a_Chunk, a_RelPos))
113  {
114  // Water was found, set block meta to 7
115  a_Chunk.FastSetBlock(a_RelPos, m_BlockType, 7);
116  return;
117  }
118 
119  // Water wasn't found, de-hydrate block:
120  if (BlockMeta > 0)
121  {
122  a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_FARMLAND, --BlockMeta);
123  return;
124  }
125 
126  // Farmland too dry. If nothing is growing on top, turn back to dirt:
127  auto UpperBlock = cChunkDef::IsValidHeight(a_RelPos.addedY(1)) ? a_Chunk.GetBlock(a_RelPos.addedY(1)) : E_BLOCK_AIR;
128  switch (UpperBlock)
129  {
130  case E_BLOCK_BEETROOTS:
131  case E_BLOCK_CROPS:
132  case E_BLOCK_POTATOES:
133  case E_BLOCK_CARROTS:
134  case E_BLOCK_MELON_STEM:
136  {
137  // Produce on top, don't revert
138  break;
139  }
140  default:
141  {
142  auto AbsPos = a_Chunk.RelativeToAbsolute(a_RelPos);
143  TurnToDirt(a_Chunk, AbsPos, a_RelPos);
144  break;
145  }
146  }
147  }
148 
149 
150 
151 
152 
153  virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) const override
154  {
155  // Don't care about any neighbor but the one above us (fix recursion loop in #2213):
156  if (a_WhichNeighbor != BLOCK_FACE_YP)
157  {
158  return;
159  }
160 
161  // Don't care about anything if we're at the top of the world:
162  if (a_BlockPos.y >= cChunkDef::Height)
163  {
164  return;
165  }
166 
167  // Check whether we should revert to dirt:
168  // TODO: fix for signs and slabs (possibly more blocks) - they should destroy farmland
169  auto upperBlock = a_ChunkInterface.GetBlock(a_BlockPos.addedY(1));
170  if (cBlockInfo::FullyOccupiesVoxel(upperBlock))
171  {
172  // Until the fix above is done, this line should also suffice:
173  // a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_DIRT, 0);
174  a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & Chunk)
175  {
176  TurnToDirt(Chunk, a_BlockPos);
177  return true;
178  });
179  }
180  }
181 
182 
183 
184 
185 
187  static bool IsWaterInNear(const cChunk & a_Chunk, const Vector3i a_RelPos)
188  {
189  if (a_Chunk.IsWeatherWetAt(a_RelPos.addedY(1)))
190  {
191  // Rain hydrates farmland, too
192  return true;
193  }
194 
195  const auto WorldPos = a_Chunk.RelativeToAbsolute(a_RelPos);
196 
197  // Search for water in a close proximity:
198  // Ref.: https://minecraft.wiki/w/Farmland#Hydration
199  // TODO: Rewrite this to use the chunk and its neighbors directly
200  cBlockArea Area;
201  if (!Area.Read(*a_Chunk.GetWorld(), WorldPos - Vector3i(4, 0, 4), WorldPos + Vector3i(4, 1, 4)))
202  {
203  // Too close to the world edge, cannot check surroundings
204  return false;
205  }
206 
207  size_t NumBlocks = Area.GetBlockCount();
208  BLOCKTYPE * BlockTypes = Area.GetBlockTypes();
209  for (size_t i = 0; i < NumBlocks; i++)
210  {
211  if (IsBlockWater(BlockTypes[i]))
212  {
213  return true;
214  }
215  } // for i - BlockTypes[]
216 
217  return false;
218  }
219 
220 
221 
222 
223 
224  virtual bool CanSustainPlant(BLOCKTYPE a_Plant) const override
225  {
226  return (
227  (a_Plant == E_BLOCK_BEETROOTS) ||
228  (a_Plant == E_BLOCK_CROPS) ||
229  (a_Plant == E_BLOCK_CARROTS) ||
230  (a_Plant == E_BLOCK_POTATOES) ||
231  (a_Plant == E_BLOCK_MELON_STEM) ||
232  (a_Plant == E_BLOCK_PUMPKIN_STEM)
233  );
234  }
235 } ;
bool IsBlockWater(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:10
@ E_BLOCK_CARROTS
Definition: BlockType.h:156
@ E_BLOCK_POTATOES
Definition: BlockType.h:157
@ E_BLOCK_MELON_STEM
Definition: BlockType.h:120
@ E_BLOCK_FARMLAND
Definition: BlockType.h:72
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_CROPS
Definition: BlockType.h:71
@ E_BLOCK_BEETROOTS
Definition: BlockType.h:226
@ E_BLOCK_DIRT
Definition: BlockType.h:13
@ E_BLOCK_PUMPKIN_STEM
Definition: BlockType.h:119
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
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc.
Definition: Defines.h:38
@ BLOCK_FACE_YP
Definition: Defines.h:43
Vector3< double > Vector3d
Definition: Vector3.h:485
Vector3< int > Vector3i
Definition: Vector3.h:487
size_t GetBlockCount(void) const
Definition: BlockArea.h:393
BLOCKTYPE * GetBlockTypes(void) const
Returns the internal pointer to the block types.
Definition: BlockArea.h:389
bool Read(cForEachChunkProvider &a_ForEachChunkProvider, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes=baTypes|baMetas|baBlockEntities)
Reads an area of blocks specified.
Definition: BlockArea.cpp:445
static bool FullyOccupiesVoxel(BLOCKTYPE Block)
Does this block fully occupy its voxel - is it a 'full' block?
Definition: BlockInfo.cpp:606
static void TurnToDirt(cChunk &a_Chunk, Vector3i a_AbsPos)
Turns farmland into dirt.
Definition: BlockFarmland.h:34
virtual bool CanSustainPlant(BLOCKTYPE a_Plant) const override
Checks whether the block has an effect on growing the plant.
virtual void OnUpdate(cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface, cBlockPluginInterface &a_PluginInterface, cChunk &a_Chunk, const Vector3i a_RelPos) const override
Called when the block gets ticked either by a random tick or by a queued tick.
virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem *const a_Tool) const override
Returns the pickups that would result if the block was mined by a_Digger using a_Tool.
Definition: BlockFarmland.h:93
virtual void OnNeighborChanged(cChunkInterface &a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) const override
Called when a direct neighbor of this block has been changed.
static void TurnToDirt(cChunk &a_Chunk, const Vector3i a_AbsPos, const Vector3i a_RelPos)
Turns farmland into dirt.
Definition: BlockFarmland.h:47
static bool IsWaterInNear(const cChunk &a_Chunk, const Vector3i a_RelPos)
Returns true if there's either a water source block close enough to hydrate the specified position,...
constexpr cBlockHandler(BLOCKTYPE a_BlockType)
Definition: BlockHandler.h:29
const BLOCKTYPE m_BlockType
Definition: BlockHandler.h:205
This interface is used to decouple block handlers from the cPluginManager dependency through cWorld.
bool DoWithChunkAt(Vector3i a_BlockPos, cFunctionRef< bool(cChunk &)> a_Callback)
BLOCKTYPE GetBlock(Vector3i a_Pos)
Represents two sets of coords, minimum and maximum for each direction.
Definition: BoundingBox.h:24
Definition: Chunk.h:36
NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:279
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta)
Definition: Chunk.cpp:1296
BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:146
Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition) const
Converts the coord relative to this chunk into an absolute coord.
Definition: Chunk.h:450
void SetBlock(Vector3i a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Definition: Chunk.cpp:1263
bool ForEachEntityInBox(const cBoundingBox &a_Box, cEntityCallback a_Callback) const
Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
Definition: Chunk.cpp:1674
bool IsWeatherWetAt(int a_RelX, int a_RelZ) const
Returns true if it is raining or storming at the specified location, taking into account biomes.
Definition: Chunk.cpp:1196
cWorld * GetWorld(void) const
Definition: Chunk.h:135
static bool IsValidHeight(Vector3i a_BlockPosition)
Validates a height-coordinate.
Definition: ChunkDef.h:185
static void AbsoluteToRelative(int &a_X, int &a_Y, int &a_Z, int &a_ChunkX, int &a_ChunkZ)
Converts absolute block coords into relative (chunk + block) coords:
Definition: ChunkDef.h:147
static const int Height
Definition: ChunkDef.h:125
Definition: Entity.h:76
bool IsPlayer(void) const
Definition: Entity.h:160
void SetPosY(double a_PosY)
Definition: Entity.h:216
double GetPosY(void) const
Definition: Entity.h:196
Definition: Item.h:37
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
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 y
Definition: Vector3.h:17