Cuberite
A lightweight, fast and extensible game server for Minecraft
BlockRail.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "BlockHandler.h"
4 #include "BlockSlab.h"
5 #include "BlockStairs.h"
6 #include "BlockType.h"
7 #include "Blocks/Mixins.h"
8 #include "../BlockInfo.h"
9 #include "../Chunk.h"
10 #include "ChunkDef.h"
11 
12 
13 
14 
15 
17 {
20  E_PURE_NONE = 2
21 };
22 
23 
24 
25 
26 
27 class cBlockRailHandler final :
28  public cClearMetaOnDrop<cBlockHandler>
29 {
31 
32 public:
33 
34  using Super::Super;
35 
36 
37  static NIBBLETYPE FindMeta(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, BLOCKTYPE a_RailType)
38  {
39  NIBBLETYPE Meta = 0;
40  char RailsCnt = 0;
41  bool Neighbors[8]; // 0 - EAST, 1 - WEST, 2 - NORTH, 3 - SOUTH, 4 - EAST UP, 5 - WEST UP, 6 - NORTH UP, 7 - SOUTH UP
42  memset(Neighbors, 0, sizeof(Neighbors));
43  Neighbors[0] = (IsUnstable(a_ChunkInterface, a_BlockPos + Vector3i(1, 0, 0)) || !IsNotConnected(a_ChunkInterface, a_BlockPos, BLOCK_FACE_EAST, E_PURE_DOWN));
44  Neighbors[1] = (IsUnstable(a_ChunkInterface, a_BlockPos + Vector3i(-1, 0, 0)) || !IsNotConnected(a_ChunkInterface, a_BlockPos, BLOCK_FACE_WEST, E_PURE_DOWN));
45  Neighbors[2] = (IsUnstable(a_ChunkInterface, a_BlockPos + Vector3i(0, 0, -1)) || !IsNotConnected(a_ChunkInterface, a_BlockPos, BLOCK_FACE_NORTH, E_PURE_DOWN));
46  Neighbors[3] = (IsUnstable(a_ChunkInterface, a_BlockPos + Vector3i(0, 0, 1)) || !IsNotConnected(a_ChunkInterface, a_BlockPos, BLOCK_FACE_SOUTH, E_PURE_DOWN));
47  Neighbors[4] = (IsUnstable(a_ChunkInterface, a_BlockPos + Vector3i(1, 1, 0)) || !IsNotConnected(a_ChunkInterface, a_BlockPos + Vector3i(0, 1, 0), BLOCK_FACE_EAST, E_PURE_NONE));
48  Neighbors[5] = (IsUnstable(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0)) || !IsNotConnected(a_ChunkInterface, a_BlockPos + Vector3i(0, 1, 0), BLOCK_FACE_WEST, E_PURE_NONE));
49  Neighbors[6] = (IsUnstable(a_ChunkInterface, a_BlockPos + Vector3i(0, 1, -1)) || !IsNotConnected(a_ChunkInterface, a_BlockPos + Vector3i(0, 1, 0), BLOCK_FACE_NORTH, E_PURE_NONE));
50  Neighbors[7] = (IsUnstable(a_ChunkInterface, a_BlockPos + Vector3i(0, 1, 1)) || !IsNotConnected(a_ChunkInterface, a_BlockPos + Vector3i(0, 1, 0), BLOCK_FACE_SOUTH, E_PURE_NONE));
51  if (IsUnstable(a_ChunkInterface, a_BlockPos + Vector3i(1, -1, 0)) || !IsNotConnected(a_ChunkInterface, a_BlockPos - Vector3i(0, 1, 0), BLOCK_FACE_EAST))
52  {
53  Neighbors[0] = true;
54  }
55  if (IsUnstable(a_ChunkInterface, a_BlockPos - Vector3i(1, 1, 0)) || !IsNotConnected(a_ChunkInterface, a_BlockPos - Vector3i(0, 1, 0), BLOCK_FACE_WEST))
56  {
57  Neighbors[1] = true;
58  }
59  if (IsUnstable(a_ChunkInterface, a_BlockPos - Vector3i(0, 1, 1)) || !IsNotConnected(a_ChunkInterface, a_BlockPos - Vector3i(0, 1, 0), BLOCK_FACE_NORTH))
60  {
61  Neighbors[2] = true;
62  }
63  if (IsUnstable(a_ChunkInterface, a_BlockPos + Vector3i(0, -1, 1)) || !IsNotConnected(a_ChunkInterface, a_BlockPos - Vector3i(0, 1, 0), BLOCK_FACE_SOUTH))
64  {
65  Neighbors[3] = true;
66  }
67  for (int i = 0; i < 8; i++)
68  {
69  if (Neighbors[i])
70  {
71  RailsCnt++;
72  }
73  }
74  if (RailsCnt == 1)
75  {
76  if (Neighbors[7])
77  {
78  return E_META_RAIL_ASCEND_ZP;
79  }
80  else if (Neighbors[6])
81  {
82  return E_META_RAIL_ASCEND_ZM;
83  }
84  else if (Neighbors[5])
85  {
86  return E_META_RAIL_ASCEND_XM;
87  }
88  else if (Neighbors[4])
89  {
90  return E_META_RAIL_ASCEND_XP;
91  }
92  else if (Neighbors[0] || Neighbors[1])
93  {
94  return E_META_RAIL_XM_XP;
95  }
96  else if (Neighbors[2] || Neighbors[3])
97  {
98  return E_META_RAIL_ZM_ZP;
99  }
100  ASSERT(!"Weird neighbor count");
101  return Meta;
102  }
103  for (int i = 0; i < 4; i++)
104  {
105  if (Neighbors[i + 4])
106  {
107  Neighbors[i] = true;
108  }
109  }
110  if (RailsCnt > 1)
111  {
112  const bool CanCurve = a_RailType == E_BLOCK_RAIL;
113 
114  if (Neighbors[3] && Neighbors[0] && CanCurve)
115  {
117  }
118  else if (Neighbors[3] && Neighbors[1] && CanCurve)
119  {
121  }
122  else if (Neighbors[2] && Neighbors[0] && CanCurve)
123  {
125  }
126  else if (Neighbors[2] && Neighbors[1] && CanCurve)
127  {
129  }
130  else if (Neighbors[7] && Neighbors[2])
131  {
132  return E_META_RAIL_ASCEND_ZP;
133  }
134  else if (Neighbors[3] && Neighbors[6])
135  {
136  return E_META_RAIL_ASCEND_ZM;
137  }
138  else if (Neighbors[5] && Neighbors[0])
139  {
140  return E_META_RAIL_ASCEND_XM;
141  }
142  else if (Neighbors[4] && Neighbors[1])
143  {
144  return E_META_RAIL_ASCEND_XP;
145  }
146  else if (Neighbors[0] && Neighbors[1])
147  {
148  return E_META_RAIL_XM_XP;
149  }
150  else if (Neighbors[2] && Neighbors[3])
151  {
152  return E_META_RAIL_ZM_ZP;
153  }
154 
155  if (CanCurve)
156  {
157  ASSERT(!"Weird neighbor count");
158  }
159  }
160  return Meta;
161  }
162 
163 private:
164 
165  static bool CanBeSupportedBy(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
166  {
167  if (cBlockSlabHandler::IsAnySlabType(a_BlockType))
168  {
169  return (a_BlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN);
170  }
171  else if (cBlockStairsHandler::IsAnyStairType(a_BlockType))
172  {
173  return (a_BlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN);
174  }
175  return cBlockInfo::FullyOccupiesVoxel(a_BlockType);
176  }
177 
178  virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, NIBBLETYPE a_Meta) const override
179  {
180  BLOCKTYPE BelowBlock;
181  NIBBLETYPE BelowBlockMeta;
182  a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta);
183 
184  if ((a_Position.y <= 0) || !CanBeSupportedBy(BelowBlock, BelowBlockMeta))
185  {
186  return false;
187  }
188 
189  switch (a_Meta)
190  {
195  {
196  // Mapping between the meta and the neighbors that need checking
197  a_Meta -= E_META_RAIL_ASCEND_XP; // Base index at zero
198  static const Vector3i Coords[] =
199  {
200  { 1, 0, 0}, // east, XP
201  {-1, 0, 0}, // west, XM
202  { 0, 0, -1}, // north, ZM
203  { 0, 0, 1}, // south, ZP
204  } ;
206  NIBBLETYPE BlockMeta;
207  if (!a_Chunk.UnboundedRelGetBlock(a_Position + Coords[a_Meta], BlockType, BlockMeta))
208  {
209  // Too close to the edge, cannot simulate
210  return true;
211  }
213  }
214  }
215 
216  return true;
217  }
218 
219 
220  static bool IsUnstable(cChunkInterface & a_ChunkInterface, Vector3i a_Pos)
221  {
222  if (!IsBlockRail(a_ChunkInterface.GetBlock(a_Pos)))
223  {
224  return false;
225  }
226  NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_Pos);
227  switch (Meta)
228  {
229  case E_META_RAIL_ZM_ZP:
230  {
231  if (
232  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_NORTH, E_PURE_DOWN) ||
233  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_SOUTH, E_PURE_DOWN)
234  )
235  {
236  return true;
237  }
238  break;
239  }
240 
241  case E_META_RAIL_XM_XP:
242  {
243  if (
244  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_EAST, E_PURE_DOWN) ||
245  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_WEST, E_PURE_DOWN)
246  )
247  {
248  return true;
249  }
250  break;
251  }
252 
254  {
255  if (
256  IsNotConnected(a_ChunkInterface, a_Pos + Vector3i(0, 1, 0), BLOCK_FACE_EAST) ||
257  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_WEST)
258  )
259  {
260  return true;
261  }
262  break;
263  }
264 
266  {
267  if (
268  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_EAST) ||
269  IsNotConnected(a_ChunkInterface, a_Pos + Vector3i(0, 1, 0), BLOCK_FACE_WEST)
270  )
271  {
272  return true;
273  }
274  break;
275  }
276 
278  {
279  if (
280  IsNotConnected(a_ChunkInterface, a_Pos + Vector3i(0, 1, 0), BLOCK_FACE_NORTH) ||
281  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_SOUTH)
282  )
283  {
284  return true;
285  }
286  break;
287  }
288 
290  {
291  if (
292  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_NORTH) ||
293  IsNotConnected(a_ChunkInterface, a_Pos + Vector3i(0, 1, 0), BLOCK_FACE_SOUTH)
294  )
295  {
296  return true;
297  }
298  break;
299  }
300 
302  {
303  if (
304  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_SOUTH) ||
305  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_EAST)
306  )
307  {
308  return true;
309  }
310  break;
311  }
312 
314  {
315  if (
316  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_SOUTH) ||
317  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_WEST)
318  )
319  {
320  return true;
321  }
322  break;
323  }
324 
326  {
327  if (
328  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_NORTH) ||
329  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_WEST)
330  )
331  {
332  return true;
333  }
334  break;
335  }
336 
338  {
339  if (
340  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_NORTH) ||
341  IsNotConnected(a_ChunkInterface, a_Pos, BLOCK_FACE_EAST)
342  )
343  {
344  return true;
345  }
346  break;
347  }
348  }
349  return false;
350  }
351 
352 
353  static bool IsNotConnected(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, eBlockFace a_BlockFace, char a_Pure = 0)
354  {
355  a_Pos = AddFaceDirection(a_Pos, a_BlockFace, false);
356 
357  NIBBLETYPE Meta;
358 
359  if (!IsBlockRail(a_ChunkInterface.GetBlock(a_Pos)))
360  {
361  if (!IsBlockRail(a_ChunkInterface.GetBlock(a_Pos + Vector3i(0, 1, 0))) || (a_Pure != E_PURE_UPDOWN))
362  {
363  if (!IsBlockRail(a_ChunkInterface.GetBlock(a_Pos - Vector3i(0, 1, 0))) || (a_Pure == E_PURE_NONE))
364  {
365  return true;
366  }
367  else
368  {
369  Meta = a_ChunkInterface.GetBlockMeta(a_Pos - Vector3i(0, 1, 0));
370  }
371  }
372  else
373  {
374  Meta = a_ChunkInterface.GetBlockMeta(a_Pos + Vector3i(0, 1, 0));
375  }
376  }
377  else
378  {
379  Meta = a_ChunkInterface.GetBlockMeta(a_Pos);
380  }
381 
382  switch (a_BlockFace)
383  {
384  case BLOCK_FACE_NORTH:
385  {
386  if (
387  (Meta == E_META_RAIL_ZM_ZP) ||
388  (Meta == E_META_RAIL_ASCEND_ZM) ||
389  (Meta == E_META_RAIL_ASCEND_ZP) ||
390  (Meta == E_META_RAIL_CURVED_ZP_XP) ||
391  (Meta == E_META_RAIL_CURVED_ZP_XM)
392  )
393  {
394  return false;
395  }
396  break;
397  }
398 
399  case BLOCK_FACE_SOUTH:
400  {
401  if (
402  (Meta == E_META_RAIL_ZM_ZP) ||
403  (Meta == E_META_RAIL_ASCEND_ZM) ||
404  (Meta == E_META_RAIL_ASCEND_ZP) ||
405  (Meta == E_META_RAIL_CURVED_ZM_XP) ||
406  (Meta == E_META_RAIL_CURVED_ZM_XM)
407  )
408  {
409  return false;
410  }
411  break;
412  }
413 
414  case BLOCK_FACE_EAST:
415  {
416  if (
417  (Meta == E_META_RAIL_XM_XP) ||
418  (Meta == E_META_RAIL_ASCEND_XP) ||
419  (Meta == E_META_RAIL_ASCEND_XM) ||
420  (Meta == E_META_RAIL_CURVED_ZP_XM) ||
421  (Meta == E_META_RAIL_CURVED_ZM_XM)
422  )
423  {
424  return false;
425  }
426  break;
427  }
428  case BLOCK_FACE_WEST:
429  {
430  if (
431  (Meta == E_META_RAIL_XM_XP) ||
432  (Meta == E_META_RAIL_ASCEND_XP) ||
433  (Meta == E_META_RAIL_ASCEND_XM) ||
434  (Meta == E_META_RAIL_CURVED_ZP_XP) ||
435  (Meta == E_META_RAIL_CURVED_ZM_XP)
436  )
437  {
438  return false;
439  }
440  break;
441  }
442  case BLOCK_FACE_NONE:
443  case BLOCK_FACE_YM:
444  case BLOCK_FACE_YP:
445  {
446  break;
447  }
448  }
449  return true;
450  }
451 
452 
453  virtual void OnBroken(
454  cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
455  Vector3i a_BlockPos,
456  BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta,
457  const cEntity * a_Digger
458  ) const override
459  {
460  Super::OnBroken(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_OldBlockType, a_OldBlockMeta, a_Digger);
461 
462  // Alert diagonal rails:
463  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE);
464  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE);
465  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE);
466  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE);
467  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE);
468  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE);
469  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE);
470  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE);
471  }
472 
473 
474  virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) const override
475  {
476  const auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
477  const auto NewMeta = FindMeta(a_ChunkInterface, a_BlockPos, m_BlockType);
478  if ((Meta != NewMeta) && IsUnstable(a_ChunkInterface, a_BlockPos))
479  {
480  a_ChunkInterface.FastSetBlock(a_BlockPos, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? NewMeta : NewMeta | (Meta & 0x08));
481  }
482 
483  Super::OnNeighborChanged(a_ChunkInterface, a_BlockPos, a_WhichNeighbor);
484  }
485 
486 
487  virtual void OnPlaced(
488  cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
489  Vector3i a_BlockPos,
490  BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
491  ) const override
492  {
493  Super::OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_BlockType, a_BlockMeta);
494 
495  // Alert diagonal rails:
496  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE);
497  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE);
498  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE);
499  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE);
500  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE);
501  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE);
502  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE);
503  NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE);
504  }
505 
506 
507  virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) const override
508  {
509  // Bit 0x08 is a flag when a_Meta is in the range 0x00--0x05 and 0x0A--0x0F.
510  // Bit 0x08 specifies direction when a_Meta is in the range 0x06-0x09.
511  if ((a_Meta < 0x06) || (a_Meta > 0x09))
512  {
513  // Save powered rail flag.
514  NIBBLETYPE OtherMeta = a_Meta & 0x08;
515  // Rotates according to table; 0x07 == 0111.
516  // Rails can either be flat (North / South) or Ascending (Asc. East)
517  switch (a_Meta & 0x07)
518  {
519  case 0x00: return 0x01 + OtherMeta; // North / South -> East / West
520  case 0x01: return 0x00 + OtherMeta; // East / West -> North / South
521 
522  case 0x02: return 0x04 + OtherMeta; // Asc. East -> Asc. North
523  case 0x04: return 0x03 + OtherMeta; // Asc. North -> Asc. West
524  case 0x03: return 0x05 + OtherMeta; // Asc. West -> Asc. South
525  case 0x05: return 0x02 + OtherMeta; // Asc. South -> Asc. East
526  }
527  }
528  else
529  {
530  switch (a_Meta)
531  {
532  // Corner Directions
533  case 0x06: return 0x09; // Northwest Cnr. -> Southwest Cnr.
534  case 0x07: return 0x06; // Northeast Cnr. -> Northwest Cnr.
535  case 0x08: return 0x07; // Southeast Cnr. -> Northeast Cnr.
536  case 0x09: return 0x08; // Southwest Cnr. -> Southeast Cnr.
537  }
538  }
539  // To avoid a compiler warning;
540  return a_Meta;
541  }
542 
543 
544  virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) const override
545  {
546  // Bit 0x08 is a flag for value in the range 0x00--0x05 and specifies direction for values withint 0x006--0x09.
547  if ((a_Meta < 0x06) || (a_Meta > 0x09))
548  {
549  // Save powered rail flag.
550  NIBBLETYPE OtherMeta = a_Meta & 0x08;
551  // Rotates according to table; 0x07 == 0111.
552  // Rails can either be flat (North / South) or Ascending (Asc. East)
553  switch (a_Meta & 0x07)
554  {
555  case 0x00: return 0x01 + OtherMeta; // North / South -> East / West
556  case 0x01: return 0x00 + OtherMeta; // East / West -> North / South
557 
558  case 0x02: return 0x05 + OtherMeta; // Asc. East -> Asc. South
559  case 0x05: return 0x03 + OtherMeta; // Asc. South -> Asc. West
560  case 0x03: return 0x04 + OtherMeta; // Asc. West -> Asc. North
561  case 0x04: return 0x02 + OtherMeta; // Asc. North -> Asc. East
562  }
563  }
564  else
565  {
566  switch (a_Meta)
567  {
568  // Corner Directions
569  case 0x06: return 0x07; // Northwest Cnr. -> Northeast Cnr.
570  case 0x07: return 0x08; // Northeast Cnr. -> Southeast Cnr.
571  case 0x08: return 0x09; // Southeast Cnr. -> Southwest Cnr.
572  case 0x09: return 0x06; // Southwest Cnr. -> Northwest Cnr.
573  }
574  }
575  // To avoid a compiler warning;
576  return a_Meta;
577  }
578 
579 
580  virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) const override
581  {
582  // MirrorXY basically flips the ZP and ZM parts of the meta
583  if (m_BlockType == E_BLOCK_RAIL)
584  {
585  // Basic rails can have curves and thus their meta behaves differently from specialized rails:
586  switch (a_Meta)
587  {
598  }
599  }
600  else
601  {
602  // Specialized rails don't have curves, instead they use bit 0x08 as a flag
603  NIBBLETYPE flag = a_Meta & 0x08;
604  switch (a_Meta & 0x07)
605  {
606  case E_META_RAIL_ASCEND_XM: return flag | E_META_RAIL_ASCEND_XM;
607  case E_META_RAIL_ASCEND_XP: return flag | E_META_RAIL_ASCEND_XP;
608  case E_META_RAIL_ASCEND_ZM: return flag | E_META_RAIL_ASCEND_ZP;
609  case E_META_RAIL_ASCEND_ZP: return flag | E_META_RAIL_ASCEND_ZM;
610  case E_META_RAIL_XM_XP: return flag | E_META_RAIL_XM_XP;
611  case E_META_RAIL_ZM_ZP: return flag | E_META_RAIL_ZM_ZP;
612  }
613  }
614  ASSERT(!"Unknown rail meta");
615  return a_Meta;
616  }
617 
618 
619  virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) const override
620  {
621  // MirrorYZ basically flips the XP and XM parts of the meta
622  if (m_BlockType == E_BLOCK_RAIL)
623  {
624  // Basic rails can have curves and thus their meta behaves differently from specialized rails:
625  switch (a_Meta)
626  {
637  }
638  }
639  else
640  {
641  // Specialized rails don't have curves, instead they use bit 0x08 as a flag
642  NIBBLETYPE flag = a_Meta & 0x08;
643  switch (a_Meta & 0x07)
644  {
645  case E_META_RAIL_ASCEND_XM: return flag | E_META_RAIL_ASCEND_XP;
646  case E_META_RAIL_ASCEND_XP: return flag | E_META_RAIL_ASCEND_XM;
647  case E_META_RAIL_ASCEND_ZM: return flag | E_META_RAIL_ASCEND_ZM;
648  case E_META_RAIL_ASCEND_ZP: return flag | E_META_RAIL_ASCEND_ZP;
649  case E_META_RAIL_XM_XP: return flag | E_META_RAIL_XM_XP;
650  case E_META_RAIL_ZM_ZP: return flag | E_META_RAIL_ZM_ZP;
651  }
652  }
653  ASSERT(!"Unknown rail meta");
654  return a_Meta;
655  }
656 
657 
658  virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
659  {
660  UNUSED(a_Meta);
661  return 0;
662  }
663 } ;
bool IsBlockRail(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:67
ENUM_PURE
Definition: BlockRail.h:17
@ E_PURE_DOWN
Definition: BlockRail.h:19
@ E_PURE_NONE
Definition: BlockRail.h:20
@ E_PURE_UPDOWN
Definition: BlockRail.h:18
@ E_META_RAIL_CURVED_ZP_XP
Definition: BlockType.h:787
@ E_META_WOODEN_SLAB_UPSIDE_DOWN
Definition: BlockType.h:989
@ E_BLOCK_STAIRS_UPSIDE_DOWN
Definition: BlockType.h:902
@ E_META_RAIL_ASCEND_ZM
Definition: BlockType.h:785
@ E_META_RAIL_ZM_ZP
Definition: BlockType.h:781
@ E_META_RAIL_ASCEND_XM
Definition: BlockType.h:784
@ E_META_RAIL_CURVED_ZP_XM
Definition: BlockType.h:788
@ E_META_RAIL_ASCEND_XP
Definition: BlockType.h:783
@ E_META_RAIL_XM_XP
Definition: BlockType.h:782
@ E_META_RAIL_ASCEND_ZP
Definition: BlockType.h:786
@ E_META_RAIL_CURVED_ZM_XM
Definition: BlockType.h:789
@ E_META_RAIL_CURVED_ZM_XP
Definition: BlockType.h:790
@ E_BLOCK_RAIL
Definition: BlockType.h:79
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
void AddFaceDirection(int &a_BlockX, int &a_BlockY, int &a_BlockZ, eBlockFace a_BlockFace, bool a_bInverse)
Modifies the specified coords so that they point to the block adjacent to the one specified through i...
Definition: Defines.cpp:378
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc.
Definition: Defines.h:38
@ BLOCK_FACE_EAST
Definition: Defines.h:53
@ BLOCK_FACE_YP
Definition: Defines.h:43
@ BLOCK_FACE_YM
Definition: Defines.h:42
@ BLOCK_FACE_SOUTH
Definition: Defines.h:51
@ BLOCK_FACE_WEST
Definition: Defines.h:52
@ BLOCK_FACE_NORTH
Definition: Defines.h:50
@ BLOCK_FACE_NONE
Definition: Defines.h:39
Byte ColourID
Definition: Globals.h:162
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
BlockType
Definition: BlockTypes.h:4
Vector3< int > Vector3i
Definition: Vector3.h:487
static bool FullyOccupiesVoxel(BLOCKTYPE Block)
Does this block fully occupy its voxel - is it a 'full' block?
Definition: BlockInfo.cpp:606
static void NeighborChanged(cChunkInterface &a_ChunkInterface, Vector3i a_NeighborPos, eBlockFace a_WhichNeighbor)
Notifies the specified neighbor that the current block has changed.
virtual void OnPlaced(cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) const
Called by cWorld::SetBlock() after the block has been set.
Definition: BlockHandler.h:50
virtual void OnNeighborChanged(cChunkInterface &a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) const
Called when a direct neighbor of this block has been changed.
virtual void OnBroken(cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta, const cEntity *a_Digger) const
Called after a block gets broken (replaced with air), by natural means.
Definition: BlockHandler.h:60
const BLOCKTYPE m_BlockType
Definition: BlockHandler.h:205
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) const override
Rotates a given block meta clockwise.
Definition: BlockRail.h:544
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: BlockRail.h:658
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.
Definition: BlockRail.h:474
static bool IsUnstable(cChunkInterface &a_ChunkInterface, Vector3i a_Pos)
Definition: BlockRail.h:220
static bool IsNotConnected(cChunkInterface &a_ChunkInterface, Vector3i a_Pos, eBlockFace a_BlockFace, char a_Pure=0)
Definition: BlockRail.h:353
virtual void OnPlaced(cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) const override
Called by cWorld::SetBlock() after the block has been set.
Definition: BlockRail.h:487
virtual void OnBroken(cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta, const cEntity *a_Digger) const override
Called after a block gets broken (replaced with air), by natural means.
Definition: BlockRail.h:453
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) const override
Mirros a given block meta around the YZ plane.
Definition: BlockRail.h:619
static NIBBLETYPE FindMeta(cChunkInterface &a_ChunkInterface, Vector3i a_BlockPos, BLOCKTYPE a_RailType)
Definition: BlockRail.h:37
static bool CanBeSupportedBy(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Definition: BlockRail.h:165
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) const override
Mirrors a given block meta around the XY plane.
Definition: BlockRail.h:580
virtual bool CanBeAt(const cChunk &a_Chunk, const Vector3i a_Position, NIBBLETYPE a_Meta) const override
Checks if the block can stay at the specified relative coords in the chunk.
Definition: BlockRail.h:178
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) const override
Rotates a given block meta counter-clockwise.
Definition: BlockRail.h:507
static bool IsAnySlabType(BLOCKTYPE a_BlockType)
Returns true if the specified blocktype is one of the slabs handled by this handler.
Definition: BlockSlab.h:30
static bool IsAnyStairType(BLOCKTYPE a_Block)
Definition: BlockStairs.h:19
NIBBLETYPE GetBlockMeta(Vector3i a_Pos)
BLOCKTYPE GetBlock(Vector3i a_Pos)
void FastSetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
Mixin to clear the block's meta value when converting to a pickup.
Definition: Mixins.h:31
Definition: Chunk.h:36
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 GetBlockTypeMeta(Vector3i a_RelPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Definition: Chunk.cpp:1757
Definition: Entity.h:76
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