diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitUtil.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitUtil.java index eb50b50ca..07d5f81d7 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitUtil.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitUtil.java @@ -28,7 +28,6 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.blocks.ItemID; -import com.sk89q.worldedit.blocks.SkullBlock; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.util.Location; import org.bukkit.DyeColor; @@ -136,9 +135,6 @@ public final class BukkitUtil { } break; - case ItemID.HEAD: - return new SkullBlock(0, (byte) itemStack.getDurability()); - default: final BaseBlock baseBlock = BlockType.getBlockForItem(typeId, itemStack.getDurability()); if (baseBlock != null) { diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java index a876a1c1f..4fc2070d0 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java @@ -25,7 +25,7 @@ import com.sk89q.jnbt.NBTUtils; import com.sk89q.jnbt.ShortTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.blocks.metadata.MobType; +import com.sk89q.worldedit.blocks.type.BlockState; import com.sk89q.worldedit.world.storage.InvalidFormatException; import java.util.HashMap; @@ -49,41 +49,23 @@ public class MobSpawnerBlock extends BaseBlock implements TileEntityBlock { private short maxNearbyEntities; private short requiredPlayerRange; - /** - * Construct the mob spawner block with a pig as the mob type. - */ - public MobSpawnerBlock() { - super(BlockID.MOB_SPAWNER); - this.mobType = MobType.PIG.getName(); - } - - /** - * Construct the mob spawner block with a given mob type. - * - * @param mobType mob type - */ - public MobSpawnerBlock(String mobType) { - super(BlockID.MOB_SPAWNER); - this.mobType = mobType; - } - /** * Construct the mob spawner block with a specified data value. * - * @param data data value + * @param blockState The block state */ - public MobSpawnerBlock(int data) { - super(BlockID.MOB_SPAWNER, data); + public MobSpawnerBlock(BlockState blockState) { + super(blockState); } /** * Construct the mob spawner block. * - * @param data data value + * @param blockState The block state * @param mobType mob type */ - public MobSpawnerBlock(int data, String mobType) { - super(BlockID.MOB_SPAWNER, data); + public MobSpawnerBlock(BlockState blockState, String mobType) { + super(blockState); this.mobType = mobType; } diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java index 78f78419e..8d71a662f 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.blocks; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.blocks.type.BlockState; import com.sk89q.worldedit.util.gson.GsonUtil; import java.util.HashMap; @@ -36,26 +37,14 @@ public class SignBlock extends BaseBlock implements TileEntityBlock { private static String EMPTY = "{\"text\":\"\"}"; - /** - * Construct the sign without text. - * - * @param type type ID - * @param data data value (orientation) - */ - public SignBlock(int type, int data) { - super(type, data); - this.text = new String[] { EMPTY, EMPTY, EMPTY, EMPTY }; - } - /** * Construct the sign with text. * - * @param type type ID - * @param data data value (orientation) + * @param blockState The block state * @param text lines of text */ - public SignBlock(int type, int data, String[] text) { - super(type, data); + public SignBlock(BlockState blockState, String[] text) { + super(blockState); if (text == null) { this.text = new String[] { EMPTY, EMPTY, EMPTY, EMPTY }; return; diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java index 6f7024c28..fb651f9ab 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java @@ -19,10 +19,10 @@ package com.sk89q.worldedit.blocks; -import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.blocks.type.BlockState; import java.util.HashMap; import java.util.Map; @@ -33,60 +33,25 @@ import java.util.Map; public class SkullBlock extends BaseBlock implements TileEntityBlock { private String owner = ""; // notchian - private byte skullType; // stored here for block, in damage value for item - private byte rot; // only matters if block data == 0x1 (on floor) /** * Construct the skull block with a default type of skelton. - * @param data data value to set, controls placement + * @param state BlockState to set */ - public SkullBlock(int data) { - this(data, (byte) 0); - } - - /** - * Construct the skull block with a given type. - * 0 - skeleton - * 1 - wither skelly - * 2 - zombie - * 3 - human - * 4 - creeper - * @param data data value to set, controls placement - * @param type type of skull - */ - public SkullBlock(int data, byte type) { - this(data, type, (byte) 0); - } - - /** - * Construct the skull block with a given type and rotation. - * @param data data value to set, controls placement - * @param type type of skull - * @param rot rotation (if on floor) - */ - public SkullBlock(int data, byte type, byte rot) { - super(BlockID.HEAD, data); - if (type < (byte) 0 || type > (byte) 4) { - this.skullType = (byte) 0; - } else { - this.skullType = type; - } - this.rot = rot; + public SkullBlock(BlockState state) { + super(state); this.owner = ""; } /** * Construct the skull block with a given rotation and owner. * The type is assumed to be player unless owner is null or empty. - * @param data data value to set, controls placement - * @param rot rotation of skull + * @param blockState BlockState to set * @param owner name of player */ - public SkullBlock(int data, byte rot, String owner) { - super(BlockID.HEAD, data); - this.rot = rot; + public SkullBlock(BlockState blockState, String owner) { + super(blockState); this.setOwner(owner); - if (owner == null || owner.isEmpty()) this.skullType = (byte) 0; } /** @@ -100,7 +65,6 @@ public class SkullBlock extends BaseBlock implements TileEntityBlock { if (owner.length() > 16 || owner.isEmpty()) this.owner = ""; else this.owner = owner; } - if (!this.owner.isEmpty()) this.skullType = (byte) 3; } /** @@ -111,38 +75,6 @@ public class SkullBlock extends BaseBlock implements TileEntityBlock { return owner; } - /** - * Get the type of skull. - * @return the skullType - */ - public byte getSkullType() { - return skullType; - } - - /** - * Set the type of skull; - * @param skullType the skullType to set - */ - public void setSkullType(byte skullType) { - this.skullType = skullType; - } - - /** - * Get rotation of skull. This only means anything if the block data is 1. - * @return the rotation - */ - public byte getRot() { - return rot; - } - - /** - * Set the rotation of skull. - * @param rot the rotation to set - */ - public void setRot(byte rot) { - this.rot = rot; - } - @Override public boolean hasNbtData() { return true; @@ -155,11 +87,9 @@ public class SkullBlock extends BaseBlock implements TileEntityBlock { @Override public CompoundTag getNbtData() { - Map values = new HashMap(); - values.put("SkullType", new ByteTag(skullType)); + Map values = new HashMap<>(); if (owner == null) owner = ""; - values.put("ExtraType", new StringTag( owner)); - values.put("Rot", new ByteTag(rot)); + values.put("ExtraType", new StringTag(owner)); return new CompoundTag(values); } @@ -178,17 +108,9 @@ public class SkullBlock extends BaseBlock implements TileEntityBlock { throw new RuntimeException("'Skull' tile entity expected"); } - t = values.get("SkullType"); - if (t instanceof ByteTag) { - skullType = ((ByteTag) t).getValue(); - } t = values.get("ExtraType"); - if (t != null && t instanceof StringTag) { + if (t instanceof StringTag) { owner = ((StringTag) t).getValue(); } - t = values.get("Rot"); - if (t instanceof ByteTag) { - rot = ((ByteTag) t).getValue(); - } } } 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 2846de359..5c1644280 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 @@ -23,6 +23,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.CuboidClipboard.FlipDirection; +import com.sk89q.worldedit.blocks.type.BlockState; import com.sk89q.worldedit.blocks.type.BlockType; import com.sk89q.worldedit.blocks.type.BlockTypes; import com.sk89q.worldedit.function.mask.Mask; @@ -76,6 +77,11 @@ public class BaseBlock implements TileEntityBlock { this.states = new HashMap<>(); } + public BaseBlock(BlockState blockState) { + this.blockType = blockState.getBlockType(); + this.states = blockState.getStates(); + } + /** * Construct a block with the given type and default data. * 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 306f15d27..420dc9a99 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 @@ -24,36 +24,52 @@ import com.google.common.collect.HashBasedTable; import com.google.common.collect.Maps; import com.google.common.collect.Table; import com.sk89q.worldedit.world.registry.state.State; -import com.sk89q.worldedit.world.registry.state.value.SimpleStateValue; +import com.sk89q.worldedit.world.registry.state.value.StateValue; +import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * An immutable class that represents the state a block can be in. */ +@SuppressWarnings("unchecked") public class BlockState { private final BlockType blockType; - private final Map, SimpleStateValue> values; + private final Map values; + private final boolean fuzzy; // Neighbouring state table. - private Table, SimpleStateValue, BlockState> states; + private Table states; BlockState(BlockType blockType) { this.blockType = blockType; this.values = new HashMap<>(); + this.fuzzy = false; } - public void populate(Map, SimpleStateValue>, BlockState> stateMap) { - final Table, SimpleStateValue, BlockState> states = HashBasedTable.create(); + /** + * Creates a fuzzy BlockState. This can be used for partial matching. + * + * @param blockType The block type + * @param values The block state values + */ + public BlockState(BlockType blockType, Map values) { + this.blockType = blockType; + this.values = values; + this.fuzzy = true; + } - for(final Map.Entry, SimpleStateValue> entry : this.values.entrySet()) { - final State state = entry.getKey(); + public void populate(Map, BlockState> stateMap) { + final Table states = HashBasedTable.create(); - state.getValues().forEach(value -> { + for(final Map.Entry entry : this.values.entrySet()) { + final State state = entry.getKey(); + + state.getValues().stream().forEach(value -> { if(value != entry.getValue()) { - states.put(state, value, stateMap.get(this.withValue(state, value))); + states.put(state, (StateValue) value, stateMap.get(this.withValue(state, (StateValue) value))); } }); } @@ -61,8 +77,8 @@ public class BlockState { this.states = states.isEmpty() ? states : ArrayTable.create(states); } - private Map, SimpleStateValue> withValue(final State property, final SimpleStateValue value) { - final Map, SimpleStateValue> values = Maps.newHashMap(this.values); + private Map withValue(final State property, final StateValue value) { + final Map values = Maps.newHashMap(this.values); values.put(property, value); return values; } @@ -83,9 +99,13 @@ public class BlockState { * @param value The value * @return The modified state, or same if could not be applied */ - public BlockState with(State state, SimpleStateValue value) { - BlockState result = states.get(state, value); - return result == null ? this : result; + public BlockState with(State state, StateValue value) { + if (fuzzy) { + return setState(state, value); + } else { + BlockState result = states.get(state, value); + return result == null ? this : result; + } } /** @@ -94,10 +114,19 @@ public class BlockState { * @param state The state * @return The value */ - public SimpleStateValue getState(State state) { + public StateValue getState(State state) { return this.values.get(state); } + /** + * Gets an immutable collection of the states. + * + * @return The states + */ + public Map getStates() { + return Collections.unmodifiableMap(this.values); + } + /** * Internal method used for creating the initial BlockState. * @@ -107,7 +136,7 @@ public class BlockState { * @param value The value * @return The blockstate, for chaining */ - BlockState setState(State state, SimpleStateValue value) { + BlockState setState(State state, StateValue value) { this.values.put(state, value); return this; } 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 2147d05e0..cb49a0795 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 @@ -19,9 +19,19 @@ package com.sk89q.worldedit.extension.factory; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.*; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.NotABlockException; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.MobSpawnerBlock; +import com.sk89q.worldedit.blocks.SignBlock; +import com.sk89q.worldedit.blocks.SkullBlock; import com.sk89q.worldedit.blocks.metadata.MobType; +import com.sk89q.worldedit.blocks.type.BlockState; +import com.sk89q.worldedit.blocks.type.BlockType; +import com.sk89q.worldedit.blocks.type.BlockTypes; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.input.InputParseException; @@ -32,6 +42,14 @@ import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.registry.BundledBlockData; +import com.sk89q.worldedit.world.registry.state.State; +import com.sk89q.worldedit.world.registry.state.value.StateValue; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Parses block input strings. @@ -59,9 +77,6 @@ class DefaultBlockParser extends InputParser { @Override public BaseBlock parseFromInput(String input, ParserContext context) throws InputParseException { - // TODO: Rewrite this entire method to use BaseBlocks and ignore - // BlockType, as well as to properly handle mod:name IDs - String originalInput = input; input = input.replace("_", " "); input = input.replace(";", "|"); @@ -84,51 +99,44 @@ class DefaultBlockParser extends InputParser { } } + private static Pattern blockStatePattern = Pattern.compile("([a-z:]+)(?:\\[([a-zA-Z0-9=, ]+)\\])?", Pattern.CASE_INSENSITIVE); + private static String[] EMPTY_STRING_ARRAY = new String[]{}; + private BaseBlock parseLogic(String input, ParserContext context) throws InputParseException, NoMatchException, DisallowedUsageException { BlockType blockType; + Map blockStates = new HashMap<>(); String[] blockAndExtraData = input.split("\\|"); - String[] blockLocator = blockAndExtraData[0].split(":", 3); - String[] typeAndData; - switch (blockLocator.length) { - case 3: - typeAndData = new String[] { - blockLocator[0] + ":" + blockLocator[1], - blockLocator[2] }; - break; - default: - typeAndData = blockLocator; + Matcher matcher = blockStatePattern.matcher(blockAndExtraData[0]); + if (matcher.groupCount() < 1 || matcher.groupCount() > 2) { + throw new InputParseException("Invalid format"); + } + String typeString = matcher.group(1); + String[] stateProperties = EMPTY_STRING_ARRAY; + if (matcher.groupCount() == 2) { + stateProperties = matcher.group(2).split(","); } - String testId = typeAndData[0]; - int blockId = -1; - - int data = -1; - - boolean parseDataValue = true; - - if ("hand".equalsIgnoreCase(testId)) { + if ("hand".equalsIgnoreCase(typeString)) { // Get the block type from the item in the user's hand. final BaseBlock blockInHand = getBlockInHand(context.requireActor(), HandSide.MAIN_HAND); if (blockInHand.getClass() != BaseBlock.class) { return blockInHand; } - blockId = blockInHand.getId(); - blockType = BlockType.fromID(blockId); - data = blockInHand.getData(); - } else if ("offhand".equalsIgnoreCase(testId)) { + blockType = blockInHand.getType(); + blockStates = blockInHand.getStates(); + } else if ("offhand".equalsIgnoreCase(typeString)) { // Get the block type from the item in the user's off hand. final BaseBlock blockInHand = getBlockInHand(context.requireActor(), HandSide.OFF_HAND); if (blockInHand.getClass() != BaseBlock.class) { return blockInHand; } - blockId = blockInHand.getId(); - blockType = BlockType.fromID(blockId); - data = blockInHand.getData(); - } else if ("pos1".equalsIgnoreCase(testId)) { + blockType = blockInHand.getType(); + blockStates = blockInHand.getStates(); + } else if ("pos1".equalsIgnoreCase(typeString)) { // Get the block type from the "primary position" final World world = context.requireWorld(); final BlockVector primaryPosition; @@ -142,135 +150,49 @@ class DefaultBlockParser extends InputParser { return blockInHand; } - blockId = blockInHand.getId(); - blockType = BlockType.fromID(blockId); - data = blockInHand.getData(); + blockType = blockInHand.getType(); + blockStates = blockInHand.getStates(); } else { - // Attempt to parse the item ID or otherwise resolve an item/block - // name to its numeric ID - try { - blockId = Integer.parseInt(testId); - blockType = BlockType.fromID(blockId); - } catch (NumberFormatException e) { - blockType = BlockType.lookup(testId); - if (blockType == null) { - int t = worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).resolveItem(testId); - if (t >= 0) { - blockType = BlockType.fromID(t); // Could be null - blockId = t; - } else if (blockLocator.length == 2) { // Block IDs in MC 1.7 and above use mod:name - t = worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).resolveItem(blockAndExtraData[0]); - if (t >= 0) { - blockType = BlockType.fromID(t); // Could be null - blockId = t; - typeAndData = new String[] { blockAndExtraData[0] }; - testId = blockAndExtraData[0]; - } - } - } - } + // Attempt to lookup a block from ID or name. + blockType = BlockTypes.getBlockType(typeString); - if (blockId == -1 && blockType == null) { - // Maybe it's a cloth - ClothColor col = ClothColor.lookup(testId); - if (col == null) { - throw new NoMatchException("Can't figure out what block '" + input + "' refers to"); - } - - blockType = BlockType.CLOTH; - data = col.getID(); - - // Prevent overriding the data value - parseDataValue = false; - } - - // Read block ID - if (blockId == -1) { - blockId = blockType.getID(); - } - - if (!context.requireWorld().isValidBlockType(blockId)) { + if (blockType == null) { throw new NoMatchException("Does not match a valid block type: '" + input + "'"); } } - if (!context.isPreferringWildcard() && data == -1) { - // No wildcards allowed => eliminate them. - data = 0; + BlockState state; + + if (!context.isPreferringWildcard()) { + // No wildcards allowed => eliminate them. (Start with default state) + state = blockType.getDefaultState(); + } else { + state = new BlockState(blockType, blockStates); } - if (parseDataValue) { // Block data not yet detected + if (stateProperties.length > 0) { // Block data not yet detected // Parse the block data (optional) - try { - if (typeAndData.length > 1 && !typeAndData[1].isEmpty()) { - data = Integer.parseInt(typeAndData[1]); - } + for (String parseableData : stateProperties) { + try { + String[] parts = parseableData.split("="); + if (parts.length != 2) { + throw new NoMatchException("Bad state format in " + parseableData); + } - if (data > 15) { - throw new NoMatchException("Invalid data value '" + typeAndData[1] + "'"); - } + 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]); + } - if (data < 0 && (context.isRestricted() || data != -1)) { - data = 0; - } - } catch (NumberFormatException e) { - if (blockType == null) { - throw new NoMatchException("Unknown data value '" + typeAndData[1] + "'"); - } - - switch (blockType) { - case CLOTH: - case STAINED_CLAY: - case CARPET: - ClothColor col = ClothColor.lookup(typeAndData[1]); - if (col == null) { - throw new NoMatchException("Unknown wool color '" + typeAndData[1] + "'"); - } - - data = col.getID(); - break; - - case STEP: - case DOUBLE_STEP: - BlockType dataType = BlockType.lookup(typeAndData[1]); - - if (dataType == null) { - throw new NoMatchException("Unknown step type '" + typeAndData[1] + "'"); - } - - switch (dataType) { - case STONE: - data = 0; - break; - case SANDSTONE: - data = 1; - break; - case WOOD: - data = 2; - break; - case COBBLESTONE: - data = 3; - break; - case BRICK: - data = 4; - break; - case STONE_BRICK: - data = 5; - break; - case NETHER_BRICK: - data = 6; - break; - case QUARTZ_BLOCK: - data = 7; - break; - - default: - throw new NoMatchException("Invalid step type '" + typeAndData[1] + "'"); - } - break; - - default: - throw new NoMatchException("Unknown data value '" + typeAndData[1] + "'"); + state = state.with(stateKey, value); + } catch (NoMatchException e) { + throw e; // Pass-through + } catch (Exception e) { + throw new NoMatchException("Unknown state '" + parseableData + "'"); } } } @@ -278,94 +200,46 @@ class DefaultBlockParser extends InputParser { // Check if the item is allowed Actor actor = context.requireActor(); if (context.isRestricted() && actor != null && !actor.hasPermission("worldedit.anyblock") - && worldEdit.getConfiguration().disallowedBlocks.contains(blockId)) { + && worldEdit.getConfiguration().disallowedBlocks.contains(blockType.getId())) { throw new DisallowedUsageException("You are not allowed to use '" + input + "'"); } - if (blockType == null) { - return new BaseBlock(blockId, data); - } - - switch (blockType) { - case SIGN_POST: - case WALL_SIGN: - // Allow special sign text syntax - String[] text = new String[4]; - text[0] = blockAndExtraData.length > 1 ? blockAndExtraData[1] : ""; - text[1] = blockAndExtraData.length > 2 ? blockAndExtraData[2] : ""; - text[2] = blockAndExtraData.length > 3 ? blockAndExtraData[3] : ""; - text[3] = blockAndExtraData.length > 4 ? blockAndExtraData[4] : ""; - return new SignBlock(blockType.getID(), data, text); - - case MOB_SPAWNER: - // Allow setting mob spawn type - if (blockAndExtraData.length > 1) { - String mobName = blockAndExtraData[1]; - for (MobType mobType : MobType.values()) { - if (mobType.getName().toLowerCase().equals(mobName.toLowerCase())) { - mobName = mobType.getName(); - break; - } - } - if (!worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).isValidMobType(mobName)) { - throw new NoMatchException("Unknown mob type '" + mobName + "'"); - } - return new MobSpawnerBlock(data, mobName); - } else { - return new MobSpawnerBlock(data, MobType.PIG.getName()); - } - - case NOTE_BLOCK: - // Allow setting note - if (blockAndExtraData.length <= 1) { - return new NoteBlock(data, (byte) 0); - } - - byte note = Byte.parseByte(blockAndExtraData[1]); - if (note < 0 || note > 24) { - throw new InputParseException("Out of range note value: '" + blockAndExtraData[1] + "'"); - } - - return new NoteBlock(data, note); - - case HEAD: - // allow setting type/player/rotation - if (blockAndExtraData.length <= 1) { - return new SkullBlock(data); - } - - byte rot = 0; - String type = ""; - try { - rot = Byte.parseByte(blockAndExtraData[1]); - } catch (NumberFormatException e) { - type = blockAndExtraData[1]; - if (blockAndExtraData.length > 2) { - try { - rot = Byte.parseByte(blockAndExtraData[2]); - } catch (NumberFormatException e2) { - throw new InputParseException("Second part of skull metadata should be a number."); - } + if (blockType == BlockTypes.SIGN || blockType == BlockTypes.WALL_SIGN) { + // Allow special sign text syntax + String[] text = new String[4]; + text[0] = blockAndExtraData.length > 1 ? blockAndExtraData[1] : ""; + text[1] = blockAndExtraData.length > 2 ? blockAndExtraData[2] : ""; + text[2] = blockAndExtraData.length > 3 ? blockAndExtraData[3] : ""; + text[3] = blockAndExtraData.length > 4 ? blockAndExtraData[4] : ""; + return new SignBlock(state, text); + } else if (blockType == BlockTypes.MOB_SPAWNER) { + // Allow setting mob spawn type + if (blockAndExtraData.length > 1) { + String mobName = blockAndExtraData[1]; + for (MobType mobType : MobType.values()) { + if (mobType.getName().toLowerCase().equals(mobName.toLowerCase())) { + mobName = mobType.getName(); + break; } } - byte skullType = 0; - // type is either the mob type or the player name - // sorry for the four minecraft accounts named "skeleton", "wither", "zombie", or "creeper" - if (!type.isEmpty()) { - if (type.equalsIgnoreCase("skeleton")) skullType = 0; - else if (type.equalsIgnoreCase("wither")) skullType = 1; - else if (type.equalsIgnoreCase("zombie")) skullType = 2; - else if (type.equalsIgnoreCase("creeper")) skullType = 4; - else skullType = 3; - } - if (skullType == 3) { - return new SkullBlock(data, rot, type.replace(" ", "_")); // valid MC usernames - } else { - return new SkullBlock(data, skullType, rot); + if (!worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).isValidMobType(mobName)) { + throw new NoMatchException("Unknown mob type '" + mobName + "'"); } + return new MobSpawnerBlock(state, mobName); + } else { + return new MobSpawnerBlock(state, MobType.PIG.getName()); + } + } else if (blockType == BlockTypes.PLAYER_HEAD || blockType == BlockTypes.PLAYER_WALL_HEAD) { + // allow setting type/player/rotation + if (blockAndExtraData.length <= 1) { + return new SkullBlock(state); + } - default: - return new BaseBlock(blockId, data); + String type = blockAndExtraData[1]; + + return new SkullBlock(state, type.replace(" ", "_")); // valid MC usernames + } else { + return new BaseBlock(state); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultItemParser.java index b837f6d4b..a4164421f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultItemParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultItemParser.java @@ -61,7 +61,7 @@ public class DefaultItemParser extends InputParser { try { damage = Short.parseShort(tokens[2]); } catch (NumberFormatException ignored) { - throw new InputParseException("Expected '" + tokens[2] + "' to be a metadata value but it's not a number"); + throw new InputParseException("Expected '" + tokens[2] + "' to be a damage value but it's not a number"); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java index 075d4236d..2eb77c97c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java @@ -28,18 +28,6 @@ import com.sk89q.worldedit.util.Location; */ public abstract class BlockBag { - /** - * Stores a block as if it was mined. - * - * @param id the type ID - * @throws BlockBagException on error - * @deprecated Use {@link BlockBag#storeDroppedBlock(int, int)} instead - */ - @Deprecated - public void storeDroppedBlock(int id) throws BlockBagException { - storeDroppedBlock(id, 0); - } - /** * Stores a block as if it was mined. * @@ -55,18 +43,6 @@ public abstract class BlockBag { storeItem(dropped); } - /** - * Sets a block as if it was placed by hand. - * - * @param id the type ID - * @throws BlockBagException on error - * @deprecated Use {@link #fetchPlacedBlock(int,int)} instead - */ - @Deprecated - public void fetchPlacedBlock(int id) throws BlockBagException { - fetchPlacedBlock(id, 0); - } - /** * Sets a block as if it was placed by hand. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index 229c3fa50..3e2b2e0ea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -62,6 +62,7 @@ public interface World extends Extent { * @param id the block ID * @return true if the block ID is a valid one */ + @Deprecated boolean isValidBlockType(int id); /** 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 99bd9cbb7..76acf9de6 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 @@ -196,7 +196,7 @@ public class BundledBlockData { private String unlocalizedName; public String localizedName; private List aliases; - private Map states = new HashMap<>(); + public Map states = new HashMap<>(); private SimpleBlockMaterial material = new SimpleBlockMaterial(); } 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 790e47bca..c34f95647 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 @@ -23,6 +23,9 @@ import com.sk89q.worldedit.world.registry.state.value.SimpleStateValue; import java.util.Collections; import java.util.List; +import java.util.Objects; + +import javax.annotation.Nullable; public class SimpleState implements State { @@ -41,4 +44,10 @@ public class SimpleState implements State { public List getValues() { return Collections.unmodifiableList(values); } + + @Nullable + @Override + public T getValueFor(String string) { + return values.stream().filter(value -> Objects.equals(value.getData(), string)).findFirst().orElse(null); + } } 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 49d77a1c0..ba3d94122 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 @@ -23,6 +23,8 @@ import com.sk89q.worldedit.world.registry.state.value.SimpleStateValue; import java.util.List; +import javax.annotation.Nullable; + /** * Describes a state property of a block. * @@ -38,4 +40,12 @@ public interface State { */ List getValues(); + /** + * Gets the value for the given string, or null. + * + * @param string The string + * @return The value, or null + */ + @Nullable + T getValueFor(String string); }