diff --git a/src/main/java/net/coreprotect/command/TeleportCommand.java b/src/main/java/net/coreprotect/command/TeleportCommand.java index e5796827e..275ffd575 100644 --- a/src/main/java/net/coreprotect/command/TeleportCommand.java +++ b/src/main/java/net/coreprotect/command/TeleportCommand.java @@ -56,6 +56,9 @@ protected static void runCommand(CommandSender player, boolean permission, Strin World world = location.getWorld(); if (wid > -1) { world = Bukkit.getServer().getWorld(WorldUtils.getWorldName(wid)); + if (world == null) { + return; + } } String x = null; @@ -100,16 +103,25 @@ else if (y == null) { location.setY(Double.parseDouble(y)); location.setZ(Double.parseDouble(z)); - int chunkX = location.getBlockX() >> 4; - int chunkZ = location.getBlockZ() >> 4; - Scheduler.runTask(CoreProtect.getInstance(), () -> { - if (!location.getWorld().isChunkLoaded(chunkX, chunkZ)) { - location.getWorld().getChunkAt(location); - } - - // Teleport the player to a safe location - Teleport.performSafeTeleport(((Player) player), location, true); - }, location); + if (ConfigHandler.isFolia) { + CoreProtect.getInstance().getServer().getRegionScheduler().run(CoreProtect.getInstance(), location, task -> { + location.getWorld().getChunkAtAsync(location).thenAccept(chunk -> { + Teleport.performSafeTeleport(((Player) player), location, true); + }); + }); + } + else { + int chunkX = location.getBlockX() >> 4; + int chunkZ = location.getBlockZ() >> 4; + Scheduler.runTask(CoreProtect.getInstance(), () -> { + if (!location.getWorld().isChunkLoaded(chunkX, chunkZ)) { + location.getWorld().getChunkAt(location); + } + + // Teleport the player to a safe location + Teleport.performSafeTeleport(((Player) player), location, true); + }, location); + } ConfigHandler.teleportThrottle.put(player.getName(), new Object[] { false, System.currentTimeMillis() }); } diff --git a/src/main/java/net/coreprotect/database/rollback/Rollback.java b/src/main/java/net/coreprotect/database/rollback/Rollback.java index 4d7d28c1a..4665f823f 100644 --- a/src/main/java/net/coreprotect/database/rollback/Rollback.java +++ b/src/main/java/net/coreprotect/database/rollback/Rollback.java @@ -10,6 +10,9 @@ import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -213,96 +216,163 @@ else if (table == 1) { // container ConfigHandler.rollbackHash.put(userString, new int[] { 0, 0, 0, 0, 0 }); final String finalUserString = userString; - for (Entry entry : DatabaseUtils.entriesSortedByValues(chunkList)) { - chunkCount++; - - int itemCount = 0; - int blockCount = 0; - int entityCount = 0; - int scannedWorldData = 0; - int[] rollbackHashData = ConfigHandler.rollbackHash.get(finalUserString); - itemCount = rollbackHashData[0]; - blockCount = rollbackHashData[1]; - entityCount = rollbackHashData[2]; - scannedWorldData = rollbackHashData[4]; - - long chunkKey = entry.getKey(); - final int finalChunkX = (int) chunkKey; - final int finalChunkZ = (int) (chunkKey >> 32); - final CommandSender finalUser = user; - - HashMap worldMap = new HashMap<>(); - for (int rollbackWorldId : worldList) { - String rollbackWorld = WorldUtils.getWorldName(rollbackWorldId); - if (rollbackWorld.length() == 0) { - continue; - } - World bukkitRollbackWorld = Bukkit.getServer().getWorld(rollbackWorld); - if (bukkitRollbackWorld == null) { - continue; + if (ConfigHandler.isFolia) { + List> chunkTasks = new ArrayList<>(); + + for (Entry entry : DatabaseUtils.entriesSortedByValues(chunkList)) { + chunkCount++; + long chunkKey = entry.getKey(); + final int finalChunkX = (int) chunkKey; + final int finalChunkZ = (int) (chunkKey >> 32); + + HashMap worldMap = new HashMap<>(); + for (int rollbackWorldId : worldList) { + String rollbackWorld = WorldUtils.getWorldName(rollbackWorldId); + if (rollbackWorld.length() == 0) { + continue; + } + + World bukkitRollbackWorld = Bukkit.getServer().getWorld(rollbackWorld); + if (bukkitRollbackWorld == null) { + continue; + } + + worldMap.put(rollbackWorldId, bukkitRollbackWorld); } - worldMap.put(rollbackWorldId, bukkitRollbackWorld); + for (Entry rollbackWorlds : worldMap.entrySet()) { + Integer rollbackWorldId = rollbackWorlds.getKey(); + World bukkitRollbackWorld = rollbackWorlds.getValue(); + Location chunkLocation = new Location(bukkitRollbackWorld, (finalChunkX << 4), 0, (finalChunkZ << 4)); + final HashMap> finalBlockList = dataList.get(rollbackWorldId); + final HashMap> finalItemList = itemDataList.get(rollbackWorldId); + + CompletableFuture chunkTask = new CompletableFuture<>(); + chunkTasks.add(chunkTask); + + Scheduler.scheduleSyncDelayedTask(CoreProtect.getInstance(), () -> { + try { + ArrayList blockData = finalBlockList != null ? finalBlockList.getOrDefault(chunkKey, new ArrayList<>()) : new ArrayList<>(); + ArrayList itemData = finalItemList != null ? finalItemList.getOrDefault(chunkKey, new ArrayList<>()) : new ArrayList<>(); + + if (!bukkitRollbackWorld.isChunkLoaded(finalChunkX, finalChunkZ)) { + bukkitRollbackWorld.getChunkAtAsync(finalChunkX, finalChunkZ).thenAccept(chunk -> { + RollbackProcessor.processChunk(finalChunkX, finalChunkZ, chunkKey, blockData, itemData, rollbackType, preview, finalUserString, user instanceof Player ? (Player) user : null, bukkitRollbackWorld, inventoryRollback); + chunkTask.complete(null); + }).exceptionally(ex -> { + chunkTask.complete(null); + return null; + }); + } else { + RollbackProcessor.processChunk(finalChunkX, finalChunkZ, chunkKey, blockData, itemData, rollbackType, preview, finalUserString, user instanceof Player ? (Player) user : null, bukkitRollbackWorld, inventoryRollback); + chunkTask.complete(null); + } + } catch (Exception e) { + chunkTask.complete(null); + } + }, chunkLocation, 0); + } } - ConfigHandler.rollbackHash.put(finalUserString, new int[] { itemCount, blockCount, entityCount, 0, scannedWorldData }); - for (Entry rollbackWorlds : worldMap.entrySet()) { - Integer rollbackWorldId = rollbackWorlds.getKey(); - World bukkitRollbackWorld = rollbackWorlds.getValue(); - Location chunkLocation = new Location(bukkitRollbackWorld, (finalChunkX << 4), 0, (finalChunkZ << 4)); - final HashMap> finalBlockList = dataList.get(rollbackWorldId); - final HashMap> finalItemList = itemDataList.get(rollbackWorldId); - - Scheduler.scheduleSyncDelayedTask(CoreProtect.getInstance(), () -> { - // Process this chunk using our new RollbackProcessor class - ArrayList blockData = finalBlockList != null ? finalBlockList.getOrDefault(chunkKey, new ArrayList<>()) : new ArrayList<>(); - ArrayList itemData = finalItemList != null ? finalItemList.getOrDefault(chunkKey, new ArrayList<>()) : new ArrayList<>(); - RollbackProcessor.processChunk(finalChunkX, finalChunkZ, chunkKey, blockData, itemData, rollbackType, preview, finalUserString, finalUser instanceof Player ? (Player) finalUser : null, bukkitRollbackWorld, inventoryRollback); - }, chunkLocation, 0); + CompletableFuture allTasks = CompletableFuture.allOf(chunkTasks.toArray(new CompletableFuture[0])); + + try { + allTasks.get(300, TimeUnit.SECONDS); + } catch (TimeoutException e) { + } catch (Exception e) { } + } else { + for (Entry entry : DatabaseUtils.entriesSortedByValues(chunkList)) { + chunkCount++; + + int itemCount = 0; + int blockCount = 0; + int entityCount = 0; + int scannedWorldData = 0; + int[] rollbackHashData = ConfigHandler.rollbackHash.get(finalUserString); + itemCount = rollbackHashData[0]; + blockCount = rollbackHashData[1]; + entityCount = rollbackHashData[2]; + scannedWorldData = rollbackHashData[4]; + + long chunkKey = entry.getKey(); + final int finalChunkX = (int) chunkKey; + final int finalChunkZ = (int) (chunkKey >> 32); + final CommandSender finalUser = user; + + HashMap worldMap = new HashMap<>(); + for (int rollbackWorldId : worldList) { + String rollbackWorld = WorldUtils.getWorldName(rollbackWorldId); + if (rollbackWorld.length() == 0) { + continue; + } - rollbackHashData = ConfigHandler.rollbackHash.get(finalUserString); - int next = rollbackHashData[3]; - int scannedWorlds = rollbackHashData[4]; - int sleepTime = 0; - int abort = 0; - - while (next == 0 || scannedWorlds < worldMap.size()) { - if (preview == 1) { - // Not actually changing blocks, so less intensive. - sleepTime = sleepTime + 1; - Thread.sleep(1); + World bukkitRollbackWorld = Bukkit.getServer().getWorld(rollbackWorld); + if (bukkitRollbackWorld == null) { + continue; + } + + worldMap.put(rollbackWorldId, bukkitRollbackWorld); } - else { - sleepTime = sleepTime + 5; - Thread.sleep(5); + + ConfigHandler.rollbackHash.put(finalUserString, new int[] { itemCount, blockCount, entityCount, 0, scannedWorldData }); + for (Entry rollbackWorlds : worldMap.entrySet()) { + Integer rollbackWorldId = rollbackWorlds.getKey(); + World bukkitRollbackWorld = rollbackWorlds.getValue(); + Location chunkLocation = new Location(bukkitRollbackWorld, (finalChunkX << 4), 0, (finalChunkZ << 4)); + final HashMap> finalBlockList = dataList.get(rollbackWorldId); + final HashMap> finalItemList = itemDataList.get(rollbackWorldId); + + Scheduler.scheduleSyncDelayedTask(CoreProtect.getInstance(), () -> { + // Process this chunk using our new RollbackProcessor class + ArrayList blockData = finalBlockList != null ? finalBlockList.getOrDefault(chunkKey, new ArrayList<>()) : new ArrayList<>(); + ArrayList itemData = finalItemList != null ? finalItemList.getOrDefault(chunkKey, new ArrayList<>()) : new ArrayList<>(); + RollbackProcessor.processChunk(finalChunkX, finalChunkZ, chunkKey, blockData, itemData, rollbackType, preview, finalUserString, finalUser instanceof Player ? (Player) finalUser : null, bukkitRollbackWorld, inventoryRollback); + }, chunkLocation, 0); } rollbackHashData = ConfigHandler.rollbackHash.get(finalUserString); - next = rollbackHashData[3]; - scannedWorlds = rollbackHashData[4]; + int next = rollbackHashData[3]; + int scannedWorlds = rollbackHashData[4]; + int sleepTime = 0; + int abort = 0; + + while (next == 0 || scannedWorlds < worldMap.size()) { + if (preview == 1) { + sleepTime = sleepTime + 1; + Thread.sleep(1); + } + else { + sleepTime = sleepTime + 5; + Thread.sleep(5); + } - if (sleepTime > 300000) { - abort = 1; - break; - } - } + rollbackHashData = ConfigHandler.rollbackHash.get(finalUserString); + next = rollbackHashData[3]; + scannedWorlds = rollbackHashData[4]; - if (abort == 1 || next == 2) { - Chat.console(Phrase.build(Phrase.ROLLBACK_ABORTED)); - break; - } + if (sleepTime > 300000) { + abort = 1; + break; + } + } - rollbackHashData = ConfigHandler.rollbackHash.get(finalUserString); - itemCount = rollbackHashData[0]; - blockCount = rollbackHashData[1]; - entityCount = rollbackHashData[2]; - ConfigHandler.rollbackHash.put(finalUserString, new int[] { itemCount, blockCount, entityCount, 0, 0 }); + if (abort == 1 || next == 2) { + Chat.console(Phrase.build(Phrase.ROLLBACK_ABORTED)); + break; + } - if (verbose && user != null && preview == 0 && !actionList.contains(11)) { - Integer chunks = chunkList.size(); - Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_CHUNKS_MODIFIED, chunkCount.toString(), chunks.toString(), (chunks == 1 ? Selector.FIRST : Selector.SECOND))); + rollbackHashData = ConfigHandler.rollbackHash.get(finalUserString); + itemCount = rollbackHashData[0]; + blockCount = rollbackHashData[1]; + entityCount = rollbackHashData[2]; + ConfigHandler.rollbackHash.put(finalUserString, new int[] { itemCount, blockCount, entityCount, 0, 0 }); + + if (verbose && user != null && preview == 0 && !actionList.contains(11)) { + Integer chunks = chunkList.size(); + Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_CHUNKS_MODIFIED, chunkCount.toString(), chunks.toString(), (chunks == 1 ? Selector.FIRST : Selector.SECOND))); + } } } diff --git a/src/main/java/net/coreprotect/database/rollback/RollbackProcessor.java b/src/main/java/net/coreprotect/database/rollback/RollbackProcessor.java index 21788c8ee..0dff9f691 100644 --- a/src/main/java/net/coreprotect/database/rollback/RollbackProcessor.java +++ b/src/main/java/net/coreprotect/database/rollback/RollbackProcessor.java @@ -182,7 +182,7 @@ else if (rowAction == 3) { // entity kill } Block block = bukkitWorld.getBlockAt(rowX, rowY, rowZ); - if (!bukkitWorld.isChunkLoaded(block.getChunk())) { + if (!ConfigHandler.isFolia && !bukkitWorld.isChunkLoaded(block.getChunk())) { bukkitWorld.getChunkAt(block.getLocation()); } @@ -346,7 +346,7 @@ else if (rowAction == ItemLogger.ITEM_REMOVE_ENDER || rowAction == ItemLogger.IT continue; } Block block = bukkitWorld.getBlockAt(rowX, rowY, rowZ); - if (!bukkitWorld.isChunkLoaded(block.getChunk())) { + if (!ConfigHandler.isFolia && !bukkitWorld.isChunkLoaded(block.getChunk())) { bukkitWorld.getChunkAt(block.getLocation()); }