Cuberite
A lightweight, fast and extensible game server for Minecraft
ItemEyeOfEnder.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "ItemHandler.h"
5 #include "ItemThrowable.h"
6 
7 
8 
9 
10 
13 {
15 
16 public:
17 
18  constexpr cItemEyeOfEnderHandler(int a_ItemType):
19  Super(a_ItemType, cProjectileEntity::pkSnowball, 30)
20  {
21  }
22 
23 
24 
25 
26 
27  virtual bool OnItemUse(
28  cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
29  const Vector3i a_ClickedBlockPos,
30  eBlockFace a_ClickedBlockFace
31  ) const override
32  {
33  // Try to fill an End Portal Frame block:
34  if (a_ClickedBlockFace != BLOCK_FACE_NONE)
35  {
36  BLOCKTYPE FacingBlock;
37  NIBBLETYPE FacingMeta;
38  a_World->GetBlockTypeMeta(a_ClickedBlockPos, FacingBlock, FacingMeta);
39  if (FacingBlock == E_BLOCK_END_PORTAL_FRAME)
40  {
41  // Fill the portal frame. E_META_END_PORTAL_EYE is the bit for holding the eye of ender.
43  {
44  a_World->SetBlock(a_ClickedBlockPos, E_BLOCK_END_PORTAL_FRAME, FacingMeta | E_META_END_PORTAL_FRAME_EYE);
45  if (!a_Player->IsGameModeCreative())
46  {
47  a_Player->GetInventory().RemoveOneEquippedItem();
48  }
49 
50  cChunkInterface ChunkInterface(a_World->GetChunkMap());
51 
52  // Try to spawn portal:
53  FindAndSetPortal(a_ClickedBlockPos, FacingMeta & 3, ChunkInterface, *a_World);
54  return true;
55  }
56  }
57  return false;
58  }
59 
60  // TODO: Create projectile for Eye Of Ender
61  // return Super::OnItemUse(a_World, a_Player, a_PluginInterface, a_Item, a_ClickedBlockPos, a_ClickedBlockFace);
62 
63  return false;
64  }
65 
66 
67 
68 
70  static bool FindAndSetPortal(Vector3i a_FirstFrame, NIBBLETYPE a_Direction, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface)
71  {
72  /*
73  PORTAL FINDING ALGORITH
74  =======================
75  - Get clicked base block
76  - Check diagonally (clockwise) for another portal block
77  - if exists, and has eye, Continue. Abort if any are facing the wrong direction.
78  - if doesn't exist, check horizontally (the block to the left of this block). Abort if there is no horizontal block.
79  - After a corner has been met, traverse the portal clockwise, ensuring valid portal frames connect the rectangle.
80  - Track the NorthWest Corner, and the dimensions.
81  - If dimensions are valid, create the portal.
82  */
83 
84  static_assert((E_META_END_PORTAL_FRAME_ZM - E_META_END_PORTAL_FRAME_XM) == 1, "Should be going clockwise");
85 
86  const int MIN_PORTAL_WIDTH = 3;
87  const int MAX_PORTAL_WIDTH = 4;
88 
89  // Directions to use for the clockwise traversal.
90  static const Vector3i Left[] =
91  {
92  { 1, 0, 0}, // 0, South, left block is East / XP
93  { 0, 0, 1}, // 1, West, left block is South / ZP
94  {-1, 0, 0}, // 2, North, left block is West / XM
95  { 0, 0, -1}, // 3, East, left block is North / ZM
96  };
97  static const Vector3i LeftForward[] =
98  {
99  { 1, 0, 1}, // 0, South, left block is SouthEast / XP ZP
100  {-1, 0, 1}, // 1, West, left block is SouthWest / XM ZP
101  {-1, 0, -1}, // 2, North, left block is NorthWest / XM ZM
102  { 1, 0, -1}, // 3, East, left block is NorthEast / XP ZM
103  };
104 
105 
106  int EdgesComplete = -1; // We start search _before_ finding the first edge
107  Vector3i NorthWestCorner;
108  int EdgeWidth[4] = { 1, 1, 1, 1 };
109  NIBBLETYPE CurrentDirection = a_Direction;
110  Vector3i CurrentPos = a_FirstFrame;
111 
112  // Scan clockwise until we have seen all 4 edges
113  while (EdgesComplete < 4)
114  {
115  // Check if we are at a corner
116  Vector3i NextPos = CurrentPos + LeftForward[CurrentDirection];
117  if (IsPortalFrame(a_ChunkInterface.GetBlock(NextPos)))
118  {
119  // We have found the corner, move clockwise to next edge
120  if (CurrentDirection == E_META_END_PORTAL_FRAME_XP)
121  {
122  // We are on the NW (XM, ZM) Corner
123  // Relative to the previous frame, the portal should appear to the right of this portal frame.
124  NorthWestCorner = NextPos - Left[CurrentDirection];
125  }
126 
127  if (EdgesComplete == -1)
128  {
129  // Reset current width, we will revisit it last
130  EdgeWidth[CurrentDirection] = 1;
131  }
132 
133  // Rotate 90 degrees clockwise
134  CurrentDirection = (CurrentDirection + 1) % 4;
135  EdgesComplete++;
136  }
137  else
138  {
139  // We are not at a corner, keep walking the edge
140  NextPos = CurrentPos + Left[CurrentDirection];
141 
142  EdgeWidth[CurrentDirection]++;
143  if (EdgeWidth[CurrentDirection] > MAX_PORTAL_WIDTH)
144  {
145  // Don't build a portal that is too long.
146  return false;
147  }
148  }
149 
150  if (!IsValidFrameAtPos(a_ChunkInterface, NextPos, CurrentDirection))
151  {
152  // Neither the edge nor the corner are valid portal blocks.
153  return false;
154  }
155 
156  CurrentPos = NextPos;
157  }
158 
159  if ((EdgeWidth[0] != EdgeWidth[2]) || (EdgeWidth[1] != EdgeWidth[3]))
160  {
161  // Mismatched Portal Dimensions.
162  return false;
163  }
164  if ((EdgeWidth[0] < MIN_PORTAL_WIDTH) || (EdgeWidth[1] < MIN_PORTAL_WIDTH))
165  {
166  // Portal too small.
167  return false;
168  }
169 
170  for (int i = 0; i < EdgeWidth[0]; i++)
171  {
172  for (int j = 0; j < EdgeWidth[1]; j++)
173  {
174  a_ChunkInterface.SetBlock(NorthWestCorner.x + i, NorthWestCorner.y, NorthWestCorner.z + j, E_BLOCK_END_PORTAL, 0);
175  }
176  }
177  return true;
178  }
179 
180 
181 
182 
183 
185  static bool IsValidFrameAtPos(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, NIBBLETYPE a_ShouldFace)
186  {
188  NIBBLETYPE BlockMeta;
189 
190  return (
191  a_ChunkInterface.GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta) &&
193  (BlockMeta == (a_ShouldFace | E_META_END_PORTAL_FRAME_EYE))
194  );
195  }
196 
197 
198 
199 
202  {
204  }
205 } ;
206 
207 
208 
209 
210 
@ 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_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
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc.
Definition: Defines.h:38
@ BLOCK_FACE_NONE
Definition: Defines.h:39
BlockType
Definition: BlockTypes.h:4
This interface is used to decouple block handlers from the cPluginManager dependency through cWorld.
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)
Definition: Player.h:29
bool IsGameModeCreative(void) const
Returns true if the player is in Creative mode, either explicitly, or by inheriting from current worl...
Definition: Player.cpp:1025
cInventory & GetInventory(void)
Definition: Player.h:156
bool RemoveOneEquippedItem(void)
Removes one item out of the currently equipped item stack, returns true if successful,...
Definition: Inventory.cpp:232
Definition: Item.h:37
static bool IsPortalFrame(BLOCKTYPE BlockType)
Return true if this block is a portal frame.
virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, cBlockPluginInterface &a_PluginInterface, const cItem &a_Item, const Vector3i a_ClickedBlockPos, eBlockFace a_ClickedBlockFace) const override
Called when the player tries to use the item (right mouse button).
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 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.
constexpr cItemEyeOfEnderHandler(int a_ItemType)
constexpr cItemThrowableHandler(int a_ItemType, cProjectileEntity::eKind a_ProjectileKind, double a_SpeedCoeff)
Definition: ItemThrowable.h:20
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17
Definition: World.h:53
bool GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Retrieves the block type and meta at the specified coords.
Definition: World.cpp:1779
cChunkMap * GetChunkMap(void)
Definition: World.h:852
void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
Definition: World.cpp:1743