diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index 61ba28413..cd7dc4c7f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -238,6 +238,16 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl return this.version; } + @Override + public int versionMinHeight() { + return serverVersion()[1] >= 18 ? -64 : 0; + } + + @Override + public int versionMaxHeight() { + return serverVersion()[1] >= 18 ? 319 : 255; + } + @Override public @NonNull String serverImplementation() { return Bukkit.getVersion(); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java index 934ab4631..9574a2fc8 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java @@ -65,7 +65,10 @@ final class BlockStatePopulator extends BlockPopulator { return; } final ChunkWrapper wrap = new ChunkWrapper(area.getWorldName(), source.getX(), source.getZ()); - final ScopedQueueCoordinator chunk = this.queue.getForChunk(wrap.x, wrap.z); + final ScopedQueueCoordinator chunk = this.queue.getForChunk(wrap.x, wrap.z, + com.plotsquared.bukkit.util.BukkitWorld.getMinWorldHeight(world), + com.plotsquared.bukkit.util.BukkitWorld.getMaxWorldHeight(world) - 1 + ); if (this.plotGenerator.populateChunk(chunk, area)) { this.queue.enqueue(); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java index f5406ef9a..baaf95dfc 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java @@ -27,6 +27,7 @@ package com.plotsquared.bukkit.generator; import com.plotsquared.bukkit.queue.GenChunk; import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.bukkit.util.BukkitWorld; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.generator.IndependentPlotGenerator; @@ -159,12 +160,14 @@ public class BukkitPlotGenerator extends ChunkGenerator @NonNull BiomeGrid biome ) { - GenChunk result = new GenChunk(); + int minY = BukkitWorld.getMinWorldHeight(world); + int maxY = BukkitWorld.getMaxWorldHeight(world); + GenChunk result = new GenChunk(minY, maxY); if (this.getPlotGenerator() instanceof SingleWorldGenerator) { if (result.getChunkData() != null) { for (int chunkX = 0; chunkX < 16; chunkX++) { for (int chunkZ = 0; chunkZ < 16; chunkZ++) { - for (int y = 0; y < world.getMaxHeight(); y++) { + for (int y = minY; y < maxY; y++) { biome.setBiome(chunkX, y, chunkZ, Biome.PLAINS); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/BlockEventListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/BlockEventListener.java index 616af9922..1e71e642c 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/BlockEventListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/BlockEventListener.java @@ -354,7 +354,8 @@ public class BlockEventListener implements Listener { Plot plot = area.getPlot(location); if (plot != null) { BukkitPlayer plotPlayer = BukkitUtil.adapt(player); - if (event.getBlock().getY() == 0) { + // == rather than <= as we only care about the "ground level" not being destroyed + if (event.getBlock().getY() == area.getMinGenHeight()) { if (!Permissions .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL)) { plotPlayer.sendMessage( @@ -649,7 +650,8 @@ public class BlockEventListener implements Listener { event.getBlock().breakNaturally(); } } - if (location.getY() == 0) { + // == rather than <= as we only care about the "ground level" not being destroyed + if (location.getY() == area.getMinGenHeight()) { event.setCancelled(true); return; } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java index e8416fab1..3f78bf39e 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java @@ -74,8 +74,9 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { private final Consumer throwableConsumer; private final boolean unloadAfter; private final int totalSize; - private final AtomicInteger expectedSize; + private final AtomicInteger loadingChunks = new AtomicInteger(); + private int batchSize; private PlotSquaredTask task; private boolean shouldCancel; @@ -150,6 +151,13 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { Chunk chunk = this.availableChunks.poll(); if (chunk == null) { + if (this.availableChunks.isEmpty()) { + if (this.requestedChunks.isEmpty() && loadingChunks.get() == 0) { + finish(); + } else { + requestBatch(); + } + } return; } long[] iterationTime = new long[2]; @@ -197,9 +205,11 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { BlockVector2 chunk; for (int i = 0; i < this.batchSize && (chunk = this.requestedChunks.poll()) != null; i++) { // This required PaperLib to be bumped to version 1.0.4 to mark the request as urgent + loadingChunks.incrementAndGet(); PaperLib .getChunkAtAsync(this.bukkitWorld, chunk.getX(), chunk.getZ(), true, true) .whenComplete((chunkObject, throwable) -> { + loadingChunks.decrementAndGet(); if (throwable != null) { throwable.printStackTrace(); // We want one less because this couldn't be processed diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java index 8c418ee88..f7e6f16a3 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java @@ -111,8 +111,8 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { public boolean enqueue() { final Clipboard regenClipboard; if (isRegen()) { - BlockVector3 start = BlockVector3.at(getRegenStart()[0] << 4, 0, getRegenStart()[1] << 4); - BlockVector3 end = BlockVector3.at((getRegenEnd()[0] << 4) + 15, 255, (getRegenEnd()[1] << 4) + 15); + BlockVector3 start = BlockVector3.at(getRegenStart()[0] << 4, getMinY(), getRegenStart()[1] << 4); + BlockVector3 end = BlockVector3.at((getRegenEnd()[0] << 4) + 15, getMaxY(), (getRegenEnd()[1] << 4) + 15); Region region = new CuboidRegion(start, end); regenClipboard = new BlockArrayClipboard(region); regenClipboard.setOrigin(start); @@ -134,7 +134,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { int sx = blockVector2.getX() << 4; int sz = blockVector2.getZ() << 4; if (isRegenChunk) { - for (int layer = 0; layer < 16; layer++) { + for (int layer = getMinLayer(); layer <= getMaxLayer(); layer++) { for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { @@ -170,7 +170,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { int lx = ChunkUtil.getX(j); int lz = ChunkUtil.getZ(j); int x = sx + lx; - int y = ChunkUtil.getY(layer, j); + int y = ChunkUtil.getY(layer + localChunk.getMinSection(), j); int z = sz + lz; boolean edge = Settings.QUEUE.UPDATE_EDGES && isEdge(y >> 4, lx, y & 15, lz, blockVector2, localChunk @@ -179,7 +179,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { } } } - for (int layer = 0; layer < localChunk.getBaseblocks().length; layer++) { + for (int layer = 0; layer < localChunk.getBiomes().length; layer++) { BiomeType[] biomesLayer = localChunk.getBiomes()[layer]; if (biomesLayer == null) { continue; @@ -295,47 +295,48 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { } private boolean isEdge(int layer, int x, int y, int z, BlockVector2 blockVector2, LocalChunk localChunk) { - if (layer == 0 || layer == localChunk.getBaseblocks().length - 1) { + int layerIndex = (layer - localChunk.getMinSection()); + if (layer == localChunk.getMinSection() || layerIndex == localChunk.getBaseblocks().length - 1) { return false; } if (x == 0) { LocalChunk localChunkX = getBlockChunks().get(blockVector2.withX(blockVector2.getX() - 1)); - if (localChunkX == null || localChunkX.getBaseblocks()[layer] == null || - localChunkX.getBaseblocks()[layer][ChunkUtil.getJ(15, y, z)] != null) { + if (localChunkX == null || localChunkX.getBaseblocks()[layerIndex] == null || + localChunkX.getBaseblocks()[layerIndex][ChunkUtil.getJ(15, y, z)] != null) { return true; } } else if (x == 15) { LocalChunk localChunkX = getBlockChunks().get(blockVector2.withX(blockVector2.getX() + 1)); - if (localChunkX == null || localChunkX.getBaseblocks()[layer] == null || - localChunkX.getBaseblocks()[layer][ChunkUtil.getJ(0, y, z)] != null) { + if (localChunkX == null || localChunkX.getBaseblocks()[layerIndex] == null || + localChunkX.getBaseblocks()[layerIndex][ChunkUtil.getJ(0, y, z)] != null) { return true; } } if (z == 0) { LocalChunk localChunkZ = getBlockChunks().get(blockVector2.withZ(blockVector2.getZ() - 1)); - if (localChunkZ == null || localChunkZ.getBaseblocks()[layer] == null || - localChunkZ.getBaseblocks()[layer][ChunkUtil.getJ(x, y, 15)] != null) { + if (localChunkZ == null || localChunkZ.getBaseblocks()[layerIndex] == null || + localChunkZ.getBaseblocks()[layerIndex][ChunkUtil.getJ(x, y, 15)] != null) { return true; } } else if (z == 15) { LocalChunk localChunkZ = getBlockChunks().get(blockVector2.withZ(blockVector2.getZ() + 1)); - if (localChunkZ == null || localChunkZ.getBaseblocks()[layer] == null || - localChunkZ.getBaseblocks()[layer][ChunkUtil.getJ(x, y, 0)] != null) { + if (localChunkZ == null || localChunkZ.getBaseblocks()[layerIndex] == null || + localChunkZ.getBaseblocks()[layerIndex][ChunkUtil.getJ(x, y, 0)] != null) { return true; } } if (y == 0) { - if (localChunk.getBaseblocks()[layer - 1] == null || - localChunk.getBaseblocks()[layer][ChunkUtil.getJ(x, 15, z)] != null) { + if (localChunk.getBaseblocks()[layerIndex - 1] == null || + localChunk.getBaseblocks()[layerIndex][ChunkUtil.getJ(x, 15, z)] != null) { return true; } } else if (y == 15) { - if (localChunk.getBaseblocks()[layer + 1] == null || - localChunk.getBaseblocks()[layer][ChunkUtil.getJ(x, 0, z)] != null) { + if (localChunk.getBaseblocks()[layerIndex + 1] == null || + localChunk.getBaseblocks()[layerIndex][ChunkUtil.getJ(x, 0, z)] != null) { return true; } } - BaseBlock[] baseBlocks = localChunk.getBaseblocks()[layer]; + BaseBlock[] baseBlocks = localChunk.getBaseblocks()[layerIndex]; if (x > 0 && baseBlocks[ChunkUtil.getJ(x - 1, y, z)] == null) { return true; } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/GenChunk.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/GenChunk.java index 10da1e0de..ac40d26ce 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/GenChunk.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/GenChunk.java @@ -31,6 +31,7 @@ import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.core.location.ChunkWrapper; import com.plotsquared.core.location.Location; import com.plotsquared.core.queue.ScopedQueueCoordinator; +import com.plotsquared.core.util.AnnotationHelper; import com.plotsquared.core.util.ChunkUtil; import com.plotsquared.core.util.PatternUtil; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -50,6 +51,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Arrays; +@AnnotationHelper.ApiDescription(info = "Internal use only. Subject to changes at any time.") public class GenChunk extends ScopedQueueCoordinator { public final Biome[] biomes; @@ -61,8 +63,14 @@ public class GenChunk extends ScopedQueueCoordinator { public int chunkZ; private ChunkData chunkData = null; - public GenChunk() { - super(null, Location.at("", 0, 0, 0), Location.at("", 15, 255, 15)); + /** + * @param minY minimum world Y, inclusive + * @param maxY maximum world Y, inclusive + * + * @since TODO + */ + public GenChunk(int minY, int maxY) { + super(null, Location.at("", 0, minY, 0), Location.at("", 15, maxY, 15)); this.biomes = Biome.values(); } @@ -117,7 +125,7 @@ public class GenChunk extends ScopedQueueCoordinator { return; } Biome biome = BukkitAdapter.adapt(biomeType); - for (int y = 0; y < 256; y++) { + for (int y = getMin().getY(); y <= getMax().getY(); y++) { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { this.biomeGrid.setBiome(x, y, z, biome); @@ -130,7 +138,7 @@ public class GenChunk extends ScopedQueueCoordinator { public void setCuboid(@NonNull Location pos1, @NonNull Location pos2, @NonNull BlockState block) { if (result != null && pos1.getX() == 0 && pos1.getZ() == 0 && pos2.getX() == 15 && pos2.getZ() == 15) { for (int y = pos1.getY(); y <= pos2.getY(); y++) { - int layer = y >> 4; + int layer = getLayerIndex(y); BlockState[] data = result[layer]; if (data == null) { result[layer] = data = new BlockState[4096]; @@ -164,7 +172,7 @@ public class GenChunk extends ScopedQueueCoordinator { */ public boolean setBiome(int x, int z, @NonNull Biome biome) { if (this.biomeGrid != null) { - for (int y = 0; y < 256; y++) { + for (int y = getMin().getY(); y <= getMax().getY(); y++) { this.setBiome(x, y, z, biome); } return true; @@ -197,7 +205,7 @@ public class GenChunk extends ScopedQueueCoordinator { } private void storeCache(final int x, final int y, final int z, final @NonNull BlockState id) { - int i = y >> 4; + int i = getLayerIndex(y); BlockState[] v = this.result[i]; if (v == null) { this.result[i] = v = new BlockState[4096]; @@ -219,7 +227,7 @@ public class GenChunk extends ScopedQueueCoordinator { @Override public @Nullable BlockState getBlock(int x, int y, int z) { - int i = y >> 4; + int i = getLayerIndex(y); if (result == null) { return BukkitBlockUtil.get(chunkData.getType(x, y, z)); } @@ -246,16 +254,16 @@ public class GenChunk extends ScopedQueueCoordinator { @Override public @NonNull Location getMax() { - return Location.at(getWorld().getName(), 15 + (getX() << 4), 255, 15 + (getZ() << 4)); + return Location.at(getWorld().getName(), 15 + (getX() << 4), super.getMax().getY(), 15 + (getZ() << 4)); } @Override public @NonNull Location getMin() { - return Location.at(getWorld().getName(), getX() << 4, 0, getZ() << 4); + return Location.at(getWorld().getName(), getX() << 4, super.getMin().getY(), getZ() << 4); } public @NonNull GenChunk clone() { - GenChunk toReturn = new GenChunk(); + GenChunk toReturn = new GenChunk(getMin().getY(), getMax().getY()); if (this.result != null) { for (int i = 0; i < this.result.length; i++) { BlockState[] matrix = this.result[i]; @@ -269,4 +277,8 @@ public class GenChunk extends ScopedQueueCoordinator { return toReturn; } + private int getLayerIndex(int y) { + return (y - getMin().getY()) >> 4; + } + } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java index 2e78b7508..74b5c1372 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java @@ -40,7 +40,6 @@ import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.RegionManager; -import com.plotsquared.core.util.RegionUtil; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.entity.EntityCategories; import com.plotsquared.core.util.task.RunnableVal; @@ -261,7 +260,7 @@ public class BukkitRegionManager extends RegionManager { if (checkX2 && checkZ2) { map.saveRegion(world, xxt2, xxt, zzt2, zzt); // } - CuboidRegion currentPlotClear = RegionUtil.createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ()); + CuboidRegion currentPlotClear = new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()); map.saveEntitiesOut(Bukkit.getWorld(world.getName()).getChunkAt(x, z), currentPlotClear); AugmentedUtils.bypass( ignoreAugment, @@ -276,7 +275,9 @@ public class BukkitRegionManager extends RegionManager { PlotLoc plotLoc = new PlotLoc(bx + x1, bz + z1); BaseBlock[] ids = map.allBlocks.get(plotLoc); if (ids != null) { - for (int y = 0; y < Math.min(128, ids.length); y++) { + int minY = value.getMin().getY(); + for (int yIndex = 0; yIndex < ids.length; yIndex++) { + int y = yIndex + minY; BaseBlock id = ids[y]; if (id != null) { value.setBlock(x1, y, z1, id); @@ -284,12 +285,6 @@ public class BukkitRegionManager extends RegionManager { value.setBlock(x1, y, z1, BlockTypes.AIR.getDefaultState()); } } - for (int y = Math.min(128, ids.length); y < ids.length; y++) { - BaseBlock id = ids[y]; - if (id != null) { - value.setBlock(x1, y, z1, id); - } - } } } } @@ -297,7 +292,7 @@ public class BukkitRegionManager extends RegionManager { }, world.getName(), chunk) ); //map.restoreBlocks(worldObj, 0, 0); - map.restoreEntities(Bukkit.getWorld(world.getName()), 0, 0); + map.restoreEntities(Bukkit.getWorld(world.getName())); }); regenQueue.setCompleteTask(whenDone); queue.setCompleteTask(regenQueue::enqueue); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java index 3a46fbb7d..73e9694da 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java @@ -44,7 +44,6 @@ import com.plotsquared.core.util.task.TaskManager; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockCategories; import com.sk89q.worldedit.world.block.BlockState; @@ -61,7 +60,6 @@ import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; @@ -246,7 +244,9 @@ public class BukkitUtil extends WorldUtil { final World bukkitWorld = Objects.requireNonNull(getWorld(world)); // Skip top and bottom block int air = 1; - for (int y = bukkitWorld.getMaxHeight() - 1; y >= 0; y--) { + int maxY = com.plotsquared.bukkit.util.BukkitWorld.getMaxWorldHeight(bukkitWorld); + int minY = com.plotsquared.bukkit.util.BukkitWorld.getMinWorldHeight(bukkitWorld); + for (int y = maxY - 1; y >= minY; y--) { Block block = bukkitWorld.getBlockAt(x, y, z); Material type = block.getType(); if (type.isSolid()) { @@ -273,7 +273,9 @@ public class BukkitUtil extends WorldUtil { final World bukkitWorld = Objects.requireNonNull(getWorld(world)); // Skip top and bottom block int air = 1; - for (int y = bukkitWorld.getMaxHeight() - 1; y >= 0; y--) { + int maxY = com.plotsquared.bukkit.util.BukkitWorld.getMaxWorldHeight(bukkitWorld); + int minY = com.plotsquared.bukkit.util.BukkitWorld.getMinWorldHeight(bukkitWorld); + for (int y = maxY - 1; y >= minY; y--) { Block block = bukkitWorld.getBlockAt(x, y, z); Material type = block.getType(); if (type.isSolid()) { @@ -371,7 +373,7 @@ public class BukkitUtil extends WorldUtil { sign.setLine(i, LEGACY_COMPONENT_SERIALIZER .serialize(MINI_MESSAGE.parse(lines[i].getComponent(LocaleHolder.console()), replacements))); } - sign.update(true); + sign.update(true, false); } }); } @@ -382,27 +384,6 @@ public class BukkitUtil extends WorldUtil { return new StringComparison().new ComparisonResult(1, state); } - @Override - public void setBiomes( - final @NonNull String worldName, - final @NonNull CuboidRegion region, - final @NonNull BiomeType biomeType - ) { - final World world = getWorld(worldName); - if (world == null) { - LOGGER.warn("An error occurred while setting the biome because the world was null", new RuntimeException()); - return; - } - final Biome biome = BukkitAdapter.adapt(biomeType); - for (int x = region.getMinimumPoint().getX(); x <= region.getMaximumPoint().getX(); x++) { - for (int z = region.getMinimumPoint().getZ(); z <= region.getMaximumPoint().getZ(); z++) { - if (world.getBiome(x, z) != biome) { - world.setBiome(x, z, biome); - } - } - } - } - @Override public com.sk89q.worldedit.world.@NonNull World getWeWorld(final @NonNull String world) { return new BukkitWorld(Bukkit.getWorld(world)); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitWorld.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitWorld.java index 38a343780..1f8045f7d 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitWorld.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitWorld.java @@ -36,6 +36,18 @@ import java.util.Objects; public class BukkitWorld implements World { private static final Map worldMap = Maps.newHashMap(); + private static final boolean HAS_MIN_Y; + + static { + boolean temp; + try { + org.bukkit.World.class.getMethod("getMinHeight"); + temp = true; + } catch (NoSuchMethodException e) { + temp = false; + } + HAS_MIN_Y = temp; + } private final org.bukkit.World world; @@ -73,6 +85,24 @@ public class BukkitWorld implements World { return bukkitWorld; } + /** + * Get the min world height from a Bukkit {@link org.bukkit.World}. Inclusive + * + * @since TODO + */ + public static int getMinWorldHeight(org.bukkit.World world) { + return HAS_MIN_Y ? world.getMinHeight() : 0; + } + + /** + * Get the max world height from a Bukkit {@link org.bukkit.World}. Exclusive + * + * @since TODO + */ + public static int getMaxWorldHeight(org.bukkit.World world) { + return HAS_MIN_Y ? world.getMaxHeight() : 256; + } + @Override public org.bukkit.World getPlatformWorld() { return this.world; @@ -83,6 +113,16 @@ public class BukkitWorld implements World { return this.world.getName(); } + @Override + public int getMinHeight() { + return getMinWorldHeight(world); + } + + @Override + public int getMaxHeight() { + return getMaxWorldHeight(world) - 1; + } + @Override public boolean equals(final Object o) { if (this == o) { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/ContentMap.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/ContentMap.java index 0fd8cdcbc..b4b63abcb 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/ContentMap.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/ContentMap.java @@ -70,7 +70,7 @@ public class ContentMap { } for (int x = x1; x <= x2; x++) { for (int z = z1; z <= z2; z++) { - saveBlocks(world, 256, x, z, 0, 0); + saveBlocks(world, x, z); } } } @@ -92,14 +92,7 @@ public class ContentMap { } } - void saveEntitiesIn(Chunk chunk, CuboidRegion region) { - saveEntitiesIn(chunk, region, 0, 0, false); - } - - void saveEntitiesIn( - Chunk chunk, CuboidRegion region, int offsetX, int offsetZ, - boolean delete - ) { + void saveEntitiesIn(Chunk chunk, CuboidRegion region, boolean delete) { for (Entity entity : chunk.getEntities()) { Location location = BukkitUtil.adapt(entity.getLocation()); int x = location.getX(); @@ -111,8 +104,6 @@ public class ContentMap { continue; } EntityWrapper wrap = new ReplicatingEntityWrapper(entity, (short) 2); - wrap.x += offsetX; - wrap.z += offsetZ; wrap.saveEntity(); this.entities.add(wrap); if (delete) { @@ -123,10 +114,10 @@ public class ContentMap { } } - void restoreEntities(World world, int xOffset, int zOffset) { + void restoreEntities(World world) { for (EntityWrapper entity : this.entities) { try { - entity.spawn(world, xOffset, zOffset); + entity.spawn(world, 0, 0); } catch (Exception e) { LOGGER.error("Failed to restore entity", e); } @@ -134,15 +125,13 @@ public class ContentMap { this.entities.clear(); } - //todo optimize maxY - void saveBlocks(BukkitWorld world, int maxY, int x, int z, int offsetX, int offsetZ) { - maxY = Math.min(255, maxY); - BaseBlock[] ids = new BaseBlock[maxY + 1]; - for (short y = 0; y <= maxY; y++) { - BaseBlock block = world.getFullBlock(BlockVector3.at(x, y, z)); - ids[y] = block; + private void saveBlocks(BukkitWorld world, int x, int z) { + BaseBlock[] ids = new BaseBlock[world.getMaxY() - world.getMinY() + 1]; + for (short yIndex = 0; yIndex <= world.getMaxY() - world.getMinY(); yIndex++) { + BaseBlock block = world.getFullBlock(BlockVector3.at(x, yIndex + world.getMinY(), z)); + ids[yIndex] = block; } - PlotLoc loc = new PlotLoc(x + offsetX, z + offsetZ); + PlotLoc loc = new PlotLoc(x, z); this.allBlocks.put(loc, ids); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/fawe/FaweRegionManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/fawe/FaweRegionManager.java index 2995db062..7c7cda737 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/fawe/FaweRegionManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/fawe/FaweRegionManager.java @@ -110,6 +110,11 @@ public class FaweRegionManager extends BukkitRegionManager { delegate.setBiome(region, extendBiome, biome, world, whenDone); } + @Override + public void setBiome(CuboidRegion region, int extendBiome, BiomeType biome, PlotArea area, Runnable whenDone) { + delegate.setBiome(region, extendBiome, biome, area.getWorldName(), whenDone); + } + @Override public boolean copyRegion( final @NonNull Location pos1, diff --git a/Core/src/main/java/com/plotsquared/core/PlotPlatform.java b/Core/src/main/java/com/plotsquared/core/PlotPlatform.java index 491431b6c..7788a21dc 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotPlatform.java +++ b/Core/src/main/java/com/plotsquared/core/PlotPlatform.java @@ -98,6 +98,22 @@ public interface PlotPlatform

extends LocaleHolder { */ int[] serverVersion(); + /** + * Gets the default minimum world height for the version of Minecraft that the server is running. + * + * @return minimum world height + * @since TODO + */ + int versionMinHeight(); + + /** + * Gets the default maximum world height for the version of Minecraft that the server is running. + * + * @return maximum world height (inclusive) + * @since TODO + */ + int versionMaxHeight(); + /** * Gets the server implementation name and version * diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index f72bab656..872d1bd68 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -1020,8 +1020,8 @@ public class PlotSquared { // save configuration final List validArguments = Arrays - .asList("s=", "size=", "g=", "gap=", "h=", "height=", "f=", "floor=", "m=", "main=", - "w=", "wall=", "b=", "border=" + .asList("s=", "size=", "g=", "gap=", "h=", "height=", "minh=", "minheight=", "maxh=", "maxheight=", + "f=", "floor=", "m=", "main=", "w=", "wall=", "b=", "border=" ); // Calculate the number of expected arguments @@ -1100,6 +1100,14 @@ public class PlotSquared { ConfigurationUtil.INTEGER.parseString(value).shortValue() ); } + case "minh", "minheight" -> this.worldConfiguration.set( + base + "world.min_gen_height", + ConfigurationUtil.INTEGER.parseString(value).shortValue() + ); + case "maxh", "maxheight" -> this.worldConfiguration.set( + base + "world.max_gen_height", + ConfigurationUtil.INTEGER.parseString(value).shortValue() + ); case "f", "floor" -> this.worldConfiguration.set( base + "plot.floor", ConfigurationUtil.BLOCK_BUCKET.parseString(value).toString() diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java index 0a966fd65..57552048d 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Area.java +++ b/Core/src/main/java/com/plotsquared/core/command/Area.java @@ -75,6 +75,7 @@ import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.World; import net.kyori.adventure.text.minimessage.Template; import org.checkerframework.checker.nullness.qual.NonNull; @@ -191,11 +192,12 @@ public class Area extends SubCommand { final BlockVector3 playerSelectionMin = playerSelectedRegion.getMinimumPoint(); final BlockVector3 playerSelectionMax = playerSelectedRegion.getMaximumPoint(); // Create a new selection that spans the entire vertical range of the world + World world = playerSelectedRegion.getWorld(); final CuboidRegion selectedRegion = new CuboidRegion( playerSelectedRegion.getWorld(), - BlockVector3.at(playerSelectionMin.getX(), 0, playerSelectionMin.getZ()), - BlockVector3.at(playerSelectionMax.getX(), 255, playerSelectionMax.getZ()) + BlockVector3.at(playerSelectionMin.getX(), world.getMinY(), playerSelectionMin.getZ()), + BlockVector3.at(playerSelectionMax.getX(), world.getMaxY(), playerSelectionMax.getZ()) ); // There's only one plot in the area... final PlotId plotId = PlotId.of(1, 1); @@ -278,9 +280,9 @@ public class Area extends SubCommand { if (offsetZ != 0) { this.worldConfiguration.set(path + ".road.offset.z", offsetZ); } - final String world = this.setupUtils.setupWorld(singleBuilder); - if (this.worldUtil.isWorld(world)) { - PlotSquared.get().loadWorld(world, null); + final String worldName = this.setupUtils.setupWorld(singleBuilder); + if (this.worldUtil.isWorld(worldName)) { + PlotSquared.get().loadWorld(worldName, null); player.sendMessage(TranslatableCaption.of("single.single_area_created")); } else { player.sendMessage( @@ -369,7 +371,8 @@ public class Area extends SubCommand { int lower = (area.ROAD_WIDTH & 1) == 0 ? area.ROAD_WIDTH / 2 - 1 : area.ROAD_WIDTH / 2; final int offsetX = bx - (area.ROAD_WIDTH == 0 ? 0 : lower); final int offsetZ = bz - (area.ROAD_WIDTH == 0 ? 0 : lower); - final CuboidRegion region = RegionUtil.createRegion(bx, tx, bz, tz); + // Height doesn't matter for this region + final CuboidRegion region = RegionUtil.createRegion(bx, tx, 0, 0, bz, tz); final Set areas = this.plotAreaManager.getPlotAreasSet(area.getWorldName(), region); if (!areas.isEmpty()) { player.sendMessage( diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugExec.java b/Core/src/main/java/com/plotsquared/core/command/DebugExec.java index 274f34cc8..d8ab55bd6 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugExec.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugExec.java @@ -49,6 +49,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.stream.Collectors; @@ -207,7 +208,7 @@ public class DebugExec extends SubCommand { } boolean result; if (HybridUtils.regions != null) { - result = this.hybridUtils.scheduleRoadUpdate(area, HybridUtils.regions, 0, new HashSet<>()); + result = this.hybridUtils.scheduleRoadUpdate(area, HybridUtils.regions, 0, new LinkedHashSet<>()); } else { result = this.hybridUtils.scheduleRoadUpdate(area, 0); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Save.java b/Core/src/main/java/com/plotsquared/core/command/Save.java index 311a2c72e..27c408e27 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Save.java +++ b/Core/src/main/java/com/plotsquared/core/command/Save.java @@ -104,8 +104,8 @@ public class Save extends SubCommand { TaskManager.runTaskAsync(() -> { String time = (System.currentTimeMillis() / 1000) + ""; Location[] corners = plot.getCorners(); - corners[0] = corners[0].withY(0); - corners[1] = corners[1].withY(255); + corners[0] = corners[0].withY(plot.getArea().getMinBuildHeight()); + corners[1] = corners[1].withY(plot.getArea().getMaxBuildHeight()); int size = (corners[1].getX() - corners[0].getX()) + 1; PlotId id = plot.getId(); String world1 = plot.getArea().toString().replaceAll(";", "-") diff --git a/Core/src/main/java/com/plotsquared/core/command/Trim.java b/Core/src/main/java/com/plotsquared/core/command/Trim.java index 01c7b8ff5..c31f020cd 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Trim.java +++ b/Core/src/main/java/com/plotsquared/core/command/Trim.java @@ -180,12 +180,12 @@ public class Trim extends SubCommand { int bx = cbx << 4; int bz = cbz << 4; CuboidRegion region = - RegionUtil.createRegion(bx, bx + 511, bz, bz + 511); + RegionUtil.createRegion(bx, bx + 511, 0, 0, bz, bz + 511); for (Plot plot : PlotQuery.newQuery().inWorld(world)) { Location bot = plot.getBottomAbs(); Location top = plot.getExtendedTopAbs(); CuboidRegion plotReg = RegionUtil - .createRegion(bot.getX(), top.getX(), bot.getZ(), top.getZ()); + .createRegion(bot.getX(), top.getX(), 0, 0, bot.getZ(), top.getZ()); if (!RegionUtil.intersects(region, plotReg)) { continue; } diff --git a/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java b/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java index 9b848e7b6..349d06b89 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java +++ b/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java @@ -70,7 +70,7 @@ public class AugmentedUtils { final int blockZ = chunkZ << 4; // Create a region that contains the // entire chunk - CuboidRegion region = RegionUtil.createRegion(blockX, blockX + 15, blockZ, blockZ + 15); + CuboidRegion region = RegionUtil.createRegion(blockX, blockX + 15, 0, 0, blockZ, blockZ + 15); // Query for plot areas in the chunk final Set areas = PlotSquared.get().getPlotAreaManager().getPlotAreasSet(world, region); if (areas.isEmpty()) { @@ -122,6 +122,7 @@ public class AugmentedUtils { } QueueCoordinator secondaryMask; BlockState air = BlockTypes.AIR.getDefaultState(); + int startYOffset = !(area instanceof ClassicPlotWorld) || ((ClassicPlotWorld) area).PLOT_BEDROCK ? 1 : 0; if (area.getTerrain() == PlotAreaTerrainType.ROAD) { PlotManager manager = area.getPlotManager(); final boolean[][] canPlace = new boolean[16][16]; @@ -132,7 +133,7 @@ public class AugmentedUtils { int worldZ = z + blockZ; boolean can = manager.getPlotId(worldX, 0, worldZ) == null; if (can) { - for (int y = 1; y < 128; y++) { + for (int y = area.getMinGenHeight() + startYOffset; y <= area.getMaxGenHeight(); y++) { queue.setBlock(worldX, y, worldZ, air); } canPlace[x][z] = true; @@ -149,7 +150,7 @@ public class AugmentedUtils { secondaryMask = primaryMask; for (int x = relativeBottomX; x <= relativeTopX; x++) { for (int z = relativeBottomZ; z <= relativeTopZ; z++) { - for (int y = 1; y < 128; y++) { + for (int y = area.getMinGenHeight() + startYOffset; y <= area.getMaxGenHeight(); y++) { queue.setBlock(blockX + x, y, blockZ + z, air); } } @@ -166,8 +167,8 @@ public class AugmentedUtils { ScopedQueueCoordinator scoped = new ScopedQueueCoordinator( secondaryMask, - Location.at(world, blockX, 0, blockZ), - Location.at(world, blockX + 15, 255, blockZ + 15) + Location.at(world, blockX, area.getMinGenHeight(), blockZ), + Location.at(world, blockX + 15, area.getMaxGenHeight(), blockZ + 15) ); generator.generateChunk(scoped, area); generator.populateChunk(scoped, area); diff --git a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java index e1e2ebfc8..7957ac912 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java +++ b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java @@ -37,7 +37,6 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotAreaTerrainType; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.queue.QueueCoordinator; -import com.plotsquared.core.util.BlockUtil; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.task.TaskManager; @@ -147,7 +146,15 @@ public class ClassicPlotManager extends SquarePlotManager { ) { Plot plot = classicPlotWorld.getPlotAbs(plotId); if (plot != null && plot.isBasePlot()) { - return this.regionManager.setCuboids(classicPlotWorld, plot.getRegions(), blocks, 1, getWorldHeight(), actor, queue); + return this.regionManager.setCuboids( + classicPlotWorld, + plot.getRegions(), + blocks, + classicPlotWorld.getMinBuildHeight(), + classicPlotWorld.getMaxBuildHeight(), + actor, + queue + ); } return false; } @@ -175,7 +182,7 @@ public class ClassicPlotManager extends SquarePlotManager { plot.getRegions(), blocks, classicPlotWorld.PLOT_HEIGHT + 1, - getWorldHeight(), + classicPlotWorld.getMaxBuildHeight(), actor, queue ); @@ -204,7 +211,7 @@ public class ClassicPlotManager extends SquarePlotManager { classicPlotWorld, plot.getRegions(), blocks, - 1, + classicPlotWorld.getMinBuildHeight(), classicPlotWorld.PLOT_HEIGHT - 1, actor, queue @@ -281,7 +288,7 @@ public class ClassicPlotManager extends SquarePlotManager { } } - int maxY = classicPlotWorld.getPlotManager().getWorldHeight(); + int maxY = classicPlotWorld.getMaxBuildHeight(); if (!plot.isMerged(Direction.NORTH)) { int z = bottom.getZ(); for (int x = bottom.getX(); x <= top.getX(); x++) { @@ -382,7 +389,7 @@ public class ClassicPlotManager extends SquarePlotManager { if (!plot.isMerged(Direction.NORTH)) { int z = bot.getZ(); for (int x = bot.getX(); x < top.getX(); x++) { - for (int y = 1; y <= classicPlotWorld.WALL_HEIGHT; y++) { + for (int y = classicPlotWorld.getMaxBuildHeight(); y <= classicPlotWorld.WALL_HEIGHT; y++) { queue.setBlock(x, y, z, blocks); } } @@ -390,7 +397,7 @@ public class ClassicPlotManager extends SquarePlotManager { if (!plot.isMerged(Direction.WEST)) { int x = bot.getX(); for (int z = bot.getZ(); z < top.getZ(); z++) { - for (int y = 1; y <= classicPlotWorld.WALL_HEIGHT; y++) { + for (int y = classicPlotWorld.getMinBuildHeight(); y <= classicPlotWorld.WALL_HEIGHT; y++) { queue.setBlock(x, y, z, blocks); } } @@ -398,7 +405,7 @@ public class ClassicPlotManager extends SquarePlotManager { if (!plot.isMerged(Direction.SOUTH)) { int z = top.getZ(); for (int x = bot.getX(); x < top.getX() + (plot.isMerged(Direction.EAST) ? 0 : 1); x++) { - for (int y = 1; y <= classicPlotWorld.WALL_HEIGHT; y++) { + for (int y = classicPlotWorld.getMinBuildHeight(); y <= classicPlotWorld.WALL_HEIGHT; y++) { queue.setBlock(x, y, z, blocks); } } @@ -406,7 +413,7 @@ public class ClassicPlotManager extends SquarePlotManager { if (!plot.isMerged(Direction.EAST)) { int x = top.getX(); for (int z = bot.getZ(); z < top.getZ() + (plot.isMerged(Direction.SOUTH) ? 0 : 1); z++) { - for (int y = 1; y <= classicPlotWorld.WALL_HEIGHT; y++) { + for (int y = classicPlotWorld.getMinBuildHeight(); y <= classicPlotWorld.WALL_HEIGHT; y++) { queue.setBlock(x, y, z, blocks); } } @@ -501,7 +508,7 @@ public class ClassicPlotManager extends SquarePlotManager { enqueue = true; } - int maxY = getWorldHeight(); + int maxY = classicPlotWorld.getMaxGenHeight(); queue.setCuboid( Location.at( classicPlotWorld.getWorldName(), @@ -513,27 +520,27 @@ public class ClassicPlotManager extends SquarePlotManager { ); if (classicPlotWorld.PLOT_BEDROCK) { queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx, 0, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex, 0, ez - 1), + Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.getMinGenHeight(), sz + 1), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getMinGenHeight(), ez - 1), BlockTypes.BEDROCK.getDefaultState() ); - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx, 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.WALL_HEIGHT, ez - 1), - classicPlotWorld.WALL_FILLING.toPattern() - ); - } else { - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx, 0, sz + 1), - Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.WALL_HEIGHT, ez - 1), - classicPlotWorld.WALL_FILLING.toPattern() - ); } + int startYOffset = classicPlotWorld.PLOT_BEDROCK ? 1 : 0; queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx, 1, sz + 1), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getMinGenHeight() + startYOffset, sz + 1), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.WALL_HEIGHT, ez - 1), + classicPlotWorld.WALL_FILLING.toPattern() + ); + queue.setCuboid( + Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.getMinGenHeight() + startYOffset, sz + 1), Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.WALL_HEIGHT, ez - 1), classicPlotWorld.WALL_FILLING.toPattern() ); + queue.setCuboid( + Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.getMinGenHeight() + startYOffset, sz + 1), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, ez - 1), + classicPlotWorld.ROAD_BLOCK.toPattern() + ); if (classicPlotWorld.PLACE_TOP_BLOCK) { queue.setCuboid( @@ -541,24 +548,12 @@ public class ClassicPlotManager extends SquarePlotManager { Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.WALL_HEIGHT + 1, ez - 1), classicPlotWorld.WALL_BLOCK.toPattern() ); - } - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), ex, 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.WALL_HEIGHT, ez - 1), - classicPlotWorld.WALL_FILLING.toPattern() - ); - if (classicPlotWorld.PLACE_TOP_BLOCK) { queue.setCuboid( Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.WALL_HEIGHT + 1, sz + 1), Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.WALL_HEIGHT + 1, ez - 1), classicPlotWorld.WALL_BLOCK.toPattern() ); } - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, ez - 1), - classicPlotWorld.ROAD_BLOCK.toPattern() - ); return !enqueue || queue.enqueue(); } @@ -584,19 +579,32 @@ public class ClassicPlotManager extends SquarePlotManager { classicPlotWorld.schematicStartHeight() + 1, sz ), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.getPlotManager().getWorldHeight(), ez), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.getMaxGenHeight(), ez), BlockTypes.AIR.getDefaultState() ); + if (classicPlotWorld.PLOT_BEDROCK) { + queue.setCuboid( + Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.getMinGenHeight(), sz), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.getMinGenHeight(), ez), + BlockTypes.BEDROCK.getDefaultState() + ); + } + int startYOffset = classicPlotWorld.PLOT_BEDROCK ? 1 : 0; queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, 0, sz), - Location.at(classicPlotWorld.getWorldName(), ex - 1, 0, ez), - BlockUtil.get((short) 7, (byte) 0) - ); - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, sz), + Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.getMinGenHeight() + startYOffset, sz), Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT, sz), classicPlotWorld.WALL_FILLING.toPattern() ); + queue.setCuboid( + Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.getMinGenHeight() + startYOffset, ez), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT, ez), + classicPlotWorld.WALL_FILLING.toPattern() + ); + queue.setCuboid( + Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.getMinGenHeight() + startYOffset, sz + 1), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, ez - 1), + classicPlotWorld.ROAD_BLOCK.toPattern() + ); if (classicPlotWorld.PLACE_TOP_BLOCK) { queue.setCuboid( @@ -604,24 +612,12 @@ public class ClassicPlotManager extends SquarePlotManager { Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT + 1, sz), classicPlotWorld.WALL_BLOCK.toPattern() ); - } - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, ez), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT, ez), - classicPlotWorld.WALL_FILLING.toPattern() - ); - if (classicPlotWorld.PLACE_TOP_BLOCK) { queue.setCuboid( Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.WALL_HEIGHT + 1, ez), Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT + 1, ez), classicPlotWorld.WALL_BLOCK.toPattern() ); } - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, ez - 1), - classicPlotWorld.ROAD_BLOCK.toPattern() - ); return !enqueue || queue.enqueue(); } @@ -642,14 +638,19 @@ public class ClassicPlotManager extends SquarePlotManager { queue.setCuboid( Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.ROAD_HEIGHT + 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.getPlotManager().getWorldHeight(), ez - 1), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.getMaxGenHeight(), ez - 1), BlockTypes.AIR.getDefaultState() ); - queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, 0, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex - 1, 0, ez - 1), BlockUtil.get((short) 7, (byte) 0) - ); + if (classicPlotWorld.PLOT_BEDROCK) { + queue.setCuboid( + Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.getMinGenHeight(), sz + 1), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.getMinGenHeight(), ez - 1), + BlockTypes.BEDROCK.getDefaultState() + ); + } + int startYOffset = classicPlotWorld.PLOT_BEDROCK ? 1 : 0; queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, sz + 1), + Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.getMinGenHeight() + startYOffset, sz + 1), Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, ez - 1), classicPlotWorld.ROAD_BLOCK.toPattern() ); @@ -679,11 +680,12 @@ public class ClassicPlotManager extends SquarePlotManager { classicPlotWorld.schematicStartHeight() + 1, sz ), - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getPlotManager().getWorldHeight(), ez), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getMaxGenHeight(), ez), BlockTypes.AIR.getDefaultState() ); + int startYOffset = classicPlotWorld.PLOT_BEDROCK ? 1 : 0; queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx, 1, sz + 1), + Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.getMinGenHeight() + startYOffset, sz + 1), Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT - 1, ez - 1), classicPlotWorld.MAIN_BLOCK.toPattern() ); @@ -719,11 +721,12 @@ public class ClassicPlotManager extends SquarePlotManager { classicPlotWorld.schematicStartHeight() + 1, sz ), - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getPlotManager().getWorldHeight(), ez), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getMaxGenHeight(), ez), BlockTypes.AIR.getDefaultState() ); + int startYOffset = classicPlotWorld.PLOT_BEDROCK ? 1 : 0; queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, sz), + Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.getMinGenHeight() + startYOffset, sz), Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.PLOT_HEIGHT - 1, ez), classicPlotWorld.MAIN_BLOCK.toPattern() ); @@ -758,11 +761,12 @@ public class ClassicPlotManager extends SquarePlotManager { classicPlotWorld.schematicStartHeight() + 1, sz ), - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getPlotManager().getWorldHeight(), ez), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getMaxGenHeight(), ez), BlockTypes.AIR.getDefaultState() ); + int startYOffset = classicPlotWorld.PLOT_BEDROCK ? 1 : 0; queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx, 1, sz), + Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.getMinGenHeight() + startYOffset, sz), Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT - 1, ez), classicPlotWorld.MAIN_BLOCK.toPattern() ); diff --git a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotWorld.java b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotWorld.java index 17db4a452..63d7afd02 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotWorld.java +++ b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotWorld.java @@ -127,16 +127,16 @@ public abstract class ClassicPlotWorld extends SquarePlotWorld { public void loadConfiguration(ConfigurationSection config) { super.loadConfiguration(config); this.PLOT_BEDROCK = config.getBoolean("plot.bedrock"); - this.PLOT_HEIGHT = Math.min(255, config.getInt("plot.height")); + this.PLOT_HEIGHT = Math.min(getMaxGenHeight(), config.getInt("plot.height")); this.MAIN_BLOCK = new BlockBucket(config.getString("plot.filling")); this.TOP_BLOCK = new BlockBucket(config.getString("plot.floor")); this.WALL_BLOCK = new BlockBucket(config.getString("wall.block")); - this.ROAD_HEIGHT = Math.min(255, config.getInt("road.height")); + this.ROAD_HEIGHT = Math.min(getMaxGenHeight(), config.getInt("road.height")); this.ROAD_BLOCK = new BlockBucket(config.getString("road.block")); this.WALL_FILLING = new BlockBucket(config.getString("wall.filling")); - this.WALL_HEIGHT = Math.min(254, config.getInt("wall.height")); - this.CLAIMED_WALL_BLOCK = new BlockBucket(config.getString("wall.block_claimed")); this.PLACE_TOP_BLOCK = config.getBoolean("wall.place_top_block"); + this.WALL_HEIGHT = Math.min(getMaxGenHeight() - (PLACE_TOP_BLOCK ? 1 : 0), config.getInt("wall.height")); + this.CLAIMED_WALL_BLOCK = new BlockBucket(config.getString("wall.block_claimed")); } int schematicStartHeight() { diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridGen.java b/Core/src/main/java/com/plotsquared/core/generator/HybridGen.java index 90bf16239..c9242a400 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridGen.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridGen.java @@ -91,7 +91,7 @@ public class HybridGen extends IndependentPlotGenerator { if (hybridPlotWorld.PLOT_BEDROCK) { for (short x = 0; x < 16; x++) { for (short z = 0; z < 16; z++) { - result.setBlock(x, 0, z, BlockTypes.BEDROCK.getDefaultState()); + result.setBlock(x, hybridPlotWorld.getMinGenHeight(), z, BlockTypes.BEDROCK.getDefaultState()); } } } @@ -156,7 +156,7 @@ public class HybridGen extends IndependentPlotGenerator { } } // generation - int startY = hybridPlotWorld.PLOT_BEDROCK ? 1 : 0; + int startY = hybridPlotWorld.getMinGenHeight() + (hybridPlotWorld.PLOT_BEDROCK ? 1: 0); for (short x = 0; x < 16; x++) { if (insideRoadX[x]) { for (short z = 0; z < 16; z++) { diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotManager.java b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotManager.java index 356858205..4fd62a40f 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotManager.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotManager.java @@ -46,7 +46,6 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -107,22 +106,32 @@ public class HybridPlotManager extends ClassicPlotManager { @Override public boolean createRoadEast(final @NonNull Plot plot, @Nullable QueueCoordinator queue) { + boolean enqueue = false; + if (queue == null) { + queue = hybridPlotWorld.getQueue(); + enqueue = true; + } super.createRoadEast(plot, queue); PlotId id = plot.getId(); PlotId id2 = PlotId.of(id.getX() + 1, id.getY()); Location bot = getPlotBottomLocAbs(id2); Location top = getPlotTopLocAbs(id); - Location pos1 = Location.at(hybridPlotWorld.getWorldName(), top.getX() + 1, 0, bot.getZ() - 1); - Location pos2 = Location.at(hybridPlotWorld.getWorldName(), bot.getX(), Math.min(getWorldHeight(), 255), top.getZ() + 1); + Location pos1 = Location.at( + hybridPlotWorld.getWorldName(), + top.getX() + 1, + hybridPlotWorld.getMinGenHeight(), + bot.getZ() - 1 + ); + Location pos2 = Location.at( + hybridPlotWorld.getWorldName(), + bot.getX(), + hybridPlotWorld.getMaxGenHeight(), + top.getZ() + 1 + ); this.resetBiome(hybridPlotWorld, pos1, pos2); if (!hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) { return true; } - boolean enqueue = false; - if (queue == null) { - queue = hybridPlotWorld.getQueue(); - enqueue = true; - } createSchemAbs(queue, pos1, pos2, true); return !enqueue || queue.enqueue(); } @@ -139,7 +148,7 @@ public class HybridPlotManager extends ClassicPlotManager { (pos1.getX() + pos2.getX()) / 2, (pos1.getZ() + pos2.getZ()) / 2 ), biome)) { - WorldUtil.setBiome(hybridPlotWorld.getWorldName(), pos1.getX(), pos1.getZ(), pos2.getX(), pos2.getZ(), biome); + WorldUtil.setBiome(hybridPlotWorld.getWorldName(), new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()), biome); } } @@ -190,38 +199,38 @@ public class HybridPlotManager extends ClassicPlotManager { @Override public boolean createRoadSouth(final @NonNull Plot plot, @Nullable QueueCoordinator queue) { + boolean enqueue = false; + if (queue == null) { + enqueue = true; + queue = hybridPlotWorld.getQueue(); + } super.createRoadSouth(plot, queue); PlotId id = plot.getId(); PlotId id2 = PlotId.of(id.getX(), id.getY() + 1); Location bot = getPlotBottomLocAbs(id2); Location top = getPlotTopLocAbs(id); - Location pos1 = Location.at(hybridPlotWorld.getWorldName(), bot.getX() - 1, 0, top.getZ() + 1); - Location pos2 = Location.at(hybridPlotWorld.getWorldName(), top.getX() + 1, Math.min(getWorldHeight(), 255), bot.getZ()); + Location pos1 = Location.at(hybridPlotWorld.getWorldName(), bot.getX() - 1, hybridPlotWorld.getMinGenHeight(), top.getZ() + 1); + Location pos2 = Location.at(hybridPlotWorld.getWorldName(), top.getX() + 1, hybridPlotWorld.getMaxGenHeight(), bot.getZ()); this.resetBiome(hybridPlotWorld, pos1, pos2); if (!hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) { return true; } - boolean enqueue = false; - if (queue == null) { - enqueue = true; - queue = hybridPlotWorld.getQueue(); - } createSchemAbs(queue, pos1, pos2, true); return !enqueue || queue.enqueue(); } @Override public boolean createRoadSouthEast(final @NonNull Plot plot, @Nullable QueueCoordinator queue) { - super.createRoadSouthEast(plot, queue); - PlotId id = plot.getId(); - PlotId id2 = PlotId.of(id.getX() + 1, id.getY() + 1); - Location pos1 = getPlotTopLocAbs(id).add(1, 0, 1).withY(0); - Location pos2 = getPlotBottomLocAbs(id2).withY(Math.min(getWorldHeight(), 255)); boolean enqueue = false; if (queue == null) { enqueue = true; queue = hybridPlotWorld.getQueue(); } + super.createRoadSouthEast(plot, queue); + PlotId id = plot.getId(); + PlotId id2 = PlotId.of(id.getX() + 1, id.getY() + 1); + Location pos1 = getPlotTopLocAbs(id).add(1, 0, 1); + Location pos2 = getPlotBottomLocAbs(id2); createSchemAbs(queue, pos1, pos2, true); if (hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) { createSchemAbs(queue, pos1, pos2, true); @@ -271,11 +280,23 @@ public class HybridPlotManager extends ClassicPlotManager { queue.setCompleteTask(whenDone); } if (!canRegen) { - queue.setCuboid(pos1.withY(0), pos2.withY(0), bedrock); + queue.setCuboid( + pos1.withY(hybridPlotWorld.getMinGenHeight()), + pos2.withY(hybridPlotWorld.getMinGenHeight()), + hybridPlotWorld.PLOT_BEDROCK ? bedrock : filling + ); // Each component has a different layer - queue.setCuboid(pos1.withY(1), pos2.withY(hybridPlotWorld.PLOT_HEIGHT - 1), filling); + queue.setCuboid( + pos1.withY(hybridPlotWorld.getMinGenHeight() + 1), + pos2.withY(hybridPlotWorld.PLOT_HEIGHT - 1), + filling + ); queue.setCuboid(pos1.withY(hybridPlotWorld.PLOT_HEIGHT), pos2.withY(hybridPlotWorld.PLOT_HEIGHT), plotfloor); - queue.setCuboid(pos1.withY(hybridPlotWorld.PLOT_HEIGHT + 1), pos2.withY(getWorldHeight()), BlockTypes.AIR.getDefaultState()); + queue.setCuboid( + pos1.withY(hybridPlotWorld.PLOT_HEIGHT + 1), + pos2.withY(hybridPlotWorld.getMaxGenHeight()), + BlockTypes.AIR.getDefaultState() + ); queue.setBiomeCuboid(pos1, pos2, biome); } else { queue.setRegenRegion(new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3())); diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java index 2b6945c61..815972ee0 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java @@ -79,6 +79,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { public int SCHEM_Y; private Location SIGN_LOCATION; private File root = null; + private int lastOverlayHeightError = Integer.MIN_VALUE; @Inject private SchematicHandler schematicHandler; @@ -171,9 +172,9 @@ public class HybridPlotWorld extends ClassicPlotWorld { public void loadConfiguration(ConfigurationSection config) { super.loadConfiguration(config); if ((this.ROAD_WIDTH & 1) == 0) { - this.PATH_WIDTH_LOWER = (short) (Math.floor(this.ROAD_WIDTH / 2) - 1); + this.PATH_WIDTH_LOWER = (short) (Math.floor(this.ROAD_WIDTH / 2f) - 1); } else { - this.PATH_WIDTH_LOWER = (short) Math.floor(this.ROAD_WIDTH / 2); + this.PATH_WIDTH_LOWER = (short) Math.floor(this.ROAD_WIDTH / 2f); } if (this.ROAD_WIDTH == 0) { this.PATH_WIDTH_UPPER = (short) (this.SIZE + 1); @@ -251,31 +252,34 @@ public class HybridPlotWorld extends ClassicPlotWorld { Schematic schematic2 = this.schematicHandler.getSchematic(schematic2File); Schematic schematic3 = this.schematicHandler.getSchematic(schematic3File); int shift = this.ROAD_WIDTH / 2; - int oddshift = (this.ROAD_WIDTH & 1) == 0 ? 0 : 1; + int oddshift = (this.ROAD_WIDTH & 1); SCHEM_Y = schematicStartHeight(); int plotY = PLOT_HEIGHT - SCHEM_Y; int minRoadWall = Settings.Schematics.USE_WALL_IN_ROAD_SCHEM_HEIGHT ? Math.min(ROAD_HEIGHT, WALL_HEIGHT) : ROAD_HEIGHT; int roadY = minRoadWall - SCHEM_Y; + int worldHeight = getMaxGenHeight() - getMinGenHeight() + 1; + + // SCHEM_Y should be normalised to the plot "start" height if (schematic3 != null) { - if (schematic3.getClipboard().getDimensions().getY() == 256) { + if (schematic3.getClipboard().getDimensions().getY() == worldHeight) { SCHEM_Y = plotY = 0; } else if (!Settings.Schematics.PASTE_ON_TOP) { - SCHEM_Y = plotY = getMinBuildHeight(); + SCHEM_Y = plotY = getMinBuildHeight() - getMinGenHeight(); } } if (schematic1 != null) { - if (schematic1.getClipboard().getDimensions().getY() == 256) { - SCHEM_Y = roadY = 0; - if (schematic3 != null && schematic3.getClipboard().getDimensions().getY() != 256 + if (schematic1.getClipboard().getDimensions().getY() == worldHeight) { + SCHEM_Y = roadY = getMinGenHeight(); + if (schematic3 != null && schematic3.getClipboard().getDimensions().getY() != worldHeight && !Settings.Schematics.PASTE_ON_TOP) { plotY = PLOT_HEIGHT; } } else if (!Settings.Schematics.PASTE_ROAD_ON_TOP) { SCHEM_Y = roadY = getMinBuildHeight(); - if (schematic3 != null && schematic3.getClipboard().getDimensions().getY() != 256 + if (schematic3 != null && schematic3.getClipboard().getDimensions().getY() != worldHeight && !Settings.Schematics.PASTE_ON_TOP) { plotY = PLOT_HEIGHT; } @@ -428,7 +432,10 @@ public class HybridPlotWorld extends ClassicPlotWorld { int pair = MathMan.pair(x, z); BaseBlock[] existing = this.G_SCH.computeIfAbsent(pair, k -> new BaseBlock[height]); if (y >= height) { - LOGGER.error("Error adding overlay block. `y > height`"); + if (y != lastOverlayHeightError) { + lastOverlayHeightError = y; + LOGGER.error(String.format("Error adding overlay block. `y > height`. y=%s, height=%s", y, height)); + } return; } existing[y] = id; diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java b/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java index ebb119775..41920f58b 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java @@ -65,6 +65,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import java.io.File; import java.util.ArrayDeque; @@ -73,6 +74,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -85,7 +87,9 @@ public class HybridUtils { public static HybridUtils manager; public static Set regions; public static int height; - public static Set chunks = new HashSet<>(); + // Use ordered for reasonable chunk loading order to reduce paper unloading neighbour chunks and then us attempting to load + // them again, causing errors + public static Set chunks = new LinkedHashSet<>(); public static PlotArea area; public static boolean UPDATE = false; @@ -145,6 +149,8 @@ public class HybridUtils { final int ctz = tz >> 4; final int width = tx - bx + 1; final int length = tz - bz + 1; + final int height = area.getMaxGenHeight() - area.getMinGenHeight() + 1; + final int minHeight = area.getMinGenHeight(); final PlotArea area = this.plotAreaManager.getPlotArea(world, null); @@ -157,7 +163,7 @@ public class HybridUtils { final BlockState airBlock = BlockTypes.AIR.getDefaultState(); final BlockState[][][] oldBlocks = chunk.getBlocks(); - final BlockState[][][] newBlocks = new BlockState[256][width][length]; + final BlockState[][][] newBlocks = new BlockState[height][width][length]; for (final BlockState[][] newBlock : newBlocks) { for (final BlockState[] blockStates : newBlock) { Arrays.fill(blockStates, airBlock); @@ -211,11 +217,12 @@ public class HybridUtils { int xx = chunkBlockX + x; for (int z = minZ; z <= maxZ; z++) { int zz = chunkBlockZ + z; - for (int y = 0; y < 256; y++) { + for (int yIndex = 0; yIndex < height; yIndex++) { + int y = yIndex + minHeight; BlockState block = queue.getBlock(xx, y, zz); int xr = xb + x; int zr = zb + z; - newBlocks[y][xr][zr] = block; + newBlocks[yIndex][xr][zr] = block; } } } @@ -232,10 +239,10 @@ public class HybridUtils { for (int x = 0; x < width; x++) { for (int z = 0; z < length; z++) { Set types = new HashSet<>(); - for (int y = 0; y < 256; y++) { - BlockState old = oldBlocks[y][x][z]; + for (int yIndex = 0; yIndex < height; yIndex++) { + BlockState old = oldBlocks[yIndex][x][z]; try { - BlockState now = newBlocks[y][x][z]; + BlockState now = newBlocks[yIndex][x][z]; if (!old.equals(now)) { changes[i]++; } @@ -244,23 +251,23 @@ public class HybridUtils { } else { // check vertices // modifications_adjacent - if (x > 0 && z > 0 && y > 0 && x < width - 1 && z < length - 1 && y < 255) { - if (newBlocks[y - 1][x][z].getBlockType().getMaterial().isAir()) { + if (x > 0 && z > 0 && yIndex > 0 && x < width - 1 && z < length - 1 && yIndex < (height - 1)) { + if (newBlocks[yIndex - 1][x][z].getBlockType().getMaterial().isAir()) { faces[i]++; } - if (newBlocks[y][x - 1][z].getBlockType().getMaterial().isAir()) { + if (newBlocks[yIndex][x - 1][z].getBlockType().getMaterial().isAir()) { faces[i]++; } - if (newBlocks[y][x][z - 1].getBlockType().getMaterial().isAir()) { + if (newBlocks[yIndex][x][z - 1].getBlockType().getMaterial().isAir()) { faces[i]++; } - if (newBlocks[y + 1][x][z].getBlockType().getMaterial().isAir()) { + if (newBlocks[yIndex + 1][x][z].getBlockType().getMaterial().isAir()) { faces[i]++; } - if (newBlocks[y][x + 1][z].getBlockType().getMaterial().isAir()) { + if (newBlocks[yIndex][x + 1][z].getBlockType().getMaterial().isAir()) { faces[i]++; } - if (newBlocks[y][x][z + 1].getBlockType().getMaterial().isAir()) { + if (newBlocks[yIndex][x][z + 1].getBlockType().getMaterial().isAir()) { faces[i]++; } } @@ -408,7 +415,7 @@ public class HybridUtils { } HybridUtils.UPDATE = true; Set regions = this.worldUtil.getChunkChunks(area.getWorldName()); - return scheduleRoadUpdate(area, regions, extend, new HashSet<>()); + return scheduleRoadUpdate(area, regions, extend, new LinkedHashSet<>()); } public boolean scheduleSingleRegionRoadUpdate(Plot plot, int extend) { @@ -418,7 +425,7 @@ public class HybridUtils { HybridUtils.UPDATE = true; Set regions = new HashSet<>(); regions.add(RegionManager.getRegion(plot.getCenterSynchronous())); - return scheduleRoadUpdate(plot.getArea(), regions, extend, new HashSet<>()); + return scheduleRoadUpdate(plot.getArea(), regions, extend, new LinkedHashSet<>()); } public boolean scheduleRoadUpdate( @@ -431,26 +438,29 @@ public class HybridUtils { HybridUtils.area = area; HybridUtils.height = extend; HybridUtils.chunks = chunks; + final int initial = 1024 * regions.size() + chunks.size(); final AtomicInteger count = new AtomicInteger(0); TaskManager.runTask(new Runnable() { @Override public void run() { if (!UPDATE) { Iterator iter = chunks.iterator(); + QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName())); while (iter.hasNext()) { BlockVector2 chunk = iter.next(); iter.remove(); - boolean regenedRoad = regenerateRoad(area, chunk, extend); + boolean regenedRoad = regenerateRoad(area, chunk, extend, queue); if (!regenedRoad) { - LOGGER.info("Failed to regenerate roads"); + LOGGER.info("Failed to regenerate roads in chunk {}", chunk); } } + queue.enqueue(); LOGGER.info("Cancelled road task"); return; } count.incrementAndGet(); - if (count.intValue() % 20 == 0) { - LOGGER.info("Progress: {}%", 100 * (2048 - chunks.size()) / 2048); + if (count.intValue() % 10 == 0) { + LOGGER.info("Progress: {}%", 100 * (initial - (chunks.size() + 1024 * regions.size())) / initial); } if (HybridUtils.regions.isEmpty() && chunks.isEmpty()) { regeneratePlotWalls(area); @@ -462,7 +472,7 @@ public class HybridUtils { final Runnable task = this; TaskManager.runTaskAsync(() -> { try { - if (chunks.size() < 1024) { + if (chunks.size() < 64) { if (!HybridUtils.regions.isEmpty()) { Iterator iterator = HybridUtils.regions.iterator(); BlockVector2 loc = iterator.next(); @@ -475,18 +485,35 @@ public class HybridUtils { } if (!chunks.isEmpty()) { TaskManager.getPlatformImplementation().sync(() -> { - long start = System.currentTimeMillis(); Iterator iterator = chunks.iterator(); - while (System.currentTimeMillis() - start < 20 && !chunks.isEmpty()) { + if (chunks.size() >= 32) { + QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName())); + for (int i = 0; i < 32; i++) { + final BlockVector2 chunk = iterator.next(); + iterator.remove(); + boolean regenedRoads = regenerateRoad(area, chunk, extend, queue); + if (!regenedRoads) { + LOGGER.info("Failed to regenerate the road in chunk {}", chunk); + } + } + queue.setCompleteTask(task); + queue.enqueue(); + return null; + } + QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName())); + while (!chunks.isEmpty()) { final BlockVector2 chunk = iterator.next(); iterator.remove(); - boolean regenedRoads = regenerateRoad(area, chunk, extend); + boolean regenedRoads = regenerateRoad(area, chunk, extend, queue); if (!regenedRoads) { - LOGGER.info("Failed to regenerate road"); + LOGGER.info("Failed to regenerate road in chunk {}", chunk); } } + queue.setCompleteTask(task); + queue.enqueue(); return null; }); + return; } } catch (Exception e) { e.printStackTrace(); @@ -514,7 +541,6 @@ public class HybridUtils { Location bot = plot.getBottomAbs().subtract(1, 0, 1); Location top = plot.getTopAbs(); final HybridPlotWorld plotworld = (HybridPlotWorld) plot.getArea(); - PlotManager plotManager = plotworld.getPlotManager(); // Do not use plotworld#schematicStartHeight() here as we want to restore the pre 6.1.4 way of doing it if // USE_WALL_IN_ROAD_SCHEM_HEIGHT is false int schemY = Settings.Schematics.USE_WALL_IN_ROAD_SCHEM_HEIGHT ? @@ -524,10 +550,10 @@ public class HybridUtils { int sy = Settings.Schematics.PASTE_ROAD_ON_TOP ? schemY : plot.getArea().getMinBuildHeight(); int ex = bot.getX(); int ez = top.getZ(); - int ey = get_ey(plotManager, queue, sx, ex, sz, ez, sy); + int ey = get_ey(plotworld, queue, sx, ex, sz, ez, sy); int bz = sz - plotworld.ROAD_WIDTH; int tz = sz - 1; - int ty = get_ey(plotManager, queue, sx, ex, bz, tz, sy); + int ty = get_ey(plotworld, queue, sx, ex, bz, tz, sy); final Set sideRoad = Collections.singleton(RegionUtil.createRegion(sx, ex, sy, ey, sz, ez)); final Set intersection = Collections.singleton(RegionUtil.createRegion(sx, ex, sy, ty, bz, tz)); @@ -553,11 +579,11 @@ public class HybridUtils { return true; } - public int get_ey(final PlotManager pm, QueueCoordinator queue, int sx, int ex, int sz, int ez, int sy) { + private int get_ey(final HybridPlotWorld hpw, QueueCoordinator queue, int sx, int ex, int sz, int ez, int sy) { int ey = sy; for (int x = sx; x <= ex; x++) { for (int z = sz; z <= ez; z++) { - for (int y = sy; y <= pm.getWorldHeight(); y++) { + for (int y = sy; y <= hpw.getMaxGenHeight(); y++) { if (y > ey) { BlockState block = queue.getBlock(x, y, z); if (!block.getBlockType().getMaterial().isAir()) { @@ -570,7 +596,36 @@ public class HybridUtils { return ey; } + /** + * Regenerate the road in a chunk in a plot area. + * + * @param area Plot area to regenerate road for + * @param chunk Chunk location to regenerate + * @param extend How far to extend setting air above the road + * @return if successful + * @deprecated use {@link HybridUtils#regenerateRoad(PlotArea, BlockVector2, int, QueueCoordinator)} + */ + @Deprecated(forRemoval = true, since = "TODO") public boolean regenerateRoad(final PlotArea area, final BlockVector2 chunk, int extend) { + return regenerateRoad(area, chunk, extend, null); + } + + /** + * Regenerate the road in a chunk in a plot area. + * + * @param area Plot area to regenerate road for + * @param chunk Chunk location to regenerate + * @param extend How far to extend setting air above the road + * @param queueCoordinator {@link QueueCoordinator} to use to set the blocks. Null if one should be created and enqueued + * @return if successful + * @since TODO + */ + public boolean regenerateRoad( + final PlotArea area, + final BlockVector2 chunk, + int extend, + @Nullable QueueCoordinator queueCoordinator + ) { int x = chunk.getX() << 4; int z = chunk.getZ() << 4; int ex = x + 15; @@ -596,92 +651,100 @@ public class HybridUtils { z -= plotWorld.ROAD_OFFSET_Z; final int finalX = x; final int finalZ = z; - QueueCoordinator queue = this.blockQueue.getNewQueue(worldUtil.getWeWorld(plotWorld.getWorldName())); + final boolean enqueue; + final QueueCoordinator queue; + if (queueCoordinator == null) { + queue = this.blockQueue.getNewQueue(worldUtil.getWeWorld(plotWorld.getWorldName())); + enqueue = true; + } else { + queue = queueCoordinator; + enqueue = false; + } if (id1 == null || id2 == null || id1 != id2) { - this.chunkManager.loadChunk(area.getWorldName(), chunk, false).thenRun(() -> { - if (id1 != null) { - Plot p1 = area.getPlotAbs(id1); - if (p1 != null && p1.hasOwner() && p1.isMerged()) { - toCheck.set(true); - } + if (id1 != null) { + Plot p1 = area.getPlotAbs(id1); + if (p1 != null && p1.hasOwner() && p1.isMerged()) { + toCheck.set(true); } - if (id2 != null && !toCheck.get()) { - Plot p2 = area.getPlotAbs(id2); - if (p2 != null && p2.hasOwner() && p2.isMerged()) { - toCheck.set(true); - } + } + if (id2 != null && !toCheck.get()) { + Plot p2 = area.getPlotAbs(id2); + if (p2 != null && p2.hasOwner() && p2.isMerged()) { + toCheck.set(true); } - int size = plotWorld.SIZE; - for (int X = 0; X < 16; X++) { - short absX = (short) ((finalX + X) % size); - for (int Z = 0; Z < 16; Z++) { - short absZ = (short) ((finalZ + Z) % size); - if (absX < 0) { - absX += size; - } - if (absZ < 0) { - absZ += size; - } - boolean condition; - if (toCheck.get()) { - condition = manager.getPlotId( - finalX + X + plotWorld.ROAD_OFFSET_X, - 1, - finalZ + Z + plotWorld.ROAD_OFFSET_Z - ) == null; - } else { - boolean gx = absX > plotWorld.PATH_WIDTH_LOWER; - boolean gz = absZ > plotWorld.PATH_WIDTH_LOWER; - boolean lx = absX < plotWorld.PATH_WIDTH_UPPER; - boolean lz = absZ < plotWorld.PATH_WIDTH_UPPER; - condition = !gx || !gz || !lx || !lz; - } - if (condition) { - BaseBlock[] blocks = plotWorld.G_SCH.get(MathMan.pair(absX, absZ)); - int minY = Settings.Schematics.PASTE_ROAD_ON_TOP ? plotWorld.SCHEM_Y : 1; - int maxY = Math.max(extend, blocks.length); - for (int y = 0; y < maxY; y++) { - if (y > blocks.length - 1) { + } + short size = plotWorld.SIZE; + for (int X = 0; X < 16; X++) { + short absX = (short) ((finalX + X) % size); + for (int Z = 0; Z < 16; Z++) { + short absZ = (short) ((finalZ + Z) % size); + if (absX < 0) { + absX += size; + } + if (absZ < 0) { + absZ += size; + } + boolean condition; + if (toCheck.get()) { + condition = manager.getPlotId( + finalX + X + plotWorld.ROAD_OFFSET_X, + 1, + finalZ + Z + plotWorld.ROAD_OFFSET_Z + ) == null; + } else { + boolean gx = absX > plotWorld.PATH_WIDTH_LOWER; + boolean gz = absZ > plotWorld.PATH_WIDTH_LOWER; + boolean lx = absX < plotWorld.PATH_WIDTH_UPPER; + boolean lz = absZ < plotWorld.PATH_WIDTH_UPPER; + condition = !gx || !gz || !lx || !lz; + } + if (condition) { + BaseBlock[] blocks = plotWorld.G_SCH.get(MathMan.pair(absX, absZ)); + int minY = Settings.Schematics.PASTE_ROAD_ON_TOP ? plotWorld.SCHEM_Y : area.getMinGenHeight() + 1; + int maxDy = Math.max(extend, blocks.length); + for (int dy = 0; dy < maxDy; dy++) { + if (dy > blocks.length - 1) { + queue.setBlock( + finalX + X + plotWorld.ROAD_OFFSET_X, + minY + dy, + finalZ + Z + plotWorld.ROAD_OFFSET_Z, + WEExtent.AIRBASE + ); + } else { + BaseBlock block = blocks[dy]; + if (block != null) { queue.setBlock( finalX + X + plotWorld.ROAD_OFFSET_X, - minY + y, + minY + dy, + finalZ + Z + plotWorld.ROAD_OFFSET_Z, + block + ); + } else { + queue.setBlock( + finalX + X + plotWorld.ROAD_OFFSET_X, + minY + dy, finalZ + Z + plotWorld.ROAD_OFFSET_Z, WEExtent.AIRBASE ); - } else { - BaseBlock block = blocks[y]; - if (block != null) { - queue.setBlock( - finalX + X + plotWorld.ROAD_OFFSET_X, - minY + y, - finalZ + Z + plotWorld.ROAD_OFFSET_Z, - block - ); - } else { - queue.setBlock( - finalX + X + plotWorld.ROAD_OFFSET_X, - minY + y, - finalZ + Z + plotWorld.ROAD_OFFSET_Z, - WEExtent.AIRBASE - ); - } } } - BiomeType biome = plotWorld.G_SCH_B.get(MathMan.pair(absX, absZ)); - if (biome != null) { - queue.setBiome(finalX + X + plotWorld.ROAD_OFFSET_X, finalZ + Z + plotWorld.ROAD_OFFSET_Z, biome); - } else { - queue.setBiome( - finalX + X + plotWorld.ROAD_OFFSET_X, - finalZ + Z + plotWorld.ROAD_OFFSET_Z, - plotWorld.getPlotBiome() - ); - } + } + BiomeType biome = plotWorld.G_SCH_B.get(MathMan.pair(absX, absZ)); + if (biome != null) { + queue.setBiome(finalX + X + plotWorld.ROAD_OFFSET_X, finalZ + Z + plotWorld.ROAD_OFFSET_Z, biome); + } else { + queue.setBiome( + finalX + X + plotWorld.ROAD_OFFSET_X, + finalZ + Z + plotWorld.ROAD_OFFSET_Z, + plotWorld.getPlotBiome() + ); } } } + } + if (enqueue) { queue.enqueue(); - }); + } return true; } return false; diff --git a/Core/src/main/java/com/plotsquared/core/generator/SquarePlotManager.java b/Core/src/main/java/com/plotsquared/core/generator/SquarePlotManager.java index 28ebbeed7..1fff887ef 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/SquarePlotManager.java +++ b/Core/src/main/java/com/plotsquared/core/generator/SquarePlotManager.java @@ -96,7 +96,7 @@ public abstract class SquarePlotManager extends GridPlotManager { .floor(squarePlotWorld.ROAD_WIDTH / 2) - 1; int z = (squarePlotWorld.ROAD_OFFSET_Z + (pz * (squarePlotWorld.ROAD_WIDTH + squarePlotWorld.PLOT_WIDTH))) - (int) Math .floor(squarePlotWorld.ROAD_WIDTH / 2) - 1; - return Location.at(squarePlotWorld.getWorldName(), x, Math.min(getWorldHeight(), 255), z); + return Location.at(squarePlotWorld.getWorldName(), x, squarePlotWorld.getMaxGenHeight(), z); } @Override @@ -260,7 +260,7 @@ public abstract class SquarePlotManager extends GridPlotManager { - (int) Math.floor(squarePlotWorld.ROAD_WIDTH / 2); int z = (squarePlotWorld.ROAD_OFFSET_Z + (pz * (squarePlotWorld.ROAD_WIDTH + squarePlotWorld.PLOT_WIDTH))) - squarePlotWorld.PLOT_WIDTH - (int) Math.floor(squarePlotWorld.ROAD_WIDTH / 2); - return Location.at(squarePlotWorld.getWorldName(), x, squarePlotWorld.getMinBuildHeight(), z); + return Location.at(squarePlotWorld.getWorldName(), x, squarePlotWorld.getMinGenHeight(), z); } } diff --git a/Core/src/main/java/com/plotsquared/core/location/World.java b/Core/src/main/java/com/plotsquared/core/location/World.java index 6e1c0a5ed..4473fd1a7 100644 --- a/Core/src/main/java/com/plotsquared/core/location/World.java +++ b/Core/src/main/java/com/plotsquared/core/location/World.java @@ -58,6 +58,21 @@ public interface World { */ @NonNull String getName(); + /** + * Get the min world height. Inclusive. + * + * @since TODO + */ + int getMinHeight(); + + + /** + * Get the max world height. Inclusive. + * + * @since TODO + */ + int getMaxHeight(); + class NullWorld implements World { private NullWorld() { @@ -74,6 +89,16 @@ public interface World { return ""; } + @Override + public int getMinHeight() { + return 0; + } + + @Override + public int getMaxHeight() { + return 0; + } + @Override public boolean equals(final Object obj) { return obj instanceof NullWorld; diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 620ed9e58..bb552e789 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -122,7 +122,7 @@ import static com.plotsquared.core.util.entity.EntityCategories.CAP_VEHICLE; */ public class Plot { - + @Deprecated(forRemoval = true, since = "TODO") public static final int MAX_HEIGHT = 256; private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + Plot.class.getSimpleName()); @@ -1371,7 +1371,7 @@ public class Plot { int z = largest.getMinimumPoint().getZ() - 1; PlotManager manager = getManager(); int y = isLoaded() ? this.worldUtil.getHighestBlockSynchronous(getWorldName(), x, z) : 62; - if (area.allowSigns() && (y <= 0 || y >= 255)) { + if (area.allowSigns() && (y <= area.getMinGenHeight() || y >= area.getMaxGenHeight())) { y = Math.max(y, manager.getSignLoc(this).getY() - 1); } return Location.at(getWorldName(), x, y + 1, z); @@ -1387,7 +1387,7 @@ public class Plot { if (isLoaded()) { this.worldUtil.getHighestBlock(getWorldName(), x, z, y -> { int height = y; - if (area.allowSigns() && (y <= 0 || y >= 255)) { + if (area.allowSigns() && (y <= area.getMinGenHeight() || y >= area.getMaxGenHeight())) { height = Math.max(y, manager.getSignLoc(this).getY() - 1); } result.accept(Location.at(getWorldName(), x, height + 1, z)); @@ -1619,8 +1619,8 @@ public class Plot { public double getVolume() { double count = 0; for (CuboidRegion region : getRegions()) { - count += (region.getMaximumPoint().getX() - (double) region.getMinimumPoint().getX() + 1) * ( - region.getMaximumPoint().getZ() - (double) region.getMinimumPoint().getZ() + 1) * MAX_HEIGHT; + // CuboidRegion#getArea is deprecated and we want to ensure use of correct height + count += region.getLength() * region.getWidth() * (area.getMaxGenHeight() - area.getMinGenHeight() + 1); } return count; } @@ -1738,7 +1738,6 @@ public class Plot { area.addPlot(this); updateWorldBorder(); } - this.getPlotModificationManager().setSign(player.getName()); player.sendMessage(TranslatableCaption.of("working.claimed"), Template.of("plot", this.getId().toString())); if (teleport) { if (!auto && Settings.Teleport.ON_CLAIM) { @@ -1786,6 +1785,7 @@ public class Plot { ); } plotworld.getPlotManager().claimPlot(this, null); + this.getPlotModificationManager().setSign(player.getName()); return true; } @@ -2438,8 +2438,8 @@ public class Plot { return regions_cache; } if (!this.isMerged()) { - Location pos1 = this.getBottomAbs(); - Location pos2 = this.getTopAbs(); + Location pos1 = this.getBottomAbs().withY(getArea().getMinBuildHeight()); + Location pos2 = this.getTopAbs().withY(getArea().getMaxBuildHeight()); connected_cache = Sets.newHashSet(this); CuboidRegion rg = new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()); regions_cache = Collections.singleton(rg); diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java index 470ff2820..378882012 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java @@ -34,8 +34,6 @@ import com.plotsquared.core.configuration.ConfigurationNode; import com.plotsquared.core.configuration.ConfigurationSection; import com.plotsquared.core.configuration.ConfigurationUtil; import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.configuration.caption.CaptionUtility; -import com.plotsquared.core.configuration.caption.LocaleHolder; import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.configuration.file.YamlConfiguration; import com.plotsquared.core.generator.GridPlotWorld; @@ -54,7 +52,6 @@ import com.plotsquared.core.plot.flag.FlagParseException; import com.plotsquared.core.plot.flag.GlobalFlagContainer; import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.plot.flag.implementations.DoneFlag; -import com.plotsquared.core.plot.flag.types.DoubleFlag; import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.MathMan; @@ -144,8 +141,10 @@ public abstract class PlotArea { private boolean homeAllowNonmember = false; private BlockLoc nonmemberHome; private BlockLoc defaultHome; - private int maxBuildHeight = 256; - private int minBuildHeight = 1; + private int maxBuildHeight = PlotSquared.platform().versionMaxHeight() + 1; // Exclusive + private int minBuildHeight = PlotSquared.platform().versionMinHeight() + 1; // Inclusive + private int maxGenHeight = PlotSquared.platform().versionMaxHeight(); // Inclusive + private int minGenHeight = PlotSquared.platform().versionMinHeight(); // Inclusive private GameMode gameMode = GameModes.CREATIVE; private Map prices = new HashMap<>(); private List schematics = new ArrayList<>(); @@ -361,6 +360,8 @@ public abstract class PlotArea { this.worldBorder = config.getBoolean("world.border"); this.maxBuildHeight = config.getInt("world.max_height"); this.minBuildHeight = config.getInt("world.min_height"); + this.minGenHeight = config.getInt("world.min_gen_height"); + this.maxGenHeight = config.getInt("world.max_gen_height"); switch (config.getString("world.gamemode").toLowerCase()) { case "creative", "c", "1" -> this.gameMode = GameModes.CREATIVE; @@ -484,6 +485,8 @@ public abstract class PlotArea { options.put("home.nonmembers", position); options.put("world.max_height", this.getMaxBuildHeight()); options.put("world.min_height", this.getMinBuildHeight()); + options.put("world.min_gen_height", this.getMinGenHeight()); + options.put("world.max_gen_height", this.getMaxGenHeight()); options.put("world.gamemode", this.getGameMode().getName().toLowerCase()); options.put("road.flags.default", null); @@ -1078,8 +1081,8 @@ public abstract class PlotArea { BlockVector2 pos1 = BlockVector2.at(value.getP1().getX(), value.getP1().getY()); BlockVector2 pos2 = BlockVector2.at(value.getP2().getX(), value.getP2().getY()); return new CuboidRegion( - pos1.toBlockVector3(), - pos2.toBlockVector3(Plot.MAX_HEIGHT - 1) + pos1.toBlockVector3(getMinGenHeight()), + pos2.toBlockVector3(getMaxGenHeight()) ); } }; @@ -1361,14 +1364,38 @@ public abstract class PlotArea { this.defaultHome = defaultHome; } + /** + * Get the maximum height players may build in. Exclusive. + */ public int getMaxBuildHeight() { return this.maxBuildHeight; } + /** + * Get the minimum height players may build in. Inclusive. + */ public int getMinBuildHeight() { return this.minBuildHeight; } + /** + * Get the min height from which P2 will generate blocks. Inclusive. + * + * @since TODO + */ + public int getMinGenHeight() { + return this.minGenHeight; + } + + /** + * Get the max height to which P2 will generate blocks. Inclusive. + * + * @since TODO + */ + public int getMaxGenHeight() { + return this.maxGenHeight; + } + public GameMode getGameMode() { return this.gameMode; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java b/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java index 901ea04fa..b09117a24 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java @@ -89,11 +89,17 @@ public class PlotCluster { } private void setRegion() { - this.region = RegionUtil.createRegion(this.pos1.getX(), this.pos2.getX(), + this.region = RegionUtil.createRegion(this.pos1.getX(), this.pos2.getX(), 0, 0, this.pos1.getY(), this.pos2.getY() ); } + /** + * Returns a region of PlotIDs + * + * @deprecated - returns region of IDs, not of actual blocks. + */ + @Deprecated public CuboidRegion getRegion() { return this.region; } @@ -165,7 +171,7 @@ public class PlotCluster { Consumer locationConsumer = toReturn -> PlotSquared.platform().worldUtil().getHighestBlock(this.area.getWorldName(), toReturn.getX(), toReturn.getZ(), highest -> { - if (highest == 0) { + if (highest <= area.getMinBuildHeight()) { highest = 63; } if (highest > toReturn.getY()) { @@ -175,12 +181,12 @@ public class PlotCluster { } } ); - if (home.getY() == 0) { + if (home.getY() == Integer.MIN_VALUE) { // default pos Plot center = getCenterPlot(); center.getHome(location -> { Location toReturn = location; - if (toReturn.getY() == 0) { + if (toReturn.getY() <= area.getMinBuildHeight()) { PlotManager manager = this.area.getPlotManager(); Location locationSign = manager.getSignLoc(center); toReturn = toReturn.withY(locationSign.getY()); diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java b/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java index 93abffdeb..042c2e14f 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java @@ -69,8 +69,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; -import static com.plotsquared.core.plot.Plot.MAX_HEIGHT; - /** * Manager that handles {@link Plot} modifications */ @@ -311,7 +309,7 @@ public final class PlotModificationManager { return; } CuboidRegion region = regions.poll(); - PlotSquared.platform().regionManager().setBiome(region, extendBiome, biome, plot.getWorldName(), this); + PlotSquared.platform().regionManager().setBiome(region, extendBiome, biome, plot.getArea(), this); } }; run.run(); @@ -527,28 +525,6 @@ public final class PlotModificationManager { return false; } - /** - * Remove the south road section of a plot
- * - Used when a plot is merged
- * - * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, - * otherwise writes to the queue but does not enqueue. - */ - public void removeRoadSouth(final @Nullable QueueCoordinator queue) { - if (this.plot.getArea().getType() != PlotAreaType.NORMAL && this.plot - .getArea() - .getTerrain() == PlotAreaTerrainType.ROAD) { - Plot other = this.plot.getRelative(Direction.SOUTH); - Location bot = other.getBottomAbs(); - Location top = this.plot.getTopAbs(); - Location pos1 = Location.at(this.plot.getWorldName(), bot.getX(), 0, top.getZ()); - Location pos2 = Location.at(this.plot.getWorldName(), top.getX(), MAX_HEIGHT, bot.getZ()); - PlotSquared.platform().regionManager().regenerateRegion(pos1, pos2, true, null); - } else if (this.plot.getArea().getTerrain() != PlotAreaTerrainType.ALL) { // no road generated => no road to remove - this.plot.getManager().removeRoadSouth(this.plot, queue); - } - } - /** * Auto merge a plot in a specific direction. * @@ -915,6 +891,28 @@ public final class PlotModificationManager { return this.setComponent(component, parsed.toPattern(), actor, queue); } + /** + * Remove the south road section of a plot
+ * - Used when a plot is merged
+ * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public void removeRoadSouth(final @Nullable QueueCoordinator queue) { + if (this.plot.getArea().getType() != PlotAreaType.NORMAL && this.plot + .getArea() + .getTerrain() == PlotAreaTerrainType.ROAD) { + Plot other = this.plot.getRelative(Direction.SOUTH); + Location bot = other.getBottomAbs(); + Location top = this.plot.getTopAbs(); + Location pos1 = Location.at(this.plot.getWorldName(), bot.getX(), plot.getArea().getMinGenHeight(), top.getZ()); + Location pos2 = Location.at(this.plot.getWorldName(), top.getX(), plot.getArea().getMaxGenHeight(), bot.getZ()); + PlotSquared.platform().regionManager().regenerateRegion(pos1, pos2, true, null); + } else if (this.plot.getArea().getTerrain() != PlotAreaTerrainType.ALL) { // no road generated => no road to remove + this.plot.getManager().removeRoadSouth(this.plot, queue); + } + } + /** * Remove the east road section of a plot
* - Used when a plot is merged
@@ -929,8 +927,8 @@ public final class PlotModificationManager { Plot other = this.plot.getRelative(Direction.EAST); Location bot = other.getBottomAbs(); Location top = this.plot.getTopAbs(); - Location pos1 = Location.at(this.plot.getWorldName(), top.getX(), 0, bot.getZ()); - Location pos2 = Location.at(this.plot.getWorldName(), bot.getX(), MAX_HEIGHT, top.getZ()); + Location pos1 = Location.at(this.plot.getWorldName(), top.getX(), plot.getArea().getMinGenHeight(), bot.getZ()); + Location pos2 = Location.at(this.plot.getWorldName(), bot.getX(), plot.getArea().getMaxGenHeight(), top.getZ()); PlotSquared.platform().regionManager().regenerateRegion(pos1, pos2, true, null); } else if (this.plot.getArea().getTerrain() != PlotAreaTerrainType.ALL) { // no road generated => no road to remove this.plot.getArea().getPlotManager().removeRoadEast(this.plot, queue); @@ -948,8 +946,8 @@ public final class PlotModificationManager { .getArea() .getTerrain() == PlotAreaTerrainType.ROAD) { Plot other = this.plot.getRelative(1, 1); - Location pos1 = this.plot.getTopAbs().add(1, 0, 1).withY(0); - Location pos2 = other.getBottomAbs().subtract(1, 0, 1).withY(MAX_HEIGHT); + Location pos1 = this.plot.getTopAbs().add(1, 0, 1); + Location pos2 = other.getBottomAbs().subtract(1, 0, 1); PlotSquared.platform().regionManager().regenerateRegion(pos1, pos2, true, null); } else if (this.plot.getArea().getTerrain() != PlotAreaTerrainType.ALL) { // no road generated => no road to remove this.plot.getArea().getPlotManager().removeRoadSouthEast(this.plot, queue); diff --git a/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java index 1d5c10a8a..1f6d6371c 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java @@ -101,7 +101,7 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { @Override public boolean setBlock(int x, int y, int z, @NonNull BaseBlock id) { - if ((y > 255) || (y < 0)) { + if ((y > world.getMaxY()) || (y < world.getMinY())) { return false; } LocalChunk chunk = getChunk(x >> 4, z >> 4); @@ -121,7 +121,7 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { @Override public boolean setBiome(int x, int z, @NonNull BiomeType biomeType) { LocalChunk chunk = getChunk(x >> 4, z >> 4); - for (int y = 0; y < 256; y++) { + for (int y = world.getMinY(); y <= world.getMaxY(); y++) { chunk.setBiome(x & 15, y, z & 15, biomeType); } settingBiomes = true; diff --git a/Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java index f7b351356..ad68de264 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java @@ -54,12 +54,12 @@ public class ChunkQueueCoordinator extends ScopedQueueCoordinator { @NonNull BlockVector3 top, boolean biomes ) { - super(null, Location.at("", 0, 0, 0), Location.at("", 15, 255, 15)); + super(null, Location.at("", 0, weWorld.getMinY(), 0), Location.at("", 15, weWorld.getMaxY(), 15)); this.weWorld = weWorld; this.width = top.getX() - bot.getX() + 1; this.length = top.getZ() - bot.getZ() + 1; - this.result = new BlockState[256][width][length]; - this.biomeResult = biomes ? new BiomeType[256][width][length] : null; + this.result = new BlockState[weWorld.getMaxY() - weWorld.getMinY() + 1][width][length]; + this.biomeResult = biomes ? new BiomeType[weWorld.getMaxY() - weWorld.getMinY() + 1][width][length] : null; this.bot = bot; this.top = top; } @@ -71,7 +71,7 @@ public class ChunkQueueCoordinator extends ScopedQueueCoordinator { @Override public boolean setBiome(int x, int z, @NonNull BiomeType biomeType) { if (this.biomeResult != null) { - for (int y = 0; y < 256; y++) { + for (int y = weWorld.getMinY(); y <= weWorld.getMaxY(); y++) { this.storeCacheBiome(x, y, z, biomeType); } return true; @@ -101,9 +101,10 @@ public class ChunkQueueCoordinator extends ScopedQueueCoordinator { } private void storeCache(final int x, final int y, final int z, final @NonNull BlockState id) { - BlockState[][] resultY = result[y]; + int yIndex = getYIndex(y); + BlockState[][] resultY = result[yIndex]; if (resultY == null) { - result[y] = resultY = new BlockState[length][]; + result[yIndex] = resultY = new BlockState[length][]; } BlockState[] resultYZ = resultY[z]; if (resultYZ == null) { @@ -113,9 +114,10 @@ public class ChunkQueueCoordinator extends ScopedQueueCoordinator { } private void storeCacheBiome(final int x, final int y, final int z, final @NonNull BiomeType id) { - BiomeType[][] resultY = biomeResult[y]; + int yIndex = getYIndex(y); + BiomeType[][] resultY = biomeResult[yIndex]; if (resultY == null) { - biomeResult[y] = resultY = new BiomeType[length][]; + biomeResult[yIndex] = resultY = new BiomeType[length][]; } BiomeType[] resultYZ = resultY[z]; if (resultYZ == null) { @@ -132,7 +134,7 @@ public class ChunkQueueCoordinator extends ScopedQueueCoordinator { @Override public @Nullable BlockState getBlock(int x, int y, int z) { - BlockState[][] blocksY = result[y]; + BlockState[][] blocksY = result[getYIndex(y)]; if (blocksY != null) { BlockState[] blocksYZ = blocksY[z]; if (blocksYZ != null) { @@ -157,4 +159,8 @@ public class ChunkQueueCoordinator extends ScopedQueueCoordinator { return Location.at(getWorld().getName(), bot.getX(), bot.getY(), bot.getZ()); } + private int getYIndex(int y) { + return y - weWorld.getMinY(); + } + } diff --git a/Core/src/main/java/com/plotsquared/core/queue/LocalChunk.java b/Core/src/main/java/com/plotsquared/core/queue/LocalChunk.java index d61ff03cc..fc242692e 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/LocalChunk.java +++ b/Core/src/main/java/com/plotsquared/core/queue/LocalChunk.java @@ -42,6 +42,7 @@ public class LocalChunk { private final QueueCoordinator parent; private final int x; private final int z; + private final int minSection; private final BaseBlock[][] baseblocks; private final BiomeType[][] biomes; @@ -52,8 +53,10 @@ public class LocalChunk { this.parent = parent; this.x = x; this.z = z; - baseblocks = new BaseBlock[16][]; - biomes = new BiomeType[16][]; + this.minSection = parent.getMinLayer(); + int sections = parent.getMaxLayer() - parent.getMinLayer() + 1; + baseblocks = new BaseBlock[sections][]; + biomes = new BiomeType[sections][]; } public @NonNull QueueCoordinator getParent() { @@ -68,6 +71,15 @@ public class LocalChunk { return this.z; } + /** + * Get the minimum layer position stored (usually -4 or 0). + * + * @since TODO + */ + public int getMinSection() { + return this.minSection; + } + public @NonNull BaseBlock[][] getBaseblocks() { return this.baseblocks; } @@ -81,7 +93,7 @@ public class LocalChunk { } public void setBiome(final int x, final int y, final int z, final @NonNull BiomeType biomeType) { - final int i = y >> 4; + final int i = getLayerIndex(y); final int j = ChunkUtil.getJ(x, y, z); BiomeType[] array = this.biomes[i]; if (array == null) { @@ -96,7 +108,7 @@ public class LocalChunk { } public void setBlock(final int x, final int y, final int z, final @NonNull BaseBlock baseBlock) { - final int i = y >> 4; + final int i = getLayerIndex(y); final int j = ChunkUtil.getJ(x, y, z); BaseBlock[] array = baseblocks[i]; if (array == null) { @@ -117,4 +129,8 @@ public class LocalChunk { return this.entities; } + private int getLayerIndex(final int y) { + return (y >> 4) - minSection; + } + } diff --git a/Core/src/main/java/com/plotsquared/core/queue/LocationOffsetDelegateQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/LocationOffsetDelegateQueueCoordinator.java index f8d49014c..9d40c3112 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/LocationOffsetDelegateQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/LocationOffsetDelegateQueueCoordinator.java @@ -87,11 +87,14 @@ public class LocationOffsetDelegateQueueCoordinator extends DelegateQueueCoordin @Override public boolean setBiome(int x, int z, @NonNull BiomeType biome) { - boolean result = true; - for (int y = 0; y < 256; y++) { - result &= this.setBiome(x, y, z, biome); + try { + if (canPlace[x - blockX][z - blockZ]) { + return super.setBiome(x, z, biome); + } + } catch (final Exception e) { + throw e; } - return result; + return false; } @Override diff --git a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java index a162486cc..1d3e8ebe2 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java @@ -75,12 +75,29 @@ public abstract class QueueCoordinator { * @param x chunk x coordinate * @param z chunk z coordinate * @return a new {@link ScopedQueueCoordinator} + * @deprecated Use {@link ScopedQueueCoordinator#getForChunk(int, int, int, int)} */ + @Deprecated(forRemoval = true, since = "TODO") public ScopedQueueCoordinator getForChunk(int x, int z) { + if (getWorld() == null) { + return getForChunk(x, z, PlotSquared.platform().versionMinHeight(), PlotSquared.platform().versionMaxHeight()); + } + return getForChunk(x, z, getWorld().getMinY(), getWorld().getMaxY()); + } + + /** + * Get a {@link ScopedQueueCoordinator} limited to the chunk at the specific chunk Coordinates + * + * @param x chunk x coordinate + * @param z chunk z coordinate + * @return a new {@link ScopedQueueCoordinator} + * @since TODO + */ + public ScopedQueueCoordinator getForChunk(int x, int z, int minY, int maxY) { int bx = x << 4; int bz = z << 4; - return new ScopedQueueCoordinator(this, Location.at(getWorld().getName(), bx, 0, bz), - Location.at(getWorld().getName(), bx + 15, 255, bz + 255) + return new ScopedQueueCoordinator(this, Location.at(getWorld().getName(), bx, minY, bz), + Location.at(getWorld().getName(), bx + 15, maxY, bz + 15) ); } @@ -404,7 +421,7 @@ public abstract class QueueCoordinator { */ public void setCuboid(@NonNull Location pos1, @NonNull Location pos2, @NonNull BlockState block) { int yMin = Math.min(pos1.getY(), pos2.getY()); - int yMax = Math.min(255, Math.max(pos1.getY(), pos2.getY())); + int yMax = Math.max(pos1.getY(), pos2.getY()); int xMin = Math.min(pos1.getX(), pos2.getX()); int xMax = Math.max(pos1.getX(), pos2.getX()); int zMin = Math.min(pos1.getZ(), pos2.getZ()); @@ -427,7 +444,7 @@ public abstract class QueueCoordinator { */ public void setCuboid(@NonNull Location pos1, @NonNull Location pos2, @NonNull Pattern blocks) { int yMin = Math.min(pos1.getY(), pos2.getY()); - int yMax = Math.min(255, Math.max(pos1.getY(), pos2.getY())); + int yMax = Math.max(pos1.getY(), pos2.getY()); int xMin = Math.min(pos1.getX(), pos2.getX()); int xMax = Math.max(pos1.getX(), pos2.getX()); int zMin = Math.min(pos1.getZ(), pos2.getZ()); @@ -450,7 +467,7 @@ public abstract class QueueCoordinator { */ public void setBiomeCuboid(@NonNull Location pos1, @NonNull Location pos2, @NonNull BiomeType biome) { int yMin = Math.min(pos1.getY(), pos2.getY()); - int yMax = Math.min(255, Math.max(pos1.getY(), pos2.getY())); + int yMax = Math.max(pos1.getY(), pos2.getY()); int xMin = Math.min(pos1.getX(), pos2.getX()); int xMax = Math.max(pos1.getX(), pos2.getX()); int zMin = Math.min(pos1.getZ(), pos2.getZ()); @@ -464,4 +481,32 @@ public abstract class QueueCoordinator { } } + /** + * Get the min Y limit associated with the queue + */ + protected int getMinY() { + return getWorld() != null ? getWorld().getMinY() : PlotSquared.platform().versionMinHeight(); + } + + /** + * Get the max Y limit associated with the queue + */ + protected int getMaxY() { + return getWorld() != null ? getWorld().getMinY() : PlotSquared.platform().versionMaxHeight(); + } + + /** + * Get the min chunk layer associated with the queue. Usually 0 or -4; + */ + protected int getMinLayer() { + return (getWorld() != null ? getWorld().getMinY() : PlotSquared.platform().versionMinHeight()) >> 4; + } + + /** + * Get the max chunk layer associated with the queue. Usually 15 or 19 + */ + protected int getMaxLayer() { + return (getWorld() != null ? getWorld().getMaxY() : PlotSquared.platform().versionMaxHeight()) >> 4; + } + } diff --git a/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java index ae05eb31d..cba1f8a2a 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java @@ -39,6 +39,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; */ public class ScopedQueueCoordinator extends DelegateQueueCoordinator { + private final Location min; + private final Location max; private final int minX; private final int minY; private final int minZ; @@ -51,8 +53,13 @@ public class ScopedQueueCoordinator extends DelegateQueueCoordinator { private final int dy; private final int dz; + /** + * Create a new ScopedQueueCoordinator instance that delegates to a given QueueCoordinator. Locations are inclusive. + */ public ScopedQueueCoordinator(@Nullable QueueCoordinator parent, @NonNull Location min, @NonNull Location max) { super(parent); + this.min = min; + this.max = max; this.minX = min.getX(); this.minY = min.getY(); this.minZ = min.getZ(); @@ -112,11 +119,11 @@ public class ScopedQueueCoordinator extends DelegateQueueCoordinator { } public @NonNull Location getMin() { - return Location.at(this.getWorld().getName(), this.minX, this.minY, this.minZ); + return min; } public @NonNull Location getMax() { - return Location.at(this.getWorld().getName(), this.maxX, this.maxY, this.maxZ); + return max; } } diff --git a/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java b/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java index c69e8a922..cda456bbc 100644 --- a/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java @@ -31,6 +31,7 @@ import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.plotsquared.core.util.task.RunnableVal; import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.world.World; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -47,18 +48,16 @@ public abstract class ChunkManager { String world, BlockVector2 loc ) { - QueueCoordinator queue = PlotSquared.platform().globalBlockQueue().getNewQueue(PlotSquared - .platform() - .worldUtil() - .getWeWorld(world)); + World weWorld = PlotSquared.platform().worldUtil().getWeWorld(world); + QueueCoordinator queue = PlotSquared.platform().globalBlockQueue().getNewQueue(weWorld); if (PlotSquared.get().getPlotAreaManager().isAugmented(world) && PlotSquared.get().isNonStandardGeneration(world, loc)) { int blockX = loc.getX() << 4; int blockZ = loc.getZ() << 4; ScopedQueueCoordinator scoped = new ScopedQueueCoordinator( queue, - Location.at(world, blockX, 0, blockZ), - Location.at(world, blockX + 15, 255, blockZ + 15) + Location.at(world, blockX, weWorld.getMinY(), blockZ), + Location.at(world, blockX + 15, weWorld.getMaxY(), blockZ + 15) ); if (force != null) { force.run(scoped); diff --git a/Core/src/main/java/com/plotsquared/core/util/ChunkUtil.java b/Core/src/main/java/com/plotsquared/core/util/ChunkUtil.java index f0b48a231..a734180b6 100644 --- a/Core/src/main/java/com/plotsquared/core/util/ChunkUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/ChunkUtil.java @@ -39,30 +39,27 @@ public class ChunkUtil { * - Used for efficient world generation
*/ private static final short[] x_loc; - private static final short[][] y_loc; + private static final short[] y_loc; private static final short[] z_loc; private static final short[][][] CACHE_J; static { x_loc = new short[4096]; - y_loc = new short[16][4096]; + y_loc = new short[4096]; z_loc = new short[4096]; - for (int i = 0; i < 16; i++) { - int i4 = i << 4; - for (int j = 0; j < 4096; j++) { - int y = i4 + (j >> 8); - int a = j - ((y & 0xF) << 8); - int z1 = a >> 4; - int x1 = a - (z1 << 4); - x_loc[j] = (short) x1; - y_loc[i][j] = (short) y; - z_loc[j] = (short) z1; - } + for (int j = 0; j < 4096; j++) { + int y = j >> 8; + int a = j - ((y & 0xF) << 8); + int z1 = a >> 4; + int x1 = a - (z1 << 4); + x_loc[j] = (short) x1; + y_loc[j] = (short) y; + z_loc[j] = (short) z1; } - CACHE_J = new short[256][16][16]; + CACHE_J = new short[16][16][16]; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { - for (int y = 0; y < 256; y++) { + for (int y = 0; y < 16; y++) { short j = (short) ((y & 0xF) << 8 | z << 4 | x); CACHE_J[y][x][z] = j; } @@ -83,7 +80,7 @@ public class ChunkUtil { * @return J value for xyz position in Array[4096]. */ public static int getJ(int x, int y, int z) { - return CACHE_J[y][x][z]; + return CACHE_J[y & 15][x & 15][z & 15]; } /** @@ -97,14 +94,14 @@ public class ChunkUtil { } /** - * Gets the y coordinate for specific I and J values for a Chunk 16x16x16x16 layerxyz Array[16][4096]. + * Gets the y coordinate for specific I and J values for a Chunk Nx16x16x16 layerxyz Array[N][4096]. * - * @param i Relative layer of the position in the layerxyz Array[16][4096]. + * @param i Relative layer of the position in the layerxyz Array[16][4096]. May be negative. * @param j Position in the xyz Array[4096]. * @return x coordinate within the chunk */ public static int getY(int i, int j) { - return y_loc[i][j]; + return (i << 4) + y_loc[j]; } /** diff --git a/Core/src/main/java/com/plotsquared/core/util/MainUtil.java b/Core/src/main/java/com/plotsquared/core/util/MainUtil.java index 8773dd446..768aa6f90 100644 --- a/Core/src/main/java/com/plotsquared/core/util/MainUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/MainUtil.java @@ -37,15 +37,21 @@ public class MainUtil { * Cache of mapping x,y,z coordinates to the chunk array
* - Used for efficient world generation
*/ + @Deprecated(forRemoval = true, since = "6.0.0") public static short[][] x_loc; + @Deprecated(forRemoval = true, since = "6.0.0") public static short[][] y_loc; + @Deprecated(forRemoval = true, since = "6.0.0") public static short[][] z_loc; + @Deprecated(forRemoval = true, since = "6.0.0") public static short[][][] CACHE_I = null; + @Deprecated(forRemoval = true, since = "6.0.0") public static short[][][] CACHE_J = null; /** * This cache is used for world generation and just saves a bit of calculation time when checking if something is in the plot area. */ + @Deprecated(forRemoval = true, since = "6.0.0") public static void initCache() { if (x_loc == null) { x_loc = new short[16][4096]; diff --git a/Core/src/main/java/com/plotsquared/core/util/RegionManager.java b/Core/src/main/java/com/plotsquared/core/util/RegionManager.java index a662adf70..87ca3708e 100644 --- a/Core/src/main/java/com/plotsquared/core/util/RegionManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/RegionManager.java @@ -279,7 +279,10 @@ public abstract class RegionManager { fromQueue1.addReadChunks(new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()).getChunks()); fromQueue2.addReadChunks(new CuboidRegion( swapPos.getBlockVector3(), - BlockVector3.at(swapPos.getX() + pos2.getX() - pos1.getX(), 0, swapPos.getZ() + pos2.getZ() - pos1.getZ()) + BlockVector3.at(swapPos.getX() + pos2.getX() - pos1.getX(), + pos1.getY(), + swapPos.getZ() + pos2.getZ() - pos1.getZ() + ) ).getChunks()); QueueCoordinator toQueue1 = blockQueue.getNewQueue(world1); QueueCoordinator toQueue2 = blockQueue.getNewQueue(world2); @@ -352,7 +355,7 @@ public abstract class RegionManager { int bz = Math.max(pos1.getZ(), cbz) & 15; int tx = Math.min(pos2.getX(), cbx + 15) & 15; int tz = Math.min(pos2.getZ(), cbz + 15) & 15; - for (int y = 0; y < 256; y++) { + for (int y = world1.getMinY(); y <= world1.getMaxY(); y++) { for (int x = bx; x <= tx; x++) { for (int z = bz; z <= tz; z++) { int rx = cbx + x; @@ -363,7 +366,10 @@ public abstract class RegionManager { } } } - Region region = new CuboidRegion(BlockVector3.at(cbx + bx, 0, cbz + bz), BlockVector3.at(cbx + tx, 255, cbz + tz)); + Region region = new CuboidRegion( + BlockVector3.at(cbx + bx, world1.getMinY(), cbz + bz), + BlockVector3.at(cbx + tx, world1.getMaxY(), cbz + tz) + ); toQueue.addEntities(world1.getEntities(region)); if (removeEntities) { for (Entity entity : world1.getEntities(region)) { @@ -373,6 +379,7 @@ public abstract class RegionManager { }); } + @Deprecated(forRemoval = true, since = "TODO") public void setBiome( final CuboidRegion region, final int extendBiome, @@ -380,39 +387,35 @@ public abstract class RegionManager { final String world, final Runnable whenDone ) { - Location pos1 = Location - .at( - world, - region.getMinimumPoint().getX() - extendBiome, - region.getMinimumPoint().getY(), - region.getMinimumPoint().getZ() - extendBiome - ); - Location pos2 = Location - .at( - world, - region.getMaximumPoint().getX() + extendBiome, - region.getMaximumPoint().getY(), - region.getMaximumPoint().getZ() + extendBiome - ); - final QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(world)); + setBiome(region, extendBiome, biome, PlotSquared.get().getPlotAreaManager().getPlotAreas(world, region)[0], whenDone); + } - final int minX = pos1.getX(); - final int minZ = pos1.getZ(); - final int maxX = pos2.getX(); - final int maxZ = pos2.getZ(); + /** + * Set a region to a biome type. + * + * @param region region to set + * @param extendBiome how far outside the region to extent setting the biome too account for 3D biomes being 4x4 + * @param biome biome to set + * @param area {@link PlotArea} in which the biome is being set + * @param whenDone task to run when complete + * @since TODO + */ + public void setBiome( + final CuboidRegion region, + final int extendBiome, + final BiomeType biome, + final PlotArea area, + final Runnable whenDone + ) { + final QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName())); queue.addReadChunks(region.getChunks()); queue.setChunkConsumer(blockVector2 -> { - final int cx = blockVector2.getX() << 4; - final int cz = blockVector2.getZ() << 4; WorldUtil.setBiome( - world, - Math.max(minX, cx), - Math.max(minZ, cz), - Math.min(maxX, cx + 15), - Math.min(maxZ, cz + 15), + area.getWorldName(), + region, biome ); - worldUtil.refreshChunk(blockVector2.getBlockX(), blockVector2.getBlockZ(), world); + worldUtil.refreshChunk(blockVector2.getBlockX(), blockVector2.getBlockZ(), area.getWorldName()); }); queue.setCompleteTask(whenDone); queue.enqueue(); diff --git a/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java b/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java index 2a489507b..cc3d704aa 100644 --- a/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java @@ -76,8 +76,9 @@ public class RegionUtil { return new CuboidRegion(min, max); } + @Deprecated(forRemoval = true, since = "TODO") public static CuboidRegion createRegion(int pos1x, int pos2x, int pos1z, int pos2z) { - return createRegion(pos1x, pos2x, 0, Plot.MAX_HEIGHT - 1, pos1z, pos2z); + return createRegion(pos1x, pos2x, 0, 255, pos1z, pos2z); } public static CuboidRegion createRegion( diff --git a/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java b/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java index c79e4eb0e..7c4b9bc07 100644 --- a/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java +++ b/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java @@ -305,12 +305,13 @@ public abstract class SchematicHandler { final int WIDTH = dimension.getX(); final int LENGTH = dimension.getZ(); final int HEIGHT = dimension.getY(); + final int worldHeight = plot.getArea().getMaxGenHeight() - plot.getArea().getMinGenHeight() + 1; // Validate dimensions CuboidRegion region = plot.getLargestRegion(); boolean sizeMismatch = ((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || ( (region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT - > 256); + > worldHeight); if (!Settings.Schematics.PASTE_MISMATCHES && sizeMismatch) { actor.sendMessage(TranslatableCaption.of("schematics.schematic_size_mismatch")); TaskManager.runTask(whenDone); @@ -321,14 +322,14 @@ public abstract class SchematicHandler { // Calculate the optimal height to paste the schematic at final int y_offset_actual; if (autoHeight) { - if (HEIGHT >= 256) { + if (HEIGHT >= worldHeight) { y_offset_actual = yOffset; } else { PlotArea pw = plot.getArea(); if (pw instanceof ClassicPlotWorld) { y_offset_actual = yOffset + pw.getMinBuildHeight() + ((ClassicPlotWorld) pw).PLOT_HEIGHT; } else { - y_offset_actual = yOffset + 1 + this.worldUtil + y_offset_actual = yOffset + pw.getMinBuildHeight() + this.worldUtil .getHighestBlockSynchronous(plot.getWorldName(), region.getMinimumPoint().getX() + 1, region.getMinimumPoint().getZ() + 1 ); @@ -360,9 +361,9 @@ public abstract class SchematicHandler { // Paste schematic here final QueueCoordinator queue = plot.getArea().getQueue(); - for (int ry = 0; ry < Math.min(256, HEIGHT); ry++) { + for (int ry = 0; ry < Math.min(worldHeight, HEIGHT); ry++) { int yy = y_offset_actual + ry; - if (yy > 255 || yy < 0) { + if (yy > plot.getArea().getMaxGenHeight() || yy < plot.getArea().getMinGenHeight()) { continue; } for (int rz = 0; rz < blockArrayClipboard.getDimensions().getZ(); rz++) { @@ -379,18 +380,18 @@ public abstract class SchematicHandler { BlockVector3 loc = BlockVector3.at(rx, ry, rz); BaseBlock id = blockArrayClipboard.getFullBlock(loc); queue.setBlock(xx, yy, zz, id); - if (ry == 0) { - BiomeType biome = blockArrayClipboard.getBiome(loc); - queue.setBiome(xx, yy, zz, biome); - } + BiomeType biome = blockArrayClipboard.getBiome(loc); + queue.setBiome(xx, yy, zz, biome); } } } if (actor != null && Settings.QUEUE.NOTIFY_PROGRESS) { queue.addProgressSubscriber(subscriberFactory.createWithActor(actor)); } - whenDone.value = true; - queue.setCompleteTask(whenDone); + if (whenDone != null) { + whenDone.value = true; + queue.setCompleteTask(whenDone); + } queue.enqueue(); } catch (Exception e) { e.printStackTrace(); diff --git a/Core/src/main/java/com/plotsquared/core/util/WEManager.java b/Core/src/main/java/com/plotsquared/core/util/WEManager.java index 2ae4e38b7..9ef38e1f4 100644 --- a/Core/src/main/java/com/plotsquared/core/util/WEManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/WEManager.java @@ -25,6 +25,7 @@ */ package com.plotsquared.core.util; +import com.fastasyncworldedit.core.regions.RegionWrapper; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.location.Location; @@ -91,10 +92,7 @@ public class WEManager { Location location = player.getLocation(); String world = location.getWorldName(); if (!PlotSquared.get().getPlotAreaManager().hasPlotArea(world)) { - regions.add(RegionUtil - .createRegion(Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, - Integer.MAX_VALUE - )); + regions.add(RegionWrapper.GLOBAL()); return regions; } PlotArea area = player.getApplicablePlotArea(); diff --git a/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java b/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java index f4c526c57..9fa8cddf0 100644 --- a/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java @@ -39,6 +39,7 @@ import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; @@ -78,14 +79,29 @@ public abstract class WorldUtil { * @param p2x Max X * @param p2z Max Z * @param biome Biome + * @deprecated use {@link WorldUtil#setBiome(String, CuboidRegion, BiomeType)} */ + @Deprecated(forRemoval = true) public static void setBiome(String world, int p1x, int p1z, int p2x, int p2z, BiomeType biome) { - BlockVector3 pos1 = BlockVector2.at(p1x, p1z).toBlockVector3(); - BlockVector3 pos2 = BlockVector2.at(p2x, p2z).toBlockVector3(Plot.MAX_HEIGHT - 1); + World weWorld = PlotSquared.platform().worldUtil().getWeWorld(world); + BlockVector3 pos1 = BlockVector2.at(p1x, p1z).toBlockVector3(weWorld.getMinY()); + BlockVector3 pos2 = BlockVector2.at(p2x, p2z).toBlockVector3(weWorld.getMaxY()); CuboidRegion region = new CuboidRegion(pos1, pos2); PlotSquared.platform().worldUtil().setBiomes(world, region, biome); } + /** + * Set the biome in a region + * + * @param world World name + * @param region Region + * @param biome Biome + * @since TODO + */ + public static void setBiome(String world, final CuboidRegion region, BiomeType biome) { + PlotSquared.platform().worldUtil().setBiomes(world, region, biome); + } + /** * Check if a given world name corresponds to a real world * @@ -217,11 +233,14 @@ public abstract class WorldUtil { /** * Set the biome in a region * - * @param world World name - * @param region Region - * @param biome New biome + * @param worldName World name + * @param region Region + * @param biome New biome */ - public abstract void setBiomes(@NonNull String world, @NonNull CuboidRegion region, @NonNull BiomeType biome); + public void setBiomes(@NonNull String worldName, @NonNull CuboidRegion region, @NonNull BiomeType biome) { + final World world = getWeWorld(worldName); + region.forEach(bv -> world.setBiome(bv, biome)); + } /** * Get the WorldEdit {@link com.sk89q.worldedit.world.World} corresponding to a world name diff --git a/Core/src/main/resources/lang/messages_en.json b/Core/src/main/resources/lang/messages_en.json index 96475e3e8..50b3639df 100644 --- a/Core/src/main/resources/lang/messages_en.json +++ b/Core/src/main/resources/lang/messages_en.json @@ -161,8 +161,9 @@ "setup.road_width": "Road width", "setup.road_height": "Road height", "setup.road_block": "Road block", - "setup.wall_filling_block": "Wall filling block (Block(s) been put under the plot border down to Y1)", + "setup.wall_filling_block": "Wall filling block (Block(s) been put under the plot border down to min gen height + 1)", "setup.wall_height": "Wall height", + "setup.min_gen_height": "Minimum height from which to generate (for 1.18+ can be negative).", "setup.bedrock_boolean": "Whether a bedrock layer under the plot should be generated or not", "setup.singleplotarea_void_world": "Void world", "plotareatype.plot_area_type_normal": "Standard plot generation",