diff --git a/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java b/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java index 7984de22f..0b141edab 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java @@ -32,6 +32,9 @@ import java.util.UUID; import org.apache.commons.lang.StringUtils; import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.Biome; import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.config.C; @@ -39,6 +42,7 @@ import com.intellectualcrafters.plot.flag.FlagManager; import com.intellectualcrafters.plot.generator.BukkitHybridUtils; import com.intellectualcrafters.plot.generator.HybridUtils; import com.intellectualcrafters.plot.object.ChunkLoc; +import com.intellectualcrafters.plot.object.Location; import com.intellectualcrafters.plot.object.OfflinePlotPlayer; import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.PlotAnalysis; @@ -61,6 +65,24 @@ public class DebugExec extends SubCommand { if (args.length > 0) { final String arg = args[0].toLowerCase(); switch (arg) { + case "biome": { + if (player == null) { + MainUtil.sendMessage(player, C.IS_CONSOLE); + return false; + } + Location loc = player.getLocation(); + World world = Bukkit.getWorld(loc.getWorld()); + int bx = (loc.getX() >> 4) << 4; + int bz = (loc.getZ() >> 4) << 4; + for (int x = bx; x < bx + 16; x++) { + for (int z = bz; z < bz + 16; z++) { + world.setBiome(x, z, Biome.DESERT); + } + } + MainUtil.update(loc.getWorld(), new ChunkLoc(loc.getX() >> 4, loc.getZ() >> 4)); + System.out.print("SET BIOME TO FOREST: " + bx + "," + bz); + return true; + } case "analyze": { if (player == null) { MainUtil.sendMessage(player, C.IS_CONSOLE); diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Set.java b/src/main/java/com/intellectualcrafters/plot/commands/Set.java index f0d9cb7f1..d364232c3 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/Set.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/Set.java @@ -246,8 +246,18 @@ public class Set extends SubCommand { MainUtil.sendMessage(plr, getBiomeList(BlockManager.manager.getBiomeList())); return true; } - plot.setBiome(args[1].toUpperCase()); - MainUtil.sendMessage(plr, C.BIOME_SET_TO.s() + args[1].toLowerCase()); + if (MainUtil.runners.containsKey(plot)) { + MainUtil.sendMessage(plr, C.WAIT_FOR_TIMER); + return false; + } + MainUtil.runners.put(plot, 1); + plot.setBiome(args[1].toUpperCase(), new Runnable() { + @Override + public void run() { + MainUtil.runners.remove(plot); + MainUtil.sendMessage(plr, C.BIOME_SET_TO.s() + args[1].toLowerCase()); + } + }); return true; } // Get components diff --git a/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java b/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java index ede0562e7..1b1bb807a 100644 --- a/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java +++ b/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java @@ -38,6 +38,8 @@ import com.intellectualcrafters.plot.object.PlotBlock; import com.intellectualcrafters.plot.object.PlotId; import com.intellectualcrafters.plot.object.PlotLoc; import com.intellectualcrafters.plot.object.PlotWorld; +import com.intellectualcrafters.plot.object.RunnableVal; +import com.intellectualcrafters.plot.util.ChunkManager; import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.SetBlockQueue; import com.intellectualcrafters.plot.util.TaskManager; @@ -174,87 +176,56 @@ public class HybridPlotManager extends ClassicPlotManager { final Location pos1 = MainUtil.getPlotBottomLocAbs(world, plot.id).add(1, 0, 1); final Location pos2 = MainUtil.getPlotTopLocAbs(world, plot.id); - - setWallFilling(dpw, plot.id, new PlotBlock[] { dpw.WALL_FILLING }); - final int p1x = pos1.getX(); - final int p1z = pos1.getZ(); - final int p2x = pos2.getX(); - final int p2z = pos2.getZ(); - final int bcx = p1x >> 4; - final int bcz = p1z >> 4; - final int tcx = p2x >> 4; - final int tcz = p2z >> 4; - + // If augmented final boolean canRegen = plotworld.TYPE == 0 && plotworld.TERRAIN == 0; - + // The component blocks final PlotBlock[] plotfloor = dpw.TOP_BLOCK; final PlotBlock[] filling = dpw.MAIN_BLOCK; final PlotBlock[] bedrock = (dpw.PLOT_BEDROCK ? new PlotBlock[] { new PlotBlock((short) 7, (byte) 0) } : filling); final PlotBlock air = new PlotBlock((short) 0, (byte) 0); - final ArrayList chunks = new ArrayList(); + setWallFilling(dpw, plot.id, new PlotBlock[] { dpw.WALL_FILLING }); - for (int x = bcx; x <= tcx; x++) { - for (int z = bcz; z <= tcz; z++) { - chunks.add(new ChunkLoc(x, z)); - } - } - - TaskManager.runTask(new Runnable() { + ChunkManager.chunkTask(pos1, pos2, new RunnableVal() { @Override public void run() { - long start = System.currentTimeMillis(); - while (chunks.size() > 0 && System.currentTimeMillis() - start < 20) { - ChunkLoc chunk = chunks.remove(0); - int x = chunk.x; - int z = chunk.z; - int xxb = x << 4; - int zzb = z << 4; - int xxt = xxb + 15; - int zzt = zzb + 15; - if (canRegen) { - if (xxb >= p1x && xxt <= p2x && zzb >= p1z && zzt <= p2z) { - BukkitUtil.regenerateChunk(world, x, z); - continue; - } - } - if (x == bcx) { - xxb = p1x; - } - if (x == tcx) { - xxt = p2x; - } - if (z == bcz) { - zzb = p1z; - } - if (z == tcz) { - zzt = p2z; - } - BukkitUtil.setBiome(plot.world, xxb, zzb, xxt, zzt, dpw.PLOT_BIOME); - Location bot = new Location(world, xxb, 0, zzb); - Location top = new Location(world, xxt + 1, 1, zzt + 1); - MainUtil.setCuboidAsync(world, bot, top, bedrock); - bot.setY(1); - top.setY(dpw.PLOT_HEIGHT); - MainUtil.setCuboidAsync(world, bot, top, filling); - bot.setY(dpw.PLOT_HEIGHT); - top.setY(dpw.PLOT_HEIGHT + 1); - MainUtil.setCuboidAsync(world, bot, top, plotfloor); - bot.setY(dpw.PLOT_HEIGHT + 1); - top.setY(256); - MainUtil.setSimpleCuboidAsync(world, bot, top, air); - } - if (chunks.size() != 0) { - TaskManager.runTaskLater(this, 1); - } - else { - pastePlotSchematic(dpw, pos1, pos2); - final PlotBlock wall = isDelete ? dpw.WALL_BLOCK : dpw.CLAIMED_WALL_BLOCK; - setWall(dpw, plot.id, new PlotBlock[] { wall }); - SetBlockQueue.addNotify(whenDone); + // If the chunk isn't near the edge and it isn't an augmented world we can just regen the whole chunk + if (canRegen && value[6] == 0) { + BukkitUtil.regenerateChunk(world, value[0], value[1]); + return; } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Otherwise we need to set each component, as we don't want to regenerate the road or other plots that share the same chunk // + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Set the biome + BukkitUtil.setBiome(plot.world, value[2], value[3], value[4], value[5], dpw.PLOT_BIOME); + // These two locations are for each component (e.g. bedrock, main block, floor, air) + Location bot = new Location(world, value[2], 0, value[3]); + Location top = new Location(world, value[4] + 1, 1, value[5] + 1); + MainUtil.setCuboidAsync(world, bot, top, bedrock); + // Each component has a different layer + bot.setY(1); + top.setY(dpw.PLOT_HEIGHT); + MainUtil.setCuboidAsync(world, bot, top, filling); + bot.setY(dpw.PLOT_HEIGHT); + top.setY(dpw.PLOT_HEIGHT + 1); + MainUtil.setCuboidAsync(world, bot, top, plotfloor); + bot.setY(dpw.PLOT_HEIGHT + 1); + top.setY(256); + MainUtil.setSimpleCuboidAsync(world, bot, top, air); + // And finally set the schematic, the y value is unimportant for this function + pastePlotSchematic(dpw, bot, top); } - }); + }, new Runnable() { + @Override + public void run() { + // When we are done with the inside of the plot, we can reset the wall / border + final PlotBlock wall = isDelete ? dpw.WALL_BLOCK : dpw.CLAIMED_WALL_BLOCK; + setWall(dpw, plot.id, new PlotBlock[] { wall }); + // And notify whatever called this when plot clearing is done + SetBlockQueue.addNotify(whenDone); + } + }, 5); return true; } diff --git a/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotWorld.java b/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotWorld.java index b9f7cedee..b4914a39c 100644 --- a/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotWorld.java +++ b/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotWorld.java @@ -89,7 +89,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { } if (schem3 != null) { this.PLOT_SCHEMATIC = true; - byte[] ids = schem3.getIds(); + short[] ids = schem3.getIds(); byte[] datas = schem3.getDatas(); final Dimension d3 = schem3.getSchematicDimension(); final short w3 = (short) d3.getX(); @@ -108,7 +108,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { for (short y = 0; y < h3; y++) { final int index = (y * w3 * l3) + (z * w3) + x; final short id = ids[index]; - final byte data = ids[index]; + final byte data = datas[index]; if (id != 0) { addOverlayBlock((short) (x + shift + oddshift + center_shift_x), (y), (short) (z + shift + oddshift + center_shift_z), id, data, false); } @@ -141,10 +141,10 @@ public class HybridPlotWorld extends ClassicPlotWorld { // Do not populate road if using schematic population this.ROAD_BLOCK = new PlotBlock(this.ROAD_BLOCK.id, (byte) 0); - byte[] ids1 = schem1.getIds(); + short[] ids1 = schem1.getIds(); byte[] datas1 = schem1.getDatas(); - byte[] ids2 = schem2.getIds(); + short[] ids2 = schem2.getIds(); byte[] datas2 = schem2.getDatas(); final Dimension d1 = schem1.getSchematicDimension(); diff --git a/src/main/java/com/intellectualcrafters/plot/object/Plot.java b/src/main/java/com/intellectualcrafters/plot/object/Plot.java index 53ec57222..de83395ea 100644 --- a/src/main/java/com/intellectualcrafters/plot/object/Plot.java +++ b/src/main/java/com/intellectualcrafters/plot/object/Plot.java @@ -467,8 +467,8 @@ public class Plot { /** * Set the plot biome */ - public void setBiome(String biome) { - MainUtil.setBiome(this, biome); + public void setBiome(String biome, Runnable whenDone) { + MainUtil.setBiome(this, biome, whenDone); } /** diff --git a/src/main/java/com/intellectualcrafters/plot/util/ChunkManager.java b/src/main/java/com/intellectualcrafters/plot/util/ChunkManager.java index 1cf3585cb..60f4605b3 100644 --- a/src/main/java/com/intellectualcrafters/plot/util/ChunkManager.java +++ b/src/main/java/com/intellectualcrafters/plot/util/ChunkManager.java @@ -1,5 +1,6 @@ package com.intellectualcrafters.plot.util; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -10,7 +11,9 @@ import com.intellectualcrafters.plot.object.PlotBlock; import com.intellectualcrafters.plot.object.PlotId; import com.intellectualcrafters.plot.object.PlotLoc; import com.intellectualcrafters.plot.object.RegionWrapper; +import com.intellectualcrafters.plot.object.RunnableVal; import com.intellectualcrafters.plot.util.SetBlockQueue.ChunkWrapper; +import com.intellectualcrafters.plot.util.bukkit.BukkitUtil; public abstract class ChunkManager { @@ -27,6 +30,72 @@ public abstract class ChunkManager { return new ChunkLoc(x, z); } + /** + * The int[] will be in the form: [chunkx, chunkz, pos1x, pos1z, pos2x, pos2z, isedge] and will represent the bottom and top parts of the chunk + * @param pos1 + * @param pos2 + * @param task + * @param whenDone + */ + public static void chunkTask(Location pos1, Location pos2, final RunnableVal task, final Runnable whenDone, final int allocate) { + final int p1x = pos1.getX(); + final int p1z = pos1.getZ(); + final int p2x = pos2.getX(); + final int p2z = pos2.getZ(); + final int bcx = p1x >> 4; + final int bcz = p1z >> 4; + final int tcx = p2x >> 4; + final int tcz = p2z >> 4; + + final ArrayList chunks = new ArrayList(); + + for (int x = bcx; x <= tcx; x++) { + for (int z = bcz; z <= tcz; z++) { + chunks.add(new ChunkLoc(x, z)); + } + } + + TaskManager.runTask(new Runnable() { + @Override + public void run() { + long start = System.currentTimeMillis(); + while (chunks.size() > 0 && System.currentTimeMillis() - start < allocate) { + ChunkLoc chunk = chunks.remove(0); + task.value = new int[7]; + task.value[0] = chunk.x; + task.value[1] = chunk.z; + task.value[2] = task.value[0] << 4; + task.value[3] = task.value[1] << 4; + task.value[4] = task.value[2] + 15; + task.value[5] = task.value[3] + 15; + if (task.value[0] == bcx) { + task.value[2] = p1x; + task.value[6] = 1; + } + if (task.value[0] == tcx) { + task.value[4] = p2x; + task.value[6] = 1; + } + if (task.value[1] == bcz) { + task.value[3] = p1z; + task.value[6] = 1; + } + if (task.value[1] == tcz) { + task.value[5] = p2z; + task.value[6] = 1; + } + task.run(); + } + if (chunks.size() != 0) { + TaskManager.runTaskLater(this, 1); + } + else { + TaskManager.runTask(whenDone); + } + } + }); + } + public abstract void setChunk(ChunkWrapper loc, PlotBlock[][] result); public abstract int[] countEntities(Plot plot); diff --git a/src/main/java/com/intellectualcrafters/plot/util/MainUtil.java b/src/main/java/com/intellectualcrafters/plot/util/MainUtil.java index 618283948..bd3d5e43e 100644 --- a/src/main/java/com/intellectualcrafters/plot/util/MainUtil.java +++ b/src/main/java/com/intellectualcrafters/plot/util/MainUtil.java @@ -44,6 +44,7 @@ import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.PlotSettings; import com.intellectualcrafters.plot.object.PlotWorld; import com.intellectualcrafters.plot.object.PseudoRandom; +import com.intellectualcrafters.plot.object.RunnableVal; import com.intellectualcrafters.plot.util.bukkit.BukkitUtil; import com.intellectualcrafters.plot.util.bukkit.UUIDHandler; @@ -957,7 +958,6 @@ public class MainUtil { final Runnable run = new Runnable() { @Override public void run() { -// MainUtil.setBiome(world, plot, "FOREST"); runners.remove(plot); TaskManager.runTask(whenDone); } @@ -1043,15 +1043,25 @@ public class MainUtil { } } - public static void setBiome(final Plot plot, final String biome) { - final int bottomX = getPlotBottomLoc(plot.world, plot.id).getX() + 1; - final int topX = getPlotTopLoc(plot.world, plot.id).getX(); - final int bottomZ = getPlotBottomLoc(plot.world, plot.id).getZ() + 1; - final int topZ = getPlotTopLoc(plot.world, plot.id).getZ(); - BukkitUtil.setBiome(plot.world, bottomX, bottomZ, topX, topZ, biome); - update(plot); + public static void setBiome(final Plot plot, final String biome, final Runnable whenDone) { + Location pos1 = plot.getBottom().add(1, 0, 1); + Location pos2 = plot.getTop(); + ChunkManager.chunkTask(pos1, pos2, new RunnableVal() { + @Override + public void run() { + BukkitUtil.loadChunkAt(plot.world, value[0], value[1], false); + BukkitUtil.setBiome(plot.world, value[2], value[3], value[4], value[4], biome); + BukkitUtil.unloadChunkAt(plot.world, value[0], value[1], true, true); + } + }, new Runnable() { + @Override + public void run() { + update(plot); + TaskManager.runTask(whenDone); + } + }, 5); } - + public static int getHeighestBlock(final String world, final int x, final int z) { final int result = BukkitUtil.getHeighestBlock(world, x, z); if (result == 0) { diff --git a/src/main/java/com/intellectualcrafters/plot/util/SchematicHandler.java b/src/main/java/com/intellectualcrafters/plot/util/SchematicHandler.java index fb72171fd..b9358c88f 100644 --- a/src/main/java/com/intellectualcrafters/plot/util/SchematicHandler.java +++ b/src/main/java/com/intellectualcrafters/plot/util/SchematicHandler.java @@ -166,7 +166,6 @@ public abstract class SchematicHandler { final int WIDTH = demensions.getX(); final int LENGTH = demensions.getZ(); final int HEIGHT = demensions.getY(); - // Validate dimensions Location bottom = plot.getBottom(); Location top = plot.getTop(); @@ -175,21 +174,20 @@ public abstract class SchematicHandler { TaskManager.runTask(whenDone); return; } - - final byte[] ids = schematic.ids; + // block id and data arrays + final short[] ids = schematic.ids; final byte[] datas = schematic.datas; - + // Calculate the optimal height to paste the schematic at final int y_offset; if (HEIGHT >= 256) { y_offset = 0; } else { - y_offset = BukkitUtil.getMaxHeight(plot.world); + y_offset = BukkitUtil.getHeighestBlock(plot.world, bottom.getX() + 1, bottom.getZ() + 1); } - Location pos1 = MainUtil.getPlotBottomLoc(plot.world, plot.id).add(1 + x_offset, y_offset - 1, 1 + z_offset); Location pos2 = pos1.clone().add(WIDTH - 1, HEIGHT - 1, LENGTH - 1); - + // TODO switch to ChunkManager.chunkTask(pos1, pos2, task, whenDone, allocate); final int p1x = pos1.getX(); final int p1z = pos1.getZ(); final int p2x = pos2.getX(); @@ -198,15 +196,12 @@ public abstract class SchematicHandler { final int bcz = p1z >> 4; final int tcx = p2x >> 4; final int tcz = p2z >> 4; - final ArrayList chunks = new ArrayList(); - for (int x = bcx; x <= tcx; x++) { for (int z = bcz; z <= tcz; z++) { chunks.add(new ChunkLoc(x, z)); } } - TaskManager.runTaskAsync(new Runnable() { @Override public void run() { @@ -235,7 +230,12 @@ public abstract class SchematicHandler { // Paste schematic here int id; - for (int ry = 0; ry < Math.max(256, HEIGHT); ry++) { + for (int ry = 0; ry < Math.min(256, HEIGHT); ry++) { + int yy = y_offset + ry; + if (yy > 255) { + System.out.print("TOO HIGH: " + ry); + continue; + } int i1 = ry * WIDTH * LENGTH; for (int rz = zzb - p1z; rz <= zzt - p1z; rz++) { int i2 = rz * WIDTH + i1; @@ -244,7 +244,6 @@ public abstract class SchematicHandler { int xx = p1x + rx; int zz = p1z + rz; - int yy = y_offset + ry; id = ids[i]; @@ -324,6 +323,7 @@ public abstract class SchematicHandler { break; } default: { + System.out.print(id +","+datas[i]); SetBlockQueue.setBlock(plot.world, xx, yy, zz, new PlotBlock((short) id, (byte) datas[i])); break; } @@ -411,9 +411,20 @@ public abstract class SchematicHandler { final short width = ShortTag.class.cast(tagMap.get("Width")).getValue(); final short length = ShortTag.class.cast(tagMap.get("Length")).getValue(); final short height = ShortTag.class.cast(tagMap.get("Height")).getValue(); - final byte[] block = ByteArrayTag.class.cast(tagMap.get("Blocks")).getValue(); + final byte[] block_sml = ByteArrayTag.class.cast(tagMap.get("Blocks")).getValue(); final byte[] data = ByteArrayTag.class.cast(tagMap.get("Data")).getValue(); + final short[] block = new short[block_sml.length]; + for (int i = 0; i < block.length; i++) { + short id = block_sml[i]; + if (id < 0) { + id = (short) (id & 0xFF); + } + block[i] = id; + } + + + // Slow + has code for exceptions (addId) inside the loop rather than outside // for (int index = 0; index < b.length; index++) { // if ((index >> 1) >= addId.length) { @@ -433,6 +444,8 @@ public abstract class SchematicHandler { // } // Schematic schem = new Schematic(collection, dimension, file); + System.out.print(width + "," + height +"," + length); + Dimension dimensions = new Dimension(width, height, length); Schematic schem = new Schematic(block, data, dimensions); @@ -747,7 +760,7 @@ public abstract class SchematicHandler { */ public class Schematic { // Lossy but fast - private final byte[] ids; + private final short[] ids; private final byte[] datas; @Deprecated @@ -766,7 +779,7 @@ public abstract class SchematicHandler { */ @Deprecated public Schematic(final DataCollection[] blockCollection, final Dimension schematicDimension) { - ids = new byte[blockCollection.length]; + ids = new short[blockCollection.length]; datas = new byte[blockCollection.length]; for (int i = 0; i < blockCollection.length; i++) { DataCollection block = blockCollection[i]; @@ -777,7 +790,7 @@ public abstract class SchematicHandler { this.schematicDimension = schematicDimension; } - public Schematic(final byte[] i, final byte[] b, final Dimension d) { + public Schematic(final short[] i, final byte[] b, final Dimension d) { ids = i; datas = b; schematicDimension = d; @@ -814,7 +827,7 @@ public abstract class SchematicHandler { * Get the block id array * @return */ - public byte[] getIds() { + public short[] getIds() { return ids; } diff --git a/src/main/java/com/intellectualcrafters/plot/util/bukkit/BukkitUtil.java b/src/main/java/com/intellectualcrafters/plot/util/bukkit/BukkitUtil.java index d71515d15..75ca22623 100644 --- a/src/main/java/com/intellectualcrafters/plot/util/bukkit/BukkitUtil.java +++ b/src/main/java/com/intellectualcrafters/plot/util/bukkit/BukkitUtil.java @@ -112,6 +112,16 @@ public class BukkitUtil extends BlockManager { return getWorld(world).getHighestBlockYAt(x, z); } + public static void unloadChunkAt(String worldname, int X, int Z, boolean save, boolean safe) { + final World world = getWorld(worldname); + world.unloadChunk(X, Z, save, safe); + } + + public static void loadChunkAt(final String worldname, int X, int Z, boolean force) { + final World world = getWorld(worldname); + world.loadChunk(X, Z, force); + } + public static Chunk getChunkAt(final String worldname, final int x, final int z) { final World world = getWorld(worldname); return world.getChunkAt(x, z); @@ -156,13 +166,10 @@ public class BukkitUtil extends BlockManager { final World world = getWorld(worldname); for (int x = pos1_x; x <= pos2_x; x++) { for (int z = pos1_z; z <= pos2_z; z++) { - final Block blk = world.getBlockAt(x, 0, z); - final Biome c = blk.getBiome(); - if (c.equals(b)) { - x += 15; + if (world.getBiome(x, z) == b) { continue; } - blk.setBiome(b); + world.setBiome(x, z, b); } } }