From 52cb2e0997382a3b2d44c4e86a758d4601994b16 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 29 Jan 2011 23:10:12 -0800 Subject: [PATCH] Added support for rotation block orientation with the rotate and flip commands. --- src/com/sk89q/worldedit/CuboidClipboard.java | 17 +- src/com/sk89q/worldedit/blocks/BaseBlock.java | 23 ++ src/com/sk89q/worldedit/data/BlockData.java | 232 ++++++++++++++++++ 3 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 src/com/sk89q/worldedit/data/BlockData.java diff --git a/src/com/sk89q/worldedit/CuboidClipboard.java b/src/com/sk89q/worldedit/CuboidClipboard.java index eb7354c68..ac7b7cf99 100644 --- a/src/com/sk89q/worldedit/CuboidClipboard.java +++ b/src/com/sk89q/worldedit/CuboidClipboard.java @@ -123,6 +123,8 @@ public class CuboidClipboard { if (angle % 90 != 0) { // Can only rotate 90 degrees at the moment return; } + boolean reverse = angle < 0; + int numRotations = (int)Math.floor(angle / 90.0); int width = getWidth(); int length = getLength(); @@ -142,7 +144,18 @@ public class CuboidClipboard { int newX = v.getBlockX(); int newZ = v.getBlockZ(); for (int y = 0; y < height; y++) { - newData[shiftX + newX][y][shiftZ + newZ] = data[x][y][z]; + BaseBlock block = data[x][y][z]; + newData[shiftX + newX][y][shiftZ + newZ] = block; + + if (reverse) { + for (int i = 0; i < numRotations; i++) { + block.rotate90Reverse(); + } + } else { + for (int i = 0; i < numRotations; i++) { + block.rotate90(); + } + } } } } @@ -171,6 +184,7 @@ public class CuboidClipboard { for (int z = 0; z < length; z++) { for (int y = 0; y < height; y++) { BaseBlock old = data[xs][y][z]; + old.flip(); data[xs][y][z] = data[width - xs - 1][y][z]; data[width - xs - 1][y][z] = old; } @@ -182,6 +196,7 @@ public class CuboidClipboard { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { BaseBlock old = data[x][y][zs]; + old.flip(); data[x][y][zs] = data[x][y][length - zs - 1]; data[x][y][length - zs - 1] = old; } diff --git a/src/com/sk89q/worldedit/blocks/BaseBlock.java b/src/com/sk89q/worldedit/blocks/BaseBlock.java index 11c15a124..f614828af 100644 --- a/src/com/sk89q/worldedit/blocks/BaseBlock.java +++ b/src/com/sk89q/worldedit/blocks/BaseBlock.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.blocks; +import com.sk89q.worldedit.data.BlockData; + /** * Represents a block. * @@ -89,4 +91,25 @@ public class BaseBlock { public boolean isAir() { return type == 0; } + + /** + * Rotate this block 90 degrees. + */ + public void rotate90() { + data = (char)BlockData.rotate90(type, data); + } + + /** + * Rotate this block -90 degrees. + */ + public void rotate90Reverse() { + data = (char)BlockData.rotate90Reverse(type, data); + } + + /** + * Flip this block. + */ + public void flip() { + data = (char)BlockData.flip(type, data); + } } diff --git a/src/com/sk89q/worldedit/data/BlockData.java b/src/com/sk89q/worldedit/data/BlockData.java new file mode 100644 index 000000000..5f3684169 --- /dev/null +++ b/src/com/sk89q/worldedit/data/BlockData.java @@ -0,0 +1,232 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit.data; + +import com.sk89q.worldedit.blocks.BlockID; + +/** + * Block data related classes. + * + * @author sk89q + */ +public final class BlockData { + /** + * Rotate a block's data value 90 degrees (north->east->south->west->north); + * + * @param type + * @param data + * @return + */ + public static int rotate90(int type, int data) { + if (type == BlockID.TORCH + || type == BlockID.REDSTONE_TORCH_OFF + || type == BlockID.REDSTONE_TORCH_ON) { + switch (data) { + case 1: return 3; + case 2: return 4; + case 3: return 2; + case 4: return 1; + } + } else if (type == BlockID.MINECART_TRACKS) { + switch (data) { + case 0: return 1; + case 1: return 0; + case 2: return 5; + case 3: return 4; + case 4: return 2; + case 5: return 3; + case 6: return 7; + case 7: return 8; + case 8: return 9; + case 9: return 6; + } + } else if (type == BlockID.WOODEN_STAIRS + || type == BlockID.COBBLESTONE_STAIRS) { + switch (data) { + case 0: return 2; + case 1: return 3; + case 2: return 1; + case 3: return 0; + } + } else if (type == BlockID.LEVER) { + int thrown = data & 0x8; + int withoutThrown = data ^ 0x8; + switch (withoutThrown) { + case 1: return 3 | thrown; + case 2: return 4 | thrown; + case 3: return 2 | thrown; + case 4: return 1 | thrown; + } + } else if (type == BlockID.WOODEN_DOOR + || type == BlockID.IRON_DOOR) { + int topHalf = data & 0x8; + int swung = data & 0x4; + int withoutFlags = data ^ (0x8 | 0x4); + switch (withoutFlags) { + case 0: return 1 | topHalf | swung; + case 1: return 2 | topHalf | swung; + case 2: return 3 | topHalf | swung; + case 3: return 0 | topHalf | swung; + } + } else if (type == BlockID.STONE_BUTTON) { + int thrown = data & 0x8; + int withoutThrown = data ^ 0x8; + switch (withoutThrown) { + case 1: return 3 | thrown; + case 2: return 4 | thrown; + case 3: return 2 | thrown; + case 4: return 1 | thrown; + } + } else if (type == BlockID.SIGN_POST) { + return (data + 4) % 16; + } else if (type == BlockID.LADDER + || type == BlockID.WALL_SIGN + || type == BlockID.FURNACE + || type == BlockID.BURNING_FURNACE + || type == BlockID.DISPENSER) { + switch (data) { + case 2: return 5; + case 3: return 4; + case 4: return 2; + case 5: return 3; + } + } else if (type == BlockID.PUMPKIN + || type == BlockID.JACKOLANTERN) { + switch (data) { + case 0: return 1; + case 1: return 2; + case 2: return 3; + case 3: return 0; + } + } + + return data; + } + + /** + * Rotate a block's data value -90 degrees (north<-east<-south<-west<-north); + * + * @param type + * @param data + * @return + */ + public static int rotate90Reverse(int type, int data) { + // case ([0-9]+): return ([0-9]+) -> case \2: return \1 + + if (type == BlockID.TORCH + || type == BlockID.REDSTONE_TORCH_OFF + || type == BlockID.REDSTONE_TORCH_ON) { + switch (data) { + case 3: return 1; + case 4: return 2; + case 2: return 3; + case 1: return 4; + } + } else if (type == BlockID.MINECART_TRACKS) { + switch (data) { + case 1: return 0; + case 0: return 1; + case 5: return 2; + case 4: return 3; + case 2: return 4; + case 3: return 5; + case 7: return 6; + case 8: return 7; + case 9: return 8; + case 6: return 9; + } + } else if (type == BlockID.WOODEN_STAIRS + || type == BlockID.COBBLESTONE_STAIRS) { + switch (data) { + case 2: return 0; + case 3: return 1; + case 1: return 2; + case 0: return 3; + } + } else if (type == BlockID.LEVER) { + int thrown = data & 0x8; + int withoutThrown = data ^ 0x8; + switch (withoutThrown) { + case 3: return 1 | thrown; + case 4: return 2 | thrown; + case 2: return 3 | thrown; + case 1: return 4 | thrown; + } + } else if (type == BlockID.WOODEN_DOOR + || type == BlockID.IRON_DOOR) { + int topHalf = data & 0x8; + int swung = data & 0x4; + int withoutFlags = data ^ (0x8 | 0x4); + switch (withoutFlags) { + case 1: return 0 | topHalf | swung; + case 2: return 1 | topHalf | swung; + case 3: return 2 | topHalf | swung; + case 0: return 3 | topHalf | swung; + } + } else if (type == BlockID.STONE_BUTTON) { + int thrown = data & 0x8; + int withoutThrown = data ^ 0x8; + switch (withoutThrown) { + case 3: return 1 | thrown; + case 4: return 2 | thrown; + case 2: return 3 | thrown; + case 1: return 4 | thrown; + } + } else if (type == BlockID.SIGN_POST) { + int newData = (data - 4); + if (newData < 0) { + newData += 16; + } + return newData; + } else if (type == BlockID.LADDER + || type == BlockID.WALL_SIGN + || type == BlockID.FURNACE + || type == BlockID.BURNING_FURNACE + || type == BlockID.DISPENSER) { + switch (data) { + case 5: return 2; + case 4: return 3; + case 2: return 4; + case 3: return 5; + } + } else if (type == BlockID.PUMPKIN + || type == BlockID.JACKOLANTERN) { + switch (data) { + case 1: return 0; + case 2: return 1; + case 3: return 2; + case 0: return 3; + } + } + + return data; + } + + /** + * Flip a block's data value. + * + * @param type + * @param data + * @return + */ + public static int flip(int type, int data) { + return rotate90(type, rotate90(type, data)); + } +}