Use final vars for lambdas to avoid them changing async

The processes could run async, especially when chunk loading took a
while, so using fields that could change would result in blocks being
missed, especially in the nether or end. Switching to final vars avoids
this.

Fixes https://github.com/BentoBoxWorld/BentoBox/issues/1840
This commit is contained in:
tastybento 2021-09-08 21:08:15 -07:00
parent 6bff4c8132
commit b24c1fdc86

View File

@ -77,13 +77,15 @@ public class DeleteIslandChunks {
inDelete = true; inDelete = true;
for (int i = 0; i < plugin.getSettings().getDeleteSpeed(); i++) { for (int i = 0; i < plugin.getSettings().getDeleteSpeed(); i++) {
boolean last = i == plugin.getSettings().getDeleteSpeed() -1; boolean last = i == plugin.getSettings().getDeleteSpeed() -1;
final int x = chunkX;
final int z = chunkZ;
plugin.getIWM().getAddon(di.getWorld()).ifPresent(gm -> plugin.getIWM().getAddon(di.getWorld()).ifPresent(gm ->
// Overworld // Overworld
processChunk(gm, di.getWorld(), chunkX, chunkZ).thenRun(() -> processChunk(gm, di.getWorld(), x, z).thenRun(() ->
// Nether // Nether
processChunk(gm, netherWorld, chunkX, chunkZ).thenRun(() -> processChunk(gm, netherWorld, x, z).thenRun(() ->
// End // End
processChunk(gm, endWorld, chunkX, chunkZ).thenRun(() -> finish(last))))); processChunk(gm, endWorld, x, z).thenRun(() -> finish(last, x)))));
chunkZ++; chunkZ++;
if (chunkZ > di.getMaxZChunk()) { if (chunkZ > di.getMaxZChunk()) {
chunkZ = di.getMinZChunk(); chunkZ = di.getMinZChunk();
@ -94,8 +96,8 @@ public class DeleteIslandChunks {
} }
private void finish(boolean last) { private void finish(boolean last, int x) {
if (chunkX > di.getMaxXChunk()) { if (x > di.getMaxXChunk()) {
// Fire event // Fire event
IslandEvent.builder().deletedIslandInfo(di).reason(Reason.DELETED).build(); IslandEvent.builder().deletedIslandInfo(di).reason(Reason.DELETED).build();
// We're done // We're done
@ -107,19 +109,25 @@ public class DeleteIslandChunks {
} }
private CompletableFuture<Boolean> processChunk(GameModeAddon gm, World world, int x, int z) { private CompletableFuture<Boolean> processChunk(GameModeAddon gm, World world, int x, int z) {
if (world != null && PaperLib.isChunkGenerated(world, x, z)) { if (world != null) {
CompletableFuture<Boolean> r = new CompletableFuture<>(); CompletableFuture<Boolean> r = new CompletableFuture<>();
PaperLib.getChunkAtAsync(world, x, z).thenAccept(chunk -> regenerateChunk(r, gm, chunk)); PaperLib.getChunkAtAsync(world, x, z).thenAccept(chunk -> regenerateChunk(r, gm, chunk, x, z));
return r; return r;
} }
return CompletableFuture.completedFuture(false); return CompletableFuture.completedFuture(false);
} }
private void regenerateChunk(CompletableFuture<Boolean> r, GameModeAddon gm, Chunk chunk) { private void regenerateChunk(CompletableFuture<Boolean> r, GameModeAddon gm, Chunk chunk, int x, int z) {
// Clear all inventories // Clear all inventories
Arrays.stream(chunk.getTileEntities()).filter(te -> (te instanceof InventoryHolder)) Arrays.stream(chunk.getTileEntities()).filter(te -> (te instanceof InventoryHolder))
.filter(te -> di.inBounds(te.getLocation().getBlockX(), te.getLocation().getBlockZ())) .filter(te -> di.inBounds(te.getLocation().getBlockX(), te.getLocation().getBlockZ()))
.forEach(te -> ((InventoryHolder)te).getInventory().clear()); .forEach(te -> ((InventoryHolder)te).getInventory().clear());
// Remove all entities
for (Entity e : chunk.getEntities()) {
if (!(e instanceof Player)) {
e.remove();
}
}
// Reset blocks // Reset blocks
MyBiomeGrid grid = new MyBiomeGrid(chunk.getWorld().getEnvironment()); MyBiomeGrid grid = new MyBiomeGrid(chunk.getWorld().getEnvironment());
ChunkGenerator cg = gm.getDefaultWorldGenerator(chunk.getWorld().getName(), "delete"); ChunkGenerator cg = gm.getDefaultWorldGenerator(chunk.getWorld().getName(), "delete");