Generate complete roads without rewrites

This commit is contained in:
2026-09-27 07:30:31 -07:00
parent fd5bf785d3
commit 30c31c185b
7 changed files with 264 additions and 103 deletions

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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) {}
}