Cuberite
A lightweight, fast and extensible game server for Minecraft
BlockSapling.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "BlockHandler.h"
5 #include "../FastRandom.h"
6 
7 
8 
9 
10 
11 class cBlockSaplingHandler final :
12  public cBlockHandler
13 {
15 
16 public:
17 
18  using Super::Super;
19 
20 private:
21 
22  virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override
23  {
24  // The low 3 bits store the sapling type; bit 0x08 is the growth timer (not used in pickups)
25  return cItem(m_BlockType, 1, a_BlockMeta & 0x07);
26  }
27 
28 
29 
30 
31 
32  virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
33  {
34  return (a_Position.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_Position.addedY(-1)));
35  }
36 
37 
38 
39 
40 
41  virtual void OnUpdate(
42  cChunkInterface & a_ChunkInterface,
43  cWorldInterface & a_WorldInterface,
44  cBlockPluginInterface & a_PluginInterface,
45  cChunk & a_Chunk,
46  const Vector3i a_RelPos
47  ) const override
48  {
49  auto Meta = a_Chunk.GetMeta(a_RelPos);
50  auto Light = std::max(a_Chunk.GetBlockLight(a_RelPos), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(a_RelPos)));
51 
52  // Only grow if we have the right amount of light
53  if (Light > 8)
54  {
55  auto & random = GetRandomProvider();
56  // Only grow if we are in the right growth stage and have the right amount of space around them.
57  if (((Meta & 0x08) != 0) && random.RandBool(0.45) && CanGrowAt(a_Chunk, a_RelPos.x, a_RelPos.y, a_RelPos.z, Meta))
58  {
59  auto WorldPos = a_Chunk.RelativeToAbsolute(a_RelPos);
60  a_Chunk.GetWorld()->GrowTree(WorldPos);
61  }
62  // Only move to the next growth stage if we haven't gone there yet
63  else if (((Meta & 0x08) == 0) && random.RandBool(0.45))
64  {
65  a_Chunk.SetMeta(a_RelPos, Meta | 0x08);
66  }
67  }
68  }
69 
70 
71 
72 
73 
74  static bool CanGrowAt(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
75  {
76  a_Meta = a_Meta & 0x07;
77  int CheckHeight = 0;
78  bool LargeTree = false;
79 
80  // Get the height to check against
81  switch (a_Meta)
82  {
84  {
85  CheckHeight = 5;
86  break;
87  }
89  {
90  CheckHeight = 7;
91  if (IsLargeTree(a_Chunk, a_RelX, a_RelY, a_RelZ, a_Meta))
92  {
93  CheckHeight = 16;
94  LargeTree = true;
95  }
96  break;
97  }
99  {
100  CheckHeight = 6;
101  break;
102  }
104  {
105  CheckHeight = 7;
106  if (IsLargeTree(a_Chunk, a_RelX, a_RelY, a_RelZ, a_Meta))
107  {
108  CheckHeight = 13;
109  LargeTree = true;
110  }
111  break;
112  }
113  // Acacias don't need horizontal clearance
115  {
116  if (!IsLargeTree(a_Chunk, a_RelX, a_RelY, a_RelZ, a_Meta))
117  {
118  return false;
119  }
120  CheckHeight = 7;
121  LargeTree = true;
122  break;
123  }
124  // Dark Oaks don't need horizontal clearance
126  {
127  if (!IsLargeTree(a_Chunk, a_RelX, a_RelY, a_RelZ, a_Meta))
128  {
129  return false;
130  }
131  CheckHeight = 7;
132  LargeTree = true;
133  break;
134  }
135  }
136  // We should always get a valid CheckHeight
137  ASSERT(CheckHeight != 0);
138 
139  // Don't grow a tree if we don't have enough space left above it in the chunk
140  if ((a_RelY + CheckHeight) > cChunkDef::Height)
141  {
142  return false;
143  }
144  bool CanGrow = true;
145 
146  // Validate the neighbor blocks. They cannot be solid.
147  BLOCKTYPE check = E_BLOCK_AIR;
148  a_Chunk.UnboundedRelGetBlockType(a_RelX - 1, a_RelY, a_RelZ, check);
149  CanGrow = CanGrow && cBlockInfo::IsTransparent(check);
150 
151  a_Chunk.UnboundedRelGetBlockType(a_RelX + 1, a_RelY, a_RelZ, check);
152  CanGrow = CanGrow && cBlockInfo::IsTransparent(check);
153 
154  a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ - 1, check);
155  CanGrow = CanGrow && cBlockInfo::IsTransparent(check);
156 
157  a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ + 1, check);
158  CanGrow = CanGrow && cBlockInfo::IsTransparent(check);
159 
160  while (CheckHeight && CanGrow)
161  {
162  check = a_Chunk.GetBlock(a_RelX, a_RelY + CheckHeight, a_RelZ);
163  CanGrow = CanGrow && ((check == E_BLOCK_AIR) || (check == E_BLOCK_LEAVES));
164 
165  // We have to check above the neighboring saplings as well
166  if (LargeTree)
167  {
168  a_Chunk.UnboundedRelGetBlockType(a_RelX + 1, a_RelY + CheckHeight, a_RelZ, check);
169  CanGrow = CanGrow && ((check == E_BLOCK_AIR) || (check == E_BLOCK_LEAVES));
170 
171  a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY + CheckHeight, a_RelZ + 1, check);
172  CanGrow = CanGrow && ((check == E_BLOCK_AIR) || (check == E_BLOCK_LEAVES));
173 
174  a_Chunk.UnboundedRelGetBlockType(a_RelX + 1, a_RelY + CheckHeight, a_RelZ + 1, check);
175  CanGrow = CanGrow && ((check == E_BLOCK_AIR) || (check == E_BLOCK_LEAVES));
176  }
177 
178  --CheckHeight;
179  }
180 
181  return CanGrow;
182  }
183 
184 
185 
186 
187 
188  virtual int Grow(cChunk & a_Chunk, Vector3i a_RelPos, int a_NumStages = 1) const override
189  {
190  auto blockMeta = a_Chunk.GetMeta(a_RelPos);
191  auto typeMeta = blockMeta & 0x07;
192  auto growState = blockMeta >> 3;
193  int res = 0;
194 
195  // Try to increase the sapling's growState:
196  if (growState < 1)
197  {
198  ++growState;
199  a_Chunk.FastSetBlock(a_RelPos, m_BlockType, static_cast<NIBBLETYPE>(growState << 3 | typeMeta));
200  if (a_NumStages == 1)
201  {
202  // Only asked to grow one stage, which we did. Bail out.
203  return 1;
204  }
205  res = 1;
206  }
207 
208  // The sapling is grown, now it becomes a tree:
209  a_Chunk.GetWorld()->GrowTreeFromSapling(a_Chunk.RelativeToAbsolute(a_RelPos));
210  return res + 1;
211  }
212 
213 
214 
215 
216 
217  virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
218  {
219  UNUSED(a_Meta);
220  return 7;
221  }
222 
223  static bool IsLargeTree(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
224  {
225  BLOCKTYPE type;
226  NIBBLETYPE meta;
227  bool LargeTree = true;
228  a_Chunk.UnboundedRelGetBlock(a_RelX + 1, a_RelY, a_RelZ, type, meta);
229  LargeTree = LargeTree && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
230 
231  a_Chunk.UnboundedRelGetBlock(a_RelX + 1, a_RelY, a_RelZ + 1, type, meta);
232  LargeTree = LargeTree && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
233 
234  a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ + 1, type, meta);
235  LargeTree = LargeTree && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
236 
237  return LargeTree;
238  }
239 } ;
240 
241 
242 
243 
bool IsBlockTypeOfDirt(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:86
@ E_META_SAPLING_JUNGLE
Definition: BlockType.h:817
@ E_META_SAPLING_CONIFER
Definition: BlockType.h:815
@ E_META_SAPLING_APPLE
Definition: BlockType.h:814
@ E_META_SAPLING_DARK_OAK
Definition: BlockType.h:819
@ E_META_SAPLING_BIRCH
Definition: BlockType.h:816
@ E_META_SAPLING_ACACIA
Definition: BlockType.h:818
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_LEAVES
Definition: BlockType.h:28
@ E_BLOCK_SAPLING
Definition: BlockType.h:16
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
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
Byte ColourID
Definition: Globals.h:162
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
static bool IsTransparent(BLOCKTYPE Block)
Is a block transparent? (https://minecraft.wiki/w/Opacity)
Definition: BlockInfo.cpp:961
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.
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
Returns the base colour ID of the block, as will be represented on a map, as per documentation: https...
Definition: BlockSapling.h:217
virtual int Grow(cChunk &a_Chunk, Vector3i a_RelPos, int a_NumStages=1) const override
Grows this block, if it supports growing, by the specified amount of stages (at most).
Definition: BlockSapling.h:188
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: BlockSapling.h:22
virtual bool CanBeAt(const cChunk &a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
Checks if the block can stay at the specified relative coords in the chunk.
Definition: BlockSapling.h:32
static bool IsLargeTree(cChunk &a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
Definition: BlockSapling.h:223
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.
Definition: BlockSapling.h:41
static bool CanGrowAt(cChunk &a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
Definition: BlockSapling.h:74
Definition: Chunk.h:36
NIBBLETYPE GetBlockLight(Vector3i a_RelPos) const
Get the level of artificial light illuminating the block (0 - 15)
Definition: Chunk.h:302
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
NIBBLETYPE GetSkyLight(Vector3i a_RelPos) const
Get the level of sky light illuminating the block (0 - 15) independent of daytime.
Definition: Chunk.h:306
NIBBLETYPE GetTimeAlteredLight(NIBBLETYPE a_Skylight) const
Light alterations based on time.
Definition: Chunk.cpp:1977
bool UnboundedRelGetBlock(Vector3i a_RelCoords, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in ...
Definition: Chunk.cpp:1008
void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
Definition: Chunk.h:286
cWorld * GetWorld(void) const
Definition: Chunk.h:135
bool UnboundedRelGetBlockType(Vector3i a_RelCoords, BLOCKTYPE &a_BlockType) const
Same as GetBlockType(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap...
Definition: Chunk.cpp:1029
static const int Height
Definition: ChunkDef.h:125
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 x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17
bool GrowTreeFromSapling(Vector3i a_BlockPos)
Grows a tree from the sapling at the specified coords.
Definition: World.cpp:1487
bool GrowTree(Vector3i a_BlockPos)
Grows a tree at the specified coords.
Definition: World.cpp:1469