Fix plot analysis (#3618)

* Fix plot analysis
 - Stop using deprecated ChunkQueueCoordinator and create a new purpose-built coordinator
 - Generation is chunk-by-chunk thus the old blocks cache needs to be filled accordingly
 - Remove the **four** System#gc calls
 - Fixes #3464
 - Fix really weird dumb... maths? in ExpiryTask
 - Fixes #3600

* Add since annotation

* Address comments and maxY should be inclusive

* Annotate new queue as internal use only
This commit is contained in:
Jordan 2022-05-15 10:58:04 +01:00 committed by GitHub
parent 0ffa22b7a6
commit 98a07dad1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 207 additions and 34 deletions

View File

@ -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;
@ -83,6 +83,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class HybridUtils {
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + HybridUtils.class.getSimpleName());
private static final BlockState AIR = BlockTypes.AIR.getDefaultState();
public static HybridUtils manager;
public static Set<BlockVector2> regions;
@ -136,6 +137,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,37 +158,28 @@ 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[][][] newBlocks = new BlockState[height][width][length];
for (final BlockState[][] newBlock : newBlocks) {
for (final BlockState[] blockStates : newBlock) {
Arrays.fill(blockStates, airBlock);
}
}
for (final BlockState[][] oldBlock : oldBlocks) {
for (final BlockState[] blockStates : oldBlock) {
Arrays.fill(blockStates, airBlock);
}
}
System.gc();
System.gc();
BlockArrayCacheScopedQueueCoordinator oldBlockQueue = new BlockArrayCacheScopedQueueCoordinator(
Location.at("", region.getMinimumPoint().withY(hpw.getMinGenHeight())),
Location.at("", region.getMaximumPoint().withY(hpw.getMaxGenHeight()))
);
region.getChunks().forEach(chunkPos -> {
int relChunkX = chunkPos.getX() - cbx;
int relChunkZ = chunkPos.getZ() - cbz;
oldBlockQueue.setOffsetX(relChunkX << 4);
oldBlockQueue.setOffsetZ(relChunkZ << 4);
hpw.getGenerator().generateChunk(oldBlockQueue, hpw);
});
final BlockState[][][] oldBlocks = oldBlockQueue.getBlockStates();
QueueCoordinator queue = area.getQueue();
queue.addReadChunks(region.getChunks());
queue.setChunkConsumer(blockVector2 -> {
int X = blockVector2.getX();
int Z = blockVector2.getZ();
queue.setChunkConsumer(chunkPos -> {
int X = chunkPos.getX();
int Z = chunkPos.getZ();
int minX;
if (X == cbx) {
minX = bx & 15;
@ -220,6 +217,9 @@ public class HybridUtils {
for (int yIndex = 0; yIndex < height; yIndex++) {
int y = yIndex + minHeight;
BlockState block = queue.getBlock(xx, y, zz);
if (block == null) {
block = AIR;
}
int xr = xb + x;
int zr = zb + z;
newBlocks[yIndex][xr][zr] = block;
@ -240,10 +240,10 @@ public class HybridUtils {
for (int z = 0; z < length; z++) {
Set<BlockType> types = new HashSet<>();
for (int yIndex = 0; yIndex < height; yIndex++) {
BlockState old = oldBlocks[yIndex][x][z];
BlockState old = oldBlocks[yIndex][x][z]; // Nullable
try {
BlockState now = newBlocks[yIndex][x][z];
if (!old.equals(now)) {
BlockState now = newBlocks[yIndex][x][z]; // Not null
if (!now.equals(old) && !(old == null && now.getBlockType().equals(BlockTypes.AIR))) {
changes[i]++;
}
if (now.getBlockType().getMaterial().isAir()) {
@ -301,8 +301,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();
});

View File

@ -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<Long> entireList =
plots.stream().map(plot -> ExpireManager.IMP.getAge(plot, settings.DELETE_IF_OWNER_IS_UNKNOWN))

View File

@ -0,0 +1,175 @@
/*
* _____ _ _ _____ _
* | __ \| | | | / ____| | |
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
* | |
* |_|
* 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 <https://www.gnu.org/licenses/>.
*/
package com.plotsquared.core.queue;
import com.plotsquared.core.location.Location;
import com.plotsquared.core.util.AnnotationHelper;
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. This should have blocks set to it one chunk at a time, based on the
* result of {@link BlockArrayCacheScopedQueueCoordinator#getMin()} and {@link BlockArrayCacheScopedQueueCoordinator#getMax()}.
* The min and max points of this queue are offset according to the minimum point given in the constructor, and the offsets set
* in {@link BlockArrayCacheScopedQueueCoordinator#setOffsetX(int)} and
* {@link BlockArrayCacheScopedQueueCoordinator#setOffsetZ(int)}
*/
@AnnotationHelper.ApiDescription(info = "Internal use only. Subject to change at any time and created for specific use cases.")
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 min Inclusive location of the minimum point to limit the scope to.
* @param max Inclusive location of the maximum point to limit the scope to.
* @since TODO
*/
public BlockArrayCacheScopedQueueCoordinator(Location min, Location max) {
super(null, min, max);
this.width = max.getX() - min.getX() + 1;
this.length = max.getZ() - min.getZ() + 1;
this.minY = min.getY();
this.maxY = max.getY();
this.height = maxY - minY + 1;
this.scopeMinX = min.getX() & 15;
this.scopeMinZ = min.getZ() & 15;
this.scopeMaxX = scopeMinX + width;
this.scopeMaxZ = scopeMinZ + length;
this.blockStates = new BlockState[height][width][length];
}
public BlockState[][][] getBlockStates() {
return blockStates;
}
@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;
}
}