Generate complete roads without rewrites
This commit is contained in:
@@ -22,7 +22,9 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.majinnaibu.bukkitplugins.metropolis.commands.MetropolisCommand;
|
||||
@@ -727,7 +729,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
private void createRoads(Cuboid plotCuboid, int roadMask) {
|
||||
private void createRoads(Cuboid plotCuboid) {
|
||||
if (plotCuboid == null) {
|
||||
if (DEBUG) {
|
||||
getLogger().warning("plotCuboid is null");
|
||||
@@ -736,84 +738,11 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
if (roadWidth > 0) {
|
||||
int x = 0;
|
||||
int y = plotCuboid.minY;
|
||||
int z = 0;
|
||||
Set<AvenueStairwayLayout.Step> stairOpenings = getUpperRoadOpenings(plotCuboid, y);
|
||||
|
||||
List<AvenueStairwayLayout.Step> stairOpenings = getUpperRoadOpenings(plotCuboid, y);
|
||||
int roadWidth1 = roadWidth / 2;
|
||||
int roadWidth2 = roadWidth - roadWidth1;
|
||||
|
||||
// North West Corner
|
||||
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, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// North Strip
|
||||
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, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// North East Corner
|
||||
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, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// East Strip
|
||||
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, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// South East Corner
|
||||
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, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// South Strip
|
||||
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, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// South West Corner
|
||||
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, stairOpenings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// West Strip
|
||||
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, stairOpenings);
|
||||
}
|
||||
}
|
||||
for (RoadLayout.BlockPosition roadBlock : RoadLayout.surroundingRoad(plotCuboid, roadWidth)) {
|
||||
setRoad(roadBlock.x(), y, roadBlock.z(), stairOpenings);
|
||||
}
|
||||
|
||||
int upperLevel = Math.floorDiv(y - roadLevel, getLevelPitchY());
|
||||
@@ -823,34 +752,13 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
private void createRoads(Cuboid plotCuboid) {
|
||||
createRoads(plotCuboid, ROAD_NORTH | ROAD_SOUTH | ROAD_EAST | ROAD_WEST);
|
||||
}
|
||||
|
||||
private void setRoad(int x, int y, int z, List<AvenueStairwayLayout.Step> stairOpenings) {
|
||||
private void setRoad(int x, int y, int z, Set<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);
|
||||
// Set the road block
|
||||
block.setType(roadMaterial);
|
||||
|
||||
// Set the support
|
||||
if (generateRoadSupports && isPhysicsMaterial(block.getType())) {
|
||||
Block blockUnder = world.getBlockAt(x, y - 1, z);
|
||||
if (!isSolidMaterial(blockUnder.getType())) {
|
||||
blockUnder.setType(roadSupportMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the space above
|
||||
for (int y1 = 0; y1 < spaceAboveRoad; y1++) {
|
||||
block = world.getBlockAt(x, y + y1 + 1, z);
|
||||
block.setType(Material.AIR);
|
||||
}
|
||||
RoadBlockWriter.build(
|
||||
world, x, y, z, roadMaterial, roadSupportMaterial, generateRoadSupports, spaceAboveRoad);
|
||||
}
|
||||
|
||||
private boolean isSolidMaterial(Material material) {
|
||||
@@ -1265,7 +1173,21 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
AvenueStairwayBuilder.build(world, flight, avenueStairMaterial);
|
||||
}
|
||||
|
||||
private List<AvenueStairwayLayout.Step> getUpperRoadOpenings(Cuboid plotCuboid, int roadY) {
|
||||
private Set<AvenueStairwayLayout.Step> getUpperRoadOpenings(Cuboid plotCuboid, int roadY) {
|
||||
Set<AvenueStairwayLayout.Step> openings = new HashSet<>();
|
||||
openings.addAll(getUpperRoadOpeningsForPlot(plotCuboid, roadY));
|
||||
if (_occupiedPlots != null) {
|
||||
for (Plot plot : _occupiedPlots) {
|
||||
if (plot instanceof PlayerHome home && home.getCuboid().minY == roadY) {
|
||||
openings.addAll(getUpperRoadOpeningsForPlot(home.getCuboid(), roadY));
|
||||
}
|
||||
}
|
||||
}
|
||||
return openings;
|
||||
}
|
||||
|
||||
private List<AvenueStairwayLayout.Step> getUpperRoadOpeningsForPlot(
|
||||
Cuboid plotCuboid, int roadY) {
|
||||
if (!generateAvenueStairs || roadY <= roadLevel) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
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 org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.type.Stairs;
|
||||
|
||||
public final class RoadBlockWriter {
|
||||
private RoadBlockWriter() {}
|
||||
|
||||
public static void build(
|
||||
World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
Material roadMaterial,
|
||||
Material supportMaterial,
|
||||
boolean generateSupports,
|
||||
int clearSpaceAbove) {
|
||||
Block roadBlock = world.getBlockAt(x, y, z);
|
||||
if (roadBlock.getType() == roadMaterial || roadBlock.getBlockData() instanceof Stairs) {
|
||||
return;
|
||||
}
|
||||
|
||||
roadBlock.setType(roadMaterial);
|
||||
if (generateSupports && (roadMaterial == Material.GRAVEL || roadMaterial == Material.SAND)) {
|
||||
Block blockUnder = world.getBlockAt(x, y - 1, z);
|
||||
if (!isSolid(blockUnder.getType())) {
|
||||
blockUnder.setType(supportMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
for (int clearance = 1; clearance <= clearSpaceAbove; clearance++) {
|
||||
Block blockAbove = world.getBlockAt(x, y + clearance, z);
|
||||
if (blockAbove.getType() != Material.AIR) {
|
||||
blockAbove.setType(Material.AIR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isSolid(Material material) {
|
||||
return material.isBlock()
|
||||
&& material != Material.AIR
|
||||
&& material != Material.WATER
|
||||
&& material != Material.LAVA
|
||||
&& material != Material.TORCH
|
||||
&& material != Material.REDSTONE_TORCH;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
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 RoadLayout {
|
||||
private RoadLayout() {}
|
||||
|
||||
public static List<BlockPosition> surroundingRoad(Cuboid plot, int roadWidth) {
|
||||
if (roadWidth < 1) {
|
||||
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);
|
||||
addRectangle(
|
||||
blocks, plot.maxX + 1, plot.maxX + roadWidth, plot.minZ - roadWidth, plot.minZ - 1);
|
||||
addRectangle(
|
||||
blocks, plot.minX - roadWidth, plot.minX - 1, plot.maxZ + 1, plot.maxZ + roadWidth);
|
||||
addRectangle(
|
||||
blocks, plot.maxX + 1, plot.maxX + roadWidth, plot.maxZ + 1, plot.maxZ + roadWidth);
|
||||
return List.copyOf(blocks);
|
||||
}
|
||||
|
||||
private static void addRectangle(
|
||||
List<BlockPosition> blocks, int minX, int maxX, int minZ, int maxZ) {
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
blocks.add(new BlockPosition(x, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record BlockPosition(int x, int z) {}
|
||||
}
|
||||
@@ -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 static org.mockito.ArgumentMatchers.any;
|
||||
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 org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.type.Stairs;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class RoadBlockWriterTest {
|
||||
@Test
|
||||
void doesNotRewriteAnExistingRoadBlockOrItsClearance() {
|
||||
World world = mock(World.class);
|
||||
Block roadBlock = mock(Block.class);
|
||||
when(world.getBlockAt(4, 62, 8)).thenReturn(roadBlock);
|
||||
when(roadBlock.getType()).thenReturn(Material.COBBLESTONE);
|
||||
|
||||
RoadBlockWriter.build(world, 4, 62, 8, Material.COBBLESTONE, Material.STONE, true, 4);
|
||||
|
||||
verify(roadBlock, never()).setType(any(Material.class));
|
||||
verify(world, never()).getBlockAt(4, 63, 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
void fillsMissingRoadBlocksAndPreservesExistingStairTreads() {
|
||||
World world = mock(World.class);
|
||||
Block missingRoadBlock = mock(Block.class);
|
||||
Block stairBlock = mock(Block.class);
|
||||
when(world.getBlockAt(4, 62, 8)).thenReturn(missingRoadBlock);
|
||||
when(world.getBlockAt(5, 76, 12)).thenReturn(stairBlock);
|
||||
when(missingRoadBlock.getType()).thenReturn(Material.AIR);
|
||||
when(stairBlock.getType()).thenReturn(Material.COBBLESTONE_STAIRS);
|
||||
when(stairBlock.getBlockData()).thenReturn(mock(Stairs.class));
|
||||
|
||||
RoadBlockWriter.build(world, 4, 62, 8, Material.COBBLESTONE, Material.STONE, false, 0);
|
||||
RoadBlockWriter.build(world, 5, 76, 12, Material.COBBLESTONE, Material.STONE, false, 4);
|
||||
|
||||
verify(missingRoadBlock).setType(Material.COBBLESTONE);
|
||||
verify(stairBlock, never()).setType(any(Material.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
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.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class RoadLayoutTest {
|
||||
private static final Cuboid PLOT = new Cuboid(2, 62, 2, 33, 71, 33);
|
||||
|
||||
@Test
|
||||
void buildsFullRoadWidthAndNonOverlappingCornersAtOnce() {
|
||||
List<RoadLayout.BlockPosition> road = RoadLayout.surroundingRoad(PLOT, 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)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnsNoRoadForZeroWidth() {
|
||||
assertTrue(RoadLayout.surroundingRoad(PLOT, 0).isEmpty());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user