From 95c7220f4ad661b7f26d3fbadb264e3bb63799f1 Mon Sep 17 00:00:00 2001 From: Daniel Saukel Date: Sun, 19 Apr 2020 00:21:43 +0200 Subject: [PATCH] Add a delay between unloading and saving edit worlds (WIP) --- .../de/erethon/dungeonsxl/DungeonsXL.java | 3 +- .../erethon/dungeonsxl/config/MainConfig.java | 22 ++++++++- .../dungeonsxl/player/DEditPlayer.java | 2 +- .../erethon/dungeonsxl/world/DEditWorld.java | 47 ++++++++++++++++++- .../dungeonsxl/world/DResourceWorld.java | 18 ++++++- .../de/erethon/dungeonsxl/world/SignData.java | 4 +- 6 files changed, 88 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/de/erethon/dungeonsxl/DungeonsXL.java b/core/src/main/java/de/erethon/dungeonsxl/DungeonsXL.java index 0b1ce3ab..35e17315 100644 --- a/core/src/main/java/de/erethon/dungeonsxl/DungeonsXL.java +++ b/core/src/main/java/de/erethon/dungeonsxl/DungeonsXL.java @@ -80,6 +80,7 @@ import de.erethon.dungeonsxl.trigger.TriggerListener; import de.erethon.dungeonsxl.trigger.TriggerTypeCache; import de.erethon.dungeonsxl.util.LWCUtil; import de.erethon.dungeonsxl.util.PlaceholderUtil; +import de.erethon.dungeonsxl.world.DEditWorld; import de.erethon.dungeonsxl.world.DResourceWorld; import de.erethon.dungeonsxl.world.DWorldListener; import de.erethon.dungeonsxl.world.LWCIntegration; @@ -436,7 +437,7 @@ public class DungeonsXL extends DREPlugin implements DungeonsAPI { public void saveData() { protections.saveAll(); - instanceCache.getAllIf(i -> i instanceof EditWorld).forEach(i -> ((EditWorld) i).save()); + instanceCache.getAllIf(i -> i instanceof EditWorld).forEach(i -> ((DEditWorld) i).forceSave()); } public void loadData() { diff --git a/core/src/main/java/de/erethon/dungeonsxl/config/MainConfig.java b/core/src/main/java/de/erethon/dungeonsxl/config/MainConfig.java index 980b10ab..ca19d4d5 100644 --- a/core/src/main/java/de/erethon/dungeonsxl/config/MainConfig.java +++ b/core/src/main/java/de/erethon/dungeonsxl/config/MainConfig.java @@ -48,7 +48,7 @@ public class MainConfig extends DREConfig { NEVER } - public static final int CONFIG_VERSION = 17; + public static final int CONFIG_VERSION = 18; private String language = "english"; private boolean enableEconomy = false; @@ -96,6 +96,7 @@ public class MainConfig extends DREConfig { /* Performance */ private int maxInstances = 10; + private int editInstanceRemovalDelay = 5; /* Secure Mode */ private boolean secureModeEnabled = false; @@ -385,6 +386,20 @@ public class MainConfig extends DREConfig { this.maxInstances = maxInstances; } + /** + * @return the delay in seconds until an edit world without players is saved and removed + */ + public int getEditInstanceRemovalDelay() { + return editInstanceRemovalDelay; + } + + /** + * @param delay the delay in seconds until an edit world without players is saved and removed + */ + public void setEditInstanceRemovalDelay(int delay) { + editInstanceRemovalDelay = delay; + } + /** * @return if the secure mode is enabled */ @@ -559,6 +574,10 @@ public class MainConfig extends DREConfig { config.set("maxInstances", maxInstances); } + if (!config.contains("editInstanceRemovalDelay")) { + config.set("editInstanceRemovalDelay", editInstanceRemovalDelay); + } + if (!config.contains("secureMode.enabled")) { config.set("secureMode.enabled", secureModeEnabled); } @@ -647,6 +666,7 @@ public class MainConfig extends DREConfig { } maxInstances = config.getInt("maxInstances", maxInstances); + editInstanceRemovalDelay = config.getInt("editInstanceRemovalDelay", editInstanceRemovalDelay); secureModeEnabled = config.getBoolean("secureMode.enabled", secureModeEnabled); openInventories = config.getBoolean("secureMode.openInventories", openInventories); dropItems = config.getBoolean("secureMode.dropItems", dropItems); diff --git a/core/src/main/java/de/erethon/dungeonsxl/player/DEditPlayer.java b/core/src/main/java/de/erethon/dungeonsxl/player/DEditPlayer.java index acbda58d..0a1e73cb 100644 --- a/core/src/main/java/de/erethon/dungeonsxl/player/DEditPlayer.java +++ b/core/src/main/java/de/erethon/dungeonsxl/player/DEditPlayer.java @@ -143,7 +143,7 @@ public class DEditPlayer extends DInstancePlayer implements EditPlayer { reset(false); - if (editWorld != null) { + if (editWorld != null && editWorld.getPlayers().isEmpty()) { editWorld.save(); } } diff --git a/core/src/main/java/de/erethon/dungeonsxl/world/DEditWorld.java b/core/src/main/java/de/erethon/dungeonsxl/world/DEditWorld.java index bb94f07d..7df6e6e4 100644 --- a/core/src/main/java/de/erethon/dungeonsxl/world/DEditWorld.java +++ b/core/src/main/java/de/erethon/dungeonsxl/world/DEditWorld.java @@ -18,16 +18,20 @@ package de.erethon.dungeonsxl.world; import de.erethon.commons.compatibility.Version; import de.erethon.commons.misc.FileUtil; +import de.erethon.commons.misc.ProgressBar; import de.erethon.dungeonsxl.DungeonsXL; import de.erethon.dungeonsxl.api.event.world.EditWorldSaveEvent; import de.erethon.dungeonsxl.api.event.world.EditWorldUnloadEvent; import de.erethon.dungeonsxl.api.world.EditWorld; +import de.erethon.dungeonsxl.player.DEditPlayer; import java.io.File; import java.io.IOException; +import java.util.List; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; +import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; /** @@ -87,7 +91,40 @@ public class DEditWorld extends DInstanceWorld implements EditWorld { public void save() { EditWorldSaveEvent event = new EditWorldSaveEvent(this); Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + plugin.setLoadingWorld(true); + List players = getWorld().getPlayers(); + kickAllPlayers(); + + getResource().editWorld = null; + plugin.getInstanceCache().remove(this); + getResource().getSignData().serializeSigns(signs.values()); + Bukkit.unloadWorld(getWorld(), true); + new ProgressBar(players, plugin.getMainConfig().getEditInstanceRemovalDelay()) { + @Override + public void onFinish() { + getResource().clearFolder(); + FileUtil.copyDir(getFolder(), getResource().getFolder(), DungeonsXL.EXCLUDED_FILES); + DResourceWorld.deleteUnusedFiles(getResource().getFolder()); + FileUtil.removeDir(getFolder()); + + EditWorld newEditWorld = getResource().getOrInstantiateEditWorld(true); + players.forEach(p -> { + if (p.isOnline()) { + new DEditPlayer(plugin, p, newEditWorld); + } + }); + plugin.setLoadingWorld(false); + } + }.send(plugin); + } + + public void forceSave() { + EditWorldSaveEvent event = new EditWorldSaveEvent(this); + Bukkit.getPluginManager().callEvent(event); if (event.isCancelled()) { return; } @@ -116,10 +153,12 @@ public class DEditWorld extends DInstanceWorld implements EditWorld { kickAllPlayers(); if (save) { + getResource().getSignData().serializeSigns(signs.values()); Bukkit.unloadWorld(getWorld(), true); new BukkitRunnable() { @Override public void run() { + getResource().clearFolder(); FileUtil.copyDir(getFolder(), getResource().getFolder(), DungeonsXL.EXCLUDED_FILES); DResourceWorld.deleteUnusedFiles(getResource().getFolder()); FileUtil.removeDir(getFolder()); @@ -128,8 +167,12 @@ public class DEditWorld extends DInstanceWorld implements EditWorld { } if (!save) { Bukkit.unloadWorld(getWorld(), /* SPIGOT-5225 */ !Version.isAtLeast(Version.MC1_14_4)); - DResourceWorld.deleteUnusedFiles(getResource().getFolder()); - FileUtil.removeDir(getFolder()); + new BukkitRunnable() { + @Override + public void run() { + FileUtil.removeDir(getFolder()); + } + }.runTaskLaterAsynchronously(plugin, 200L); } getResource().editWorld = null; diff --git a/core/src/main/java/de/erethon/dungeonsxl/world/DResourceWorld.java b/core/src/main/java/de/erethon/dungeonsxl/world/DResourceWorld.java index 3f3d44a4..a156ba61 100644 --- a/core/src/main/java/de/erethon/dungeonsxl/world/DResourceWorld.java +++ b/core/src/main/java/de/erethon/dungeonsxl/world/DResourceWorld.java @@ -65,7 +65,7 @@ public class DResourceWorld implements ResourceWorld { config = new WorldConfig(plugin, configFile); } - signData = new SignData(new File(folder, "DXLData.data")); + signData = new SignData(new File(folder, SignData.FILE_NAME)); } public DResourceWorld(DungeonsXL plugin, File folder) { @@ -78,7 +78,7 @@ public class DResourceWorld implements ResourceWorld { config = new WorldConfig(plugin, configFile); } - signData = new SignData(new File(folder, "DXLData.data")); + signData = new SignData(new File(folder, SignData.FILE_NAME)); } /* Getters and setters */ @@ -211,6 +211,7 @@ public class DResourceWorld implements ResourceWorld { if (game) { signData.deserializeSigns((DGameWorld) instance); + instance.getWorld().setAutoSave(false); } else { signData.deserializeSigns((DEditWorld) instance); } @@ -297,6 +298,19 @@ public class DResourceWorld implements ResourceWorld { return editWorld; } + void clearFolder() { + for (File file : FileUtil.getFilesForFolder(getFolder())) { + if (file.getName().equals(SignData.FILE_NAME)) { + continue; + } + if (file.isDirectory()) { + FileUtil.removeDir(file); + } else { + file.delete(); + } + } + } + /** * Removes files that are not needed from a world * diff --git a/core/src/main/java/de/erethon/dungeonsxl/world/SignData.java b/core/src/main/java/de/erethon/dungeonsxl/world/SignData.java index c847470d..93993e94 100644 --- a/core/src/main/java/de/erethon/dungeonsxl/world/SignData.java +++ b/core/src/main/java/de/erethon/dungeonsxl/world/SignData.java @@ -36,6 +36,8 @@ import org.bukkit.block.Sign; */ public class SignData { + public static final String FILE_NAME = "DXLData.data"; + private File file; public SignData(File file) { @@ -55,7 +57,7 @@ public class SignData { } public void updateFile(DResourceWorld resource) { - file = new File(resource.getFolder(), "DXLData.data"); + file = new File(resource.getFolder(), FILE_NAME); } /**