From d34dc240dc6542222273d1663c49a03be00ff4c7 Mon Sep 17 00:00:00 2001 From: Sn0wStorm Date: Sat, 28 Nov 2020 00:47:53 +0100 Subject: [PATCH] Async Saving on World Unload --- src/com/dre/brewery/BCauldron.java | 16 ++++-- src/com/dre/brewery/Barrel.java | 25 +++++---- src/com/dre/brewery/Wakeup.java | 10 +++- src/com/dre/brewery/filedata/DataSave.java | 53 +++++++++++++------ .../dre/brewery/listeners/WorldListener.java | 16 +++--- 5 files changed, 81 insertions(+), 39 deletions(-) diff --git a/src/com/dre/brewery/BCauldron.java b/src/com/dre/brewery/BCauldron.java index 93db60be..fae52c6d 100644 --- a/src/com/dre/brewery/BCauldron.java +++ b/src/com/dre/brewery/BCauldron.java @@ -507,14 +507,22 @@ public static boolean remove(Block block) { /** * Are any Cauldrons in that World */ - public static boolean hasDataInWorld(String name) { - return bcauldrons.keySet().stream().anyMatch(block -> block.getWorld().getName().equals(name)); + public static boolean hasDataInWorld(World world) { + return bcauldrons.keySet().stream().anyMatch(block -> block.getWorld().equals(world)); } // unloads cauldrons that are in a unloading world // as they were written to file just before, this is safe to do - public static void onUnload(String name) { - bcauldrons.keySet().removeIf(block -> block.getWorld().getName().equals(name)); + public static void onUnload(World world) { + bcauldrons.keySet().removeIf(block -> block.getWorld().equals(world)); + } + + /** + * Unload all Cauldrons that have are in a unloaded World + */ + public static void unloadWorlds() { + List worlds = P.p.getServer().getWorlds(); + bcauldrons.keySet().removeIf(block -> !worlds.contains(block.getWorld())); } public static void save(ConfigurationSection config, ConfigurationSection oldData) { diff --git a/src/com/dre/brewery/Barrel.java b/src/com/dre/brewery/Barrel.java index a00734c5..0c880f1d 100644 --- a/src/com/dre/brewery/Barrel.java +++ b/src/com/dre/brewery/Barrel.java @@ -14,6 +14,7 @@ import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.SoundCategory; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.HumanEntity; @@ -125,13 +126,9 @@ public boolean hasPermsOpen(Player player, PlayerInteractEvent event) { // Call event BarrelAccessEvent accessEvent = new BarrelAccessEvent(this, player, event.getClickedBlock(), event.getBlockFace()); - // Listened to by WGBarrel7, WGBarrelNew, WGBarrelOld, GriefPreventionBarrel (IntegrationListener) + // Listened to by IntegrationListener P.p.getServer().getPluginManager().callEvent(accessEvent); - if (accessEvent.isCancelled()) { - return false; - } - - return true; + return !accessEvent.isCancelled(); } /** @@ -475,15 +472,23 @@ public Block getBrokenBlock(boolean force) { /** * Are any Barrels in that World */ - public static boolean hasDataInWorld(String name) { - return barrels.stream().anyMatch(barrel -> barrel.spigot.getWorld().getName().equals(name)); + public static boolean hasDataInWorld(World world) { + return barrels.stream().anyMatch(barrel -> barrel.spigot.getWorld().equals(world)); } /** * unloads barrels that are in a unloading world */ - public static void onUnload(String name) { - barrels.removeIf(barrel -> barrel.spigot.getWorld().getName().equals(name)); + public static void onUnload(World world) { + barrels.removeIf(barrel -> barrel.spigot.getWorld().equals(world)); + } + + /** + * Unload all Barrels that have a Block in a unloaded World + */ + public static void unloadWorlds() { + List worlds = P.p.getServer().getWorlds(); + barrels.removeIf(barrel -> !worlds.contains(barrel.spigot.getWorld())); } /** diff --git a/src/com/dre/brewery/Wakeup.java b/src/com/dre/brewery/Wakeup.java index 75583c0d..d5773184 100644 --- a/src/com/dre/brewery/Wakeup.java +++ b/src/com/dre/brewery/Wakeup.java @@ -2,6 +2,7 @@ import com.dre.brewery.utility.BUtil; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; @@ -266,8 +267,13 @@ public static void save(ConfigurationSection section, ConfigurationSection oldDa } } - public static void onUnload(String worldName) { - wakeups.removeIf(wakeup -> wakeup.loc.getWorld().getName().equals(worldName)); + public static void onUnload(World world) { + wakeups.removeIf(wakeup -> wakeup.loc.getWorld().equals(world)); + } + + public static void unloadWorlds() { + List worlds = P.p.getServer().getWorlds(); + wakeups.removeIf(wakeup -> !worlds.contains(wakeup.loc.getWorld())); } } diff --git a/src/com/dre/brewery/filedata/DataSave.java b/src/com/dre/brewery/filedata/DataSave.java index 6d33cb0c..9135baae 100644 --- a/src/com/dre/brewery/filedata/DataSave.java +++ b/src/com/dre/brewery/filedata/DataSave.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; public class DataSave extends BukkitRunnable { @@ -19,18 +20,22 @@ public class DataSave extends BukkitRunnable { public static int autosave = 3; final public static String dataVersion = "1.2"; public static DataSave running; + public static List unloadingWorlds = new CopyOnWriteArrayList<>(); public ReadOldData read; - private long time; + private final long time; + private final List loadedWorlds; public boolean collected = false; // Not Thread-Safe! Needs to be run in main thread but uses async Read/Write public DataSave(ReadOldData read) { this.read = read; time = System.currentTimeMillis(); + loadedWorlds = P.p.getServer().getWorlds(); } + // Running in Main Thread @Override public void run() { try { @@ -107,6 +112,20 @@ public void run() { collected = true; + if (!unloadingWorlds.isEmpty()) { + try { + for (World world : unloadingWorlds) { + // In the very most cases, it is just one world, so just looping like this is fine + Barrel.onUnload(world); + BCauldron.onUnload(world); + Wakeup.onUnload(world); + } + } catch (Exception e) { + e.printStackTrace(); + } + unloadingWorlds.clear(); + } + P.p.debugLog("saving: " + ((System.nanoTime() - saveTime) / 1000000.0) + "ms"); if (P.p.isEnabled()) { @@ -121,6 +140,22 @@ public void run() { } } + public void saveWorldNames(FileConfiguration root, ConfigurationSection old) { + if (old != null) { + root.set("Worlds", old); + } + for (World world : loadedWorlds) { + String worldName = world.getName(); + if (worldName.startsWith("DXL_")) { + worldName = BUtil.getDxlName(worldName); + root.set("Worlds." + worldName, 0); + } else { + worldName = world.getUID().toString(); + root.set("Worlds." + worldName, world.getName()); + } + } + } + // Finish the collection of data immediately public void now() { if (!read.done) { @@ -164,20 +199,4 @@ public static void autoSave() { lastSave++; } } - - public static void saveWorldNames(FileConfiguration root, ConfigurationSection old) { - if (old != null) { - root.set("Worlds", old); - } - for (World world : P.p.getServer().getWorlds()) { - String worldName = world.getName(); - if (worldName.startsWith("DXL_")) { - worldName = BUtil.getDxlName(worldName); - root.set("Worlds." + worldName, 0); - } else { - worldName = world.getUID().toString(); - root.set("Worlds." + worldName, world.getName()); - } - } - } } diff --git a/src/com/dre/brewery/listeners/WorldListener.java b/src/com/dre/brewery/listeners/WorldListener.java index e9988ec2..1455b2cb 100644 --- a/src/com/dre/brewery/listeners/WorldListener.java +++ b/src/com/dre/brewery/listeners/WorldListener.java @@ -45,13 +45,17 @@ private void lwDataTask(World world) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onWorldUnload(WorldUnloadEvent event) { - String worldName = event.getWorld().getName(); - if (Barrel.hasDataInWorld(worldName) || BCauldron.hasDataInWorld(worldName)) { - DataSave.save(true); - Barrel.onUnload(worldName); - BCauldron.onUnload(worldName); + World world = event.getWorld(); + if (DataSave.running == null) { + // No datasave running, save data if we have any in that world + if (Barrel.hasDataInWorld(world) || BCauldron.hasDataInWorld(world)) { + DataSave.unloadingWorlds.add(world); + DataSave.save(false); + } + } else { + // already running, tell it to unload world + DataSave.unloadingWorlds.add(world); } - Wakeup.onUnload(worldName); } }