Cuberite
A lightweight, fast and extensible game server for Minecraft
BlockFire.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "BlockHandler.h"
5 
6 
7 
8 
9 
11  public cBlockHandler
12 {
13 public:
15  : cBlockHandler(a_BlockType),
16  XZP(0), XZM(0), Dir(0)
17  {
18  }
19 
21  // TODO: These need to be removed, BlockHandler instances are shared for all blocks in all worlds on the server
22  // and are not supposed to have any data in them.
23  int XZP, XZM;
25 
26 
27 
28 
29 
30  virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
31  {
32  /*
33  PORTAL FINDING ALGORITH
34  =======================
35  - Get clicked base block
36  - Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered.
37  Uses this value as a reference (the 'ceiling')
38  - For both directions (if one fails, try the other), BASE (clicked) block:
39  - Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1)
40  - If a border was encountered, go the other direction and repeat above
41  - Write borders to XZP and XZM, write direction portal faces to Dir
42  - Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir
43  */
44 
45  // a_BlockY - 1: Because we want the block below the fire
46  FindAndSetPortalFrame(a_BlockPos.x, a_BlockPos.y - 1, a_BlockPos.z, a_ChunkInterface, a_WorldInterface);
47  }
48 
49 
50 
51 
52 
53  virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
54  {
55  // No pickups from this block
56  return {};
57  }
58 
59 
60 
61 
62 
63  virtual bool IsClickedThrough(void) override
64  {
65  return true;
66  }
67 
70  int FindObsidianCeiling(int X, int Y, int Z, cChunkInterface & a_ChunkInterface, int MaxY = 0)
71  {
72  if (a_ChunkInterface.GetBlock({X, Y, Z}) != E_BLOCK_OBSIDIAN)
73  {
74  return 0;
75  }
76 
77  for (int newY = Y + 1; newY < cChunkDef::Height; newY++)
78  {
79  BLOCKTYPE Block = a_ChunkInterface.GetBlock({X, newY, Z});
80  if ((Block == E_BLOCK_AIR) || (Block == E_BLOCK_FIRE))
81  {
82  continue;
83  }
84  else if (Block == E_BLOCK_OBSIDIAN)
85  {
86  // We found an obsidian ceiling
87  // Make sure MaxY has a value and newY ('ceiling' location) is at one above the base block
88  // This is because the frame is a solid obsidian pillar
89  if ((MaxY != 0) && (newY == Y + 1))
90  {
91  return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface) ? -1 /* -1 = found a frame */ : 0;
92  }
93  else
94  {
95  // Return ceiling Y, whoever called this function will decide if it's part of a portal or not
96  return newY;
97  }
98  }
99  }
100 
101  return 0;
102  }
103 
105  bool EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface)
106  {
107  for (int checkBorder = FoundObsidianY + 1; checkBorder <= MaxY - 1; checkBorder++) // FoundObsidianY + 1: FoundObsidianY has already been checked in FindObsidianCeiling; MaxY - 1: portal doesn't need corners
108  {
109  if (a_ChunkInterface.GetBlock({X, checkBorder, Z}) != E_BLOCK_OBSIDIAN)
110  {
111  // Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal
112  return false;
113  }
114  }
115  // Everything was obsidian, found a border!
116  return true;
117  }
118 
119 
120 
121 
122 
124  void FindAndSetPortalFrame(int X, int Y, int Z, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface)
125  {
126  int MaxY = FindObsidianCeiling(X, Y, Z, a_ChunkInterface); // Get topmost obsidian block as reference for all other checks
127  int X1 = X + 1, Z1 = Z + 1, X2 = X - 1, Z2 = Z - 1; // Duplicate XZ values, add / subtract one as we've checked the original already the line above
128 
129  if (MaxY == 0) // Oh noes! Not a portal coordinate :(
130  {
131  return;
132  }
133 
134  if (!FindPortalSliceX(X1, X2, Y, Z, MaxY, a_ChunkInterface))
135  {
136  if (!FindPortalSliceZ(X, Y, Z1, Z2, MaxY, a_ChunkInterface))
137  {
138  return; // No eligible portal construct, abort abort abort!!
139  }
140  }
141 
142  int PortalHeight = MaxY - Y - 1;
143  int PortalWidth = XZP - XZM + 1;
144  if ((PortalHeight < a_WorldInterface.GetMinNetherPortalHeight()) || (PortalHeight > a_WorldInterface.GetMaxNetherPortalHeight()))
145  {
146  // The portal isn't high enough, or is too high
147  return;
148  }
149 
150  if ((PortalWidth < a_WorldInterface.GetMinNetherPortalWidth()) || (PortalWidth > a_WorldInterface.GetMaxNetherPortalWidth()))
151  {
152  // The portal isn't wide enough, or is too wide
153  return;
154  }
155 
156  for (int Height = Y + 1; Height <= MaxY - 1; Height++) // Loop through boundary to set portal blocks
157  {
158  for (int Width = XZM; Width <= XZP; Width++)
159  {
160  if (Dir == 1)
161  {
162  a_ChunkInterface.SetBlock(Width, Height, Z, E_BLOCK_NETHER_PORTAL, Dir);
163  }
164  else
165  {
166  a_ChunkInterface.SetBlock(X, Height, Width, E_BLOCK_NETHER_PORTAL, Dir);
167  }
168  }
169  }
170 
171  return;
172  }
173 
176  bool FindPortalSliceX(int X1, int X2, int Y, int Z, int MaxY, cChunkInterface & a_ChunkInterface)
177  {
178  Dir = 1; // Set assumed direction (will change if portal turns out to be facing the other direction)
179  bool FoundFrameXP = false, FoundFrameXM = false;
180  for (; ((a_ChunkInterface.GetBlock({X1, Y, Z}) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock({X1, Y + 1, Z}) == E_BLOCK_OBSIDIAN)); X1++) // Check XP for obsidian blocks, exempting corners
181  {
182  int Value = FindObsidianCeiling(X1, Y, Z, a_ChunkInterface, MaxY);
183  int ValueTwo = FindObsidianCeiling(X1, Y + 1, Z, a_ChunkInterface, MaxY); // For corners without obsidian
184  if ((Value == -1) || (ValueTwo == -1)) // FindObsidianCeiling returns -1 upon frame-find
185  {
186  FoundFrameXP = true; // Found a frame border in this direction, proceed in other direction (don't go further)
187  break;
188  }
189  else if ((Value != MaxY) && (ValueTwo != MaxY)) // Make sure that there is a valid portal 'slice'
190  {
191  return false; // Not valid slice, no portal can be formed
192  }
193  }
194  XZP = X1 - 1; // Set boundary of frame interior
195  for (; ((a_ChunkInterface.GetBlock({X2, Y, Z}) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock({X2, Y + 1, Z}) == E_BLOCK_OBSIDIAN)); X2--) // Go the other direction (XM)
196  {
197  int Value = FindObsidianCeiling(X2, Y, Z, a_ChunkInterface, MaxY);
198  int ValueTwo = FindObsidianCeiling(X2, Y + 1, Z, a_ChunkInterface, MaxY);
199  if ((Value == -1) || (ValueTwo == -1))
200  {
201  FoundFrameXM = true;
202  break;
203  }
204  else if ((Value != MaxY) && (ValueTwo != MaxY))
205  {
206  return false;
207  }
208  }
209  XZM = X2 + 1; // Set boundary, see previous
210 
211  return (FoundFrameXP && FoundFrameXM);
212  }
213 
215  bool FindPortalSliceZ(int X, int Y, int Z1, int Z2, int MaxY, cChunkInterface & a_ChunkInterface)
216  {
217  Dir = 2;
218  bool FoundFrameZP = false, FoundFrameZM = false;
219  for (; ((a_ChunkInterface.GetBlock({X, Y, Z1}) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock({X, Y + 1, Z1}) == E_BLOCK_OBSIDIAN)); Z1++)
220  {
221  int Value = FindObsidianCeiling(X, Y, Z1, a_ChunkInterface, MaxY);
222  int ValueTwo = FindObsidianCeiling(X, Y + 1, Z1, a_ChunkInterface, MaxY);
223  if ((Value == -1) || (ValueTwo == -1))
224  {
225  FoundFrameZP = true;
226  break;
227  }
228  else if ((Value != MaxY) && (ValueTwo != MaxY))
229  {
230  return false;
231  }
232  }
233  XZP = Z1 - 1;
234  for (; ((a_ChunkInterface.GetBlock({X, Y, Z2}) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock({X, Y + 1, Z2}) == E_BLOCK_OBSIDIAN)); Z2--)
235  {
236  int Value = FindObsidianCeiling(X, Y, Z2, a_ChunkInterface, MaxY);
237  int ValueTwo = FindObsidianCeiling(X, Y + 1, Z2, a_ChunkInterface, MaxY);
238  if ((Value == -1) || (ValueTwo == -1))
239  {
240  FoundFrameZM = true;
241  break;
242  }
243  else if ((Value != MaxY) && (ValueTwo != MaxY))
244  {
245  return false;
246  }
247  }
248  XZM = Z2 + 1;
249 
250  return (FoundFrameZP && FoundFrameZM);
251  }
252 
253  virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override
254  {
255  return true;
256  }
257 
258  virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
259  {
260  UNUSED(a_Meta);
261  return 15;
262  }
263 };
264 
265 
266 
267 
void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
virtual void OnPlaced(cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
Called by cWorld::SetBlock() after the block has been set.
Definition: BlockFire.h:30
T x
Definition: Vector3.h:17
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: BlockFire.h:258
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:42
bool FindPortalSliceX(int X1, int X2, int Y, int Z, int MaxY, cChunkInterface &a_ChunkInterface)
Evaluates if coordinates are a portal going XP / XM; returns true if so, and writes boundaries to var...
Definition: BlockFire.h:176
Definition: Player.h:27
bool EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface &a_ChunkInterface)
Evaluates if coords have a valid border on top, based on MaxY.
Definition: BlockFire.h:105
virtual int GetMaxNetherPortalWidth(void) const =0
NIBBLETYPE Dir
Definition: BlockFire.h:24
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:45
T y
Definition: Vector3.h:17
virtual int GetMinNetherPortalWidth(void) const =0
Returns or sets the minumim or maximum netherportal width.
T z
Definition: Vector3.h:17
static const int Height
Definition: ChunkDef.h:135
virtual int GetMinNetherPortalHeight(void) const =0
Returns or sets the minumim or maximum netherportal height.
int XZP
Portal boundary and direction variables.
Definition: BlockFire.h:23
void FindAndSetPortalFrame(int X, int Y, int Z, cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface)
Finds entire frame in any direction with the coordinates of a base block and fills hole with nether p...
Definition: BlockFire.h:124
virtual bool IsClickedThrough(void) override
Indicates whether the client will click through this block.
Definition: BlockFire.h:63
virtual bool DoesIgnoreBuildCollision(cChunkInterface &a_ChunkInterface, Vector3i a_Pos, cPlayer &a_Player, NIBBLETYPE a_Meta) override
Checks if the player can build "inside" this block.
Definition: BlockFire.h:253
bool FindPortalSliceZ(int X, int Y, int Z1, int Z2, int MaxY, cChunkInterface &a_ChunkInterface)
Evaluates if coords are a portal going ZP / ZM; returns true if so, and writes boundaries to variable...
Definition: BlockFire.h:215
#define UNUSED
Definition: Globals.h:152
int FindObsidianCeiling(int X, int Y, int Z, cChunkInterface &a_ChunkInterface, int MaxY=0)
Traces along YP until it finds an obsidian block, returns Y difference or 0 if no portal...
Definition: BlockFire.h:70
BLOCKTYPE GetBlock(Vector3i a_Pos)
Byte ColourID
Definition: Globals.h:118
Definition: Entity.h:73
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: BlockFire.h:53
cBlockFireHandler(BLOCKTYPE a_BlockType)
Definition: BlockFire.h:14
Definition: Item.h:36
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:234
virtual int GetMaxNetherPortalHeight(void) const =0