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/
This commit is contained in:
Brettflan 2013-10-19 22:43:07 -05:00
parent 97aca7a5bb
commit a5a2fca2fa
4 changed files with 61 additions and 22 deletions

View File

@ -377,9 +377,9 @@ public class Config
save(false); 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()) if (fillTask.valid())
{ {
fillTask.continueProgress(x, z, length, total); fillTask.continueProgress(x, z, length, total);
@ -387,6 +387,11 @@ public class Config
fillTask.setTaskID(task); 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() public static void StopTrimTask()
@ -517,7 +522,8 @@ public class Config
int fillZ = storedFillTask.getInt("z", 0); int fillZ = storedFillTask.getInt("z", 0);
int fillLength = storedFillTask.getInt("length", 0); int fillLength = storedFillTask.getInt("length", 0);
int fillTotal = storedFillTask.getInt("total", 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); save(false);
} }
@ -577,6 +583,7 @@ public class Config
cfg.set("fillTask.z", fillTask.refZ()); cfg.set("fillTask.z", fillTask.refZ());
cfg.set("fillTask.length", fillTask.refLength()); cfg.set("fillTask.length", fillTask.refLength());
cfg.set("fillTask.total", fillTask.refTotal()); cfg.set("fillTask.total", fillTask.refTotal());
cfg.set("fillTask.forceLoad", fillTask.refForceLoad());
} }
else else
cfg.set("fillTask", null); cfg.set("fillTask", null);

View File

@ -577,7 +577,7 @@ public class WBCommand implements CommandExecutor
if (!Config.HasPermission(player, "fill")) return true; if (!Config.HasPermission(player, "fill")) return true;
boolean cancel = false, confirm = false, pause = false; boolean cancel = false, confirm = false, pause = false;
String pad = "", frequency = ""; String frequency = "";
if (split.length >= 3) if (split.length >= 3)
{ {
cancel = split[2].equalsIgnoreCase("cancel") || split[2].equalsIgnoreCase("stop"); cancel = split[2].equalsIgnoreCase("cancel") || split[2].equalsIgnoreCase("stop");
@ -586,12 +586,12 @@ public class WBCommand implements CommandExecutor
if (!cancel && !confirm && !pause) if (!cancel && !confirm && !pause)
frequency = split[2]; frequency = split[2];
} }
if (split.length >= 4) String pad = (split.length >= 4) ? split[3] : "";
pad = split[3]; String forceLoad = (split.length >= 5) ? split[4] : "";
String world = split[0]; 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 // "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; if (!Config.HasPermission(player, "fill")) return true;
boolean cancel = false, confirm = false, pause = false; boolean cancel = false, confirm = false, pause = false;
String pad = "", frequency = ""; String frequency = "";
if (split.length >= 2) if (split.length >= 2)
{ {
cancel = split[1].equalsIgnoreCase("cancel") || split[1].equalsIgnoreCase("stop"); cancel = split[1].equalsIgnoreCase("cancel") || split[1].equalsIgnoreCase("stop");
@ -609,8 +609,8 @@ public class WBCommand implements CommandExecutor
if (!cancel && !confirm && !pause) if (!cancel && !confirm && !pause)
frequency = split[1]; frequency = split[1];
} }
if (split.length >= 3) String pad = (split.length >= 3) ? split[2] : "";
pad = split[2]; String forceLoad = (split.length >= 4) ? split[3] : "";
String world = ""; String world = "";
if (player != null && !cancel && !confirm && !pause) if (player != null && !cancel && !confirm && !pause)
@ -618,11 +618,11 @@ public class WBCommand implements CommandExecutor
if (!cancel && !confirm && !pause && world.isEmpty()) 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; 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 // "trim" command from player or console, world specified
@ -821,7 +821,7 @@ public class WBCommand implements CommandExecutor
if (page == 0 || page == 2) if (page == 0 || page == 2)
{ {
sender.sendMessage(cmd+" list" + clrDesc + " - show border information for all worlds."); 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(cmdW+" trim " + clrOpt + "[freq] [pad]" + clrDesc + " - trim world outside of border.");
sender.sendMessage(cmd+" bypass " + ((player == null) ? clrReq + "<player>" : clrOpt + "[player]") + clrOpt + " [on/off]" + clrDesc + " - let player go beyond border."); sender.sendMessage(cmd+" bypass " + ((player == null) ? clrReq + "<player>" : clrOpt + "[player]") + clrOpt + " [on/off]" + clrDesc + " - let player go beyond border.");
sender.sendMessage(cmd+" wshape " + ((player == null) ? clrReq + "<world>" : clrOpt + "[world]") + clrReq + " <elliptic|rectangular|default>" + clrDesc + " - shape override for this world."); sender.sendMessage(cmd+" wshape " + ((player == null) ? clrReq + "<world>" : clrOpt + "[world]") + clrReq + " <elliptic|rectangular|default>" + clrDesc + " - shape override for this world.");
@ -905,6 +905,7 @@ public class WBCommand implements CommandExecutor
private String fillWorld = ""; private String fillWorld = "";
private int fillFrequency = 20; private int fillFrequency = 20;
private int fillPadding = CoordXZ.chunkToBlock(13); private int fillPadding = CoordXZ.chunkToBlock(13);
private boolean fillForceLoad = false;
private void fillDefaults() 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 // 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: // was loading 11 chunks beyond the border in a couple of directions (10 chunks in the other two directions); thus:
fillPadding = CoordXZ.chunkToBlock(13); 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) if (cancel)
{ {
@ -956,6 +958,8 @@ public class WBCommand implements CommandExecutor
sender.sendMessage(clrErr + "The frequency and padding values must be integers."); sender.sendMessage(clrErr + "The frequency and padding values must be integers.");
return false; return false;
} }
if (!forceLoad.isEmpty())
fillForceLoad = strAsBool(forceLoad);
// set world if it was specified // set world if it was specified
if (!world.isEmpty()) if (!world.isEmpty())
@ -978,7 +982,7 @@ public class WBCommand implements CommandExecutor
else else
ticks = 20 / fillFrequency; 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()) if (Config.fillTask.valid())
{ {
int task = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, Config.fillTask, ticks, ticks); 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"); 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(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 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 + "."); sender.sendMessage(clrDesc + "You can cancel at any time with " + cmd + " fill cancel" + clrDesc + ", or pause/unpause with " + cmd + " fill pause" + clrDesc + ".");

View File

@ -1,5 +1,6 @@
package com.wimbli.WorldBorder; package com.wimbli.WorldBorder;
import org.bukkit.Chunk;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -41,6 +42,19 @@ public class WBListener implements Listener
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR)
public void onChunkLoad(ChunkLoadEvent event) 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 // make sure our border monitoring task is still running like it should
if (Config.isBorderTimerRunning()) return; if (Config.isBorderTimerRunning()) return;

