Apply offsets to the logical plot grid
This commit is contained in:
@@ -98,6 +98,9 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
private int plotSizeX = 24;
|
||||
private int plotSizeY = 256;
|
||||
private int plotSizeZ = 24;
|
||||
private int plotOffsetX;
|
||||
private int plotOffsetY;
|
||||
private int plotOffsetZ;
|
||||
private int gridSizeX = 28;
|
||||
private int gridSizeY = 256;
|
||||
private int maxLevels = 1;
|
||||
@@ -146,6 +149,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
private Cuboid _cityCuboid = null;
|
||||
private ProtectedRegion _spawnRegion = null;
|
||||
private ProtectedRegion _cityRegion = null;
|
||||
private PlotGridLayout plotGridLayout;
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
@@ -201,6 +205,9 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
plotSizeX = safeGetIntFromConfig(config, "plot.sizeX");
|
||||
plotSizeY = optionalIntFromConfig(config, "plot.sizeY", 256);
|
||||
plotSizeZ = safeGetIntFromConfig(config, "plot.sizeZ");
|
||||
plotOffsetX = safeGetIntFromConfig(config, "plot.offsetX");
|
||||
plotOffsetY = safeGetIntFromConfig(config, "plot.offsetY");
|
||||
plotOffsetZ = safeGetIntFromConfig(config, "plot.offsetZ");
|
||||
maxLevels = optionalIntFromConfig(config, "plot.maxLevels", "maxLevels", 1);
|
||||
generateFloor = safeGetBooleanFromConfig(config, "plot.floor.generate");
|
||||
floorMaterial = safeGetMaterialFromConfig(config, "plot.floor.material");
|
||||
@@ -329,9 +336,20 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
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;
|
||||
plotGridLayout =
|
||||
new PlotGridLayout(
|
||||
plotSizeX,
|
||||
plotSizeY,
|
||||
plotSizeZ,
|
||||
streetWidth,
|
||||
avenueWidth,
|
||||
plotOffsetX,
|
||||
plotOffsetY,
|
||||
plotOffsetZ,
|
||||
roadLevel);
|
||||
gridSizeX = plotGridLayout.gridSizeX();
|
||||
gridSizeY = plotGridLayout.gridSizeY();
|
||||
gridSizeZ = plotGridLayout.gridSizeZ();
|
||||
|
||||
regionManager =
|
||||
WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(world));
|
||||
@@ -622,7 +640,10 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
plotSizeZ,
|
||||
avenueWidth,
|
||||
streetWidth,
|
||||
roadLevel);
|
||||
roadLevel,
|
||||
plotOffsetX,
|
||||
plotOffsetY,
|
||||
plotOffsetZ);
|
||||
if (!SpawnLayout.withinBuildHeight(spawnCuboid, world.getMinHeight(), world.getMaxHeight())) {
|
||||
getLogger()
|
||||
.severe(
|
||||
@@ -1037,11 +1058,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
public BlockVector3 getPlotMin(int row, int col, int plotMultiplier, int level) {
|
||||
BlockVector3 gridMin = getGridMin(row, col, plotMultiplier, level);
|
||||
|
||||
BlockVector3 bv =
|
||||
BlockVector3.at(
|
||||
gridMin.x() + avenueWidth / 2, getLevelStartY(level), gridMin.z() + streetWidth / 2);
|
||||
BlockVector3 bv = plotGridLayout.plotMin(row, col, level);
|
||||
getLogger().info(String.format("getPlotMin (%d, %d, %d)", bv.x(), bv.y(), bv.z()));
|
||||
return bv;
|
||||
}
|
||||
@@ -1051,13 +1068,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
public BlockVector3 getPlotMax(int row, int col, int plotMultiplier, int level) {
|
||||
BlockVector3 gridMax = getGridMax(row, col, plotMultiplier, level);
|
||||
|
||||
BlockVector3 bv =
|
||||
BlockVector3.at(
|
||||
gridMax.x() - (avenueWidth - avenueWidth / 2),
|
||||
getLevelStartY(level) + plotSizeY - 1,
|
||||
gridMax.z() - (streetWidth - streetWidth / 2));
|
||||
BlockVector3 bv = plotGridLayout.plotMax(row, col, plotMultiplier, plotMultiplier, level);
|
||||
getLogger().info(String.format("getPlotMax (%d, %d, %d)", bv.x(), bv.y(), bv.z()));
|
||||
return bv;
|
||||
}
|
||||
@@ -1067,7 +1078,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
public BlockVector3 getGridMin(int row, int col, int plotMultiplier, int level) {
|
||||
BlockVector3 bv = BlockVector3.at(col * gridSizeX, getLevelStartY(level), row * gridSizeZ);
|
||||
BlockVector3 bv = plotGridLayout.gridMin(row, col, level);
|
||||
getLogger().info(String.format("getGridMin (%d, %d, %d)", bv.x(), bv.y(), bv.z()));
|
||||
return bv;
|
||||
}
|
||||
@@ -1077,31 +1088,29 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
public BlockVector3 getGridMax(int row, int col, int plotMultiplier, int level) {
|
||||
BlockVector3 bv =
|
||||
BlockVector3.at(
|
||||
(col + plotMultiplier) * gridSizeX - 1,
|
||||
getLevelStartY(level) + plotSizeY - 1,
|
||||
(row + plotMultiplier) * gridSizeZ - 1);
|
||||
BlockVector3 bv = plotGridLayout.gridMax(row, col, plotMultiplier, plotMultiplier, level);
|
||||
getLogger().info(String.format("getGridMax (%d, %d, %d)", bv.x(), bv.y(), bv.z()));
|
||||
return bv;
|
||||
}
|
||||
|
||||
private int getPlotXFromMin(Cuboid cuboid) {
|
||||
return (cuboid.minX - avenueWidth / 2) / gridSizeX;
|
||||
return plotGridLayout.plotXIndexFromMin(cuboid);
|
||||
}
|
||||
|
||||
private int getPlotZFromMin(Cuboid cuboid) {
|
||||
return (cuboid.minZ - streetWidth / 2) / gridSizeZ;
|
||||
return plotGridLayout.plotZIndexFromMin(cuboid);
|
||||
}
|
||||
|
||||
private int getLevelPitchY() {
|
||||
return plotSizeY + Math.max(streetWidth, avenueWidth);
|
||||
return plotGridLayout.gridSizeY();
|
||||
}
|
||||
|
||||
private int getEffectiveMaxLevels() {
|
||||
int availableStreetLevels = getAvailableLevelsAt(roadLevel);
|
||||
int streetBaseY = getLevelStartY(0);
|
||||
int avenueBaseY = streetBaseY + avenueLevel - roadLevel;
|
||||
int availableStreetLevels = getAvailableLevelsAt(streetBaseY);
|
||||
int availableAvenueLevels =
|
||||
avenueWidth > 0 ? getAvailableLevelsAt(avenueLevel) : availableStreetLevels;
|
||||
avenueWidth > 0 ? getAvailableLevelsAt(avenueBaseY) : availableStreetLevels;
|
||||
int maxWorldLevels = Math.min(availableStreetLevels, availableAvenueLevels);
|
||||
return clampMaxLevels(maxLevels, maxWorldLevels);
|
||||
}
|
||||
@@ -1119,7 +1128,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
private int getLevelStartY(int level) {
|
||||
return roadLevel + level * getLevelPitchY();
|
||||
return plotGridLayout.levelStartY(level);
|
||||
}
|
||||
|
||||
private void setHomeOccupied(
|
||||
@@ -1289,7 +1298,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
|
||||
private List<AvenueStairwayLayout.Step> getUpperRoadOpeningsForPlot(
|
||||
Cuboid plotCuboid, int roadY, RoadLayout.RoadType roadType) {
|
||||
int baseY = roadType == RoadLayout.RoadType.AVENUE ? avenueLevel : roadLevel;
|
||||
int baseY = (roadType == RoadLayout.RoadType.AVENUE ? avenueLevel : roadLevel) + plotOffsetY;
|
||||
if (!areStairsEnabled(roadType) || roadY <= baseY) {
|
||||
return List.of();
|
||||
}
|
||||
@@ -1325,7 +1334,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
avenueStairsEveryNBlocks,
|
||||
avenueWidth,
|
||||
avenueStairWidth,
|
||||
avenueLevel + lowerLevel * getLevelPitchY(),
|
||||
avenueLevel + plotOffsetY + lowerLevel * getLevelPitchY(),
|
||||
getLevelPitchY(),
|
||||
3);
|
||||
}
|
||||
@@ -1338,7 +1347,7 @@ public class MetropolisPlugin extends JavaPlugin {
|
||||
streetStairsEveryNBlocks,
|
||||
streetWidth,
|
||||
streetStairWidth,
|
||||
roadLevel + lowerLevel * getLevelPitchY(),
|
||||
roadLevel + plotOffsetY + lowerLevel * getLevelPitchY(),
|
||||
getLevelPitchY(),
|
||||
3);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
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.sk89q.worldedit.math.BlockVector3;
|
||||
|
||||
public final class PlotGridLayout {
|
||||
private final int plotSizeX;
|
||||
private final int plotSizeY;
|
||||
private final int plotSizeZ;
|
||||
private final int streetWidth;
|
||||
private final int avenueWidth;
|
||||
private final int offsetX;
|
||||
private final int offsetY;
|
||||
private final int offsetZ;
|
||||
private final int roadLevel;
|
||||
private final int gridSizeX;
|
||||
private final int gridSizeY;
|
||||
private final int gridSizeZ;
|
||||
|
||||
public PlotGridLayout(
|
||||
int plotSizeX,
|
||||
int plotSizeY,
|
||||
int plotSizeZ,
|
||||
int streetWidth,
|
||||
int avenueWidth,
|
||||
int offsetX,
|
||||
int offsetY,
|
||||
int offsetZ,
|
||||
int roadLevel) {
|
||||
if (plotSizeX < 1 || plotSizeY < 1 || plotSizeZ < 1 || streetWidth < 0 || avenueWidth < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Plot dimensions must be positive and road widths nonnegative");
|
||||
}
|
||||
|
||||
this.plotSizeX = plotSizeX;
|
||||
this.plotSizeY = plotSizeY;
|
||||
this.plotSizeZ = plotSizeZ;
|
||||
this.streetWidth = streetWidth;
|
||||
this.avenueWidth = avenueWidth;
|
||||
this.offsetX = offsetX;
|
||||
this.offsetY = offsetY;
|
||||
this.offsetZ = offsetZ;
|
||||
this.roadLevel = roadLevel;
|
||||
gridSizeX = Math.addExact(plotSizeX, avenueWidth);
|
||||
gridSizeY = Math.addExact(plotSizeY, Math.max(streetWidth, avenueWidth));
|
||||
gridSizeZ = Math.addExact(plotSizeZ, streetWidth);
|
||||
}
|
||||
|
||||
public BlockVector3 gridMin(int row, int col, int level) {
|
||||
return BlockVector3.at(
|
||||
offsetX + col * gridSizeX, levelStartY(level), offsetZ + row * gridSizeZ);
|
||||
}
|
||||
|
||||
public BlockVector3 gridMax(int row, int col, int multiplierX, int multiplierZ, int level) {
|
||||
return BlockVector3.at(
|
||||
offsetX + (col + multiplierX) * gridSizeX - 1,
|
||||
levelStartY(level) + plotSizeY - 1,
|
||||
offsetZ + (row + multiplierZ) * gridSizeZ - 1);
|
||||
}
|
||||
|
||||
public BlockVector3 plotMin(int row, int col, int level) {
|
||||
BlockVector3 gridMin = gridMin(row, col, level);
|
||||
return BlockVector3.at(
|
||||
gridMin.x() + avenueWidth / 2, gridMin.y(), gridMin.z() + streetWidth / 2);
|
||||
}
|
||||
|
||||
public BlockVector3 plotMax(int row, int col, int multiplierX, int multiplierZ, int level) {
|
||||
BlockVector3 gridMax = gridMax(row, col, multiplierX, multiplierZ, level);
|
||||
return BlockVector3.at(
|
||||
gridMax.x() - (avenueWidth - avenueWidth / 2),
|
||||
gridMax.y(),
|
||||
gridMax.z() - (streetWidth - streetWidth / 2));
|
||||
}
|
||||
|
||||
public int plotXIndexFromMin(Cuboid plot) {
|
||||
return Math.floorDiv(plot.minX - offsetX - avenueWidth / 2, gridSizeX);
|
||||
}
|
||||
|
||||
public int plotZIndexFromMin(Cuboid plot) {
|
||||
return Math.floorDiv(plot.minZ - offsetZ - streetWidth / 2, gridSizeZ);
|
||||
}
|
||||
|
||||
public int levelStartY(int level) {
|
||||
return roadLevel + offsetY + level * gridSizeY;
|
||||
}
|
||||
|
||||
public int gridSizeX() {
|
||||
return gridSizeX;
|
||||
}
|
||||
|
||||
public int gridSizeY() {
|
||||
return gridSizeY;
|
||||
}
|
||||
|
||||
public int gridSizeZ() {
|
||||
return gridSizeZ;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,10 @@ public final class SpawnLayout {
|
||||
int plotSizeZ,
|
||||
int avenueWidth,
|
||||
int streetWidth,
|
||||
int roadLevel) {
|
||||
int roadLevel,
|
||||
int offsetX,
|
||||
int offsetY,
|
||||
int offsetZ) {
|
||||
if (sizeX < 1 || sizeY < 1 || sizeZ < 1 || avenueWidth < 0 || streetWidth < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Spawn multipliers must be positive and road widths nonnegative");
|
||||
@@ -42,10 +45,11 @@ public final class SpawnLayout {
|
||||
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 baseY = Math.addExact(roadLevel, offsetY);
|
||||
int maxY = Math.addExact(baseY, Math.multiplyExact(sizeY, plotSizeY) - 1);
|
||||
int maxZ = Math.subtractExact(Math.multiplyExact(sizeZ, gridSizeZ) - 1, maxInsetZ);
|
||||
|
||||
return new Cuboid(minX, roadLevel, minZ, maxX, maxY, maxZ);
|
||||
return new Cuboid(offsetX + minX, baseY, offsetZ + minZ, offsetX + maxX, maxY, offsetZ + maxZ);
|
||||
}
|
||||
|
||||
public static boolean withinBuildHeight(Cuboid cuboid, int minHeight, int maxHeight) {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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 com.sk89q.worldedit.math.BlockVector3;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class PlotGridLayoutTest {
|
||||
@Test
|
||||
void zeroOffsetsPreserveTheExistingPlotGrid() {
|
||||
PlotGridLayout grid = new PlotGridLayout(32, 10, 32, 4, 4, 0, 0, 0, 62);
|
||||
|
||||
assertEquals(BlockVector3.at(0, 62, 0), grid.gridMin(0, 0, 0));
|
||||
assertEquals(BlockVector3.at(35, 71, 35), grid.gridMax(0, 0, 1, 1, 0));
|
||||
assertEquals(BlockVector3.at(2, 62, 2), grid.plotMin(0, 0, 0));
|
||||
assertEquals(BlockVector3.at(33, 71, 33), grid.plotMax(0, 0, 1, 1, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void offsetsShiftGridAndPlotsOnAllAxesIncludingHigherLevels() {
|
||||
PlotGridLayout grid = new PlotGridLayout(32, 10, 32, 2, 6, -7, 3, 11, 62);
|
||||
|
||||
assertEquals(BlockVector3.at(-45, 97, -23), grid.gridMin(-1, -1, 2));
|
||||
assertEquals(BlockVector3.at(30, 106, 44), grid.gridMax(-1, -1, 2, 2, 2));
|
||||
assertEquals(BlockVector3.at(-42, 97, -22), grid.plotMin(-1, -1, 2));
|
||||
assertEquals(BlockVector3.at(27, 106, 43), grid.plotMax(-1, -1, 2, 2, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapsNegativePlotBoundsBackToTheirLogicalIndices() {
|
||||
PlotGridLayout grid = new PlotGridLayout(32, 10, 32, 2, 6, -7, 3, 11, 62);
|
||||
Cuboid plot = new Cuboid(grid.plotMin(-1, -1, 0), grid.plotMax(-1, -1, 2, 2, 0));
|
||||
|
||||
assertEquals(-1, grid.plotXIndexFromMin(plot));
|
||||
assertEquals(-1, grid.plotZIndexFromMin(plot));
|
||||
}
|
||||
}
|
||||
@@ -26,21 +26,21 @@ import org.junit.jupiter.api.Test;
|
||||
class SpawnLayoutTest {
|
||||
@Test
|
||||
void defaultMultipliersPreserveTheOnePlotSpawnBounds() {
|
||||
Cuboid spawn = SpawnLayout.bounds(1, 1, 1, 32, 10, 32, 4, 4, 62);
|
||||
Cuboid spawn = SpawnLayout.bounds(1, 1, 1, 32, 10, 32, 4, 4, 62, 0, 0, 0);
|
||||
|
||||
assertEqualsBounds(spawn, 2, 62, 2, 33, 71, 33);
|
||||
}
|
||||
|
||||
@Test
|
||||
void appliesEachMultiplierToItsOwnAlignedGridDimension() {
|
||||
Cuboid spawn = SpawnLayout.bounds(2, 3, 4, 32, 10, 32, 4, 4, 62);
|
||||
Cuboid spawn = SpawnLayout.bounds(2, 3, 4, 32, 10, 32, 4, 4, 62, 0, 0, 0);
|
||||
|
||||
assertEqualsBounds(spawn, 2, 62, 2, 69, 91, 141);
|
||||
}
|
||||
|
||||
@Test
|
||||
void validatesTheEntireSpawnHeightAgainstWorldBounds() {
|
||||
Cuboid spawn = SpawnLayout.bounds(1, 3, 1, 32, 10, 32, 4, 4, 62);
|
||||
Cuboid spawn = SpawnLayout.bounds(1, 3, 1, 32, 10, 32, 4, 4, 62, 0, 0, 0);
|
||||
|
||||
assertTrue(SpawnLayout.withinBuildHeight(spawn, -64, 320));
|
||||
assertFalse(SpawnLayout.withinBuildHeight(spawn, -64, 91));
|
||||
@@ -48,15 +48,23 @@ class SpawnLayoutTest {
|
||||
|
||||
@Test
|
||||
void alignsSpawnAxesToTheirIndependentRoadWidths() {
|
||||
Cuboid spawn = SpawnLayout.bounds(2, 1, 3, 32, 10, 32, 6, 2, 62);
|
||||
Cuboid spawn = SpawnLayout.bounds(2, 1, 3, 32, 10, 32, 6, 2, 62, 0, 0, 0);
|
||||
|
||||
assertEqualsBounds(spawn, 3, 62, 1, 72, 71, 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
void alignsSpawnBoundsWithAllGridOffsets() {
|
||||
Cuboid spawn = SpawnLayout.bounds(2, 2, 3, 32, 10, 32, 6, 2, 62, -7, 3, 11);
|
||||
|
||||
assertEqualsBounds(spawn, -4, 65, 12, 65, 84, 111);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsNonPositiveSpawnMultipliers() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> SpawnLayout.bounds(0, 1, 1, 32, 10, 32, 4, 4, 62));
|
||||
IllegalArgumentException.class,
|
||||
() -> SpawnLayout.bounds(0, 1, 1, 32, 10, 32, 4, 4, 62, 0, 0, 0));
|
||||
}
|
||||
|
||||
private static void assertEqualsBounds(
|
||||
|
||||
Reference in New Issue
Block a user