#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 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 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 { r *= 8; } 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 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; }