From 6f6a82d326f4e323bb028a94f3d06cada5dd0818 Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 19 Jan 2011 01:12:05 -0800 Subject: [PATCH] Ported block tracing code to WorldEdit. --- src/com/sk89q/worldedit/LocalPlayer.java | 37 +- src/com/sk89q/worldedit/Vector.java | 14 + .../sk89q/worldedit/bukkit/BukkitPlayer.java | 52 -- .../sk89q/worldedit/bukkit/TargetBlock.java | 625 ------------------ src/com/sk89q/worldedit/util/TargetBlock.java | 174 +++++ 5 files changed, 222 insertions(+), 680 deletions(-) delete mode 100644 src/com/sk89q/worldedit/bukkit/TargetBlock.java create mode 100644 src/com/sk89q/worldedit/util/TargetBlock.java diff --git a/src/com/sk89q/worldedit/LocalPlayer.java b/src/com/sk89q/worldedit/LocalPlayer.java index 3916be495..b5a0b878a 100644 --- a/src/com/sk89q/worldedit/LocalPlayer.java +++ b/src/com/sk89q/worldedit/LocalPlayer.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit; import com.sk89q.worldedit.bags.BlockBag; import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.util.TargetBlock; /** * @@ -298,7 +299,10 @@ public abstract class LocalPlayer { * @param range * @return point */ - public abstract WorldVector getBlockTrace(int range); + public WorldVector getBlockTrace(int range) { + TargetBlock tb = new TargetBlock(this, range, 0.2); + return tb.getTargetBlock(); + } /** * Get the point of the block being looked at. May return null. @@ -306,7 +310,10 @@ public abstract class LocalPlayer { * @param range * @return point */ - public abstract WorldVector getSolidBlockTrace(int range); + public WorldVector getSolidBlockTrace(int range) { + TargetBlock tb = new TargetBlock(this, range, 0.2); + return tb.getSolidTargetBlock(); + } /** * Get the player's cardinal direction (N, W, NW, etc.). May return null. @@ -418,7 +425,31 @@ public abstract class LocalPlayer { * @param range * @return whether the player was pass through */ - public abstract boolean passThroughForwardWall(int range); + public boolean passThroughForwardWall(int range) { + boolean foundNext = false; + int searchDist = 0; + TargetBlock hitBlox = new TargetBlock(this, range, 0.2); + LocalWorld world = getPosition().getWorld(); + BlockWorldVector block; + while ((block = hitBlox.getNextBlock()) != null) { + searchDist++; + if (searchDist > 20) { + return false; + } + if (BlockType.canPassThrough(world.getBlockType(block))) { + if (foundNext) { + Vector v = new Vector(block.getX(), block.getY() - 1, block.getZ()); + if (BlockType.canPassThrough(world.getBlockType(v))) { + setPosition(v.add(0.5, 0, 0.5)); + return true; + } + } + } else { + foundNext = true; + } + } + return false; + } /** * Print a message. diff --git a/src/com/sk89q/worldedit/Vector.java b/src/com/sk89q/worldedit/Vector.java index 8a4e62800..018ca498a 100644 --- a/src/com/sk89q/worldedit/Vector.java +++ b/src/com/sk89q/worldedit/Vector.java @@ -532,6 +532,20 @@ public class Vector { (int)Math.floor(z)); } + /** + * Get a block point from a point. + * + * @param x + * @param y + * @param z + * @return point + */ + public BlockVector toBlockPoint() { + return new BlockVector((int)Math.floor(x), + (int)Math.floor(y), + (int)Math.floor(z)); + } + /** * Checks if another object is equivalent. * diff --git a/src/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/src/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 6c1d8b961..d7815bfff 100644 --- a/src/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/src/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -20,12 +20,10 @@ package com.sk89q.worldedit.bukkit; import org.bukkit.*; -import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import com.sk89q.worldedit.*; import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.blocks.BlockType; public class BukkitPlayer extends LocalPlayer { private Player player; @@ -37,29 +35,6 @@ public class BukkitPlayer extends LocalPlayer { this.player = player; } - @Override - public WorldVector getBlockTrace(int range) { - TargetBlock tb = new TargetBlock(player, range, 0.2); - Block block = tb.getTargetBlock(); - if (block == null) { - return null; - } - return new WorldVector(getWorld(), block.getX(), block.getY(), block.getZ()); - } - - @Override - public WorldVector getSolidBlockTrace(int range) { - TargetBlock tb = new TargetBlock(player, range, 0.2); - tb.reset(); - while (tb.getNextBlock() != null - && BlockType.canPassThrough(tb.getCurrentBlock().getTypeId())); - Block block = tb.getCurrentBlock(); - if (block == null) { - return null; - } - return new WorldVector(getWorld(), block.getX(), block.getY(), block.getZ()); - } - @Override public int getItemInHand() { ItemStack itemStack = player.getItemInHand(); @@ -94,33 +69,6 @@ public class BukkitPlayer extends LocalPlayer { // TODO: Make this actually give the item } - @Override - public boolean passThroughForwardWall(int range) { - boolean foundNext = false; - int searchDist = 0; - TargetBlock hitBlox = new TargetBlock(player, range, 0.2); - LocalWorld world = getPosition().getWorld(); - Block block; - while ((block = hitBlox.getNextBlock()) != null) { - searchDist++; - if (searchDist > 20) { - return false; - } - if (BlockType.canPassThrough(block.getTypeId())) { - if (foundNext) { - Vector v = new Vector(block.getX(), block.getY() - 1, block.getZ()); - if (BlockType.canPassThrough(world.getBlockType(v))) { - setPosition(v.add(0.5, 0, 0.5)); - return true; - } - } - } else { - foundNext = true; - } - } - return false; - } - @Override public void printRaw(String msg) { player.sendMessage(msg); diff --git a/src/com/sk89q/worldedit/bukkit/TargetBlock.java b/src/com/sk89q/worldedit/bukkit/TargetBlock.java deleted file mode 100644 index 472919223..000000000 --- a/src/com/sk89q/worldedit/bukkit/TargetBlock.java +++ /dev/null @@ -1,625 +0,0 @@ -package com.sk89q.worldedit.bukkit; - -import java.util.ArrayList; -import org.bukkit.block.Block; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.util.Vector; - -/** - * @author toi Thanks to Raphfrk for optimization of this class. - */ -public class TargetBlock { - - private Location loc; - private double viewHeight; - private int maxDistance; - private int[] blockToIgnore; - private double checkDistance, curDistance; - private double xRotation, yRotation; - private Vector targetPos = new Vector(); - private Vector targetPosDouble = new Vector(); - private Vector prevPos = new Vector(); - private Vector offset = new Vector(); - - /** - * Constructor requiring a player, uses default values - * - * @param player - * Player to work with - */ - public TargetBlock(Player player) { - this.setValues(player.getLocation(), 300, 1.65, 0.2, null); - } - - /** - * Constructor requiring a location, uses default values - * - * @param loc - * Location to work with - */ - public TargetBlock(Location loc) { - this.setValues(loc, 300, 0, 0.2, null); - } - - /** - * Constructor requiring a player, max distance and a checking distance - * - * @param player - * Player to work with - * @param maxDistance - * How far it checks for blocks - * @param checkDistance - * How often to check for blocks, the smaller the more precise - */ - public TargetBlock(Player player, int maxDistance, double checkDistance) { - this.setValues(player.getLocation(), maxDistance, 1.65, checkDistance, - null); - } - - /** - * Constructor requiring a location, max distance and a checking distance - * - * @param loc - * What location to work with - * @param maxDistance - * How far it checks for blocks - * @param checkDistance - * How often to check for blocks, the smaller the more precise - */ - public TargetBlock(Location loc, int maxDistance, double checkDistance) { - this.setValues(loc, maxDistance, 0, checkDistance, null); - } - - /** - * Constructor requiring a player, max distance, checking distance and an - * array of blocks to ignore - * - * @param player - * What player to work with - * @param maxDistance - * How far it checks for blocks - * @param checkDistance - * How often to check for blocks, the smaller the more precise - * @param blocksToIgnore - * Integer array of what block ids to ignore while checking for - * viable targets - */ - public TargetBlock(Player player, int maxDistance, double checkDistance, - int[] blocksToIgnore) { - this.setValues(player.getLocation(), maxDistance, 1.65, checkDistance, - blocksToIgnore); - } - - /** - * Constructor requiring a location, max distance, checking distance and an - * array of blocks to ignore - * - * @param loc - * What location to work with - * @param maxDistance - * How far it checks for blocks - * @param checkDistance - * How often to check for blocks, the smaller the more precise - * @param blocksToIgnore - * Array of what block ids to ignore while checking for viable - * targets - */ - public TargetBlock(Location loc, int maxDistance, double checkDistance, - int[] blocksToIgnore) { - this.setValues(loc, maxDistance, 0, checkDistance, blocksToIgnore); - } - - /** - * Constructor requiring a player, max distance, checking distance and an - * array of blocks to ignore - * - * @param player - * What player to work with - * @param maxDistance - * How far it checks for blocks - * @param checkDistance - * How often to check for blocks, the smaller the more precise - * @param blocksToIgnore - * String ArrayList of what block ids to ignore while checking - * for viable targets - */ - public TargetBlock(Player player, int maxDistance, double checkDistance, - ArrayList blocksToIgnore) { - int[] bti = this.convertStringArraytoIntArray(blocksToIgnore); - this.setValues(player.getLocation(), maxDistance, 1.65, checkDistance, - bti); - } - - /** - * Constructor requiring a location, max distance, checking distance and an - * array of blocks to ignore - * - * @param loc - * What location to work with - * @param maxDistance - * How far it checks for blocks - * @param checkDistance - * How often to check for blocks, the smaller the more precise - * @param blocksToIgnore - * String ArrayList of what block ids to ignore while checking - * for viable targets - */ - public TargetBlock(Location loc, int maxDistance, double checkDistance, - ArrayList blocksToIgnore) { - int[] bti = this.convertStringArraytoIntArray(blocksToIgnore); - this.setValues(loc, maxDistance, 0, checkDistance, bti); - } - - /** - * Set the values, all constructors uses this function - * - * @param loc - * Location of the view - * @param maxDistance - * How far it checks for blocks - * @param viewPos - * Where the view is positioned in y-axis - * @param checkDistance - * How often to check for blocks, the smaller the more precise - * @param blocksToIgnore - * Ids of blocks to ignore while checking for viable targets - */ - private void setValues(Location loc, int maxDistance, double viewHeight, - double checkDistance, int[] blocksToIgnore) { - this.loc = loc; - this.maxDistance = maxDistance; - this.viewHeight = viewHeight; - this.checkDistance = checkDistance; - this.blockToIgnore = blocksToIgnore; - this.curDistance = 0; - xRotation = (loc.getYaw() + 90) % 360; - yRotation = loc.getPitch() * -1; - - double h = (checkDistance * Math.cos(Math.toRadians(yRotation))); - offset.setY((checkDistance * Math.sin(Math.toRadians(yRotation)))); - offset.setX((h * Math.cos(Math.toRadians(xRotation)))); - offset.setZ((h * Math.sin(Math.toRadians(xRotation)))); - - targetPosDouble = new Vector(loc.getX(), loc.getY() + viewHeight, - loc.getZ()); - targetPos = new Vector(targetPosDouble.getBlockX(), - targetPosDouble.getBlockY(), targetPosDouble.getBlockZ()); - prevPos = targetPos.clone(); - } - - /** - * Call this to reset checking position to allow you to check for a new - * target with the same TargetBlock instance. - */ - public void reset() { - targetPosDouble = new Vector(loc.getX(), loc.getY() + viewHeight, - loc.getZ()); - targetPos = new Vector(targetPosDouble.getBlockX(), - targetPosDouble.getBlockY(), targetPosDouble.getBlockZ()); - prevPos = targetPos.clone(); - this.curDistance = 0; - } - - /** - * Gets the distance to a block. Measures from the block underneath the - * player to the targetblock Should only be used when passing player as an - * constructor parameter - * - * @return double - */ - public double getDistanceToBlock() { - Vector blockUnderPlayer = new Vector( - (int) Math.floor(loc.getX() + 0.5), - (int) Math.floor(loc.getY() - 0.5), - (int) Math.floor(loc.getZ() + 0.5)); - - Block blk = getTargetBlock(); - double x = blk.getX() - blockUnderPlayer.getBlockX(); - double y = blk.getY() - blockUnderPlayer.getBlockY(); - double z = blk.getZ() - blockUnderPlayer.getBlockZ(); - - return Math.sqrt((Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2))); - } - - /** - * Gets the rounded distance to a block. Measures from the block underneath - * the player to the targetblock Should only be used when passing player as - * an constructor parameter - * - * @return int - */ - public int getDistanceToBlockRounded() { - Vector blockUnderPlayer = new Vector( - (int) Math.floor(loc.getX() + 0.5), - (int) Math.floor(loc.getY() - 0.5), - (int) Math.floor(loc.getZ() + 0.5)); - - Block blk = getTargetBlock(); - double x = blk.getX() - blockUnderPlayer.getBlockX(); - double y = blk.getY() - blockUnderPlayer.getBlockY(); - double z = blk.getZ() - blockUnderPlayer.getBlockZ(); - - return (int) Math - .round((Math.sqrt((Math.pow(x, 2) + Math.pow(y, 2) + Math.pow( - z, 2))))); - } - - /** - * Gets the floored x distance to a block. - * - * @return int - */ - public int getXDistanceToBlock() { - this.reset(); - return (int) Math - .floor(getTargetBlock().getX() - loc.getBlockX() + 0.5); - } - - /** - * Gets the floored y distance to a block - * - * @return int - */ - public int getYDistanceToBlock() { - this.reset(); - return (int) Math.floor(getTargetBlock().getY() - loc.getBlockY() - + viewHeight); - } - - /** - * Gets the floored z distance to a block - * - * @return int - */ - public int getZDistanceToBlock() { - this.reset(); - return (int) Math - .floor(getTargetBlock().getZ() - loc.getBlockZ() + 0.5); - } - - /** - * Returns the block at the sight. Returns null if out of range or if no - * viable target was found - * - * @return Block - */ - public Block getTargetBlock() { - this.reset(); - while ((getNextBlock() != null) - && ((getCurrentBlock().getTypeId() == 0) || this - .blockToIgnoreHasValue(getCurrentBlock().getTypeId()))) - ; - return getCurrentBlock(); - } - - /** - * Sets the type of the block at the sight. Returns false if the block - * wasn't set. - * - * @param typeID - * ID of type to set the block to - * @return boolean - */ - public boolean setTargetBlock(int typeID) { - if (Material.getMaterial(typeID) != null) { - this.reset(); - while (getNextBlock() != null && getCurrentBlock().getTypeId() == 0) - ; - if (getCurrentBlock() != null) { - Block blk = loc.getWorld().getBlockAt(targetPos.getBlockX(), - targetPos.getBlockY(), targetPos.getBlockZ()); - blk.setTypeId(typeID); - return true; - } - } - return false; - } - - /** - * Sets the type of the block at the sight. Returns false if the block - * wasn't set. - * - * @param type - * Material to set the block to - * @return boolean - */ - public boolean setTargetBlock(Material type) { - this.reset(); - while ((getNextBlock() != null) - && ((getCurrentBlock().getTypeId() == 0) || this - .blockToIgnoreHasValue(getCurrentBlock().getTypeId()))) - ; - if (getCurrentBlock() != null) { - Block blk = loc.getWorld().getBlockAt(targetPos.getBlockX(), - targetPos.getBlockY(), targetPos.getBlockZ()); - blk.setType(type); - return true; - } - return false; - } - - /** - * Sets the type of the block at the sight. Returns false if the block - * wasn't set. Observe! At the moment this function is using the built-in - * enumerator function .valueOf(String) but would preferably be changed to - * smarter function, when implemented - * - * @param type - * Name of type to set the block to - * @return boolean - */ - public boolean setTargetBlock(String type) { - Material mat = Material.valueOf(type); - if (mat != null) { - this.reset(); - while ((getNextBlock() != null) - && ((getCurrentBlock().getTypeId() == 0) || this - .blockToIgnoreHasValue(getCurrentBlock() - .getTypeId()))) - ; - if (getCurrentBlock() != null) { - Block blk = loc.getWorld().getBlockAt(targetPos.getBlockX(), - targetPos.getBlockY(), targetPos.getBlockZ()); - blk.setType(mat); - return true; - } - } - return false; - } - - /** - * Returns the block attached to the face at the sight. Returns null if out - * of range or if no viable target was found - * - * @return Block - */ - public Block getFaceBlock() { - while ((getNextBlock() != null) - && ((getCurrentBlock().getTypeId() == 0) || this - .blockToIgnoreHasValue(getCurrentBlock().getTypeId()))) - ; - if (getCurrentBlock() != null) { - return getPreviousBlock(); - } else { - return null; - } - } - - /** - * Sets the type of the block attached to the face at the sight. Returns - * false if the block wasn't set. - * - * @param typeID - * @return boolean - */ - public boolean setFaceBlock(int typeID) { - if (Material.getMaterial(typeID) != null) { - if (getCurrentBlock() != null) { - Block blk = loc.getWorld().getBlockAt(prevPos.getBlockX(), - prevPos.getBlockY(), prevPos.getBlockZ()); - blk.setTypeId(typeID); - return true; - } - } - return false; - } - - /** - * Sets the type of the block attached to the face at the sight. Returns - * false if the block wasn't set. - * - * @param type - * @return boolean - */ - public boolean setFaceBlock(Material type) { - if (getCurrentBlock() != null) { - Block blk = loc.getWorld().getBlockAt(prevPos.getBlockX(), - prevPos.getBlockY(), prevPos.getBlockZ()); - blk.setType(type); - return true; - } - return false; - } - - /** - * Sets the type of the block attached to the face at the sight. Returns - * false if the block wasn't set. Observe! At the moment this function is - * using the built-in enumerator function .valueOf(String) but would - * preferably be changed to smarter function, when implemented - * - * @param type - * @return boolean - */ - public boolean setFaceBlock(String type) { - Material mat = Material.valueOf(type); - if (mat != null) { - if (getCurrentBlock() != null) { - Block blk = loc.getWorld().getBlockAt(prevPos.getBlockX(), - prevPos.getBlockY(), prevPos.getBlockZ()); - blk.setType(mat); - return true; - } - } - return false; - } - - /** - * Get next block - * - * @return Block - */ - public Block getNextBlock() { - prevPos = targetPos.clone(); - do { - curDistance += checkDistance; - - targetPosDouble.setX(offset.getX() + targetPosDouble.getX()); - targetPosDouble.setY(offset.getY() + targetPosDouble.getY()); - targetPosDouble.setZ(offset.getZ() + targetPosDouble.getZ()); - targetPos = new Vector(targetPosDouble.getBlockX(), - targetPosDouble.getBlockY(), targetPosDouble.getBlockZ()); - } while (curDistance <= maxDistance - && targetPos.getBlockX() == prevPos.getBlockX() - && targetPos.getBlockY() == prevPos.getBlockY() - && targetPos.getBlockZ() == prevPos.getBlockZ()); - if (curDistance > maxDistance) { - return null; - } - - return this.loc.getWorld().getBlockAt(this.targetPos.getBlockX(), - this.targetPos.getBlockY(), this.targetPos.getBlockZ()); - } - - /** - * Returns the current block along the line of vision - * - * @return Block - */ - public Block getCurrentBlock() { - if (curDistance > maxDistance) { - return null; - } else { - return this.loc.getWorld().getBlockAt(this.targetPos.getBlockX(), - this.targetPos.getBlockY(), this.targetPos.getBlockZ()); - } - } - - /** - * Sets current block type. Returns false if the block wasn't set. - * - * @param typeID - */ - public boolean setCurrentBlock(int typeID) { - if (Material.getMaterial(typeID) != null) { - Block blk = getCurrentBlock(); - if (blk != null) { - blk.setTypeId(typeID); - return true; - } - } - return false; - } - - /** - * Sets current block type. Returns false if the block wasn't set. - * - * @param type - */ - public boolean setCurrentBlock(Material type) { - Block blk = getCurrentBlock(); - if (blk != null) { - blk.setType(type); - return true; - } - return false; - } - - /** - * Sets current block type. Returns false if the block wasn't set. Observe! - * At the moment this function is using the built-in enumerator function - * .valueOf(String) but would preferably be changed to smarter function, - * when implemented - * - * @param type - */ - public boolean setCurrentBlock(String type) { - Material mat = Material.valueOf(type); - if (mat != null) { - Block blk = getCurrentBlock(); - if (blk != null) { - blk.setType(mat); - return true; - } - } - return false; - } - - /** - * Returns the previous block in the aimed path - * - * @return Block - */ - public Block getPreviousBlock() { - return this.loc.getWorld().getBlockAt(prevPos.getBlockX(), - prevPos.getBlockY(), prevPos.getBlockZ()); - } - - /** - * Sets previous block type id. Returns false if the block wasn't set. - * - * @param typeID - */ - public boolean setPreviousBlock(int typeID) { - if (Material.getMaterial(typeID) != null) { - Block blk = getPreviousBlock(); - if (blk != null) { - blk.setTypeId(typeID); - return true; - } - } - return false; - } - - /** - * Sets previous block type id. Returns false if the block wasn't set. - * - * @param type - */ - public boolean setPreviousBlock(Material type) { - Block blk = getPreviousBlock(); - if (blk != null) { - blk.setType(type); - return true; - } - return false; - } - - /** - * Sets previous block type id. Returns false if the block wasn't set. - * Observe! At the moment this function is using the built-in enumerator - * function .valueOf(String) but would preferably be changed to smarter - * function, when implemented - * - * @param type - */ - public boolean setPreviousBlock(String type) { - Material mat = Material.valueOf(type); - if (mat != null) { - Block blk = getPreviousBlock(); - if (blk != null) { - blk.setType(mat); - return true; - } - } - return false; - } - - private int[] convertStringArraytoIntArray(ArrayList array) { - if (array != null) { - int intarray[] = new int[array.size()]; - for (int i = 0; i < array.size(); i++) { - try { - intarray[i] = Integer.parseInt(array.get(i)); - } catch (NumberFormatException nfe) { - intarray[i] = 0; - } - } - return intarray; - } - return null; - } - - private boolean blockToIgnoreHasValue(int value) { - if (this.blockToIgnore != null) { - if (this.blockToIgnore.length > 0) { - for (int i : this.blockToIgnore) { - if (i == value) - return true; - } - } - } - return false; - } -} \ No newline at end of file diff --git a/src/com/sk89q/worldedit/util/TargetBlock.java b/src/com/sk89q/worldedit/util/TargetBlock.java new file mode 100644 index 000000000..9ef5f3f19 --- /dev/null +++ b/src/com/sk89q/worldedit/util/TargetBlock.java @@ -0,0 +1,174 @@ +// $Id$ +/* + * Copyright (c) 2011 toi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. +*/ + +package com.sk89q.worldedit.util; + +import com.sk89q.worldedit.BlockWorldVector; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BlockType; + +/** + * This class uses an inefficient method to figure out what block a player + * is looking towards. + * + * Originally written by toi. It was ported to WorldEdit and trimmed down by + * sk89q. Thanks to Raphfrk for optimization of toi's original class. + * + * @author toi + */ +public class TargetBlock { + private LocalWorld world; + private int maxDistance; + private double checkDistance, curDistance; + private Vector targetPos = new Vector(); + private Vector targetPosDouble = new Vector(); + private Vector prevPos = new Vector(); + private Vector offset = new Vector(); + + /** + * Constructor requiring a player, uses default values + * + * @param player player to work with + */ + public TargetBlock(LocalPlayer player) { + this.world = player.getWorld(); + this.setValues(player.getPosition(), player.getYaw(), player.getPitch(), + 300, 1.65, 0.2); + } + + /** + * Constructor requiring a player, max distance and a checking distance + * + * @param player LocalPlayer to work with + * @param maxDistance how far it checks for blocks + * @param checkDistance how often to check for blocks, the smaller the more precise + */ + public TargetBlock(LocalPlayer player, int maxDistance, double checkDistance) { + this.world = player.getWorld(); + this.setValues(player.getPosition(), player.getYaw(), player.getPitch(), + maxDistance, 1.65, checkDistance); + } + + /** + * Set the values, all constructors uses this function + * + * @param loc location of the view + * @param xRotation + * @param yRotation + * @param maxDistance how far it checks for blocks + * @param viewPos where the view is positioned in y-axis + * @param checkDistance how often to check for blocks, the smaller the more precise + */ + private void setValues(Vector loc, double xRotation, double yRotation, + int maxDistance, double viewHeight, double checkDistance) { + this.maxDistance = maxDistance; + this.checkDistance = checkDistance; + this.curDistance = 0; + xRotation = (xRotation + 90) % 360; + yRotation = yRotation * -1; + + double h = (checkDistance * Math.cos(Math.toRadians(yRotation))); + + offset = new Vector((h * Math.cos(Math.toRadians(xRotation))), + (checkDistance * Math.sin(Math.toRadians(yRotation))), + (h * Math.sin(Math.toRadians(xRotation)))); + + targetPosDouble = loc.add(0, viewHeight, 0); + targetPos = targetPosDouble.toBlockPoint(); + prevPos = targetPos; + } + + /** + * Returns the block at the sight. Returns null if out of range or if no + * viable target was found + * + * @return Block + */ + public BlockWorldVector getTargetBlock() { + while ((getNextBlock() != null) + && (world.getBlockType(getCurrentBlock()) == 0)); + return getCurrentBlock(); + } + + /** + * Returns the block at the sight. Returns null if out of range or if no + * viable target was found + * + * @return Block + */ + public BlockWorldVector getSolidTargetBlock() { + while ((getNextBlock() != null) + && BlockType.canPassThrough(world.getBlockType(getCurrentBlock()))); + return getCurrentBlock(); + } + + /** + * Get next block + * + * @return next block position + */ + public BlockWorldVector getNextBlock() { + prevPos = targetPos; + do { + curDistance += checkDistance; + + targetPosDouble = offset.add(targetPosDouble.getX(), + targetPosDouble.getY(), + targetPosDouble.getZ()); + targetPos = targetPosDouble.toBlockPoint(); + } while (curDistance <= maxDistance + && targetPos.getBlockX() == prevPos.getBlockX() + && targetPos.getBlockY() == prevPos.getBlockY() + && targetPos.getBlockZ() == prevPos.getBlockZ()); + + if (curDistance > maxDistance) { + return null; + } + + return new BlockWorldVector(world, targetPos); + } + + /** + * Returns the current block along the line of vision + * + * @return block position + */ + public BlockWorldVector getCurrentBlock() { + if (curDistance > maxDistance) { + return null; + } else { + return new BlockWorldVector(world, targetPos); + } + } + + /** + * Returns the previous block in the aimed path + * + * @return block position + */ + public BlockWorldVector getPreviousBlock() { + return new BlockWorldVector(world, prevPos); + } +} \ No newline at end of file