Add upper-road stairwell generation
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
import com.majinnaibu.bukkitplugins.metropolis.AvenueStairwayLayout.Flight;
|
||||
import com.majinnaibu.bukkitplugins.metropolis.AvenueStairwayLayout.Step;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.Bisected;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Stairs;
|
||||
|
||||
public final class AvenueStairwayBuilder {
|
||||
private AvenueStairwayBuilder() {}
|
||||
|
||||
public static void build(World world, Flight flight, Material stairMaterial) {
|
||||
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.setHalf(Bisected.Half.BOTTOM);
|
||||
stairs.setShape(Stairs.Shape.STRAIGHT);
|
||||
stairBlock.setBlockData(stairs, false);
|
||||
}
|
||||
}
|
||||
|
||||
for (Step backing : flight.invertedBackingBlocks()) {
|
||||
Block supportBlock = world.getBlockAt(backing.x(), backing.y(), backing.z());
|
||||
supportBlock.setType(stairMaterial, false);
|
||||
BlockData supportData = supportBlock.getBlockData();
|
||||
if (supportData instanceof Stairs stairs) {
|
||||
stairs.setFacing(BlockFace.NORTH);
|
||||
stairs.setHalf(Bisected.Half.TOP);
|
||||
stairs.setShape(Stairs.Shape.STRAIGHT);
|
||||
supportBlock.setBlockData(stairs, false);
|
||||
}
|
||||
}
|
||||
|
||||
for (Step opening : flight.roadOpenings()) {
|
||||
world.getBlockAt(opening.x(), opening.y(), opening.z()).setType(Material.AIR, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class AvenueStairwayLayout {
|
||||
private 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 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));
|
||||
}
|
||||
}
|
||||
return List.copyOf(steps);
|
||||
}
|
||||
|
||||
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);
|
||||
if (stairs.isEmpty() || openingLength < 1) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
Step topStair = stairs.get(stairs.size() - 1);
|
||||
int firstX = stairs.getFirst().x();
|
||||
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));
|
||||
}
|
||||
}
|
||||
return List.copyOf(opening);
|
||||
}
|
||||
|
||||
public static Flight forUpperRoad(
|
||||
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());
|
||||
}
|
||||
|
||||
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 new Flight(
|
||||
stairs,
|
||||
invertedBackings,
|
||||
upperRoadOpening(plot, roadWidth, stairWidth, lowerY, rise, openingLength));
|
||||
}
|
||||
|
||||
public record Step(int x, int y, int z) {}
|
||||
|
||||
public record Flight(
|
||||
List<Step> stairBlocks, List<Step> invertedBackingBlocks, List<Step> roadOpenings) {
|
||||
public Flight {
|
||||
stairBlocks = List.copyOf(stairBlocks);
|
||||
invertedBackingBlocks = List.copyOf(invertedBackingBlocks);
|
||||
roadOpenings = List.copyOf(roadOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.type.Stairs;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -100,11 +101,16 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
private int maxLevels = 1;
|
||||
private int gridSizeZ = 28;
|
||||
private int roadWidth = 4;
|
||||
private int avenueWidth = 4;
|
||||
private int roadLevel = 62;
|
||||
private int spaceAboveRoad = 2;
|
||||
private Material roadMaterial = Material.COBBLESTONE;
|
||||
private boolean generateRoadSupports = true;
|
||||
private Material roadSupportMaterial = Material.STONE;
|
||||
private boolean generateAvenueStairs;
|
||||
private Material avenueStairMaterial = Material.COBBLESTONE_STAIRS;
|
||||
private int avenueStairWidth;
|
||||
private int avenueStairsEveryNBlocks;
|
||||
private String worldName = "world";
|
||||
private boolean generateFloor = false;
|
||||
private Material floorMaterial = Material.GRASS_BLOCK;
|
||||
@@ -190,6 +196,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
generateSign = safeGetBooleanFromConfig(config, "plot.sign.generate");
|
||||
roadWidth =
|
||||
safeGetIntFromConfig(config, "road.streets.width", "road.avenues.width", "road.width");
|
||||
avenueWidth = safeGetIntFromConfig(config, "road.avenues.width");
|
||||
spaceAboveRoad =
|
||||
safeGetIntFromConfig(
|
||||
config,
|
||||
@@ -213,6 +220,32 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
"road.streets.supports.material",
|
||||
"road.avenues.supports.material",
|
||||
"road.supports.material");
|
||||
generateAvenueStairs = safeGetBooleanFromConfig(config, "road.avenues.stairs.generate");
|
||||
if (generateAvenueStairs) {
|
||||
avenueStairMaterial = safeGetMaterialFromConfig(config, "road.avenues.stairs.material");
|
||||
avenueStairWidth = safeGetIntFromConfig(config, "road.avenues.stairs.width");
|
||||
avenueStairsEveryNBlocks = safeGetIntFromConfig(config, "road.avenues.stairs.everyNBlocks");
|
||||
|
||||
if (avenueStairWidth < 1 || avenueStairWidth >= avenueWidth) {
|
||||
getLogger()
|
||||
.severe(
|
||||
"road.avenues.stairs.width must be positive and narrower than road.avenues.width;"
|
||||
+ " avenue stairs are disabled.");
|
||||
generateAvenueStairs = false;
|
||||
}
|
||||
if (avenueStairsEveryNBlocks < 1) {
|
||||
getLogger()
|
||||
.severe(
|
||||
"road.avenues.stairs.everyNBlocks must be positive; avenue stairs are disabled.");
|
||||
generateAvenueStairs = false;
|
||||
}
|
||||
if (!(avenueStairMaterial.createBlockData() instanceof Stairs)) {
|
||||
getLogger()
|
||||
.severe(
|
||||
"road.avenues.stairs.material must be a stair block; avenue stairs are disabled.");
|
||||
generateAvenueStairs = false;
|
||||
}
|
||||
}
|
||||
generateSpawn = safeGetBooleanFromConfig(config, "spawn.generate");
|
||||
setWorldSpawn = safeGetBooleanFromConfig(config, "spawn.setAsWorldSpawn");
|
||||
spawnFloorMaterial = safeGetMaterialFromConfig(config, "spawn.material");
|
||||
@@ -695,18 +728,19 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
private void createRoads(Cuboid plotCuboid, int roadMask) {
|
||||
if (plotCuboid == null) {
|
||||
if (DEBUG) {
|
||||
getLogger().warning("plotCuboid is null");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (roadWidth > 0) {
|
||||
int x = 0;
|
||||
int y = plotCuboid.minY;
|
||||
int z = 0;
|
||||
|
||||
if (plotCuboid == null) {
|
||||
if (DEBUG) {
|
||||
getLogger().warning("plotCuboid is null");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
List<AvenueStairwayLayout.Step> stairOpenings = getUpperRoadOpenings(plotCuboid, y);
|
||||
int roadWidth1 = roadWidth / 2;
|
||||
int roadWidth2 = roadWidth - roadWidth1;
|
||||
|
||||
@@ -714,7 +748,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
if ((roadMask & (ROAD_NORTH | ROAD_WEST)) != 0) {
|
||||
for (x = plotCuboid.minX - roadWidth1; x < plotCuboid.minX; x++) {
|
||||
for (z = plotCuboid.minZ - roadWidth1; z < plotCuboid.minZ; z++) {
|
||||
setRoad(x, y, z);
|
||||
setRoad(x, y, z, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -723,7 +757,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
if ((roadMask & ROAD_NORTH) != 0) {
|
||||
for (x = plotCuboid.minX; x <= plotCuboid.maxX; x++) {
|
||||
for (z = plotCuboid.minZ - roadWidth1; z < plotCuboid.minZ; z++) {
|
||||
setRoad(x, y, z);
|
||||
setRoad(x, y, z, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -732,7 +766,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
if ((roadMask & (ROAD_NORTH | ROAD_EAST)) != 0) {
|
||||
for (x = plotCuboid.maxX + 1; x <= plotCuboid.maxX + roadWidth2; x++) {
|
||||
for (z = plotCuboid.minZ - roadWidth1; z < plotCuboid.minZ; z++) {
|
||||
setRoad(x, y, z);
|
||||
setRoad(x, y, z, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -741,7 +775,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
if ((roadMask & ROAD_EAST) != 0) {
|
||||
for (x = plotCuboid.maxX + 1; x <= plotCuboid.maxX + roadWidth2; x++) {
|
||||
for (z = plotCuboid.minZ; z <= plotCuboid.maxZ; z++) {
|
||||
setRoad(x, y, z);
|
||||
setRoad(x, y, z, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -750,7 +784,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
if ((roadMask & (ROAD_SOUTH | ROAD_EAST)) != 0) {
|
||||
for (x = plotCuboid.maxX + 1; x <= plotCuboid.maxX + roadWidth2; x++) {
|
||||
for (z = plotCuboid.maxZ + 1; z <= plotCuboid.maxZ + roadWidth2; z++) {
|
||||
setRoad(x, y, z);
|
||||
setRoad(x, y, z, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -759,7 +793,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
if ((roadMask & ROAD_SOUTH) != 0) {
|
||||
for (x = plotCuboid.minX; x <= plotCuboid.maxX; x++) {
|
||||
for (z = plotCuboid.maxZ + 1; z <= plotCuboid.maxZ + roadWidth2; z++) {
|
||||
setRoad(x, y, z);
|
||||
setRoad(x, y, z, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -768,7 +802,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
if ((roadMask & (ROAD_SOUTH | ROAD_WEST)) != 0) {
|
||||
for (x = plotCuboid.minX - roadWidth1; x < plotCuboid.minX; x++) {
|
||||
for (z = plotCuboid.maxZ + 1; z <= plotCuboid.maxZ + roadWidth2; z++) {
|
||||
setRoad(x, y, z);
|
||||
setRoad(x, y, z, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -777,10 +811,15 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
if ((roadMask & ROAD_WEST) != 0) {
|
||||
for (x = plotCuboid.minX - roadWidth1; x < plotCuboid.minX; x++) {
|
||||
for (z = plotCuboid.minZ; z <= plotCuboid.maxZ; z++) {
|
||||
setRoad(x, y, z);
|
||||
setRoad(x, y, z, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int upperLevel = Math.floorDiv(y - roadLevel, getLevelPitchY());
|
||||
if (upperLevel > 0 && getLevelStartY(upperLevel) == y) {
|
||||
generateAvenueStairs(plotCuboid, upperLevel - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,7 +827,11 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
createRoads(plotCuboid, ROAD_NORTH | ROAD_SOUTH | ROAD_EAST | ROAD_WEST);
|
||||
}
|
||||
|
||||
private void setRoad(int x, int y, int z) {
|
||||
private void setRoad(int x, int y, int z, List<AvenueStairwayLayout.Step> stairOpenings) {
|
||||
if (stairOpenings.contains(new AvenueStairwayLayout.Step(x, y, z))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if(DEBUG){getLogger().info(String.format("setting road at (%d, %d, %d)", x, y, z));}
|
||||
|
||||
Block block = world.getBlockAt(x, y, z);
|
||||
@@ -1193,6 +1236,61 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
sign.update(true);
|
||||
}
|
||||
|
||||
private void generateAvenueStairs(Cuboid plotCuboid, int lowerLevel) {
|
||||
if (!generateAvenueStairs || lowerLevel < 0 || lowerLevel >= getEffectiveMaxLevels() - 1) {
|
||||
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()) {
|
||||
getLogger()
|
||||
.warning(
|
||||
"Avenue stair run does not fit beside plot at "
|
||||
+ plotCuboid.minX
|
||||
+ ","
|
||||
+ plotCuboid.minY
|
||||
+ ","
|
||||
+ plotCuboid.minZ);
|
||||
return;
|
||||
}
|
||||
|
||||
AvenueStairwayBuilder.build(world, flight, avenueStairMaterial);
|
||||
}
|
||||
|
||||
private List<AvenueStairwayLayout.Step> getUpperRoadOpenings(Cuboid plotCuboid, int roadY) {
|
||||
if (!generateAvenueStairs || roadY <= roadLevel) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
int upperLevel = Math.floorDiv(roadY - roadLevel, getLevelPitchY());
|
||||
if (getLevelStartY(upperLevel) != roadY) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
int lowerLevel = upperLevel - 1;
|
||||
int avenueBlockIndex = getPlotZFromMin(plotCuboid);
|
||||
if (lowerLevel < 0 || Math.floorMod(avenueBlockIndex + 1, avenueStairsEveryNBlocks) != 0) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
return AvenueStairwayLayout.forUpperRoad(
|
||||
plotCuboid,
|
||||
avenueWidth,
|
||||
avenueStairWidth,
|
||||
getLevelStartY(lowerLevel),
|
||||
getLevelPitchY(),
|
||||
3)
|
||||
.roadOpenings();
|
||||
}
|
||||
|
||||
public List<Plot> getCityBlocks() {
|
||||
return Collections.unmodifiableList(_occupiedPlots);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ road:
|
||||
supports:
|
||||
generate: true
|
||||
material: STONE
|
||||
stairs:
|
||||
generate: false
|
||||
streets:
|
||||
width: 4
|
||||
clearSpaceAbove: 66
|
||||
|
||||
@@ -31,6 +31,7 @@ road:
|
||||
generate: true
|
||||
material: COBBLESTONE_STAIRS
|
||||
everyNBlocks: 4
|
||||
width: 2
|
||||
streets:
|
||||
width: 4
|
||||
clearSpaceAbove: 9
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.majinnaibu.bukkitplugins.metropolis.AvenueStairwayLayout.Flight;
|
||||
import com.majinnaibu.bukkitplugins.metropolis.AvenueStairwayLayout.Step;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.Bisected;
|
||||
import org.bukkit.block.data.type.Stairs;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AvenueStairwayBuilderTest {
|
||||
@Test
|
||||
void buildsAscendingAndInvertedStairsAndClearsOnlyThePlannedOpening() {
|
||||
Cuboid plot = new Cuboid(2, 62, 2, 33, 71, 33);
|
||||
Flight flight = AvenueStairwayLayout.forUpperRoad(plot, 4, 2, 62, 14, 3);
|
||||
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);
|
||||
|
||||
for (Step stair : flight.stairBlocks()) {
|
||||
verify(blocks.get(stair)).setType(Material.COBBLESTONE_STAIRS, false);
|
||||
}
|
||||
for (Step backing : flight.invertedBackingBlocks()) {
|
||||
verify(blocks.get(backing)).setType(Material.COBBLESTONE_STAIRS, false);
|
||||
}
|
||||
for (Step opening : flight.roadOpenings()) {
|
||||
verify(blocks.get(opening)).setType(Material.AIR, false);
|
||||
}
|
||||
|
||||
Step firstStair = flight.stairBlocks().getFirst();
|
||||
Stairs firstStairData = blockData.get(firstStair);
|
||||
assertNotNull(firstStairData);
|
||||
verify(firstStairData).setFacing(BlockFace.SOUTH);
|
||||
verify(firstStairData).setHalf(Bisected.Half.BOTTOM);
|
||||
|
||||
Step firstInvertedBacking = flight.invertedBackingBlocks().getFirst();
|
||||
Stairs invertedBackingData = blockData.get(firstInvertedBacking);
|
||||
assertNotNull(invertedBackingData);
|
||||
verify(invertedBackingData).setFacing(BlockFace.NORTH);
|
||||
verify(invertedBackingData).setHalf(Bisected.Half.TOP);
|
||||
|
||||
verify(world, never()).getBlockAt(anyInt(), eq(62), anyInt());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AvenueStairwayLayoutTest {
|
||||
@Test
|
||||
void centersStairsAcrossTheAvenueAndAlongThePlotLength() {
|
||||
Cuboid plot = new Cuboid(2, 62, 2, 33, 71, 33);
|
||||
|
||||
List<AvenueStairwayLayout.Step> steps =
|
||||
AvenueStairwayLayout.centeredEastAvenue(plot, 4, 2, 62, 14);
|
||||
|
||||
assertEquals(28, steps.size());
|
||||
assertEquals(new AvenueStairwayLayout.Step(35, 63, 12), steps.get(0));
|
||||
assertEquals(new AvenueStairwayLayout.Step(36, 63, 12), steps.get(1));
|
||||
assertEquals(new AvenueStairwayLayout.Step(35, 64, 13), steps.get(2));
|
||||
assertEquals(new AvenueStairwayLayout.Step(36, 76, 25), steps.get(27));
|
||||
}
|
||||
|
||||
@Test
|
||||
void opensOnlyTheThreeUpperRoadBlocksBeforeTheTopStair() {
|
||||
Cuboid plot = new Cuboid(2, 62, 2, 33, 71, 33);
|
||||
|
||||
List<AvenueStairwayLayout.Step> openings =
|
||||
AvenueStairwayLayout.upperRoadOpening(plot, 4, 2, 62, 14, 3);
|
||||
|
||||
assertEquals(6, openings.size());
|
||||
assertEquals(new AvenueStairwayLayout.Step(35, 76, 22), openings.get(0));
|
||||
assertEquals(new AvenueStairwayLayout.Step(35, 76, 23), openings.get(1));
|
||||
assertEquals(new AvenueStairwayLayout.Step(35, 76, 24), openings.get(2));
|
||||
assertEquals(new AvenueStairwayLayout.Step(36, 76, 24), openings.get(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
void upperRoadFlightPreservesTheLowerRoadAndPlansInvertedBacking() {
|
||||
Cuboid plot = new Cuboid(2, 62, 2, 33, 71, 33);
|
||||
|
||||
AvenueStairwayLayout.Flight flight = AvenueStairwayLayout.forUpperRoad(plot, 4, 2, 62, 14, 3);
|
||||
|
||||
assertEquals(28, flight.stairBlocks().size());
|
||||
assertEquals(new AvenueStairwayLayout.Step(35, 63, 12), flight.stairBlocks().getFirst());
|
||||
assertEquals(new AvenueStairwayLayout.Step(36, 76, 25), flight.stairBlocks().getLast());
|
||||
assertEquals(26, flight.invertedBackingBlocks().size());
|
||||
assertEquals(
|
||||
new AvenueStairwayLayout.Step(35, 63, 13), flight.invertedBackingBlocks().getFirst());
|
||||
assertTrue(flight.stairBlocks().stream().allMatch(step -> step.y() > 62));
|
||||
assertTrue(flight.invertedBackingBlocks().stream().allMatch(step -> step.y() > 62));
|
||||
assertEquals(6, flight.roadOpenings().size());
|
||||
assertTrue(flight.roadOpenings().stream().allMatch(step -> step.y() == 76));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsAStairRunThatCannotFitWithinThePlotLength() {
|
||||
Cuboid plot = new Cuboid(2, 62, 2, 33, 71, 13);
|
||||
|
||||
assertTrue(AvenueStairwayLayout.centeredEastAvenue(plot, 4, 2, 62, 14).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsStairsThatAreNotNarrowerThanTheAvenue() {
|
||||
Cuboid plot = new Cuboid(2, 62, 2, 33, 71, 33);
|
||||
|
||||
assertTrue(AvenueStairwayLayout.centeredEastAvenue(plot, 4, 4, 62, 14).isEmpty());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user