Added a tool that allows a player to place and remove blocks at a distance.

This commit is contained in:
Wizjany 2011-09-18 21:49:45 -04:00
parent 1a6bc6f42c
commit 67a7969cd1
7 changed files with 353 additions and 8 deletions

View File

@ -31,7 +31,7 @@ import com.sk89q.worldedit.util.TargetBlock;
* *
* @author sk89q * @author sk89q
*/ */
public abstract class LocalPlayer { public abstract class LocalPlayer {
/** /**
* Server. * Server.
*/ */
@ -319,7 +319,11 @@ public abstract class LocalPlayer {
TargetBlock tb = new TargetBlock(this, range, 0.2); TargetBlock tb = new TargetBlock(this, range, 0.2);
return (useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock()); 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. * Get the point of the block being looked at. May return null.
* *

View File

@ -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;
}
}

View File

@ -0,0 +1,148 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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));
}
}

View File

@ -192,4 +192,24 @@ public class ToolCommands {
session.setTool(player.getItemInHand(), new DistanceWand()); session.setTool(player.getItemInHand(), new DistanceWand());
player.print("Far wand tool bound to " + ItemType.toHeldName(player.getItemInHand()) + "."); player.print("Far wand tool bound to " + ItemType.toHeldName(player.getItemInHand()) + ".");
} }
@Command(
aliases = {"lrbuild", "/lrbuild"},
usage = "<leftclick block> <rightclick block>",
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()) + ".");
}
} }

View File

@ -167,11 +167,7 @@ public class BrushTool implements TraceTool {
public boolean actPrimary(ServerInterface server, LocalConfiguration config, public boolean actPrimary(ServerInterface server, LocalConfiguration config,
LocalPlayer player, LocalSession session) { LocalPlayer player, LocalSession session) {
WorldVector target = null; WorldVector target = null;
if (this.range > -1) { target = player.getBlockTrace(getRange(), true);
target = player.getBlockTrace(getRange(), true);
} else {
target = player.getBlockTrace(MAX_RANGE);
}
if (target == null) { if (target == null) {
player.printError("No block in sight!"); player.printError("No block in sight!");

View File

@ -0,0 +1,97 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -27,6 +27,8 @@ import com.sk89q.worldedit.BlockWorldVector;
import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.LocalPlayer;
import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldVectorFace;
import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.blocks.BlockType;
/** /**
@ -110,7 +112,7 @@ public class TargetBlock {
boolean searchForLastBlock = true; boolean searchForLastBlock = true;
BlockWorldVector lastBlock = null; BlockWorldVector lastBlock = null;
while (getNextBlock() != null) { while (getNextBlock() != null) {
if (world.getBlockType(getCurrentBlock()) == 0) { if (world.getBlockType(getCurrentBlock()) == BlockID.AIR) {
if(searchForLastBlock) { if(searchForLastBlock) {
lastBlock = getCurrentBlock(); lastBlock = getCurrentBlock();
if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= 127) { if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= 127) {
@ -196,4 +198,14 @@ public class TargetBlock {
public BlockWorldVector getPreviousBlock() { public BlockWorldVector getPreviousBlock() {
return new BlockWorldVector(world, prevPos); 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());
}
} }