aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/PortalForcer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.World/PortalForcer.cpp')
-rw-r--r--Minecraft.World/PortalForcer.cpp381
1 files changed, 381 insertions, 0 deletions
diff --git a/Minecraft.World/PortalForcer.cpp b/Minecraft.World/PortalForcer.cpp
new file mode 100644
index 00000000..7c9b7a86
--- /dev/null
+++ b/Minecraft.World/PortalForcer.cpp
@@ -0,0 +1,381 @@
+#include "stdafx.h"
+#include "net.minecraft.world.entity.h"
+#include "net.minecraft.world.level.h"
+#include "net.minecraft.world.level.tile.h"
+#include "net.minecraft.world.level.dimension.h"
+#include "PortalForcer.h"
+
+PortalForcer::PortalForcer()
+{
+ random = new Random();
+}
+
+
+void PortalForcer::force(Level *level, shared_ptr<Entity> e)
+{
+ if (level->dimension->id == 1)
+ {
+ int x = Mth::floor(e->x);
+ int y = Mth::floor(e->y) - 1;
+ int z = Mth::floor(e->z);
+
+ int xa = 1;
+ int za = 0;
+ for (int b = -2; b <= 2; b++)
+ {
+ for (int s = -2; s <= 2; s++)
+ {
+ for (int h = -1; h < 3; h++)
+ {
+ int xt = x + s * xa + b * za;
+ int yt = y + h;
+ int zt = z + s * za - b * xa;
+
+ bool border = h < 0;
+
+ level->setTile(xt, yt, zt, border ? Tile::obsidian_Id : 0);
+ }
+ }
+ }
+
+ e->moveTo(x, y, z, e->yRot, 0);
+ e->xd = e->yd = e->zd = 0;
+
+ return;
+ }
+
+ if (findPortal(level, e))
+ {
+ return;
+ }
+
+ createPortal(level, e);
+ findPortal(level, e);
+}
+
+
+bool PortalForcer::findPortal(Level *level, shared_ptr<Entity> e)
+{
+ // 4J Stu - Decrease the range at which we search for a portal in the nether given our smaller nether
+ int r = 16;//* 8;
+ if(level->dimension->id == -1)
+ {
+ r *= 3;
+ }
+ else
+ {
+#ifdef __PSVITA__
+ // AP poor little Vita takes 30 seconds to leave the Nether. This should help
+ r *= 5;
+#else
+ r *= 8;
+#endif
+ }
+ double closest = -1;
+ int xTarget = 0;
+ int yTarget = 0;
+ int zTarget = 0;
+
+ int xc = Mth::floor(e->x);
+ int zc = Mth::floor(e->z);
+
+ for (int x = xc - r; x <= xc + r; x++)
+ {
+ double xd = (x + 0.5) - e->x;
+ for (int z = zc - r; z <= zc + r; z++)
+ {
+ double zd = (z + 0.5) - e->z;
+ for (int y = level->getHeight() - 1; y >= 0; y--)
+ {
+ if (level->getTile(x, y, z) == Tile::portalTile_Id)
+ {
+ while (level->getTile(x, y - 1, z) == Tile::portalTile_Id)
+ {
+ y--;
+ }
+
+ double yd = (y + 0.5) - e->y;
+ double dist = xd * xd + yd * yd + zd * zd;
+ if (closest < 0 || dist < closest)
+ {
+ closest = dist;
+ xTarget = x;
+ yTarget = y;
+ zTarget = z;
+ }
+ }
+ }
+ }
+ }
+
+ if (closest >= 0)
+ {
+ int x = xTarget;
+ int y = yTarget;
+ int z = zTarget;
+
+ double xt = x + 0.5;
+ double yt = y + 0.5;
+ double zt = z + 0.5;
+
+ if (level->getTile(x - 1, y, z) == Tile::portalTile_Id) xt -= 0.5;
+ if (level->getTile(x + 1, y, z) == Tile::portalTile_Id) xt += 0.5;
+
+ if (level->getTile(x, y, z - 1) == Tile::portalTile_Id) zt -= 0.5;
+ if (level->getTile(x, y, z + 1) == Tile::portalTile_Id) zt += 0.5;
+
+ e->moveTo(xt, yt, zt, e->yRot, 0);
+ e->xd = e->yd = e->zd = 0;
+ return true;
+ }
+
+ return false;
+}
+
+
+bool PortalForcer::createPortal(Level *level, shared_ptr<Entity> e)
+{
+ // 4J Stu - Increase the range at which we try and create a portal to stop creating them floating in mid air over lava
+ int r = 16 * 3;
+ double closest = -1;
+
+ int xc = Mth::floor(e->x);
+ int yc = Mth::floor(e->y);
+ int zc = Mth::floor(e->z);
+
+ // 4J Stu - Changes to stop Portals being created at the border of the nether inside the bedrock
+ int XZSIZE = level->dimension->getXZSize() * 16; // XZSize is chunks, convert to blocks
+ int XZOFFSET = (XZSIZE / 2) - 4; // Subtract 4 to stay away from the edges // TODO Make the 4 a constant in HellRandomLevelSource
+
+ // Move the positions that we want to check away from the edge of the world
+ if( (xc - r) < -XZOFFSET )
+ {
+ app.DebugPrintf("Adjusting portal creation x due to being too close to the edge\n");
+ xc -= ( (xc - r) + XZOFFSET);
+ }
+ else if ( (xc + r) >= XZOFFSET )
+ {
+ app.DebugPrintf("Adjusting portal creation x due to being too close to the edge\n");
+ xc -= ( (xc + r) - XZOFFSET);
+ }
+ if( (zc - r) < -XZOFFSET )
+ {
+ app.DebugPrintf("Adjusting portal creation z due to being too close to the edge\n");
+ zc -= ( (zc - r) + XZOFFSET);
+ }
+ else if ( (zc + r) >= XZOFFSET )
+ {
+ app.DebugPrintf("Adjusting portal creation z due to being too close to the edge\n");
+ zc -= ( (zc + r) - XZOFFSET);
+ }
+
+ int xTarget = xc;
+ int yTarget = yc;
+ int zTarget = zc;
+ int dirTarget = 0;
+
+ int dirOffs = random->nextInt(4);
+
+ {
+ for (int x = xc - r; x <= xc + r; x++)
+ {
+ double xd = (x + 0.5) - e->x;
+ for (int z = zc - r; z <= zc + r; z++)
+ {
+ double zd = (z + 0.5) - e->z;
+
+ for (int y = level->getHeight() - 1; y >= 0; y--)
+ {
+ if (level->isEmptyTile(x, y, z))
+ {
+ while (y>0 && level->isEmptyTile(x, y - 1, z))
+ {
+ y--;
+ }
+
+ for (int dir = dirOffs; dir < dirOffs + 4; dir++)
+ {
+ int xa = dir % 2;
+ int za = 1 - xa;
+
+ if (dir % 4 >= 2)
+ {
+ xa = -xa;
+ za = -za;
+ }
+
+
+ for (int b = 0; b < 3; b++)
+ {
+ for (int s = 0; s < 4; s++)
+ {
+ for (int h = -1; h < 4; h++)
+ {
+ int xt = x + (s - 1) * xa + b * za;
+ int yt = y + h;
+ int zt = z + (s - 1) * za - b * xa;
+
+ // 4J Stu - Changes to stop Portals being created at the border of the nether inside the bedrock
+ if( ( xt < -XZOFFSET ) || ( xt >= XZOFFSET ) || ( zt < -XZOFFSET ) || ( zt >= XZOFFSET ) )
+ {
+ app.DebugPrintf("Skipping possible portal location as at least one block is too close to the edge\n");
+ goto next_first;
+ }
+
+ if (h < 0 && !level->getMaterial(xt, yt, zt)->isSolid()) goto next_first;
+ if (h >= 0 && !level->isEmptyTile(xt, yt, zt)) goto next_first;
+ }
+ }
+ }
+
+ double yd = (y + 0.5) - e->y;
+ double dist = xd * xd + yd * yd + zd * zd;
+ if (closest < 0 || dist < closest)
+ {
+ closest = dist;
+ xTarget = x;
+ yTarget = y;
+ zTarget = z;
+ dirTarget = dir % 4;
+ }
+ }
+ }
+ next_first: continue;
+ }
+ }
+ }
+ }
+ if (closest < 0)
+ {
+ for (int x = xc - r; x <= xc + r; x++)
+ {
+ double xd = (x + 0.5) - e->x;
+ for (int z = zc - r; z <= zc + r; z++)
+ {
+ double zd = (z + 0.5) - e->z;
+
+ for (int y = level->getHeight() - 1; y >= 0; y--)
+ {
+ if (level->isEmptyTile(x, y, z))
+ {
+ while (y > 0 && level->isEmptyTile(x, y - 1, z))
+ {
+ y--;
+ }
+
+ for (int dir = dirOffs; dir < dirOffs + 2; dir++)
+ {
+ int xa = dir % 2;
+ int za = 1 - xa;
+ for (int s = 0; s < 4; s++)
+ {
+ for (int h = -1; h < 4; h++)
+ {
+ int xt = x + (s - 1) * xa;
+ int yt = y + h;
+ int zt = z + (s - 1) * za;
+
+ // 4J Stu - Changes to stop Portals being created at the border of the nether inside the bedrock
+ if( ( xt < -XZOFFSET ) || ( xt >= XZOFFSET ) || ( zt < -XZOFFSET ) || ( zt >= XZOFFSET ) )
+ {
+ app.DebugPrintf("Skipping possible portal location as at least one block is too close to the edge\n");
+ goto next_second;
+ }
+
+ if (h < 0 && !level->getMaterial(xt, yt, zt)->isSolid()) goto next_second;
+ if (h >= 0 && !level->isEmptyTile(xt, yt, zt)) goto next_second;
+ }
+ }
+
+ double yd = (y + 0.5) - e->y;
+ double dist = xd * xd + yd * yd + zd * zd;
+ if (closest < 0 || dist < closest)
+ {
+ closest = dist;
+ xTarget = x;
+ yTarget = y;
+ zTarget = z;
+ dirTarget = dir % 2;
+ }
+ }
+ }
+ next_second: continue;
+ }
+ }
+ }
+ }
+
+
+
+ int dir = dirTarget;
+
+ int x = xTarget;
+ int y = yTarget;
+ int z = zTarget;
+
+ int xa = dir % 2;
+ int za = 1 - xa;
+
+ if (dir % 4 >= 2)
+ {
+ xa = -xa;
+ za = -za;
+ }
+
+
+ if (closest < 0)
+ {
+ if (yTarget < 70) yTarget = 70;
+ if (yTarget > level->getHeight() - 10) yTarget = level->getHeight() - 10;
+ y = yTarget;
+
+ for (int b = -1; b <= 1; b++)
+ {
+ for (int s = 1; s < 3; s++)
+ {
+ for (int h = -1; h < 3; h++)
+ {
+ int xt = x + (s - 1) * xa + b * za;
+ int yt = y + h;
+ int zt = z + (s - 1) * za - b * xa;
+
+ bool border = h < 0;
+
+ level->setTile(xt, yt, zt, border ? Tile::obsidian_Id : 0);
+ }
+ }
+ }
+ }
+
+ for (int pass = 0; pass < 4; pass++)
+ {
+ level->noNeighborUpdate = true;
+ for (int s = 0; s < 4; s++)
+ {
+ for (int h = -1; h < 4; h++)
+ {
+ int xt = x + (s - 1) * xa;
+ int yt = y + h;
+ int zt = z + (s - 1) * za;
+
+ bool border = s == 0 || s == 3 || h == -1 || h == 3;
+ level->setTile(xt, yt, zt, border ? Tile::obsidian_Id : Tile::portalTile_Id);
+ }
+ }
+ level->noNeighborUpdate = false;
+
+ for (int s = 0; s < 4; s++)
+ {
+ for (int h = -1; h < 4; h++)
+ {
+ int xt = x + (s - 1) * xa;
+ int yt = y + h;
+ int zt = z + (s - 1) * za;
+
+ level->updateNeighborsAt(xt, yt, zt, level->getTile(xt, yt, zt));
+ }
+ }
+ }
+
+ return true;
+}