From 398943b9b05a432a89eb8f4d73a3f3009b4e44c6 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Wed, 6 Sep 2017 18:18:58 +1000 Subject: [PATCH] Add `slot#` pattern --- .../bukkit/BukkitPlayerBlockBag.java | 68 ++++++- core/src/main/java/com/boydti/fawe/Fawe.java | 2 + .../com/sk89q/worldedit/blocks/BaseItem.java | 140 ++++++++++++++ .../extension/factory/DefaultBlockParser.java | 172 ++++++++++-------- .../extent/inventory/SlottableBlockBag.java | 17 ++ 5 files changed, 324 insertions(+), 75 deletions(-) create mode 100644 core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java create mode 100644 core/src/main/java/com/sk89q/worldedit/extent/inventory/SlottableBlockBag.java diff --git a/bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java b/bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java index aa8d64b4..b6a06fa7 100644 --- a/bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java +++ b/bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java @@ -19,16 +19,23 @@ package com.sk89q.worldedit.bukkit; +import com.boydti.fawe.Fawe; +import com.boydti.fawe.bukkit.FaweBukkit; +import com.boydti.fawe.bukkit.util.ItemUtil; import com.sk89q.worldedit.WorldVector; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import com.sk89q.worldedit.extent.inventory.*; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.ItemType; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.extent.inventory.BlockBagException; +import com.sk89q.worldedit.extent.inventory.OutOfBlocksException; +import com.sk89q.worldedit.extent.inventory.OutOfSpaceException; +import com.sk89q.worldedit.extent.inventory.SlottableBlockBag; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; -public class BukkitPlayerBlockBag extends BlockBag { +public class BukkitPlayerBlockBag extends BlockBag implements SlottableBlockBag { private Player player; private ItemStack[] items; @@ -60,6 +67,59 @@ public class BukkitPlayerBlockBag extends BlockBag { return player; } + @Override + public BaseItem getItem(int slot) { + loadInventory(); + return toBaseItem(items[slot]); + } + + @Override + public void setItem(int slot, BaseItem block) { + loadInventory(); + items[slot] = toItemStack(block); + } + + @Override + public int getSelectedSlot() { + return player.getInventory().getHeldItemSlot(); + } + + private BaseItem toBaseItem(ItemStack item) { + if (item == null) return new BaseItemStack(0, 0); + int id = item.getTypeId(); + short data; + if (id < 256) { + data = item.getData().getData(); + } else { + data = item.getDurability(); + } + BaseItemStack baseItem = new BaseItemStack(id, item.getAmount(), data); + ItemUtil itemUtil = Fawe.imp().getItemUtil(); + if (itemUtil != null && item.hasItemMeta()) { + baseItem.setNbtData(itemUtil.getNBT(item)); + } + return baseItem; + } + + private ItemStack toItemStack(BaseItem item) { + if (item == null) return null; + final int id = item.getType(); + final int damage = item.getData(); + int amount = (item instanceof BaseItemStack) ? ((BaseItemStack) item).getAmount() : 1; + ItemStack bukkitItem; + if (id < 256) { + bukkitItem = new ItemStack(id, amount, (short) 0, (byte) damage); + } else { + bukkitItem = new ItemStack(id, amount, (short) damage); + } + ItemUtil itemUtil = Fawe.imp().getItemUtil(); + if (itemUtil != null && item.hasNBTData()) { + bukkitItem = itemUtil.setNBT(bukkitItem, item.getNbtData()); + } + return bukkitItem; + } + + @Override public void fetchItem(BaseItem item) throws BlockBagException { final int id = item.getType(); diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index c55a8e85..fd0a01ce 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BlockData; import com.sk89q.worldedit.command.BiomeCommands; import com.sk89q.worldedit.command.BrushCommands; @@ -573,6 +574,7 @@ public class Fawe { Vector2D.inject(); // Optimizations // Block BaseBlock.inject(); // Optimizations + BaseItem.inject(); // Biome BaseBiome.inject(); // Features // Pattern diff --git a/core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java b/core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java new file mode 100644 index 00000000..8fb6987f --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java @@ -0,0 +1,140 @@ +/* + * 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.blocks; + +import com.sk89q.jnbt.CompoundTag; +import java.util.HashMap; +import java.util.Map; + +/** + * Represents an item, without an amount value. See {@link BaseItemStack} + * for an instance with stack amount information. + * + *

This class may be removed in the future.

+ */ +public class BaseItem { + + private int id; + private short data; + private CompoundTag nbt; + private final Map enchantments = new HashMap(); + + /** + * Construct the object. + * + * @param id ID of the item + */ + public BaseItem(int id) { + this.id = id; + this.data = 0; + } + + /** + * Construct the object. + * + * @param id ID of the item + * @param data data value of the item + */ + public BaseItem(int id, short data) { + this.id = id; + this.data = data; + } + + /** + * Get the type of item. + * + * @return the id + */ + public int getType() { + return id; + } + + /** + * Get the type of item. + * + * @param id the id to set + */ + public void setType(int id) { + this.id = id; + } + + /** + * Get the damage value. + * + * @return the damage + */ + @Deprecated + public short getDamage() { + return data; + } + + /** + * Get the data value. + * + * @return the data + */ + public short getData() { + return data; + } + + /** + * Set the data value. + * + * @param data the damage to set + */ + @Deprecated + public void setDamage(short data) { + this.data = data; + } + + /** + * Set the data value. + * + * @param data the damage to set + */ + public void setData(short data) { + this.data = data; + } + + public boolean hasNBTData() { + return nbt != null; + } + + public CompoundTag getNbtData() { + return nbt; + } + + public void setNbtData(CompoundTag nbt) { + this.nbt = nbt; + } + + /** + * Get the map of enchantments. + * + * @return map of enchantments + */ + public Map getEnchantments() { + return enchantments; + } + + public static Class inject() { + return BaseItem.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java b/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java index 19396dba..1961fd76 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java @@ -31,6 +31,7 @@ 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.BaseItem; import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.blocks.ClothColor; import com.sk89q.worldedit.blocks.MobSpawnerBlock; @@ -44,6 +45,8 @@ import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.extent.inventory.SlottableBlockBag; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.BundledBlockData; @@ -132,93 +135,120 @@ public class DefaultBlockParser extends InputParser { CompoundTag nbt = null; boolean parseDataValue = true; - - if ("hand".equalsIgnoreCase(testId)) { - // Get the block type from the item in the user's hand. - final BaseBlock blockInHand = getBlockInHand(context.requireActor()); - blockId = blockInHand.getId(); - blockType = BlockType.fromID(blockId); - data = blockInHand.getData(); - nbt = blockInHand.getNbtData(); - } else if ("pos1".equalsIgnoreCase(testId)) { - // Get the block type from the "primary position" - final World world = context.requireWorld(); - final BlockVector primaryPosition; - try { - primaryPosition = context.requireSession().getRegionSelector(world).getPrimaryPosition(); - } catch (IncompleteRegionException e) { - throw new InputParseException("Your selection is not complete."); - } - final BaseBlock blockInHand = world.getBlock(primaryPosition); - blockId = blockInHand.getId(); - blockType = BlockType.fromID(blockId); - data = blockInHand.getData(); - nbt = blockInHand.getNbtData(); - } else { - // Attempt to parse the item ID or otherwise resolve an item/block - // name to its numeric ID - if (MathMan.isInteger(testId)) { - blockId = Integer.parseInt(testId); + switch (testId.substring(0, Math.min(testId.length(), 4))) { + case "pos1": { + // Get the block type from the "primary position" + final World world = context.requireWorld(); + final BlockVector primaryPosition; + try { + primaryPosition = context.requireSession().getRegionSelector(world).getPrimaryPosition(); + } catch (IncompleteRegionException e) { + throw new InputParseException("Your selection is not complete."); + } + final BaseBlock block = world.getBlock(primaryPosition); + blockId = block.getId(); blockType = BlockType.fromID(blockId); - } else { - BundledBlockData.BlockEntry block = BundledBlockData.getInstance().findById(testId); - if (block == null) { - BaseBlock baseBlock = BundledBlockData.getInstance().findByState(testId); - if (baseBlock == null) { - blockType = BlockType.lookup(testId); - if (blockType == null) { - int t = worldEdit.getServer().resolveItem(testId); - if (t == 0 && !testId.contains("air")) { - throw new NoMatchException("Invalid block '" + input + "'."); - } - 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.getServer().resolveItem(blockAndExtraData[0]); + data = block.getData(); + nbt = block.getNbtData(); + break; + } + case "hand": { + BaseBlock blockInHand = getBlockInHand(context.requireActor()); + blockId = blockInHand.getId(); + blockType = BlockType.fromID(blockId); + data = blockInHand.getData(); + nbt = blockInHand.getNbtData(); + break; + } + case "slot": { + try { + int slot = Integer.parseInt(testId.substring(4)) - 1; + Actor actor = context.requireActor(); + if (!(actor instanceof Player)) { + throw new InputParseException("The user is not a player!"); + } + Player player = (Player) actor; + BlockBag bag = player.getInventoryBlockBag(); + if (bag == null || !(bag instanceof SlottableBlockBag)) { + throw new InputParseException("Unsupported!"); + } + SlottableBlockBag slottable = (SlottableBlockBag) bag; + BaseItem item = slottable.getItem(slot); + + blockId = item.getType(); + if (!player.getWorld().isValidBlockType(blockId)) { + throw new InputParseException("You're not holding a block!"); + } + blockType = BlockType.fromID(blockId); + data = item.getData(); + nbt = item.getNbtData(); + break; + } catch (NumberFormatException ignore) {} + } + default: { + // Attempt to parse the item ID or otherwise resolve an item/block + // name to its numeric ID + if (MathMan.isInteger(testId)) { + blockId = Integer.parseInt(testId); + blockType = BlockType.fromID(blockId); + } else { + BundledBlockData.BlockEntry block = BundledBlockData.getInstance().findById(testId); + if (block == null) { + BaseBlock baseBlock = BundledBlockData.getInstance().findByState(testId); + if (baseBlock == null) { + blockType = BlockType.lookup(testId); + if (blockType == null) { + int t = worldEdit.getServer().resolveItem(testId); + if (t == 0 && !testId.contains("air")) { + throw new NoMatchException("Invalid block '" + input + "'."); + } if (t >= 0) { blockType = BlockType.fromID(t); // Could be null blockId = t; - typeAndData = new String[]{blockAndExtraData[0]}; - testId = blockAndExtraData[0]; + } else if (blockLocator.length == 2) { // Block IDs in MC 1.7 and above use mod:name + t = worldEdit.getServer().resolveItem(blockAndExtraData[0]); + if (t >= 0) { + blockType = BlockType.fromID(t); // Could be null + blockId = t; + typeAndData = new String[]{blockAndExtraData[0]}; + testId = blockAndExtraData[0]; + } } } + } else { + blockId = baseBlock.getId(); + blockType = BlockType.fromID(blockId); + data = baseBlock.getData(); } } else { - blockId = baseBlock.getId(); + blockId = block.legacyId; blockType = BlockType.fromID(blockId); - data = baseBlock.getData(); } - } else { - blockId = block.legacyId; - blockType = BlockType.fromID(blockId); } - } - 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"); + 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; } - blockType = BlockType.CLOTH; - data = col.getID(); + // Read block ID + if (blockId == -1) { + blockId = blockType.getID(); + } - // Prevent overriding the data value - parseDataValue = false; - } - - // Read block ID - if (blockId == -1) { - blockId = blockType.getID(); - } - - if (!context.requireWorld().isValidBlockType(blockId)) { - throw new NoMatchException("Does not match a valid block type: '" + input + "'"); + if (!context.requireWorld().isValidBlockType(blockId)) { + throw new NoMatchException("Does not match a valid block type: '" + input + "'"); + } } } - - if (!context.isPreferringWildcard() && data == -1) { // No wildcards allowed => eliminate them. data = 0; diff --git a/core/src/main/java/com/sk89q/worldedit/extent/inventory/SlottableBlockBag.java b/core/src/main/java/com/sk89q/worldedit/extent/inventory/SlottableBlockBag.java new file mode 100644 index 00000000..8bb2f3ec --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/extent/inventory/SlottableBlockBag.java @@ -0,0 +1,17 @@ +package com.sk89q.worldedit.extent.inventory; + +import com.sk89q.worldedit.blocks.BaseItem; + +public interface SlottableBlockBag { + BaseItem getItem(int slot); + + void setItem(int slot, BaseItem block); + + default int size() { + return 36; + } + + default int getSelectedSlot() { + return -1; + } +}