feat: add Portal
This commit is contained in:
1 parent
0369d07996
commit
81d5504932
1 file changed
+156
@@ -0,0 +1,156 @@
|
|||||||
|
#include "vf/Portal.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace vf {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const Vec3i endRingOffsets[PortalNetwork::endFrameSlots] = {
|
||||||
|
{-2, 0, -1}, {-2, 0, 0}, {-2, 0, 1},
|
||||||
|
{2, 0, -1}, {2, 0, 0}, {2, 0, 1},
|
||||||
|
{-1, 0, -2}, {0, 0, -2}, {1, 0, -2},
|
||||||
|
{-1, 0, 2}, {0, 0, 2}, {1, 0, 2},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t dimensionIndex(DimensionId id) {
|
||||||
|
return static_cast<std::size_t>(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Vec3i PortalFrame::interiorBlock(int across, int up) const {
|
||||||
|
if (alongX) return {origin.x + across, origin.y + up, origin.z};
|
||||||
|
return {origin.x, origin.y + up, origin.z + across};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalFrame::containsInterior(const Vec3i& pos) const {
|
||||||
|
int up = pos.y - origin.y;
|
||||||
|
if (up < 0 || up >= height) return false;
|
||||||
|
if (alongX) {
|
||||||
|
if (pos.z != origin.z) return false;
|
||||||
|
int across = pos.x - origin.x;
|
||||||
|
return across >= 0 && across < width;
|
||||||
|
}
|
||||||
|
if (pos.x != origin.x) return false;
|
||||||
|
int across = pos.z - origin.z;
|
||||||
|
return across >= 0 && across < width;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalFrame::operator==(const PortalFrame& other) const {
|
||||||
|
return origin == other.origin && width == other.width && height == other.height &&
|
||||||
|
alongX == other.alongX && dimension == other.dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalScan::interiorCell(Block block) {
|
||||||
|
return block == Block::Air || block == Block::NetherPortal;
|
||||||
|
}
|
||||||
|
|
||||||
|
PortalScan PortalScan::detect(const World& world, const Vec3i& probe, DimensionId dimension) {
|
||||||
|
PortalScan scan;
|
||||||
|
|
||||||
|
for (int attempt = 0; attempt < 2; ++attempt) {
|
||||||
|
bool alongX = attempt == 0;
|
||||||
|
int plane = alongX ? probe.z : probe.x;
|
||||||
|
int seed = alongX ? probe.x : probe.z;
|
||||||
|
|
||||||
|
auto sample = [&](int across, int y) {
|
||||||
|
return alongX ? world.blockAt(across, y, plane) : world.blockAt(plane, y, across);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!interiorCell(sample(seed, probe.y))) continue;
|
||||||
|
|
||||||
|
int bottom = probe.y;
|
||||||
|
int steps = 0;
|
||||||
|
while (steps < PortalFrame::maxHeight && interiorCell(sample(seed, bottom - 1))) {
|
||||||
|
--bottom;
|
||||||
|
++steps;
|
||||||
|
}
|
||||||
|
if (sample(seed, bottom - 1) != Block::Obsidian) continue;
|
||||||
|
|
||||||
|
int left = seed;
|
||||||
|
steps = 0;
|
||||||
|
while (steps < PortalFrame::maxWidth && interiorCell(sample(left - 1, bottom))) {
|
||||||
|
--left;
|
||||||
|
++steps;
|
||||||
|
}
|
||||||
|
if (sample(left - 1, bottom) != Block::Obsidian) continue;
|
||||||
|
|
||||||
|
int right = seed;
|
||||||
|
steps = 0;
|
||||||
|
while (steps < PortalFrame::maxWidth && interiorCell(sample(right + 1, bottom))) {
|
||||||
|
++right;
|
||||||
|
++steps;
|
||||||
|
}
|
||||||
|
if (sample(right + 1, bottom) != Block::Obsidian) continue;
|
||||||
|
|
||||||
|
int width = right - left + 1;
|
||||||
|
if (width < PortalFrame::minWidth || width > PortalFrame::maxWidth) continue;
|
||||||
|
|
||||||
|
int top = bottom;
|
||||||
|
steps = 0;
|
||||||
|
while (steps < PortalFrame::maxHeight && interiorCell(sample(left, top + 1))) {
|
||||||
|
++top;
|
||||||
|
++steps;
|
||||||
|
}
|
||||||
|
int height = top - bottom + 1;
|
||||||
|
if (height < PortalFrame::minHeight || height > PortalFrame::maxHeight) continue;
|
||||||
|
|
||||||
|
PortalFrame frame;
|
||||||
|
frame.alongX = alongX;
|
||||||
|
frame.dimension = dimension;
|
||||||
|
frame.width = width;
|
||||||
|
frame.height = height;
|
||||||
|
frame.origin = alongX ? Vec3i{left, bottom, plane} : Vec3i{plane, bottom, left};
|
||||||
|
|
||||||
|
if (!intact(world, frame) || !interiorClear(world, frame)) continue;
|
||||||
|
|
||||||
|
scan.found = true;
|
||||||
|
scan.frame = frame;
|
||||||
|
scan.interiorArea = frame.interiorArea();
|
||||||
|
return scan;
|
||||||
|
}
|
||||||
|
return scan;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalScan::intact(const World& world, const PortalFrame& frame) {
|
||||||
|
for (int across = 0; across < frame.width; ++across) {
|
||||||
|
Vec3i low = frame.bottomRow(across);
|
||||||
|
Vec3i high = frame.topRow(across);
|
||||||
|
if (world.blockAt(low.x, low.y, low.z) != Block::Obsidian) return false;
|
||||||
|
if (world.blockAt(high.x, high.y, high.z) != Block::Obsidian) return false;
|
||||||
|
}
|
||||||
|
for (int up = 0; up < frame.height; ++up) {
|
||||||
|
Vec3i left = frame.leftColumn(up);
|
||||||
|
Vec3i right = frame.rightColumn(up);
|
||||||
|
if (world.blockAt(left.x, left.y, left.z) != Block::Obsidian) return false;
|
||||||
|
if (world.blockAt(right.x, right.y, right.z) != Block::Obsidian) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalScan::interiorClear(const World& world, const PortalFrame& frame) {
|
||||||
|
for (int across = 0; across < frame.width; ++across) {
|
||||||
|
for (int up = 0; up < frame.height; ++up) {
|
||||||
|
Vec3i cell = frame.interiorBlock(across, up);
|
||||||
|
if (!interiorCell(world.blockAt(cell.x, cell.y, cell.z))) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortalScan::light(World& world, const PortalFrame& frame) {
|
||||||
|
if (!intact(world, frame) || !interiorClear(world, frame)) return 0;
|
||||||
|
|
||||||
|
int lit = 0;
|
||||||
|
for (int across = 0; across < frame.width; ++across) {
|
||||||
|
for (int up = 0; up < frame.height; ++up) {
|
||||||
|
Vec3i cell = frame.interiorBlock(across, up);
|
||||||
|
if (world.blockAt(cell.x, cell.y, cell.z) == Block::NetherPortal) continue;
|
||||||
|
world.setBlock(cell.x, cell.y, cell.z, Block::NetherPortal);
|
||||||
|
++lit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lit;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user