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