diff --git a/src/main/java/me/unurled/sacredrealms/sr/commands/CommandManager.java b/src/main/java/me/unurled/sacredrealms/sr/commands/CommandManager.java index be98094..b5c883e 100644 --- a/src/main/java/me/unurled/sacredrealms/sr/commands/CommandManager.java +++ b/src/main/java/me/unurled/sacredrealms/sr/commands/CommandManager.java @@ -7,6 +7,7 @@ import me.unurled.sacredrealms.sr.SR; import me.unurled.sacredrealms.sr.commands.admin.AttributeCommand; import me.unurled.sacredrealms.sr.commands.admin.ClientBuildCommand; import me.unurled.sacredrealms.sr.commands.admin.EntityTypeCommand; +import me.unurled.sacredrealms.sr.commands.admin.ItemCommand; import me.unurled.sacredrealms.sr.commands.admin.LevelCommand; import me.unurled.sacredrealms.sr.commands.player.ResetAdventureCommand; import me.unurled.sacredrealms.sr.managers.Manager; @@ -40,6 +41,7 @@ public class CommandManager extends Manager { registerCommand("clientbuild", ClientBuildCommand.class); registerCommand("level", LevelCommand.class); registerCommand("entitytype", EntityTypeCommand.class); + registerCommand("item", ItemCommand.class); registerCommand("resetadventure", ResetAdventureCommand.class); } diff --git a/src/main/java/me/unurled/sacredrealms/sr/commands/admin/ItemCommand.java b/src/main/java/me/unurled/sacredrealms/sr/commands/admin/ItemCommand.java new file mode 100644 index 0000000..31aa33d --- /dev/null +++ b/src/main/java/me/unurled/sacredrealms/sr/commands/admin/ItemCommand.java @@ -0,0 +1,435 @@ +package me.unurled.sacredrealms.sr.commands.admin; + +import static me.unurled.sacredrealms.sr.utils.Component.comp; +import static me.unurled.sacredrealms.sr.utils.Logger.error; + +import java.util.Arrays; +import java.util.List; +import me.unurled.sacredrealms.sr.components.attributes.Attribute; +import me.unurled.sacredrealms.sr.components.item.Item; +import me.unurled.sacredrealms.sr.components.item.ItemManager; +import me.unurled.sacredrealms.sr.components.item.ItemType; +import me.unurled.sacredrealms.sr.components.item.Rarity; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ItemCommand implements TabExecutor { + + /** + * Executes the given command, returning its success.
+ * If false is returned, then the "usage" plugin.yml entry for this command (if defined) will be + * sent to the player. + * + * @param sender Source of the command + * @param command Command which was executed + * @param label Alias of the command which was used + * @param args Passed command arguments + * @return true if a valid command, otherwise false + */ + @Override + public boolean onCommand( + @NotNull CommandSender sender, + @NotNull Command command, + @NotNull String label, + @NotNull String[] args) { + if (!(sender instanceof Player p)) { + sender.sendMessage("You must be a player to use this command."); + return true; + } + + if (!p.hasPermission("sr.admin.item")) { + p.sendMessage("You do not have permission to use this command."); + return true; + } + + if (args.length == 0) { + p.sendMessage("Usage: /item "); + return true; + } + + if (args[0].equalsIgnoreCase("list")) { + ItemManager im = ItemManager.getInstance(ItemManager.class); + if (im.getItemIDs().isEmpty()) { + p.sendMessage(comp("There are no items.")); + return true; + } + p.sendMessage("Items:"); + im.getItemIDs().forEach(p::sendMessage); + return true; + } + + if (args[0].equalsIgnoreCase("create")) { + if (args.length < 2) { + p.sendMessage("Usage: /item create "); + return true; + } + ItemManager im = ItemManager.getInstance(ItemManager.class); + if (im.getItemIDs().contains(args[1])) { + p.sendMessage(comp("An item with that ID already exists.")); + return true; + } + Item item = new Item(); + item.setID(args[1]); + im.addItem(item); + p.sendMessage( + comp( + "Item created. You can now modify it using " + + " /item modify " + + args[1] + + "")); + return true; + } + + if (args[0].equalsIgnoreCase("delete")) { + if (args.length < 2) { + p.sendMessage("Usage: /item delete "); + return true; + } + ItemManager im = ItemManager.getInstance(ItemManager.class); + if (!im.getItemIDs().contains(args[1])) { + p.sendMessage(comp("An item with that ID does not exist.")); + return true; + } + im.removeItem(args[1]); + p.sendMessage(comp("Item deleted.")); + return true; + } + + if (args[0].equalsIgnoreCase("give")) { + if (args.length < 2) { + p.sendMessage("Usage: /item give "); + return true; + } + + ItemManager im = ItemManager.getInstance(ItemManager.class); + if (!im.getItemIDs().contains(args[1])) { + p.sendMessage(comp("An item with that ID does not exist.")); + return true; + } + + Item item = im.getItem(args[1]); + + if (args.length == 2) { + p.getInventory().addItem(item.toItemStack()); + p.sendMessage(comp("Item given.")); + return true; + } + + Player target = Bukkit.getPlayer(args[2]); + if (target == null) { + p.sendMessage(comp("Player not found.")); + return true; + } + + target.getInventory().addItem(item.toItemStack()); + p.sendMessage(comp("Item given.")); + + return true; + } + + if (args[0].equalsIgnoreCase("modify")) { + if (args.length < 2) { + p.sendMessage( + "Usage: /item modify [value]"); + return true; + } + + ItemManager im = ItemManager.getInstance(ItemManager.class); + if (!im.getItemIDs().contains(args[1])) { + p.sendMessage(comp("An item with that ID does not exist.")); + return true; + } + + Item item = im.getItem(args[1]); + + if (args.length == 2) { + p.sendMessage( + "Usage: /item modify [value]"); + return true; + } + + switch (args[2].toLowerCase()) { + case "name" -> { + if (args.length < 4) { + p.sendMessage("Usage: /item modify name "); + return true; + } + String name = String.join(" ", Arrays.copyOfRange(args, 3, args.length)); + item.setName(name); + p.sendMessage(comp("Item name set.")); + // TODO: update item in player inventory + return true; + } + case "material" -> { + if (args.length < 4) { + p.sendMessage("Usage: /item modify material "); + return true; + } + Material material = Material.matchMaterial(args[3]); + if (material == null) { + p.sendMessage(comp("Material not found.")); + return true; + } + item.setMaterial(material); + p.sendMessage(comp("Item material set.")); + } + case "enchantments" -> { + if (args.length < 4) { + p.sendMessage("Usage: /item modify enchantments [enchantment]"); + return true; + } + if (args[3].equalsIgnoreCase("add")) { + if (args.length < 5) { + p.sendMessage("Usage: /item modify enchantments add "); + return true; + } + // TODO: add enchantment + p.sendMessage("Enchantments not working for now."); + return true; + } + if (args[3].equalsIgnoreCase("remove")) { + if (args.length < 5) { + p.sendMessage("Usage: /item modify enchantments remove "); + return true; + } + // TODO: remove enchantment + p.sendMessage("Enchantments not working for now."); + return true; + } + } + case "attributes" -> { + if (args.length < 4) { + p.sendMessage("Usage: /item modify attributes [attribute] [value]"); + return true; + } + if (args[3].equalsIgnoreCase("add")) { + if (args.length < 6) { + p.sendMessage("Usage: /item modify attributes add "); + return true; + } + Attribute attribute = null; + try { + attribute = Attribute.valueOf(args[4]); + } catch (Exception e) { + p.sendMessage(comp("Attribute not found.")); + error("Error on attribute affectation on item: " + args[1] + "\n" + e); + return true; + } + double value; + try { + value = Double.parseDouble(args[5]); + } catch (NumberFormatException e) { + p.sendMessage(comp("Invalid value.")); + return true; + } + item.addAttribute(attribute, value); + p.sendMessage(comp("Attribute added.")); + return true; + } + if (args[3].equalsIgnoreCase("remove")) { + if (args.length < 5) { + p.sendMessage("Usage: /item modify attributes remove "); + return true; + } + Attribute attribute = null; + try { + attribute = Attribute.valueOf(args[4]); + } catch (Exception e) { + p.sendMessage(comp("Attribute not found.")); + error("Error on attribute affectation on item: " + args[1] + "\n" + e); + return true; + } + item.removeAttribute(attribute); + p.sendMessage(comp("Attribute removed.")); + return true; + } + return true; + } + case "abilities" -> { + if (args.length < 5) { + p.sendMessage("Usage: /item modify abilities add "); + return true; + } + if (args[3].equalsIgnoreCase("add")) { + p.sendMessage("Abilities not working for now."); + // TODO: add ability + } else if (args[3].equalsIgnoreCase("remove")) { + p.sendMessage("Abilities not working for now."); + // TODO: remove ability + } + return true; + } + case "custommodeldata" -> { + if (args.length < 4) { + p.sendMessage("Usage: /item modify custommodeldata "); + return true; + } + int customModelData; + try { + customModelData = Integer.parseInt(args[3]); + } catch (NumberFormatException e) { + p.sendMessage(comp("Invalid value.")); + return true; + } + item.setCustomModelData(customModelData); + p.sendMessage(comp("Custom model data set.")); + return true; + } + case "rarity" -> { + if (args.length < 4) { + p.sendMessage("Usage: /item modify rarity "); + return true; + } + Rarity rarity; + try { + rarity = Rarity.valueOf(args[3]); + } catch (Exception e) { + p.sendMessage(comp("Rarity not found.")); + return true; + } + item.setRarity(rarity); + p.sendMessage(comp("Rarity set.")); + return true; + } + case "type" -> { + if (args.length < 4) { + p.sendMessage("Usage: /item modify type "); + return true; + } + ItemType type; + try { + type = ItemType.valueOf(args[3]); + } catch (Exception e) { + p.sendMessage(comp("Type not found.")); + return true; + } + item.setType(type); + p.sendMessage(comp("Type set.")); + return true; + } + case "description" -> { + if (args.length < 4) { + p.sendMessage("Usage: /item modify description "); + return true; + } + String description = String.join(" ", Arrays.copyOfRange(args, 3, args.length)); + item.setDescription(description); + p.sendMessage(comp("Description set.")); + return true; + } + } + } + + return true; + } + + /** + * Requests a list of possible completions for a command argument. + * + * @param sender Source of the command. For players tab-completing a command inside of a command + * block, this will be the player, not the command block. + * @param command Command which was executed + * @param label Alias of the command which was used + * @param args The arguments passed to the command, including final partial argument to be + * completed + * @return A List of possible completions for the final argument, or null to default to the + * command executor + */ + @Override + public @Nullable List onTabComplete( + @NotNull CommandSender sender, + @NotNull Command command, + @NotNull String label, + @NotNull String[] args) { + if (!(sender instanceof Player) || !sender.hasPermission("sr.admin.item")) { + return List.of(""); + } + + if (args.length == 1) { + return List.of("list", "create", "delete", "give", "modify"); + } + + if (args.length == 2) { + if (args[0].equalsIgnoreCase("delete") + || args[0].equalsIgnoreCase("give") + || args[0].equalsIgnoreCase("modify")) { + ItemManager im = ItemManager.getInstance(ItemManager.class); + return im.getItemIDs(); + } + } + + if (args.length == 3) { + if (args[0].equalsIgnoreCase("modify")) { + return List.of( + "name", + "material", + "enchantments", + "attributes", + "abilities", + "custommodeldata", + "rarity", + "type", + "description"); + } else if (args[0].equalsIgnoreCase("give")) { + return Bukkit.getOnlinePlayers().stream().map(Player::getName).toList(); + } + } + + if (args.length == 4) { + if (args[0].equalsIgnoreCase("modify")) { + if (args[2].equalsIgnoreCase("rarity")) { + return Arrays.stream(Rarity.values()).map(Enum::name).toList(); + } else if (args[2].equalsIgnoreCase("type")) { + return Arrays.stream(ItemType.values()).map(Enum::name).toList(); + } else if (args[2].equalsIgnoreCase("material")) { + return Arrays.stream(Material.values()).map(Enum::name).toList(); + } else if (args[2].equalsIgnoreCase("enchantments")) { + return List.of("add", "remove"); + } else if (args[2].equalsIgnoreCase("abilities")) { + return List.of("add", "remove"); + } else if (args[2].equalsIgnoreCase("attributes")) { + return List.of("add", "remove"); + } else if (args[2].equalsIgnoreCase("custommodeldata")) { + try { + Integer.parseInt(args[3]); + } catch (NumberFormatException e) { + return List.of("1"); + } + } + } + } + + if (args.length == 5) { + if (args[0].equalsIgnoreCase("modify")) { + /*if (args[2].equalsIgnoreCase("enchantments")) { // TODO: Enchantments in completion + return Arrays.stream(Enchantment.values()).map(Enum::name).toList(); + } else*/ if (args[2].equalsIgnoreCase("attributes")) { + return Arrays.stream(Attribute.values()).map(Enum::name).toList(); + } + } + } + + if (args.length == 6) { + if (args[0].equalsIgnoreCase("modify")) { + if (args[2].equalsIgnoreCase("attributes")) { + try { + Double.parseDouble(args[5]); + } catch (NumberFormatException e) { + return List.of("1.0"); + } + } + } + } + + return List.of(""); + } +} diff --git a/src/main/java/me/unurled/sacredrealms/sr/components/item/Item.java b/src/main/java/me/unurled/sacredrealms/sr/components/item/Item.java index 72d4ab2..470549e 100644 --- a/src/main/java/me/unurled/sacredrealms/sr/components/item/Item.java +++ b/src/main/java/me/unurled/sacredrealms/sr/components/item/Item.java @@ -127,6 +127,14 @@ public class Item { this.rarity = rarity; } + public ItemType getType() { + return type; + } + + public void setType(ItemType type) { + this.type = type; + } + public HashMap getAttributes() { return attributes; } @@ -263,4 +271,8 @@ public class Item { error("Failed to parse item from string: " + item + "\n" + e.getMessage()); } } + + public void setID(String arg) { + this.ID = arg; + } } diff --git a/src/main/java/me/unurled/sacredrealms/sr/components/item/ItemManager.java b/src/main/java/me/unurled/sacredrealms/sr/components/item/ItemManager.java index 15814e9..4798298 100644 --- a/src/main/java/me/unurled/sacredrealms/sr/components/item/ItemManager.java +++ b/src/main/java/me/unurled/sacredrealms/sr/components/item/ItemManager.java @@ -3,6 +3,7 @@ package me.unurled.sacredrealms.sr.components.item; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.HashMap; +import java.util.List; import me.unurled.sacredrealms.sr.data.DataHandler; import me.unurled.sacredrealms.sr.data.DataManager; import me.unurled.sacredrealms.sr.data.gson.ItemDeserializer; @@ -12,7 +13,6 @@ import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataType; -@SuppressWarnings("EmptyMethod") public class ItemManager extends Manager { public static final NamespacedKey ID = new NamespacedKey("sr", "id"); @@ -85,4 +85,8 @@ public class ItemManager extends Manager { public boolean isItem(String id) { return items.containsKey(id); } + + public List getItemIDs() { + return List.copyOf(items.keySet()); + } } diff --git a/src/main/java/me/unurled/sacredrealms/sr/components/item/enchantments/Enchantment.java b/src/main/java/me/unurled/sacredrealms/sr/components/item/enchantments/Enchantment.java index 367838d..fde513e 100644 --- a/src/main/java/me/unurled/sacredrealms/sr/components/item/enchantments/Enchantment.java +++ b/src/main/java/me/unurled/sacredrealms/sr/components/item/enchantments/Enchantment.java @@ -1,25 +1,3 @@ package me.unurled.sacredrealms.sr.components.item.enchantments; -public class Enchantment { - private final String name; - private final String ID; - private final Integer maxLevel; - - public Enchantment(String name, String ID, Integer maxLevel) { - this.name = name; - this.ID = ID; - this.maxLevel = maxLevel; - } - - public String getName() { - return name; - } - - public String getID() { - return ID; - } - - public Integer getMaxLevel() { - return maxLevel; - } -} +public record Enchantment(String name, String ID, Integer maxLevel) {} diff --git a/src/main/java/me/unurled/sacredrealms/sr/utils/Items.java b/src/main/java/me/unurled/sacredrealms/sr/utils/Items.java index f25c378..bbe857b 100644 --- a/src/main/java/me/unurled/sacredrealms/sr/utils/Items.java +++ b/src/main/java/me/unurled/sacredrealms/sr/utils/Items.java @@ -112,8 +112,7 @@ public class Items { lore.add(comp("Enchantments:")); item.getEnchantments() .forEach( - (k, v) -> - lore.add(comp(" ➤ " + k.getName() + " " + v))); + (k, v) -> lore.add(comp(" ➤ " + k.name() + " " + v))); } stack.lore(lore); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index dbd04a4..8efb3c4 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -26,6 +26,9 @@ permissions: sr.entitytype: default: op description: When the player has permission for the command /entitytype + sr.admin.item: + default: op + description: When the player has permission for the command /item sr.resetadventure: default: op description: When the player has permission for the command /resetadventure @@ -39,5 +42,7 @@ commands: description: Set the level of the player. entitytype: description: Create a new entity type. + item: + description: Create/modify an item. resetadventure: description: Reset the adventure of the player \ No newline at end of file