diff --git a/pom.xml b/pom.xml index 39428aa..59c811d 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 me.simplex buildr - 0.8.0-SNAPSHOT + 0.8.2-SNAPSHOT Buildr @@ -35,6 +35,14 @@ pwasson + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + private + + @@ -49,7 +57,7 @@ org.bukkit bukkit - [1.8,) + [1.9,) diff --git a/src/main/java/me/simplex/buildr/Buildr.java b/src/main/java/me/simplex/buildr/Buildr.java index 9944186..920a221 100644 --- a/src/main/java/me/simplex/buildr/Buildr.java +++ b/src/main/java/me/simplex/buildr/Buildr.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 s1mpl3x + * Copyright 2012-2015 s1mpl3x * * This file is part of Buildr. * @@ -49,7 +49,8 @@ import me.simplex.buildr.manager.commands.Buildr_Manager_Command_Wool; import me.simplex.buildr.manager.commands.SlopeCommand; import me.simplex.buildr.runnable.Buildr_Runnable_TimeChecker; -import me.simplex.buildr.util.Buildr_Interface_Building; +import me.simplex.buildr.manager.builder.BuilderManager; +import me.simplex.buildr.manager.commands.CloneCommand; import org.bukkit.ChatColor; import org.bukkit.GameMode; @@ -58,6 +59,8 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; @@ -66,7 +69,7 @@ public class Buildr extends JavaPlugin { //tech public Server server; - private Logger log = Logger.getLogger("Minecraft"); + private final Logger log = Logger.getLogger("Minecraft"); private String prefix; private String version; @@ -99,6 +102,7 @@ public class Buildr extends JavaPlugin { private Buildr_Manager_Command_Wall cmdWall; private Buildr_Manager_Command_Wallx cmdWallx; private SlopeCommand cmdSlope; + private CloneCommand cmdClone; private Buildr_Manager_Command_Wool cmdWool; private String pluginDirectory; @@ -109,7 +113,7 @@ public class Buildr extends JavaPlugin { private ArrayList worldBuildMode; private ArrayList worldBuildAllowed; private ArrayList playerBuildMode; - private ArrayList startedBuildings; + private ArrayList startedBuildings; private LinkedList playerCuttingTree; @@ -126,7 +130,7 @@ public void onEnable() { pluginDirectory = "plugins/Buildr"; version = getDescription().getVersion(); - version_cfg = "0.8.0"; + version_cfg = "0.8.1"; prefix = "[Buildr] "; cfgManager = new Buildr_Manager_Configuration(this); @@ -156,12 +160,13 @@ public void onEnable() { cmdWall = new Buildr_Manager_Command_Wall(this); cmdWallx = new Buildr_Manager_Command_Wallx(this); cmdSlope = new SlopeCommand(this); + cmdClone = new CloneCommand(this); cmdWool = new Buildr_Manager_Command_Wool(this); worldBuildMode = new ArrayList(); worldBuildAllowed = new ArrayList(); playerBuildMode = new ArrayList(); - startedBuildings = new ArrayList(); + startedBuildings = new ArrayList(); playerCuttingTree = new LinkedList(); if (cfgManager.checkDirectory()) { @@ -213,6 +218,7 @@ public void onEnable() { getCommand("wall").setExecutor(cmdWall); getCommand("wallx").setExecutor(cmdWallx); getCommand("slope").setExecutor(cmdSlope); + getCommand("bclone").setExecutor(cmdClone); getCommand("wool").setExecutor(cmdWool); log("command executors set.."); @@ -246,25 +252,31 @@ public void log(String msg){ log.info(prefix+msg); } } - + + public void importantLog(String msg){ log.info(prefix+msg); } - + + public boolean checkPermission(Player player, String node){ if (!getConfigValue("GENERAL_USE_PERMISSIONS")) { return player.isOp(); } return player.hasPermission(node); } - + + public boolean checkWorldBuildMode(World world){ return worldBuildMode.contains(world); } + + public boolean checkPlayerBuildMode(Player player){ return playerBuildMode.contains(player); } - + + public void handlePlayerOnLogin(Player player){ //System.out.println("BM_STAY_AFTR_LGOUT"+getConfigValue("BUILDMODE_STAY_AFTER_LOGOUT")); if (!getConfigValue("BUILDMODE_STAY_AFTER_LOGOUT") && checkPlayerBuildMode(player)) { @@ -277,101 +289,129 @@ public void handlePlayerOnLogin(Player player){ //System.out.println("enter bm"); } } - - public boolean checkPlayerHasStartedBuilding(Player player){ - for (Buildr_Interface_Building wallbuilder : startedBuildings) { - if (wallbuilder.getBuildingcreater() == player) { - return true; - } - } - return false; - } - - public boolean checkWorldHasBuildmodeUnlocked(World world){ - for (World allowed : worldBuildAllowed) { - if (allowed.equals(world)) { - return true; - } - } - return false; - } - + + + public boolean checkPlayerHasStartedBuilding(Player player) { + for (BuilderManager wallbuilder : startedBuildings) { + if (wallbuilder.getBuildingCreator() == player) { + return true; + } + } + return false; + } + + + public boolean checkWorldHasBuildmodeUnlocked(World world) { + for (World allowed : worldBuildAllowed) { + if (allowed.equals(world)) { + return true; + } + } + return false; + } + + public boolean checkTreecuterFireOnLeaves(Block block) { - if (block.getType()== Material.LEAVES && getConfigValue("TREECUTTER_ACTIVATE_ON_LEAVES")) { - return true; - } - return false; + return (block.getType()== Material.LEAVES && getConfigValue("TREECUTTER_ACTIVATE_ON_LEAVES")); } - - public Buildr_Interface_Building giveBuilderManager(Player player){ - for (Buildr_Interface_Building builder : startedBuildings) { - if (builder.getBuildingcreater() == player) { + + + public BuilderManager giveBuilderManager(Player player){ + for (BuilderManager builder : startedBuildings) { + if (builder.getBuildingCreator() == player) { return builder; } } return null; } - + + public void removeStartedBuilding(Player player){ - for (Buildr_Interface_Building wallbuilder : startedBuildings) { - if (wallbuilder.getBuildingcreater() == player) { + for (BuilderManager wallbuilder : startedBuildings) { + if (wallbuilder.getBuildingCreator() == player) { startedBuildings.remove(wallbuilder); return; } } } - + + public boolean checkPlayerItemInHandIsPickaxe(Player player){ - if (player.getItemInHand().getType() == Material.DIAMOND_PICKAXE || + return (player.getItemInHand().getType() == Material.DIAMOND_PICKAXE || player.getItemInHand().getType() == Material.IRON_PICKAXE || player.getItemInHand().getType() == Material.STONE_PICKAXE || - player.getItemInHand().getType() == Material.WOOD_PICKAXE) { - return true; - } - return false; + player.getItemInHand().getType() == Material.WOOD_PICKAXE); } + public boolean checkPlayerItemInHandIsAxe(Player player) { - if (player.getItemInHand().getType() == Material.DIAMOND_AXE || + return (player.getItemInHand().getType() == Material.DIAMOND_AXE || player.getItemInHand().getType() == Material.IRON_AXE || player.getItemInHand().getType() == Material.STONE_AXE || - player.getItemInHand().getType() == Material.WOOD_AXE) { - return true; - } - return false; + player.getItemInHand().getType() == Material.WOOD_AXE); } - - public boolean checkPlayerItemInHandIsStick(Player player) { - if (player.getItemInHand().getType() == Material.STICK){ - return true; - } - return false; + + + public boolean checkPlayerItemInHandIsStick(Player player, + EquipmentSlot hand) { + // check HAND vs. OFF_HAND + ItemStack held = (EquipmentSlot.HAND == hand) ? player.getInventory().getItemInMainHand() : player.getInventory().getItemInOffHand(); + return (held.getType() == Material.STICK); } + public boolean playerClickedBuildingBlock(Player player, Block clickedBlock) { if (!checkPlayerHasStartedBuilding(player)) { return false; } - - Buildr_Interface_Building wallbuilder = giveBuilderManager(player); - if (!wallbuilder.isCoordinate1Placed()) { + + // if we got here, player has at least one coordinate to add. + + BuilderManager wallbuilder = giveBuilderManager(player); + + wallbuilder.addCoordinate(clickedBlock); + player.sendMessage(wallbuilder.getLastPositionMessage()); + if (wallbuilder.checkCoordinates()) { + if (wallbuilder.gotAllCoordinates()) { + player.sendMessage(wallbuilder.getBuildingMessage()); + wallbuilder.startBuild(); + removeStartedBuilding(player); + } else { + player.sendMessage(wallbuilder.getNextPositionMessage()); + } + } else {// last coordinate placed was somehow invalid. + removeStartedBuilding(player); + player.sendMessage(String.format("%sERROR: %s%s", + ChatColor.RED, ChatColor.WHITE, wallbuilder.getCoordinateCheckFailed())); + } +/* old way + if (!wallbuilder.isCoordinate1Placed()) { wallbuilder.addCoordinate1(clickedBlock); - player.sendMessage("Got positon 1 of your "+wallbuilder.getBuildingName()+" at ["+ChatColor.BLUE+clickedBlock.getX()+ChatColor.WHITE+", "+ChatColor.BLUE+clickedBlock.getY()+ChatColor.WHITE+", "+ChatColor.BLUE+clickedBlock.getZ()+ChatColor.WHITE+"]"); + player.sendMessage( + "Got positon 1 of your " + wallbuilder.getBuildingName() + " at [" + ChatColor.BLUE + + clickedBlock.getX() + ChatColor.WHITE + ", " + ChatColor.BLUE + clickedBlock.getY() + + ChatColor.WHITE + ", " + ChatColor.BLUE + clickedBlock.getZ() + + ChatColor.WHITE + "]"); player.sendMessage("Now rightclick on block 2 (again with a stick) to continue"); } else { - player.sendMessage("Got positon 2 of your"+wallbuilder.getBuildingName()+" at ["+ChatColor.BLUE+clickedBlock.getX()+ChatColor.WHITE+", "+ChatColor.BLUE+clickedBlock.getY()+ChatColor.WHITE+", "+ChatColor.BLUE+clickedBlock.getZ()+ChatColor.WHITE+"]"); - wallbuilder.addCoordinate2(clickedBlock); - if (wallbuilder.checkCoordinates()) { - player.sendMessage("Positions OK, build "+wallbuilder.getBuildingName()+".."); - wallbuilder.startBuild(); - removeStartedBuilding(player); - } - else { - removeStartedBuilding(player); - player.sendMessage(ChatColor.RED+"ERROR: "+ChatColor.WHITE+wallbuilder.getCoordinateCheckFailed()); - } - } + player.sendMessage( + "Got positon 2 of your" + wallbuilder.getBuildingName() + " at [" + ChatColor.BLUE + + clickedBlock.getX() + ChatColor.WHITE + ", " + ChatColor.BLUE + clickedBlock.getY() + + ChatColor.WHITE + ", " + ChatColor.BLUE + clickedBlock.getZ() + + ChatColor.WHITE + "]"); + wallbuilder.addCoordinate2(clickedBlock); + if (wallbuilder.checkCoordinates()) { + player.sendMessage("Positions OK, build " + wallbuilder.getBuildingName() + ".."); + wallbuilder.startBuild(); + removeStartedBuilding(player); + } else { + removeStartedBuilding(player); + player.sendMessage(ChatColor.RED + "ERROR: " + ChatColor.WHITE + + wallbuilder.getCoordinateCheckFailed()); + } + } +*/ return true; } @@ -457,7 +497,7 @@ public LinkedList getPlayerCuttingTree() { return playerCuttingTree; } - public ArrayList getStartedBuildings() { + public ArrayList getStartedBuildings() { return startedBuildings; } diff --git a/src/main/java/me/simplex/buildr/listener/Buildr_Listener_Player.java b/src/main/java/me/simplex/buildr/listener/Buildr_Listener_Player.java index 4ddefed..a2f5ffd 100644 --- a/src/main/java/me/simplex/buildr/listener/Buildr_Listener_Player.java +++ b/src/main/java/me/simplex/buildr/listener/Buildr_Listener_Player.java @@ -136,7 +136,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { } // Builders - if (event.getAction() == Action.RIGHT_CLICK_BLOCK && plugin.checkPlayerItemInHandIsStick(event.getPlayer())) { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && plugin.checkPlayerItemInHandIsStick(event.getPlayer(), event.getHand())) { if (!plugin.playerClickedBuildingBlock(event.getPlayer(),event.getClickedBlock())) { if (player.hasPermission("buildr.feature.block_info")) { String loc = ChatColor.GOLD + "X: " + block.getX() + " Y: " + block.getY() + " Z: " + block.getZ() + ChatColor.WHITE; diff --git a/src/main/java/me/simplex/buildr/manager/Buildr_Manager_Configuration.java b/src/main/java/me/simplex/buildr/manager/Buildr_Manager_Configuration.java index 2d4c568..a7db19e 100644 --- a/src/main/java/me/simplex/buildr/manager/Buildr_Manager_Configuration.java +++ b/src/main/java/me/simplex/buildr/manager/Buildr_Manager_Configuration.java @@ -85,10 +85,10 @@ public void createSettings(){ w.write("# #");w.newLine(); w.write("# BUILDR CONFIGURATION #");w.newLine(); w.write("# #");w.newLine(); - w.write("# v0.8.0 #");w.newLine(); + w.write("# v0.8.1 #");w.newLine(); w.write("############################################################");w.newLine(); w.newLine(); - w.write("CFG=0.8.0");w.newLine(); + w.write("CFG=0.8.1");w.newLine(); w.newLine(); w.write("##### General settings: ####################################");w.newLine(); w.newLine(); @@ -181,6 +181,9 @@ public void createSettings(){ w.newLine(); w.write("# Enable the slope command");w.newLine(); //done w.write("FEATURE_BUILDER_SLOPE=true");w.newLine(); + w.newLine(); + w.write("# Enable the clone command");w.newLine(); //done + w.write("FEATURE_BUILDER_CLONE=true");w.newLine(); w.newLine(); w.write("# Enable the top command");w.newLine(); //done w.write("FEATURE_TOP=true");w.newLine(); diff --git a/src/main/java/me/simplex/buildr/manager/Buildr_Manager_UndoStack.java b/src/main/java/me/simplex/buildr/manager/Buildr_Manager_UndoStack.java index 5aa07be..e9b404b 100644 --- a/src/main/java/me/simplex/buildr/manager/Buildr_Manager_UndoStack.java +++ b/src/main/java/me/simplex/buildr/manager/Buildr_Manager_UndoStack.java @@ -19,7 +19,8 @@ package me.simplex.buildr.manager; import java.util.ArrayList; -import java.util.HashMap; +import java.util.List; +import java.util.Map; import me.simplex.buildr.util.Buildr_Container_UndoBlock; import me.simplex.buildr.util.Buildr_Stack_Undo; @@ -28,14 +29,14 @@ import org.bukkit.entity.Player; public class Buildr_Manager_UndoStack { - private ArrayList playerUndos; + private List playerUndos; public Buildr_Manager_UndoStack() { playerUndos = new ArrayList(); } - public void addToStack(HashMap blocks, Player player){ + public void addToStack(Map blocks, Player player){ if (checkPlayerUndoStackExist(player)) { giveStack(player).push(blocks); } @@ -44,11 +45,11 @@ public void addToStack(HashMap blocks, Player } } - private void newStack(Player player, HashMap blocks) { + private void newStack(Player player, Map blocks) { playerUndos.add(new Buildr_StackItem(player, blocks)); } - public HashMap getAndDeleteFromStack(Player player){ + public Map getAndDeleteFromStack(Player player){ if (checkPlayerUndoStackExist(player)) { if (!giveStack(player).isEmpty()) { return giveStack(player).poll(); @@ -79,7 +80,7 @@ private class Buildr_StackItem{ Buildr_Stack_Undo orig_blocks; Player player; - public Buildr_StackItem(Player player, HashMap blocks) { + public Buildr_StackItem(Player player, Map blocks) { this.orig_blocks = new Buildr_Stack_Undo(20); this.orig_blocks.pushWithLimit(blocks); this.player = player; diff --git a/src/main/java/me/simplex/buildr/manager/builder/AbstractBuilderManager.java b/src/main/java/me/simplex/buildr/manager/builder/AbstractBuilderManager.java index 1ef0fa2..15980fc 100644 --- a/src/main/java/me/simplex/buildr/manager/builder/AbstractBuilderManager.java +++ b/src/main/java/me/simplex/buildr/manager/builder/AbstractBuilderManager.java @@ -19,8 +19,10 @@ */ package me.simplex.buildr.manager.builder; +import java.util.ArrayList; +import java.util.List; import me.simplex.buildr.Buildr; -import me.simplex.buildr.util.Buildr_Interface_Building; +import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -31,7 +33,7 @@ * need to be so verbose. * @author pwasson */ -abstract class AbstractBuilderManager implements Buildr_Interface_Building { +abstract class AbstractBuilderManager implements BuilderManager { protected final Buildr plugin; protected final Player creator; protected final String buildingName; @@ -39,7 +41,7 @@ abstract class AbstractBuilderManager implements Buildr_Interface_Building { protected final byte material_data; protected final boolean replace; protected final Material replace_mat; - protected Block position1,position2; + protected final List positions = new ArrayList(); protected boolean coordinate1placed = false; public AbstractBuilderManager(String inBuildingName, @@ -57,29 +59,36 @@ public AbstractBuilderManager(String inBuildingName, this.replace_mat = inReplaceMaterial; } - - @Override - public Player getBuildingcreater() { - return creator; - } + /** + * get the Block position with the specified index. + * @param n the index of the position to get (1-based). + * @return the Block specifying the requested position. + */ + protected Block getPosition(int n) { + if (n < 1 || n > positions.size()) { + throw new IllegalArgumentException("invalid position index"); + } else { + return positions.get(n-1); + } + } + @Override - public boolean isCoordinate1Placed() { - return coordinate1placed; + public Player getBuildingCreator() { + return creator; } @Override - public void addCoordinate1(Block position1) { - this.position1 = position1; - coordinate1placed = true; + public boolean gotAllCoordinates() { + return (positions.size() > 1); } @Override - public void addCoordinate2(Block position2) { - this.position2 = position2; + public void addCoordinate(Block position) { + this.positions.add(position); } @@ -93,4 +102,42 @@ public boolean checkCoordinates() { public String getBuildingName() { return buildingName; } + + + @Override + public String getBuildingMessage() { + return String.format("Positions OK, building %s...", getBuildingName()); + } + + + protected String getCoordForChat(Block pos) { + return String.format("[%s%s%s, %s%s%s, %s%s%s]", + ChatColor.BLUE, pos.getX(), ChatColor.WHITE, + ChatColor.BLUE, pos.getY(), ChatColor.WHITE, + ChatColor.BLUE, pos.getZ(), ChatColor.WHITE); + } + + + @Override + public String getLastPositionMessage() { + String s; + if (positions.isEmpty()) { + return "invalid"; + } else { + Block pos = positions.get(positions.size() - 1); + return String.format("Got positon %d of your %s at %s", + positions.size(), getBuildingName(), getCoordForChat(pos)); + } + } + + + /** + * {@inheritDoc} + * This base version assumes there are only two required positions and the second is described + * as “block 2”. + */ + @Override + public String getNextPositionMessage() { + return "Now right-click on block 2 (again with a stick) to continue"; + } } diff --git a/src/main/java/me/simplex/buildr/manager/builder/BuilderManager.java b/src/main/java/me/simplex/buildr/manager/builder/BuilderManager.java new file mode 100644 index 0000000..b4e10bf --- /dev/null +++ b/src/main/java/me/simplex/buildr/manager/builder/BuilderManager.java @@ -0,0 +1,89 @@ +/* + * Copyright 2012-2015 s1mpl3x + * + * This file is part of Buildr. + * + * Buildr 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. + * + * Buildr 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 Buildr If not, see . + */ +package me.simplex.buildr.manager.builder; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + +/** + * A BuilderManager is responsible for accepting user input events from the plugin, checking for valid + * coordinates, and spawning the building task once all required coordinates have been added. + * @author s1mpl3x + */ +public interface BuilderManager { + /** + * @return the Player that started this build. + */ + public Player getBuildingCreator(); + + /** + * Actually begin building. Will do nothing if all the required coordinates have not + * been added or if any are invalid. + */ + public void startBuild(); + + /** + * @return whether or not all the required coordinates have been added. + */ + public boolean gotAllCoordinates(); + + /** + * add the next coordinate. Will do nothing if no more coordinates are expected. + * @param position the coordinate to add. + */ + public void addCoordinate(Block position); + + /** + * examines all the coordinates add so far to determine whether they are valid. + * This does not require that all coordinates have been added yet, just that none of + * them conflict so far. + * @return whether coordinates added so far are valid. + */ + public boolean checkCoordinates(); + + /** + * @return the name of the structure being built, e.g. "Wall", "Sphere", etc. + */ + public String getBuildingName(); + + /** + * @return a message to display to the player that says we are starting to build. + * This is completely abstract since some Builders might not be building a structure, + * as such, and thus the message will not be a consistent pattern for all Builders. + */ + public String getBuildingMessage(); + + /** + * @return a message to display to the user saying that the coordinate just added has + * been accepted. This might be more specific than just "position 1", etc. + */ + public String getLastPositionMessage(); + + /** + * @return a message to display to the user saying that they should place the next + * coordinate. Again, this may be more specific than just "position 2", etc. + */ + public String getNextPositionMessage(); + + /** + * @return a message to display to the user describing why the last coordinate added + * was invalid. This should be just the reason; a colorized "ERROR" will be prefixed. + */ + public String getCoordinateCheckFailed(); +} \ No newline at end of file diff --git a/src/main/java/me/simplex/buildr/manager/builder/CloneBuilderManager.java b/src/main/java/me/simplex/buildr/manager/builder/CloneBuilderManager.java new file mode 100644 index 0000000..6708037 --- /dev/null +++ b/src/main/java/me/simplex/buildr/manager/builder/CloneBuilderManager.java @@ -0,0 +1,177 @@ +/* + * Copyright 2015 s1mpl3x + * Copyright 2015 pdwasson + * + * This file is part of Buildr. + * + * Buildr 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. + * + * Buildr 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 Buildr If not, see . + */ +package me.simplex.buildr.manager.builder; + +import me.simplex.buildr.Buildr; +import me.simplex.buildr.runnable.builder.CloneBuilderTask; +import me.simplex.buildr.util.BlockLocation; +import me.simplex.buildr.util.Cuboid; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + + +/** + * + * @author pwasson + */ +public class CloneBuilderManager extends AbstractBuilderManager { + private static final String COORD_FAIL_MESSAGE_TOO_BIG = "The volume of the area to be cloned must be no more than 32768 blocks. Cloning stopped."; + private static final String COORD_FAIL_MESSAGE_OVERLAP = "The source and destination areas overlap, which would cause indeterminate results. Cloning stopped."; + + private final int rotationAngle; + + private CoordFail coordReason = null; + + public CloneBuilderManager( + Player inPlayer, + Buildr inPlugin, + int inRotationAngle) { + super("Clone", inPlugin, inPlayer, null, (byte)0, null); + this.rotationAngle = inRotationAngle; + } + +/* + player.getEyeLocation().getYaw() returns a float that specifies which way the player is looking + (on the horizontal plane, not up or down, which is getPitch()). It would be better if we extended + the destination from the tapped corner toward the direction the player is looking when they tap, + instead of always extending south-east from the tapped block. + */ + @Override + public String getNextPositionMessage() { + String s; + switch (positions.size()) { + case 0: + s = "Right-click with a stick on the first corner of the cuboid to clone."; + break; + case 1: + s = "Now right-click (again with a stick) on the second corner of the cuboid to clone."; + break; + default: + s = "Now right-click (again with a stick) on the block that will be the lowest north-west corner of the clone."; + } + return s; + } + + + @Override + public String getLastPositionMessage() { + String s; + switch (positions.size()) { + case 0: + s = ""; + break; + case 1: + s = String.format("Got the first corner of your clone source at %s.", + getCoordForChat(positions.get(0))); + break; + case 2: + s = String.format("Got the second corner of your clone source at %s.", + getCoordForChat(positions.get(1))); + break; + default: + s = String.format("Got the corner of your clone destination at %s.", + getCoordForChat(positions.get(2))); + } + return s; + } + + + @Override + public boolean gotAllCoordinates() { + return (positions.size() >= 3); + } + + + private enum CoordFail { + TOO_BIG, + OVERLAP + } + + @Override + public boolean checkCoordinates() { + Block position1; + Block position2; + Block position3; + + // if we have the source coordinates but the cuboid volume is bigger than 32K blocks, that's a fail. + if (positions.size() >= 2) { + position1 = getPosition(1); + position2 = getPosition(2); + int height = Math.abs(position1.getY() - position2.getY()) + 1; + int width = Math.abs(position1.getX() - position2.getX()) + 1; + int depth = Math.abs(position1.getZ() - position2.getZ()) + 1; + long volume = (long)height * (long)width * (long)depth; + if (volume > 32768) { + coordReason = CoordFail.TOO_BIG; + return false; + } + + /* if we have the destination and it overlaps with the source, that's a fail. (We don't support + the built-in command's "force" option. */ + if (positions.size() >= 3) { + Cuboid source = new Cuboid(position1.getLocation(), position2.getLocation()); + position3 = getPosition(3); + /* if we're rotating, we have to adjust the destination coordinates accordingly, i.e. swap + width and depth if angle is 90 or 270 */ + boolean quarterRot = (rotationAngle == 90 || rotationAngle == 270); + int destWidth = quarterRot ? depth : width; + int destDepth = quarterRot ? width : depth; + BlockLocation loc4 = new BlockLocation(position3.getLocation().getBlockX() + destWidth - 1, + position3.getLocation().getBlockY() + height - 1, + position3.getLocation().getBlockZ() + destDepth - 1); + Cuboid dest = new Cuboid(new BlockLocation(position3.getLocation()), loc4); + if (source.intersects(dest)) { + coordReason = CoordFail.OVERLAP; + return false; + } + // FIXME remove debugging log messages +//plugin.getLogger().info(String.format("Source: [%d, %d, %d] - [%d, %d, %d]", +// source.getLowCorner().getX(), source.getLowCorner().getY(), source.getLowCorner().getZ(), +// source.getHighCorner().getX(), source.getHighCorner().getY(), source.getHighCorner().getZ())); +//plugin.getLogger().info(String.format("Dest: [%d, %d, %d] - [%d, %d, %d]", +// dest.getLowCorner().getX(), dest.getLowCorner().getY(), dest.getLowCorner().getZ(), +// dest.getHighCorner().getX(), dest.getHighCorner().getY(), dest.getHighCorner().getZ())); + } + } + + return true; + } + + + @Override + public String getCoordinateCheckFailed() { + if (coordReason != null) + switch (coordReason) { + case TOO_BIG: + return COORD_FAIL_MESSAGE_TOO_BIG; + case OVERLAP: + return COORD_FAIL_MESSAGE_OVERLAP; + } + return ""; + } + + + @Override + public void startBuild() { + plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new CloneBuilderTask(plugin, creator, getPosition(1), getPosition(2), getPosition(3), + rotationAngle)); + } +} diff --git a/src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Cuboid.java b/src/main/java/me/simplex/buildr/manager/builder/CuboidBuilderManager.java similarity index 82% rename from src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Cuboid.java rename to src/main/java/me/simplex/buildr/manager/builder/CuboidBuilderManager.java index 4d6b5a3..324595b 100644 --- a/src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Cuboid.java +++ b/src/main/java/me/simplex/buildr/manager/builder/CuboidBuilderManager.java @@ -21,17 +21,16 @@ import me.simplex.buildr.Buildr; import me.simplex.buildr.runnable.builder.Buildr_Runnable_Builder_Cuboid; -import me.simplex.buildr.util.Buildr_Interface_Building; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; -public class Buildr_Manager_Builder_Cuboid extends AbstractBuilderManager { +public class CuboidBuilderManager extends AbstractBuilderManager { private final boolean hollow; - public Buildr_Manager_Builder_Cuboid( + public CuboidBuilderManager( Player inPlayer, Material inBuildMaterial, Material inReplaceMaterial, @@ -52,6 +51,6 @@ public String getCoordinateCheckFailed() { @Override public void startBuild() { plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Buildr_Runnable_Builder_Cuboid( - position1, position2, material, replace, replace_mat, hollow, plugin, creator, material_data)); + getPosition(1), getPosition(2), material, replace, replace_mat, hollow, plugin, creator, material_data)); } } diff --git a/src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Cylinder.java b/src/main/java/me/simplex/buildr/manager/builder/CylinderBuilderManager.java similarity index 81% rename from src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Cylinder.java rename to src/main/java/me/simplex/buildr/manager/builder/CylinderBuilderManager.java index 807cc40..37d38d5 100644 --- a/src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Cylinder.java +++ b/src/main/java/me/simplex/buildr/manager/builder/CylinderBuilderManager.java @@ -21,16 +21,14 @@ import me.simplex.buildr.Buildr; import me.simplex.buildr.runnable.builder.Buildr_Runnable_Builder_Cylinder; -import me.simplex.buildr.util.Buildr_Interface_Building; import org.bukkit.Material; -import org.bukkit.block.Block; import org.bukkit.entity.Player; -public class Buildr_Manager_Builder_Cylinder extends AbstractBuilderManager { +public class CylinderBuilderManager extends AbstractBuilderManager { private final boolean hollow; - public Buildr_Manager_Builder_Cylinder( + public CylinderBuilderManager( Player inPlayer, Material inBuildMaterial, Material inReplaceMaterial, @@ -50,7 +48,7 @@ public String getCoordinateCheckFailed() { @Override public void startBuild() { plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, - new Buildr_Runnable_Builder_Cylinder(position1, position2, material, replace, replace_mat, + new Buildr_Runnable_Builder_Cylinder(getPosition(1), getPosition(2), material, replace, replace_mat, hollow, plugin, creator, material_data)); } } diff --git a/src/main/java/me/simplex/buildr/manager/builder/SlopeBuilderManager.java b/src/main/java/me/simplex/buildr/manager/builder/SlopeBuilderManager.java index 2e21988..acd9809 100644 --- a/src/main/java/me/simplex/buildr/manager/builder/SlopeBuilderManager.java +++ b/src/main/java/me/simplex/buildr/manager/builder/SlopeBuilderManager.java @@ -23,9 +23,6 @@ import java.util.Set; import me.simplex.buildr.Buildr; import me.simplex.buildr.runnable.builder.SlopeBuilderTask; -import me.simplex.buildr.util.Buildr_Interface_Building; -import me.simplex.buildr.util.Buildr_Type_Wall; -import me.simplex.buildr.util.MaterialAndData; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -72,6 +69,8 @@ public boolean checkCoordinates() { // the slope must be a 45 degree angle, i.e. deltaY == deltaX or deltaY == deltaZ. // Also, if deltaY == deltaX == deltaZ, orientation is arbitrary, so an orientation hint // must have been provided and must be valid for the given coordinates. + Block position1 = getPosition(1); + Block position2 = getPosition(2); int deltaY = Math.abs(position1.getY() - position2.getY()); int deltaX = Math.abs(position1.getX() - position2.getX()); int deltaZ = Math.abs(position1.getZ() - position2.getZ()); @@ -148,7 +147,7 @@ public String getCoordinateCheckFailed() { @Override public void startBuild() { plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, - new SlopeBuilderTask(plugin, creator, position1, position2, decidedOrientation, + new SlopeBuilderTask(plugin, creator, getPosition(1), getPosition(2), decidedOrientation, material, material_data, replace_mat)); } } diff --git a/src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Sphere.java b/src/main/java/me/simplex/buildr/manager/builder/SphereBuilderManager.java similarity index 82% rename from src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Sphere.java rename to src/main/java/me/simplex/buildr/manager/builder/SphereBuilderManager.java index 9734a5a..0d30d40 100644 --- a/src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Sphere.java +++ b/src/main/java/me/simplex/buildr/manager/builder/SphereBuilderManager.java @@ -20,19 +20,17 @@ package me.simplex.buildr.manager.builder; import org.bukkit.Material; -import org.bukkit.block.Block; import org.bukkit.entity.Player; import me.simplex.buildr.Buildr; import me.simplex.buildr.runnable.builder.Buildr_Runnable_Builder_Sphere; -import me.simplex.buildr.util.Buildr_Interface_Building; -public class Buildr_Manager_Builder_Sphere extends AbstractBuilderManager { +public class SphereBuilderManager extends AbstractBuilderManager { private final boolean hollow; private final boolean halfcube; - public Buildr_Manager_Builder_Sphere( + public SphereBuilderManager( Player inPlayer, Material inBuildMaterial, Material inReplaceMaterial, @@ -55,7 +53,7 @@ public String getCoordinateCheckFailed() { @Override public void startBuild() { plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Buildr_Runnable_Builder_Sphere( - position1, position2, material, replace, replace_mat, hollow, halfcube, plugin, creator, + getPosition(1), getPosition(2), material, replace, replace_mat, hollow, halfcube, plugin, creator, material_data)); } } diff --git a/src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Wall.java b/src/main/java/me/simplex/buildr/manager/builder/WallBuilderManager.java similarity index 82% rename from src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Wall.java rename to src/main/java/me/simplex/buildr/manager/builder/WallBuilderManager.java index 32a874d..db7b98b 100644 --- a/src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Wall.java +++ b/src/main/java/me/simplex/buildr/manager/builder/WallBuilderManager.java @@ -21,17 +21,16 @@ import me.simplex.buildr.Buildr; import me.simplex.buildr.runnable.builder.Buildr_Runnable_Builder_Wall; -import me.simplex.buildr.util.Buildr_Interface_Building; import me.simplex.buildr.util.Buildr_Type_Wall; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; -public class Buildr_Manager_Builder_Wall extends AbstractBuilderManager { +public class WallBuilderManager extends AbstractBuilderManager { private Buildr_Type_Wall type; - public Buildr_Manager_Builder_Wall( + public WallBuilderManager( Player inPlayer, Material inBuildMaterial, Material inReplaceMaterial, @@ -54,7 +53,10 @@ public boolean checkCoordinates(){ private Buildr_Type_Wall checkWallType() { - if (position1.getX() == position2.getX()) { + Block position1 = getPosition(1); + Block position2 = getPosition(2); + + if (position1.getX() == position2.getX()) { return Buildr_Type_Wall.WALL_X; } if (position1.getY() == position2.getY()) { @@ -78,6 +80,6 @@ public String getCoordinateCheckFailed() { @Override public void startBuild(){ plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Buildr_Runnable_Builder_Wall( - position1, position2, type, material, replace, replace_mat, plugin, creator, material_data)); + getPosition(1), getPosition(2), type, material, replace, replace_mat, plugin, creator, material_data)); } } diff --git a/src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Wallx.java b/src/main/java/me/simplex/buildr/manager/builder/WallxBuilderManager.java similarity index 80% rename from src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Wallx.java rename to src/main/java/me/simplex/buildr/manager/builder/WallxBuilderManager.java index 0e4a1c5..e5edba1 100644 --- a/src/main/java/me/simplex/buildr/manager/builder/Buildr_Manager_Builder_Wallx.java +++ b/src/main/java/me/simplex/buildr/manager/builder/WallxBuilderManager.java @@ -21,15 +21,13 @@ import me.simplex.buildr.Buildr; import me.simplex.buildr.runnable.builder.Buildr_Runnable_Builder_Wallx; -import me.simplex.buildr.util.Buildr_Interface_Building; import org.bukkit.Material; -import org.bukkit.block.Block; import org.bukkit.entity.Player; -public class Buildr_Manager_Builder_Wallx extends AbstractBuilderManager { - public Buildr_Manager_Builder_Wallx( +public class WallxBuilderManager extends AbstractBuilderManager { + public WallxBuilderManager( Player inPlayer, Material inBuildMaterial, Material inReplaceMaterial, @@ -48,6 +46,6 @@ public String getCoordinateCheckFailed() { @Override public void startBuild() { plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Buildr_Runnable_Builder_Wallx( - position1, position2, material, replace, replace_mat, plugin, creator, material_data)); + getPosition(1), getPosition(2), material, replace, replace_mat, plugin, creator, material_data)); } } diff --git a/src/main/java/me/simplex/buildr/manager/commands/AbstractBuilderCommand.java b/src/main/java/me/simplex/buildr/manager/commands/AbstractBuilderCommand.java index e6640ea..fb0fcbd 100644 --- a/src/main/java/me/simplex/buildr/manager/commands/AbstractBuilderCommand.java +++ b/src/main/java/me/simplex/buildr/manager/commands/AbstractBuilderCommand.java @@ -28,23 +28,37 @@ /** * A Command handler that handles a few chores common to builder commands, i.e. those commands that build - * stuff such as walls, cuboids, etc. + * stuff such as walls, cuboids, etc. A BuilderCommand parses arguments, constructs an appropriate + * {@link me.simplex.buildr.manager.builder.AbstractBuilderManager Manager}, and associates that Manager + * with the user that initiated the command so that the user’s future actions, such as tapping with a + * stick, can advance the specified operation. * @author pwasson */ public abstract class AbstractBuilderCommand extends Buildr_Manager_Command_Super { protected final String commandName; protected final String permission; protected final int maxArgs; + protected final int minArgs; public AbstractBuilderCommand(Buildr plugin, String commandName, String permission, - int maxArgs) { + int maxArgs, + int minArgs) { super(plugin); this.commandName = commandName; this.permission = permission; this.maxArgs = maxArgs; + this.minArgs = minArgs; + } + + + public AbstractBuilderCommand(Buildr plugin, + String commandName, + String permission, + int maxArgs) { + this(plugin, commandName, permission, maxArgs, 1); } @@ -56,11 +70,11 @@ public final boolean onCommand(CommandSender sender, if (!command.getName().equalsIgnoreCase(commandName)) { return false; } - if (args.length < 1 || args.length > maxArgs) { + if (args.length < minArgs || args.length > maxArgs) { return false; } if (!plugin.checkPermission((Player) sender, permission)) { - sendTo(sender, MsgType.ERROR, "You do not have permission to perform this action"); + sendTo(sender, MsgType.ERROR, "You do not have permission to perform this action."); return true; } @@ -78,7 +92,7 @@ public final boolean onCommand(CommandSender sender, * @param command * @param label * @param args - * @return + * @return whether the arguments were acceptable. */ protected abstract boolean onCommandSelf(CommandSender sender, Command command, diff --git a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Cuboid.java b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Cuboid.java index 34b533c..3e7ae36 100644 --- a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Cuboid.java +++ b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Cuboid.java @@ -20,7 +20,7 @@ package me.simplex.buildr.manager.commands; import me.simplex.buildr.Buildr; -import me.simplex.buildr.manager.builder.Buildr_Manager_Builder_Cuboid; +import me.simplex.buildr.manager.builder.CuboidBuilderManager; import me.simplex.buildr.util.Buildr_Type_Wool; import me.simplex.buildr.util.MaterialAndData; @@ -55,7 +55,7 @@ public void doBuildCommand(CommandSender sender, if (null != replace_mat) { replace_info = "Replace: " + ChatColor.BLUE + replace_mat; } - plugin.getStartedBuildings().add(new Buildr_Manager_Builder_Cuboid((Player) sender, material, + plugin.getStartedBuildings().add(new CuboidBuilderManager((Player) sender, material, replace_mat, hollow, plugin, material_data)); String buildinfo = "Started new Cuboid. Info: Blocktype: " + ChatColor.BLUE + material.toString() + ChatColor.WHITE + " (ID:" + ChatColor.BLUE + material. getId() + ChatColor.WHITE + ") " + replace_info + ChatColor.WHITE + " Hollow: " + ChatColor.BLUE + hollow; diff --git a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Cylinder.java b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Cylinder.java index e736d6d..a195f5f 100644 --- a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Cylinder.java +++ b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Cylinder.java @@ -20,7 +20,7 @@ package me.simplex.buildr.manager.commands; import me.simplex.buildr.Buildr; -import me.simplex.buildr.manager.builder.Buildr_Manager_Builder_Cylinder; +import me.simplex.buildr.manager.builder.CylinderBuilderManager; import me.simplex.buildr.util.Buildr_Type_Wool; import org.bukkit.ChatColor; @@ -55,7 +55,7 @@ public void doBuildCommand(CommandSender sender, replace_info = "Replace: " + ChatColor.BLUE + replace_mat; } - plugin.getStartedBuildings().add(new Buildr_Manager_Builder_Cylinder((Player) sender, material, + plugin.getStartedBuildings().add(new CylinderBuilderManager((Player) sender, material, replace_mat, hollow, plugin, material_data)); String buildinfo = "Started new cylinder. Info: Blocktype: " + ChatColor.BLUE + material.toString() + ChatColor.WHITE + " (ID:" + ChatColor.BLUE + material. getId() + ChatColor.WHITE + ") " + replace_info + ChatColor.WHITE + " Hollow: " + ChatColor.BLUE + hollow; diff --git a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Halfsphere.java b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Halfsphere.java index 798a1be..4b4644d 100644 --- a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Halfsphere.java +++ b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Halfsphere.java @@ -20,7 +20,7 @@ package me.simplex.buildr.manager.commands; import me.simplex.buildr.Buildr; -import me.simplex.buildr.manager.builder.Buildr_Manager_Builder_Sphere; +import me.simplex.buildr.manager.builder.SphereBuilderManager; import me.simplex.buildr.util.Buildr_Type_Wool; import org.bukkit.ChatColor; @@ -53,7 +53,7 @@ public void doBuildCommand(CommandSender sender, if (null != replace_mat) { replace_info = "Replace: " + ChatColor.BLUE + replace_mat; } - plugin.getStartedBuildings().add(new Buildr_Manager_Builder_Sphere((Player) sender, material, + plugin.getStartedBuildings().add(new SphereBuilderManager((Player) sender, material, replace_mat, hollow, true, plugin, material_data)); String buildinfo = "Started new half sphere. Info: Blocktype: " + ChatColor.BLUE + material.toString() + ChatColor.WHITE + " (ID:" + ChatColor.BLUE + material. getId() + ChatColor.WHITE + ") " + replace_info + ChatColor.WHITE + " Hollow: " + ChatColor.BLUE + hollow; diff --git a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Sphere.java b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Sphere.java index 2c02ada..6f468f8 100644 --- a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Sphere.java +++ b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Sphere.java @@ -20,7 +20,7 @@ package me.simplex.buildr.manager.commands; import me.simplex.buildr.Buildr; -import me.simplex.buildr.manager.builder.Buildr_Manager_Builder_Sphere; +import me.simplex.buildr.manager.builder.SphereBuilderManager; import me.simplex.buildr.util.Buildr_Type_Wool; import org.bukkit.ChatColor; @@ -53,7 +53,7 @@ public void doBuildCommand(CommandSender sender, if (null != replace_mat) { replace_info = "Replace: " + ChatColor.BLUE + replace_mat; } - plugin.getStartedBuildings().add(new Buildr_Manager_Builder_Sphere((Player) sender, material, + plugin.getStartedBuildings().add(new SphereBuilderManager((Player) sender, material, replace_mat, hollow, false, plugin, material_data)); String buildinfo = "Started new Sphere. Info: Blocktype: " + ChatColor.BLUE + material.toString() + ChatColor.WHITE + " (ID:" + ChatColor.BLUE + material. getId() + ChatColor.WHITE + ") " + replace_info + ChatColor.WHITE + " Hollow: " + ChatColor.BLUE + hollow; diff --git a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Wall.java b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Wall.java index ffd2716..5e990e6 100644 --- a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Wall.java +++ b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Wall.java @@ -20,7 +20,7 @@ package me.simplex.buildr.manager.commands; import me.simplex.buildr.Buildr; -import me.simplex.buildr.manager.builder.Buildr_Manager_Builder_Wall; +import me.simplex.buildr.manager.builder.WallBuilderManager; import me.simplex.buildr.util.Buildr_Type_Wool; import org.bukkit.ChatColor; @@ -54,7 +54,7 @@ public void doBuildCommand(CommandSender sender, if (null != replace_mat) { replace_info = "Replace: " + ChatColor.BLUE + replace_mat; } - plugin.getStartedBuildings().add(new Buildr_Manager_Builder_Wall((Player) sender, material, + plugin.getStartedBuildings().add(new WallBuilderManager((Player) sender, material, replace_mat, plugin, material_data)); String buildinfo = "Started new Wall. Info: Blocktype: " + ChatColor.BLUE + material.toString() + ChatColor.WHITE + " (ID:" + ChatColor.BLUE + material. getId() + ChatColor.WHITE + ") " + replace_info; diff --git a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Wallx.java b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Wallx.java index 1046a42..3fccee3 100644 --- a/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Wallx.java +++ b/src/main/java/me/simplex/buildr/manager/commands/Buildr_Manager_Command_Wallx.java @@ -20,7 +20,7 @@ package me.simplex.buildr.manager.commands; import me.simplex.buildr.Buildr; -import me.simplex.buildr.manager.builder.Buildr_Manager_Builder_Wallx; +import me.simplex.buildr.manager.builder.WallxBuilderManager; import me.simplex.buildr.util.Buildr_Type_Wool; import org.bukkit.ChatColor; @@ -49,7 +49,7 @@ public void doBuildCommand(CommandSender sender, plugin.removeStartedBuilding((Player) sender); sendTo(sender, MsgType.WARNING, "previous started building aborted"); } - plugin.getStartedBuildings().add(new Buildr_Manager_Builder_Wallx((Player) sender, material, + plugin.getStartedBuildings().add(new WallxBuilderManager((Player) sender, material, replace_mat, plugin, material_data)); String replace_info = ""; if (null != replace_mat) { diff --git a/src/main/java/me/simplex/buildr/manager/commands/CloneCommand.java b/src/main/java/me/simplex/buildr/manager/commands/CloneCommand.java new file mode 100644 index 0000000..aee1054 --- /dev/null +++ b/src/main/java/me/simplex/buildr/manager/commands/CloneCommand.java @@ -0,0 +1,114 @@ +/* + * Copyright 2015 s1mpl3x + * Copyright 2015 pwasson + * + * This file is part of Buildr. + * + * Buildr 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. + * + * Buildr 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 Buildr If not, see . + */ +package me.simplex.buildr.manager.commands; + +import me.simplex.buildr.Buildr; +import me.simplex.buildr.manager.builder.CloneBuilderManager; +import static me.simplex.buildr.manager.commands.Buildr_Manager_Command_Super.sendTo; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + + +public class CloneCommand extends AbstractBuilderCommand { + public CloneCommand(Buildr plugin) { + super(plugin, "bclone", "buildr.cmd.clone", 1, 0); + } +/* TODO support options from built-in command: + "masked" (do not copy air blocks) + ? "filtered" (with material, only copy blocks of specified material) + ? "move" (allow overlap of source and dest; blocks in source that are not occupied by dest afterward, + but were copied, are replaced by air) +*/ + @Override + public boolean onCommandSelf(CommandSender sender, + Command command, + String label, + String[] args) { + try { + // the only argument we have is an optional rotation + int rotationAngle = 0; + + if (args.length > 0) { + String arg = args[0]; + if (null != arg) { + if (org.bukkit.util.StringUtil.startsWithIgnoreCase(arg, "R")) { + String angleString = arg.substring(1); + try { + rotationAngle = Integer.parseInt(angleString); + if ((rotationAngle % 90) != 0) { + sendTo(sender, Buildr_Manager_Command_Super.MsgType.ERROR, + "invalid rotation angle; must be a multiple of 90."); + return true; + } + // normalize the rotation angle to > 0, < 360. + rotationAngle = rotationAngle % 360; + while (rotationAngle < 0) + rotationAngle += 360; + } catch (NumberFormatException numX) { + sendTo(sender, Buildr_Manager_Command_Super.MsgType.ERROR, + "invalid rotation angle; must be a multiple of 90."); + return true; + } + } else { + sendTo(sender, Buildr_Manager_Command_Super.MsgType.ERROR, + "invalid argument; r expected, e.g. \"r90\"."); + return true; + } + } + } + + cmd_clone(sender, rotationAngle); + return true; + } catch (BadFormatException formatX) { + sendTo(sender, Buildr_Manager_Command_Super.MsgType.ERROR, + formatX.getMessage()); + return true; + } + } + + + public void cmd_clone(CommandSender sender, + int rotationAngle) { + if (!plugin.getConfigValue("FEATURE_BUILDER_CLONE")) { + sendTo(sender, Buildr_Manager_Command_Super.MsgType.INFO, "feature not enabled"); + return; + } + if (plugin.checkPlayerHasStartedBuilding((Player) sender)) { + plugin.removeStartedBuilding((Player) sender); + sendTo(sender, Buildr_Manager_Command_Super.MsgType.WARNING, "previous started building aborted"); + } + + plugin.getStartedBuildings().add( + new CloneBuilderManager((Player) sender, plugin, rotationAngle)); + + StringBuilder sb = new StringBuilder("Started new Clone"); + if (rotationAngle != 0) { + sb.append(String.format(", rotating %d degrees", rotationAngle)); + } + sb.append("."); + String buildinfo = sb.toString(); + + sendTo(sender, Buildr_Manager_Command_Super.MsgType.INFO, buildinfo); + sendTo(sender, Buildr_Manager_Command_Super.MsgType.INFO, + "Right-click on one corner of the cuboid to clone while holding a stick to begin"); + } +} diff --git a/src/main/java/me/simplex/buildr/manager/commands/StdArgBuilderCommand.java b/src/main/java/me/simplex/buildr/manager/commands/StdArgBuilderCommand.java index 4efc85c..18604ec 100644 --- a/src/main/java/me/simplex/buildr/manager/commands/StdArgBuilderCommand.java +++ b/src/main/java/me/simplex/buildr/manager/commands/StdArgBuilderCommand.java @@ -20,7 +20,7 @@ package me.simplex.buildr.manager.commands; import me.simplex.buildr.Buildr; -import me.simplex.buildr.util.Buildr_Interface_Building; +import me.simplex.buildr.manager.builder.BuilderManager; import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -85,7 +85,7 @@ protected final boolean onCommandSelf(CommandSender sender, * @param hollow * @param replace_mat * @see Buildr#getStartedBuildings() - * @see Buildr_Interface_Building + * @see BuilderManager */ protected abstract void doBuildCommand(CommandSender sender, Material material, diff --git a/src/main/java/me/simplex/buildr/runnable/Buildr_Runnable_Undo.java b/src/main/java/me/simplex/buildr/runnable/Buildr_Runnable_Undo.java index 8d6041d..9f2505b 100644 --- a/src/main/java/me/simplex/buildr/runnable/Buildr_Runnable_Undo.java +++ b/src/main/java/me/simplex/buildr/runnable/Buildr_Runnable_Undo.java @@ -18,18 +18,19 @@ */ package me.simplex.buildr.runnable; -import java.util.HashMap; +import java.util.Map; import me.simplex.buildr.Buildr; import me.simplex.buildr.util.Buildr_Container_UndoBlock; import org.bukkit.block.Block; import org.bukkit.entity.Player; +import org.bukkit.material.Attachable; public class Buildr_Runnable_Undo implements Runnable { - private Player player; - private HashMap undos; - private Buildr plugin; + private final Player player; + private final Map undos; + private final Buildr plugin; public Buildr_Runnable_Undo(Player player, Buildr plugin) { this.player = player; @@ -39,9 +40,21 @@ public Buildr_Runnable_Undo(Player player, Buildr plugin) { @Override public void run() { if (undos != null) { + // first undo attachables, then non-attachables. + // FIXME this doesn't work to prevent drops from items being removed. for (Block block : undos.keySet()) { - block.setType(undos.get(block).getMaterial()); - block.setData(undos.get(block).getMaterialData()); + boolean isAttachable = Attachable.class.isAssignableFrom(block.getType().getData()); + if (isAttachable) { + block.setType(undos.get(block).getMaterial()); + block.setData(undos.get(block).getMaterialData()); + } + } + for (Block block : undos.keySet()) { + boolean isAttachable = Attachable.class.isAssignableFrom(block.getType().getData()); + if (!isAttachable) { + block.setType(undos.get(block).getMaterial()); + block.setData(undos.get(block).getMaterialData()); + } } plugin.log(player.getName()+" used /undo: "+undos.size()+" blocks affected"); player.sendMessage(undos.size()+" blocks restored"); diff --git a/src/main/java/me/simplex/buildr/runnable/builder/Buildr_Runnable_Builder_Super.java b/src/main/java/me/simplex/buildr/runnable/builder/Buildr_Runnable_Builder_Super.java index 289b92e..3503ed5 100644 --- a/src/main/java/me/simplex/buildr/runnable/builder/Buildr_Runnable_Builder_Super.java +++ b/src/main/java/me/simplex/buildr/runnable/builder/Buildr_Runnable_Builder_Super.java @@ -18,7 +18,7 @@ */ package me.simplex.buildr.runnable.builder; -import java.util.HashMap; +import java.util.Map; import me.simplex.buildr.Buildr; import me.simplex.buildr.util.Buildr_Container_UndoBlock; @@ -42,7 +42,7 @@ public abstract class Buildr_Runnable_Builder_Super implements Runnable { @Override public abstract void run(); - protected void changeBlock(Block block_handle, HashMap undo){ + protected void changeBlock(Block block_handle, Map undo){ undo.put(block_handle, new Buildr_Container_UndoBlock(block_handle.getType(), block_handle.getData())); if (canBuild(player, block_handle)) { if (!plugin.checkPermission(player, "buildr.feature.break_bedrock")) { diff --git a/src/main/java/me/simplex/buildr/runnable/builder/CloneBuilderTask.java b/src/main/java/me/simplex/buildr/runnable/builder/CloneBuilderTask.java new file mode 100644 index 0000000..2d2d533 --- /dev/null +++ b/src/main/java/me/simplex/buildr/runnable/builder/CloneBuilderTask.java @@ -0,0 +1,338 @@ +/* + * Copyright 2015 s1mpl3x + * Copyright 2015 pdwasson + * + * This file is part of Buildr. + * + * Buildr 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. + * + * Buildr 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 Buildr If not, see . + */ +package me.simplex.buildr.runnable.builder; + +import java.util.HashMap; +import java.util.Map; +import me.simplex.buildr.Buildr; +import me.simplex.buildr.util.BlockLocation; +import me.simplex.buildr.util.Buildr_Container_UndoBlock; +import me.simplex.buildr.util.Cuboid; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.CommandBlock; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.material.Attachable; +import org.bukkit.material.Directional; +import org.bukkit.material.Door; +import org.bukkit.material.Ladder; +import org.bukkit.material.MaterialData; +import org.bukkit.material.Stairs; + + +/** + * + * @author pwasson + */ +public class CloneBuilderTask extends Buildr_Runnable_Builder_Super { + private final Block position3; + private final int rotation; + private final boolean canBreakBedrock; + + + public CloneBuilderTask(Buildr plugin, + Player player, + Block position1, + Block position2, + Block position3, + int inRotation) { + this.plugin = plugin; + this.player = player; + this.position1 = position1; + this.position2 = position2; + this.position3 = position3; + this.rotation = inRotation; + this.canBreakBedrock = plugin.checkPermission(player, "buildr.feature.break_bedrock"); + } + + + @Override + public void run() { + int height = Math.abs(position1.getY() - position2.getY()) + 1; + int width = Math.abs(position1.getX() - position2.getX()) + 1; + int depth = Math.abs(position1.getZ() - position2.getZ()) + 1; + + Cuboid source = new Cuboid(position1.getLocation(), position2.getLocation()); + /* if we're rotating, we have to adjust the destination coordinates accordingly, i.e. swap + width and depth if angle is 90 or 270 */ + boolean quarterRot = (rotation % 180 != 0); + int destWidth = quarterRot ? depth : width; + int destDepth = quarterRot ? width : depth; + BlockLocation loc4 = new BlockLocation(position3.getLocation().getBlockX() + destWidth - 1, + position3.getLocation().getBlockY() + height - 1, + position3.getLocation().getBlockZ() + destDepth - 1); + Cuboid dest = new Cuboid(new BlockLocation(position3.getLocation()), loc4); + + Map undoBlocks = new HashMap(); + World theWorld = position1.getWorld(); +// FIXME doors still drop as items. Don't know why yet. + /* + We need to do this in two passes. If we clone an attachable block, such as a torch or ladder, + before the block it's attached to, it will drop as an item as soon as it's placed. So clone the + non-attachable blocks in the first pass (to provide surfaces), then only the attachable + blocks in the second pass. + */ + cloneLoop(source, dest, theWorld, undoBlocks, false); + cloneLoop(source, dest, theWorld, undoBlocks, true); + + plugin.getUndoList().addToStack(undoBlocks, player); + player.sendMessage(String.format("Done! Placed %d blocks", undoBlocks.size())); + plugin.log(String.format("%s cloned a cuboid: %d blocks affected.", player.getName(), + undoBlocks.size())); + } + + + private void cloneLoop(Cuboid source, + Cuboid dest, + World theWorld, + Map undoBlocks, + boolean copyAttachables) { + for (int srcX = source.getLowCorner().getX(); srcX <= source.getHighCorner().getX(); ++srcX) { + for (int srcZ = source.getLowCorner().getZ(); srcZ <= source.getHighCorner().getZ(); ++srcZ) { + BlockLocation destLoc = calcDest(source, dest, srcX, srcZ); + + int yOffset = dest.getLowCorner().getY() - source.getLowCorner().getY(); + for (int srcY = source.getLowCorner().getY(); srcY <= source.getHighCorner().getY(); ++srcY) { + int destY = srcY + yOffset; + Block srcBlockHandle = theWorld.getBlockAt(srcX, srcY, srcZ); + + boolean isAttachable = Attachable.class.isAssignableFrom(srcBlockHandle.getType().getData()); + if (copyAttachables != isAttachable) continue; + + /* TODO if we are filtering by material or only cloning non-air blocks, this is where we'd + check and skip this iteration if it doesn't pass the filter. + */ + + Block destBlockHandle = theWorld.getBlockAt(destLoc.getX(), destY, destLoc.getZ()); + cloneBlock(srcBlockHandle, destBlockHandle, undoBlocks); + } + } + } + } + + + /** + * calculates the destination X and Z coordinates based on the source and destination cuboids, the + * source X, source Z, and rotation angle. (The destination Y is always set to 0.) + * @param src + * @param dest + * @param srcX + * @param srcZ + * @return + */ + private BlockLocation calcDest(Cuboid src, Cuboid dest, int srcX, int srcZ) { + int offsetX = srcX - src.getLowCorner().getX(); + int offsetZ = srcZ - src.getLowCorner().getZ(); + int destX, destZ; + + switch (rotation) { + case 90: + case -270: + destX = dest.getHighCorner().getX() - offsetZ; + destZ = dest.getLowCorner().getZ() + offsetX; + break; + case 180: + case -180: + destX = dest.getHighCorner().getX() - offsetX; + destZ = dest.getHighCorner().getZ() - offsetZ; + break; + case 270: + case -90: + destX = dest.getLowCorner().getX() + offsetZ; + destZ = dest.getHighCorner().getZ() - offsetX; + break; + default: + // assume no rotation + destX = dest.getLowCorner().getX() + offsetX; + destZ = dest.getLowCorner().getZ() + offsetZ; + break; + } +//plugin.getLogger().info(String.format( +// "X %d -> %d, Z %d - %d", srcX, destX, srcZ, destZ)); + return new BlockLocation(destX, 0, destZ); + } + + + protected void cloneBlock(Block srcBlockHandle, + Block destBlockHandle, + Map undo) { + if (canBuild(player, destBlockHandle)) { + if (canBreakBedrock || !destBlockHandle.getType().equals(Material.BEDROCK)) { + undo.put(destBlockHandle, new Buildr_Container_UndoBlock(destBlockHandle.getType(), + destBlockHandle.getData())); + Material mat = srcBlockHandle.getType(); + byte blockData = srcBlockHandle.getData(); + if (0 != rotation && Directional.class.isAssignableFrom(mat.getData())) { + MaterialData newData = mat.getNewData(blockData); + Directional newDataAsDirectional = (Directional)newData; + BlockFace originalFacing = getActualFacing(newDataAsDirectional); +//plugin.getLogger().info(String.format("%s Before: %s", mat.name(), originalFacing)); + + BlockFace newFacing = getRotatedFacing(originalFacing); + +//plugin.getLogger().info(String.format("\tRotated: %s", newFacing)); + setFacingCorrectly(newData, newDataAsDirectional, newFacing); +//plugin.getLogger().info(String.format("\tSet Data: %s", getActualFacing(newDataAsDirectional))); + blockData = newData.getData(); +//plugin.getLogger().info(String.format("\tAfter: %s", getActualFacing((Directional)mat.getNewData(destBlockHandle.getData())))); + } + + destBlockHandle.setTypeIdAndData(mat.getId(), blockData, true); + BlockState srcState = srcBlockHandle.getState(); + BlockState destState = destBlockHandle.getState(); + boolean stateChanged = false; + + /* copy inventory of items with inventories: Beacon, Brewing Stand, Chest, Dispenser, Dropper, + Furnace, Hopper + */ + if (srcState instanceof InventoryHolder) { + ((InventoryHolder)destState).getInventory(). + setContents(((InventoryHolder)srcState).getInventory().getContents()); + stateChanged = true; + } + if (srcState instanceof CommandBlock) { + ((CommandBlock)destState).setName(((CommandBlock)srcState).getName()); + ((CommandBlock)destState).setCommand(((CommandBlock)srcState).getCommand()); + stateChanged = true; + } + if (srcState instanceof Sign) { + for (int i = 0; i <= 3; ++i) + ((Sign)destState).setLine(i, ((Sign)srcState).getLine(i)); + stateChanged = true; + } + + // TODO lots of other specific BlockState subclasses to copy... + + if (stateChanged) destState.update(); + } + } + } + + + /** + * Some block types appear to lie about their facing. + * + * + * + * + * + * + * + *
StairsgetFacing() returns opposite of what it’s set to.
Torch Facing and attached face are opposite; getFacing() is accurate.
Ladder Facing and AttachedFace are the same, but SimpleAttachableMaterialData will + * flip the result when you call getFacing() so it lies.
Button same as Torch
Lever same as Torch?
Trapdoor same as Torch
TripwireHook same as Torch
+ * Basically, this ask the Block for its facing, and if it is one that lies, the result is flipped. + * @param handle the block whose facing you want to know. + * @return the true facing of the block. + */ + private BlockFace getActualFacing(Directional dirData) { + BlockFace facing = dirData.getFacing(); + if (Stairs.class.isAssignableFrom(dirData.getClass()) + || Ladder.class.isAssignableFrom(dirData.getClass())) { + facing = facing.getOppositeFace(); + } + return facing; + } + + + private BlockFace getRotatedFacing(BlockFace inFacing) { + BlockFace facing = inFacing; + int angle = this.rotation; + while (angle > 0) { + switch (facing) { + case NORTH: + facing = BlockFace.EAST; + break; + case EAST: + facing = BlockFace.SOUTH; + break; + case SOUTH: + facing = BlockFace.WEST; + break; + case WEST: + facing = BlockFace.NORTH; + break; + case NORTH_EAST: + facing = BlockFace.SOUTH_EAST; + break; + case NORTH_WEST: + facing = BlockFace.NORTH_EAST; + break; + case SOUTH_EAST: + facing = BlockFace.SOUTH_WEST; + break; + case SOUTH_WEST: + facing = BlockFace.NORTH_WEST; + break; + case WEST_NORTH_WEST: + facing = BlockFace.NORTH_NORTH_EAST; + break; + case NORTH_NORTH_WEST: + facing = BlockFace.EAST_NORTH_EAST; + break; + case NORTH_NORTH_EAST: + facing = BlockFace.EAST_SOUTH_EAST; + break; + case EAST_NORTH_EAST: + facing = BlockFace.SOUTH_SOUTH_EAST; + break; + case EAST_SOUTH_EAST: + facing = BlockFace.SOUTH_SOUTH_WEST; + break; + case SOUTH_SOUTH_EAST: + facing = BlockFace.WEST_SOUTH_WEST; + break; + case SOUTH_SOUTH_WEST: + facing = BlockFace.WEST_NORTH_WEST; + break; + case WEST_SOUTH_WEST: + facing = BlockFace.NORTH_NORTH_WEST; + break; + } + angle -= 90; + } + return facing; + } + + + /** + * attempts to work around any bugs in any Directional block type’s + * {@link Directional#setFacingDirection(org.bukkit.block.BlockFace) setFacingDirection()}. + * @param data + * @param dataAsDirectional + * @param newFacing + */ + private void setFacingCorrectly(MaterialData data, + Directional dataAsDirectional, + BlockFace newFacing) { + if (Door.class.isAssignableFrom(data.getClass())) { + int faceVal = (((newFacing == BlockFace.WEST) ? 0x00 : ((newFacing == BlockFace.NORTH) ? 0x01 : ((newFacing == BlockFace.EAST) ? 0x02 : 0x03)))); + int cleanData = data.getData() & 0x03; + int newData = cleanData | faceVal; + data.setData((byte)newData); + } else { + dataAsDirectional.setFacingDirection(newFacing); + } + } +} diff --git a/src/main/java/me/simplex/buildr/runnable/builder/SlopeBuilderTask.java b/src/main/java/me/simplex/buildr/runnable/builder/SlopeBuilderTask.java index edcb9dc..1418af3 100644 --- a/src/main/java/me/simplex/buildr/runnable/builder/SlopeBuilderTask.java +++ b/src/main/java/me/simplex/buildr/runnable/builder/SlopeBuilderTask.java @@ -20,9 +20,9 @@ package me.simplex.buildr.runnable.builder; import java.util.HashMap; +import java.util.Map; import me.simplex.buildr.Buildr; import me.simplex.buildr.util.Buildr_Container_UndoBlock; -import me.simplex.buildr.util.MaterialAndData; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -78,7 +78,7 @@ public void run() { int north = Math.min(position1.getZ(), position2.getZ()); int south = Math.max(position1.getZ(), position2.getZ()); - HashMap undoBlocks = null; + Map undoBlocks = null; switch (orientation) { case NORTH: undoBlocks = buildSlopeNorthSouth(low, high, west, east, north, 1); @@ -98,19 +98,19 @@ public void run() { if (null != undoBlocks) { plugin.getUndoList().addToStack(undoBlocks, player); player.sendMessage(String.format("done! Placed %d blocks", undoBlocks.size())); - plugin.log(String.format("%s built a slope: %d blocks asffected.", player.getName(), + plugin.log(String.format("%s built a slope: %d blocks affected.", player.getName(), undoBlocks.size())); } } - private HashMap buildSlopeNorthSouth(int low, + private Map buildSlopeNorthSouth(int low, int high, int west, int east, int startZ, int deltaZ) { - HashMap undo = + Map undo = new HashMap(); int z = startZ; @@ -129,13 +129,13 @@ private HashMap buildSlopeNorthSouth(int low, } - private HashMap buildSlopeEastWest(int low, + private Map buildSlopeEastWest(int low, int high, int north, int south, int startX, int deltaX) { - HashMap undo = + Map undo = new HashMap(); int x = startX; diff --git a/src/main/java/me/simplex/buildr/util/Buildr_Interface_Building.java b/src/main/java/me/simplex/buildr/util/BlockLocation.java similarity index 50% rename from src/main/java/me/simplex/buildr/util/Buildr_Interface_Building.java rename to src/main/java/me/simplex/buildr/util/BlockLocation.java index c02380b..b60dd8f 100644 --- a/src/main/java/me/simplex/buildr/util/Buildr_Interface_Building.java +++ b/src/main/java/me/simplex/buildr/util/BlockLocation.java @@ -1,33 +1,62 @@ -/* - * Copyright 2012 s1mpl3x - * - * This file is part of Buildr. - * - * Buildr 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. - * - * Buildr 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 Buildr If not, see . - */ -package me.simplex.buildr.util; - -import org.bukkit.block.Block; -import org.bukkit.entity.Player; - -public interface Buildr_Interface_Building { - public Player getBuildingcreater(); - public void startBuild(); - public boolean isCoordinate1Placed(); - public void addCoordinate1(Block position1); - public void addCoordinate2(Block position2); - public boolean checkCoordinates(); - public String getBuildingName(); - public String getCoordinateCheckFailed(); -} \ No newline at end of file +/* + * Copyright 2012 s1mpl3x + * Copyright 2015 pdwasson + * + * This file is part of Buildr. + * + * Buildr 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. + * + * Buildr 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 Buildr If not, see . + */ +package me.simplex.buildr.util; + +import org.bukkit.Location; + + +/** + * A simple class that holds the 3-dimensional location of a block, as x, y, and z integers. It is immutable. + * @author pwasson + */ +public class BlockLocation { + private final int x, y, z; + + + public BlockLocation(int x, + int y, + int z) { + this.x = x; + this.y = y; + this.z = z; + } + + + public BlockLocation(Location loc) { + this.x = loc.getBlockX(); + this.y = loc.getBlockY(); + this.z = loc.getBlockZ(); + } + + + public int getX() { + return x; + } + + + public int getY() { + return y; + } + + + public int getZ() { + return z; + } +} diff --git a/src/main/java/me/simplex/buildr/util/Buildr_Stack_Undo.java b/src/main/java/me/simplex/buildr/util/Buildr_Stack_Undo.java index ed3d25b..67831f7 100644 --- a/src/main/java/me/simplex/buildr/util/Buildr_Stack_Undo.java +++ b/src/main/java/me/simplex/buildr/util/Buildr_Stack_Undo.java @@ -18,11 +18,11 @@ */ package me.simplex.buildr.util; -import java.util.HashMap; import java.util.LinkedList; +import java.util.Map; import org.bukkit.block.Block; -public class Buildr_Stack_Undo extends LinkedList> { +public class Buildr_Stack_Undo extends LinkedList> { private static final long serialVersionUID = 2757868195679642194L; private int maxSize; @@ -31,7 +31,7 @@ public Buildr_Stack_Undo(final int maxSize){ this.maxSize = maxSize; } - public void pushWithLimit(HashMap item){ + public void pushWithLimit(Map item){ push(item); if (size() > maxSize) { removeLast(); diff --git a/src/main/java/me/simplex/buildr/util/Cuboid.java b/src/main/java/me/simplex/buildr/util/Cuboid.java new file mode 100644 index 0000000..e1a3cae --- /dev/null +++ b/src/main/java/me/simplex/buildr/util/Cuboid.java @@ -0,0 +1,94 @@ +/* + * Copyright 2012 s1mpl3x + * Copyright 2015 pdwasson + * + * This file is part of Buildr. + * + * Buildr 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. + * + * Buildr 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 Buildr If not, see . + */ +package me.simplex.buildr.util; + +import org.bukkit.Location; + + +/** + * Represents a 3-dimensional volume specified by two opposing corners, each represented as a + * {@link org.bukkit.Location}. Coordinates are always interpreted as “block” coordinates; no + * fractional blocks are supported. The coordinates are internally kept normalized, i.e. one corner + * has the lowest coordinates and other has the highest coordinates. The volume includes both corners. + * @author pwasson + */ +public class Cuboid { + private BlockLocation lowCorner; + private BlockLocation highCorner; + + + public Cuboid(BlockLocation cornerOne, + BlockLocation cornerTwo) { + this.lowCorner = cornerOne; + this.highCorner = cornerTwo; + normalize(); + } + + + public Cuboid(Location cornerOne, + Location cornerTwo) { + this(new BlockLocation(cornerOne), + new BlockLocation(cornerTwo)); + } + + + private void normalize() { + int low = Math.min(lowCorner.getY(), highCorner.getY()); + int high = Math.max(lowCorner.getY(), highCorner.getY()); + int west = Math.min(lowCorner.getX(), highCorner.getX()); + int east = Math.max(lowCorner.getX(), highCorner.getX()); + int north = Math.min(lowCorner.getZ(), highCorner.getZ()); + int south = Math.max(lowCorner.getZ(), highCorner.getZ()); + + lowCorner = new BlockLocation(west, low, north); + highCorner = new BlockLocation(east, high, south); + } + + + public BlockLocation getLowCorner() { + return lowCorner; + } + + + public BlockLocation getHighCorner() { + return highCorner; + } + + + public long getVolume() { + long width = Math.abs(highCorner.getX() - lowCorner.getX()) + 1; + long height = Math.abs(highCorner.getY() - lowCorner.getY()) + 1; + long depth = Math.abs(highCorner.getZ() - lowCorner.getZ()) + 1; + return height * width * depth; + } + + + public boolean intersects(final Cuboid other) { + // the volumes must overlap in all three dimensions to really intersect. + return (overlaps(lowCorner.getX(), highCorner.getX(), other.lowCorner.getX(), other.highCorner.getX()) + && overlaps(lowCorner.getY(), highCorner.getY(), other.lowCorner.getY(), other.highCorner.getY()) + && overlaps(lowCorner.getZ(), highCorner.getZ(), other.lowCorner.getZ(), other.highCorner.getZ())); + } + + + private boolean overlaps(int range1Low, int range1High, int range2Low, int range2High) { + return !(range1Low > range2High || range2Low > range1High); + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5b94e4d..46cf837 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: Buildr main: me.simplex.buildr.Buildr -version: 0.8.0 +version: 0.8.2 website: http://forums.bukkit.org/threads/25644/ author: simplex startup: startup @@ -60,6 +60,11 @@ commands: aliases: [ramp] usage: | / {:data} {rReplace_material{:data}} {north|east|south|west} + bclone: + description: Starts cloning a cuboid + aliases: [bcl] + usage: | + / {rAngle (rotation angle, multiple of 90, clockwise)} airfloor: description: places a block (area) of material x y blocks above the player aliases: [af,airf] @@ -131,6 +136,7 @@ permissions: buildr.cmd.cylinder: true buildr.cmd.airfloor: true buildr.cmd.slope: true + buildr.cmd.clone: true buildr.cmd.top: true buildr.cmd.undo: true buildr.cmd.gv: true