From 6ab19fd52d4f395654a6cbd211b622da96353dbb Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 12 Oct 2010 21:41:06 -0700 Subject: [PATCH] Added /editexpand and /editcontract. --- src/EditSession.java | 10 +- src/WorldEdit.java | 118 ++++++++++----- src/WorldEditPlayer.java | 15 ++ src/WorldEditSMListener.java | 2 + src/WorldEditSession.java | 30 +++- src/com/sk89q/worldedit/CuboidRegion.java | 134 ++++++++++++++++++ src/com/sk89q/worldedit/Region.java | 12 ++ .../worldedit/UnknownDirectionException.java | 36 +++++ src/com/sk89q/worldedit/Vector.java | 30 ++++ 9 files changed, 342 insertions(+), 45 deletions(-) create mode 100644 src/com/sk89q/worldedit/UnknownDirectionException.java diff --git a/src/EditSession.java b/src/EditSession.java index 471650a98..9b56234fc 100644 --- a/src/EditSession.java +++ b/src/EditSession.java @@ -584,15 +584,13 @@ public class EditSession { * Stack a cuboid region. * * @param region - * @param xm - * @param ym - * @param zm + * @param dir * @param count * @param copyAir * @return number of blocks affected * @throws MaxChangedBlocksException */ - public int stackCuboidRegion(Region region, int xm, int ym, int zm, + public int stackCuboidRegion(Region region, Vector dir, int count, boolean copyAir) throws MaxChangedBlocksException { int affected = 0; @@ -610,8 +608,8 @@ public class EditSession { if (blockType != 0 || copyAir) { for (int i = 1; i <= count; i++) { - if (setBlock(x + xs * xm * i, y + ys * ym * i, - z + zs * zm * i, blockType)) { + if (setBlock(x + xs * dir.getBlockX() * i, y + ys * dir.getBlockY() * i, + z + zs * dir.getBlockZ() * i, blockType)) { affected++; } } diff --git a/src/WorldEdit.java b/src/WorldEdit.java index 698e2e4a4..bed8a1fa2 100644 --- a/src/WorldEdit.java +++ b/src/WorldEdit.java @@ -91,6 +91,8 @@ public class WorldEdit { commands.put("/editfill", "[ID] [Radius] - Fill a hole"); commands.put("/editdrain", "[Radius] - Drain nearby water/lava pools"); commands.put("/editlimit", "[Num] - See documentation"); + commands.put("/editexpand", " [Num] - Expands the selection"); + commands.put("/editcontract", " [Num] - Contracts the selection"); commands.put("/unstuck", "Go up to the first free spot"); } @@ -464,49 +466,101 @@ public class WorldEdit { split[0].equalsIgnoreCase("/editstack")) { checkArgs(split, 0, 2, split[0]); int count = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1; - String dir = split.length > 2 ? split[2].toLowerCase() : "me"; - int xm = 0; - int ym = 0; - int zm = 0; + Vector dir = getDirection(player, + split.length > 2 ? split[2].toLowerCase() : "me"); boolean copyAir = split[0].equalsIgnoreCase("/editstackair"); - if (dir.equals("me")) { - // From hey0's code - double rot = (player.getYaw() - 90) % 360; - if (rot < 0) { - rot += 360.0; - } - - dir = etc.getCompassPointForDirection(rot).toLowerCase(); - } - - if (dir.charAt(0) == 'w') { - zm += 1; - } else if (dir.charAt(0) == 'e') { - zm -= 1; - } else if (dir.charAt(0) == 's') { - xm += 1; - } else if (dir.charAt(0) == 'n') { - xm -= 1; - } else if (dir.charAt(0) == 'u') { - ym += 1; - } else if (dir.charAt(0) == 'd') { - ym -= 1; - } else { - player.printError("Unknown direction: " + dir); - return true; - } - int affected = editSession.stackCuboidRegion(session.getRegion(), - xm, ym, zm, count, copyAir); + dir, count, copyAir); player.print(affected + " blocks changed. Undo with /editundo"); + return true; + + // Expand + } else if (split[0].equalsIgnoreCase("/editexpand")) { + checkArgs(split, 1, 2, split[0]); + Vector dir; + int change; + if (split.length == 3) { + dir = getDirection(player, split[1].toLowerCase()); + change = Integer.parseInt(split[2]); + } else { + dir = getDirection(player, "me"); + change = Integer.parseInt(split[1]); + } + + Region region = session.getRegion(); + int oldSize = region.getSize(); + region.expand(dir.multiply(change)); + session.learnRegionChanges(); + int newSize = region.getSize(); + player.print("Region expanded " + (newSize - oldSize) + " blocks."); + + return true; + + // Expand + } else if (split[0].equalsIgnoreCase("/editcontract")) { + checkArgs(split, 1, 2, split[0]); + Vector dir; + int change; + if (split.length == 3) { + dir = getDirection(player, split[1].toLowerCase()); + change = Integer.parseInt(split[2]); + } else { + dir = getDirection(player, "me"); + change = Integer.parseInt(split[1]); + } + + Region region = session.getRegion(); + int oldSize = region.getSize(); + region.contract(dir.multiply(change)); + session.learnRegionChanges(); + int newSize = region.getSize(); + player.print("Region contracted " + (oldSize - newSize) + " blocks."); + return true; } return false; } + /** + * Get the direction vector for a player's direction. May return + * null if a direction could not be found. + * + * @param player + * @param dir + * @return + */ + public Vector getDirection(WorldEditPlayer player, String dir) + throws UnknownDirectionException { + int xm = 0; + int ym = 0; + int zm = 0; + + if (dir.equals("me")) { + dir = player.getCardinalDirection(); + } + + if (dir.charAt(0) == 'w') { + zm += 1; + } else if (dir.charAt(0) == 'e') { + zm -= 1; + } else if (dir.charAt(0) == 's') { + xm += 1; + } else if (dir.charAt(0) == 'n') { + xm -= 1; + } else if (dir.charAt(0) == 'u') { + ym += 1; + } else if (dir.charAt(0) == 'd') { + ym -= 1; + } else { + throw new UnknownDirectionException(dir); + } + + return new Vector(xm, ym, zm); + } + /** * Remove a session. * diff --git a/src/WorldEditPlayer.java b/src/WorldEditPlayer.java index b36b18589..45141d54b 100644 --- a/src/WorldEditPlayer.java +++ b/src/WorldEditPlayer.java @@ -98,6 +98,21 @@ public class WorldEditPlayer { return player.getItemInHand(); } + /** + * Get the player's cardinal direction (N, W, NW, etc.). + * + * @return + */ + public String getCardinalDirection() { + // From hey0's code + double rot = (getYaw() - 90) % 360; + if (rot < 0) { + rot += 360.0; + } + + return etc.getCompassPointForDirection(rot).toLowerCase(); + } + /** * Print a WorldEdit message. * diff --git a/src/WorldEditSMListener.java b/src/WorldEditSMListener.java index ab6a72e55..89144e377 100644 --- a/src/WorldEditSMListener.java +++ b/src/WorldEditSMListener.java @@ -157,6 +157,8 @@ public class WorldEditSMListener extends PluginListener { } catch (MaxChangedBlocksException e5) { modPlayer.sendMessage(Colors.Rose + "The maximum number of blocks changed (" + e5.getBlockLimit() + ") in an instance was reached."); + } catch (UnknownDirectionException ue) { + modPlayer.sendMessage(Colors.Rose + "Unknown direction: " + ue.getDirection()); } catch (InsufficientArgumentsException e6) { modPlayer.sendMessage(Colors.Rose + e6.getMessage()); } catch (WorldEditException e7) { diff --git a/src/WorldEditSession.java b/src/WorldEditSession.java index 00fbca2bb..3d88649aa 100644 --- a/src/WorldEditSession.java +++ b/src/WorldEditSession.java @@ -27,6 +27,7 @@ import java.util.LinkedList; public class WorldEditSession { public static final int MAX_HISTORY_SIZE = 15; private Vector pos1, pos2; + private Region region; private LinkedList history = new LinkedList(); private int historyPointer = 0; private CuboidClipboard clipboard; @@ -132,6 +133,9 @@ public class WorldEditSession { */ public void setPos1(Vector pt) { pos1 = pt; + if (pos1 != null && pos2 != null) { + region = new CuboidRegion(pos1, pos2); + } } /** @@ -152,19 +156,31 @@ public class WorldEditSession { */ public void setPos2(Vector pt) { pos2 = pt; + if (pos1 != null && pos2 != null) { + region = new CuboidRegion(pos1, pos2); + } } /** - * Get the region. + * Update session position 1/2 based on the currently set region, + * provided that the region is of a cuboid. + */ + public void learnRegionChanges() { + if (region instanceof CuboidRegion) { + CuboidRegion cuboidRegion = (CuboidRegion)region; + pos1 = cuboidRegion.getPos1(); + pos2 = cuboidRegion.getPos2(); + } + } + + /** + * Get the region. May return null. If you change the region, you should + * call learnRegionChanges(). * * @return region - * @throws IncompleteRegionException */ - public Region getRegion() throws IncompleteRegionException { - checkPos1(); - checkPos2(); - - return new CuboidRegion(pos1, pos2); + public Region getRegion() { + return region; } /** diff --git a/src/com/sk89q/worldedit/CuboidRegion.java b/src/com/sk89q/worldedit/CuboidRegion.java index 9b3e31388..7d0cc01b1 100644 --- a/src/com/sk89q/worldedit/CuboidRegion.java +++ b/src/com/sk89q/worldedit/CuboidRegion.java @@ -120,6 +120,140 @@ public class CuboidRegion implements Region { return (int)(max.getZ() - min.getZ() + 1); } + /** + * Expands the cuboid in a direction. + * + * @param change + */ + public void expand(Vector change) { + if (change.getX() > 0) { + if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) { + pos1 = pos1.add(new Vector(change.getX(), 0, 0)); + } else { + pos2 = pos2.add(new Vector(change.getX(), 0, 0)); + } + } else { + if (Math.min(pos1.getX(), pos2.getX()) == pos1.getX()) { + pos1 = pos1.add(new Vector(change.getX(), 0, 0)); + } else { + pos2 = pos2.add(new Vector(change.getX(), 0, 0)); + } + } + + if (change.getY() > 0) { + if (Math.max(pos1.getY(), pos2.getY()) == pos1.getY()) { + pos1 = pos1.add(new Vector(0, change.getY(), 0)); + } else { + pos2 = pos2.add(new Vector(0, change.getY(), 0)); + } + } else { + if (Math.min(pos1.getY(), pos2.getY()) == pos1.getY()) { + pos1 = pos1.add(new Vector(0, change.getY(), 0)); + } else { + pos2 = pos2.add(new Vector(0, change.getY(), 0)); + } + } + + if (change.getZ() > 0) { + if (Math.max(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { + pos1 = pos1.add(new Vector(0, 0, change.getZ())); + } else { + pos2 = pos2.add(new Vector(0, 0, change.getZ())); + } + } else { + if (Math.min(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { + pos1 = pos1.add(new Vector(0, 0, change.getZ())); + } else { + pos2 = pos2.add(new Vector(0, 0, change.getZ())); + } + } + } + + /** + * Contracts the cuboid in a direction. + * + * @param change + */ + public void contract(Vector change) { + if (change.getX() < 0) { + if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) { + pos1 = pos1.add(new Vector(change.getX(), 0, 0)); + } else { + pos2 = pos2.add(new Vector(change.getX(), 0, 0)); + } + } else { + if (Math.min(pos1.getX(), pos2.getX()) == pos1.getX()) { + pos1 = pos1.add(new Vector(change.getX(), 0, 0)); + } else { + pos2 = pos2.add(new Vector(change.getX(), 0, 0)); + } + } + + if (change.getY() < 0) { + if (Math.max(pos1.getY(), pos2.getY()) == pos1.getY()) { + pos1 = pos1.add(new Vector(0, change.getY(), 0)); + } else { + pos2 = pos2.add(new Vector(0, change.getY(), 0)); + } + } else { + if (Math.min(pos1.getY(), pos2.getY()) == pos1.getY()) { + pos1 = pos1.add(new Vector(0, change.getY(), 0)); + } else { + pos2 = pos2.add(new Vector(0, change.getY(), 0)); + } + } + + if (change.getZ() < 0) { + if (Math.max(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { + pos1 = pos1.add(new Vector(0, 0, change.getZ())); + } else { + pos2 = pos2.add(new Vector(0, 0, change.getZ())); + } + } else { + if (Math.min(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { + pos1 = pos1.add(new Vector(0, 0, change.getZ())); + } else { + pos2 = pos2.add(new Vector(0, 0, change.getZ())); + } + } + } + + /** + * Get position 1. + * + * @return position 1 + */ + public Vector getPos1() { + return pos1; + } + + /** + * Set position 1. + * + * @param pos1 + */ + public void setPos1(Vector pos1) { + this.pos1 = pos1; + } + + /** + * Get position 2. + * + * @return position 2 + */ + public Vector getPos2() { + return pos2; + } + + /** + * Set position 2. + * + * @param pos2 + */ + public void setPos2(Vector pos2) { + this.pos2 = pos2; + } + /** * Get the iterator. * diff --git a/src/com/sk89q/worldedit/Region.java b/src/com/sk89q/worldedit/Region.java index 76c1f31f6..ff19e3284 100644 --- a/src/com/sk89q/worldedit/Region.java +++ b/src/com/sk89q/worldedit/Region.java @@ -60,4 +60,16 @@ public interface Region extends Iterable { * @return length */ public int getLength(); + /** + * Expand the region. + * + * @param change + */ + public void expand(Vector change); + /** + * Contract the region. + * + * @param change + */ + public void contract(Vector change); } diff --git a/src/com/sk89q/worldedit/UnknownDirectionException.java b/src/com/sk89q/worldedit/UnknownDirectionException.java new file mode 100644 index 000000000..e3f3bc974 --- /dev/null +++ b/src/com/sk89q/worldedit/UnknownDirectionException.java @@ -0,0 +1,36 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit; + +/** + * + * @author sk89q + */ +public class UnknownDirectionException extends WorldEditException { + private String dir; + + public UnknownDirectionException(String dir) { + this.dir = dir; + } + + public String getDirection() { + return dir; + } +} diff --git a/src/com/sk89q/worldedit/Vector.java b/src/com/sk89q/worldedit/Vector.java index 43b2901c9..80d7f4120 100644 --- a/src/com/sk89q/worldedit/Vector.java +++ b/src/com/sk89q/worldedit/Vector.java @@ -280,6 +280,36 @@ public class Vector { return new Vector(newX, newY, newZ); } + /** + * Scalar multiplication. + * + * @param n + * @return New point + */ + public Vector multiply(double n) { + return new Vector(this.x * n, this.y * n, this.z * n); + } + + /** + * Scalar multiplication. + * + * @param n + * @return New point + */ + public Vector multiply(float n) { + return new Vector(this.x * n, this.y * n, this.z * n); + } + + /** + * Scalar multiplication. + * + * @param n + * @return New point + */ + public Vector multiply(int n) { + return new Vector(this.x * n, this.y * n, this.z * n); + } + /** * Divide two points. *