From a5a2fca2fa6713cf93e3f34c093472ddf5e818ec Mon Sep 17 00:00:00 2001 From: Brettflan Date: Sat, 19 Oct 2013 22:43:07 -0500 Subject: [PATCH] Added option to Fill command which will force it to load all chunks instead of automatically skipping chunks which are already fully generated. This option was mainly added for people wanting to follow Mojang's recommendation to load all important world chunks in 1.6.3 - 1.6.4 before updating to the eventual 1.7 release to prevent errors with structures such as witch huts and nether fortresses: https://mojang.com/2013/09/minecraft-snapshot-13w37a/ --- .../java/com/wimbli/WorldBorder/Config.java | 13 ++++++-- .../com/wimbli/WorldBorder/WBCommand.java | 30 +++++++++++-------- .../com/wimbli/WorldBorder/WBListener.java | 14 +++++++++ .../com/wimbli/WorldBorder/WorldFillTask.java | 26 ++++++++++++---- 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/wimbli/WorldBorder/Config.java b/src/main/java/com/wimbli/WorldBorder/Config.java index 33a495e..27bc89a 100644 --- a/src/main/java/com/wimbli/WorldBorder/Config.java +++ b/src/main/java/com/wimbli/WorldBorder/Config.java @@ -377,9 +377,9 @@ public class Config save(false); } - public static void RestoreFillTask(String world, int fillDistance, int chunksPerRun, int tickFrequency, int x, int z, int length, int total) + public static void RestoreFillTask(String world, int fillDistance, int chunksPerRun, int tickFrequency, int x, int z, int length, int total, boolean forceLoad) { - fillTask = new WorldFillTask(plugin.getServer(), null, world, fillDistance, chunksPerRun, tickFrequency); + fillTask = new WorldFillTask(plugin.getServer(), null, world, fillDistance, chunksPerRun, tickFrequency, forceLoad); if (fillTask.valid()) { fillTask.continueProgress(x, z, length, total); @@ -387,6 +387,11 @@ public class Config fillTask.setTaskID(task); } } + // for backwards compatibility + public static void RestoreFillTask(String world, int fillDistance, int chunksPerRun, int tickFrequency, int x, int z, int length, int total) + { + RestoreFillTask(world, fillDistance, chunksPerRun, tickFrequency, x, z, length, total, false); + } public static void StopTrimTask() @@ -517,7 +522,8 @@ public class Config int fillZ = storedFillTask.getInt("z", 0); int fillLength = storedFillTask.getInt("length", 0); int fillTotal = storedFillTask.getInt("total", 0); - RestoreFillTask(worldName, fillDistance, chunksPerRun, tickFrequency, fillX, fillZ, fillLength, fillTotal); + boolean forceLoad = storedFillTask.getBoolean("forceLoad", false); + RestoreFillTask(worldName, fillDistance, chunksPerRun, tickFrequency, fillX, fillZ, fillLength, fillTotal, forceLoad); save(false); } @@ -577,6 +583,7 @@ public class Config cfg.set("fillTask.z", fillTask.refZ()); cfg.set("fillTask.length", fillTask.refLength()); cfg.set("fillTask.total", fillTask.refTotal()); + cfg.set("fillTask.forceLoad", fillTask.refForceLoad()); } else cfg.set("fillTask", null); diff --git a/src/main/java/com/wimbli/WorldBorder/WBCommand.java b/src/main/java/com/wimbli/WorldBorder/WBCommand.java index ccc00a5..48de1c7 100644 --- a/src/main/java/com/wimbli/WorldBorder/WBCommand.java +++ b/src/main/java/com/wimbli/WorldBorder/WBCommand.java @@ -577,7 +577,7 @@ public class WBCommand implements CommandExecutor if (!Config.HasPermission(player, "fill")) return true; boolean cancel = false, confirm = false, pause = false; - String pad = "", frequency = ""; + String frequency = ""; if (split.length >= 3) { cancel = split[2].equalsIgnoreCase("cancel") || split[2].equalsIgnoreCase("stop"); @@ -586,12 +586,12 @@ public class WBCommand implements CommandExecutor if (!cancel && !confirm && !pause) frequency = split[2]; } - if (split.length >= 4) - pad = split[3]; + String pad = (split.length >= 4) ? split[3] : ""; + String forceLoad = (split.length >= 5) ? split[4] : ""; String world = split[0]; - cmdFill(sender, player, world, confirm, cancel, pause, pad, frequency); + cmdFill(sender, player, world, confirm, cancel, pause, pad, frequency, forceLoad); } // "fill" command from player (or from console solely if using cancel or confirm), using current world @@ -600,7 +600,7 @@ public class WBCommand implements CommandExecutor if (!Config.HasPermission(player, "fill")) return true; boolean cancel = false, confirm = false, pause = false; - String pad = "", frequency = ""; + String frequency = ""; if (split.length >= 2) { cancel = split[1].equalsIgnoreCase("cancel") || split[1].equalsIgnoreCase("stop"); @@ -609,8 +609,8 @@ public class WBCommand implements CommandExecutor if (!cancel && !confirm && !pause) frequency = split[1]; } - if (split.length >= 3) - pad = split[2]; + String pad = (split.length >= 3) ? split[2] : ""; + String forceLoad = (split.length >= 4) ? split[3] : ""; String world = ""; if (player != null && !cancel && !confirm && !pause) @@ -618,11 +618,11 @@ public class WBCommand implements CommandExecutor if (!cancel && !confirm && !pause && world.isEmpty()) { - sender.sendMessage("You must specify a world! Example: " + cmdW+" fill " + clrOpt + "[freq] [pad]"); + sender.sendMessage("You must specify a world! Example: " + cmdW + " fill " + clrOpt + "[freq] [pad] [force]"); return true; } - cmdFill(sender, player, world, confirm, cancel, pause, pad, frequency); + cmdFill(sender, player, world, confirm, cancel, pause, pad, frequency, forceLoad); } // "trim" command from player or console, world specified @@ -821,7 +821,7 @@ public class WBCommand implements CommandExecutor if (page == 0 || page == 2) { sender.sendMessage(cmd+" list" + clrDesc + " - show border information for all worlds."); - sender.sendMessage(cmdW+" fill " + clrOpt + "[freq] [pad]" + clrDesc + " - generate world out to border."); + sender.sendMessage(cmdW+" fill " + clrOpt + "[freq] [pad] [force]" + clrDesc + " - generate world to border."); sender.sendMessage(cmdW+" trim " + clrOpt + "[freq] [pad]" + clrDesc + " - trim world outside of border."); sender.sendMessage(cmd+" bypass " + ((player == null) ? clrReq + "" : clrOpt + "[player]") + clrOpt + " [on/off]" + clrDesc + " - let player go beyond border."); sender.sendMessage(cmd+" wshape " + ((player == null) ? clrReq + "" : clrOpt + "[world]") + clrReq + " " + clrDesc + " - shape override for this world."); @@ -905,6 +905,7 @@ public class WBCommand implements CommandExecutor private String fillWorld = ""; private int fillFrequency = 20; private int fillPadding = CoordXZ.chunkToBlock(13); + private boolean fillForceLoad = false; private void fillDefaults() { @@ -913,9 +914,10 @@ public class WBCommand implements CommandExecutor // with "view-distance=10" in server.properties and "Render Distance: Far" in client, hitting border during testing // was loading 11 chunks beyond the border in a couple of directions (10 chunks in the other two directions); thus: fillPadding = CoordXZ.chunkToBlock(13); + fillForceLoad = false; } - private boolean cmdFill(CommandSender sender, Player player, String world, boolean confirm, boolean cancel, boolean pause, String pad, String frequency) + private boolean cmdFill(CommandSender sender, Player player, String world, boolean confirm, boolean cancel, boolean pause, String pad, String frequency, String forceLoad) { if (cancel) { @@ -956,6 +958,8 @@ public class WBCommand implements CommandExecutor sender.sendMessage(clrErr + "The frequency and padding values must be integers."); return false; } + if (!forceLoad.isEmpty()) + fillForceLoad = strAsBool(forceLoad); // set world if it was specified if (!world.isEmpty()) @@ -978,7 +982,7 @@ public class WBCommand implements CommandExecutor else ticks = 20 / fillFrequency; - Config.fillTask = new WorldFillTask(plugin.getServer(), player, fillWorld, fillPadding, repeats, ticks); + Config.fillTask = new WorldFillTask(plugin.getServer(), player, fillWorld, fillPadding, repeats, ticks, fillForceLoad); if (Config.fillTask.valid()) { int task = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, Config.fillTask, ticks, ticks); @@ -999,7 +1003,7 @@ public class WBCommand implements CommandExecutor } String cmd = clrCmd + ((player == null) ? "wb" : "/wb"); - sender.sendMessage(clrHead + "World generation task is ready for world \"" + fillWorld + "\", padding the map out to " + fillPadding + " blocks beyond the border (default " + CoordXZ.chunkToBlock(13) + "), and the task will try to generate up to " + fillFrequency + " chunks per second (default 20)."); + sender.sendMessage(clrHead + "World generation task is ready for world \"" + fillWorld + "\", padding the map out to " + fillPadding + " blocks beyond the border (default " + CoordXZ.chunkToBlock(13) + "), and the task will try to generate up to " + fillFrequency + " chunks per second (default 20). Parts of the world which are already fully generated will be " + (fillForceLoad ? "loaded anyway." : "skipped.")); sender.sendMessage(clrHead + "This process can take a very long time depending on the world's border size. Also, depending on the chunk processing rate, players will likely experience severe lag for the duration."); sender.sendMessage(clrDesc + "You should now use " + cmd + " fill confirm" + clrDesc + " to start the process."); sender.sendMessage(clrDesc + "You can cancel at any time with " + cmd + " fill cancel" + clrDesc + ", or pause/unpause with " + cmd + " fill pause" + clrDesc + "."); diff --git a/src/main/java/com/wimbli/WorldBorder/WBListener.java b/src/main/java/com/wimbli/WorldBorder/WBListener.java index b72f2b1..4f48564 100644 --- a/src/main/java/com/wimbli/WorldBorder/WBListener.java +++ b/src/main/java/com/wimbli/WorldBorder/WBListener.java @@ -1,5 +1,6 @@ package com.wimbli.WorldBorder; +import org.bukkit.Chunk; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -41,6 +42,19 @@ public class WBListener implements Listener @EventHandler(priority = EventPriority.MONITOR) public void onChunkLoad(ChunkLoadEvent event) { +/* // tested, found to spam pretty rapidly as client repeatedly requests the same chunks since they're not being sent + // definitely too spammy at only 16 blocks outside border + // potentially useful at standard 208 block padding as it was triggering only occasionally while trying to get out all along edge of round border, though sometimes up to 3 triggers within a second corresponding to 3 adjacent chunks + // would of course need to be further worked on to have it only affect chunks outside a border, along with an option somewhere to disable it or even set specified distance outside border for it to take effect + + // method to prevent new chunks from being generated, core method courtesy of code from NoNewChunk plugin (http://dev.bukkit.org/bukkit-plugins/nonewchunk/) + if(event.isNewChunk()) + { + Chunk chunk = event.getChunk(); + chunk.unload(false, false); + Config.LogWarn("New chunk generation has been prevented at X " + chunk.getX() + ", Z " + chunk.getZ()); + } +*/ // make sure our border monitoring task is still running like it should if (Config.isBorderTimerRunning()) return; diff --git a/src/main/java/com/wimbli/WorldBorder/WorldFillTask.java b/src/main/java/com/wimbli/WorldBorder/WorldFillTask.java index 1886e41..68c5f32 100644 --- a/src/main/java/com/wimbli/WorldBorder/WorldFillTask.java +++ b/src/main/java/com/wimbli/WorldBorder/WorldFillTask.java @@ -25,6 +25,7 @@ public class WorldFillTask implements Runnable private transient Player notifyPlayer = null; private transient int chunksPerRun = 1; private transient boolean continueNotice = false; + private transient boolean forceLoad = false; // these are only stored for saving task to config private transient int fillDistance = 208; @@ -53,13 +54,14 @@ public class WorldFillTask implements Runnable private transient int reportNum = 0; - public WorldFillTask(Server theServer, Player player, String worldName, int fillDistance, int chunksPerRun, int tickFrequency) + public WorldFillTask(Server theServer, Player player, String worldName, int fillDistance, int chunksPerRun, int tickFrequency, boolean forceLoad) { this.server = theServer; this.notifyPlayer = player; this.fillDistance = fillDistance; this.tickFrequency = tickFrequency; this.chunksPerRun = chunksPerRun; + this.forceLoad = forceLoad; this.world = server.getWorld(worldName); if (this.world == null) @@ -112,6 +114,11 @@ public class WorldFillTask implements Runnable this.readyToGo = true; } + // for backwards compatibility + public WorldFillTask(Server theServer, Player player, String worldName, int fillDistance, int chunksPerRun, int tickFrequency) + { + this(theServer, player, worldName, fillDistance, chunksPerRun, tickFrequency, false); + } public void setTaskID(int ID) { @@ -175,12 +182,15 @@ public class WorldFillTask implements Runnable } insideBorder = true; - // skip past any chunks which are confirmed as fully generated using our super-special isChunkFullyGenerated routine - while (worldData.isChunkFullyGenerated(x, z)) + if (!forceLoad) { - insideBorder = true; - if (!moveToNext()) - return; + // skip past any chunks which are confirmed as fully generated using our super-special isChunkFullyGenerated routine + while (worldData.isChunkFullyGenerated(x, z)) + { + insideBorder = true; + if (!moveToNext()) + return; + } } // load the target chunk and generate it if necessary @@ -450,4 +460,8 @@ public class WorldFillTask implements Runnable { return world.getName(); } + public boolean refForceLoad() + { + return forceLoad; + } }