View File

@ -25,6 +25,7 @@ public class WorldFillTask implements Runnable
private transient Player notifyPlayer = null; private transient Player notifyPlayer = null;
private transient int chunksPerRun = 1; private transient int chunksPerRun = 1;
private transient boolean continueNotice = false; private transient boolean continueNotice = false;
private transient boolean forceLoad = false;
// these are only stored for saving task to config // these are only stored for saving task to config
private transient int fillDistance = 208; private transient int fillDistance = 208;
@ -53,13 +54,14 @@ public class WorldFillTask implements Runnable
private transient int reportNum = 0; 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.server = theServer;
this.notifyPlayer = player; this.notifyPlayer = player;
this.fillDistance = fillDistance; this.fillDistance = fillDistance;
this.tickFrequency = tickFrequency; this.tickFrequency = tickFrequency;
this.chunksPerRun = chunksPerRun; this.chunksPerRun = chunksPerRun;
this.forceLoad = forceLoad;
this.world = server.getWorld(worldName); this.world = server.getWorld(worldName);
if (this.world == null) if (this.world == null)
@ -112,6 +114,11 @@ public class WorldFillTask implements Runnable
this.readyToGo = true; 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) public void setTaskID(int ID)
{ {
@ -175,6 +182,8 @@ public class WorldFillTask implements Runnable
} }
insideBorder = true; insideBorder = true;
if (!forceLoad)
{
// skip past any chunks which are confirmed as fully generated using our super-special isChunkFullyGenerated routine // skip past any chunks which are confirmed as fully generated using our super-special isChunkFullyGenerated routine
while (worldData.isChunkFullyGenerated(x, z)) while (worldData.isChunkFullyGenerated(x, z))
{ {
@ -182,6 +191,7 @@ public class WorldFillTask implements Runnable
if (!moveToNext()) if (!moveToNext())
return; return;
} }
}
// load the target chunk and generate it if necessary // load the target chunk and generate it if necessary
world.loadChunk(x, z, true); world.loadChunk(x, z, true);
@ -450,4 +460,8 @@ public class WorldFillTask implements Runnable
{ {
return world.getName(); return world.getName();
} }
public boolean refForceLoad()
{
return forceLoad;
}
} }