From b06937d1c882e128d78301277ff890982340f6a5 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sun, 1 Jul 2018 22:03:22 +1000 Subject: [PATCH] Setup a legacy mapper system. The file does not exist yet. --- .../sk89q/worldedit/bukkit/BukkitWorld.java | 15 +- .../EditSessionBlockChangeDelegate.java | 10 +- .../java/com/sk89q/worldedit/EditSession.java | 13 +- .../java/com/sk89q/worldedit/WorldEdit.java | 2 + .../com/sk89q/worldedit/blocks/BaseBlock.java | 35 +- .../com/sk89q/worldedit/blocks/BaseItem.java | 8 +- .../com/sk89q/worldedit/blocks/BlockData.java | 422 ++++++++---------- .../com/sk89q/worldedit/blocks/BlockType.java | 19 - .../sk89q/worldedit/blocks/ClothColor.java | 100 +---- .../worldedit/blocks/type/BlockState.java | 5 + .../blocks/type/BlockStateHolder.java | 7 + .../worldedit/blocks/type/BlockType.java | 5 +- .../sk89q/worldedit/blocks/type/ItemType.java | 8 +- .../command/tool/BlockDataCyler.java | 9 +- .../extension/factory/DefaultBlockParser.java | 68 +-- .../extent/clipboard/BlockArrayClipboard.java | 6 +- .../function/block/ExtentBlockCopy.java | 2 +- .../util/PropertiesConfiguration.java | 6 +- .../worldedit/util/YAMLConfiguration.java | 5 +- .../world/registry/BlockRegistry.java | 10 - .../world/registry/BundledBlockData.java | 53 +-- .../world/registry/BundledBlockRegistry.java | 11 - .../world/registry/BundledItemData.java | 52 +-- .../world/registry/BundledItemRegistry.java | 11 - .../world/registry/ItemRegistry.java | 9 - .../world/registry/LegacyMapper.java | 152 +++++++ .../world/registry/state/SimpleState.java | 13 + .../worldedit/world/registry/state/State.java | 7 + .../sk89q/worldedit/blocks/BlockDataTest.java | 76 ---- .../worldedit/forge/ForgeItemRegistry.java | 10 - .../config/ConfigurateConfiguration.java | 7 +- 31 files changed, 497 insertions(+), 659 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 2c1a5e606..56654dc07 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -31,8 +31,6 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.blocks.type.BlockStateHolder; -import com.sk89q.worldedit.blocks.type.BlockType; -import com.sk89q.worldedit.blocks.type.BlockTypes; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.history.change.BlockChange; @@ -40,7 +38,7 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.biome.BaseBiome; -import com.sk89q.worldedit.world.registry.BundledBlockData; +import com.sk89q.worldedit.world.registry.LegacyMapper; import org.bukkit.Effect; import org.bukkit.TreeType; import org.bukkit.World; @@ -361,10 +359,7 @@ public class BukkitWorld extends AbstractWorld { @Override public com.sk89q.worldedit.blocks.type.BlockState getBlock(Vector position) { Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - BlockType blockType = BlockTypes.getBlockType( - BundledBlockData.getInstance().fromLegacyId(bukkitBlock.getTypeId()) - ); - return blockType.getDefaultState(); // TODO Data + return LegacyMapper.getInstance().getBlockFromLegacy(bukkitBlock.getTypeId(), bukkitBlock.getData()); } @Override @@ -374,7 +369,11 @@ public class BukkitWorld extends AbstractWorld { return adapter.setBlock(BukkitAdapter.adapt(getWorld(), position), block, notifyAndLight); } else { Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - return bukkitBlock.setTypeIdAndData(block.getBlockType().getLegacyId(), (byte) 0, notifyAndLight); // TODO Data + int[] datas = LegacyMapper.getInstance().getLegacyFromBlock(block.toImmutableState()); + if (datas == null) { + throw new WorldEditException("Unknown block"){}; // TODO Remove. + } + return bukkitBlock.setTypeIdAndData(datas[0], (byte) datas[1], notifyAndLight); } } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDelegate.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDelegate.java index 04de1794d..08d1c0841 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDelegate.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDelegate.java @@ -19,13 +19,12 @@ package com.sk89q.worldedit.bukkit; -import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.type.BlockTypes; +import com.sk89q.worldedit.world.registry.LegacyMapper; import org.bukkit.BlockChangeDelegate; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.blocks.BaseBlock; /** * Proxy class to catch calls to set blocks. @@ -41,7 +40,7 @@ public class EditSessionBlockChangeDelegate implements BlockChangeDelegate { @Override public boolean setRawTypeId(int x, int y, int z, int typeId) { try { - return editSession.setBlock(new Vector(x, y, z), new BaseBlock(typeId)); + return editSession.setBlock(new Vector(x, y, z), LegacyMapper.getInstance().getBlockFromLegacy(typeId)); } catch (MaxChangedBlocksException ex) { return false; } @@ -50,7 +49,7 @@ public class EditSessionBlockChangeDelegate implements BlockChangeDelegate { @Override public boolean setRawTypeIdAndData(int x, int y, int z, int typeId, int data) { try { - return editSession.setBlock(new Vector(x, y, z), new BaseBlock(typeId, data)); + return editSession.setBlock(new Vector(x, y, z), LegacyMapper.getInstance().getBlockFromLegacy(typeId, data)); } catch (MaxChangedBlocksException ex) { return false; } @@ -68,7 +67,8 @@ public class EditSessionBlockChangeDelegate implements BlockChangeDelegate { @Override public int getTypeId(int x, int y, int z) { - return editSession.getBlock(new Vector(x, y, z)).getBlockType().getLegacyId(); + int[] datas = LegacyMapper.getInstance().getLegacyFromBlock(editSession.getBlock(new Vector(x, y, z))); + return datas[0]; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index e18c95efd..1d98d726a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -108,6 +108,7 @@ import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.registry.LegacyMapper; import java.util.ArrayList; import java.util.Collections; @@ -440,10 +441,9 @@ public class EditSession implements Extent { public int getHighestTerrainBlock(int x, int z, int minY, int maxY, boolean naturalOnly) { for (int y = maxY; y >= minY; --y) { Vector pt = new Vector(x, y, z); - BaseBlock block = getLazyBlock(pt); - int id = block.getId(); - int data = block.getData(); - if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, data) : !BlockType.canPassThrough(id, data)) { + BlockState block = getBlock(pt); + int[] datas = LegacyMapper.getInstance().getLegacyFromBlock(block); + if (naturalOnly ? BlockType.isNaturalTerrainBlock(datas[0], datas[1]) : !BlockType.canPassThrough(datas[0], datas[1])) { return y; } } @@ -2115,8 +2115,9 @@ public class EditSession implements Extent { while (!queue.isEmpty()) { final BlockVector current = queue.removeFirst(); - final BaseBlock block = getLazyBlock(current); - if (!BlockType.canPassThrough(block.getId(), block.getData())) { + final BlockState block = getBlock(current); + int[] datas = LegacyMapper.getInstance().getLegacyFromBlock(block); + if (!BlockType.canPassThrough(datas[0], datas[1])) { continue; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index 761f4fb60..64d9485c0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -53,6 +53,7 @@ import com.sk89q.worldedit.util.io.file.InvalidFilenameException; import com.sk89q.worldedit.util.logging.WorldEditPrefixHandler; import com.sk89q.worldedit.world.registry.BundledBlockData; import com.sk89q.worldedit.world.registry.BundledItemData; +import com.sk89q.worldedit.world.registry.LegacyMapper; import java.io.DataInputStream; import java.io.File; @@ -101,6 +102,7 @@ public class WorldEdit { getVersion(); BundledBlockData.getInstance(); // Load block registry BundledItemData.getInstance(); // Load item registry + LegacyMapper.getInstance(); // Load item registry } private WorldEdit() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java index 45db309f8..00a2832d4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java @@ -27,7 +27,7 @@ import com.sk89q.worldedit.blocks.type.BlockStateHolder; import com.sk89q.worldedit.blocks.type.BlockType; import com.sk89q.worldedit.blocks.type.BlockTypes; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.world.registry.BundledBlockData; +import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.registry.state.State; import com.sk89q.worldedit.world.registry.state.value.StateValue; @@ -52,9 +52,6 @@ import javax.annotation.Nullable; */ public class BaseBlock implements BlockStateHolder, TileEntityBlock { - // Instances of this class should be _as small as possible_ because there will - // be millions of instances of this object. - private BlockState blockState; @Nullable private CompoundTag nbtData; @@ -67,10 +64,12 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { @Deprecated public BaseBlock(int id) { try { - this.blockState = BlockTypes.getBlockType(BundledBlockData.getInstance().fromLegacyId(id)).getDefaultState(); + this.blockState = LegacyMapper.getInstance().getBlockFromLegacy(id); + if (this.blockState == null) { + this.blockState = BlockTypes.AIR.getDefaultState(); + } } catch (Exception e) { System.out.println(id); - System.out.println(BundledBlockData.getInstance().fromLegacyId(id)); e.printStackTrace(); } } @@ -134,16 +133,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { * @param other the other block */ public BaseBlock(BaseBlock other) { - this(other.getState(), other.getNbtData()); - } - - /** - * Get the block state - * - * @return The block state - */ - public BlockState getState() { - return this.blockState; + this(other.toImmutableState(), other.getNbtData()); } /** @@ -240,7 +230,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { final BaseBlock otherBlock = (BaseBlock) o; - return this.getState().equals(otherBlock.getState()) && Objects.equals(getNbtData(), otherBlock.getNbtData()); + return this.toImmutableState().equals(otherBlock.toImmutableState()) && Objects.equals(getNbtData(), otherBlock.getNbtData()); } @@ -252,12 +242,17 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { */ @Override public boolean equalsFuzzy(BlockStateHolder o) { - return this.getState().equalsFuzzy(o); + return this.toImmutableState().equalsFuzzy(o); + } + + @Override + public BlockState toImmutableState() { + return this.blockState; } @Override public int hashCode() { - int ret = getState().hashCode() << 3; + int ret = toImmutableState().hashCode() << 3; if (hasNbtData()) { ret += getNbtData().hashCode(); } @@ -266,7 +261,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { @Override public String toString() { - return "Block{State: " + this.getState().toString() + ", NBT: " + String.valueOf(getNbtData()) + "}"; + return "Block{State: " + this.toImmutableState().toString() + ", NBT: " + String.valueOf(getNbtData()) + "}"; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java index be35174d1..5f7e7f1b2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java @@ -23,7 +23,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.blocks.type.ItemType; import com.sk89q.worldedit.blocks.type.ItemTypes; import com.sk89q.worldedit.world.NbtValued; -import com.sk89q.worldedit.world.registry.BundledItemData; +import com.sk89q.worldedit.world.registry.LegacyMapper; import javax.annotation.Nullable; @@ -46,7 +46,11 @@ public class BaseItem implements NbtValued { */ @Deprecated public BaseItem(int id) { - this(ItemTypes.getItemType(BundledItemData.getInstance().fromLegacyId(id))); + ItemType type = LegacyMapper.getInstance().getItemFromLegacy(id); + if (type == null) { + type = ItemTypes.AIR; + } + this.itemType = type; } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockData.java index 006de9041..ebdfae894 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockData.java @@ -855,246 +855,188 @@ public final class BlockData { * @return the new data value for the block */ public static int cycle(int type, int data, int increment) { - if (increment != -1 && increment != 1) { - throw new IllegalArgumentException("Increment must be 1 or -1."); - } - - int store; - switch (type) { - - // special case here, going to use "forward" for type and "backward" for orientation - case BlockID.LOG: - case BlockID.LOG2: - if (increment == -1) { - store = data & 0x3; // copy bottom (type) bits - return mod((data & ~0x3) + 4, 16) | store; // switch orientation with top bits and reapply bottom bits; - } else { - store = data & ~0x3; // copy top (orientation) bits - return mod((data & 0x3) + 1, 4) | store; // switch type with bottom bits and reapply top bits - } - - // same here - screw you unit tests - /*case BlockID.QUARTZ_BLOCK: - if (increment == -1 && data > 2) { - switch (data) { - case 2: return 3; - case 3: return 4; - case 4: return 2; - } - } else if (increment == 1) { - switch (data) { - case 0: - return 1; - case 1: - return 2; - case 2: - case 3: - case 4: - return 0; - } - } else { - return -1; - }*/ - - case BlockID.LONG_GRASS: - case BlockID.SANDSTONE: - case BlockID.DIRT: - if (data > 2) return -1; - return mod((data + increment), 3); - - case BlockID.TORCH: - case BlockID.REDSTONE_TORCH_ON: - case BlockID.REDSTONE_TORCH_OFF: - if (data < 1 || data > 4) return -1; - return mod((data - 1 + increment), 4) + 1; - - case BlockID.OAK_WOOD_STAIRS: - case BlockID.COBBLESTONE_STAIRS: - case BlockID.BRICK_STAIRS: - case BlockID.STONE_BRICK_STAIRS: - case BlockID.NETHER_BRICK_STAIRS: - case BlockID.SANDSTONE_STAIRS: - case BlockID.SPRUCE_WOOD_STAIRS: - case BlockID.BIRCH_WOOD_STAIRS: - case BlockID.JUNGLE_WOOD_STAIRS: - case BlockID.QUARTZ_STAIRS: - case BlockID.ACACIA_STAIRS: - case BlockID.DARK_OAK_STAIRS: - if (data > 7) return -1; - return mod((data + increment), 8); - - case BlockID.STONE_BRICK: - case BlockID.QUARTZ_BLOCK: - case BlockID.PUMPKIN: - case BlockID.JACKOLANTERN: - case BlockID.NETHER_WART: - case BlockID.CAULDRON: - case BlockID.WOODEN_STEP: - case BlockID.DOUBLE_WOODEN_STEP: - case BlockID.HAY_BLOCK: - if (data > 3) return -1; - return mod((data + increment), 4); - - case BlockID.STEP: - case BlockID.DOUBLE_STEP: - case BlockID.CAKE_BLOCK: - case BlockID.PISTON_BASE: - case BlockID.PISTON_STICKY_BASE: - case BlockID.SILVERFISH_BLOCK: - if (data > 5) return -1; - return mod((data + increment), 6); - - case BlockID.DOUBLE_PLANT: - store = data & 0x8; // top half flag - data &= ~0x8; - if (data > 5) return -1; - return mod((data + increment), 6) | store; - - case BlockID.CROPS: - case BlockID.PUMPKIN_STEM: - case BlockID.MELON_STEM: - if (data > 6) return -1; - return mod((data + increment), 7); - - case BlockID.SOIL: - case BlockID.RED_FLOWER: - if (data > 8) return -1; - return mod((data + increment), 9); - - case BlockID.RED_MUSHROOM_CAP: - case BlockID.BROWN_MUSHROOM_CAP: - if (data > 10) return -1; - return mod((data + increment), 11); - - case BlockID.CACTUS: - case BlockID.REED: - case BlockID.SIGN_POST: - case BlockID.VINE: - case BlockID.SNOW: - case BlockID.COCOA_PLANT: - if (data > 15) return -1; - return mod((data + increment), 16); - - case BlockID.FURNACE: - case BlockID.BURNING_FURNACE: - case BlockID.WALL_SIGN: - case BlockID.LADDER: - case BlockID.CHEST: - case BlockID.ENDER_CHEST: - case BlockID.TRAPPED_CHEST: - case BlockID.HOPPER: - int extra = data & 0x8; - int withoutFlags = data & ~0x8; - if (withoutFlags < 2 || withoutFlags > 5) return -1; - return (mod((withoutFlags - 2 + increment), 4) + 2) | extra; - - case BlockID.DISPENSER: - case BlockID.DROPPER: - store = data & 0x8; - data &= ~0x8; - if (data > 5) return -1; - return mod((data + increment), 6) | store; - - case BlockID.REDSTONE_REPEATER_OFF: - case BlockID.REDSTONE_REPEATER_ON: - case BlockID.COMPARATOR_OFF: - case BlockID.COMPARATOR_ON: - case BlockID.TRAP_DOOR: - case BlockID.FENCE_GATE: - case BlockID.LEAVES: - case BlockID.LEAVES2: - if (data > 7) return -1; - store = data & ~0x3; - return mod(((data & 0x3) + increment), 4) | store; - - case BlockID.MINECART_TRACKS: - if (data < 6 || data > 9) return -1; - return mod((data - 6 + increment), 4) + 6; - - case BlockID.SAPLING: - if ((data & 0x3) == 3 || data > 15) return -1; - store = data & ~0x3; - return mod(((data & 0x3) + increment), 3) | store; - - case BlockID.FLOWER_POT: - if (data > 13) return -1; - return mod((data + increment), 14); - - case BlockID.CLOTH: - case BlockID.STAINED_CLAY: - case BlockID.CARPET: - case BlockID.STAINED_GLASS: - case BlockID.STAINED_GLASS_PANE: - if (increment == 1) { - data = nextClothColor(data); - } else if (increment == -1) { - data = prevClothColor(data); - } - return data; - - default: - return -1; - } - } - - /** - * Returns the data value for the next color of cloth in the rainbow. This - * should not be used if you want to just increment the data value. - * - * @param data the data value - * @return the next data value - */ - public static int nextClothColor(int data) { - switch (data) { - case ClothColor.ID.WHITE: return ClothColor.ID.LIGHT_GRAY; - case ClothColor.ID.LIGHT_GRAY: return ClothColor.ID.GRAY; - case ClothColor.ID.GRAY: return ClothColor.ID.BLACK; - case ClothColor.ID.BLACK: return ClothColor.ID.BROWN; - case ClothColor.ID.BROWN: return ClothColor.ID.RED; - case ClothColor.ID.RED: return ClothColor.ID.ORANGE; - case ClothColor.ID.ORANGE: return ClothColor.ID.YELLOW; - case ClothColor.ID.YELLOW: return ClothColor.ID.LIGHT_GREEN; - case ClothColor.ID.LIGHT_GREEN: return ClothColor.ID.DARK_GREEN; - case ClothColor.ID.DARK_GREEN: return ClothColor.ID.CYAN; - case ClothColor.ID.CYAN: return ClothColor.ID.LIGHT_BLUE; - case ClothColor.ID.LIGHT_BLUE: return ClothColor.ID.BLUE; - case ClothColor.ID.BLUE: return ClothColor.ID.PURPLE; - case ClothColor.ID.PURPLE: return ClothColor.ID.MAGENTA; - case ClothColor.ID.MAGENTA: return ClothColor.ID.PINK; - case ClothColor.ID.PINK: return ClothColor.ID.WHITE; - } - - return ClothColor.ID.WHITE; - } - - /** - * Returns the data value for the previous ext color of cloth in the rainbow. - * This should not be used if you want to just increment the data value. - * - * @param data the data value - * @return the new data value - */ - public static int prevClothColor(int data) { - switch (data) { - case ClothColor.ID.LIGHT_GRAY: return ClothColor.ID.WHITE; - case ClothColor.ID.GRAY: return ClothColor.ID.LIGHT_GRAY; - case ClothColor.ID.BLACK: return ClothColor.ID.GRAY; - case ClothColor.ID.BROWN: return ClothColor.ID.BLACK; - case ClothColor.ID.RED: return ClothColor.ID.BROWN; - case ClothColor.ID.ORANGE: return ClothColor.ID.RED; - case ClothColor.ID.YELLOW: return ClothColor.ID.ORANGE; - case ClothColor.ID.LIGHT_GREEN: return ClothColor.ID.YELLOW; - case ClothColor.ID.DARK_GREEN: return ClothColor.ID.LIGHT_GREEN; - case ClothColor.ID.CYAN: return ClothColor.ID.DARK_GREEN; - case ClothColor.ID.LIGHT_BLUE: return ClothColor.ID.CYAN; - case ClothColor.ID.BLUE: return ClothColor.ID.LIGHT_BLUE; - case ClothColor.ID.PURPLE: return ClothColor.ID.BLUE; - case ClothColor.ID.MAGENTA: return ClothColor.ID.PURPLE; - case ClothColor.ID.PINK: return ClothColor.ID.MAGENTA; - case ClothColor.ID.WHITE: return ClothColor.ID.PINK; - } - - return ClothColor.ID.WHITE; + return data + increment; + // TODO Fix +// if (increment != -1 && increment != 1) { +// throw new IllegalArgumentException("Increment must be 1 or -1."); +// } +// +// int store; +// switch (type) { +// +// // special case here, going to use "forward" for type and "backward" for orientation +// case BlockID.LOG: +// case BlockID.LOG2: +// if (increment == -1) { +// store = data & 0x3; // copy bottom (type) bits +// return mod((data & ~0x3) + 4, 16) | store; // switch orientation with top bits and reapply bottom bits; +// } else { +// store = data & ~0x3; // copy top (orientation) bits +// return mod((data & 0x3) + 1, 4) | store; // switch type with bottom bits and reapply top bits +// } +// +// // same here - screw you unit tests +// /*case BlockID.QUARTZ_BLOCK: +// if (increment == -1 && data > 2) { +// switch (data) { +// case 2: return 3; +// case 3: return 4; +// case 4: return 2; +// } +// } else if (increment == 1) { +// switch (data) { +// case 0: +// return 1; +// case 1: +// return 2; +// case 2: +// case 3: +// case 4: +// return 0; +// } +// } else { +// return -1; +// }*/ +// +// case BlockID.LONG_GRASS: +// case BlockID.SANDSTONE: +// case BlockID.DIRT: +// if (data > 2) return -1; +// return mod((data + increment), 3); +// +// case BlockID.TORCH: +// case BlockID.REDSTONE_TORCH_ON: +// case BlockID.REDSTONE_TORCH_OFF: +// if (data < 1 || data > 4) return -1; +// return mod((data - 1 + increment), 4) + 1; +// +// case BlockID.OAK_WOOD_STAIRS: +// case BlockID.COBBLESTONE_STAIRS: +// case BlockID.BRICK_STAIRS: +// case BlockID.STONE_BRICK_STAIRS: +// case BlockID.NETHER_BRICK_STAIRS: +// case BlockID.SANDSTONE_STAIRS: +// case BlockID.SPRUCE_WOOD_STAIRS: +// case BlockID.BIRCH_WOOD_STAIRS: +// case BlockID.JUNGLE_WOOD_STAIRS: +// case BlockID.QUARTZ_STAIRS: +// case BlockID.ACACIA_STAIRS: +// case BlockID.DARK_OAK_STAIRS: +// if (data > 7) return -1; +// return mod((data + increment), 8); +// +// case BlockID.STONE_BRICK: +// case BlockID.QUARTZ_BLOCK: +// case BlockID.PUMPKIN: +// case BlockID.JACKOLANTERN: +// case BlockID.NETHER_WART: +// case BlockID.CAULDRON: +// case BlockID.WOODEN_STEP: +// case BlockID.DOUBLE_WOODEN_STEP: +// case BlockID.HAY_BLOCK: +// if (data > 3) return -1; +// return mod((data + increment), 4); +// +// case BlockID.STEP: +// case BlockID.DOUBLE_STEP: +// case BlockID.CAKE_BLOCK: +// case BlockID.PISTON_BASE: +// case BlockID.PISTON_STICKY_BASE: +// case BlockID.SILVERFISH_BLOCK: +// if (data > 5) return -1; +// return mod((data + increment), 6); +// +// case BlockID.DOUBLE_PLANT: +// store = data & 0x8; // top half flag +// data &= ~0x8; +// if (data > 5) return -1; +// return mod((data + increment), 6) | store; +// +// case BlockID.CROPS: +// case BlockID.PUMPKIN_STEM: +// case BlockID.MELON_STEM: +// if (data > 6) return -1; +// return mod((data + increment), 7); +// +// case BlockID.SOIL: +// case BlockID.RED_FLOWER: +// if (data > 8) return -1; +// return mod((data + increment), 9); +// +// case BlockID.RED_MUSHROOM_CAP: +// case BlockID.BROWN_MUSHROOM_CAP: +// if (data > 10) return -1; +// return mod((data + increment), 11); +// +// case BlockID.CACTUS: +// case BlockID.REED: +// case BlockID.SIGN_POST: +// case BlockID.VINE: +// case BlockID.SNOW: +// case BlockID.COCOA_PLANT: +// if (data > 15) return -1; +// return mod((data + increment), 16); +// +// case BlockID.FURNACE: +// case BlockID.BURNING_FURNACE: +// case BlockID.WALL_SIGN: +// case BlockID.LADDER: +// case BlockID.CHEST: +// case BlockID.ENDER_CHEST: +// case BlockID.TRAPPED_CHEST: +// case BlockID.HOPPER: +// int extra = data & 0x8; +// int withoutFlags = data & ~0x8; +// if (withoutFlags < 2 || withoutFlags > 5) return -1; +// return (mod((withoutFlags - 2 + increment), 4) + 2) | extra; +// +// case BlockID.DISPENSER: +// case BlockID.DROPPER: +// store = data & 0x8; +// data &= ~0x8; +// if (data > 5) return -1; +// return mod((data + increment), 6) | store; +// +// case BlockID.REDSTONE_REPEATER_OFF: +// case BlockID.REDSTONE_REPEATER_ON: +// case BlockID.COMPARATOR_OFF: +// case BlockID.COMPARATOR_ON: +// case BlockID.TRAP_DOOR: +// case BlockID.FENCE_GATE: +// case BlockID.LEAVES: +// case BlockID.LEAVES2: +// if (data > 7) return -1; +// store = data & ~0x3; +// return mod(((data & 0x3) + increment), 4) | store; +// +// case BlockID.MINECART_TRACKS: +// if (data < 6 || data > 9) return -1; +// return mod((data - 6 + increment), 4) + 6; +// +// case BlockID.SAPLING: +// if ((data & 0x3) == 3 || data > 15) return -1; +// store = data & ~0x3; +// return mod(((data & 0x3) + increment), 3) | store; +// +// case BlockID.FLOWER_POT: +// if (data > 13) return -1; +// return mod((data + increment), 14); +// +// case BlockID.CLOTH: +// case BlockID.STAINED_CLAY: +// case BlockID.CARPET: +// case BlockID.STAINED_GLASS: +// case BlockID.STAINED_GLASS_PANE: +// if (increment == 1) { +// data = nextClothColor(data); +// } else if (increment == -1) { +// data = prevClothColor(data); +// } +// return data; +// +// default: +// return -1; +// } } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockType.java index 32208eb00..c77a4ca67 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockType.java @@ -1194,25 +1194,6 @@ public enum BlockType { return isNaturalTerrainBlock.contains(-16*id-data) || isNaturalTerrainBlock.contains(id); } - /** - * Checks if the block type is naturally occurring - * - * @param block the block - * @return true if the block type is naturally occurring - */ - public static boolean isNaturalTerrainBlock(BaseBlock block) { - return isNaturalTerrainBlock(block.getId(), block.getData()); - } - - /** - * Checks if the block type is naturally occurring - * - * @return true if the block type is naturally occurring - */ - public boolean isNaturalTerrainBlock() { - return isNaturalTerrainBlock.contains(id); - } - /** * HashSet for emitsLight. */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java index 5cf0a5e3f..23562fdf0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java @@ -31,61 +31,32 @@ import java.util.EnumSet; */ public enum ClothColor { - WHITE(ID.WHITE, "White", "white"), - ORANGE(ID.ORANGE, "Orange", "orange"), - MAGENTA(ID.MAGENTA, "Magenta", "magenta"), - LIGHT_BLUE(ID.LIGHT_BLUE, "Light blue", "lightblue"), - YELLOW(ID.YELLOW, "Yellow", "yellow"), - LIGHT_GREEN(ID.LIGHT_GREEN, "Light green", "lightgreen"), - PINK(ID.PINK, "Pink", new String[] { "pink", "lightred" }), - GRAY(ID.GRAY, "Gray", new String[] { "grey", "gray" }), - LIGHT_GRAY(ID.LIGHT_GRAY, "Light gray", new String[] { "lightgrey", "lightgray" }), - CYAN(ID.CYAN, "Cyan", new String[] { "cyan", "turquoise" }), - PURPLE(ID.PURPLE, "Purple", new String[] { "purple", "violet" }), - BLUE(ID.BLUE, "Blue", "blue"), - BROWN(ID.BROWN, "Brown", new String[] { "brown", "cocoa", "coffee" }), - DARK_GREEN(ID.DARK_GREEN, "Dark green", new String[] { "green", "darkgreen", "cactusgreen", "cactigreen" }), - RED(ID.RED, "Red", "red"), - BLACK(ID.BLACK, "Black", "black"); - - public static final class ID { - public static final int WHITE = 0; - public static final int ORANGE = 1; - public static final int MAGENTA = 2; - public static final int LIGHT_BLUE = 3; - public static final int YELLOW = 4; - public static final int LIGHT_GREEN = 5; - public static final int PINK = 6; - public static final int GRAY = 7; - public static final int LIGHT_GRAY = 8; - public static final int CYAN = 9; - public static final int PURPLE = 10; - public static final int BLUE = 11; - public static final int BROWN = 12; - public static final int DARK_GREEN = 13; - public static final int RED = 14; - public static final int BLACK = 15; - - private ID() { - } - } - - /** - * Stores a map of the IDs for fast access. - */ - private static final Map ids = new HashMap<>(); + WHITE("White", "white"), + ORANGE("Orange", "orange"), + MAGENTA("Magenta", "magenta"), + LIGHT_BLUE("Light blue", "lightblue"), + YELLOW("Yellow", "yellow"), + LIGHT_GREEN("Light green", "lightgreen"), + PINK("Pink", "pink", "lightred"), + GRAY("Gray", "grey", "gray"), + LIGHT_GRAY("Light gray", "lightgrey", "lightgray"), + CYAN("Cyan", "cyan", "turquoise"), + PURPLE("Purple", "purple", "violet"), + BLUE("Blue", "blue"), + BROWN("Brown", "brown", "cocoa", "coffee"), + DARK_GREEN("Dark green", "green", "darkgreen", "cactusgreen", "cactigreen"), + RED("Red", "red"), + BLACK("Black", "black"); /** * Stores a map of the names for fast access. */ private static final Map lookup = new HashMap<>(); - private final int id; private final String name; private final String[] lookupKeys; static { for (ClothColor type : EnumSet.allOf(ClothColor.class)) { - ids.put(type.id, type); for (String key : type.lookupKeys) { lookup.put(key, type); } @@ -96,40 +67,14 @@ public enum ClothColor { /** * Construct the type. * - * @param id the ID of the color * @param name the name of the color - * @param lookupKey a name to refer to the color by + * @param lookupKeys a name to refer to the color by */ - ClothColor(int id, String name, String lookupKey) { - this.id = id; - this.name = name; - this.lookupKeys = new String[] { lookupKey }; - } - - /** - * Construct the type. - * - * @param id the ID of the color - * @param name the name of the color - * @param lookupKeys an array of lookup keys - */ - ClothColor(int id, String name, String[] lookupKeys) { - this.id = id; + ClothColor(String name, String ... lookupKeys) { this.name = name; this.lookupKeys = lookupKeys; } - /** - * Return type from ID. May return null. - * - * @param id the ID - * @return a color or null - */ - @Nullable - public static ClothColor fromID(int id) { - return ids.get(id); - } - /** * Return type from name. May return null. * @@ -141,15 +86,6 @@ public enum ClothColor { return lookup.get(name.toLowerCase()); } - /** - * Get item numeric ID. - * - * @return the ID - */ - public int getID() { - return id; - } - /** * Get user-friendly item name. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockState.java index 43a867180..8fb84cfbb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockState.java @@ -141,6 +141,11 @@ public class BlockState implements BlockStateHolder { return true; } + @Override + public BlockState toImmutableState() { + return this; + } + /** * Internal method used for creating the initial BlockState. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockStateHolder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockStateHolder.java index d39d1c5d1..3c71c3e29 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockStateHolder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockStateHolder.java @@ -64,4 +64,11 @@ public interface BlockStateHolder { * @return true if equal */ boolean equalsFuzzy(BlockStateHolder o); + + /** + * Returns an immutable BlockState from this BlockStateHolder. + * + * @return A BlockState + */ + BlockState toImmutableState(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockType.java index a1afc2820..98b2c4fdd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/BlockType.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.blocks.type; import com.sk89q.worldedit.world.registry.BundledBlockData; +import com.sk89q.worldedit.world.registry.LegacyMapper; import java.util.function.Function; @@ -85,9 +86,9 @@ public class BlockType { */ @Deprecated public int getLegacyId() { - Integer id = BundledBlockData.getInstance().toLegacyId(this.id); + int[] id = LegacyMapper.getInstance().getLegacyFromBlock(this.getDefaultState()); if (id != null) { - return id; + return id[0]; } else { return 0; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/ItemType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/ItemType.java index f7443adf7..c3c6659f0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/ItemType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/type/ItemType.java @@ -19,8 +19,8 @@ package com.sk89q.worldedit.blocks.type; -import com.sk89q.worldedit.world.registry.BundledBlockData; import com.sk89q.worldedit.world.registry.BundledItemData; +import com.sk89q.worldedit.world.registry.LegacyMapper; public class ItemType { @@ -61,9 +61,9 @@ public class ItemType { */ @Deprecated public int getLegacyId() { - Integer id = BundledItemData.getInstance().toLegacyId(this.id); - if (id != null) { - return id; + int ids[] = LegacyMapper.getInstance().getLegacyFromItem(this); + if (ids != null) { + return ids[0]; } else { return 0; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java index 85e0c56b1..7894852e4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java @@ -25,11 +25,13 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockData; +import com.sk89q.worldedit.blocks.type.BlockState; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.registry.LegacyMapper; /** * A mode that cycles the data values of supported blocks. @@ -46,9 +48,10 @@ public class BlockDataCyler implements DoubleActionBlockTool { World world = (World) clicked.getExtent(); - BaseBlock block = world.getLazyBlock(clicked.toVector()); - int type = block.getId(); - int data = block.getData(); + BlockState block = world.getBlock(clicked.toVector()); + int[] datas = LegacyMapper.getInstance().getLegacyFromBlock(block); + int type = datas[0]; + int data = datas[1]; if (!config.allowedDataCycleBlocks.isEmpty() && !player.hasPermission("worldedit.override.data-cycler") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java index b315d485d..8edeb5dee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java @@ -153,6 +153,37 @@ class DefaultBlockParser extends InputParser { } } + private static BlockState applyProperties(BlockState state, String[] stateProperties) throws NoMatchException { + if (stateProperties.length > 0) { // Block data not yet detected + // Parse the block data (optional) + for (String parseableData : stateProperties) { + try { + String[] parts = parseableData.split("="); + if (parts.length != 2) { + throw new NoMatchException("Bad state format in " + parseableData); + } + + State stateKey = BundledBlockData.getInstance().findById(state.getBlockType().getId()).states.get(parts[0]); + if (stateKey == null) { + throw new NoMatchException("Unknown state " + parts[0] + " for block " + state.getBlockType().getName()); + } + StateValue value = stateKey.getValueFor(parts[1]); + if (value == null) { + throw new NoMatchException("Unknown value " + parts[1] + " for state " + parts[0]); + } + + state = state.with(stateKey, value); + } catch (NoMatchException e) { + throw e; // Pass-through + } catch (Exception e) { + throw new NoMatchException("Unknown state '" + parseableData + "'"); + } + } + } + + return state; + } + private BlockStateHolder parseLogic(String input, ParserContext context) throws InputParseException { BlockType blockType; Map blockStates = new HashMap<>(); @@ -217,38 +248,15 @@ class DefaultBlockParser extends InputParser { state = new BlockState(blockType, blockStates); } - if (stateProperties.length > 0) { // Block data not yet detected - // Parse the block data (optional) - for (String parseableData : stateProperties) { - try { - String[] parts = parseableData.split("="); - if (parts.length != 2) { - throw new NoMatchException("Bad state format in " + parseableData); - } - - State stateKey = BundledBlockData.getInstance().findById(blockType.getId()).states.get(parts[0]); - if (stateKey == null) { - throw new NoMatchException("Unknown state " + parts[0] + " for block " + blockType.getName()); - } - StateValue value = stateKey.getValueFor(parts[1]); - if (value == null) { - throw new NoMatchException("Unknown value " + parts[1] + " for state " + parts[0]); - } - - state = state.with(stateKey, value); - } catch (NoMatchException e) { - throw e; // Pass-through - } catch (Exception e) { - throw new NoMatchException("Unknown state '" + parseableData + "'"); - } - } - } + state = applyProperties(state, stateProperties); // Check if the item is allowed - Actor actor = context.requireActor(); - if (context.isRestricted() && actor != null && !actor.hasPermission("worldedit.anyblock") - && worldEdit.getConfiguration().disallowedBlocks.contains(blockType.getId())) { - throw new DisallowedUsageException("You are not allowed to use '" + input + "'"); + if (context.isRestricted()) { + Actor actor = context.requireActor(); + if (actor != null && !actor.hasPermission("worldedit.anyblock") + && worldEdit.getConfiguration().disallowedBlocks.contains(blockType.getId())) { + throw new DisallowedUsageException("You are not allowed to use '" + input + "'"); + } } if (blockType == BlockTypes.SIGN || blockType == BlockTypes.WALL_SIGN) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 4c563f1ae..6a5d86acd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -128,11 +128,7 @@ public class BlockArrayClipboard implements Clipboard { Vector v = position.subtract(region.getMinimumPoint()); BlockStateHolder block = blocks[v.getBlockX()][v.getBlockY()][v.getBlockZ()]; if (block != null) { - if (block instanceof BlockState) { - return (BlockState) block; - } else if (block instanceof BaseBlock) { - return ((BaseBlock) block).getState(); - } + return block.toImmutableState(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java index 2b669b332..d20043450 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java @@ -105,7 +105,7 @@ public class ExtentBlockCopy implements RegionFunction { builder.putByte("Rot", (byte) MCDirections.toRotation(newDirection)); - return new BaseBlock(state.getState(), builder.build()); + return new BaseBlock(state.toImmutableState(), builder.build()); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index 9d0333814..472796c4a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -24,7 +24,7 @@ package com.sk89q.worldedit.util; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.world.registry.BundledItemData; +import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.snapshot.SnapshotRepository; import java.io.File; @@ -92,7 +92,7 @@ public class PropertiesConfiguration extends LocalConfiguration { registerHelp = getBool("register-help", registerHelp); wandItem = getString("wand-item", wandItem); try { - wandItem = BundledItemData.getInstance().fromLegacyId(Integer.parseInt(wandItem)); + wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).getId(); } catch (Throwable e) { } superPickaxeDrop = getBool("super-pickaxe-drop-items", superPickaxeDrop); @@ -103,7 +103,7 @@ public class PropertiesConfiguration extends LocalConfiguration { useInventoryCreativeOverride = getBool("use-inventory-creative-override", useInventoryCreativeOverride); navigationWand = getString("nav-wand-item", navigationWand); try { - navigationWand = BundledItemData.getInstance().fromLegacyId(Integer.parseInt(navigationWand)); + navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).getId(); } catch (Throwable e) { } navigationWandMaxDistance = getInt("nav-wand-distance", navigationWandMaxDistance); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java index e4502d949..24705db26 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.session.SessionManager; import com.sk89q.worldedit.world.registry.BundledItemData; +import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.snapshot.SnapshotRepository; import java.io.IOException; @@ -57,7 +58,7 @@ public class YAMLConfiguration extends LocalConfiguration { profile = config.getBoolean("debug", profile); wandItem = config.getString("wand-item", wandItem); try { - wandItem = BundledItemData.getInstance().fromLegacyId(Integer.parseInt(wandItem)); + wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).getId(); } catch (Throwable e) { } @@ -105,7 +106,7 @@ public class YAMLConfiguration extends LocalConfiguration { navigationWand = config.getString("navigation-wand.item", navigationWand); try { - navigationWand = BundledItemData.getInstance().fromLegacyId(Integer.parseInt(navigationWand)); + navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).getId(); } catch (Throwable e) { } navigationWandMaxDistance = config.getInt("navigation-wand.max-distance", navigationWandMaxDistance); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java index 4debcc682..ed1a88b9d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java @@ -42,16 +42,6 @@ public interface BlockRegistry { @Nullable BlockState createFromId(String id); - /** - * Create a new block using its legacy numeric ID. - * - * @param id the id - * @return the block, which may be null if no block exists - */ - @Nullable - @Deprecated - BlockState createFromId(int id); - /** * Get the material for the given block. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java index 76acf9de6..549bfe37a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java @@ -56,7 +56,6 @@ public class BundledBlockData { private static final BundledBlockData INSTANCE = new BundledBlockData(); private final Map idMap = new HashMap<>(); - private final Map legacyMap = new HashMap<>(); // Trove usage removed temporarily /** * Create a new instance. @@ -87,7 +86,7 @@ public class BundledBlockData { for (BlockEntry entry : entries) { idMap.put(entry.id, entry); - legacyMap.put(entry.legacyId, entry); + entry.postDeserialization(); } } @@ -106,49 +105,6 @@ public class BundledBlockData { return idMap.get(id); } - /** - * Return the entry for the given block legacy numeric ID. - * - * @param id the ID - * @return the entry, or null - */ - @Nullable - private BlockEntry findById(int id) { - return legacyMap.get(id); - } - - /** - * Convert the given string ID to a legacy numeric ID. - * - * @param id the ID - * @return the legacy ID, which may be null if the block does not have a legacy ID - */ - @Nullable - public Integer toLegacyId(String id) { - BlockEntry entry = findById(id); - if (entry != null) { - return entry.legacyId; - } else { - return null; - } - } - - /** - * Convert the given legacy numeric ID to a string ID. - * - * @param id the legacy ID - * @return the ID, which may be null if the block does not have a ID - */ - @Nullable - public String fromLegacyId(Integer id) { - BlockEntry entry = findById(id); - if (entry != null) { - return entry.id; - } else { - return null; - } - } - /** * Get the material properties for the given block. * @@ -191,13 +147,18 @@ public class BundledBlockData { } public static class BlockEntry { - private int legacyId; private String id; private String unlocalizedName; public String localizedName; private List aliases; public Map states = new HashMap<>(); private SimpleBlockMaterial material = new SimpleBlockMaterial(); + + void postDeserialization() { + for (Map.Entry state : states.entrySet()) { + state.getValue().setName(state.getKey()); + } + } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java index 56637e552..518f008e7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java @@ -41,17 +41,6 @@ public class BundledBlockRegistry implements BlockRegistry { return BlockTypes.getBlockType(id).getDefaultState(); } - @Nullable - @Override - public BlockState createFromId(int legacyId) { - String id = BundledBlockData.getInstance().fromLegacyId(legacyId); - if (id != null) { - return createFromId(id); - } else { - return null; - } - } - @Nullable @Override public BlockMaterial getMaterial(BaseBlock block) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java index 2a5fc607a..725367d40 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java @@ -54,7 +54,6 @@ public class BundledItemData { private static final BundledItemData INSTANCE = new BundledItemData(); private final Map idMap = new HashMap<>(); - private final Map legacyMap = new HashMap<>(); // Trove usage removed temporarily /** * Create a new instance. @@ -85,9 +84,6 @@ public class BundledItemData { for (ItemEntry entry : entries) { idMap.put(entry.id, entry); - if (entry.legacyId >= 0) { - legacyMap.put(entry.legacyId, entry); - } } } @@ -97,7 +93,8 @@ public class BundledItemData { * @param id the ID * @return the entry, or null */ - @Nullable public ItemEntry findById(String id) { + @Nullable + public ItemEntry findById(String id) { // If it has no namespace, assume minecraft. if (!id.contains(":")) { id = "minecraft:" + id; @@ -105,49 +102,6 @@ public class BundledItemData { return idMap.get(id); } - /** - * Return the entry for the given item legacy numeric ID. - * - * @param id the ID - * @return the entry, or null - */ - @Nullable - private ItemEntry findById(int id) { - return legacyMap.get(id); - } - - /** - * Convert the given string ID to a legacy numeric ID. - * - * @param id the ID - * @return the legacy ID, which may be null if the item does not have a legacy ID - */ - @Nullable - public Integer toLegacyId(String id) { - ItemEntry entry = findById(id); - if (entry != null) { - return entry.legacyId; - } else { - return null; - } - } - - /** - * Convert the given legacy numeric ID to a string ID. - * - * @param id the legacy ID - * @return the ID, which may be null if the item does not have a ID - */ - @Nullable - public String fromLegacyId(Integer id) { - ItemEntry entry = findById(id); - if (entry != null) { - return entry.id; - } else { - return null; - } - } - /** * Get a singleton instance of this object. * @@ -158,8 +112,6 @@ public class BundledItemData { } public static class ItemEntry { - private int legacyId; // -1 for items without legacy IDs. - private short legacyData; private String id; private String unlocalizedName; public String localizedName; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java index ab864ae29..d3692db76 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java @@ -35,15 +35,4 @@ public class BundledItemRegistry implements ItemRegistry { public BaseItem createFromId(String id) { return new BaseItem(ItemTypes.getItemType(id)); } - - @Nullable - @Override - public BaseItem createFromId(int legacyId) { - String id = BundledItemData.getInstance().fromLegacyId(legacyId); - if (id != null) { - return createFromId(id); - } else { - return null; - } - } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemRegistry.java index 31afa867f..749aa6a37 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemRegistry.java @@ -34,13 +34,4 @@ public interface ItemRegistry { @Nullable BaseItem createFromId(String id); - /** - * Create a new item using its legacy numeric ID. - * - * @param id the id - * @return the item, which may be null if no item exists - */ - @Nullable - BaseItem createFromId(int id); - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java new file mode 100644 index 000000000..823bb71e9 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java @@ -0,0 +1,152 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.registry; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.io.Resources; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.type.BlockState; +import com.sk89q.worldedit.blocks.type.ItemType; +import com.sk89q.worldedit.blocks.type.ItemTypes; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.util.gson.VectorAdapter; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.annotation.Nullable; + +public class LegacyMapper { + + private static final Logger log = Logger.getLogger(LegacyMapper.class.getCanonicalName()); + private static final LegacyMapper INSTANCE = new LegacyMapper(); + + private BiMap blockMap = HashBiMap.create(); + private BiMap itemMap = HashBiMap.create(); + + /** + * Create a new instance. + */ + private LegacyMapper() { + try { + loadFromResource(); + } catch (IOException e) { + log.log(Level.WARNING, "Failed to load the built-in legacy id registry", e); + } + } + + /** + * Attempt to load the data from file. + * + * @throws IOException thrown on I/O error + */ + private void loadFromResource() throws IOException { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(Vector.class, new VectorAdapter()); + Gson gson = gsonBuilder.disableHtmlEscaping().create(); + URL url = LegacyMapper.class.getResource("legacy.json"); + if (url == null) { + throw new IOException("Could not find legacy.json"); + } + String data = Resources.toString(url, Charset.defaultCharset()); + LegacyDataFile dataFile = gson.fromJson(data, new TypeToken() {}.getType()); + + ParserContext parserContext = new ParserContext(); + parserContext.setPreferringWildcard(false); + parserContext.setRestricted(false); + + for (Map.Entry blockEntry : dataFile.blocks.entrySet()) { + try { + blockMap.put(blockEntry.getKey(), + (BlockState) WorldEdit.getInstance().getBlockFactory().parseFromInput(blockEntry.getValue(), parserContext)); + } catch (Exception e) { + log.warning("Unknown block: " + blockEntry.getValue()); + } + } + + for (Map.Entry itemEntry : dataFile.items.entrySet()) { + try { + itemMap.put(itemEntry.getKey(), ItemTypes.getItemType(itemEntry.getValue())); + } catch (Exception e) { + log.warning("Unknown item: " + itemEntry.getValue()); + } + } + } + + @Nullable + public ItemType getItemFromLegacy(int legacyId) { + return itemMap.get(legacyId + ":0"); + } + + @Nullable + public ItemType getItemFromLegacy(int legacyId, int data) { + return itemMap.get(legacyId + ":" + data); + } + + @Nullable + public int[] getLegacyFromItem(ItemType itemType) { + if (!itemMap.inverse().containsKey(itemType)) { + return null; + } else { + String value = itemMap.inverse().get(itemType); + return Arrays.stream(value.split(":")).mapToInt(Integer::parseInt).toArray(); + } + } + + @Nullable + public BlockState getBlockFromLegacy(int legacyId) { + return blockMap.get(legacyId + ":0"); + } + + @Nullable + public BlockState getBlockFromLegacy(int legacyId, int data) { + return blockMap.get(legacyId + ":" + data); + } + + @Nullable + public int[] getLegacyFromBlock(BlockState blockState) { + if (!blockMap.inverse().containsKey(blockState)) { + return null; + } else { + String value = blockMap.inverse().get(blockState); + return Arrays.stream(value.split(":")).mapToInt(Integer::parseInt).toArray(); + } + } + + public static LegacyMapper getInstance() { + return INSTANCE; + } + + @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection", "unused"}) + private static class LegacyDataFile { + private Map blocks; + private Map items; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/state/SimpleState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/state/SimpleState.java index c34f95647..fb66705b5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/state/SimpleState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/state/SimpleState.java @@ -29,6 +29,7 @@ import javax.annotation.Nullable; public class SimpleState implements State { + private String name; private List values; /** @@ -37,9 +38,21 @@ public class SimpleState implements State { * @param values The values */ public SimpleState(List values) { + this.name = "Unknown"; this.values = values; } + /** + * Internal method for name setting post-deserialise. Do not use. + */ + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + @Override public List getValues() { return Collections.unmodifiableList(values); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/state/State.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/state/State.java index ba3d94122..c6c2fc0c1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/state/State.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/state/State.java @@ -33,6 +33,13 @@ import javax.annotation.Nullable; */ public interface State { + /** + * Returns the name of this state. + * + * @return The state name + */ + String getName(); + /** * Return a list of available values for this state. * diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/blocks/BlockDataTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/blocks/BlockDataTest.java index 044b6a88b..1a44ddeb0 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/blocks/BlockDataTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/blocks/BlockDataTest.java @@ -61,80 +61,4 @@ public class BlockDataTest { } } } - - private static final TreeSet datasTemplate = new TreeSet(); - static { - for (int data = 0; data < 16; ++data) { - datasTemplate.add(data); - } - } - - @Test - public void testCycle() { - // Test monotony and continuity - for (int type = 0; type < 256; ++type) { - // Cloth isn't monotonous, and thus excluded. - if (type == BlockID.CLOTH - || type == BlockID.STAINED_CLAY - || type == BlockID.STAINED_GLASS - || type == BlockID.STAINED_GLASS_PANE - || type == BlockID.CARPET) { - continue; - } - - for (int data = 0; data < 16; ++data) { - final String message = type + "/" + data; - - final int cycled = BlockData.cycle(type, data, 1); - - // If the cycle goes back (including -1), everything is ok. - if (cycled <= data) { - continue; - } - - // If there's a gap in the cycle, there's a problem. - assertEquals(message, data + 1, cycled); - } - } - - // Test cyclicity forwards - testCycle(1); - - // ...and backwards - testCycle(-1); - } - - private static void testCycle(final int increment) { - // Iterate each block type and data value that wasn't part of a cycle yet. - for (int type = 0; type < 256; ++type) { - @SuppressWarnings("unchecked") - final TreeSet datas = (TreeSet) datasTemplate.clone(); - while (!datas.isEmpty()) { - final int start = datas.pollFirst(); - String message = type + "/" + start; - int current = start; - boolean first = true; - while (true) { - current = BlockData.cycle(type, current, increment); - - // If the cycle immediately goes to -1, everything is ok. - if (first && current == -1) break; - - first = false; - message += "->" + current; - - // If the cycle goes off limits (including -1), there's a problem. - assertTrue(message, current >= 0); - assertTrue(message, current < 16); - - // The cycle completes, everything is ok. - if (current == start) break; - - // Mark the current element as walked. - assertTrue(message, datas.remove(current)); - } - } - } - } - } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java index 713297e02..44142e551 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java @@ -37,14 +37,4 @@ public class ForgeItemRegistry implements ItemRegistry { return null; } } - - @Nullable - @Override - public BaseItem createFromId(int id) { - if (Item.REGISTRY.getObjectById(id) != null) { - return new BaseItem(id); - } else { - return null; - } - } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java index f971c3c78..80ff1e0e9 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java @@ -22,9 +22,8 @@ package com.sk89q.worldedit.sponge.config; import com.google.common.reflect.TypeToken; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.blocks.type.ItemTypes; import com.sk89q.worldedit.session.SessionManager; -import com.sk89q.worldedit.world.registry.BundledItemData; +import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.snapshot.SnapshotRepository; import ninja.leaping.configurate.ConfigurationOptions; import ninja.leaping.configurate.commented.CommentedConfigurationNode; @@ -61,7 +60,7 @@ public class ConfigurateConfiguration extends LocalConfiguration { profile = node.getNode("debug").getBoolean(profile); wandItem = node.getNode("wand-item").getString(wandItem); try { - wandItem = BundledItemData.getInstance().fromLegacyId(Integer.parseInt(wandItem)); + wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).getId(); } catch (Throwable e) { } @@ -105,7 +104,7 @@ public class ConfigurateConfiguration extends LocalConfiguration { navigationWand = node.getNode("navigation-wand", "item").getString(navigationWand); try { - navigationWand = BundledItemData.getInstance().fromLegacyId(Integer.parseInt(navigationWand)); + navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).getId(); } catch (Throwable e) { } navigationWandMaxDistance = node.getNode("navigation-wand", "max-distance").getInt(navigationWandMaxDistance);