Use independent street and avenue settings
This commit is contained in:
@@ -32,12 +32,14 @@ public final class AvenueStairwayBuilder {
|
||||
private AvenueStairwayBuilder() {}
|
||||
|
||||
public static void build(World world, Flight flight, Material stairMaterial) {
|
||||
BlockFace ascendingFacing = flight.side().runsAlongX() ? BlockFace.EAST : BlockFace.SOUTH;
|
||||
BlockFace descendingFacing = ascendingFacing.getOppositeFace();
|
||||
for (Step step : flight.stairBlocks()) {
|
||||
Block stairBlock = world.getBlockAt(step.x(), step.y(), step.z());
|
||||
stairBlock.setType(stairMaterial, false);
|
||||
BlockData blockData = stairBlock.getBlockData();
|
||||
if (blockData instanceof Stairs stairs) {
|
||||
stairs.setFacing(BlockFace.SOUTH);
|
||||
stairs.setFacing(ascendingFacing);
|
||||
stairs.setHalf(Bisected.Half.BOTTOM);
|
||||
stairs.setShape(Stairs.Shape.STRAIGHT);
|
||||
stairBlock.setBlockData(stairs, false);
|
||||
@@ -49,7 +51,7 @@ public final class AvenueStairwayBuilder {
|
||||
supportBlock.setType(stairMaterial, false);
|
||||
BlockData supportData = supportBlock.getBlockData();
|
||||
if (supportData instanceof Stairs stairs) {
|
||||
stairs.setFacing(BlockFace.NORTH);
|
||||
stairs.setFacing(descendingFacing);
|
||||
stairs.setHalf(Bisected.Half.TOP);
|
||||
stairs.setShape(Stairs.Shape.STRAIGHT);
|
||||
supportBlock.setBlockData(stairs, false);
|
||||
|
||||
@@ -61,15 +61,64 @@ public final class AvenueStairwayLayout {
|
||||
plot.maxX,
|
||||
plot.maxY,
|
||||
Math.min(segmentStart + plotSizeZ - 1, plot.maxZ));
|
||||
for (Side side : Side.values()) {
|
||||
for (Side side : List.of(Side.EAST, Side.WEST)) {
|
||||
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));
|
||||
upperRoadOpening(stairs, avenueWidth, stairWidth, lowerY, rise, openingLength, side);
|
||||
flights.add(new Flight(side, stairs, backings, openings));
|
||||
}
|
||||
}
|
||||
return List.copyOf(flights);
|
||||
}
|
||||
|
||||
public static List<Flight> forUpperStreetSegments(
|
||||
Cuboid plot,
|
||||
int plotSizeX,
|
||||
int gridSizeX,
|
||||
int firstBlockIndex,
|
||||
int everyNBlocks,
|
||||
int streetWidth,
|
||||
int stairWidth,
|
||||
int lowerY,
|
||||
int rise,
|
||||
int openingLength) {
|
||||
if (plotSizeX < 1 || gridSizeX < plotSizeX || everyNBlocks < 1) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<Flight> flights = new ArrayList<>();
|
||||
int segmentIndex = 0;
|
||||
for (int segmentStart = plot.minX;
|
||||
segmentStart <= plot.maxX;
|
||||
segmentStart += gridSizeX, segmentIndex++) {
|
||||
if (Math.floorMod(firstBlockIndex + segmentIndex + 1, everyNBlocks) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Cuboid segment =
|
||||
new Cuboid(
|
||||
segmentStart,
|
||||
plot.minY,
|
||||
plot.minZ,
|
||||
Math.min(segmentStart + plotSizeX - 1, plot.maxX),
|
||||
plot.maxY,
|
||||
plot.maxZ);
|
||||
for (Side side : List.of(Side.NORTH, Side.SOUTH)) {
|
||||
List<Step> stairs = stairBlocks(segment, streetWidth, stairWidth, lowerY, rise, side);
|
||||
if (stairs.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
flights.add(
|
||||
new Flight(
|
||||
side,
|
||||
stairs,
|
||||
invertedBackings(stairs, lowerY),
|
||||
upperRoadOpening(
|
||||
stairs, streetWidth, stairWidth, lowerY, rise, openingLength, side)));
|
||||
}
|
||||
}
|
||||
return List.copyOf(flights);
|
||||
@@ -78,22 +127,31 @@ public final class AvenueStairwayLayout {
|
||||
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);
|
||||
return upperRoadOpening(stairs, roadWidth, stairWidth, lowerY, rise, openingLength, Side.EAST);
|
||||
}
|
||||
|
||||
private static List<Step> upperRoadOpening(
|
||||
List<Step> stairs, int roadWidth, int stairWidth, int lowerY, int rise, int openingLength) {
|
||||
List<Step> stairs,
|
||||
int roadWidth,
|
||||
int stairWidth,
|
||||
int lowerY,
|
||||
int rise,
|
||||
int openingLength,
|
||||
Side side) {
|
||||
if (stairs.isEmpty() || openingLength < 1) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
Step topStair = stairs.get(stairs.size() - 1);
|
||||
int firstX = stairs.getFirst().x();
|
||||
Step firstStair = stairs.getFirst();
|
||||
int upperRoadY = lowerY + rise;
|
||||
List<Step> opening = new ArrayList<>(stairWidth * openingLength);
|
||||
for (int widthIndex = 0; widthIndex < stairWidth; widthIndex++) {
|
||||
for (int lengthIndex = openingLength; lengthIndex > 0; lengthIndex--) {
|
||||
opening.add(new Step(firstX + widthIndex, upperRoadY, topStair.z() - lengthIndex));
|
||||
opening.add(
|
||||
side.runsAlongX()
|
||||
? new Step(topStair.x() - lengthIndex, upperRoadY, firstStair.z() + widthIndex)
|
||||
: new Step(firstStair.x() + widthIndex, upperRoadY, topStair.z() - lengthIndex));
|
||||
}
|
||||
}
|
||||
return List.copyOf(opening);
|
||||
@@ -103,13 +161,14 @@ public final class AvenueStairwayLayout {
|
||||
Cuboid plot, int roadWidth, int stairWidth, int lowerY, int rise, int openingLength) {
|
||||
List<Step> stairs = centeredEastAvenue(plot, roadWidth, stairWidth, lowerY, rise);
|
||||
if (stairs.isEmpty()) {
|
||||
return new Flight(List.of(), List.of(), List.of());
|
||||
return new Flight(Side.EAST, List.of(), List.of(), List.of());
|
||||
}
|
||||
|
||||
return new Flight(
|
||||
Side.EAST,
|
||||
stairs,
|
||||
invertedBackings(stairs, lowerY),
|
||||
upperRoadOpening(stairs, roadWidth, stairWidth, lowerY, rise, openingLength));
|
||||
upperRoadOpening(stairs, roadWidth, stairWidth, lowerY, rise, openingLength, Side.EAST));
|
||||
}
|
||||
|
||||
private static List<Step> invertedBackings(List<Step> stairs, int lowerY) {
|
||||
@@ -124,7 +183,7 @@ public final class AvenueStairwayLayout {
|
||||
|
||||
private static List<Step> stairBlocks(
|
||||
Cuboid plot, int roadWidth, int stairWidth, int lowerY, int rise, Side side) {
|
||||
int plotLength = plot.maxZ - plot.minZ + 1;
|
||||
int plotLength = side.runsAlongX() ? plot.maxX - plot.minX + 1 : plot.maxZ - plot.minZ + 1;
|
||||
if (roadWidth < 1
|
||||
|| stairWidth < 1
|
||||
|| stairWidth >= roadWidth
|
||||
@@ -133,15 +192,21 @@ public final class AvenueStairwayLayout {
|
||||
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;
|
||||
int firstRun = (side.runsAlongX() ? plot.minX : plot.minZ) + (plotLength - rise) / 2 + 1;
|
||||
int firstCross =
|
||||
switch (side) {
|
||||
case EAST -> plot.maxX + 1 + (roadWidth - stairWidth) / 2;
|
||||
case WEST -> plot.minX - roadWidth + (roadWidth - stairWidth) / 2;
|
||||
case NORTH -> plot.minZ - roadWidth + (roadWidth - stairWidth) / 2;
|
||||
case SOUTH -> plot.maxZ + 1 + (roadWidth - stairWidth) / 2;
|
||||
};
|
||||
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));
|
||||
steps.add(
|
||||
side.runsAlongX()
|
||||
? new Step(firstRun + riseIndex, lowerY + riseIndex + 1, firstCross + widthIndex)
|
||||
: new Step(firstCross + widthIndex, lowerY + riseIndex + 1, firstRun + riseIndex));
|
||||
}
|
||||
}
|
||||
return List.copyOf(steps);
|
||||
@@ -149,13 +214,22 @@ public final class AvenueStairwayLayout {
|
||||
|
||||
public enum Side {
|
||||
EAST,
|
||||
WEST
|
||||
WEST,
|
||||
NORTH,
|
||||
SOUTH;
|
||||
|
||||
public boolean runsAlongX() {
|
||||
return this == NORTH || this == SOUTH;
|
||||
}
|
||||
}
|
||||
|
||||
public record Step(int x, int y, int z) {}
|
||||
|
||||
public record Flight(
|
||||
List<Step> stairBlocks, List<Step> invertedBackingBlocks, List<Step> roadOpenings) {
|
||||
Side side,
|
||||
List<Step> stairBlocks,
|
||||
List<Step> invertedBackingBlocks,
|
||||
List<Step> roadOpenings) {
|
||||
public Flight {
|
||||
stairBlocks = List.copyOf(stairBlocks);
|
||||
invertedBackingBlocks = List.copyOf(invertedBackingBlocks);
|
||||
|
||||
@@ -101,14 +101,23 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
private int gridSizeX = 28;
|
||||
private int gridSizeY = 256;
|
||||
private int maxLevels = 1;
|
||||
private int gridSizeZ = 28;
|
||||
private int roadWidth = 4;
|
||||
private int streetWidth = 4;
|
||||
private int avenueWidth = 4;
|
||||
private int gridSizeZ = 28;
|
||||
private int roadLevel = 62;
|
||||
private int spaceAboveRoad = 2;
|
||||
private Material roadMaterial = Material.COBBLESTONE;
|
||||
private boolean generateRoadSupports = true;
|
||||
private Material roadSupportMaterial = Material.STONE;
|
||||
private int avenueLevel = 62;
|
||||
private int streetSpaceAbove = 2;
|
||||
private int avenueSpaceAbove = 2;
|
||||
private Material streetMaterial = Material.COBBLESTONE;
|
||||
private Material avenueMaterial = Material.COBBLESTONE;
|
||||
private boolean generateStreetSupports = true;
|
||||
private boolean generateAvenueSupports = true;
|
||||
private Material streetSupportMaterial = Material.STONE;
|
||||
private Material avenueSupportMaterial = Material.STONE;
|
||||
private boolean generateStreetStairs;
|
||||
private Material streetStairMaterial = Material.COBBLESTONE_STAIRS;
|
||||
private int streetStairWidth;
|
||||
private int streetStairsEveryNBlocks;
|
||||
private boolean generateAvenueStairs;
|
||||
private Material avenueStairMaterial = Material.COBBLESTONE_STAIRS;
|
||||
private int avenueStairWidth;
|
||||
@@ -199,32 +208,44 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
generateFloorSupports = safeGetBooleanFromConfig(config, "plot.floor.supports.generate");
|
||||
floorSupportMaterial = safeGetMaterialFromConfig(config, "plot.floor.supports.material");
|
||||
generateSign = safeGetBooleanFromConfig(config, "plot.sign.generate");
|
||||
roadWidth =
|
||||
safeGetIntFromConfig(config, "road.streets.width", "road.avenues.width", "road.width");
|
||||
streetWidth = safeGetIntFromConfig(config, "road.streets.width");
|
||||
avenueWidth = safeGetIntFromConfig(config, "road.avenues.width");
|
||||
spaceAboveRoad =
|
||||
safeGetIntFromConfig(
|
||||
config,
|
||||
"road.streets.clearSpaceAbove",
|
||||
"road.avenues.clearSpaceAbove",
|
||||
"road.clearSpaceAbove");
|
||||
roadLevel =
|
||||
safeGetIntFromConfig(config, "road.streets.level", "road.avenues.level", "road.level");
|
||||
roadMaterial =
|
||||
safeGetMaterialFromConfig(
|
||||
config, "road.streets.material", "road.avenues.material", "road.material");
|
||||
generateRoadSupports =
|
||||
safeGetBooleanFromConfig(
|
||||
config,
|
||||
"road.streets.supports.generate",
|
||||
"road.avenues.supports.generate",
|
||||
"road.supports.generate");
|
||||
roadSupportMaterial =
|
||||
safeGetMaterialFromConfig(
|
||||
config,
|
||||
"road.streets.supports.material",
|
||||
"road.avenues.supports.material",
|
||||
"road.supports.material");
|
||||
streetSpaceAbove = safeGetIntFromConfig(config, "road.streets.clearSpaceAbove");
|
||||
avenueSpaceAbove = safeGetIntFromConfig(config, "road.avenues.clearSpaceAbove");
|
||||
roadLevel = safeGetIntFromConfig(config, "road.streets.level");
|
||||
avenueLevel = safeGetIntFromConfig(config, "road.avenues.level");
|
||||
streetMaterial = safeGetMaterialFromConfig(config, "road.streets.material");
|
||||
avenueMaterial = safeGetMaterialFromConfig(config, "road.avenues.material");
|
||||
generateStreetSupports = safeGetBooleanFromConfig(config, "road.streets.supports.generate");
|
||||
generateAvenueSupports = safeGetBooleanFromConfig(config, "road.avenues.supports.generate");
|
||||
streetSupportMaterial = safeGetMaterialFromConfig(config, "road.streets.supports.material");
|
||||
avenueSupportMaterial = safeGetMaterialFromConfig(config, "road.avenues.supports.material");
|
||||
generateStreetStairs = safeGetBooleanFromConfig(config, "road.streets.stairs.generate");
|
||||
if (generateStreetStairs) {
|
||||
streetStairMaterial = safeGetMaterialFromConfig(config, "road.streets.stairs.material");
|
||||
streetStairWidth = safeGetIntFromConfig(config, "road.streets.stairs.width");
|
||||
streetStairsEveryNBlocks = safeGetIntFromConfig(config, "road.streets.stairs.everyNBlocks");
|
||||
|
||||
if (streetStairWidth < 1 || streetStairWidth >= streetWidth) {
|
||||
getLogger()
|
||||
.severe(
|
||||
"road.streets.stairs.width must be positive and narrower than road.streets.width;"
|
||||
+ " street stairs are disabled.");
|
||||
generateStreetStairs = false;
|
||||
}
|
||||
if (streetStairsEveryNBlocks < 1) {
|
||||
getLogger()
|
||||
.severe(
|
||||
"road.streets.stairs.everyNBlocks must be positive; street stairs are disabled.");
|
||||
generateStreetStairs = false;
|
||||
}
|
||||
if (!(streetStairMaterial.createBlockData() instanceof Stairs)) {
|
||||
getLogger()
|
||||
.severe(
|
||||
"road.streets.stairs.material must be a stair block; street stairs are disabled.");
|
||||
generateStreetStairs = false;
|
||||
}
|
||||
}
|
||||
generateAvenueStairs = safeGetBooleanFromConfig(config, "road.avenues.stairs.generate");
|
||||
if (generateAvenueStairs) {
|
||||
avenueStairMaterial = safeGetMaterialFromConfig(config, "road.avenues.stairs.material");
|
||||
@@ -305,9 +326,12 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
throw new RuntimeException(String.format("The world %s does not exist", worldName));
|
||||
}
|
||||
|
||||
gridSizeX = plotSizeX + roadWidth;
|
||||
gridSizeY = Math.max(plotSizeY + roadWidth, 1);
|
||||
gridSizeZ = plotSizeZ + roadWidth;
|
||||
if (streetWidth < 0 || avenueWidth < 0) {
|
||||
throw new IllegalArgumentException("Road widths must not be negative.");
|
||||
}
|
||||
gridSizeX = plotSizeX + avenueWidth;
|
||||
gridSizeY = Math.max(plotSizeY + Math.max(streetWidth, avenueWidth), 1);
|
||||
gridSizeZ = plotSizeZ + streetWidth;
|
||||
|
||||
regionManager =
|
||||
WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(world));
|
||||
@@ -372,7 +396,8 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
*/
|
||||
|
||||
getLogger().info(String.format("roadWidth = %d", roadWidth));
|
||||
getLogger()
|
||||
.info(String.format("streetWidth = %d, avenueWidth = %d", streetWidth, avenueWidth));
|
||||
}
|
||||
|
||||
_occupiedPlots = new ArrayList<Plot>();
|
||||
@@ -595,7 +620,8 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
plotSizeX,
|
||||
plotSizeY,
|
||||
plotSizeZ,
|
||||
roadWidth,
|
||||
avenueWidth,
|
||||
streetWidth,
|
||||
roadLevel);
|
||||
if (!SpawnLayout.withinBuildHeight(spawnCuboid, world.getMinHeight(), world.getMaxHeight())) {
|
||||
getLogger()
|
||||
@@ -702,7 +728,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
|
||||
public static int clampMaxLevels(int requestedLevels, int availableLevels) {
|
||||
int normalizedRequested = normalizeMaxLevels(requestedLevels);
|
||||
int normalizedAvailable = Math.max(1, availableLevels);
|
||||
int normalizedAvailable = Math.max(0, availableLevels);
|
||||
return Math.min(normalizedRequested, normalizedAvailable);
|
||||
}
|
||||
|
||||
@@ -770,28 +796,46 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
if (roadWidth > 0) {
|
||||
int y = plotCuboid.minY;
|
||||
Set<AvenueStairwayLayout.Step> stairOpenings = getUpperRoadOpenings(plotCuboid, y);
|
||||
|
||||
for (RoadLayout.BlockPosition roadBlock : RoadLayout.surroundingRoad(plotCuboid, roadWidth)) {
|
||||
setRoad(roadBlock.x(), y, roadBlock.z(), stairOpenings);
|
||||
if (streetWidth > 0 || avenueWidth > 0) {
|
||||
for (RoadLayout.BlockPosition roadBlock :
|
||||
RoadLayout.surroundingRoad(plotCuboid, streetWidth, avenueWidth)) {
|
||||
int roadY =
|
||||
roadBlock.roadType() == RoadLayout.RoadType.AVENUE
|
||||
? plotCuboid.minY + avenueLevel - roadLevel
|
||||
: plotCuboid.minY;
|
||||
Set<AvenueStairwayLayout.Step> stairOpenings =
|
||||
getUpperRoadOpenings(plotCuboid, roadY, roadBlock.roadType());
|
||||
setRoad(roadBlock.x(), roadY, roadBlock.z(), roadBlock.roadType(), stairOpenings);
|
||||
}
|
||||
|
||||
int upperLevel = Math.floorDiv(y - roadLevel, getLevelPitchY());
|
||||
if (upperLevel > 0 && getLevelStartY(upperLevel) == y) {
|
||||
generateAvenueStairs(plotCuboid, upperLevel - 1);
|
||||
int upperLevel = Math.floorDiv(plotCuboid.minY - roadLevel, getLevelPitchY());
|
||||
if (upperLevel > 0 && getLevelStartY(upperLevel) == plotCuboid.minY) {
|
||||
generateRoadStairs(plotCuboid, upperLevel - 1, RoadLayout.RoadType.AVENUE);
|
||||
generateRoadStairs(plotCuboid, upperLevel - 1, RoadLayout.RoadType.STREET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setRoad(int x, int y, int z, Set<AvenueStairwayLayout.Step> stairOpenings) {
|
||||
private void setRoad(
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
RoadLayout.RoadType roadType,
|
||||
Set<AvenueStairwayLayout.Step> stairOpenings) {
|
||||
if (stairOpenings.contains(new AvenueStairwayLayout.Step(x, y, z))) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean useAvenueSettings = roadType == RoadLayout.RoadType.AVENUE;
|
||||
RoadBlockWriter.build(
|
||||
world, x, y, z, roadMaterial, roadSupportMaterial, generateRoadSupports, spaceAboveRoad);
|
||||
world,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
useAvenueSettings ? avenueMaterial : streetMaterial,
|
||||
useAvenueSettings ? avenueSupportMaterial : streetSupportMaterial,
|
||||
useAvenueSettings ? generateAvenueSupports : generateStreetSupports,
|
||||
useAvenueSettings ? avenueSpaceAbove : streetSpaceAbove);
|
||||
}
|
||||
|
||||
private boolean isSolidMaterial(Material material) {
|
||||
@@ -853,6 +897,10 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
int max = ring - (plotMultiplier - 1);
|
||||
boolean done = false;
|
||||
int levelCount = getEffectiveMaxLevels();
|
||||
if (levelCount == 0) {
|
||||
getLogger().severe("No configured plot level fits within the world's build height.");
|
||||
return null;
|
||||
}
|
||||
|
||||
while (!done) {
|
||||
row = min;
|
||||
@@ -921,11 +969,9 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
getLogger().info(String.format("row: %d, col: %d", row, col));
|
||||
}
|
||||
return new Cuboid(
|
||||
getPlotMin(row, col, plotMultiplier, 0), getPlotMax(row, col, plotMultiplier, 0));
|
||||
getLogger()
|
||||
.severe("Unable to find an available supported plot within the allocation search area.");
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isAvailableSupportedPlot(int row, int col, int plotMultiplier, int level) {
|
||||
@@ -995,7 +1041,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
|
||||
BlockVector3 bv =
|
||||
BlockVector3.at(
|
||||
gridMin.x() + roadWidth / 2, getLevelStartY(level), gridMin.z() + roadWidth / 2);
|
||||
gridMin.x() + avenueWidth / 2, getLevelStartY(level), gridMin.z() + streetWidth / 2);
|
||||
getLogger().info(String.format("getPlotMin (%d, %d, %d)", bv.x(), bv.y(), bv.z()));
|
||||
return bv;
|
||||
}
|
||||
@@ -1009,9 +1055,9 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
|
||||
BlockVector3 bv =
|
||||
BlockVector3.at(
|
||||
gridMax.x() - (roadWidth - roadWidth / 2),
|
||||
gridMax.x() - (avenueWidth - avenueWidth / 2),
|
||||
getLevelStartY(level) + plotSizeY - 1,
|
||||
gridMax.z() - (roadWidth - roadWidth / 2));
|
||||
gridMax.z() - (streetWidth - streetWidth / 2));
|
||||
getLogger().info(String.format("getPlotMax (%d, %d, %d)", bv.x(), bv.y(), bv.z()));
|
||||
return bv;
|
||||
}
|
||||
@@ -1041,22 +1087,37 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
private int getPlotXFromMin(Cuboid cuboid) {
|
||||
return (cuboid.minX - roadWidth / 2) / gridSizeX;
|
||||
return (cuboid.minX - avenueWidth / 2) / gridSizeX;
|
||||
}
|
||||
|
||||
private int getPlotZFromMin(Cuboid cuboid) {
|
||||
return (cuboid.minZ - roadWidth / 2) / gridSizeZ;
|
||||
return (cuboid.minZ - streetWidth / 2) / gridSizeZ;
|
||||
}
|
||||
|
||||
private int getLevelPitchY() {
|
||||
return plotSizeY + roadWidth;
|
||||
return plotSizeY + Math.max(streetWidth, avenueWidth);
|
||||
}
|
||||
|
||||
private int getEffectiveMaxLevels() {
|
||||
int maxWorldLevels = Math.max(1, (world.getMaxHeight() - roadLevel) / getLevelPitchY());
|
||||
int availableStreetLevels = getAvailableLevelsAt(roadLevel);
|
||||
int availableAvenueLevels =
|
||||
avenueWidth > 0 ? getAvailableLevelsAt(avenueLevel) : availableStreetLevels;
|
||||
int maxWorldLevels = Math.min(availableStreetLevels, availableAvenueLevels);
|
||||
return clampMaxLevels(maxLevels, maxWorldLevels);
|
||||
}
|
||||
|
||||
private int getAvailableLevelsAt(int baseY) {
|
||||
if (world == null || baseY < world.getMinHeight() || plotSizeY < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int highestPlotBase = world.getMaxHeight() - plotSizeY;
|
||||
if (baseY > highestPlotBase) {
|
||||
return 0;
|
||||
}
|
||||
return (highestPlotBase - baseY) / getLevelPitchY() + 1;
|
||||
}
|
||||
|
||||
private int getLevelStartY(int level) {
|
||||
return roadLevel + level * getLevelPitchY();
|
||||
}
|
||||
@@ -1104,6 +1165,9 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
homeCuboid = findNextUnownedHomeRegion(multiplier);
|
||||
if (homeCuboid == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
getLogger().info("Metropolis Generating home in " + homeCuboid.toString());
|
||||
|
||||
@@ -1195,37 +1259,28 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
sign.update(true);
|
||||
}
|
||||
|
||||
private void generateAvenueStairs(Cuboid plotCuboid, int lowerLevel) {
|
||||
if (!generateAvenueStairs || lowerLevel < 0 || lowerLevel >= getEffectiveMaxLevels() - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int lowerY = getLevelStartY(lowerLevel);
|
||||
List<AvenueStairwayLayout.Flight> flights = getAvenueStairFlights(plotCuboid, lowerLevel);
|
||||
private void generateRoadStairs(Cuboid plotCuboid, int lowerLevel, RoadLayout.RoadType roadType) {
|
||||
List<AvenueStairwayLayout.Flight> flights =
|
||||
getRoadStairFlights(plotCuboid, lowerLevel, roadType);
|
||||
if (flights.isEmpty()) {
|
||||
getLogger()
|
||||
.warning(
|
||||
"Avenue stair run does not fit beside plot at "
|
||||
+ plotCuboid.minX
|
||||
+ ","
|
||||
+ plotCuboid.minY
|
||||
+ ","
|
||||
+ plotCuboid.minZ);
|
||||
return;
|
||||
}
|
||||
|
||||
Material stairMaterial =
|
||||
roadType == RoadLayout.RoadType.AVENUE ? avenueStairMaterial : streetStairMaterial;
|
||||
for (AvenueStairwayLayout.Flight flight : flights) {
|
||||
AvenueStairwayBuilder.build(world, flight, avenueStairMaterial);
|
||||
AvenueStairwayBuilder.build(world, flight, stairMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<AvenueStairwayLayout.Step> getUpperRoadOpenings(Cuboid plotCuboid, int roadY) {
|
||||
private Set<AvenueStairwayLayout.Step> getUpperRoadOpenings(
|
||||
Cuboid plotCuboid, int roadY, RoadLayout.RoadType roadType) {
|
||||
Set<AvenueStairwayLayout.Step> openings = new HashSet<>();
|
||||
openings.addAll(getUpperRoadOpeningsForPlot(plotCuboid, roadY));
|
||||
openings.addAll(getUpperRoadOpeningsForPlot(plotCuboid, roadY, roadType));
|
||||
if (_occupiedPlots != null) {
|
||||
for (Plot plot : _occupiedPlots) {
|
||||
if (plot instanceof PlayerHome home && home.getCuboid().minY == roadY) {
|
||||
openings.addAll(getUpperRoadOpeningsForPlot(home.getCuboid(), roadY));
|
||||
if (plot instanceof PlayerHome home) {
|
||||
openings.addAll(getUpperRoadOpeningsForPlot(home.getCuboid(), roadY, roadType));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1233,41 +1288,57 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
private List<AvenueStairwayLayout.Step> getUpperRoadOpeningsForPlot(
|
||||
Cuboid plotCuboid, int roadY) {
|
||||
if (!generateAvenueStairs || roadY <= roadLevel) {
|
||||
Cuboid plotCuboid, int roadY, RoadLayout.RoadType roadType) {
|
||||
int baseY = roadType == RoadLayout.RoadType.AVENUE ? avenueLevel : roadLevel;
|
||||
if (!areStairsEnabled(roadType) || roadY <= baseY) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
int upperLevel = Math.floorDiv(roadY - roadLevel, getLevelPitchY());
|
||||
if (getLevelStartY(upperLevel) != roadY) {
|
||||
int upperLevel = Math.floorDiv(roadY - baseY, getLevelPitchY());
|
||||
if (baseY + upperLevel * getLevelPitchY() != roadY || upperLevel < 1) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
int lowerLevel = upperLevel - 1;
|
||||
if (lowerLevel < 0) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
return getAvenueStairFlights(plotCuboid, lowerLevel).stream()
|
||||
return getRoadStairFlights(plotCuboid, upperLevel - 1, roadType).stream()
|
||||
.flatMap(flight -> flight.roadOpenings().stream())
|
||||
.toList();
|
||||
}
|
||||
|
||||
private List<AvenueStairwayLayout.Flight> getAvenueStairFlights(
|
||||
Cuboid plotCuboid, int lowerLevel) {
|
||||
if (!generateAvenueStairs || lowerLevel < 0 || lowerLevel >= getEffectiveMaxLevels() - 1) {
|
||||
private boolean areStairsEnabled(RoadLayout.RoadType roadType) {
|
||||
return roadType == RoadLayout.RoadType.AVENUE ? generateAvenueStairs : generateStreetStairs;
|
||||
}
|
||||
|
||||
private List<AvenueStairwayLayout.Flight> getRoadStairFlights(
|
||||
Cuboid plotCuboid, int lowerLevel, RoadLayout.RoadType roadType) {
|
||||
if (!areStairsEnabled(roadType)
|
||||
|| lowerLevel < 0
|
||||
|| lowerLevel >= getEffectiveMaxLevels() - 1) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
return AvenueStairwayLayout.forUpperRoadSegments(
|
||||
if (roadType == RoadLayout.RoadType.AVENUE) {
|
||||
return AvenueStairwayLayout.forUpperRoadSegments(
|
||||
plotCuboid,
|
||||
plotSizeZ,
|
||||
gridSizeZ,
|
||||
getPlotZFromMin(plotCuboid),
|
||||
avenueStairsEveryNBlocks,
|
||||
avenueWidth,
|
||||
avenueStairWidth,
|
||||
avenueLevel + lowerLevel * getLevelPitchY(),
|
||||
getLevelPitchY(),
|
||||
3);
|
||||
}
|
||||
|
||||
return AvenueStairwayLayout.forUpperStreetSegments(
|
||||
plotCuboid,
|
||||
plotSizeZ,
|
||||
gridSizeZ,
|
||||
getPlotZFromMin(plotCuboid),
|
||||
avenueStairsEveryNBlocks,
|
||||
avenueWidth,
|
||||
avenueStairWidth,
|
||||
getLevelStartY(lowerLevel),
|
||||
plotSizeX,
|
||||
gridSizeX,
|
||||
getPlotXFromMin(plotCuboid),
|
||||
streetStairsEveryNBlocks,
|
||||
streetWidth,
|
||||
streetStairWidth,
|
||||
roadLevel + lowerLevel * getLevelPitchY(),
|
||||
getLevelPitchY(),
|
||||
3);
|
||||
}
|
||||
|
||||
@@ -23,35 +23,67 @@ import java.util.List;
|
||||
public final class RoadLayout {
|
||||
private RoadLayout() {}
|
||||
|
||||
public static List<BlockPosition> surroundingRoad(Cuboid plot, int roadWidth) {
|
||||
if (roadWidth < 1) {
|
||||
public static List<BlockPosition> surroundingRoad(Cuboid plot, int streetWidth, int avenueWidth) {
|
||||
if (streetWidth < 0 || avenueWidth < 0 || streetWidth + avenueWidth == 0) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<BlockPosition> blocks = new ArrayList<>();
|
||||
addRectangle(blocks, plot.minX, plot.maxX, plot.minZ - roadWidth, plot.minZ - 1);
|
||||
addRectangle(blocks, plot.minX, plot.maxX, plot.maxZ + 1, plot.maxZ + roadWidth);
|
||||
addRectangle(blocks, plot.minX - roadWidth, plot.minX - 1, plot.minZ, plot.maxZ);
|
||||
addRectangle(blocks, plot.maxX + 1, plot.maxX + roadWidth, plot.minZ, plot.maxZ);
|
||||
addRectangle(
|
||||
blocks, plot.minX - roadWidth, plot.minX - 1, plot.minZ - roadWidth, plot.minZ - 1);
|
||||
blocks, plot.minX, plot.maxX, plot.minZ - streetWidth, plot.minZ - 1, RoadType.STREET);
|
||||
addRectangle(
|
||||
blocks, plot.maxX + 1, plot.maxX + roadWidth, plot.minZ - roadWidth, plot.minZ - 1);
|
||||
blocks, plot.minX, plot.maxX, plot.maxZ + 1, plot.maxZ + streetWidth, RoadType.STREET);
|
||||
addRectangle(
|
||||
blocks, plot.minX - roadWidth, plot.minX - 1, plot.maxZ + 1, plot.maxZ + roadWidth);
|
||||
blocks, plot.minX - avenueWidth, plot.minX - 1, plot.minZ, plot.maxZ, RoadType.AVENUE);
|
||||
addRectangle(
|
||||
blocks, plot.maxX + 1, plot.maxX + roadWidth, plot.maxZ + 1, plot.maxZ + roadWidth);
|
||||
blocks, plot.maxX + 1, plot.maxX + avenueWidth, plot.minZ, plot.maxZ, RoadType.AVENUE);
|
||||
if (streetWidth > 0 && avenueWidth > 0) {
|
||||
addRectangle(
|
||||
blocks,
|
||||
plot.minX - avenueWidth,
|
||||
plot.minX - 1,
|
||||
plot.minZ - streetWidth,
|
||||
plot.minZ - 1,
|
||||
RoadType.INTERSECTION);
|
||||
addRectangle(
|
||||
blocks,
|
||||
plot.maxX + 1,
|
||||
plot.maxX + avenueWidth,
|
||||
plot.minZ - streetWidth,
|
||||
plot.minZ - 1,
|
||||
RoadType.INTERSECTION);
|
||||
addRectangle(
|
||||
blocks,
|
||||
plot.minX - avenueWidth,
|
||||
plot.minX - 1,
|
||||
plot.maxZ + 1,
|
||||
plot.maxZ + streetWidth,
|
||||
RoadType.INTERSECTION);
|
||||
addRectangle(
|
||||
blocks,
|
||||
plot.maxX + 1,
|
||||
plot.maxX + avenueWidth,
|
||||
plot.maxZ + 1,
|
||||
plot.maxZ + streetWidth,
|
||||
RoadType.INTERSECTION);
|
||||
}
|
||||
return List.copyOf(blocks);
|
||||
}
|
||||
|
||||
private static void addRectangle(
|
||||
List<BlockPosition> blocks, int minX, int maxX, int minZ, int maxZ) {
|
||||
List<BlockPosition> blocks, int minX, int maxX, int minZ, int maxZ, RoadType roadType) {
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
blocks.add(new BlockPosition(x, z));
|
||||
blocks.add(new BlockPosition(x, z, roadType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record BlockPosition(int x, int z) {}
|
||||
public enum RoadType {
|
||||
STREET,
|
||||
AVENUE,
|
||||
INTERSECTION
|
||||
}
|
||||
|
||||
public record BlockPosition(int x, int z, RoadType roadType) {}
|
||||
}
|
||||
|
||||
@@ -27,22 +27,25 @@ public final class SpawnLayout {
|
||||
int plotSizeX,
|
||||
int plotSizeY,
|
||||
int plotSizeZ,
|
||||
int roadWidth,
|
||||
int avenueWidth,
|
||||
int streetWidth,
|
||||
int roadLevel) {
|
||||
if (sizeX < 1 || sizeY < 1 || sizeZ < 1 || roadWidth < 0) {
|
||||
if (sizeX < 1 || sizeY < 1 || sizeZ < 1 || avenueWidth < 0 || streetWidth < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Spawn multipliers must be positive and road width nonnegative");
|
||||
"Spawn multipliers must be positive and road widths nonnegative");
|
||||
}
|
||||
|
||||
int gridSizeX = Math.addExact(plotSizeX, roadWidth);
|
||||
int gridSizeZ = Math.addExact(plotSizeZ, roadWidth);
|
||||
int inset = roadWidth / 2;
|
||||
int maxInset = roadWidth - inset;
|
||||
int maxX = Math.subtractExact(Math.multiplyExact(sizeX, gridSizeX) - 1, maxInset);
|
||||
int gridSizeX = Math.addExact(plotSizeX, avenueWidth);
|
||||
int gridSizeZ = Math.addExact(plotSizeZ, streetWidth);
|
||||
int minX = avenueWidth / 2;
|
||||
int minZ = streetWidth / 2;
|
||||
int maxInsetX = avenueWidth - minX;
|
||||
int maxInsetZ = streetWidth - minZ;
|
||||
int maxX = Math.subtractExact(Math.multiplyExact(sizeX, gridSizeX) - 1, maxInsetX);
|
||||
int maxY = Math.addExact(roadLevel, Math.multiplyExact(sizeY, plotSizeY) - 1);
|
||||
int maxZ = Math.subtractExact(Math.multiplyExact(sizeZ, gridSizeZ) - 1, maxInset);
|
||||
int maxZ = Math.subtractExact(Math.multiplyExact(sizeZ, gridSizeZ) - 1, maxInsetZ);
|
||||
|
||||
return new Cuboid(inset, roadLevel, inset, maxX, maxY, maxZ);
|
||||
return new Cuboid(minX, roadLevel, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
|
||||
public static boolean withinBuildHeight(Cuboid cuboid, int minHeight, int maxHeight) {
|
||||
|
||||
@@ -28,6 +28,9 @@ road:
|
||||
material: STONE
|
||||
stairs:
|
||||
generate: false
|
||||
material: COBBLESTONE_STAIRS
|
||||
everyNBlocks: 4
|
||||
width: 2
|
||||
streets:
|
||||
width: 4
|
||||
clearSpaceAbove: 66
|
||||
@@ -36,6 +39,11 @@ road:
|
||||
supports:
|
||||
generate: true
|
||||
material: STONE
|
||||
stairs:
|
||||
generate: false
|
||||
material: COBBLESTONE_STAIRS
|
||||
everyNBlocks: 4
|
||||
width: 2
|
||||
spawn:
|
||||
generate: true
|
||||
setAsWorldSpawn: true
|
||||
|
||||
@@ -42,6 +42,9 @@ road:
|
||||
material: STONE
|
||||
stairs:
|
||||
generate: false
|
||||
material: COBBLESTONE_STAIRS
|
||||
everyNBlocks: 4
|
||||
width: 2
|
||||
spawn:
|
||||
generate: true
|
||||
setAsWorldSpawn: true
|
||||
|
||||
@@ -40,6 +40,39 @@ import org.bukkit.block.data.type.Stairs;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AvenueStairwayBuilderTest {
|
||||
@Test
|
||||
void buildsStreetStairsFacingEastWithWestFacingInvertedBacking() {
|
||||
Cuboid plot = new Cuboid(2, 62, 2, 33, 71, 33);
|
||||
Flight flight =
|
||||
AvenueStairwayLayout.forUpperStreetSegments(plot, 32, 36, 0, 1, 4, 2, 62, 14, 3).getFirst();
|
||||
World world = mock(World.class);
|
||||
Map<Step, Block> blocks = new HashMap<>();
|
||||
Map<Step, Stairs> blockData = new HashMap<>();
|
||||
when(world.getBlockAt(anyInt(), anyInt(), anyInt()))
|
||||
.thenAnswer(
|
||||
invocation -> {
|
||||
Step position =
|
||||
new Step(
|
||||
invocation.getArgument(0),
|
||||
invocation.getArgument(1),
|
||||
invocation.getArgument(2));
|
||||
return blocks.computeIfAbsent(
|
||||
position,
|
||||
ignored -> {
|
||||
Block block = mock(Block.class);
|
||||
Stairs stairs = mock(Stairs.class);
|
||||
when(block.getBlockData()).thenReturn(stairs);
|
||||
blockData.put(position, stairs);
|
||||
return block;
|
||||
});
|
||||
});
|
||||
|
||||
AvenueStairwayBuilder.build(world, flight, Material.COBBLESTONE_STAIRS);
|
||||
|
||||
verify(blockData.get(flight.stairBlocks().getFirst())).setFacing(BlockFace.EAST);
|
||||
verify(blockData.get(flight.invertedBackingBlocks().getFirst())).setFacing(BlockFace.WEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildsAscendingAndInvertedStairsAndClearsOnlyThePlannedOpening() {
|
||||
Cuboid plot = new Cuboid(2, 62, 2, 33, 71, 33);
|
||||
|
||||
@@ -104,6 +104,25 @@ class AvenueStairwayLayoutTest {
|
||||
new AvenueStairwayLayout.Step(-1, 63, 48), flights.getLast().stairBlocks().getFirst());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsStreetFlightsAlongXOnBothNorthAndSouthBorders() {
|
||||
Cuboid twoByTwoPlot = new Cuboid(2, 62, 2, 69, 71, 69);
|
||||
|
||||
List<AvenueStairwayLayout.Flight> flights =
|
||||
AvenueStairwayLayout.forUpperStreetSegments(twoByTwoPlot, 32, 36, 0, 1, 4, 2, 62, 14, 3);
|
||||
|
||||
assertEquals(4, flights.size());
|
||||
assertEquals(AvenueStairwayLayout.Side.NORTH, flights.getFirst().side());
|
||||
assertEquals(
|
||||
new AvenueStairwayLayout.Step(12, 63, -1), flights.getFirst().stairBlocks().getFirst());
|
||||
assertEquals(AvenueStairwayLayout.Side.SOUTH, flights.get(1).side());
|
||||
assertEquals(
|
||||
new AvenueStairwayLayout.Step(12, 63, 71), flights.get(1).stairBlocks().getFirst());
|
||||
assertEquals(
|
||||
new AvenueStairwayLayout.Step(48, 63, -1), flights.get(2).stairBlocks().getFirst());
|
||||
assertTrue(flights.stream().allMatch(flight -> flight.stairBlocks().getLast().y() == 76));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsAStairRunThatCannotFitWithinThePlotLength() {
|
||||
Cuboid plot = new Cuboid(2, 62, 2, 33, 71, 13);
|
||||
|
||||
@@ -30,19 +30,30 @@ class RoadLayoutTest {
|
||||
|
||||
@Test
|
||||
void buildsFullRoadWidthAndNonOverlappingCornersAtOnce() {
|
||||
List<RoadLayout.BlockPosition> road = RoadLayout.surroundingRoad(PLOT, 4);
|
||||
List<RoadLayout.BlockPosition> road = RoadLayout.surroundingRoad(PLOT, 4, 4);
|
||||
HashSet<RoadLayout.BlockPosition> uniqueBlocks = new HashSet<>(road);
|
||||
|
||||
assertEquals(576, road.size());
|
||||
assertEquals(road.size(), uniqueBlocks.size());
|
||||
assertTrue(road.contains(new RoadLayout.BlockPosition(34, 2)));
|
||||
assertTrue(road.contains(new RoadLayout.BlockPosition(37, 33)));
|
||||
assertTrue(road.contains(new RoadLayout.BlockPosition(2, 34)));
|
||||
assertTrue(road.contains(new RoadLayout.BlockPosition(33, 37)));
|
||||
assertTrue(road.contains(new RoadLayout.BlockPosition(34, 2, RoadLayout.RoadType.AVENUE)));
|
||||
assertTrue(road.contains(new RoadLayout.BlockPosition(2, 34, RoadLayout.RoadType.STREET)));
|
||||
assertTrue(
|
||||
road.contains(new RoadLayout.BlockPosition(34, 34, RoadLayout.RoadType.INTERSECTION)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnsNoRoadForZeroWidth() {
|
||||
assertTrue(RoadLayout.surroundingRoad(PLOT, 0).isEmpty());
|
||||
assertTrue(RoadLayout.surroundingRoad(PLOT, 0, 0).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void usesIndependentWidthsForStreetAndAvenueBands() {
|
||||
List<RoadLayout.BlockPosition> road = RoadLayout.surroundingRoad(PLOT, 2, 4);
|
||||
|
||||
assertEquals(416, road.size());
|
||||
assertTrue(road.contains(new RoadLayout.BlockPosition(2, 0, RoadLayout.RoadType.STREET)));
|
||||
assertTrue(road.contains(new RoadLayout.BlockPosition(-2, 2, RoadLayout.RoadType.AVENUE)));
|
||||
assertTrue(
|
||||
road.contains(new RoadLayout.BlockPosition(-2, 0, RoadLayout.RoadType.INTERSECTION)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,30 +26,37 @@ import org.junit.jupiter.api.Test;
|
||||
class SpawnLayoutTest {
|
||||
@Test
|
||||
void defaultMultipliersPreserveTheOnePlotSpawnBounds() {
|
||||
Cuboid spawn = SpawnLayout.bounds(1, 1, 1, 32, 10, 32, 4, 62);
|
||||
Cuboid spawn = SpawnLayout.bounds(1, 1, 1, 32, 10, 32, 4, 4, 62);
|
||||
|
||||
assertEqualsBounds(spawn, 2, 62, 2, 33, 71, 33);
|
||||
}
|
||||
|
||||
@Test
|
||||
void appliesEachMultiplierToItsOwnAlignedGridDimension() {
|
||||
Cuboid spawn = SpawnLayout.bounds(2, 3, 4, 32, 10, 32, 4, 62);
|
||||
Cuboid spawn = SpawnLayout.bounds(2, 3, 4, 32, 10, 32, 4, 4, 62);
|
||||
|
||||
assertEqualsBounds(spawn, 2, 62, 2, 69, 91, 141);
|
||||
}
|
||||
|
||||
@Test
|
||||
void validatesTheEntireSpawnHeightAgainstWorldBounds() {
|
||||
Cuboid spawn = SpawnLayout.bounds(1, 3, 1, 32, 10, 32, 4, 62);
|
||||
Cuboid spawn = SpawnLayout.bounds(1, 3, 1, 32, 10, 32, 4, 4, 62);
|
||||
|
||||
assertTrue(SpawnLayout.withinBuildHeight(spawn, -64, 320));
|
||||
assertFalse(SpawnLayout.withinBuildHeight(spawn, -64, 91));
|
||||
}
|
||||
|
||||
@Test
|
||||
void alignsSpawnAxesToTheirIndependentRoadWidths() {
|
||||
Cuboid spawn = SpawnLayout.bounds(2, 1, 3, 32, 10, 32, 6, 2, 62);
|
||||
|
||||
assertEqualsBounds(spawn, 3, 62, 1, 72, 71, 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsNonPositiveSpawnMultipliers() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> SpawnLayout.bounds(0, 1, 1, 32, 10, 32, 4, 62));
|
||||
IllegalArgumentException.class, () -> SpawnLayout.bounds(0, 1, 1, 32, 10, 32, 4, 4, 62));
|
||||
}
|
||||
|
||||
private static void assertEqualsBounds(
|
||||
|
||||
@@ -82,6 +82,6 @@ class MetropolisHomeAcquireTest {
|
||||
assertEquals(4, MetropolisPlugin.normalizeMaxLevels(4));
|
||||
assertEquals(3, MetropolisPlugin.clampMaxLevels(10, 3));
|
||||
assertEquals(1, MetropolisPlugin.clampMaxLevels(2, 1));
|
||||
assertEquals(1, MetropolisPlugin.clampMaxLevels(0, 0));
|
||||
assertEquals(0, MetropolisPlugin.clampMaxLevels(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user