feat: extend Dimension
This commit is contained in:
1 parent
62ae595999
commit
ee06045c3f
1 file changed
+147
@@ -150,3 +150,150 @@ int Dimension::highestSolidY(int gx, int gz) const {
|
|||||||
return cfg.floorY - 1;
|
return cfg.floorY - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Dimension::standingSpot(int gx, int gz, int fromY, int clearance, int& outFeetY) const {
|
||||||
|
int start = std::max(fromY, cfg.floorY);
|
||||||
|
for (int y = start; y < cfg.highestPlaceableY() - clearance; ++y) {
|
||||||
|
if (!blocks.solidAt(gx, y, gz)) continue;
|
||||||
|
bool roomy = true;
|
||||||
|
for (int up = 1; up <= clearance && roomy; ++up)
|
||||||
|
roomy = blocks.blockAt(gx, y + up, gz) == Block::Air;
|
||||||
|
if (!roomy) continue;
|
||||||
|
outFeetY = y + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DimensionSet::DimensionSet(uint32_t worldSeed) : baseSeed(worldSeed) {
|
||||||
|
worlds.reserve(dimensionCount);
|
||||||
|
for (int index = 0; index < dimensionCount; ++index) {
|
||||||
|
DimensionId id = static_cast<DimensionId>(index);
|
||||||
|
worlds.push_back(std::make_unique<Dimension>(DimensionConfig::forDimension(id), worldSeed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DimensionSet::tickAll(int steps) {
|
||||||
|
for (auto& dimension : worlds) dimension->tick(steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t DimensionSet::totalChunks() const {
|
||||||
|
std::size_t total = 0;
|
||||||
|
for (const auto& dimension : worlds) total += dimension->world().chunkCount();
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3i DimensionTravel::scale(const Vec3i& pos, const DimensionConfig& from,
|
||||||
|
const DimensionConfig& to) {
|
||||||
|
double ratio = static_cast<double>(from.coordinateScale) /
|
||||||
|
static_cast<double>(to.coordinateScale);
|
||||||
|
return {static_cast<int>(std::floor(pos.x * ratio)), pos.y,
|
||||||
|
static_cast<int>(std::floor(pos.z * ratio))};
|
||||||
|
}
|
||||||
|
|
||||||
|
int DimensionTravel::searchRadiusFor(DimensionId to) {
|
||||||
|
return to == DimensionId::Nether ? 128 : 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DimensionTravel::buildRadiusFor(DimensionId to) {
|
||||||
|
return std::min(searchRadiusFor(to), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
TravelResult DimensionTravel::plan(DimensionId from, DimensionId to, const Vec3i& pos) const {
|
||||||
|
return plan(from, to, pos, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
TravelResult DimensionTravel::plan(DimensionId from, DimensionId to, const Vec3i& pos,
|
||||||
|
const std::vector<Vec3i>& knownPortals) const {
|
||||||
|
TravelResult result;
|
||||||
|
result.from = from;
|
||||||
|
result.to = to;
|
||||||
|
result.source = pos;
|
||||||
|
|
||||||
|
const DimensionConfig& origin = worlds.dimension(from).config();
|
||||||
|
const DimensionConfig& destination = worlds.dimension(to).config();
|
||||||
|
|
||||||
|
result.scaledTarget = scale(pos, origin, destination);
|
||||||
|
result.target = result.scaledTarget;
|
||||||
|
if (result.target.y < destination.lowestPlaceableY()) {
|
||||||
|
result.target.y = destination.lowestPlaceableY();
|
||||||
|
result.clampedToFloor = true;
|
||||||
|
} else if (result.target.y > destination.highestPlaceableY()) {
|
||||||
|
result.target.y = destination.highestPlaceableY();
|
||||||
|
result.clampedToCeiling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.searchRadius = searchRadiusFor(to);
|
||||||
|
long long best = -1;
|
||||||
|
for (std::size_t index = 0; index < knownPortals.size(); ++index) {
|
||||||
|
const Vec3i& candidate = knownPortals[index];
|
||||||
|
long long dx = candidate.x - result.target.x;
|
||||||
|
long long dy = candidate.y - result.target.y;
|
||||||
|
long long dz = candidate.z - result.target.z;
|
||||||
|
if (std::llabs(dx) > result.searchRadius || std::llabs(dz) > result.searchRadius) continue;
|
||||||
|
long long distance = dx * dx + dy * dy + dz * dz;
|
||||||
|
if (best >= 0 && distance >= best) continue;
|
||||||
|
best = distance;
|
||||||
|
result.nearestIndex = static_cast<int>(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.nearestIndex >= 0) {
|
||||||
|
result.needsPortal = false;
|
||||||
|
result.nearestDistanceSquared = static_cast<int>(best);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DimensionTravel::findSafeSpot(DimensionId to, const Vec3i& near, int radius, int clearance,
|
||||||
|
Vec3i& outSpot) const {
|
||||||
|
const Dimension& destination = worlds.dimension(to);
|
||||||
|
int floorY = destination.config().floorY;
|
||||||
|
|
||||||
|
for (int ring = 0; ring <= radius; ++ring) {
|
||||||
|
int bestDrop = -1;
|
||||||
|
Vec3i best;
|
||||||
|
for (int dx = -ring; dx <= ring; ++dx) {
|
||||||
|
for (int dz = -ring; dz <= ring; ++dz) {
|
||||||
|
if (std::max(std::abs(dx), std::abs(dz)) != ring) continue;
|
||||||
|
|
||||||
|
int gx = near.x + dx;
|
||||||
|
int gz = near.z + dz;
|
||||||
|
int scan = floorY;
|
||||||
|
int feetY = 0;
|
||||||
|
while (destination.standingSpot(gx, gz, scan, clearance, feetY)) {
|
||||||
|
int drop = std::abs(feetY - near.y);
|
||||||
|
if (drop <= safeSpotVerticalBand && (bestDrop < 0 || drop < bestDrop)) {
|
||||||
|
bestDrop = drop;
|
||||||
|
best = {gx, feetY, gz};
|
||||||
|
}
|
||||||
|
scan = feetY + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bestDrop >= 0) {
|
||||||
|
outSpot = best;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DimensionTravel::carvePlatform(DimensionId to, const Vec3i& spot, int halfWidth,
|
||||||
|
int clearance) {
|
||||||
|
Dimension& destination = worlds.dimension(to);
|
||||||
|
const DimensionConfig& cfg = destination.config();
|
||||||
|
World& world = destination.world();
|
||||||
|
|
||||||
|
int deck = std::max(spot.y - 1, cfg.floorY);
|
||||||
|
for (int dx = -halfWidth; dx <= halfWidth; ++dx) {
|
||||||
|
for (int dz = -halfWidth; dz <= halfWidth; ++dz) {
|
||||||
|
world.setBlock(spot.x + dx, deck, spot.z + dz, Block::Obsidian);
|
||||||
|
for (int up = 1; up <= clearance; ++up) {
|
||||||
|
int y = deck + up;
|
||||||
|
if (y >= cfg.ceilingY - 1) break;
|
||||||
|
world.setBlock(spot.x + dx, y, spot.z + dz, Block::Air);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace vf
|
||||||
Reference in new issue
Block a user