Rework the chunk deletion (#1897)
* delete island one by one * register before IslandDeletionManager * optimize imports * setting * just some indents * config * run synchronously * a bit reformat before recoding * proper delete chunks * comment * combine the task call * expose the NMS Handler * don't have to try-catch this * we know that this is final * expose copy chunk data so that it can be overridden * Don't have to use Vector * set block from minimum height * remove NMS and use fallback if not set * only get the height once * fix test
This commit is contained in:
parent
c9c9ea0389
commit
ce1d8e5117
13
pom.xml
13
pom.xml
|
@ -172,7 +172,10 @@
|
|||
<id>maven-snapshots</id>
|
||||
<url>https://repository.apache.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>minecraft-repo</id>
|
||||
<url>https://libraries.minecraft.net/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
|
@ -190,11 +193,11 @@
|
|||
<version>${paper.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Spigot NMS. Used for Head Getter and chunk deletion. -->
|
||||
<!-- AuthLib. Used for Head Getter. -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>${spigot.version}</version>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>authlib</artifactId>
|
||||
<version>3.2.38</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Metrics -->
|
||||
|
|
|
@ -30,19 +30,7 @@ import world.bentobox.bentobox.listeners.JoinLeaveListener;
|
|||
import world.bentobox.bentobox.listeners.PanelListenerManager;
|
||||
import world.bentobox.bentobox.listeners.PortalTeleportationListener;
|
||||
import world.bentobox.bentobox.listeners.StandardSpawnProtectionListener;
|
||||
import world.bentobox.bentobox.managers.AddonsManager;
|
||||
import world.bentobox.bentobox.managers.BlueprintsManager;
|
||||
import world.bentobox.bentobox.managers.CommandsManager;
|
||||
import world.bentobox.bentobox.managers.FlagsManager;
|
||||
import world.bentobox.bentobox.managers.HooksManager;
|
||||
import world.bentobox.bentobox.managers.IslandDeletionManager;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.bentobox.managers.LocalesManager;
|
||||
import world.bentobox.bentobox.managers.PlaceholdersManager;
|
||||
import world.bentobox.bentobox.managers.PlayersManager;
|
||||
import world.bentobox.bentobox.managers.RanksManager;
|
||||
import world.bentobox.bentobox.managers.WebManager;
|
||||
import world.bentobox.bentobox.managers.*;
|
||||
import world.bentobox.bentobox.util.heads.HeadGetter;
|
||||
import world.bentobox.bentobox.versions.ServerCompatibility;
|
||||
|
||||
|
@ -69,6 +57,7 @@ public class BentoBox extends JavaPlugin {
|
|||
private HooksManager hooksManager;
|
||||
private PlaceholdersManager placeholdersManager;
|
||||
private IslandDeletionManager islandDeletionManager;
|
||||
private IslandChunkDeletionManager islandChunkDeletionManager;
|
||||
private WebManager webManager;
|
||||
|
||||
// Settings
|
||||
|
@ -294,6 +283,7 @@ public class BentoBox extends JavaPlugin {
|
|||
// Death counter
|
||||
manager.registerEvents(new DeathListener(this), this);
|
||||
// Island Delete Manager
|
||||
islandChunkDeletionManager = new IslandChunkDeletionManager(this);
|
||||
islandDeletionManager = new IslandDeletionManager(this);
|
||||
manager.registerEvents(islandDeletionManager, this);
|
||||
}
|
||||
|
@ -523,6 +513,13 @@ public class BentoBox extends JavaPlugin {
|
|||
return islandDeletionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the islandChunkDeletionManager
|
||||
*/
|
||||
public IslandChunkDeletionManager getIslandChunkDeletionManager() {
|
||||
return islandChunkDeletionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an optional of the Bstats instance
|
||||
* @since 1.1
|
||||
|
|
|
@ -298,6 +298,15 @@ public class Settings implements ConfigObject {
|
|||
@ConfigEntry(path = "island.deletion.keep-previous-island-on-reset", since = "1.13.0")
|
||||
private boolean keepPreviousIslandOnReset = false;
|
||||
|
||||
@ConfigComment("Toggles how the islands are deleted.")
|
||||
@ConfigComment("* If set to 'false', all islands will be deleted at once.")
|
||||
@ConfigComment(" This is fast but may cause an impact on the performance")
|
||||
@ConfigComment(" as it'll load all the chunks of the in-deletion islands.")
|
||||
@ConfigComment("* If set to 'true', the islands will be deleted one by one.")
|
||||
@ConfigComment(" This is slower but will not cause any impact on the performance.")
|
||||
@ConfigEntry(path = "island.deletion.slow-deletion", since = "1.19.1")
|
||||
private boolean slowDeletion = false;
|
||||
|
||||
@ConfigComment("By default, If the destination is not safe, the plugin will try to search for a safe spot around the destination,")
|
||||
@ConfigComment("then it will try to expand the y-coordinate up and down from the destination.")
|
||||
@ConfigComment("This setting limits how far the y-coordinate will be expanded.")
|
||||
|
@ -905,4 +914,12 @@ public class Settings implements ConfigObject {
|
|||
public void setSafeSpotSearchVerticalRange(int safeSpotSearchVerticalRange) {
|
||||
this.safeSpotSearchVerticalRange = safeSpotSearchVerticalRange;
|
||||
}
|
||||
|
||||
public boolean isSlowDeletion() {
|
||||
return slowDeletion;
|
||||
}
|
||||
|
||||
public void setSlowDeletion(boolean slowDeletion) {
|
||||
this.slowDeletion = slowDeletion;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package world.bentobox.bentobox.managers;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
||||
import world.bentobox.bentobox.util.DeleteIslandChunks;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Manages the queue of island chunks to be deleted.
|
||||
*/
|
||||
public class IslandChunkDeletionManager implements Runnable {
|
||||
private final boolean slowDeletion;
|
||||
private final BentoBox plugin;
|
||||
private final AtomicReference<DeleteIslandChunks> currentTask;
|
||||
private final Queue<IslandDeletion> queue;
|
||||
|
||||
public IslandChunkDeletionManager(BentoBox plugin) {
|
||||
this.plugin = plugin;
|
||||
this.currentTask = new AtomicReference<>();
|
||||
this.queue = new LinkedList<>();
|
||||
this.slowDeletion = plugin.getSettings().isSlowDeletion();
|
||||
|
||||
if (slowDeletion) {
|
||||
plugin.getServer().getScheduler().runTaskTimer(plugin, this, 0L, 20L);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (queue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
DeleteIslandChunks task = this.currentTask.get();
|
||||
if (task != null && !task.isCompleted()) {
|
||||
return;
|
||||
}
|
||||
IslandDeletion islandDeletion = queue.remove();
|
||||
currentTask.set(startDeleteTask(islandDeletion));
|
||||
}
|
||||
|
||||
private DeleteIslandChunks startDeleteTask(IslandDeletion islandDeletion) {
|
||||
return new DeleteIslandChunks(plugin, islandDeletion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an island deletion to the queue.
|
||||
*
|
||||
* @param islandDeletion island deletion
|
||||
*/
|
||||
public void add(IslandDeletion islandDeletion) {
|
||||
if (slowDeletion) {
|
||||
queue.add(islandDeletion);
|
||||
} else {
|
||||
startDeleteTask(islandDeletion);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@ import world.bentobox.bentobox.api.events.island.IslandDeleteChunksEvent;
|
|||
import world.bentobox.bentobox.api.events.island.IslandDeletedEvent;
|
||||
import world.bentobox.bentobox.database.Database;
|
||||
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
||||
import world.bentobox.bentobox.util.DeleteIslandChunks;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
|
@ -57,7 +56,7 @@ public class IslandDeletionManager implements Listener {
|
|||
} else {
|
||||
plugin.log("Resuming deletion of island at " + di.getLocation().getWorld().getName() + " " + Util.xyz(di.getLocation().toVector()));
|
||||
inDeletion.add(di.getLocation());
|
||||
new DeleteIslandChunks(plugin, di);
|
||||
plugin.getIslandChunkDeletionManager().add(di);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -54,7 +54,6 @@ import world.bentobox.bentobox.database.objects.Island;
|
|||
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
||||
import world.bentobox.bentobox.lists.Flags;
|
||||
import world.bentobox.bentobox.managers.island.IslandCache;
|
||||
import world.bentobox.bentobox.util.DeleteIslandChunks;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.bentobox.util.teleport.SafeSpotTeleport;
|
||||
|
||||
|
@ -346,7 +345,7 @@ public class IslandsManager {
|
|||
// Remove players from island
|
||||
removePlayersFromIsland(island);
|
||||
// Remove blocks from world
|
||||
new DeleteIslandChunks(plugin, new IslandDeletion(island));
|
||||
plugin.getIslandChunkDeletionManager().add(new IslandDeletion(island));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,37 @@ package world.bentobox.bentobox.nms;
|
|||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
public interface NMSAbstraction {
|
||||
|
||||
/**
|
||||
* Copy the chunk data and biome grid to the given chunk.
|
||||
* @param chunk - chunk to copy to
|
||||
* @param chunkData - chunk data to copy
|
||||
* @param biomeGrid - biome grid to copy to
|
||||
* @param limitBox - bounding box to limit the copying
|
||||
*/
|
||||
default void copyChunkDataToChunk(Chunk chunk, ChunkGenerator.ChunkData chunkData, ChunkGenerator.BiomeGrid biomeGrid, BoundingBox limitBox) {
|
||||
double baseX = chunk.getX() << 4;
|
||||
double baseZ = chunk.getZ() << 4;
|
||||
int minHeight = chunk.getWorld().getMinHeight();
|
||||
int maxHeight = chunk.getWorld().getMaxHeight();
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
if (!limitBox.contains(baseX + x, 0, baseZ + z)) {
|
||||
continue;
|
||||
}
|
||||
for (int y = minHeight; y < maxHeight; y++) {
|
||||
setBlockInNativeChunk(chunk, x, y, z, chunkData.getBlockData(x, y, z), false);
|
||||
// 3D biomes, 4 blocks separated
|
||||
if (x % 4 == 0 && y % 4 == 0 && z % 4 == 0) {
|
||||
chunk.getBlock(x, y, z).setBiome(biomeGrid.getBiome(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the low-level chunk information for the given block to the new block ID and data. This
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
package world.bentobox.bentobox.nms.v1_18_R1;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData;
|
||||
|
||||
import net.minecraft.core.BlockPosition;
|
||||
import net.minecraft.world.level.World;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
import net.minecraft.world.level.chunk.Chunk;
|
||||
import world.bentobox.bentobox.nms.NMSAbstraction;
|
||||
|
||||
|
||||
public class NMSHandler implements NMSAbstraction {
|
||||
|
||||
private static final IBlockData AIR = ((CraftBlockData) Bukkit.createBlockData(Material.AIR)).getState();
|
||||
|
||||
@Override
|
||||
public void setBlockInNativeChunk(org.bukkit.Chunk chunk, int x, int y, int z, BlockData blockData, boolean applyPhysics) {
|
||||
CraftBlockData craft = (CraftBlockData) blockData;
|
||||
World nmsWorld = ((CraftWorld) chunk.getWorld()).getHandle();
|
||||
Chunk nmsChunk = nmsWorld.d(chunk.getX(), chunk.getZ());
|
||||
BlockPosition bp = new BlockPosition((chunk.getX() << 4) + x, y, (chunk.getZ() << 4) + z);
|
||||
// Setting the block to air before setting to another state prevents some console errors
|
||||
nmsChunk.a(bp, AIR, applyPhysics);
|
||||
nmsChunk.a(bp, craft.getState(), applyPhysics);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
package world.bentobox.bentobox.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
@ -13,8 +10,6 @@ import org.bukkit.generator.ChunkGenerator;
|
|||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import io.papermc.lib.PaperLib;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent;
|
||||
|
@ -22,6 +17,13 @@ import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
|
|||
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
||||
import world.bentobox.bentobox.nms.NMSAbstraction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Deletes islands chunk by chunk
|
||||
*
|
||||
|
@ -29,21 +31,23 @@ import world.bentobox.bentobox.nms.NMSAbstraction;
|
|||
*/
|
||||
public class DeleteIslandChunks {
|
||||
|
||||
private final IslandDeletion di;
|
||||
private final BentoBox plugin;
|
||||
private final World netherWorld;
|
||||
private final World endWorld;
|
||||
private final AtomicBoolean completed;
|
||||
private final NMSAbstraction nms;
|
||||
private int chunkX;
|
||||
private int chunkZ;
|
||||
private BukkitTask task;
|
||||
private final IslandDeletion di;
|
||||
private boolean inDelete;
|
||||
private final BentoBox plugin;
|
||||
private NMSAbstraction nms;
|
||||
private final World netherWorld;
|
||||
private final World endWorld;
|
||||
private CompletableFuture<Void> currentTask = CompletableFuture.completedFuture(null);
|
||||
|
||||
public DeleteIslandChunks(BentoBox plugin, IslandDeletion di) {
|
||||
this.plugin = plugin;
|
||||
this.chunkX = di.getMinXChunk();
|
||||
this.chunkZ = di.getMinZChunk();
|
||||
this.di = di;
|
||||
completed = new AtomicBoolean(false);
|
||||
// Nether
|
||||
if (plugin.getIWM().isNetherGenerate(di.getWorld()) && plugin.getIWM().isNetherIslands(di.getWorld())) {
|
||||
netherWorld = plugin.getIWM().getNetherWorld(di.getWorld());
|
||||
|
@ -57,9 +61,8 @@ public class DeleteIslandChunks {
|
|||
endWorld = null;
|
||||
}
|
||||
// NMS
|
||||
try {
|
||||
this.nms = Util.getNMS();
|
||||
} catch (Exception e) {
|
||||
this.nms = Util.getNMS();
|
||||
if (nms == null) {
|
||||
plugin.logError("Could not delete chunks because of NMS error");
|
||||
return;
|
||||
}
|
||||
|
@ -73,55 +76,58 @@ public class DeleteIslandChunks {
|
|||
private void regenerateChunks() {
|
||||
// Run through all chunks of the islands and regenerate them.
|
||||
task = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
|
||||
if (inDelete) return;
|
||||
inDelete = true;
|
||||
if (!currentTask.isDone()) return;
|
||||
if (isEnded(chunkX)) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
List<CompletableFuture<Void>> newTasks = new ArrayList<>();
|
||||
for (int i = 0; i < plugin.getSettings().getDeleteSpeed(); i++) {
|
||||
boolean last = i == plugin.getSettings().getDeleteSpeed() -1;
|
||||
if (isEnded(chunkX)) {
|
||||
break;
|
||||
}
|
||||
final int x = chunkX;
|
||||
final int z = chunkZ;
|
||||
plugin.getIWM().getAddon(di.getWorld()).ifPresent(gm ->
|
||||
// Overworld
|
||||
processChunk(gm, di.getWorld(), x, z).thenRun(() ->
|
||||
// Nether
|
||||
processChunk(gm, netherWorld, x, z).thenRun(() ->
|
||||
// End
|
||||
processChunk(gm, endWorld, x, z).thenRun(() -> finish(last, x)))));
|
||||
plugin.getIWM().getAddon(di.getWorld()).ifPresent(gm -> {
|
||||
newTasks.add(processChunk(gm, di.getWorld(), x, z)); // Overworld
|
||||
newTasks.add(processChunk(gm, netherWorld, x, z)); // Nether
|
||||
newTasks.add(processChunk(gm, endWorld, x, z)); // End
|
||||
});
|
||||
chunkZ++;
|
||||
if (chunkZ > di.getMaxZChunk()) {
|
||||
chunkZ = di.getMinZChunk();
|
||||
chunkX++;
|
||||
}
|
||||
}
|
||||
currentTask = CompletableFuture.allOf(newTasks.toArray(new CompletableFuture[0]));
|
||||
}, 0L, 20L);
|
||||
|
||||
}
|
||||
|
||||
private void finish(boolean last, int x) {
|
||||
if (x > di.getMaxXChunk()) {
|
||||
// Fire event
|
||||
IslandEvent.builder().deletedIslandInfo(di).reason(Reason.DELETED).build();
|
||||
// We're done
|
||||
task.cancel();
|
||||
}
|
||||
if (last) {
|
||||
inDelete = false;
|
||||
}
|
||||
private boolean isEnded(int chunkX) {
|
||||
return chunkX > di.getMaxXChunk();
|
||||
}
|
||||
|
||||
private CompletableFuture<Boolean> processChunk(GameModeAddon gm, World world, int x, int z) {
|
||||
private void finish() {
|
||||
// Fire event
|
||||
IslandEvent.builder().deletedIslandInfo(di).reason(Reason.DELETED).build();
|
||||
// We're done
|
||||
completed.set(true);
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> processChunk(GameModeAddon gm, World world, int x, int z) {
|
||||
if (world != null) {
|
||||
CompletableFuture<Boolean> r = new CompletableFuture<>();
|
||||
PaperLib.getChunkAtAsync(world, x, z).thenAccept(chunk -> regenerateChunk(r, gm, chunk, x, z));
|
||||
return r;
|
||||
return PaperLib.getChunkAtAsync(world, x, z).thenAccept(chunk -> regenerateChunk(gm, chunk, x, z));
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
|
||||
private void regenerateChunk(CompletableFuture<Boolean> r, GameModeAddon gm, Chunk chunk, int x, int z) {
|
||||
private void regenerateChunk(GameModeAddon gm, Chunk chunk, int x, int z) {
|
||||
// Clear all inventories
|
||||
Arrays.stream(chunk.getTileEntities()).filter(te -> (te instanceof InventoryHolder))
|
||||
.filter(te -> di.inBounds(te.getLocation().getBlockX(), te.getLocation().getBlockZ()))
|
||||
.forEach(te -> ((InventoryHolder)te).getInventory().clear());
|
||||
Arrays.stream(chunk.getTileEntities()).filter(InventoryHolder.class::isInstance)
|
||||
.filter(te -> di.inBounds(te.getLocation().getBlockX(), te.getLocation().getBlockZ()))
|
||||
.forEach(te -> ((InventoryHolder) te).getInventory().clear());
|
||||
// Remove all entities
|
||||
for (Entity e : chunk.getEntities()) {
|
||||
if (!(e instanceof Player)) {
|
||||
|
@ -133,30 +139,18 @@ public class DeleteIslandChunks {
|
|||
ChunkGenerator cg = gm.getDefaultWorldGenerator(chunk.getWorld().getName(), "delete");
|
||||
// Will be null if use-own-generator is set to true
|
||||
if (cg != null) {
|
||||
|
||||
ChunkData cd = cg.generateChunkData(chunk.getWorld(), new Random(), chunk.getX(), chunk.getZ(), grid);
|
||||
createChunk(cd, chunk, grid);
|
||||
}
|
||||
r.complete(true);
|
||||
}
|
||||
|
||||
private void createChunk(ChunkData cd, Chunk chunk, MyBiomeGrid grid) {
|
||||
int baseX = chunk.getX() << 4;
|
||||
int baseZ = chunk.getZ() << 4;
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
if (di.inBounds(baseX + x, baseZ + z)) {
|
||||
for (int y = 0; y < chunk.getWorld().getMaxHeight(); y++) {
|
||||
nms.setBlockInNativeChunk(chunk, x, y, z, cd.getBlockData(x, y, z), false);
|
||||
// 3D biomes, 4 blocks separated
|
||||
if (x%4 == 0 && y%4 == 0 && z%4 == 0) {
|
||||
chunk.getBlock(x, y, z).setBiome(grid.getBiome(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nms.copyChunkDataToChunk(chunk, cd, grid, di.getBox());
|
||||
// Remove all entities in chunk, including any dropped items as a result of clearing the blocks above
|
||||
Arrays.stream(chunk.getEntities()).filter(e -> !(e instanceof Player) && di.inBounds(e.getLocation().getBlockX(), e.getLocation().getBlockZ())).forEach(Entity::remove);
|
||||
}
|
||||
|
||||
public boolean isCompleted() {
|
||||
return completed.get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package world.bentobox.bentobox.util;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
@ -65,6 +64,7 @@ public class Util {
|
|||
private static final String THE_END = "_the_end";
|
||||
private static String serverVersion = null;
|
||||
private static BentoBox plugin = BentoBox.getInstance();
|
||||
private static NMSAbstraction nms = null;
|
||||
|
||||
private Util() {}
|
||||
|
||||
|
@ -689,33 +689,23 @@ public class Util {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks what version the server is running and picks the appropriate NMS handler, or fallback
|
||||
* @return an NMS accelerated class for this server, or a fallback Bukkit API based one
|
||||
* @throws ClassNotFoundException - thrown if there is no fallback class - should never be thrown
|
||||
* @throws SecurityException - thrown if security violation - should never be thrown
|
||||
* @throws NoSuchMethodException - thrown if no constructor for NMS package
|
||||
* @throws InvocationTargetException - should never be thrown
|
||||
* @throws IllegalArgumentException - should never be thrown
|
||||
* @throws IllegalAccessException - should never be thrown
|
||||
* @throws InstantiationException - should never be thrown
|
||||
* Set the NMS handler the plugin will use
|
||||
* @param nms the NMS handler
|
||||
*/
|
||||
public static NMSAbstraction getNMS() throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
|
||||
String serverPackageName = Bukkit.getServer().getClass().getPackage().getName();
|
||||
String pluginPackageName = plugin.getClass().getPackage().getName();
|
||||
String version = serverPackageName.substring(serverPackageName.lastIndexOf('.') + 1);
|
||||
Class<?> clazz;
|
||||
try {
|
||||
clazz = Class.forName(pluginPackageName + ".nms." + version + ".NMSHandler");
|
||||
} catch (Exception e) {
|
||||
plugin.logWarning("No NMS Handler found for " + version + ", falling back to Bukkit API.");
|
||||
clazz = Class.forName(pluginPackageName + ".nms.fallback.NMSHandler");
|
||||
}
|
||||
// Check if we have a NMSAbstraction implementing class at that location.
|
||||
if (NMSAbstraction.class.isAssignableFrom(clazz)) {
|
||||
return (NMSAbstraction) clazz.getConstructor().newInstance();
|
||||
} else {
|
||||
throw new IllegalStateException("Class " + clazz.getName() + " does not implement NMSAbstraction");
|
||||
public static void setNms(NMSAbstraction nms) {
|
||||
Util.nms = nms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the NMS handler the plugin will use
|
||||
* @return an NMS accelerated class for this server
|
||||
*/
|
||||
public static NMSAbstraction getNMS() {
|
||||
if (nms == null) {
|
||||
plugin.log("No NMS Handler was set, falling back to Bukkit API.");
|
||||
setNms(new world.bentobox.bentobox.nms.fallback.NMSHandler());
|
||||
}
|
||||
return nms;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -195,6 +195,14 @@ island:
|
|||
# This is the default behaviour.
|
||||
# Added since 1.13.0.
|
||||
keep-previous-island-on-reset: false
|
||||
# Toggles how the islands are deleted.
|
||||
# * If set to 'false', all islands will be deleted at once.
|
||||
# This is fast but may cause an impact on the performance
|
||||
# as it'll load all the chunks of the in-deletion islands.
|
||||
# * If set to 'true', the islands will be deleted one by one.
|
||||
# This is slower but will not cause any impact on the performance.
|
||||
# Added since 1.19.1.
|
||||
slow-deletion: false
|
||||
# By default, If the destination is not safe, the plugin will try to search for a safe spot around the destination,
|
||||
# then it will try to expand the y-coordinate up and down from the destination.
|
||||
# This setting limits how far the y-coordinate will be expanded.
|
||||
|
|
|
@ -67,6 +67,8 @@ public class IslandDeletionManagerTest {
|
|||
private BukkitScheduler scheduler;
|
||||
@Mock
|
||||
private IslandWorldManager iwm;
|
||||
@Mock
|
||||
private IslandChunkDeletionManager chunkDeletionManager;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -101,6 +103,8 @@ public class IslandDeletionManagerTest {
|
|||
// IWM
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
when(iwm.getIslandDistance(any())).thenReturn(64);
|
||||
// Chunk deletion manager
|
||||
when(plugin.getIslandChunkDeletionManager()).thenReturn(chunkDeletionManager);
|
||||
|
||||
// Island Deletion Manager
|
||||
idm = new IslandDeletionManager(plugin);
|
||||
|
|
|
@ -108,6 +108,8 @@ public class IslandsManagerTest {
|
|||
@Mock
|
||||
private IslandWorldManager iwm;
|
||||
@Mock
|
||||
private IslandChunkDeletionManager chunkDeletionManager;
|
||||
@Mock
|
||||
private IslandCache islandCache;
|
||||
private Optional<Island> optionalIsland;
|
||||
@Mock
|
||||
|
@ -158,6 +160,9 @@ public class IslandsManagerTest {
|
|||
when(iwm.inWorld(any(Location.class))).thenReturn(true);
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
|
||||
// Chunk deletion manager
|
||||
when(plugin.getIslandChunkDeletionManager()).thenReturn(chunkDeletionManager);
|
||||
|
||||
// Settings
|
||||
Settings s = mock(Settings.class);
|
||||
when(plugin.getSettings()).thenReturn(s);
|
||||
|
|
Loading…
Reference in New Issue