feat: extend Portal
This commit is contained in:
1 parent
81d5504932
commit
a919a0bfe6
1 file changed
+161
@@ -154,3 +154,164 @@ int PortalScan::light(World& world, const PortalFrame& frame) {
|
||||
return lit;
|
||||
}
|
||||
|
||||
int PortalScan::douse(World& world, const PortalFrame& frame) {
|
||||
int cleared = 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::Air);
|
||||
++cleared;
|
||||
}
|
||||
}
|
||||
return cleared;
|
||||
}
|
||||
|
||||
bool PortalScan::siteUsable(const World& world, const PortalFrame& frame) {
|
||||
for (int across = -1; across <= frame.width; ++across) {
|
||||
for (int up = -1; up <= frame.height; ++up) {
|
||||
Vec3i cell = frame.interiorBlock(across, up);
|
||||
if (world.blockAt(cell.x, cell.y, cell.z) == Block::Bedrock) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PortalScan::buildFrame(World& world, const PortalFrame& frame) {
|
||||
for (int across = -1; across <= frame.width; ++across) {
|
||||
for (int up = -1; up <= frame.height; ++up) {
|
||||
Vec3i cell = frame.interiorBlock(across, up);
|
||||
bool ring = across == -1 || across == frame.width || up == -1 || up == frame.height;
|
||||
world.setBlock(cell.x, cell.y, cell.z, ring ? Block::Obsidian : Block::Air);
|
||||
}
|
||||
}
|
||||
|
||||
int stepX = frame.alongX ? 0 : 1;
|
||||
int stepZ = frame.alongX ? 1 : 0;
|
||||
for (int side = -1; side <= 1; side += 2) {
|
||||
for (int across = 0; across < frame.width; ++across) {
|
||||
Vec3i deck = frame.interiorBlock(across, -1);
|
||||
world.setBlock(deck.x + stepX * side, deck.y, deck.z + stepZ * side, Block::Obsidian);
|
||||
for (int up = 0; up < frame.height; ++up) {
|
||||
Vec3i cell = frame.interiorBlock(across, up);
|
||||
world.setBlock(cell.x + stepX * side, cell.y, cell.z + stepZ * side, Block::Air);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PortalNetwork::PortalNetwork(DimensionSet& set) : transit(set) {
|
||||
eyes.resize(static_cast<std::size_t>(DimensionSet::dimensionCount));
|
||||
}
|
||||
|
||||
int PortalNetwork::registerPortal(DimensionId dimension, const PortalFrame& frame) {
|
||||
PortalLink link;
|
||||
link.id = static_cast<int>(portals.size());
|
||||
link.dimension = dimension;
|
||||
link.frame = frame;
|
||||
link.frame.dimension = dimension;
|
||||
portals.push_back(link);
|
||||
return link.id;
|
||||
}
|
||||
|
||||
int PortalNetwork::ignite(DimensionId dimension, const Vec3i& probe) {
|
||||
World& world = dimensions().dimension(dimension).world();
|
||||
PortalScan scan = PortalScan::detect(world, probe, dimension);
|
||||
if (!scan.found) return -1;
|
||||
|
||||
PortalScan::light(world, scan.frame);
|
||||
for (PortalLink& link : portals) {
|
||||
if (link.dimension != dimension || link.frame != scan.frame) continue;
|
||||
link.active = true;
|
||||
return link.id;
|
||||
}
|
||||
return registerPortal(dimension, scan.frame);
|
||||
}
|
||||
|
||||
const PortalLink* PortalNetwork::portal(int id) const {
|
||||
if (id < 0 || id >= static_cast<int>(portals.size())) return nullptr;
|
||||
return &portals[static_cast<std::size_t>(id)];
|
||||
}
|
||||
|
||||
int PortalNetwork::activeCountIn(DimensionId dimension) const {
|
||||
int total = 0;
|
||||
for (const PortalLink& link : portals)
|
||||
if (link.active && link.dimension == dimension) ++total;
|
||||
return total;
|
||||
}
|
||||
|
||||
void PortalNetwork::unlink(int id) {
|
||||
const PortalLink* link = portal(id);
|
||||
if (!link || link->linkedId < 0) return;
|
||||
|
||||
int partner = link->linkedId;
|
||||
portals[static_cast<std::size_t>(id)].linkedId = -1;
|
||||
if (partner >= 0 && partner < static_cast<int>(portals.size()))
|
||||
portals[static_cast<std::size_t>(partner)].linkedId = -1;
|
||||
}
|
||||
|
||||
void PortalNetwork::linkPortals(int firstId, int secondId) {
|
||||
if (!portal(firstId) || !portal(secondId)) return;
|
||||
unlink(firstId);
|
||||
unlink(secondId);
|
||||
portals[static_cast<std::size_t>(firstId)].linkedId = secondId;
|
||||
portals[static_cast<std::size_t>(secondId)].linkedId = firstId;
|
||||
}
|
||||
|
||||
int PortalNetwork::validate(DimensionId dimension) {
|
||||
World& world = dimensions().dimension(dimension).world();
|
||||
int destroyed = 0;
|
||||
|
||||
for (std::size_t index = 0; index < portals.size(); ++index) {
|
||||
PortalLink& link = portals[index];
|
||||
if (!link.active || link.dimension != dimension) continue;
|
||||
if (PortalScan::intact(world, link.frame)) continue;
|
||||
|
||||
PortalScan::douse(world, link.frame);
|
||||
link.active = false;
|
||||
unlink(link.id);
|
||||
++destroyed;
|
||||
}
|
||||
return destroyed;
|
||||
}
|
||||
|
||||
PortalSearch PortalNetwork::findNearest(DimensionId dimension, const Vec3i& position,
|
||||
int radius) const {
|
||||
PortalSearch search;
|
||||
long long best = -1;
|
||||
|
||||
for (const PortalLink& link : portals) {
|
||||
if (!link.active || link.dimension != dimension) continue;
|
||||
Vec3i entry = link.frame.entry();
|
||||
long long dx = entry.x - position.x;
|
||||
long long dy = entry.y - position.y;
|
||||
long long dz = entry.z - position.z;
|
||||
if (std::llabs(dx) > radius || std::llabs(dz) > radius) continue;
|
||||
|
||||
long long distance = dx * dx + dy * dy + dz * dz;
|
||||
if (best >= 0 && distance >= best) continue;
|
||||
best = distance;
|
||||
search.found = true;
|
||||
search.portalId = link.id;
|
||||
search.position = entry;
|
||||
}
|
||||
if (search.found) search.distanceSquared = static_cast<int>(best);
|
||||
return search;
|
||||
}
|
||||
|
||||
int PortalNetwork::buildPortalNear(DimensionId dimension, const Vec3i& target) {
|
||||
Dimension& destination = dimensions().dimension(dimension);
|
||||
destination.generateArea(floorDiv(target.x, chunkSize), floorDiv(target.z, chunkSize), 1);
|
||||
|
||||
PortalFrame frame;
|
||||
frame.dimension = dimension;
|
||||
frame.alongX = true;
|
||||
frame.width = 2;
|
||||
frame.height = 3;
|
||||
|
||||
const DimensionConfig& cfg = destination.config();
|
||||
int radius = DimensionTravel::buildRadiusFor(dimension);
|
||||
Vec3i spot;
|
||||
bool natural = transit.findSafeSpot(dimension, target, radius, frame.height + 1, spot);
|
||||
if (!natural) spot = {target.x, cfg.clampY(target.y), target.z};
|
||||
|
||||
Reference in new issue
Block a user