Cuberite
A lightweight, fast and extensible game server for Minecraft
BlockGrass.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "BlockHandler.h"
5 #include "../FastRandom.h"
6 #include "../Root.h"
7 #include "../Bindings/PluginManager.h"
8 
9 
10 
11 
12 
13 class cBlockGrassHandler final :
14  public cBlockHandler
15 {
16 public:
17 
19 
20 private:
21 
22  enum class Survivability
23  {
24  // Light level so good that the grass can try to spread to neighbours
25  CanSpread,
26 
27  // Stay put, light is enough to live on but not propagate
28  DoNothing,
29 
30  // Insufficient light, death is upon us
32  };
33 
34  virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override
35  {
36  if (!ToolHasSilkTouch(a_Tool))
37  {
38  return cItem(E_BLOCK_DIRT, 1, 0);
39  }
40  return cItem(E_BLOCK_GRASS, 1, 0);
41  }
42 
43 
44 
45 
46 
47  virtual void OnUpdate(
48  cChunkInterface & a_ChunkInterface,
49  cWorldInterface & a_WorldInterface,
50  cBlockPluginInterface & a_PluginInterface,
51  cChunk & a_Chunk,
52  const Vector3i a_RelPos
53  ) const override
54  {
55  if (!a_Chunk.IsLightValid())
56  {
57  a_Chunk.GetWorld()->QueueLightChunk(a_Chunk.GetPosX(), a_Chunk.GetPosZ());
58  return;
59  }
60 
61  switch (cBlockGrassHandler::DetermineSurvivability(a_Chunk, a_RelPos))
62  {
63  case Survivability::CanSpread: break;
64  case Survivability::DoNothing: return;
66  {
67  a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_DIRT, E_META_DIRT_NORMAL);
68  return;
69  }
70  }
71 
72  // Grass spreads to adjacent dirt blocks:
73  for (unsigned i = 0; i < 2; i++) // Pick two blocks to grow to
74  {
75  auto & Random = GetRandomProvider();
76  int OfsX = Random.RandInt(-1, 1);
77  int OfsY = Random.RandInt(-3, 1);
78  int OfsZ = Random.RandInt(-1, 1);
79 
80  cBlockGrassHandler::TrySpreadTo(a_Chunk, a_RelPos + Vector3i(OfsX, OfsY, OfsZ));
81  } // for i - repeat twice
82  }
83 
84 
85 
86 
87 
88  virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
89  {
90  UNUSED(a_Meta);
91  return 1;
92  }
93 
94 private:
95 
99  static Survivability DetermineSurvivability(cChunk & a_Chunk, const Vector3i a_RelPos)
100  {
101  const auto AbovePos = a_RelPos.addedY(1);
102  if (!cChunkDef::IsValidHeight(AbovePos))
103  {
105  }
106 
107  // Grass turns back to dirt when the block above it is not transparent or water.
108  // It does not turn to dirt when a snow layer is above.
109  const auto Above = a_Chunk.GetBlock(AbovePos);
110  if (
111  (Above != E_BLOCK_SNOW) &&
112  (!cBlockInfo::IsTransparent(Above) || IsBlockWater(Above)))
113  {
115  }
116 
117  // Make sure that there is enough light at the source block to spread
118  const auto Light = std::max(a_Chunk.GetBlockLight(AbovePos), a_Chunk.GetSkyLightAltered(AbovePos));
119  return (Light >= 9) ? Survivability::CanSpread : Survivability::DoNothing;
120  }
121 
122 
123 
124 
125 
127  static void TrySpreadTo(cChunk & a_Chunk, Vector3i a_RelPos)
128  {
129  if (!cChunkDef::IsValidHeight(a_RelPos))
130  {
131  // Y Coord out of range
132  return;
133  }
134 
135  auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(a_RelPos);
136  if ((Chunk == nullptr) || !Chunk->IsValid())
137  {
138  // Unloaded chunk
139  return;
140  }
141 
142  BLOCKTYPE DestBlock;
143  NIBBLETYPE DestMeta;
144  Chunk->GetBlockTypeMeta(a_RelPos, DestBlock, DestMeta);
145 
146  if ((DestBlock != E_BLOCK_DIRT) || (DestMeta != E_META_DIRT_NORMAL))
147  {
148  // Not a regular dirt block
149  return;
150  }
151 
152  const auto AbovePos = a_RelPos.addedY(1);
153  const auto Above = Chunk->GetBlock(AbovePos);
154  const auto Light = std::max(Chunk->GetBlockLight(AbovePos), Chunk->GetSkyLightAltered(AbovePos));
155 
156  if (
157  (Light > 4) &&
158  cBlockInfo::IsTransparent(Above) &&
159  !IsBlockLava(Above) &&
160  !IsBlockWaterOrIce(Above)
161  )
162  {
163  const auto AbsPos = Chunk->RelativeToAbsolute(a_RelPos);
164  if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*Chunk->GetWorld(), AbsPos, ssGrassSpread))
165  {
166  Chunk->FastSetBlock(a_RelPos, E_BLOCK_GRASS, 0);
167  }
168  }
169  }
170 } ;
bool IsBlockWater(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:10
bool IsBlockWaterOrIce(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:40
bool IsBlockLava(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:49
@ E_META_DIRT_NORMAL
Definition: BlockType.h:639
@ E_BLOCK_GRASS
Definition: BlockType.h:12
@ E_BLOCK_SNOW
Definition: BlockType.h:92
@ E_BLOCK_DIRT
Definition: BlockType.h:13
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
@ ssGrassSpread
Definition: Defines.h:341
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
Byte ColourID
Definition: Globals.h:162
#define UNUSED
Definition: Globals.h:72
Vector3< int > Vector3i
Definition: Vector3.h:487
static bool IsTransparent(BLOCKTYPE Block)
Is a block transparent? (https://minecraft.wiki/w/Opacity)
Definition: BlockInfo.cpp:961
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: BlockGrass.h:88
static void TrySpreadTo(cChunk &a_Chunk, Vector3i a_RelPos)
Attempt to spread grass to a block at the given position.
Definition: BlockGrass.h:127
static Survivability DetermineSurvivability(cChunk &a_Chunk, const Vector3i a_RelPos)
Check if conditions are favourable to a grass block at the given position.
Definition: BlockGrass.h:99
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: BlockGrass.h:47
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: BlockGrass.h:34
static bool ToolHasSilkTouch(const cItem *a_Tool)
Returns true if the specified tool is valid and has a non-zero silk-touch enchantment.
constexpr cBlockHandler(BLOCKTYPE a_BlockType)
Definition: BlockHandler.h:29
This interface is used to decouple block handlers from the cPluginManager dependency through cWorld.
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
int GetPosX(void) const
Definition: Chunk.h:131
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
cChunk * GetRelNeighborChunkAdjustCoords(Vector3i &a_RelPos) const
Returns the chunk into which the relatively-specified block belongs.
Definition: Chunk.cpp:1885
bool IsLightValid(void) const
Definition: Chunk.h:83
NIBBLETYPE GetSkyLightAltered(Vector3i a_RelPos) const
Get the level of sky light illuminating the block (0 - 15), taking daytime into a account.
Definition: Chunk.h:310
cWorld * GetWorld(void) const
Definition: Chunk.h:135
int GetPosZ(void) const
Definition: Chunk.h:132
void GetBlockTypeMeta(Vector3i a_RelPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Definition: Chunk.cpp:1757
static bool IsValidHeight(Vector3i a_BlockPosition)
Validates a height-coordinate.
Definition: ChunkDef.h:185
Definition: Item.h:37
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
static cRoot * Get()
Definition: Root.h:52
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
void QueueLightChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr< cChunkCoordCallback > a_Callback={})
Queues a chunk for lighting; a_Callback is called after the chunk is lighted.
Definition: World.cpp:2676