Cuberite
A lightweight, fast and extensible game server for Minecraft
NetherPortalScanner.cpp
Go to the documentation of this file.
1 
2 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
3 
4 #include "NetherPortalScanner.h"
5 #include "Entities/Entity.h"
6 #include "World.h"
7 
8 
9 
10 
11 
12 const double cNetherPortalScanner::OutOffset = 0.5;
13 const double cNetherPortalScanner::AcrossOffset = 0.5;
14 
15 
16 
17 
18 
19 cNetherPortalScanner::cNetherPortalScanner(cEntity * a_MovingEntity, cWorld * a_DestinationWorld, Vector3d a_DestPosition, int a_MaxY) :
20  m_Entity(a_MovingEntity),
21  m_World(a_DestinationWorld),
22  m_FoundPortal(false),
23  m_BuildPlatform(true),
24  m_Dir(Direction::X),
25  m_PortalLoc(a_DestPosition.Floor()),
26  m_Position(a_DestPosition),
27  m_MaxY(a_MaxY)
28 {
33  for (int x = MinX; x < MaxX; x++)
34  {
35  for (int z = MinZ; z < MaxZ; z++)
36  {
37  Add(x, z);
38  }
39  }
40  Enable(*a_DestinationWorld->GetChunkMap());
41 }
42 
43 
44 
45 
46 
47 void cNetherPortalScanner::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
48 {
49  cChunkDef::BlockTypes blocks;
50  m_World->GetChunkBlockTypes(a_ChunkX, a_ChunkZ, blocks);
51 
52  // Iterate through all of the blocks in the chunk
53  for (unsigned int i = 0; i < cChunkDef::NumBlocks; i++)
54  {
55  if (blocks[i] == E_BLOCK_NETHER_PORTAL)
56  {
57  Vector3i Coordinate = cChunkDef::IndexToCoordinate(i);
58  if (Coordinate.y >= m_MaxY)
59  {
60  // This is above the map, don't consider it.
61  continue;
62  }
63 
64  Vector3d PortalLoc = Vector3d(Coordinate.x + a_ChunkX * cChunkDef::Width, Coordinate.y, Coordinate.z + a_ChunkZ * cChunkDef::Width);
65  if (!m_FoundPortal)
66  {
67  m_FoundPortal = true;
68  m_PortalLoc = PortalLoc;
69  }
70  else
71  {
72  if ((PortalLoc - m_Position).SqrLength() < (m_PortalLoc - m_Position).SqrLength())
73  {
74  m_FoundPortal = true;
75  m_PortalLoc = PortalLoc;
76  }
77  }
78  }
79  }
80 }
81 
82 
83 
84 
85 
87 {
88  // Check the base
89  for (int i = 0; i < SearchSolidBaseWidth; i++)
90  {
91  for (int j = 0; j < PortalLength; j++)
92  {
93  BLOCKTYPE blocktype = m_World->GetBlock(a_BlockPos.x + i, a_BlockPos.y, a_BlockPos.z + j);
94  if (!cBlockInfo::IsSolid(blocktype))
95  {
96  return false;
97  }
98 
99  // Check the airspace
100  for (int k = 1; k < PortalHeight; k++)
101  {
102  blocktype = m_World->GetBlock(a_BlockPos.x + i, a_BlockPos.y + k, a_BlockPos.z + j);
103  if (blocktype != E_BLOCK_AIR)
104  {
105  return false;
106  }
107  }
108  }
109  }
110  return true;
111 }
112 
113 
114 
115 
116 
118 {
119  if (m_FoundPortal)
120  {
121  // Find the bottom of this portal
123  {
124  m_PortalLoc.y -= 1;
125  }
126  m_PortalLoc.y += 1;
127 
128  // Figure out which way the portal is facing
131  if ((BXP == E_BLOCK_NETHER_PORTAL) || (BXM == E_BLOCK_NETHER_PORTAL))
132  {
133  // The long axis is along X
135  }
136  else
137  {
138  // The long axis is along Z
140  }
141  }
142  else
143  {
144  // Scan the area for a suitable location
145  int minx = FloorC(m_Position.x) - BuildSearchRadius;
146  int minz = FloorC(m_Position.z) - BuildSearchRadius;
147  int maxx = FloorC(m_Position.x) + BuildSearchRadius;
148  int maxz = FloorC(m_Position.z) + BuildSearchRadius;
149  int maxy = m_MaxY;
150  std::vector<Vector3i> Possibilities;
151  int x, y, z;
152  for (y = 0; y < maxy - PortalHeight; y++)
153  {
154  for (x = minx; x < maxx - PortalLength; x++)
155  {
156  for (z = minz; z < maxz - SearchSolidBaseWidth; z++)
157  {
158  Vector3i Location = Vector3i(x, y, z);
159  if (IsValidBuildLocation(Location))
160  {
161  Possibilities.push_back(Vector3i(x, y, z));
162  }
163  }
164  }
165  }
166 
167  if (Possibilities.size() > 0)
168  {
169  m_BuildPlatform = false;
170 
171  // Find the nearest
172  double DistanceToClosest = (Possibilities[0] - m_Position).SqrLength();
173  Vector3i Closest = Possibilities[0];
174  for (const auto & itr : Possibilities)
175  {
176  double Distance = (itr - m_Position).SqrLength();
177  if (Distance < DistanceToClosest)
178  {
179  DistanceToClosest = Distance;
180  Closest = itr;
181  }
182  }
183 
184  m_PortalLoc = Closest;
185  }
186  }
187  return true;
188 }
189 
190 
191 
192 
193 
194 void cNetherPortalScanner::BuildNetherPortal(Vector3i a_Location, Direction a_Direction, bool a_IncludePlatform)
195 {
196  int x = a_Location.x;
197  int y = a_Location.y;
198  int z = a_Location.z;
199 
200  // Clear a 3x4x4 area starting right above the base
201  for (int i = 0; i < SearchSolidBaseWidth; i++)
202  {
203  for (int j = 0; j < PortalLength; j++)
204  {
205  for (int k = 1; k < PortalHeight; k++)
206  {
207  if (a_Direction == Direction::Y)
208  {
209  m_World->SetBlock(x + i, y + k, z + j, E_BLOCK_AIR, 0);
210  }
211  else if (a_Direction == Direction::X)
212  {
213  m_World->SetBlock(x + j, y + k, z + i, E_BLOCK_AIR, 0);
214  }
215  }
216  }
217  }
218 
219  // Put in an obsidian base
220  if (a_IncludePlatform)
221  {
222  for (int j = 0; j < PortalLength; j++)
223  {
224  // +2 on the short axis because that's where we deposit the entity
225  if (a_Direction == Direction::Y)
226  {
227  m_World->SetBlock(x + 2, y, z + j, E_BLOCK_OBSIDIAN, 0);
228  }
229  else if (a_Direction == Direction::X)
230  {
231  m_World->SetBlock(x + j, y, z + 2, E_BLOCK_OBSIDIAN, 0);
232  }
233  }
234  }
235 
236  // Build an obsidian frame
237  for (int i = 0; i < PortalHeight; i++)
238  {
239  if (a_Direction == Direction::Y)
240  {
241  m_World->SetBlock(x + 1, y + i, z, E_BLOCK_OBSIDIAN, 0);
242  m_World->SetBlock(x + 1, y + i, z + 3, E_BLOCK_OBSIDIAN, 0);
243  }
244  else if (a_Direction == Direction::X)
245  {
246  m_World->SetBlock(x, y + i, z + 1, E_BLOCK_OBSIDIAN, 0);
247  m_World->SetBlock(x + 3, y + i, z + 1, E_BLOCK_OBSIDIAN, 0);
248  }
249  }
250  for (int i = 0; i < PortalLength; i++)
251  {
252  if (a_Direction == Direction::Y)
253  {
254  m_World->SetBlock(x + 1, y + 4, z + i, E_BLOCK_OBSIDIAN, 0);
255  m_World->SetBlock(x + 1, y, z + i, E_BLOCK_OBSIDIAN, 0);
256  }
257  else if (a_Direction == Direction::X)
258  {
259  m_World->SetBlock(x + i, y + 4, z + 1, E_BLOCK_OBSIDIAN, 0);
260  m_World->SetBlock(x + i, y, z + 1, E_BLOCK_OBSIDIAN, 0);
261  }
262  }
263 
264  // Fill the frame (place a fire in the bottom)
265  m_World->SetBlock(x + 1, y + 1, z + 1, E_BLOCK_FIRE, 0);
266 }
267 
268 
269 
270 
271 
273 {
274  // Now we actually move the player
275  if (!m_FoundPortal)
276  {
277  // Build a new nether portal.
278  FLOGD("Building nether portal at {0}", m_PortalLoc);
280  m_PortalLoc.x += 1;
281  m_PortalLoc.y += 1;
282  m_PortalLoc.z += 1;
283  }
284 
285  // Put the entity near the opening
286  Vector3d Position = m_PortalLoc;
287  if (m_Dir == Direction::Y)
288  {
289  Position.x += OutOffset;
290  Position.z += AcrossOffset;
291  }
292  else if (m_Dir == Direction::X)
293  {
294  Position.x += AcrossOffset;
295  Position.z += OutOffset;
296  }
297 
298  FLOGD("Placing player at {0}", Position);
299  m_Entity->ScheduleMoveToWorld(m_World, Position, true);
300  delete this;
301 }
302 
BLOCKTYPE GetBlock(Vector3i a_BlockPos)
Returns the block type at the specified position.
Definition: World.h:416
T x
Definition: Vector3.h:17
bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE *a_BlockTypes)
Gets the chunk&#39;s blocks, only the block types.
Definition: World.cpp:2383
BLOCKTYPE BlockTypes[NumBlocks]
The type used for block type operations and storage, AXIS_ORDER ordering.
Definition: ChunkDef.h:150
static const int SearchSolidBaseWidth
The width of a solid base to search for when building.
static bool IsSolid(BLOCKTYPE a_Type)
Definition: BlockInfo.h:48
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:42
static const int Width
Definition: ChunkDef.h:134
static const int NumBlocks
Definition: ChunkDef.h:136
cNetherPortalScanner(cEntity *a_MovingEntity, cWorld *a_DestinationWorld, Vector3d a_DestPosition, int a_MaxY)
void ScheduleMoveToWorld(cWorld *a_World, Vector3d a_NewPosition, bool a_ShouldSetPortalCooldown=false, bool a_ShouldSendRespawn=false)
Schedules a MoveToWorld call to occur on the next Tick of the entity.
Definition: Entity.cpp:1313
void Enable(cChunkMap &a_ChunkMap)
Enables the ChunkStay on the specified chunkmap, causing it to load and generate chunks.
Definition: ChunkStay.cpp:80
Vector3i m_PortalLoc
The position of the pre-existing portal.
T y
Definition: Vector3.h:17
cWorld * m_World
The world we&#39;re moving the entity to.
T z
Definition: Vector3.h:17
bool m_BuildPlatform
Whether to build a platform.
cEntity * m_Entity
The entity that&#39;s being moved.
static const double OutOffset
Where to place the player out from the face and across the face.
virtual void OnDisabled(void) override
Called by the ChunkMap when the ChunkStay is disabled.
Definition: World.h:65
virtual void OnChunkAvailable(int a_ChunkX, int a_ChunkY) override
Called when a specific chunk become available.
Vector3< double > Vector3d
Definition: Vector3.h:445
static const double AcrossOffset
int m_MaxY
The maximum Y to scan to.
static const int PortalHeight
static const int BuildSearchRadius
cChunkMap * GetChunkMap(void)
Definition: World.h:1044
#define FLOGD(...)
Definition: LoggerSimple.h:48
bool m_FoundPortal
Whether we found a portal during the loading of the chunks.
Definition: Entity.h:73
void BuildNetherPortal(Vector3i a_Location, Direction a_Direction, bool a_IncludePlatform)
Builds a portal.
Vector3< int > Vector3i
Definition: Vector3.h:447
void Add(int a_ChunkX, int a_ChunkZ)
Adds a chunk to be locked from unloading.
Definition: ChunkStay.cpp:42
Direction m_Dir
The direction of the portal.
static const int SearchRadius
bool IsValidBuildLocation(Vector3i a_BlockPosition)
Whether the given location is a valid location to build a portal.
Vector3d m_Position
The center of the search area.
std::enable_if< std::is_arithmetic< T >::value, C >::type FloorC(T a_Value)
Floors a value, then casts it to C (an int by default)
Definition: Globals.h:362
static const int PortalLength
Length and height, including the obsidian.
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:1873
virtual bool OnAllChunksAvailable(void) override
Caled once all of the contained chunks are available.
static Vector3i IndexToCoordinate(size_t index)
Definition: ChunkDef.h:294
std::enable_if< std::is_arithmetic< T >::value, C >::type CeilC(T a_Value)
Ceils a value, then casts it to C (an int by default)
Definition: Globals.h:369