the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "net.minecraft.world.entity.h"
3#include "net.minecraft.world.level.h"
4#include "net.minecraft.world.level.tile.h"
5#include "net.minecraft.world.level.dimension.h"
6#include "..\Minecraft.Client\ServerLevel.h"
7#include "PortalForcer.h"
8
9PortalForcer::PortalPosition::PortalPosition(int x, int y, int z, __int64 time) : Pos(x, y, z)
10{
11 lastUsed = time;
12}
13
14PortalForcer::PortalForcer(ServerLevel *level)
15{
16 this->level = level;
17 random = new Random(level->getSeed());
18}
19
20PortalForcer::~PortalForcer()
21{
22 for(AUTO_VAR(it,cachedPortals.begin()); it != cachedPortals.end(); ++it)
23 {
24 delete it->second;
25 }
26}
27
28void PortalForcer::force(shared_ptr<Entity> e, double xOriginal, double yOriginal, double zOriginal, float yRotOriginal)
29{
30 if (level->dimension->id == 1)
31 {
32 int x = Mth::floor(e->x);
33 int y = Mth::floor(e->y) - 1;
34 int z = Mth::floor(e->z);
35
36 int xa = 1;
37 int za = 0;
38 for (int b = -2; b <= 2; b++)
39 {
40 for (int s = -2; s <= 2; s++)
41 {
42 for (int h = -1; h < 3; h++)
43 {
44 int xt = x + s * xa + b * za;
45 int yt = y + h;
46 int zt = z + s * za - b * xa;
47
48 bool border = h < 0;
49
50 level->setTileAndUpdate(xt, yt, zt, border ? Tile::obsidian_Id : 0);
51 }
52 }
53 }
54
55 e->moveTo(x, y, z, e->yRot, 0);
56 e->xd = e->yd = e->zd = 0;
57
58 return;
59 }
60
61 if (findPortal(e, xOriginal, yOriginal, zOriginal, yRotOriginal))
62 {
63 return;
64 }
65
66 createPortal(e);
67 findPortal(e, xOriginal, yOriginal, zOriginal, yRotOriginal);
68}
69
70
71bool PortalForcer::findPortal(shared_ptr<Entity> e, double xOriginal, double yOriginal, double zOriginal, float yRotOriginal)
72{
73 // 4J Stu - Decrease the range at which we search for a portal in the nether given our smaller nether
74 int r = 16;//* 8;
75 if(level->dimension->id == -1)
76 {
77 r *= 3;
78 }
79 else
80 {
81#ifdef __PSVITA__
82 // AP poor little Vita takes 30 seconds to leave the Nether. This should help
83 r *= 5;
84#else
85 r *= 8;
86#endif
87 }
88 double closest = -1;
89 int xTarget = 0;
90 int yTarget = 0;
91 int zTarget = 0;
92
93 int xc = Mth::floor(e->x);
94 int zc = Mth::floor(e->z);
95
96 long hash = ChunkPos::hashCode(xc, zc);
97 bool updateCache = true;
98
99 AUTO_VAR(it, cachedPortals.find(hash));
100 if (it != cachedPortals.end())
101 {
102 PortalPosition *pos = it->second;
103
104 closest = 0;
105 xTarget = pos->x;
106 yTarget = pos->y;
107 zTarget = pos->z;
108 pos->lastUsed = level->getGameTime();
109 updateCache = false;
110 }
111 else
112 {
113 for (int x = xc - r; x <= xc + r; x++)
114 {
115 double xd = (x + 0.5) - e->x;
116 for (int z = zc - r; z <= zc + r; z++)
117 {
118 double zd = (z + 0.5) - e->z;
119 for (int y = level->getHeight() - 1; y >= 0; y--)
120 {
121 if (level->getTile(x, y, z) == Tile::portalTile_Id)
122 {
123 while (level->getTile(x, y - 1, z) == Tile::portalTile_Id)
124 {
125 y--;
126 }
127
128 double yd = (y + 0.5) - e->y;
129 double dist = xd * xd + yd * yd + zd * zd;
130 if (closest < 0 || dist < closest)
131 {
132 closest = dist;
133 xTarget = x;
134 yTarget = y;
135 zTarget = z;
136 }
137 }
138 }
139 }
140 }
141 }
142
143 if (closest >= 0)
144 {
145 int x = xTarget;
146 int y = yTarget;
147 int z = zTarget;
148
149 if (updateCache)
150 {
151 cachedPortals[hash] = new PortalPosition(x, y, z, level->getGameTime());
152 cachedPortalKeys.push_back(hash);
153 }
154
155 double xt = x + 0.5;
156 double yt = y + 0.5;
157 double zt = z + 0.5;
158 int dir = Direction::UNDEFINED;
159
160 if (level->getTile(x - 1, y, z) == Tile::portalTile_Id) dir = Direction::NORTH;
161 if (level->getTile(x + 1, y, z) == Tile::portalTile_Id) dir = Direction::SOUTH;
162 if (level->getTile(x, y, z - 1) == Tile::portalTile_Id) dir = Direction::EAST;
163 if (level->getTile(x, y, z + 1) == Tile::portalTile_Id) dir = Direction::WEST;
164
165 int originalDir = e->getPortalEntranceDir();
166
167 if (dir > Direction::UNDEFINED)
168 {
169 int leftDir = Direction::DIRECTION_COUNTER_CLOCKWISE[dir];
170 int forwardsx = Direction::STEP_X[dir];
171 int forwardsz = Direction::STEP_Z[dir];
172 int leftx = Direction::STEP_X[leftDir];
173 int leftz = Direction::STEP_Z[leftDir];
174
175 bool leftBlocked = !level->isEmptyTile(x + forwardsx + leftx, y, z + forwardsz + leftz) || !level->isEmptyTile(x + forwardsx + leftx, y + 1, z + forwardsz + leftz);
176 bool rightBlocked = !level->isEmptyTile(x + forwardsx, y, z + forwardsz) || !level->isEmptyTile(x + forwardsx, y + 1, z + forwardsz);
177
178 if (leftBlocked && rightBlocked)
179 {
180 dir = Direction::DIRECTION_OPPOSITE[dir];
181 leftDir = Direction::DIRECTION_OPPOSITE[leftDir];
182 forwardsx = Direction::STEP_X[dir];
183 forwardsz = Direction::STEP_Z[dir];
184 leftx = Direction::STEP_X[leftDir];
185 leftz = Direction::STEP_Z[leftDir];
186
187 x -= leftx;
188 xt -= leftx;
189 z -= leftz;
190 zt -= leftz;
191 leftBlocked = !level->isEmptyTile(x + forwardsx + leftx, y, z + forwardsz + leftz) || !level->isEmptyTile(x + forwardsx + leftx, y + 1, z + forwardsz + leftz);
192 rightBlocked = !level->isEmptyTile(x + forwardsx, y, z + forwardsz) || !level->isEmptyTile(x + forwardsx, y + 1, z + forwardsz);
193 }
194
195 float offsetLeft = 0.5f;
196 float offsetForwards = 0.5f;
197
198 if (!leftBlocked && rightBlocked)
199 {
200 offsetLeft = 1;
201 }
202 else if (leftBlocked && !rightBlocked)
203 {
204 offsetLeft = 0;
205 }
206 else if (leftBlocked && rightBlocked)
207 {
208 offsetForwards = 0;
209 }
210
211 // Center them in the frame and push them out forwards
212 xt += (leftx * offsetLeft) + (offsetForwards * forwardsx);
213 zt += (leftz * offsetLeft) + (offsetForwards * forwardsz);
214
215 float xx = 0;
216 float zz = 0;
217 float xz = 0;
218 float zx = 0;
219
220 if (dir == originalDir)
221 {
222 xx = 1;
223 zz = 1;
224 }
225 else if (dir == Direction::DIRECTION_OPPOSITE[originalDir])
226 {
227 xx = -1;
228 zz = -1;
229 }
230 else if (dir == Direction::DIRECTION_CLOCKWISE[originalDir])
231 {
232 xz = 1;
233 zx = -1;
234 }
235 else
236 {
237 xz = -1;
238 zx = 1;
239 }
240
241 double xd = e->xd;
242 double zd = e->zd;
243 e->xd = xd * xx + zd * zx;
244 e->zd = xd * xz + zd * zz;
245 e->yRot = (yRotOriginal - originalDir * 90) + (dir * 90);
246 }
247 else
248 {
249 e->xd = e->yd = e->zd = 0;
250 }
251
252 e->moveTo(xt, yt, zt, e->yRot, e->xRot);
253 return true;
254 }
255
256 return false;
257}
258
259
260bool PortalForcer::createPortal(shared_ptr<Entity> e)
261{
262 // 4J Stu - Increase the range at which we try and create a portal to stop creating them floating in mid air over lava
263 int r = 16 * 3;
264 double closest = -1;
265
266 int xc = Mth::floor(e->x);
267 int yc = Mth::floor(e->y);
268 int zc = Mth::floor(e->z);
269
270 // 4J Stu - Changes to stop Portals being created at the border of the nether inside the bedrock
271 int XZSIZE = level->dimension->getXZSize() * 16; // XZSize is chunks, convert to blocks
272 int XZOFFSET = (XZSIZE / 2) - 4; // Subtract 4 to stay away from the edges // TODO Make the 4 a constant in HellRandomLevelSource
273
274 // Move the positions that we want to check away from the edge of the world
275 if( (xc - r) < -XZOFFSET )
276 {
277 app.DebugPrintf("Adjusting portal creation x due to being too close to the edge\n");
278 xc -= ( (xc - r) + XZOFFSET);
279 }
280 else if ( (xc + r) >= XZOFFSET )
281 {
282 app.DebugPrintf("Adjusting portal creation x due to being too close to the edge\n");
283 xc -= ( (xc + r) - XZOFFSET);
284 }
285 if( (zc - r) < -XZOFFSET )
286 {
287 app.DebugPrintf("Adjusting portal creation z due to being too close to the edge\n");
288 zc -= ( (zc - r) + XZOFFSET);
289 }
290 else if ( (zc + r) >= XZOFFSET )
291 {
292 app.DebugPrintf("Adjusting portal creation z due to being too close to the edge\n");
293 zc -= ( (zc + r) - XZOFFSET);
294 }
295
296 int xTarget = xc;
297 int yTarget = yc;
298 int zTarget = zc;
299 int dirTarget = 0;
300
301 int dirOffs = random->nextInt(4);
302
303 {
304 for (int x = xc - r; x <= xc + r; x++)
305 {
306 double xd = (x + 0.5) - e->x;
307 for (int z = zc - r; z <= zc + r; z++)
308 {
309 double zd = (z + 0.5) - e->z;
310
311 for (int y = level->getHeight() - 1; y >= 0; y--)
312 {
313 if (level->isEmptyTile(x, y, z))
314 {
315 while (y>0 && level->isEmptyTile(x, y - 1, z))
316 {
317 y--;
318 }
319
320 for (int dir = dirOffs; dir < dirOffs + 4; dir++)
321 {
322 int xa = dir % 2;
323 int za = 1 - xa;
324
325 if (dir % 4 >= 2)
326 {
327 xa = -xa;
328 za = -za;
329 }
330
331
332 for (int b = 0; b < 3; b++)
333 {
334 for (int s = 0; s < 4; s++)
335 {
336 for (int h = -1; h < 4; h++)
337 {
338 int xt = x + (s - 1) * xa + b * za;
339 int yt = y + h;
340 int zt = z + (s - 1) * za - b * xa;
341
342 // 4J Stu - Changes to stop Portals being created at the border of the nether inside the bedrock
343 if( ( xt < -XZOFFSET ) || ( xt >= XZOFFSET ) || ( zt < -XZOFFSET ) || ( zt >= XZOFFSET ) )
344 {
345 app.DebugPrintf("Skipping possible portal location as at least one block is too close to the edge\n");
346 goto next_first;
347 }
348
349 if (h < 0 && !level->getMaterial(xt, yt, zt)->isSolid()) goto next_first;
350 if (h >= 0 && !level->isEmptyTile(xt, yt, zt)) goto next_first;
351 }
352 }
353 }
354
355 double yd = (y + 0.5) - e->y;
356 double dist = xd * xd + yd * yd + zd * zd;
357 if (closest < 0 || dist < closest)
358 {
359 closest = dist;
360 xTarget = x;
361 yTarget = y;
362 zTarget = z;
363 dirTarget = dir % 4;
364 }
365 }
366 }
367next_first: continue;
368 }
369 }
370 }
371 }
372 if (closest < 0)
373 {
374 for (int x = xc - r; x <= xc + r; x++)
375 {
376 double xd = (x + 0.5) - e->x;
377 for (int z = zc - r; z <= zc + r; z++)
378 {
379 double zd = (z + 0.5) - e->z;
380
381 for (int y = level->getHeight() - 1; y >= 0; y--)
382 {
383 if (level->isEmptyTile(x, y, z))
384 {
385 while (y > 0 && level->isEmptyTile(x, y - 1, z))
386 {
387 y--;
388 }
389
390 for (int dir = dirOffs; dir < dirOffs + 2; dir++)
391 {
392 int xa = dir % 2;
393 int za = 1 - xa;
394 for (int s = 0; s < 4; s++)
395 {
396 for (int h = -1; h < 4; h++)
397 {
398 int xt = x + (s - 1) * xa;
399 int yt = y + h;
400 int zt = z + (s - 1) * za;
401
402 // 4J Stu - Changes to stop Portals being created at the border of the nether inside the bedrock
403 if( ( xt < -XZOFFSET ) || ( xt >= XZOFFSET ) || ( zt < -XZOFFSET ) || ( zt >= XZOFFSET ) )
404 {
405 app.DebugPrintf("Skipping possible portal location as at least one block is too close to the edge\n");
406 goto next_second;
407 }
408
409 if (h < 0 && !level->getMaterial(xt, yt, zt)->isSolid()) goto next_second;
410 if (h >= 0 && !level->isEmptyTile(xt, yt, zt)) goto next_second;
411 }
412 }
413
414 double yd = (y + 0.5) - e->y;
415 double dist = xd * xd + yd * yd + zd * zd;
416 if (closest < 0 || dist < closest)
417 {
418 closest = dist;
419 xTarget = x;
420 yTarget = y;
421 zTarget = z;
422 dirTarget = dir % 2;
423 }
424 }
425 }
426next_second: continue;
427 }
428 }
429 }
430 }
431
432
433
434 int dir = dirTarget;
435
436 int x = xTarget;
437 int y = yTarget;
438 int z = zTarget;
439
440 int xa = dir % 2;
441 int za = 1 - xa;
442
443 if (dir % 4 >= 2)
444 {
445 xa = -xa;
446 za = -za;
447 }
448
449
450 if (closest < 0)
451 {
452 if (yTarget < 70) yTarget = 70;
453 if (yTarget > level->getHeight() - 10) yTarget = level->getHeight() - 10;
454 y = yTarget;
455
456 for (int b = -1; b <= 1; b++)
457 {
458 for (int s = 1; s < 3; s++)
459 {
460 for (int h = -1; h < 3; h++)
461 {
462 int xt = x + (s - 1) * xa + b * za;
463 int yt = y + h;
464 int zt = z + (s - 1) * za - b * xa;
465
466 bool border = h < 0;
467
468 level->setTileAndUpdate(xt, yt, zt, border ? Tile::obsidian_Id : 0);
469 }
470 }
471 }
472 }
473
474 for (int pass = 0; pass < 4; pass++)
475 {
476 for (int s = 0; s < 4; s++)
477 {
478 for (int h = -1; h < 4; h++)
479 {
480 int xt = x + (s - 1) * xa;
481 int yt = y + h;
482 int zt = z + (s - 1) * za;
483
484 bool border = s == 0 || s == 3 || h == -1 || h == 3;
485 level->setTileAndData(xt, yt, zt, border ? Tile::obsidian_Id : Tile::portalTile_Id, 0, Tile::UPDATE_CLIENTS);
486 }
487 }
488
489 for (int s = 0; s < 4; s++)
490 {
491 for (int h = -1; h < 4; h++)
492 {
493 int xt = x + (s - 1) * xa;
494 int yt = y + h;
495 int zt = z + (s - 1) * za;
496
497 level->updateNeighborsAt(xt, yt, zt, level->getTile(xt, yt, zt));
498 }
499 }
500 }
501
502 return true;
503}
504
505void PortalForcer::tick(__int64 time)
506{
507 if (time % (SharedConstants::TICKS_PER_SECOND * 5) == 0)
508 {
509 __int64 cutoff = time - SharedConstants::TICKS_PER_SECOND * 30;
510
511 for(AUTO_VAR(it,cachedPortalKeys.begin()); it != cachedPortalKeys.end();)
512 {
513 __int64 key = *it;
514 PortalPosition *pos = cachedPortals[key];
515
516 if (pos == NULL || pos->lastUsed < cutoff)
517 {
518 delete pos;
519 it = cachedPortalKeys.erase(it);
520 cachedPortals.erase(key);
521 }
522 else
523 {
524 ++it;
525 }
526 }
527 }
528}