Cuberite
A lightweight, fast and extensible game server for Minecraft
BlockEndPortalFrame.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "BlockHandler.h"
5 
6 
7 
8 
9 
11  public cYawRotator<cBlockHandler, 0x03,
12  E_META_END_PORTAL_FRAME_ZP,
13  E_META_END_PORTAL_FRAME_XM,
14  E_META_END_PORTAL_FRAME_ZM,
15  E_META_END_PORTAL_FRAME_XP
16  >
17 {
18  using Super = cYawRotator<
19  cBlockHandler, 0x03,
24  >;
25 
26 public:
27 
28  using Super::Super;
29 
30 private:
31 
32  virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) const override
33  {
34  // E_META_END_PORTAL_FRAME_EYE is the bit which signifies the eye of ender is in it.
35  // LOG("PortalPlaced, meta %d", a_BlockMeta);
37  {
38  // LOG("Location is %d %d %d", a_BlockX, a_BlockY, a_BlockZ);
39  // Direction is the first two bits, masked by 0x3
40  FindAndSetPortal(a_BlockPos, a_BlockMeta & 3, a_ChunkInterface, a_WorldInterface);
41  }
42  }
43 
44 
45 
46 
47 
49  static bool FindAndSetPortal(Vector3i a_FirstFrame, NIBBLETYPE a_Direction, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface)
50  {
51  /*
52  PORTAL FINDING ALGORITH
53  =======================
54  - Get clicked base block
55  - Check diagonally (clockwise) for another portal block
56  - if exists, and has eye, Continue. Abort if any are facing the wrong direction.
57  - if doesn't exist, check horizontally (the block to the left of this block). Abort if there is no horizontal block.
58  - After a corner has been met, traverse the portal clockwise, ensuring valid portal frames connect the rectangle.
59  - Track the NorthWest Corner, and the dimensions.
60  - If dimensions are valid, create the portal.
61  */
62 
63  static_assert((E_META_END_PORTAL_FRAME_ZM - E_META_END_PORTAL_FRAME_XM) == 1, "Should be going clockwise");
64 
65  const int MIN_PORTAL_WIDTH = 3;
66  const int MAX_PORTAL_WIDTH = 4;
67 
68  // Directions to use for the clockwise traversal.
69  static const Vector3i Left[] =
70  {
71  { 1, 0, 0}, // 0, South, left block is East / XP
72  { 0, 0, 1}, // 1, West, left block is South / ZP
73  {-1, 0, 0}, // 2, North, left block is West / XM
74  { 0, 0, -1}, // 3, East, left block is North / ZM
75  };
76  static const Vector3i LeftForward[] =
77  {
78  { 1, 0, 1}, // 0, South, left block is SouthEast / XP ZP
79  {-1, 0, 1}, // 1, West, left block is SouthWest / XM ZP
80  {-1, 0, -1}, // 2, North, left block is NorthWest / XM ZM
81  { 1, 0, -1}, // 3, East, left block is NorthEast / XP ZM
82  };
83 
84 
85  int EdgesComplete = -1; // We start search _before_ finding the first edge
86  Vector3i NorthWestCorner;
87  int EdgeWidth[4] = { 1, 1, 1, 1 };
88  NIBBLETYPE CurrentDirection = a_Direction;
89  Vector3i CurrentPos = a_FirstFrame;
90 
91  // Scan clockwise until we have seen all 4 edges
92  while (EdgesComplete < 4)
93  {
94  // Check if we are at a corner
95  Vector3i NextPos = CurrentPos + LeftForward[CurrentDirection];
96  if (IsPortalFrame(a_ChunkInterface.GetBlock(NextPos)))
97  {
98  // We have found the corner, move clockwise to next edge
99  if (CurrentDirection == E_META_END_PORTAL_FRAME_XP)
100  {
101  // We are on the NW (XM, ZM) Corner
102  // Relative to the previous frame, the portal should appear to the right of this portal frame.
103  NorthWestCorner = NextPos - Left[CurrentDirection];
104  }
105 
106  if (EdgesComplete == -1)
107  {
108  // Reset current width, we will revisit it last
109  EdgeWidth[CurrentDirection] = 1;
110  }
111 
112  // Rotate 90 degrees clockwise
113  CurrentDirection = (CurrentDirection + 1) % 4;
114  EdgesComplete++;
115  }
116  else
117  {
118  // We are not at a corner, keep walking the edge
119  NextPos = CurrentPos + Left[CurrentDirection];
120 
121  EdgeWidth[CurrentDirection]++;
122  if (EdgeWidth[CurrentDirection] > MAX_PORTAL_WIDTH)
123  {
124  // Don't build a portal that is too long.
125  return false;
126  }
127  }
128 
129  if (!IsValidFrameAtPos(a_ChunkInterface, NextPos, CurrentDirection))
130  {
131  // Neither the edge nor the corner are valid portal blocks.
132  return false;
133  }
134 
135  CurrentPos = NextPos;
136  }
137 
138  if ((EdgeWidth[0] != EdgeWidth[2]) || (EdgeWidth[1] != EdgeWidth[3]))
139  {
140  // Mismatched Portal Dimensions.
141  return false;
142  }
143  if ((EdgeWidth[0] < MIN_PORTAL_WIDTH) || (EdgeWidth[1] < MIN_PORTAL_WIDTH))
144  {
145  // Portal too small.
146  return false;
147  }
148 
149  // LOG("NW corner (low corner) %d %d %d", Corner.x, Corner.y, Corner.z);
150  // LOG("%d by %d", Width[0], Width[1]);
151  for (int i = 0; i < EdgeWidth[0]; i++)
152  {
153  for (int j = 0; j < EdgeWidth[1]; j++)
154  {
155  a_ChunkInterface.SetBlock(NorthWestCorner.x + i, NorthWestCorner.y, NorthWestCorner.z + j, E_BLOCK_END_PORTAL, 0);
156  // TODO: Create block entity so portal doesn't become invisible on relog.
157  }
158  }
159  return true;
160  }
161 
162 
163 
164 
165 
167  static bool IsValidFrameAtPos(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, NIBBLETYPE a_ShouldFace)
168  {
170  NIBBLETYPE BlockMeta;
171 
172  return (
173  a_ChunkInterface.GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta) &&
175  (BlockMeta == (a_ShouldFace | E_META_END_PORTAL_FRAME_EYE))
176  );
177  }
178 
179 
180 
181 
184  {
186  }
187 
188 
189 
190 
191 
192  virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
193  {
194  UNUSED(a_Meta);
195  return 27;
196  }
197 };
198 
199 
200 
201 
@ E_META_END_PORTAL_FRAME_EYE
Definition: BlockType.h:677
@ E_META_END_PORTAL_FRAME_XP
Definition: BlockType.h:671
@ E_META_END_PORTAL_FRAME_ZP
Definition: BlockType.h:668
@ E_META_END_PORTAL_FRAME_XM
Definition: BlockType.h:669
@ E_META_END_PORTAL_FRAME_ZM
Definition: BlockType.h:670
@ E_BLOCK_END_PORTAL_FRAME
Definition: BlockType.h:135
@ E_BLOCK_END_PORTAL
Definition: BlockType.h:134
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
Byte ColourID
Definition: Globals.h:162
#define UNUSED
Definition: Globals.h:72
BlockType
Definition: BlockTypes.h:4
static bool FindAndSetPortal(Vector3i a_FirstFrame, NIBBLETYPE a_Direction, cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface)
Returns false if portal cannot be made, true if portal was made.
static bool IsValidFrameAtPos(cChunkInterface &a_ChunkInterface, Vector3i a_BlockPos, NIBBLETYPE a_ShouldFace)
Return true if this block is a portal frame, has an eye, and is facing the correct direction.
static bool IsPortalFrame(BLOCKTYPE BlockType)
Return true if this block is a portal frame.
virtual void OnPlaced(cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) const override
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
bool GetBlockTypeMeta(Vector3i a_Pos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta)
void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
BLOCKTYPE GetBlock(Vector3i a_Pos)
Mixin for blocks whose meta on placement depends on the yaw of the player placing the block.
Definition: Mixins.h:162
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17