Improve multi-level support and stairs
This commit is contained in:
@@ -25,29 +25,64 @@ public final class AvenueStairwayLayout {
|
||||
|
||||
public static List<Step> centeredEastAvenue(
|
||||
Cuboid plot, int roadWidth, int stairWidth, int lowerY, int rise) {
|
||||
int plotLength = plot.maxZ - plot.minZ + 1;
|
||||
if (roadWidth < 1
|
||||
|| stairWidth < 1
|
||||
|| stairWidth >= roadWidth
|
||||
|| rise < 1
|
||||
|| rise + 2 > plotLength) {
|
||||
return stairBlocks(plot, roadWidth, stairWidth, lowerY, rise, Side.EAST);
|
||||
}
|
||||
|
||||
public static List<Flight> forUpperRoadSegments(
|
||||
Cuboid plot,
|
||||
int plotSizeZ,
|
||||
int gridSizeZ,
|
||||
int firstBlockIndex,
|
||||
int everyNBlocks,
|
||||
int avenueWidth,
|
||||
int stairWidth,
|
||||
int lowerY,
|
||||
int rise,
|
||||
int openingLength) {
|
||||
if (plotSizeZ < 1 || gridSizeZ < plotSizeZ || everyNBlocks < 1) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
int firstX = plot.maxX + 1 + (roadWidth - stairWidth) / 2;
|
||||
int firstZ = plot.minZ + (plotLength - rise) / 2 + 1;
|
||||
List<Step> steps = new ArrayList<>(stairWidth * rise);
|
||||
for (int riseIndex = 0; riseIndex < rise; riseIndex++) {
|
||||
for (int widthIndex = 0; widthIndex < stairWidth; widthIndex++) {
|
||||
steps.add(new Step(firstX + widthIndex, lowerY + riseIndex + 1, firstZ + riseIndex));
|
||||
List<Flight> flights = new ArrayList<>();
|
||||
int segmentIndex = 0;
|
||||
for (int segmentStart = plot.minZ;
|
||||
segmentStart <= plot.maxZ;
|
||||
segmentStart += gridSizeZ, segmentIndex++) {
|
||||
int avenueBlockIndex = firstBlockIndex + segmentIndex;
|
||||
if (Math.floorMod(avenueBlockIndex + 1, everyNBlocks) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Cuboid segment =
|
||||
new Cuboid(
|
||||
plot.minX,
|
||||
plot.minY,
|
||||
segmentStart,
|
||||
plot.maxX,
|
||||
plot.maxY,
|
||||
Math.min(segmentStart + plotSizeZ - 1, plot.maxZ));
|
||||
for (Side side : Side.values()) {
|
||||
List<Step> stairs = stairBlocks(segment, avenueWidth, stairWidth, lowerY, rise, side);
|
||||
if (stairs.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
List<Step> backings = invertedBackings(stairs, lowerY);
|
||||
List<Step> openings =
|
||||
upperRoadOpening(stairs, avenueWidth, stairWidth, lowerY, rise, openingLength);
|
||||
flights.add(new Flight(stairs, backings, openings));
|
||||
}
|
||||
}
|
||||
return List.copyOf(steps);
|
||||
return List.copyOf(flights);
|
||||
}
|
||||
|
||||
public static List<Step> upperRoadOpening(
|
||||
Cuboid plot, int roadWidth, int stairWidth, int lowerY, int rise, int openingLength) {
|
||||
List<Step> stairs = centeredEastAvenue(plot, roadWidth, stairWidth, lowerY, rise);
|
||||
return upperRoadOpening(stairs, roadWidth, stairWidth, lowerY, rise, openingLength);
|
||||
}
|
||||
|
||||
private static List<Step> upperRoadOpening(
|
||||
List<Step> stairs, int roadWidth, int stairWidth, int lowerY, int rise, int openingLength) {
|
||||
if (stairs.isEmpty() || openingLength < 1) {
|
||||
return List.of();
|
||||
}
|
||||
@@ -71,17 +106,50 @@ public final class AvenueStairwayLayout {
|
||||
return new Flight(List.of(), List.of(), List.of());
|
||||
}
|
||||
|
||||
return new Flight(
|
||||
stairs,
|
||||
invertedBackings(stairs, lowerY),
|
||||
upperRoadOpening(stairs, roadWidth, stairWidth, lowerY, rise, openingLength));
|
||||
}
|
||||
|
||||
private static List<Step> invertedBackings(List<Step> stairs, int lowerY) {
|
||||
List<Step> invertedBackings = new ArrayList<>();
|
||||
for (Step stair : stairs) {
|
||||
if (stair.y() > lowerY + 1) {
|
||||
invertedBackings.add(new Step(stair.x(), stair.y() - 1, stair.z()));
|
||||
}
|
||||
}
|
||||
return List.copyOf(invertedBackings);
|
||||
}
|
||||
|
||||
return new Flight(
|
||||
stairs,
|
||||
invertedBackings,
|
||||
upperRoadOpening(plot, roadWidth, stairWidth, lowerY, rise, openingLength));
|
||||
private static List<Step> stairBlocks(
|
||||
Cuboid plot, int roadWidth, int stairWidth, int lowerY, int rise, Side side) {
|
||||
int plotLength = plot.maxZ - plot.minZ + 1;
|
||||
if (roadWidth < 1
|
||||
|| stairWidth < 1
|
||||
|| stairWidth >= roadWidth
|
||||
|| rise < 1
|
||||
|| rise + 2 > plotLength) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
int firstX =
|
||||
side == Side.EAST
|
||||
? plot.maxX + 1 + (roadWidth - stairWidth) / 2
|
||||
: plot.minX - roadWidth + (roadWidth - stairWidth) / 2;
|
||||
int firstZ = plot.minZ + (plotLength - rise) / 2 + 1;
|
||||
List<Step> steps = new ArrayList<>(stairWidth * rise);
|
||||
for (int riseIndex = 0; riseIndex < rise; riseIndex++) {
|
||||
for (int widthIndex = 0; widthIndex < stairWidth; widthIndex++) {
|
||||
steps.add(new Step(firstX + widthIndex, lowerY + riseIndex + 1, firstZ + riseIndex));
|
||||
}
|
||||
}
|
||||
return List.copyOf(steps);
|
||||
}
|
||||
|
||||
public enum Side {
|
||||
EAST,
|
||||
WEST
|
||||
}
|
||||
|
||||
public record Step(int x, int y, int z) {}
|
||||
|
||||
@@ -828,7 +828,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
for (int level = 0; level < levelCount; level++) {
|
||||
// Top
|
||||
for (col = min; col <= max; col++) {
|
||||
if (!areBlocksOccupied(row, col, plotMultiplier, level)) {
|
||||
if (isAvailableSupportedPlot(row, col, plotMultiplier, level)) {
|
||||
if (DEBUG) {
|
||||
getLogger().info(String.format("row: %d, col: %d, level: %d", row, col, level));
|
||||
}
|
||||
@@ -841,7 +841,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
// Right side
|
||||
col = max;
|
||||
for (row = min + 1; row < max; row++) {
|
||||
if (!areBlocksOccupied(row, col, plotMultiplier, level)) {
|
||||
if (isAvailableSupportedPlot(row, col, plotMultiplier, level)) {
|
||||
if (DEBUG) {
|
||||
getLogger().info(String.format("row: %d, col: %d, level: %d", row, col, level));
|
||||
}
|
||||
@@ -854,7 +854,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
// Bottom
|
||||
row = max;
|
||||
for (col = max; col >= min; col--) {
|
||||
if (!areBlocksOccupied(row, col, plotMultiplier, level)) {
|
||||
if (isAvailableSupportedPlot(row, col, plotMultiplier, level)) {
|
||||
if (DEBUG) {
|
||||
getLogger().info(String.format("row: %d, col: %d, level: %d", row, col, level));
|
||||
}
|
||||
@@ -867,7 +867,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
// Left
|
||||
col = min;
|
||||
for (row = max; row > min; row--) {
|
||||
if (!areBlocksOccupied(row, col, plotMultiplier, level)) {
|
||||
if (isAvailableSupportedPlot(row, col, plotMultiplier, level)) {
|
||||
if (row != 0 || col != 0) {
|
||||
if (DEBUG) {
|
||||
getLogger().info(String.format("row: %d, col: %d, level: %d", row, col, level));
|
||||
@@ -895,6 +895,24 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
getPlotMin(row, col, plotMultiplier, 0), getPlotMax(row, col, plotMultiplier, 0));
|
||||
}
|
||||
|
||||
private boolean isAvailableSupportedPlot(int row, int col, int plotMultiplier, int level) {
|
||||
return !areBlocksOccupied(row, col, plotMultiplier, level)
|
||||
&& PlotLevelSupport.hasCompleteSupport(
|
||||
row, col, plotMultiplier, level, this::isGeneratedLogicalBlock);
|
||||
}
|
||||
|
||||
private boolean isGeneratedLogicalBlock(int row, int col, int level) {
|
||||
Cuboid gridCell = new Cuboid(getGridMin(row, col, 1, level), getGridMax(row, col, 1, level));
|
||||
if (_occupiedPlots != null) {
|
||||
for (Plot plot : _occupiedPlots) {
|
||||
if (plot instanceof PlayerHome && plot.getCuboid().intersects(gridCell)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _spawnCuboid != null && _spawnCuboid.intersects(gridCell);
|
||||
}
|
||||
|
||||
private void resizeCityRegion() {
|
||||
size = calculateCitySize();
|
||||
ProtectedRegion cityRegion = regionManager.getRegion("City");
|
||||
@@ -1149,16 +1167,9 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
int avenueBlockIndex = getPlotZFromMin(plotCuboid);
|
||||
if (Math.floorMod(avenueBlockIndex + 1, avenueStairsEveryNBlocks) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int lowerY = getLevelStartY(lowerLevel);
|
||||
AvenueStairwayLayout.Flight flight =
|
||||
AvenueStairwayLayout.forUpperRoad(
|
||||
plotCuboid, avenueWidth, avenueStairWidth, lowerY, getLevelPitchY(), 3);
|
||||
if (flight.stairBlocks().isEmpty()) {
|
||||
List<AvenueStairwayLayout.Flight> flights = getAvenueStairFlights(plotCuboid, lowerLevel);
|
||||
if (flights.isEmpty()) {
|
||||
getLogger()
|
||||
.warning(
|
||||
"Avenue stair run does not fit beside plot at "
|
||||
@@ -1170,7 +1181,9 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
AvenueStairwayBuilder.build(world, flight, avenueStairMaterial);
|
||||
for (AvenueStairwayLayout.Flight flight : flights) {
|
||||
AvenueStairwayBuilder.build(world, flight, avenueStairMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<AvenueStairwayLayout.Step> getUpperRoadOpenings(Cuboid plotCuboid, int roadY) {
|
||||
@@ -1198,19 +1211,32 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
int lowerLevel = upperLevel - 1;
|
||||
int avenueBlockIndex = getPlotZFromMin(plotCuboid);
|
||||
if (lowerLevel < 0 || Math.floorMod(avenueBlockIndex + 1, avenueStairsEveryNBlocks) != 0) {
|
||||
if (lowerLevel < 0) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
return AvenueStairwayLayout.forUpperRoad(
|
||||
plotCuboid,
|
||||
avenueWidth,
|
||||
avenueStairWidth,
|
||||
getLevelStartY(lowerLevel),
|
||||
getLevelPitchY(),
|
||||
3)
|
||||
.roadOpenings();
|
||||
return getAvenueStairFlights(plotCuboid, lowerLevel).stream()
|
||||
.flatMap(flight -> flight.roadOpenings().stream())
|
||||
.toList();
|
||||
}
|
||||
|
||||
private List<AvenueStairwayLayout.Flight> getAvenueStairFlights(
|
||||
Cuboid plotCuboid, int lowerLevel) {
|
||||
if (!generateAvenueStairs || lowerLevel < 0 || lowerLevel >= getEffectiveMaxLevels() - 1) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
return AvenueStairwayLayout.forUpperRoadSegments(
|
||||
plotCuboid,
|
||||
plotSizeZ,
|
||||
gridSizeZ,
|
||||
getPlotZFromMin(plotCuboid),
|
||||
avenueStairsEveryNBlocks,
|
||||
avenueWidth,
|
||||
avenueStairWidth,
|
||||
getLevelStartY(lowerLevel),
|
||||
getLevelPitchY(),
|
||||
3);
|
||||
}
|
||||
|
||||
public List<Plot> getCityBlocks() {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
This file is part of Metropolis.
|
||||
|
||||
Metropolis is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Metropolis is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Metropolis. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
|
||||
*/
|
||||
|
||||
package com.majinnaibu.bukkitplugins.metropolis;
|
||||
|
||||
public final class PlotLevelSupport {
|
||||
private PlotLevelSupport() {}
|
||||
|
||||
public static boolean hasCompleteSupport(
|
||||
int row, int col, int multiplier, int targetLevel, GeneratedCellLookup generatedCellLookup) {
|
||||
if (multiplier < 1 || targetLevel < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int supportLevel = 0; supportLevel < targetLevel; supportLevel++) {
|
||||
for (int rowOffset = 0; rowOffset < multiplier; rowOffset++) {
|
||||
for (int colOffset = 0; colOffset < multiplier; colOffset++) {
|
||||
if (!generatedCellLookup.isGenerated(row + rowOffset, col + colOffset, supportLevel)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface GeneratedCellLookup {
|
||||
boolean isGenerated(int row, int col, int level);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user