/*
* CommandBook
* Copyright (C) 2011 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.commandbook;
import com.google.common.collect.Lists;
import com.sk89q.commandbook.commands.PaginatedResult;
import com.sk89q.commandbook.util.ChatUtil;
import com.sk89q.commandbook.util.InputUtil;
import com.sk89q.commandbook.util.entity.player.PlayerUtil;
import com.sk89q.commandbook.util.item.ItemUtil;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.blocks.ItemType;
import com.zachsthings.libcomponents.ComponentInformation;
import com.zachsthings.libcomponents.bukkit.BukkitComponent;
import com.zachsthings.libcomponents.config.ConfigurationBase;
import com.zachsthings.libcomponents.config.Setting;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.*;
import static com.sk89q.commandbook.util.item.InventoryUtil.giveItem;
import static com.sk89q.commandbook.util.item.InventoryUtil.takeItem;
@ComponentInformation(friendlyName = "Inventory",
desc = "Inventory-related commands, such as /give and /clear, are handled in this component.")
public class InventoryComponent extends BukkitComponent {
protected LocalConfiguration config;
@Override
public void enable() {
config = configure(new LocalConfiguration());
registerCommands(Commands.class);
}
@Override
public void reload() {
super.reload();
configure(config);
}
private static class LocalConfiguration extends ConfigurationBase {
@Setting("item-permissions-only") public boolean useItemPermissionsOnly;
@Setting("allowed-items") public Set<Integer> allowedItems = Collections.emptySet();
@Setting("disllowed-items") public Set<Integer> disallowedItems = Collections.emptySet();
@Setting("default-item-stack-size") public int defaultItemStackSize = 1;
}
// -- Helper methods
/**
* Checks to see if a user can use an item.
*
* @param sender
* @param id
* @throws CommandException
*/
public void checkAllowedItem(CommandSender sender, int id, int damage)
throws CommandException {
if (Material.getMaterial(id) == null || id == 0) {
throw new CommandException("Non-existent item specified.");
}
// Check if the user has an override
if (CommandBook.inst().hasPermission(sender, "commandbook.override.any-item")) {
return;
}
boolean hasPermissions = CommandBook.inst().hasPermission(sender, "commandbook.items." + id)
|| CommandBook.inst().hasPermission(sender, "commandbook.items." + id + "." + damage);
// Also check the permissions system
if (hasPermissions) {
return;
}
if (config.useItemPermissionsOnly) {
throw new CommandException("That item is not allowed.");
}
if (config.allowedItems.size() > 0) {
if (!config.allowedItems.contains(id)) {
throw new CommandException("That item is not allowed.");
}
}
if (config.disallowedItems.contains((id))) {
throw new CommandException("That item is disallowed.");
}
}
private ItemStack matchItem(String name) throws CommandException {
return ItemUtil.getCommandItem(name);
}
public class Commands {
@Command(aliases = {"item", "i"},
usage = "[target] <item[:data][|enchantment:level]> [amount]", desc = "Give an item",
flags = "do", min = 1, max = 3)
@CommandPermissions({"commandbook.give"})
public void item(CommandContext args, CommandSender sender) throws CommandException {
ItemStack item = null;
int amt = config.defaultItemStackSize;
Collection<Player> targets = null;
// How this command handles parameters depends on how many there
// are, so the following code splits the incoming input
// into three different possibilities
// One argument: Just the item type and amount 1
if (args.argsLength() == 1) {
item = matchItem(args.getString(0));
targets = Lists.newArrayList(PlayerUtil.checkPlayer(sender));
// Two arguments: Item type and amount
} else if (args.argsLength() == 2) {
item = matchItem(args.getString(0));
amt = args.getInteger(1);
targets = Lists.newArrayList(PlayerUtil.checkPlayer(sender));
// Three arguments: Player, item type, and item amount
} else if (args.argsLength() == 3) {
item = matchItem(args.getString(1));
amt = args.getInteger(2);
targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
// Make sure that this player has permission to give items to other
// players!
for (Player player : targets) {
if (player != sender) {
CommandBook.inst().checkPermission(sender, "commandbook.give.other");
}
}
}
if (item == null) {
throw new CommandException("Something went wrong parsing the item info!");
}
giveItem(sender, item, amt, targets, InventoryComponent.this, args.hasFlag('d'), args.hasFlag('o'));
}
@Command(aliases = {"give"},
usage = "[-d] <target> <item[:data]> [amount]", desc = "Give an item",
flags = "do", min = 2, max = 3)
@CommandPermissions({"commandbook.give", "commandbook.give.other"})
public void give(CommandContext args, CommandSender sender) throws CommandException {
ItemStack item = null;
int amt = config.defaultItemStackSize;
Collection<Player> targets = null;
// How this command handles parameters depends on how many there
// are, so the following code splits the incoming input
// into three different possibilities
// Two arguments: Player, item type
if (args.argsLength() == 2) {
targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
item = matchItem(args.getString(1));
// Three arguments: Player, item type, and item amount
} else if (args.argsLength() == 3) {
targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
item = matchItem(args.getString(1));
amt = args.getInteger(2);
}
for (Player target : targets) {
if (target != sender) {
CommandBook.inst().checkPermission(sender, "commandbook.give.other");
} else {
CommandBook.inst().checkPermission(sender, "commandbook.give");
}
}
if (item == null) {
throw new CommandException("Something went wrong parsing the item info!");
}
giveItem(sender, item, amt, targets, InventoryComponent.this, args.hasFlag('d'), args.hasFlag('o'));
}
@Command(aliases = {"clear"},
usage = "[target]", desc = "Clear your inventory",
flags = "as", min = 0, max = 1)
@CommandPermissions({"commandbook.clear"})
public void clear(CommandContext args, CommandSender sender) throws CommandException {
Iterable<Player> targets;
boolean clearAll = args.hasFlag('a');
boolean clearSingle = args.hasFlag('s');
boolean included = false;
if (args.argsLength() == 0) {
targets = Lists.newArrayList(PlayerUtil.checkPlayer(sender));
// A different player
} else {
targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
}
for (Player player : targets) {
if (sender != player) {
// Make sure that this player can clear other players!
CommandBook.inst().checkPermission(sender, "commandbook.clear.other");
break;
}
}
for (Player player : targets) {
Inventory inventory = player.getInventory();
if (clearSingle) {
player.setItemInHand(null);
} else {
for (int i = (clearAll ? 0 : 9); i < 36; i++) {
inventory.setItem(i, null);
}
if (clearAll) {
// Armor slots
for (int i = 36; i <= 39; i++) {
inventory.setItem(i, null);
}
}
}
// Tell the user about the given item
if (player.equals(sender)) {
if (clearAll) {
player.sendMessage(ChatColor.YELLOW
+ "Your inventory has been cleared.");
} else {
player.sendMessage(ChatColor.YELLOW
+ "Your inventory has been cleared. Use -a to clear ALL.");
}
// Keep track of this
included = true;
} else {
player.sendMessage(ChatColor.YELLOW
+ "Your inventory has been cleared by "
+ ChatUtil.toColoredName(sender, ChatColor.YELLOW));
}
}
// The player didn't receive any items, then we need to send the
// user a message so s/he know that something is indeed working
if (!included) {
sender.sendMessage(ChatColor.YELLOW
+ "Inventories cleared.");
}
}
@Command(aliases = {"more"},
usage = "[player]", desc = "Gets more of an item",
flags = "aio", min = 0, max = 1)
@CommandPermissions({"commandbook.more"})
public void more(CommandContext args, CommandSender sender) throws CommandException {
Iterable<Player> targets;
boolean moreAll = args.hasFlag('a');
boolean infinite = args.hasFlag('i');
boolean overrideStackSize = args.hasFlag('o');
if (infinite) {
CommandBook.inst().checkPermission(sender, "commandbook.more.infinite");
} else if (overrideStackSize) {
CommandBook.inst().checkPermission(sender, "commandbook.override.maxstacksize");
}
boolean included = false;
if (args.argsLength() == 0) {
targets = Lists.newArrayList(PlayerUtil.checkPlayer(sender));
// A different player
} else {
targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
}
for (Player player : targets) {
if (player != sender) {
// Check permissions!
CommandBook.inst().checkPermission(sender, "commandbook.more.other");
} else {
CommandBook.inst().checkPermission(sender, "commandbook.more");
}
}
for (Player player : targets) {
Inventory inventory = player.getInventory();
if (moreAll) {
for (int i = 0; i < 39; i++) {
ItemUtil.expandStack(inventory.getItem(i), infinite, overrideStackSize);
}
} else {
ItemUtil.expandStack(player.getItemInHand(), infinite, overrideStackSize);
}
// Tell the user about the given item
if (player.equals(sender)) {
player.sendMessage(ChatColor.YELLOW
+ "Your item(s) has been expanded in stack size.");
// Keep track of this
included = true;
} else {
player.sendMessage(ChatColor.YELLOW
+ "Your item(s) has been expanded in stack size by "
+ ChatUtil.toColoredName(sender, ChatColor.YELLOW));
}
}
// The player didn't receive any items, then we need to send the
// user a message so s/he know that something is indeed working
if (!included) {
sender.sendMessage(ChatColor.YELLOW
+ "Stack sizes increased.");
}
}
@Command(aliases = {"take"},
usage = "<target> <item[:data]> [amount]", desc = "Take an item",
flags = "", min = 2, max = 3)
@CommandPermissions({"commandbook.take"})
public void take(CommandContext args, CommandSender sender) throws CommandException {
ItemStack item = null;
int amt = config.defaultItemStackSize;
Player target = null;
// Two arguments: Player, item type
if (args.argsLength() == 2) {
target = InputUtil.PlayerParser.matchSinglePlayer(sender, args.getString(0));
item = matchItem(args.getString(1));
// Three arguments: Player, item type, and item amount
} else if (args.argsLength() == 3) {
target = InputUtil.PlayerParser.matchSinglePlayer(sender, args.getString(0));
item = matchItem(args.getString(1));
amt = args.getInteger(2);
}
if (target != sender) {
// Check permissions!
CommandBook.inst().checkPermission(sender, "commandbook.take.other");
} else {
CommandBook.inst().checkPermission(sender, "commandbook.take");
}
if (item == null) {
throw new CommandException("Something went wrong parsing the item info!");
}
takeItem(sender, item, amt, target);
}
@Command(aliases = {"stack"},
usage = "", desc = "Stack items",
max = 0)
@CommandPermissions({"commandbook.stack"})
public void stack(CommandContext args, CommandSender sender) throws CommandException {
Player player = PlayerUtil.checkPlayer(sender);
boolean ignoreMax = CommandBook.inst().hasPermission(player, "commandbook.stack.illegitimate");
boolean ignoreDamaged = CommandBook.inst().hasPermission(player, "commandbook.stack.damaged");
ItemStack[] items = player.getInventory().getContents();
int len = items.length;
int affected = 0;
for (int i = 0; i < len; i++) {
ItemStack item = items[i];
// Avoid infinite stacks and stacks with durability
if (item == null || item.getAmount() <= 0
|| (!ignoreMax && item.getMaxStackSize() == 1)) {
continue;
}
int max = ignoreMax ? 64 : item.getMaxStackSize();
if (item.getAmount() < max) {
int needed = max - item.getAmount(); // Number of needed items until max
// Find another stack of the same type
for (int j = i + 1; j < len; j++) {
ItemStack item2 = items[j];
// Avoid infinite stacks and stacks with durability
if (item2 == null || item2.getAmount() <= 0
|| (!ignoreMax && item.getMaxStackSize() == 1)) {
continue;
}
// Same type?
// Blocks store their color in the damage value
if (item2.getTypeId() == item.getTypeId() &&
((!ItemType.usesDamageValue(item.getTypeId()) && ignoreDamaged)
|| item.getDurability() == item2.getDurability()) &&
((item.getItemMeta() == null && item2.getItemMeta() == null)
|| (item.getItemMeta() != null &&
item.getItemMeta().equals(item2.getItemMeta())))) {
// This stack won't fit in the parent stack
if (item2.getAmount() > needed) {
item.setAmount(64);
item2.setAmount(item2.getAmount() - needed);
break;
// This stack will
} else {
items[j] = null;
item.setAmount(item.getAmount() + item2.getAmount());
needed = 64 - item.getAmount();
}
affected++;
}
}
}
}
if (affected > 0) {
player.getInventory().setContents(items);
}
player.sendMessage(ChatColor.YELLOW + "Items compacted into stacks!");
}
@Command(aliases = {"repair"},
usage = "[targets]", desc = "Repair items",
flags = "ahe", min = 0, max = 1)
@CommandPermissions({"commandbook.repair"})
public void repair(CommandContext args, CommandSender sender) throws CommandException {
Iterable<Player> targets;
boolean repairAll = args.hasFlag('a');
boolean repairHotbar = args.hasFlag('h');
boolean repairEquipment = args.hasFlag('e');
boolean included = false;
if (args.argsLength() == 0) {
targets = Lists.newArrayList(PlayerUtil.checkPlayer(sender));
// A different player
} else {
targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
}
for (Player player : targets) {
if (sender != player) {
// Make sure that this player can clear other players!
CommandBook.inst().checkPermission(sender, "commandbook.repair.other");
break;
}
}
for (Player player : targets) {
Inventory inventory = player.getInventory();
if (!repairAll && !repairHotbar && !repairEquipment) {
ItemStack stack = player.getItemInHand();
if (stack != null && !ItemType.usesDamageValue(stack.getTypeId())) {
stack.setDurability((short) 0);
}
} else {
if (repairAll || repairHotbar) {
for (int i = (repairAll ? 36 : 8); i >= 0; --i) {
ItemStack stack = inventory.getItem(i);
if (stack != null && !ItemType.usesDamageValue(stack.getTypeId())) {
stack.setDurability((short) 0);
}
}
}
if (repairAll || repairEquipment) {
// Armor slots
for (int i = 36; i <= 39; i++) {
ItemStack stack = inventory.getItem(i);
if (stack != null && !ItemType.usesDamageValue(stack.getTypeId())) {
stack.setDurability((short) 0);
}
}
}
}
// Tell the user about the given item
if (player.equals(sender)) {
if (repairAll || repairHotbar || repairEquipment) {
player.sendMessage(ChatColor.YELLOW
+ "Your items have been repaired.");
} else {
player.sendMessage(ChatColor.YELLOW
+ "Your held item has been repaired. Use -a to repair all.");
}
// Keep track of this
included = true;
} else {
player.sendMessage(ChatColor.YELLOW
+ "One or more of your item(s) has been repaired by "
+ ChatUtil.toColoredName(sender, ChatColor.YELLOW));
}
}
// The player didn't receive any items, then we need to send the
// user a message so s/he know that something is indeed working
if (!included) {
sender.sendMessage(ChatColor.YELLOW + "Items repaired.");
}
}
@Command(aliases = {"enchantments", "listenchant", "lsenchant"}, desc = "List available enchantments", usage = "[-p page]", flags = "p:")
public void enchantments(CommandContext args, CommandSender sender) throws CommandException {
new PaginatedResult<Enchantment>(ChatColor.GOLD + "Enchantments") {
@Override
public String format(Enchantment entry) {
return ChatColor.BLUE + entry.getName().toUpperCase() + ChatColor.YELLOW
+ " (ID: " + ChatColor.WHITE + entry.getId() + ChatColor.YELLOW
+ ", Max Level: " + ChatColor.WHITE + entry.getMaxLevel() + ChatColor.YELLOW + ')';
}
}.display(sender, Arrays.asList(Enchantment.values()), args.getFlagInteger('p', 1));
}
}
}