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 
12  public cBlockHandler
13 {
15 
16 public:
17 
19  super(a_BlockType)
20  {
21  }
22 
23 
24 
25 
26 
27  virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
28  {
29  // The low 3 bits store the sapling type; bit 0x08 is the growth timer (not used in pickups)
30  return cItem(m_BlockType, 1, a_BlockMeta & 0x07);
31  }
32 
33 
34 
35 
36 
37  virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
38  {
39  return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ));
40  }
41 
42 
43 
44 
45 
46  virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
47  {
48  NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
49  NIBBLETYPE Light = std::max(a_Chunk.GetBlockLight(a_RelX, a_RelY, a_RelZ), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(a_RelX, a_RelY, a_RelZ)));
50 
51  // Only grow if we have the right amount of light
52  if (Light > 8)
53  {
54  auto & random = GetRandomProvider();
55  // Only grow if we are in the right growth stage and have the right amount of space around them.
56  if (((Meta & 0x08) != 0) && random.RandBool(0.45) && CanGrowAt(a_Chunk, a_RelX, a_RelY, a_RelZ, Meta))
57  {
58  int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
59  int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
60  a_Chunk.GetWorld()->GrowTree(BlockX, a_RelY, BlockZ);
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_RelX, a_RelY, a_RelZ, Meta | 0x08);
66  }
67  }
68  }
69 
70 
71 
72 
73 
74  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) 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), blockMeta);
210  return res + 1;
211  }
212 
213 
214 
215 
216 
217  virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
218  {
219  UNUSED(a_Meta);
220  return 7;
221  }
222 
223 
224 
225 
226 
227 private:
228 
229  bool IsLargeTree(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
230  {
231  BLOCKTYPE type;
232  NIBBLETYPE meta;
233  bool LargeTree = true;
234  a_Chunk.UnboundedRelGetBlock(a_RelX + 1, a_RelY, a_RelZ, type, meta);
235  LargeTree = LargeTree && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
236 
237  a_Chunk.UnboundedRelGetBlock(a_RelX + 1, a_RelY, a_RelZ + 1, type, meta);
238  LargeTree = LargeTree && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
239 
240  a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ + 1, type, meta);
241  LargeTree = LargeTree && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
242 
243  return LargeTree;
244  }
245 } ;
246 
247 
248 
249 
cWorld * GetWorld(void) const
Definition: Chunk.h:153
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity *a_BlockEntity, const cEntity *a_Digger, const cItem *a_Tool) override
Returns the pickups that would result if the block was mined by a_Digger using a_Tool.
Definition: BlockSapling.h:27
NIBBLETYPE GetSkyLight(Vector3i a_RelPos) const
Get the level of sky light illuminating the block (0 - 15) independent of daytime.
Definition: Chunk.h:419
NIBBLETYPE GetTimeAlteredLight(NIBBLETYPE a_Skylight) const
Light alterations based on time.
Definition: Chunk.cpp:2450
NIBBLETYPE GetBlockLight(Vector3i a_RelPos) const
Get the level of artificial light illuminating the block (0 - 15)
Definition: Chunk.h:415
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:42
bool GrowTreeFromSapling(Vector3i a_BlockPos, NIBBLETYPE a_SaplingMeta)
Grows a tree at the specified coords, based on the sapling meta provided.
Definition: World.h:814
MTRand & GetRandomProvider()
Returns the current thread&#39;s random number source.
Definition: FastRandom.cpp:20
static const int Width
Definition: ChunkDef.h:134
Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition)
Converts the coord relative to this chunk into an absolute coord.
Definition: Chunk.h:569
bool UnboundedRelGetBlockType(Vector3i a_RelCoords, BLOCKTYPE &a_BlockType) const
Same as GetBlockType(), but relative coords needn&#39;t be in this chunk (uses m_Neighbor-s or m_ChunkMap...
Definition: Chunk.cpp:1018
cBlockHandler(BLOCKTYPE a_BlockType)
BLOCKTYPE m_BlockType
Definition: BlockHandler.h:213
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:45
Definition: Chunk.h:49
cBlockSaplingHandler(BLOCKTYPE a_BlockType)
Definition: BlockSapling.h:18
static const int Height
Definition: ChunkDef.h:135
virtual int Grow(cChunk &a_Chunk, Vector3i a_RelPos, int a_NumStages=1) override
Grows this block, if it supports growing, by the specified amount of stages (at most).
Definition: BlockSapling.h:188
This interface is used to decouple block handlers from the cPluginManager dependency through cWorld...
virtual void OnUpdate(cChunkInterface &cChunkInterface, cWorldInterface &a_WorldInterface, cBlockPluginInterface &a_PluginInterface, cChunk &a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
Called when the block gets ticked either by a random tick or by a queued tick.
Definition: BlockSapling.h:46
bool GrowTree(int a_BlockX, int a_BlockY, int a_BlockZ)
Grows a tree at the specified coords.
Definition: World.cpp:1576
NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:380
int GetPosX(void) const
Definition: Chunk.h:150
bool IsLargeTree(cChunk &a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
Definition: BlockSapling.h:229
#define ASSERT(x)
Definition: Globals.h:335
#define UNUSED
Definition: Globals.h:152
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) 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 bool CanBeAt(cChunkInterface &a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk &a_Chunk) override
Checks if the block can stay at the specified relative coords in the chunk.
Definition: BlockSapling.h:37
bool UnboundedRelGetBlock(Vector3i a_RelCoords, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Same as GetBlock(), but relative coords needn&#39;t be in this chunk (uses m_Neighbor-s or m_ChunkMap in ...
Definition: Chunk.cpp:997
BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:177
static bool IsTransparent(BLOCKTYPE a_Type)
Definition: BlockInfo.h:32
Byte ColourID
Definition: Globals.h:118
int GetPosZ(void) const
Definition: Chunk.h:151
bool IsBlockTypeOfDirt(BLOCKTYPE a_BlockType)
Definition: Defines.h:511
Definition: Entity.h:73
bool CanGrowAt(cChunk &a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
Definition: BlockSapling.h:74
void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta, bool a_ShouldMarkDirty=true, bool a_ShouldInformClients=true)
Definition: Chunk.h:387
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients=true)
Definition: Chunk.cpp:1402
Definition: Item.h:36
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:234