From 67a7969cd164cea4842be2b7bc914be689aac52a Mon Sep 17 00:00:00 2001 From: Wizjany Date: Sun, 18 Sep 2011 21:49:45 -0400 Subject: [PATCH] Added a tool that allows a player to place and remove blocks at a distance. --- .../java/com/sk89q/worldedit/LocalPlayer.java | 8 +- .../java/com/sk89q/worldedit/VectorFace.java | 68 ++++++++ .../com/sk89q/worldedit/WorldVectorFace.java | 148 ++++++++++++++++++ .../worldedit/commands/ToolCommands.java | 20 +++ .../com/sk89q/worldedit/tools/BrushTool.java | 6 +- .../worldedit/tools/LongRangeBuildTool.java | 97 ++++++++++++ .../com/sk89q/worldedit/util/TargetBlock.java | 14 +- 7 files changed, 353 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/VectorFace.java create mode 100644 src/main/java/com/sk89q/worldedit/WorldVectorFace.java create mode 100644 src/main/java/com/sk89q/worldedit/tools/LongRangeBuildTool.java diff --git a/src/main/java/com/sk89q/worldedit/LocalPlayer.java b/src/main/java/com/sk89q/worldedit/LocalPlayer.java index 84da5f3e5..125c1b5c8 100644 --- a/src/main/java/com/sk89q/worldedit/LocalPlayer.java +++ b/src/main/java/com/sk89q/worldedit/LocalPlayer.java @@ -31,7 +31,7 @@ import com.sk89q.worldedit.util.TargetBlock; * * @author sk89q */ -public abstract class LocalPlayer { +public abstract class LocalPlayer { /** * Server. */ @@ -319,7 +319,11 @@ public abstract class LocalPlayer { TargetBlock tb = new TargetBlock(this, range, 0.2); return (useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock()); } - + + public WorldVectorFace getBlockTraceFace(int range, boolean useLastBlock) { + TargetBlock tb = new TargetBlock(this, range, 0.2); + return (useLastBlock ? tb.getAnyTargetBlockFace() : tb.getTargetBlockFace()); + } /** * Get the point of the block being looked at. May return null. * diff --git a/src/main/java/com/sk89q/worldedit/VectorFace.java b/src/main/java/com/sk89q/worldedit/VectorFace.java new file mode 100644 index 000000000..9695f386c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/VectorFace.java @@ -0,0 +1,68 @@ +package com.sk89q.worldedit; + +/** + * Represents the adjacency of one vector to another. Works similarly to + * Bukkit's BlockFace class. + * + * @author wizjany + */ +public enum VectorFace { + NORTH(-1, 0, 0), + EAST(0, 0, -1), + SOUTH(1, 0, 0), + WEST(0, 0, 1), + UP(0, 1, 0), + DOWN(0, -1, 0), + NORTH_EAST(NORTH, EAST), + NORTH_WEST(NORTH, WEST), + SOUTH_EAST(SOUTH, EAST), + SOUTH_WEST(SOUTH, WEST), + ABOVE_NORTH(UP, NORTH), + BELOW_NORTH(DOWN, NORTH), + ABOVE_SOUTH(UP, SOUTH), + BELOW_SOUTH(DOWN, SOUTH), + ABOVE_WEST(UP, WEST), + BELOW_WEST(DOWN, WEST), + ABOVE_EAST(UP, EAST), + BELOW_EAST(DOWN, EAST), + SELF(0, 0, 0); + + private int modX; + private int modY; + private int modZ; + + private VectorFace(final int modX, final int modY, final int modZ) { + this.modX = modX; + this.modY = modY; + this.modZ = modZ; + } + + private VectorFace(VectorFace face1, VectorFace face2) { + this.modX = face1.getModX() + face2.getModX(); + this.modY = face1.getModY() + face2.getModY(); + this.modZ = face1.getModZ() + face2.getModZ(); + } + + public int getModX() { + return modX; + } + + public int getModZ() { + return modZ; + } + + public int getModY() { + return modY; + } + + public static VectorFace fromMods(int modX2, int modY2, int modZ2) { + for (VectorFace face : values()) { + if (face.getModX() == modX2 + && face.getModY() == modY2 + && face.getModZ() == modZ2) { + return face; + } + } + return VectorFace.SELF; + } +} diff --git a/src/main/java/com/sk89q/worldedit/WorldVectorFace.java b/src/main/java/com/sk89q/worldedit/WorldVectorFace.java new file mode 100644 index 000000000..60bb2bfcd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/WorldVectorFace.java @@ -0,0 +1,148 @@ +// $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; + +/** + * A WorldVector that emphasizes one side of the block + */ +public class WorldVectorFace extends WorldVector { + /** + * Represents the side. + */ + private VectorFace face; + + /** + * Construct the Vector object. + * + * @param world + * @param x + * @param y + * @param z + * @param face + */ + public WorldVectorFace(LocalWorld world, double x, double y, double z, VectorFace face) { + super(world, x, y, z); + this.face = face; + } + + /** + * Construct the Vector object. + * + * @param world + * @param x + * @param y + * @param z + * @param face + */ + public WorldVectorFace(LocalWorld world, int x, int y, int z, VectorFace face) { + super(world, x, y, z); + this.face = face; + } + + /** + * Construct the Vector object. + * + * @param world + * @param x + * @param y + * @param z + * @param face + */ + public WorldVectorFace(LocalWorld world, float x, float y, float z, VectorFace face) { + super(world, x, y, z); + this.face = face; + } + + /** + * Construct the Vector object. + * + * @param world + * @param pt + * @param face + */ + public WorldVectorFace(LocalWorld world, Vector pt, VectorFace face) { + super(world, pt); + this.face = face; + } + + /** + * Construct the Vector object. + * + * @param world + * @param face + */ + public WorldVectorFace(LocalWorld world, VectorFace face) { + super(world); + this.face = face; + } + + /** + * Get the face. + * + * @return + */ + public VectorFace getFace() { + return face; + } + + /** + * Get the WorldVector adjacent to this WorldVectorFace. + * + * @return + */ + public WorldVector getFaceVector() { + return new WorldVector(getWorld(), + getBlockX() - face.getModX(), + getBlockY() - face.getModY(), + getBlockZ() - face.getModZ()); + } + + /** + * Get a WorldVectorFace by comparing two vectors. Note that they need not be + * adjacent, as only the directions, not distance, will be taken into account. + * + * @param world the world in which the resulting vector should lie + * @param vector the original vector + * @param face the direction in which the face should lie + * @return + */ + public static WorldVectorFace getWorldVectorFace(LocalWorld world, Vector vector, Vector face) { + if (vector == null || face == null) return null; + // check which direction the face is from the vector + final int x1 = vector.getBlockX(); + final int y1 = vector.getBlockY(); + final int z1 = vector.getBlockZ(); + int modX = x1 - face.getBlockX(); + int modY = y1 - face.getBlockY(); + int modZ = z1 - face.getBlockZ(); + if (modX > 0) modX = 1; + else if (modX < 0) modX = -1; + else modX = 0; + if (modY > 0) modY = 1; + else if (modY < 0) modY = -1; + else modY = 0; + if (modZ > 0) modZ = 1; + else if (modZ < 0) modZ = -1; + else modZ = 0; + // construct new vector + return new WorldVectorFace(world, x1, y1, z1, VectorFace.fromMods(modX, modY, modZ)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/commands/ToolCommands.java b/src/main/java/com/sk89q/worldedit/commands/ToolCommands.java index c484c4828..08a4ce96f 100644 --- a/src/main/java/com/sk89q/worldedit/commands/ToolCommands.java +++ b/src/main/java/com/sk89q/worldedit/commands/ToolCommands.java @@ -192,4 +192,24 @@ public class ToolCommands { session.setTool(player.getItemInHand(), new DistanceWand()); player.print("Far wand tool bound to " + ItemType.toHeldName(player.getItemInHand()) + "."); } + + @Command( + aliases = {"lrbuild", "/lrbuild"}, + usage = " ", + desc = "Long-range building tool", + min = 2, + max = 2 + ) + @CommandPermissions({"worldedit.tool.lrbuild"}) + public static void longrangebuildtool(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + BaseBlock secondary = we.getBlock(player, args.getString(0)); + BaseBlock primary = we.getBlock(player, args.getString(1)); + session.setTool(player.getItemInHand(), new LongRangeBuildTool(primary, secondary)); + player.print("Long-range building tool bound to " + ItemType.toHeldName(player.getItemInHand()) + "."); + player.print("Left-click set to " + ItemType.toName(secondary.getType()) + "; right-click set to " + + ItemType.toName(primary.getType()) + "."); + } } diff --git a/src/main/java/com/sk89q/worldedit/tools/BrushTool.java b/src/main/java/com/sk89q/worldedit/tools/BrushTool.java index 0bbc1854c..7a1da6d70 100644 --- a/src/main/java/com/sk89q/worldedit/tools/BrushTool.java +++ b/src/main/java/com/sk89q/worldedit/tools/BrushTool.java @@ -167,11 +167,7 @@ public class BrushTool implements TraceTool { public boolean actPrimary(ServerInterface server, LocalConfiguration config, LocalPlayer player, LocalSession session) { WorldVector target = null; - if (this.range > -1) { - target = player.getBlockTrace(getRange(), true); - } else { - target = player.getBlockTrace(MAX_RANGE); - } + target = player.getBlockTrace(getRange(), true); if (target == null) { player.printError("No block in sight!"); diff --git a/src/main/java/com/sk89q/worldedit/tools/LongRangeBuildTool.java b/src/main/java/com/sk89q/worldedit/tools/LongRangeBuildTool.java new file mode 100644 index 000000000..4095bdce3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/tools/LongRangeBuildTool.java @@ -0,0 +1,97 @@ +// $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.tools; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; + +/** + * A tool that can place (or remove) blocks at a distance. + * + * @author wizjany + */ +public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTool { + + BaseBlock primary; + BaseBlock secondary; + + public LongRangeBuildTool(BaseBlock primary, BaseBlock secondary) { + super("worldedit.tool.lrbuild"); + this.primary = primary; + this.secondary = secondary; + } + + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.tool.lrbuild"); + } + + public boolean actSecondary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session) { + + WorldVectorFace pos = getTargetFace(player); + if (pos == null) return false; + EditSession eS = session.createEditSession(player); + try { + if (secondary.getType() == BlockID.AIR) { + eS.setBlock(pos, secondary); + } else { + eS.setBlock(pos.getFaceVector(), secondary); + } + return true; + } catch (MaxChangedBlocksException e) { + // one block? eat it + } + return false; + + } + + @Override + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session) { + + WorldVectorFace pos = getTargetFace(player); + if (pos == null) return false; + EditSession eS = session.createEditSession(player); + try { + if (primary.getType() == BlockID.AIR) { + eS.setBlock(pos, primary); + } else { + eS.setBlock(pos.getFaceVector(), primary); + } + return true; + } catch (MaxChangedBlocksException e) { + // one block? eat it + } + return false; + } + + public WorldVectorFace getTargetFace(LocalPlayer player) { + WorldVectorFace target = null; + target = player.getBlockTraceFace(getRange(), true); + + if (target == null) { + player.printError("No block in sight!"); + return null; + } + + return target; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/TargetBlock.java b/src/main/java/com/sk89q/worldedit/util/TargetBlock.java index 5acba026c..670e09726 100644 --- a/src/main/java/com/sk89q/worldedit/util/TargetBlock.java +++ b/src/main/java/com/sk89q/worldedit/util/TargetBlock.java @@ -27,6 +27,8 @@ import com.sk89q.worldedit.BlockWorldVector; import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldVectorFace; +import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockType; /** @@ -110,7 +112,7 @@ public class TargetBlock { boolean searchForLastBlock = true; BlockWorldVector lastBlock = null; while (getNextBlock() != null) { - if (world.getBlockType(getCurrentBlock()) == 0) { + if (world.getBlockType(getCurrentBlock()) == BlockID.AIR) { if(searchForLastBlock) { lastBlock = getCurrentBlock(); if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= 127) { @@ -196,4 +198,14 @@ public class TargetBlock { public BlockWorldVector getPreviousBlock() { return new BlockWorldVector(world, prevPos); } + + public WorldVectorFace getAnyTargetBlockFace() { + getAnyTargetBlock(); + return WorldVectorFace.getWorldVectorFace(world, getCurrentBlock(), getPreviousBlock()); + } + + public WorldVectorFace getTargetBlockFace() { + getAnyTargetBlock(); + return WorldVectorFace.getWorldVectorFace(world, getCurrentBlock(), getPreviousBlock()); + } } \ No newline at end of file