diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java index 47b5d0c..78a7f54 100644 --- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java +++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java @@ -20,6 +20,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.lishid.openinv.commands.ContainerSettingCommand; import com.lishid.openinv.commands.OpenInvCommand; +import com.lishid.openinv.commands.SearchContainerCommand; import com.lishid.openinv.commands.SearchEnchantCommand; import com.lishid.openinv.commands.SearchInvCommand; import com.lishid.openinv.internal.IAnySilentContainer; @@ -334,6 +335,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { this.getCommand("openinv").setExecutor(openInv); this.getCommand("openender").setExecutor(openInv); SearchInvCommand searchInv = new SearchInvCommand(this); + this.getCommand("searchcontainer").setExecutor(new SearchContainerCommand()); this.getCommand("searchinv").setExecutor(searchInv); this.getCommand("searchender").setExecutor(searchInv); this.getCommand("searchenchant").setExecutor(new SearchEnchantCommand(this)); diff --git a/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java index 609e44f..8c20be9 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java @@ -34,8 +34,8 @@ import org.bukkit.scheduler.BukkitRunnable; public class OpenInvCommand implements TabExecutor { private final OpenInv plugin; - private final HashMap openInvHistory = new HashMap(); - private final HashMap openEnderHistory = new HashMap(); + private final HashMap openInvHistory = new HashMap<>(); + private final HashMap openEnderHistory = new HashMap<>(); public OpenInvCommand(final OpenInv plugin) { this.plugin = plugin; @@ -48,7 +48,7 @@ public class OpenInvCommand implements TabExecutor { return true; } - if (args.length > 0 && args[0].equalsIgnoreCase("?")) { + if (args.length > 0 && (args[0].equalsIgnoreCase("help") || args[0].equals("?"))) { this.plugin.showHelp((Player) sender); return true; } diff --git a/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java new file mode 100644 index 0000000..d95d3d3 --- /dev/null +++ b/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2011-2020 lishid. All rights reserved. + * + * 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, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.commands; + +import com.lishid.openinv.util.TabCompleter; +import java.util.Collections; +import java.util.List; +import org.bukkit.ChatColor; +import org.bukkit.Chunk; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; + +/** + * Command for searching containers in a radius of chunks. + */ +public class SearchContainerCommand implements TabExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage(ChatColor.RED + "You can't use this from the console."); + return true; + } + + if (args.length < 1) { + // Must supply material + return false; + } + + Material material = Material.getMaterial(args[0]); + + if (material == null) { + sender.sendMessage(ChatColor.RED + "Unknown item: \"" + args[0] + "\""); + return false; + } + + int radius = 5; + + if (args.length > 1) { + try { + radius = Integer.parseInt(args[1]); + } catch (NumberFormatException e) { + // Invalid radius supplied + return false; + } + } + + Player senderPlayer = (Player) sender; + World world = senderPlayer.getWorld(); + Chunk centerChunk = senderPlayer.getLocation().getChunk(); + StringBuilder locations = new StringBuilder(); + + for (int dX = -radius; dX <= radius; ++dX) { + for (int dZ = -radius; dZ <= radius; ++dZ) { + if (!world.loadChunk(centerChunk.getX() + dX, centerChunk.getZ() + dZ, false)) { + continue; + } + Chunk chunk = world.getChunkAt(centerChunk.getX() + dX, centerChunk.getZ() + dZ); + for (BlockState tileEntity : chunk.getTileEntities()) { + if (!(tileEntity instanceof InventoryHolder)) { + continue; + } + InventoryHolder holder = (InventoryHolder) tileEntity; + if (!holder.getInventory().contains(material)) { + continue; + } + locations.append(holder.getInventory().getType().name().toLowerCase()).append(" (") + .append(tileEntity.getX()).append(',').append(tileEntity.getY()).append(',') + .append(tileEntity.getZ()).append("), "); + } + } + } + + // Matches found, delete trailing comma and space + if (locations.length() > 0) { + locations.delete(locations.length() - 2, locations.length()); + } else { + sender.sendMessage("No containers found with " + material.toString()); + } + + sender.sendMessage("Containers holding item " + material.toString() + ": " + locations.toString()); + return true; + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { + if (args.length < 1 || args.length > 2 || !command.testPermissionSilent(sender)) { + return Collections.emptyList(); + } + + String argument = args[args.length - 1]; + if (args.length == 1) { + return TabCompleter.completeEnum(argument, Material.class); + } else { + return TabCompleter.completeInteger(argument); + } + } + +} diff --git a/plugin/src/main/java/com/lishid/openinv/commands/SearchInvCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/SearchInvCommand.java index 9a42ee9..c92b064 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/SearchInvCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/SearchInvCommand.java @@ -56,7 +56,7 @@ public class SearchInvCommand implements TabExecutor { } if (material == null) { - sender.sendMessage(ChatColor.RED + "Unknown item"); + sender.sendMessage(ChatColor.RED + "Unknown item: \"" + args[0] + "\""); return false; } diff --git a/plugin/src/main/resources/plugin.yml b/plugin/src/main/resources/plugin.yml index 62053b1..598e14f 100644 --- a/plugin/src/main/resources/plugin.yml +++ b/plugin/src/main/resources/plugin.yml @@ -24,6 +24,7 @@ permissions: OpenInv.silent: true OpenInv.anychest: true OpenInv.searchenchant: true + OpenInv.searchcontainer commands: openinv: @@ -43,13 +44,13 @@ commands: description: Search and list players having a specific item permission: OpenInv.search usage: |- - / [MinAmount] - Item is the Bukkit Material, MinAmount is the minimum amount required + / [MinAmount] - MinAmount is optional, the minimum amount required searchender: aliases: [se] permission: OpenInv.search description: Searches and lists players having a specific item in their ender chest usage: |- - / [MinAmount] - Item is the Bukkit Material, MinAmount is the minimum amount required + / [MinAmount] - MinAmount is optional, the minimum amount required silentcontainer: aliases: [sc, silent, silentchest] description: SilentContainer stops sounds and animations when using containers. @@ -67,4 +68,9 @@ commands: description: Search and list players with a specific enchantment. permission: OpenInv.searchenchant usage: |- - / <[enchantment] [MinLevel]> - Enchantment is the enchantment type, MinLevel is the minimum level. One is optional + / <[Enchantment] [MinLevel]> - Enchantment is the enchantment type, MinLevel is the minimum level. One is optional + searchcontainer: + aliases: [searchchest] + description: Search and list containers with a specific material. + permission: OpenInv.searchcontainer + usage: / [ChunkRadius] - ChunkRadius is optional, the length that will be searched for matching items. Default 5