diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index 3328cb150..f11d76793 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -2996,6 +2996,73 @@ public class EditSession { return affected; } + /** + * Draws a line (out of blocks) between two vectors. + * + * @param pattern The block pattern used to draw the line + * @param pos1 One of the points that define the line. + * @param pos2 The other point that defines the line. + * + * @return number of blocks affected + * @throws MaxChangedBlocksException + */ + public int drawLine(Pattern pattern, Vector pos1, Vector pos2) + throws MaxChangedBlocksException { + + int affected = 0; + boolean notdrawn = true; + + int x1 = pos1.getBlockX(), y1 = pos1.getBlockY(), z1 = pos1.getBlockZ(); + int x2 = pos2.getBlockX(), y2 = pos2.getBlockY(), z2 = pos2.getBlockZ(); + int tipx = x1, tipy = y1, tipz = z1; + int dx = Math.abs(x2 - x1), dy = Math.abs(y2 - y1), dz = Math.abs(z2 - z1); + + if (dx + dy + dz == 0) { + return setBlock(new Vector(tipx, tipy, tipz), pattern) ? 1 : 0; + } + + if (Math.max(Math.max(dx, dy), dz) == dx && notdrawn) { + for (int domstep = 0; domstep <= dx; domstep++) { + tipx = x1 + domstep * (x2 - x1 > 0 ? 1 : -1); + tipy = (int) Math.round(y1 + domstep * ((double) dy) / ((double) dx) * (y2 - y1 > 0 ? 1 : -1)); + tipz = (int) Math.round(z1 + domstep * ((double) dz) / ((double) dx) * (z2 - z1 > 0 ? 1 : -1)); + + if (setBlock(new Vector(tipx, tipy, tipz), pattern)) { + affected++; + } + } + notdrawn = false; + } + + if (Math.max(Math.max(dx, dy), dz) == dy && notdrawn) { + for (int domstep = 0; domstep <= dy; domstep++) { + tipy = y1 + domstep * (y2 - y1 > 0 ? 1 : -1); + tipx = (int) Math.round(x1 + domstep * ((double) dx) / ((double) dy) * (x2 - x1 > 0 ? 1 : -1)); + tipz = (int) Math.round(z1 + domstep * ((double) dz) / ((double) dy) * (z2 - z1 > 0 ? 1 : -1)); + + if (setBlock(new Vector(tipx, tipy, tipz), pattern)) { + affected++; + } + } + notdrawn = false; + } + + if (Math.max(Math.max(dx, dy), dz) == dz && notdrawn) { + for (int domstep = 0; domstep <= dz; domstep++) { + tipz = z1 + domstep * (z2 - z1 > 0 ? 1 : -1); + tipy = (int) Math.round(y1 + domstep * ((double) dy) / ((double) dz) * (y2-y1>0 ? 1 : -1)); + tipx = (int) Math.round(x1 + domstep * ((double) dx) / ((double) dz) * (x2-x1>0 ? 1 : -1)); + + if (setBlock(new Vector(tipx, tipy, tipz), pattern)) { + affected++; + } + } + notdrawn = false; + } + + return affected; + } + private void recurseHollow(Region region, BlockVector origin, Set outside) { final LinkedList queue = new LinkedList(); queue.addLast(origin); diff --git a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java b/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java index b39fc4ef4..b8b8cf329 100644 --- a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java +++ b/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java @@ -86,6 +86,32 @@ public class RegionCommands { player.print(affected + " block(s) have been changed."); } + @Command( + aliases = { "/line" }, + usage = "", + desc = "Draw a line segment between selection corners.", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.region.line") + @Logging(REGION) + public void line(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Region region = session.getSelection(session.getSelectionWorld()); + if (!(region instanceof CuboidRegion)) { + player.printError("Invalid region type"); + return; + } + + Pattern pattern = we.getBlockPattern(player, args.getString(0)); + Vector pos1 = ((CuboidRegion) region).getPos1(); + Vector pos2 = ((CuboidRegion) region).getPos2(); + int blocksChanged = editSession.drawLine(pattern, pos1, pos2); + + player.print(blocksChanged + " block(s) have been changed."); + } + @Command( aliases = { "/replace", "/re", "/rep" }, usage = "[from-block] ",