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 0eab11c71..a0ebaadfa 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java @@ -41,7 +41,7 @@ import com.plotsquared.core.plot.flag.GlobalFlagContainer; import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.plot.flag.implementations.AnalysisFlag; import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.queue.ChunkQueueCoordinator; +import com.plotsquared.core.queue.BlockArrayCacheScopedQueueCoordinator; import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.ChunkManager; @@ -136,6 +136,11 @@ public class HybridUtils { * */ TaskManager.runTaskAsync(() -> { + final PlotArea area = this.plotAreaManager.getPlotArea(world, null); + if (!(area instanceof HybridPlotWorld hpw)) { + return; + } + final BlockVector3 bot = region.getMinimumPoint(); final BlockVector3 top = region.getMaximumPoint(); @@ -152,17 +157,8 @@ public class HybridUtils { final int height = area.getMaxGenHeight() - area.getMinGenHeight() + 1; final int minHeight = area.getMinGenHeight(); - final PlotArea area = this.plotAreaManager.getPlotArea(world, null); - - if (!(area instanceof HybridPlotWorld hpw)) { - return; - } - - ChunkQueueCoordinator chunk = new ChunkQueueCoordinator(worldUtil.getWeWorld(world), bot, top, false); - hpw.getGenerator().generateChunk(chunk, hpw); - final BlockState airBlock = BlockTypes.AIR.getDefaultState(); - final BlockState[][][] oldBlocks = chunk.getBlocks(); + final BlockState[][][] oldBlocks = new BlockState[height][width][length]; final BlockState[][][] newBlocks = new BlockState[height][width][length]; for (final BlockState[][] newBlock : newBlocks) { for (final BlockState[] blockStates : newBlock) { @@ -175,8 +171,20 @@ public class HybridUtils { } } - System.gc(); - System.gc(); + BlockArrayCacheScopedQueueCoordinator oldBlockQueue = new BlockArrayCacheScopedQueueCoordinator( + oldBlocks, + area.getMinGenHeight(), + Location.at("", region.getMinimumPoint()), + Location.at("", region.getMaximumPoint()) + ); + + region.getChunks().forEach(blockVector2 -> { + int relChunkX = blockVector2.getX() - cbx; + int relChunkZ = blockVector2.getZ() - cbz; + oldBlockQueue.setOffsetX(relChunkX << 4); + oldBlockQueue.setOffsetZ(relChunkZ << 4); + hpw.getGenerator().generateChunk(oldBlockQueue, hpw); + }); QueueCoordinator queue = area.getQueue(); queue.addReadChunks(region.getChunks()); @@ -301,8 +309,6 @@ public class HybridUtils { analysis.data_sd = (int) (MathMan.getSD(data, analysis.data) * 100); analysis.air_sd = (int) (MathMan.getSD(air, analysis.air) * 100); analysis.variety_sd = (int) (MathMan.getSD(variety, analysis.variety) * 100); - System.gc(); - System.gc(); whenDone.value = analysis; whenDone.run(); }); diff --git a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpiryTask.java b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpiryTask.java index 03a9c010b..c0e2b8a1a 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpiryTask.java +++ b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpiryTask.java @@ -75,9 +75,9 @@ public class ExpiryTask { plots = plots != null ? plots : getPlotsToCheck(); int diff = settings.REQUIRED_PLOTS; boolean min = true; - if (settings.REQUIRED_PLOTS - plots.size() < settings.REQUIRED_PLOTS) { + if (plots.size() > settings.REQUIRED_PLOTS) { min = false; - diff = settings.REQUIRED_PLOTS - plots.size(); + diff = plots.size() - settings.REQUIRED_PLOTS; } List entireList = plots.stream().map(plot -> ExpireManager.IMP.getAge(plot, settings.DELETE_IF_OWNER_IS_UNKNOWN)) diff --git a/Core/src/main/java/com/plotsquared/core/queue/BlockArrayCacheScopedQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/BlockArrayCacheScopedQueueCoordinator.java new file mode 100644 index 000000000..b5c282c6d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/queue/BlockArrayCacheScopedQueueCoordinator.java @@ -0,0 +1,168 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2014 - 2022 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.queue; + +import com.plotsquared.core.location.Location; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * {@link QueueCoordinator} that caches all blocks set to it in a given array of form BlockState[][][]. An offset can be + * applied to blocks set to it, and the scope limited. + */ +public class BlockArrayCacheScopedQueueCoordinator extends ScopedQueueCoordinator { + + private final BlockState[][][] blockStates; + private final int height; + private final int width; + private final int length; + private final int minY; + private final int maxY; + private final int scopeMinX; + private final int scopeMinZ; + private final int scopeMaxX; + private final int scopeMaxZ; + + private int offsetX = 0; + private int offsetZ = 0; + + /** + * Construct a new instance + * + * @param blockStates Array of form BlockState[y][x][z]. Must be fully initialised. + * @param minY Minimum applicable y value. Used to account for negative world heights (e.g. -64). Inclusive + * @param min Inclusive location of the minimum point to limit the scope to. + * @param max Exclusive location of the maximum point to limit the scope to. + */ + public BlockArrayCacheScopedQueueCoordinator(@NonNull BlockState[][][] blockStates, int minY, Location min, Location max) { + super(null, min, max); + this.blockStates = blockStates; + this.height = blockStates.length; + this.width = blockStates[0].length; + this.length = blockStates[0][0].length; + this.minY = minY; + this.maxY = height + minY; // exclusive + + this.scopeMinX = min.getX() & 15; + this.scopeMinZ = min.getZ() & 15; + this.scopeMaxX = scopeMinX + width; + this.scopeMaxZ = scopeMinZ + length; + } + + @Override + public boolean setBlock(int x, final int y, int z, final @NonNull BlockState id) { + x += offsetX; + z += offsetZ; + if (x >= scopeMinX && x < scopeMaxX && y >= minY && y < maxY && z >= scopeMinZ && z < scopeMaxZ) { + blockStates[y - minY][x - scopeMinX][z - scopeMinZ] = id; + } + return false; + } + + @Override + public boolean setBlock(final int x, final int y, final int z, @NonNull final Pattern pattern) { + int rx = x + offsetX; + int rz = z + offsetZ; + if (rx >= scopeMinX && rx < scopeMaxX && y >= minY && y < maxY && rz >= scopeMinZ && rz < scopeMaxZ) { + BlockState state = pattern + .applyBlock(super.getMin().getBlockVector3().add(BlockVector3.at(x, y, z))) + .toImmutableState(); + blockStates[y - minY][rx - scopeMinX][rz - scopeMinZ] = state; + } + return false; + } + + @Override + public @NonNull Location getMin() { + return super.getMin().add(offsetX - scopeMinX, 0, offsetZ - scopeMinZ); + } + + @Override + public @NonNull Location getMax() { + return getMin().add(15, 0, 15).withY(maxY); + } + + @Override + public boolean setBlock(int x, int y, int z, final @NonNull BaseBlock id) { + x += offsetX; + z += offsetZ; + if (x >= scopeMinX && x < scopeMaxX && y >= minY && y < maxY && z >= scopeMinZ && z < scopeMaxZ) { + blockStates[y - minY][x][z] = id.toImmutableState(); + } + return false; + } + + @Override + public @Nullable BlockState getBlock(final int x, final int y, final int z) { + if (x >= 0 && x < width && y >= minY && y < maxY && z >= 0 && z < length) { + return blockStates[y - minY][x][z]; + } + return null; + } + + public void setOffsetX(final int offsetX) { + this.offsetX = offsetX; + } + + public void setOffsetZ(final int offsetZ) { + this.offsetZ = offsetZ; + } + + @Override + public int size() { + return height * width * length; + } + + @Override + public boolean setBiome(final int x, final int z, @NonNull final BiomeType biome) { + //do nothing + return false; + } + + @Override + public boolean setBiome(final int x, final int y, final int z, @NonNull final BiomeType biome) { + //do nothing + return false; + } + + @Override + public void fillBiome(final BiomeType biome) { + //do nothing + } + + @Override + public boolean setTile(final int x, final int y, final int z, @NonNull final CompoundTag tag) { + //do nothing + return false; + } + +}