diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index de57e6c2..2cd0f778 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,12 +8,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [ 17 ] + java: [ 21 ] fail-fast: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: ${{ matrix.java }} distribution: 'temurin' @@ -21,7 +21,7 @@ jobs: - name: Build with Gradle run: ./gradlew build --stacktrace - name: Upload build artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ github.event.repository.name }}-${{ github.sha }} path: | diff --git a/build.gradle.kts b/build.gradle.kts index a677e415..a1dd117d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ plugins { `java-library` - id("net.minecrell.plugin-yml.bukkit") version "0.6.0" // Generates plugin.yml - id("com.github.johnrengelman.shadow") version "8.1.1" // Shades and relocates dependencies into our plugin jar + id("net.minecrell.plugin-yml.paper") version "0.6.0" // Generates plugin.yml + id("com.gradleup.shadow") version "8.3.9" // Shades and relocates dependencies into our plugin jar id("xyz.jpenilla.run-paper") version "2.3.0" // Adds runServer and runMojangMappedServer tasks for testing } @@ -11,7 +11,7 @@ description = "A plugin for HoloCons SMP that adds a ton of custom items and blo java { // Configure the java toolchain. This allows gradle to auto-provision JDK 17 on systems that only have JDK 8 installed for example. - toolchain.languageVersion.set(JavaLanguageVersion.of(17)) + toolchain.languageVersion.set(JavaLanguageVersion.of(21)) } repositories { @@ -21,10 +21,10 @@ repositories { } dependencies { - compileOnly("io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT") - compileOnly("com.comphenix.protocol:ProtocolLib:5.2.0-SNAPSHOT") + compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT") compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.9") - implementation("com.github.stefvanschie.inventoryframework:IF:0.10.13") + implementation("com.github.stefvanschie.inventoryframework:IF:0.11.3") + implementation("com.typesafe:config:1.4.4") } tasks { @@ -38,7 +38,7 @@ tasks { // Set the release flag. This configures what version bytecode the compiler will emit, as well as what JDK APIs are usable. // See https://openjdk.java.net/jeps/247 for more information. - options.release.set(17) + options.release.set(21) } javadoc { options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything @@ -57,6 +57,7 @@ tasks { // https://github.com/johnrengelman/shadow shadowJar { relocate("com.github.stefvanschie.inventoryframework", "shadow.inventoryframework") + relocate("com.typesafe.config", "shadow.lightbend") archiveClassifier.set("") } @@ -64,24 +65,36 @@ tasks { // Configure the Minecraft version for runServer task // https://github.com/jpenilla/run-paper runServer { - minecraftVersion("1.20.1") + dependsOn("copyDatapack") + minecraftVersion("1.21.1") + } +} + +tasks.register("copyDatapack") { + // Not sure what group to make this + description = "Copies the datapack into the world's datapacks folder" + + delete("./run/world/datapacks/holoitems_datapack") + + copy { + from("./holoitems_datapack") + into("./run/world/datapacks/holoitems_datapack") } } // Configure plugin.yml generation // https://github.com/Minecrell/plugin-yml -bukkit { +paper { main = "xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp" - apiVersion = "1.20" + bootstrapper = "xyz.holocons.mc.holoitemsrevamp.HoloItemsBootstrap" + apiVersion = "1.21.1" authors = listOf("TraceL", "dlee13") website = "holocons.xyz" - depend = listOf("ProtocolLib") - softDepend = listOf("WorldGuard") prefix = "HoloItems" - commands { - register("holoitems") { - usage = "/holoitems" + serverDependencies { + register("WorldGuard") { + required = false } } } diff --git a/holoitems_datapack/data/holoitems/enchantment/backdash.json b/holoitems_datapack/data/holoitems/enchantment/backdash.json new file mode 100644 index 00000000..5facfed7 --- /dev/null +++ b/holoitems_datapack/data/holoitems/enchantment/backdash.json @@ -0,0 +1,17 @@ +{ + "description": "Backdash", + "supported_items": "#minecraft:enchantable/foot_armor", + "primary_items": [], + "weight": 1, + "max_level": 1, + "min_cost": { + "base": 100, + "per_level_above_first": 100 + }, + "max_cost": { + "base": 100, + "per_level_above_first": 100 + }, + "anvil_cost": 20, + "slots": ["feet"] +} \ No newline at end of file diff --git a/holoitems_datapack/data/holoitems/enchantment/magnet.json b/holoitems_datapack/data/holoitems/enchantment/magnet.json new file mode 100644 index 00000000..42d56d8b --- /dev/null +++ b/holoitems_datapack/data/holoitems/enchantment/magnet.json @@ -0,0 +1,17 @@ +{ + "description": "Magnet", + "supported_items": "#minecraft:pickaxes", + "primary_items": [], + "weight": 1, + "max_level": 1, + "min_cost": { + "base": 100, + "per_level_above_first": 100 + }, + "max_cost": { + "base": 100, + "per_level_above_first": 100 + }, + "anvil_cost": 39, + "slots": ["mainhand"] +} \ No newline at end of file diff --git a/holoitems_datapack/data/holoitems/enchantment/memento.json b/holoitems_datapack/data/holoitems/enchantment/memento.json new file mode 100644 index 00000000..61b90c99 --- /dev/null +++ b/holoitems_datapack/data/holoitems/enchantment/memento.json @@ -0,0 +1,17 @@ +{ + "description": "Memento", + "supported_items": "minecraft:ender_chest", + "primary_items": [], + "weight": 1, + "max_level": 1, + "min_cost": { + "base": 100, + "per_level_above_first": 100 + }, + "max_cost": { + "base": 100, + "per_level_above_first": 100 + }, + "anvil_cost": 30, + "slots": ["any"] +} \ No newline at end of file diff --git a/holoitems_datapack/data/holoitems/enchantment/plow.json b/holoitems_datapack/data/holoitems/enchantment/plow.json new file mode 100644 index 00000000..30877791 --- /dev/null +++ b/holoitems_datapack/data/holoitems/enchantment/plow.json @@ -0,0 +1,17 @@ +{ + "description": "Plow", + "supported_items": "#minecraft:shovels", + "primary_items": [], + "weight": 1, + "max_level": 1, + "min_cost": { + "base": 100, + "per_level_above_first": 100 + }, + "max_cost": { + "base": 100, + "per_level_above_first": 100 + }, + "anvil_cost": 32, + "slots": ["mainhand"] +} \ No newline at end of file diff --git a/holoitems_datapack/data/holoitems/enchantment/tide_rider.json b/holoitems_datapack/data/holoitems/enchantment/tide_rider.json new file mode 100644 index 00000000..50bf85de --- /dev/null +++ b/holoitems_datapack/data/holoitems/enchantment/tide_rider.json @@ -0,0 +1,17 @@ +{ + "description": "Tide Rider", + "supported_items": "#minecraft:enchantable/trident", + "primary_items": [], + "weight": 1, + "max_level": 1, + "min_cost": { + "base": 100, + "per_level_above_first": 100 + }, + "max_cost": { + "base": 100, + "per_level_above_first": 100 + }, + "anvil_cost": 20, + "slots": ["mainhand"] +} \ No newline at end of file diff --git a/holoitems_datapack/data/holoitems/tags/enchantment/holoenchantments.json b/holoitems_datapack/data/holoitems/tags/enchantment/holoenchantments.json new file mode 100644 index 00000000..3d798f52 --- /dev/null +++ b/holoitems_datapack/data/holoitems/tags/enchantment/holoenchantments.json @@ -0,0 +1,9 @@ +{ + "values": [ + "holoitems:backdash", + "holoitems:magnet", + "holoitems:memento", + "holoitems:plow", + "holoitems:tide_rider" + ] +} \ No newline at end of file diff --git a/holoitems_datapack/pack.mcmeta b/holoitems_datapack/pack.mcmeta new file mode 100644 index 00000000..0c256684 --- /dev/null +++ b/holoitems_datapack/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "pack_format": 48, + "description": "HoloItems" + } +} diff --git a/src/main/java/com/strangeone101/holoitemsapi/Keys.java b/src/main/java/com/strangeone101/holoitemsapi/Keys.java index 36450272..e411509d 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/Keys.java +++ b/src/main/java/com/strangeone101/holoitemsapi/Keys.java @@ -4,39 +4,21 @@ import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + import java.util.UUID; public class Keys { - public static Property OWNER; public static Property COOLDOWN; - public static Property UNSTACKABLE; public static Property ITEM_ID; + /** + * Used to represent an item that can also be used "like" an enchantment book. + * The first example of this is Backdash, which is both boots and applicable to other boots. + */ + public static Property BOOK_LIKE; public static void fillKeys(Plugin plugin) { - OWNER = new Property(plugin, "owner") { - - @Override - public boolean has(PersistentDataContainer data) { - return data.has(getKey(), DataType.UUID); - } - - @Override - public UUID get(PersistentDataContainer data) { - return data.get(getKey(), DataType.UUID); - } - - @Override - public void set(PersistentDataContainer data, UUID value) { - data.set(getKey(), DataType.UUID, value); - } - - @Override - public String getPropertyName() { - return "Owner"; - } - }; - COOLDOWN = new Property(plugin, "cooldown") { @Override @@ -60,53 +42,52 @@ public String getPropertyName() { } }; - UNSTACKABLE = new Property(plugin, "unstackable") { + ITEM_ID = new Property(plugin, "item_id") { @Override public boolean has(PersistentDataContainer data) { - return data.has(getKey(), PersistentDataType.INTEGER); + return data.has(getKey(), PersistentDataType.STRING); } @Override - public Boolean get(PersistentDataContainer data) { - return has(data); + public String get(PersistentDataContainer data) { + return data.get(getKey(), PersistentDataType.STRING); } @Override - public void set(PersistentDataContainer data, Boolean value) { - if (value) { - data.set(getKey(), PersistentDataType.INTEGER, Bukkit.getCurrentTick()); - } else { - data.remove(getKey()); - } + public void set(PersistentDataContainer data, String value) { + data.set(getKey(), PersistentDataType.STRING, value); } @Override public String getPropertyName() { - return "Unstackable"; + return "Item ID"; } }; - ITEM_ID = new Property(plugin, "item_id") { - + BOOK_LIKE = new Property(plugin, "book_like") { @Override public boolean has(PersistentDataContainer data) { - return data.has(getKey(), PersistentDataType.STRING); + return data.has(getKey(), PersistentDataType.BOOLEAN); } @Override - public String get(PersistentDataContainer data) { - return data.get(getKey(), PersistentDataType.STRING); + public Boolean get(PersistentDataContainer data) { + return data.getOrDefault(getKey(), PersistentDataType.BOOLEAN, false); } @Override - public void set(PersistentDataContainer data, String value) { - data.set(getKey(), PersistentDataType.STRING, value); + public void set(PersistentDataContainer data, Boolean value) { + if (value == null || !value) { + data.remove(getKey()); + } else { + data.set(getKey(), PersistentDataType.BOOLEAN, true); + } } @Override public String getPropertyName() { - return "Item ID"; + return "Book-like"; } }; } diff --git a/src/main/java/com/strangeone101/holoitemsapi/enchantment/AnvilListener.java b/src/main/java/com/strangeone101/holoitemsapi/enchantment/AnvilListener.java index eb5cfcc8..60742a5a 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/enchantment/AnvilListener.java +++ b/src/main/java/com/strangeone101/holoitemsapi/enchantment/AnvilListener.java @@ -1,247 +1,103 @@ package com.strangeone101.holoitemsapi.enchantment; - -import com.strangeone101.holoitemsapi.item.CustomItemManager; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.bukkit.GameMode; -import org.bukkit.Material; +import com.strangeone101.holoitemsapi.Keys; +import io.papermc.paper.registry.RegistryAccess; +import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.PrepareAnvilEvent; -import org.bukkit.inventory.AnvilInventory; -import org.bukkit.inventory.InventoryView; -import org.bukkit.inventory.ItemStack; +import org.bukkit.event.inventory.PrepareGrindstoneEvent; import org.bukkit.inventory.meta.Repairable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.bukkit.persistence.PersistentDataType; import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; -import xyz.holocons.mc.holoitemsrevamp.packet.PlayerAbilitiesPacket; import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; public class AnvilListener implements Listener { - private static final int MAX_REPAIR_COST = Short.MAX_VALUE; - private final HoloItemsRevamp plugin; public AnvilListener(HoloItemsRevamp plugin) { this.plugin = plugin; } - /** - * Makes sure that after a player closes an anvil inventory, their instant build - * ability gets disabled. - */ - @EventHandler(priority = EventPriority.MONITOR) - public void onInventoryClose(InventoryCloseEvent event) { - if (!(event.getInventory() instanceof AnvilInventory) - || !(event.getPlayer() instanceof Player player) - || player.getGameMode() == GameMode.CREATIVE) { - return; - } - - new PlayerAbilitiesPacket(player, false).sendPacket(player); - } - - /** - * Handles anvil craftings regarding custom enchantments and custom items. - */ - @EventHandler + @EventHandler(ignoreCancelled = true) public void onPrepareAnvil(PrepareAnvilEvent event) { - // Make sure viewer is a player and they don't have creative bypasses - if (!(event.getView().getPlayer() instanceof Player player) || player.getGameMode() == GameMode.CREATIVE) - return; - + // Handle Anvil scenarios involving the BOOK_LIKE key. var inventory = event.getInventory(); - - var base = inventory.getFirstItem(); - var addition = inventory.getSecondItem(); - - if (base == null || !(base.getItemMeta() instanceof Repairable) || base.getAmount() != 1) - return; - - // Only handle events that contain custom enchantments - if (hasNoCustomEnchants(base) && hasNoCustomEnchants(addition)) - return; - - if (CustomItemManager.isCustomItem(base)) { // Disallow players to modify custom items - event.setResult(null); - plugin.getServer().getScheduler().runTask(plugin, () -> inventory.setResult(null)); + var firstItem = inventory.getFirstItem(); + var secondItem = inventory.getSecondItem(); + if(firstItem == null || secondItem == null) { + // BOOK_LIKE doesn't care about these scenarios (only renaming possible) return; } - inventory.setMaximumRepairCost(MAX_REPAIR_COST); - - // Name handling with base item containing custom enchantments - if (addition == null) { - var renameText = inventory.getRenameText(); - var displayName = base.getItemMeta().hasDisplayName() - ? PlainTextComponentSerializer.plainText().serialize(base.getItemMeta().displayName()) - : ""; - if (renameText != null && !renameText.isBlank() && !displayName.equals(renameText)) { - var result = base.clone(); - var resultMeta = result.getItemMeta(); - - resultMeta.displayName(Component.text(renameText)); - result.setItemMeta(resultMeta); - - final int levelCost = inventory.getRepairCost(); + if(Keys.BOOK_LIKE.get(secondItem.getItemMeta().getPersistentDataContainer())) { + // Second item is book-like. That means its enchantments need to be applied to the result. + var result = inventory.getResult(); + if(result == null) { + result = firstItem.clone(); + event.setResult(result); + } - plugin.getServer().getScheduler().runTask(plugin, () -> { - if (!base.equals(inventory.getFirstItem())) - return; + boolean addedEnch = false; + for(Map.Entry ench : secondItem.getEnchantments().entrySet()) { + // Note the >=: I do not care to implement "merging" (ie: two lv3 enchs becomes a lv4 ench) + if(result.getEnchantmentLevel(ench.getKey()) >= ench.getValue()) { + continue; + } + try { + result.addEnchantment(ench.getKey(), ench.getValue()); + } catch (IllegalArgumentException ignored) { + // either the enchantment is null (not possible) + // or the enchantment is not applicable, so they weren't applied + // in either case, an enchantment wasn't added + continue; + } + addedEnch = true; + } - inventory.setResult(result); - inventory.setRepairCost(levelCost); - player.setWindowProperty(InventoryView.Property.REPAIR_COST, levelCost); - new PlayerAbilitiesPacket(player, hasEnoughLevels(player, levelCost)).sendPacket(player); - }); + if(!addedEnch) { + // Whatever enchantment(s) were on the 2nd item weren't allowed to be on the result. + // Therefore, block the result from being made. + event.setResult(null); + } + else { + // If it succeeded, the repair-cost also needs to be set. + // If it's non-zero, the book_like tag tells us what the repair cost should be! + // TODO: Remove this todo when your IDE is no longer marking getView and setRepairCost as unstable + // (when that happens, it might get deprecated/changed/removed.) + var anvilView = event.getView(); + if(firstItem instanceof Repairable repairable) { + anvilView.setRepairCost(repairable.getRepairCost()); + } + else { + anvilView.setRepairCost(1); + } } - return; } - // Enchantment handling if addition item is an enchanted book - if (addition.getType() == Material.ENCHANTED_BOOK) { - var customEnchants = combineCustomEnchants(base, addition); + if(Keys.BOOK_LIKE.get(firstItem.getItemMeta().getPersistentDataContainer())) { + // First item is book-like. + // If this is adding enchantments, don't let the result stay book-like. + // (If this is just a renaming or repairing, it's fine.) var result = event.getResult(); - int levelCost = inventory.getRepairCost(); - - if (customEnchants.isEmpty()) - return; - - // Enchantment handling if the enchanted book contains only custom enchantments - if (result == null) { - result = base.clone(); - levelCost = ((Repairable) base.getItemMeta()).getRepairCost(); + if(result != null) { + if(!firstItem.getEnchantments().equals(result.getEnchantments())) { + Keys.BOOK_LIKE.set(result.getItemMeta().getPersistentDataContainer(), false); + } } - - customEnchants.forEach(result::addEnchantment); - plugin.getEnchantManager().removeCustomEnchantmentLore(result); - plugin.getEnchantManager().applyCustomEnchantmentLore(result); - - final var finalLevelCost = getCustomEnchantCost(customEnchants, levelCost); - final var finalResult = result; - - inventory.setResult(finalResult); - inventory.setRepairCost(finalLevelCost); - - plugin.getServer().getScheduler().runTask(plugin, () -> { - if (!base.equals(inventory.getFirstItem()) || !addition.equals(inventory.getSecondItem())) - return; - - inventory.setResult(finalResult); - inventory.setRepairCost(finalLevelCost); - player.setWindowProperty(InventoryView.Property.REPAIR_COST, finalLevelCost); - new PlayerAbilitiesPacket(player, hasEnoughLevels(player, finalLevelCost)).sendPacket(player); - }); - return; - } - - // Enchantment handling if the addition is not an enchanted book - if (CustomItemManager.isCustomItem(addition)) { - // It's a custom item, but not an enchanted book. Should not be used to - // enchant/repair stuff - event.setResult(null); - plugin.getServer().getScheduler().runTask(plugin, () -> inventory.setResult(null)); - return; - } - - var result = inventory.getResult(); - if (result == null) { - return; } - - var customEnchants = combineCustomEnchants(base, addition); - var levelCost = getCustomEnchantCost(customEnchants, inventory.getRepairCost()); - - customEnchants.forEach(result::addEnchantment); - plugin.getEnchantManager().removeCustomEnchantmentLore(result); - plugin.getEnchantManager().applyCustomEnchantmentLore(result); - - event.setResult(result); - inventory.setRepairCost(levelCost); - - plugin.getServer().getScheduler().runTask(plugin, () -> { - if (!base.equals(inventory.getFirstItem()) || !addition.equals(inventory.getSecondItem())) - return; - - inventory.setResult(result); - inventory.setRepairCost(levelCost); - player.setWindowProperty(InventoryView.Property.REPAIR_COST, levelCost); - new PlayerAbilitiesPacket(player, hasEnoughLevels(player, levelCost)).sendPacket(player); - }); } - private static boolean hasEnoughLevels(Player player, int repairCost) { - return player.getLevel() >= repairCost; - } - - /** - * Combines custom enchantments from two items while handling conflicts and - * levels. - * - * @param base The base item - * @param addition The second item - * @return A map containing all custom enchants - */ - private static Map combineCustomEnchants( - @NotNull ItemStack base, - @NotNull ItemStack addition) { - final var baseEnchantments = EnchantManager.getEnchantments(base); - final var additionEnchantments = EnchantManager.getEnchantments(addition) - .entrySet() - .stream() - .filter(entry -> hasNoConflictEnchants(baseEnchantments, entry.getKey()) - && entry.getKey().canEnchantItem(base)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - - final var combinedEnchantments = Stream - .of(baseEnchantments, additionEnchantments).>mapMulti( - (enchantments, consumer) -> { - for (final var entry : enchantments.entrySet()) { - if (entry.getKey() instanceof CustomEnchantment enchantment) { - consumer.accept(Map.entry(enchantment, entry.getValue())); - } - } - }) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, - (a, b) -> a.equals(b) ? a + 1 : Integer.max(a, b))); - combinedEnchantments.replaceAll((enchantment, level) -> Integer.min(level, enchantment.getMaxLevel())); - - return combinedEnchantments; - } - - /** - * Get the total enchantment cost from the map of enchantments. - * - * @param enchantments Enchantments to calculate level cost - * @param initialCost Repair cost before custom enchantments are considered - * @return Level cost to add enchantments to an item - */ - private static int getCustomEnchantCost(Map enchantments, int initialCost) { - return enchantments.entrySet().stream() - .reduce(initialCost, AnvilListener::levelCostAccumulator, Integer::sum); - } - - private static int levelCostAccumulator(int partialCost, Map.Entry nextEnchantment) { - return partialCost + Integer.min(nextEnchantment.getKey().getCostMultiplier(), MAX_REPAIR_COST) - * nextEnchantment.getValue(); - } - - private static boolean hasNoConflictEnchants(Map enchantments, Enchantment other) { - return enchantments.keySet().stream().noneMatch(other::conflictsWith); - } - - private static boolean hasNoCustomEnchants(@Nullable ItemStack itemStack) { - return itemStack == null || !itemStack.hasItemMeta() - || EnchantManager.getEnchantments(itemStack).keySet().stream() - .noneMatch(entry -> entry instanceof CustomEnchantment); + @EventHandler(ignoreCancelled = true) + public void onPrepareGrindstone(PrepareGrindstoneEvent event) { + // Make grindstones remove book-like value. + var result = event.getResult(); + if(result != null) { + var meta = result.getItemMeta(); + Keys.BOOK_LIKE.set(meta.getPersistentDataContainer(), false); + result.setItemMeta(meta); + } } } diff --git a/src/main/java/com/strangeone101/holoitemsapi/enchantment/CustomEnchantment.java b/src/main/java/com/strangeone101/holoitemsapi/enchantment/CustomEnchantment.java deleted file mode 100644 index c7e1b019..00000000 --- a/src/main/java/com/strangeone101/holoitemsapi/enchantment/CustomEnchantment.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.strangeone101.holoitemsapi.enchantment; - -import io.papermc.paper.enchantments.EnchantmentRarity; -import net.kyori.adventure.text.Component; - -import org.bukkit.NamespacedKey; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.enchantments.EnchantmentTarget; -import org.bukkit.entity.EntityCategory; -import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; -import java.util.Set; - -/** - * An abstract class to implement custom enchantments. Unsurprisingly, The Bukkit API has no capabilities of adding custom - * enchantments to the enchanting table. Most of these methods here are practically useless because they were meant for - * enchantments that would appear in the enchantment table. However, that will not happen because, again, Bukkit has no capabilities - * of adding it. So, most of the Enchantment methods are set to default values. - * - * Some methods, like {@link Enchantment#displayName(int)} and {@link Enchantment#canEnchantItem(ItemStack)} aren't implemented. - * While they also do nothing, they might help in setting enchantment lores, and validating anvil crafts. - */ -public abstract class CustomEnchantment extends Enchantment { - - private static final HashMap enchantmentsByKey = new HashMap<>(); - - public CustomEnchantment(Plugin plugin, String key) { - super(new NamespacedKey(plugin, key)); - } - - public static final void registerEnchantment(@NotNull CustomEnchantment enchantment) { - if (!Enchantment.isAcceptingRegistrations()) { - return; - } - Enchantment.registerEnchantment(enchantment); - enchantmentsByKey.put(enchantment.getKey(), enchantment); - } - - /** - * Gets the CustomEnchantment at the specified key. - * @param key The NamespacedKey of the enchantment to fetch - * @return Resulting CustomEnchantment, or null if not found - */ - @Nullable - public static final CustomEnchantment getByKey(@Nullable NamespacedKey key) { - return enchantmentsByKey.get(key); - } - - /** - * Gets the lore that will be applied to items that have this enchantment. Lore will - * not be applied if this returns null. - * @param level The level of the enchantment - * @return Lore corresponding to the given enchantment level - */ - @Nullable - public Component lore(int level) { - return displayName(level); - } - - /** - * Returns the multiplier used to add levels when combining the enchantment. This method is simillar to vanilla - * anvil mechanics - * @see Anvil Mechanics - * @return The multiplier for combining this enchantment - */ - public abstract int getCostMultiplier(); - - @NotNull - @Deprecated - @Override - public final String getName() { - return name(); - } - - @NotNull - public final String name() { - return getKey().getKey(); - } - - @Override - public @NotNull String translationKey() { - return ""; - } - - @Override - public int getStartLevel() { - return 1; - } - - @Override - public @NotNull EnchantmentTarget getItemTarget() { - return null; - } - - @Override - public boolean isTreasure() { - return false; - } - - @Override - public boolean isCursed() { - return false; - } - - @Override - public boolean isTradeable() { - return false; - } - - @Override - public boolean isDiscoverable() { - return false; - } - - @Override - public @NotNull EnchantmentRarity getRarity() { - return EnchantmentRarity.VERY_RARE; - } - - @Override - public float getDamageIncrease(int level, @NotNull EntityCategory entityCategory) { - return 0; - } - - @Override - public @NotNull Set getActiveSlots() { - return null; - } -} diff --git a/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantManager.java b/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantManager.java index 5f524024..19b9154c 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantManager.java +++ b/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantManager.java @@ -1,116 +1,66 @@ package com.strangeone101.holoitemsapi.enchantment; -import net.kyori.adventure.text.Component; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import io.papermc.paper.registry.tag.Tag; +import io.papermc.paper.registry.tag.TagKey; +import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; import xyz.holocons.mc.holoitemsrevamp.enchantment.*; import xyz.holocons.mc.holoitemsrevamp.integration.Integrations; -import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.Stream; +// For the most part, the UnstableApiUsage is coming up because of Paper's Tag<>. However, in +// 1.21.8, that goes away. Therefore, after we update, this should be removed. +@SuppressWarnings("UnstableApiUsage") public class EnchantManager { - private final List enchantmentNames; - private final Map, Component> enchantmentLores; + private final HoloItemsRevamp plugin; + private final Tag<@NotNull Enchantment> HoloEnchantmentsTag; + private final Map enchantmentsByKey; public EnchantManager(HoloItemsRevamp plugin) { - try { - final var field = Enchantment.class.getDeclaredField("acceptingNew"); - field.setAccessible(true); - field.set(null, true); - } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException(e); - } + this.plugin = plugin; + var enchantmentRegistry = RegistryAccess.registryAccess().getRegistry(RegistryKey.ENCHANTMENT); + var enchantmentTagName = new NamespacedKey(plugin, "holoenchantments"); + var enchantmentTagKey = TagKey.create(RegistryKey.ENCHANTMENT, enchantmentTagName); + this.HoloEnchantmentsTag = enchantmentRegistry.getTag(enchantmentTagKey); - final var enchantments = buildCustomEnchantments(plugin); - - enchantments.forEach(CustomEnchantment::registerEnchantment); - enchantments.forEach(Integrations.WORLDGUARD::registerEnchantment); - - this.enchantmentNames = enchantments.stream().map(CustomEnchantment::name).toList(); - // Key is a pair of Enchantment and level, value is the lore - this.enchantmentLores = enchantments - .stream()., Component>>mapMulti( - (customEnchantment, consumer) -> IntStream - .rangeClosed(customEnchantment.getStartLevel(), customEnchantment.getMaxLevel()) - .forEach(level -> { - final var lore = customEnchantment.lore(level); - if (lore != null) { - consumer.accept(Map.entry(Map.entry(customEnchantment, level), lore)); - } - })) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - - Enchantment.stopAcceptingRegistrations(); + this.enchantmentsByKey = this.buildCustomEnchantments(); + this.enchantmentsByKey.forEach(Integrations.WORLDGUARD::registerEnchantment); } - public List enchantmentNames() { - return enchantmentNames; - } - - /** - * If the item stack is an enchanted book, it will get the enchantments using - * {@link EnchantmentStorageMeta#getStoredEnchants()} - * - * @param itemStack An ItemStack that has enchantments - * @return A map of the enchantments - */ - public static Map getEnchantments(ItemStack itemStack) { - return itemStack.getItemMeta() instanceof EnchantmentStorageMeta enchantmentStorageMeta - ? enchantmentStorageMeta.getStoredEnchants() - : itemStack.getEnchantments(); + public boolean isTaggedHoloEnchantment(Enchantment enchantment) { + var typedEnchantmentKey = TypedKey.create(RegistryKey.ENCHANTMENT, enchantment.getKey()); + return HoloEnchantmentsTag.contains(typedEnchantmentKey); } /** - * Applies the display names of all custom enchantments present on an itemstack - * to the itemstack as lore. If any custom enchantment lore is already on the - * given itemstack, {@code EnchantManager#removeCustomEnchantmentLore} should be - * done first. - * - * @param itemStack An ItemStack that has custom enchantments + * Gets the CustomEnchantment at the specified key. + * @param key The NamespacedKey of the enchantment to fetch + * @return Resulting CustomEnchantment, or null if not found */ - public void applyCustomEnchantmentLore(ItemStack itemStack) { - final var enchantmentLore = getEnchantments(itemStack).entrySet().stream() - .map(enchantmentLores::get) - .filter(Objects::nonNull); - - final var oldLore = itemStack.lore(); - final var newLore = oldLore == null - ? enchantmentLore.toList() - : Stream.concat(enchantmentLore, oldLore.stream()).toList(); - itemStack.lore(newLore.isEmpty() ? null : newLore); + @Nullable + public EnchantmentAbility getByKey(@Nullable NamespacedKey key) { + return enchantmentsByKey.get(key); } - /** - * Removes all custom enchantment lore from the given itemstack. - * - * @param itemStack An ItemStack without custom enchantments - */ - public void removeCustomEnchantmentLore(ItemStack itemStack) { - final var oldLore = itemStack.lore(); - if (oldLore != null) { - final var newLore = oldLore.stream() - .filter(loreComponent -> !enchantmentLores.containsValue(loreComponent)) - .toList(); - itemStack.lore(newLore.isEmpty() ? null : newLore); - } + private Map buildCustomEnchantments() { + return Map.ofEntries( + createEntry("magnet", new Magnet(plugin)), + createEntry("memento", new Memento(plugin)), + createEntry("tide_rider", new TideRider(plugin)), + createEntry("backdash", new Backdash(plugin)), + createEntry("plow", new Plow(plugin)) + ); } - private static Set buildCustomEnchantments(HoloItemsRevamp plugin) { - return Set.of( - new Magnet(plugin), - new Memento(plugin), - new TideRider(plugin), - new Backdash(plugin), - new Plow(plugin) - ); + private Map.Entry createEntry(String name, EnchantmentAbility ability) { + return Map.entry(new NamespacedKey(plugin, name), ability); } } diff --git a/src/main/java/com/strangeone101/holoitemsapi/enchantment/Enchantable.java b/src/main/java/com/strangeone101/holoitemsapi/enchantment/Enchantable.java index 53f0b722..f0f4c31a 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/enchantment/Enchantable.java +++ b/src/main/java/com/strangeone101/holoitemsapi/enchantment/Enchantable.java @@ -1,5 +1,8 @@ package com.strangeone101.holoitemsapi.enchantment; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; @@ -8,11 +11,21 @@ */ public interface Enchantable { + /** + * Returns the key used by the custom enchantment. + * @return The NamespacedKey + */ + public NamespacedKey getEnchantmentKey(); + /** * Returns the enchantment the custom item uses. * @return The enchantment. */ - public Enchantment getEnchantment(); + public default Enchantment getEnchantment() { + return RegistryAccess.registryAccess() + .getRegistry(RegistryKey.ENCHANTMENT) + .get(getEnchantmentKey()); + } /** * Applies the enchantment to the itemstack. diff --git a/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantmentAbility.java b/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantmentAbility.java index fcc8beb5..9a01c528 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantmentAbility.java +++ b/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantmentAbility.java @@ -9,7 +9,7 @@ import org.bukkit.event.player.PlayerToggleSneakEvent; import org.bukkit.inventory.ItemStack; -public interface EnchantmentAbility extends Keyed { +public interface EnchantmentAbility { default void onBlockBreak(BlockBreakEvent event, ItemStack itemStack) { } diff --git a/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantmentListener.java b/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantmentListener.java index 5e662b18..20bb47ad 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantmentListener.java +++ b/src/main/java/com/strangeone101/holoitemsapi/enchantment/EnchantmentListener.java @@ -3,6 +3,7 @@ import java.util.function.Consumer; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.entity.ThrowableProjectile; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -13,15 +14,29 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerToggleSneakEvent; import org.bukkit.inventory.ItemStack; +import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; public class EnchantmentListener implements Listener { - private static void forEachEnchantment(final ItemStack itemStack, + private HoloItemsRevamp plugin; + private EnchantManager manager; + + public EnchantmentListener(HoloItemsRevamp plugin) { + this.plugin = plugin; + this.manager = this.plugin.getEnchantManager(); + } + + private void forEachEnchantment(final ItemStack itemStack, final Consumer action) { itemStack.getEnchantments().keySet().forEach(enchantment -> { - if (enchantment instanceof EnchantmentAbility ability) { - action.accept(ability); + NamespacedKey enchKey = enchantment.getKey(); + var ench = manager.getByKey(enchKey); + if(ench != null) { + action.accept(ench); } +// if (enchantment instanceof EnchantmentAbility ability) { +// action.accept(ability); +// } }); } diff --git a/src/main/java/com/strangeone101/holoitemsapi/item/CustomItem.java b/src/main/java/com/strangeone101/holoitemsapi/item/CustomItem.java index aa9627f5..b42968ec 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/item/CustomItem.java +++ b/src/main/java/com/strangeone101/holoitemsapi/item/CustomItem.java @@ -34,6 +34,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.format.NamedTextColor; +import org.jetbrains.annotations.Nullable; import xyz.holocons.mc.holoitemsrevamp.Util; /** @@ -49,11 +50,12 @@ public class CustomItem implements Keyed { private Component displayName; private List lore; private int cooldown = 0; - private boolean stackable = true; + private Integer stackSize = null; private Set> properties = new HashSet<>(); private Set> statGoals; private int hex; private ItemFlag[] flags; + private boolean bookLike; private Map> variables = new HashMap<>(); @@ -77,10 +79,6 @@ public final String getInternalName() { return getKey().getKey(); } - protected Recipe getRecipe() { - return null; - } - /** * Create a new ItemStack for use. NOT for updating existing ones; see updateStack * @param player The player @@ -108,18 +106,17 @@ public ItemStack buildStack(Player player) { if (customModelID != 0) meta.setCustomModelData(customModelID); //Used for resource packs - if (properties.contains(Keys.OWNER) && player != null) { - Keys.OWNER.set(meta.getPersistentDataContainer(), player.getUniqueId()); - } - if (properties.contains(Keys.COOLDOWN)) { Keys.COOLDOWN.set(meta.getPersistentDataContainer(), 0L); } Keys.ITEM_ID.set(meta.getPersistentDataContainer(), getInternalName()); + Keys.BOOK_LIKE.set(meta.getPersistentDataContainer(), this.getBookLike()); // If the item shouldn't be stackable, add a random INTEGER to the NBT - Keys.UNSTACKABLE.set(meta.getPersistentDataContainer(), !isStackable()); + if(this.getStackSize() != null){ + meta.setMaxStackSize(this.getStackSize()); + } if (flags != null && flags.length > 0) meta.addItemFlags(flags); @@ -132,56 +129,6 @@ public ItemStack buildStack(Player player) { return stack; } - public ItemStack updateStack(Player player, ItemStack itemStack) { - var meta = itemStack.getItemMeta(); - - if (getMaterial() != itemStack.getType() && meta instanceof Damageable originalDamageable) { - int damage = originalDamageable.getDamage(); - itemStack = buildStack(player); - meta = itemStack.getItemMeta(); - if (meta instanceof Damageable newDamageable) { - newDamageable.setDamage(damage); - } - } - - if (properties.contains(Keys.OWNER) && player != null) { - var uuid = Keys.OWNER.get(meta.getPersistentDataContainer()); - if (uuid == null) { // There should be a UUID, so we'll add the player's UUID as a failsafe - Keys.OWNER.set(meta.getPersistentDataContainer(), player.getUniqueId()); - } - } - - if (properties.contains(Keys.UNSTACKABLE)) { - if (!Keys.UNSTACKABLE.has(meta.getPersistentDataContainer())) { - Keys.UNSTACKABLE.set(meta.getPersistentDataContainer(), true); - } - } else { - if (Keys.UNSTACKABLE.has(meta.getPersistentDataContainer())) { - Keys.UNSTACKABLE.set(meta.getPersistentDataContainer(), false); - } - } - - var lore = new ArrayList(); - - for (var line : getLore()) { - lore.add(replaceVariables(line, meta.getPersistentDataContainer())); - } - - if (meta instanceof LeatherArmorMeta) { - ((LeatherArmorMeta) meta).setColor(Color.fromRGB(hex)); - } else if (meta instanceof PotionMeta) { - ((PotionMeta) meta).setColor(Color.fromRGB(hex)); - } - - itemStack.setItemMeta(meta); - - if (this instanceof Enchantable enchantable) { - itemStack = enchantable.applyEnchantment(itemStack); - } - - return itemStack; - } - /** * Builds an ItemStack that should only be used for showing an item through an inventory or any other methods * that does not allow the player to use the item. This will add missing statistics to the lore. @@ -211,6 +158,15 @@ public ItemStack buildGuiStack(OfflinePlayer player) { return itemStack; } + /** + * Called by CustomItemManager on every CustomItem. + * If non-null, the recipe is added to the server. + * @return A recipe to add. + */ + protected @Nullable Recipe getRecipe() { + return null; + } + /** * Replaces the string provided with variables * @param component The component @@ -385,20 +341,31 @@ public void register() { } /** - * If the item is stackable - * @return True if stackable + * The stack size of the item, or null if using the default. + * @return the stack size, or null + */ + public Integer getStackSize() { + return stackSize; + } + + /** + * The stack size of the item, or the default stack size if it's not defined. + * @return the stack size */ - public boolean isStackable() { - return stackable && material.getMaxStackSize() != 1; + public int getStackSizeOrDefault() { + // Note: I did it this way because Registry does it this way (though with getOrThrow). + // https://jd.papermc.io/paper/1.21.8/org/bukkit/Registry.html#get(org.bukkit.NamespacedKey) + // I'm not 100% sure if this is the best way, though. + return stackSize != null ? stackSize : material.getMaxStackSize(); } /** - * Whether the item can be stacked - * @param stackable Stackable + * Sets the stack size of the item. Feeding null will reset to the default stack size. + * @param stackSize The new stack size * @return Itself */ - public CustomItem setStackable(boolean stackable) { - this.stackable = stackable; + public CustomItem setStackSize(Integer stackSize) { + this.stackSize = stackSize; return this; } @@ -427,7 +394,7 @@ public String toString() { ", textureID=" + customModelID + ", material=" + material + ", displayName='" + displayName + "\'\u00A7r'" + - ", stackable=" + stackable + + ", stackSize=" + stackSize + ", properties=" + properties + '}'; } @@ -482,4 +449,12 @@ public CustomItem setFlags(ItemFlag... flags) { this.flags = flags; return this; } + + public boolean getBookLike() { + return bookLike; + } + + public void setBookLike(boolean bookLike) { + this.bookLike = bookLike; + } } diff --git a/src/main/java/com/strangeone101/holoitemsapi/item/CustomItemManager.java b/src/main/java/com/strangeone101/holoitemsapi/item/CustomItemManager.java index c2312c06..d4d87437 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/item/CustomItemManager.java +++ b/src/main/java/com/strangeone101/holoitemsapi/item/CustomItemManager.java @@ -3,11 +3,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import com.strangeone101.holoitemsapi.recipe.RecipeManager; +import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; import com.strangeone101.holoitemsapi.Keys; -import com.strangeone101.holoitemsapi.recipe.RecipeManager; /** * A registry for managing all custom items @@ -30,10 +32,12 @@ public static void register(CustomItem item) { CUSTOM_ITEMS.put(item.getInternalName(), item); } - public static void lock() { + public static void lock(RecipeManager manager) { if (!locked) { locked = true; - CUSTOM_ITEMS.values().forEach(item -> RecipeManager.registerRecipe(item.getRecipe())); + CUSTOM_ITEMS.values().stream() + .map(CustomItem::getRecipe) + .forEach(manager::registerRecipe); } } diff --git a/src/main/java/com/strangeone101/holoitemsapi/loot/CustomLootRegistry.java b/src/main/java/com/strangeone101/holoitemsapi/loot/CustomLootRegistry.java index 77d30e37..46cd47bd 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/loot/CustomLootRegistry.java +++ b/src/main/java/com/strangeone101/holoitemsapi/loot/CustomLootRegistry.java @@ -67,7 +67,7 @@ public static void handleDeath(LivingEntity entity, List drops) { if (entity.getKiller() == null) return; Location location = entity.getLocation(); - int looting_mod = entity.getKiller().getInventory().getItemInMainHand().getEnchantmentLevel(Enchantment.LOOT_BONUS_MOBS); + int looting_mod = entity.getKiller().getInventory().getItemInMainHand().getEnchantmentLevel(Enchantment.LOOTING); double luck_mod = entity.getKiller().getAttribute(Attribute.GENERIC_LUCK).getValue(); LootContext.Builder builder = new LootContext.Builder(location); @@ -95,7 +95,7 @@ public static void handleDeath(LivingEntity entity, List drops) { */ public static void handleBlockBreak(BlockBreakEvent event) { if (BLOCK_TABLES.containsKey(event.getBlock().getType())) { - int fortune_mod = event.getPlayer().getInventory().getItemInMainHand().getEnchantmentLevel(Enchantment.LOOT_BONUS_BLOCKS); + int fortune_mod = event.getPlayer().getInventory().getItemInMainHand().getEnchantmentLevel(Enchantment.FORTUNE); double luck_mod = event.getPlayer().getAttribute(Attribute.GENERIC_LUCK).getValue(); boolean silk_mod = event.getPlayer().getInventory().getItemInMainHand().getEnchantmentLevel(Enchantment.SILK_TOUCH) > 0; diff --git a/src/main/java/com/strangeone101/holoitemsapi/recipe/CraftListener.java b/src/main/java/com/strangeone101/holoitemsapi/recipe/CraftListener.java index 516d24a1..ca681278 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/recipe/CraftListener.java +++ b/src/main/java/com/strangeone101/holoitemsapi/recipe/CraftListener.java @@ -1,219 +1,166 @@ package com.strangeone101.holoitemsapi.recipe; +import com.strangeone101.holoitemsapi.enchantment.EnchantManager; import com.strangeone101.holoitemsapi.item.CustomItemManager; -import org.bukkit.entity.Player; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.registry.tag.Tag; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Crafter; +import org.bukkit.enchantments.Enchantment; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.block.CrafterCraftEvent; import org.bukkit.event.inventory.CraftItemEvent; import org.bukkit.event.inventory.PrepareItemCraftEvent; -import org.bukkit.event.player.PlayerRecipeDiscoverEvent; -import org.bukkit.inventory.CraftingInventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.RecipeChoice; -import org.bukkit.inventory.ShapedRecipe; -import org.bukkit.inventory.ShapelessRecipe; -import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.inventory.*; import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; public class CraftListener implements Listener { private final HoloItemsRevamp plugin; + private final RecipeManager recipeManager; + private final EnchantManager enchantManager; public CraftListener(HoloItemsRevamp plugin) { this.plugin = plugin; + this.recipeManager = this.plugin.getRecipeManager(); + this.enchantManager = this.plugin.getEnchantManager(); + } + + @EventHandler + public void onCrafterCraft(CrafterCraftEvent event) { + final var crafter = event.getBlock(); + if(crafter.getState() instanceof Crafter crafterState) { + var crafterInv = crafterState.getInventory(); + var crafterContents = crafterInv.getStorageContents(); + var recipe = event.getRecipe(); + var validCraft = checkRecipeCustomItems(crafterContents, recipe); + event.setCancelled(!validCraft); + } + else { + // ... crafter.getState() wasn't a Crafter state? + // just gonna cancel the event to be safe + event.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true) + public void onCraft(CraftItemEvent event) { + // Shouldn't even fire if PrepareItemCraftEvent fired properly, + // but I'm checking again in here just in case. + var contents = event.getInventory().getStorageContents(); + var recipe = event.getRecipe(); + var valid = checkRecipeCustomItems(Arrays.copyOfRange(contents, 1, 10), recipe); + event.setCancelled(!valid); } @EventHandler(ignoreCancelled = true) - public void onCraftItem(CraftItemEvent event) { - ItemStack stack = event.getCurrentItem(); - if (CustomItemManager.isCustomItem(event.getCurrentItem()) && event.getWhoClicked() instanceof Player) { - //Makes the output a fresh build of the item. Means it will be owned by that player - event.setCurrentItem(CustomItemManager.getCustomItem(stack).buildStack((Player) event.getWhoClicked())); + public void onPrepareCraft(PrepareItemCraftEvent event) { + var contents = event.getInventory().getStorageContents(); + var recipe = event.getRecipe(); + var valid = checkRecipeCustomItems(Arrays.copyOfRange(contents, 1, 10), recipe); + if(!valid) { + event.getInventory().setResult(null); } + } - if (!RecipeManager.isManagedRecipe(event.getRecipe())) { - for (ItemStack ingredient : event.getInventory().getMatrix()) { - if (CustomItemManager.isCustomItem(ingredient)) { - event.setCancelled(true); - } + /** + * Checks the custom items in a recipe. If there are custom items where they aren't allowed, returns false. + * Otherwise, returns true. + * @return Whether the recipe is valid/okay. + */ + private boolean checkRecipeCustomItems(ItemStack[] contents, Recipe recipe) { + final List customItemIndices = new ArrayList<>(); + for (int i = 0; i < contents.length; i++) { + var stack = contents[i]; + if(stack == null) { + continue; } - } else if (RecipeManager.isHiddenRecipe(event.getRecipe())) { - RecipeBuilder.AdvancedRecipe recipe = RecipeManager.getAdvancedFromDummy(event.getRecipe()); - boolean notMatch = false; - - if (recipe instanceof RecipeBuilder.AdvancedShape) { - RecipeBuilder.AdvancedShape advancedShape = (RecipeBuilder.AdvancedShape) recipe; - CraftingInventory craftingInventory = event.getInventory(); - int size = craftingInventory.getSize() == 9 ? 3 : 2; - int offset = 0; - outter: - for (int row = 0; row < size; row++) { - for (int col = 0; col < size; col++) { - int currIndex = row * size + col; - if (craftingInventory.getMatrix()[currIndex] != null) { - offset = currIndex - advancedShape.getFirstNotEmpty(); - break outter; - } - } - } - String[] shape = advancedShape.getShape(); - ItemStack[] matrix = craftingInventory.getMatrix(); - outter: - for (int row = 0; row < shape.length; row++) { - for (int col = 0; col < shape[row].length(); col++) { - int matrixNum = offset + (row * 3) + col; - if (shape[row].charAt(col) == ' ') { - if (matrix[matrixNum] != null) { - notMatch = true; - break outter; - } - } else { - ItemStack craftingStack = matrix[matrixNum]; - if (!advancedShape.checkStack(shape[row].charAt(col), craftingStack)) { - notMatch = true; - break outter; - } - } - } - } + if(CustomItemManager.isCustomItem(stack)) { + customItemIndices.add(i); } - if (!notMatch) { - ItemStack updated = recipe.getCraftModifier().create(event.getInventory().getResult(), - recipe.getInputItems(event.getInventory()), recipe.buildContext(event.getInventory(), event.getClick())); - - event.getInventory().setResult(updated); - } else { - event.setCancelled(true); + // ... Depending on SandPortal's implementation, this might be relevant? + // Mostly for stopping people from making sandstone blocks with them. + boolean hasCustomEnchantments = stack + .getEnchantments().keySet().stream().anyMatch(enchantManager::isTaggedHoloEnchantment); + if(hasCustomEnchantments) { + // There might be a use for this that isn't just "Recipe is automatically invalid" + // but for now I'm leaving it like this. + return false; } - } else if (RecipeManager.isAdvancedRecipe(event.getRecipe())) { - RecipeBuilder.AdvancedRecipe advRecipe = RecipeManager.getAdvancedRecipe(event.getRecipe()); - - ItemStack updated = advRecipe.getCraftModifier().create(event.getInventory().getResult(), - advRecipe.getInputItems(event.getInventory()), advRecipe.buildContext(event.getInventory(), event.getClick())); - - event.getInventory().setResult(updated); - event.setCurrentItem(updated); } - if (RecipeManager.hasNonConsumable(event.getRecipe())) { - Map slots = new HashMap<>(); - for (int slot = 0; slot < event.getInventory().getSize(); slot++) { - ItemStack slotItem = event.getInventory().getItem(slot); - - if (event.getRecipe() instanceof ShapedRecipe) { - for (RecipeChoice choice : ((ShapedRecipe) event.getRecipe()).getChoiceMap().values()) { - if (choice instanceof NonConsumableChoice && choice.test(slotItem)) { - slots.put(slot, slotItem.clone()); - if (event.isShiftClick()) { //If they shift click, - slotItem.setAmount(64); //Allow it to craft as many as possible - event.getInventory().setItem(slot, slotItem); - } - } - } - } else if (event.getRecipe() instanceof ShapelessRecipe) { - for (RecipeChoice choice : ((ShapelessRecipe) event.getRecipe()).getChoiceList()) { - if (choice instanceof NonConsumableChoice && choice.test(slotItem)) { - slots.put(slot, slotItem.clone()); - if (event.isShiftClick()) { //If they shift click, - slotItem.setAmount(64); //Allow it to craft as many as possible - event.getInventory().setItem(slot, slotItem); - } - } - } - } - } + if(customItemIndices.isEmpty()) { + // no custom items in recipe so automatically valid + // at least, by this check + return true; + } - //1 tick later, restore the items that were removed - if (slots.size() > 0) { - new BukkitRunnable() { - @Override - public void run() { - for (int slot : slots.keySet()) { - event.getInventory().setItem(slot, slots.get(slot)); - } - } - }.runTaskLater(plugin, 1L); - } + var registeredRecipe = recipeManager.getRegisteredRecipe(recipe); + if(registeredRecipe == null) { + // recipe is not registered but there's custom items + return false; } - } - @EventHandler - public void onPrepareItemCraft(PrepareItemCraftEvent event) { - if (!RecipeManager.isManagedRecipe(event.getRecipe())) { - for (ItemStack ingredient : event.getInventory().getMatrix()) { - if (CustomItemManager.isCustomItem(ingredient)) { - event.getInventory().setResult(null); //Stops recipes using our custom items + /* + The code below was made because I assumed when an event returns a Recipe, it returns the original recipe + THIS IS NOT THE CASE. The RecipeChoices I was getting were exclusively ExactChoice and MaterialChoice, even + if one of them was originally a CustomItemRecipeChoice. + + RecipeManager was made after the code below was made - but I've left it here, so that we can still use + MaterialChoice in other CustomItems. Ex: use Material.TINTED_GLASS for lunarlaser without having to explicitly + state "and NOT the Reading Glasses holoitem" + + As a result, this is tested code, but I didn't get to thoroughly test it. I've only left it here instead of + replacing it with "return true;" because I think this will be useful in the future, I just don't know when. + */ + if(registeredRecipe instanceof ShapedRecipe shapedRecipe) { + // needed so that if a 2x2 recipe is in the bottom-right + // it gets "moved" to the top-left + int minRow = 2; + int minCol = 2; + + for (int i = 0; i < contents.length; i++) { + var stack = contents[i]; + if(stack.isEmpty()) { + int row = i/3; + int col = i%3; + minRow = Math.min(row, minRow); + minCol = Math.min(col, minCol); } } - } else if (RecipeManager.isHiddenRecipe(event.getRecipe())) { - RecipeBuilder.AdvancedRecipe recipe = RecipeManager.getAdvancedFromDummy(event.getRecipe()); - boolean notMatch = false; - - if (recipe instanceof RecipeBuilder.AdvancedShape) { - RecipeBuilder.AdvancedShape advancedShape = (RecipeBuilder.AdvancedShape) recipe; - CraftingInventory craftingInventory = event.getInventory(); - int size = craftingInventory.getSize() == 9 ? 3 : 2; - int offset = 0; - outter: - for (int row = 0; row < size; row++) { - for (int col = 0; col < size; col++) { - int currIndex = row * size + col; - if (craftingInventory.getMatrix()[currIndex] != null) { - offset = currIndex - advancedShape.getFirstNotEmpty(); - break outter; - } - } - } - String[] shape = advancedShape.getShape(); - ItemStack[] matrix = craftingInventory.getMatrix(); - outter: - for (int row = 0; row < shape.length; row++) { - for (int col = 0; col < shape[row].length(); col++) { - int matrixNum = offset + (row * 3) + col; - if (shape[row].charAt(col) == ' ') { - if (matrix[matrixNum] != null) { - notMatch = true; - break outter; - } - } else { - ItemStack craftingStack = matrix[matrixNum]; - if (!advancedShape.checkStack(shape[row].charAt(col), craftingStack)) { - notMatch = true; - break outter; - } - } - } + for(Integer customItemIndex : customItemIndices) { + int row = (customItemIndex/3) - minRow; + int col = (customItemIndex%3) - minCol; + Character choiceChar = shapedRecipe.getShape()[row].charAt(col); + var choice = shapedRecipe.getChoiceMap().get(choiceChar); + if(!(choice instanceof CustomItemRecipeChoice)) { + // this is a non-custom-item slot with a custom item in it + return false; } } - - if (!notMatch) { - ItemStack updated = recipe.getPreviewModifier().create(event.getInventory().getResult(), - recipe.getInputItems(event.getInventory()), recipe.buildContext(event.getInventory(), null)); - - event.getInventory().setResult(updated); - } else { - event.getInventory().setResult(null); - } - } else if (RecipeManager.isAdvancedRecipe(event.getRecipe())) { - RecipeBuilder.AdvancedRecipe advRecipe = RecipeManager.getAdvancedRecipe(event.getRecipe()); - - ItemStack updated = advRecipe.getPreviewModifier().create(event.getInventory().getResult(), - advRecipe.getInputItems(event.getInventory()), advRecipe.buildContext(event.getInventory(), null)); - - event.getInventory().setResult(updated); + // all slots passed + return true; } - } - - @EventHandler - public void onPlayerRecipeDiscover(PlayerRecipeDiscoverEvent event) { - if (RecipeManager.isHiddenRecipe(event.getRecipe())) { - event.setCancelled(true); + else { + // TODO: Implement ShapelessRecipe checks. + // Recipe is not an instance of CraftingRecipe + // uh, maybe it's a furnace recipe (i know emerald leaf or whatever gnaw requires is a furnace recipe) + // either way, point is it's not implemented + plugin.getLogger().warning("CraftListener.checkRecipeCustomItems called with unknown recipe type"); + plugin.getLogger().warning("Recipe class: " + recipe.getClass().toGenericString()); + plugin.getLogger().warning("Recipe toString value: " + recipe); + return false; } } } diff --git a/src/main/java/com/strangeone101/holoitemsapi/recipe/ItemGroups.java b/src/main/java/com/strangeone101/holoitemsapi/recipe/ItemGroups.java deleted file mode 100644 index 270d05ea..00000000 --- a/src/main/java/com/strangeone101/holoitemsapi/recipe/ItemGroups.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.strangeone101.holoitemsapi.recipe; - -import org.bukkit.Material; - -public class ItemGroups { - - public static final Material[] DYES = {Material.RED_DYE, Material.ORANGE_DYE, Material.YELLOW_DYE, Material.LIME_DYE, - Material.GREEN_DYE, Material.CYAN_DYE, Material.LIGHT_BLUE_DYE, Material.BLUE_DYE, Material.PURPLE_DYE, - Material.MAGENTA_DYE, Material.PINK_DYE, Material.BROWN_DYE, Material.WHITE_DYE, Material.GRAY_DYE, - Material.LIGHT_GRAY_DYE, Material.BLACK_DYE - }; -} diff --git a/src/main/java/com/strangeone101/holoitemsapi/recipe/NonConsumableChoice.java b/src/main/java/com/strangeone101/holoitemsapi/recipe/NonConsumableChoice.java deleted file mode 100644 index a371e926..00000000 --- a/src/main/java/com/strangeone101/holoitemsapi/recipe/NonConsumableChoice.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.strangeone101.holoitemsapi.recipe; - -/** - * A recipe choice item that will not be consumed in recipes. Like how - * milk buckets do not consume the bucket when used in crafting - */ -public class NonConsumableChoice extends CustomItemRecipeChoice { - - public NonConsumableChoice(String... ids) { - super(ids); - } - -} diff --git a/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeBuilder.java b/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeBuilder.java deleted file mode 100644 index 631f032a..00000000 --- a/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeBuilder.java +++ /dev/null @@ -1,406 +0,0 @@ -package com.strangeone101.holoitemsapi.recipe; - -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.inventory.CraftingInventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.RecipeChoice; -import org.bukkit.inventory.ShapedRecipe; -import org.bukkit.inventory.ShapelessRecipe; -import org.bukkit.inventory.meta.ItemMeta; - -import com.strangeone101.holoitemsapi.item.CustomItemManager; - -import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; - -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; - -public class RecipeBuilder { - - public static class Shaped { - - private ShapedRecipe recipe; - private Map ingredients = new HashMap<>(); - private Map riingredients = new HashMap<>(); - private String[] shape; - - public Shaped(NamespacedKey key, ItemStack stack) { - this.recipe = new ShapedRecipe(key, stack); - } - - public Shaped setIngredient(char character, Material material) { - ingredients.put(character, new ItemStack(material)); - return this; - } - - public Shaped setIngredient(char character, ItemStack stack) { - ingredients.put(character, stack); - return this; - } - - public Shaped setIngredient(char character, RecipeChoice recipeChoice) { - riingredients.put(character, recipeChoice); - return this; - } - - public Shaped setShape(String... shape) { - this.shape = shape; - return this; - } - - public ShapedRecipe build() { - if (shape == null) throw new NoSuchElementException("Shape was not provided!"); - - if (ingredients.size() == 0 && riingredients.size() == 0) { - throw new NoSuchElementException("No ingredients provided!"); - } - - recipe.shape(shape); - - for (Character c : ingredients.keySet()) { - recipe.setIngredient(c, new RecipeChoice.ExactChoice(ingredients.get(c))); - } - - for (Character c : riingredients.keySet()) { - recipe.setIngredient(c, riingredients.get(c)); - } - - return recipe; - } - - public ShapedRecipe buildRegister() { - ShapedRecipe recipe = build(); - RecipeManager.registerRecipe(recipe); - return recipe; - } - } - - public static class Shapeless { - - private ShapelessRecipe recipe; - private Map ingredients = new HashMap<>(); - private Map riingredients = new HashMap<>(); - private int totalSlots = 0; - - public Shapeless(NamespacedKey key, ItemStack stack) { - this.recipe = new ShapelessRecipe(key, stack); - } - - public Shapeless addIngredient(Material material) { - ingredients.put(new ItemStack(material), 1); - totalSlots++; - return this; - } - - public Shapeless addIngredient(ItemStack stack) { - ingredients.put(stack, 1); - totalSlots++; - return this; - } - - public Shapeless addIngredient(RecipeChoice recipeChoice) { - riingredients.put(recipeChoice, 1); - totalSlots++; - return this; - } - - public Shapeless addIngredient(Material material, int amount) { - ingredients.put(new ItemStack(material), amount); - totalSlots += amount; - return this; - } - - public Shapeless addIngredient(ItemStack stack, int amount) { - ingredients.put(stack, amount); - totalSlots += amount; - return this; - } - - public Shapeless setIngredient(RecipeChoice recipeChoice, int amount) { - riingredients.put(recipeChoice, amount); - totalSlots += amount; - return this; - } - - public ShapelessRecipe build() { - if (totalSlots > 9) throw new NoSuchElementException("Provided more than 9 slots!"); - - if (ingredients.size() == 0 && riingredients.size() == 0) { - throw new NoSuchElementException("No ingredients provided!"); - } - - for (ItemStack stack : ingredients.keySet()) { - for (int i = 0; i < ingredients.get(stack); i++) - recipe.addIngredient(new RecipeChoice.ExactChoice(stack)); - - } - - for (RecipeChoice c : riingredients.keySet()) { - recipe.addIngredient(c); - } - - return recipe; - } - - public ShapelessRecipe buildRegister() { - ShapelessRecipe recipe = build(); - RecipeManager.registerRecipe(recipe); - return recipe; - } - } - - public static class Furnace { - //TODO - } - - public static class AdvancedShape extends AdvancedRecipe { - - private ShapedRecipe recipe; - private Map ingredients = new HashMap<>(); - private Map riingredients = new HashMap<>(); - private Map groups = new HashMap<>(); - private Map indexedGroups = new HashMap<>(); - private String[] shape; - private int firstNotEmpty = -1; - - - public AdvancedShape(String key, ItemStack output) { - super(key, output); - } - - public AdvancedShape setGroupFilter(RecipeGroup group, CustomItemRecipeChoice choice) { - this.filters.put(group, choice); - return this; - } - - // public AdvancedShape setGroupItems(RecipeGroup group, ItemStack... itemstacks) { - // this.filters.put(group, new CustomItemRecipeChoice(itemstacks)); - // return this; - // } - - // public AdvancedShape setGroupItems(RecipeGroup group, Material... materials) { - // ItemStack[] stacks = new ItemStack[materials.length]; - // for (int i = 0; i < materials.length; i++) { - // stacks[i] = new ItemStack(materials[i]); - // } - // this.filters.put(group, new CustomItemRecipeChoice(stacks)); - // return this; - // } - - public AdvancedShape setIngredientGroup(char character, RecipeGroup group) { - this.groups.put(character, group); - return this; - } - - public AdvancedShape setIngredient(char character, Material material) { - ingredients.put(character, new ItemStack(material)); - return this; - } - - public AdvancedShape setIngredient(char character, ItemStack stack) { - ingredients.put(character, stack); - return this; - } - - public AdvancedShape setIngredient(char character, RecipeChoice recipeChoice) { - riingredients.put(character, recipeChoice); - return this; - } - - public AdvancedShape setShape(String... shape) { - this.shape = shape; - return this; - } - - public String[] getShape() { - return this.shape; - } - - public int getFirstNotEmpty() { - return firstNotEmpty; - } - - public boolean checkStack(char ingredientChar, ItemStack stack) { - if (ingredients.containsKey(ingredientChar)) { - if (CustomItemManager.isCustomItem(ingredients.get(ingredientChar)) && CustomItemManager.isCustomItem(stack)) { - return CustomItemManager.getCustomItem(ingredients.get(ingredientChar)).getCustomModelID() == CustomItemManager.getCustomItem(stack).getCustomModelID(); - } else { - return ingredients.get(ingredientChar).isSimilar(stack); - } - } else if (riingredients.containsKey(ingredientChar)) { - return riingredients.get(ingredientChar).test(stack); - } else if (groups.containsKey(ingredientChar)) { - return this.filters.get(groups.get(ingredientChar)).test(stack); - } - return false; - } - - public AdvancedShape previewModifier(RecipeModifier modifier) { - this.preview = modifier; - return this; - } - - public AdvancedShape craftModifier(RecipeModifier modifier) { - this.craft = modifier; - return this; - } - - public AdvancedShape enableRecipeBookPreviews() { - this.previewInRecipeBook = true; - return this; - } - - public ShapedRecipe[] buildRegister(HoloItemsRevamp plugin) { - if (shape == null) throw new NoSuchElementException("Shape was not provided!"); - - if (ingredients.size() == 0 && riingredients.size() == 0 && filters.size() == 0) { - throw new NoSuchElementException("No ingredients provided!"); - } - - if (previewInRecipeBook) { - //TODO Make 20 recipes with different inputs from the groups - //before grouping them together - } else { - ShapedRecipe recipe = new ShapedRecipe(new NamespacedKey(plugin, key), output); - - ItemStack dummyItem = new ItemStack(Material.KNOWLEDGE_BOOK); - ItemMeta dummyMeta = dummyItem.getItemMeta(); - dummyMeta.setDisplayName(recipe.getKey().getKey()); - dummyItem.setItemMeta(dummyMeta); - ShapedRecipe dummyRecipe = new ShapedRecipe(new NamespacedKey(plugin, "__" + key), dummyItem); - - recipe.shape(shape); - dummyRecipe.shape(shape); - - for (Character c : ingredients.keySet()) { - recipe.setIngredient(c, new RecipeChoice.ExactChoice(ingredients.get(c))); - dummyRecipe.setIngredient(c, new RecipeChoice.ExactChoice(ingredients.get(c))); - } - - for (Character c : riingredients.keySet()) { - recipe.setIngredient(c, riingredients.get(c)); - dummyRecipe.setIngredient(c, riingredients.get(c)); - } - - for (Character c : groups.keySet()) { - RecipeGroup g = groups.get(c); - recipe.setIngredient(c, filters.get(g)); //The proper item it accepts - dummyRecipe.setIngredient(c, filters.get(g).getItemStack().getType()); //The dummy item without any NBT - - outter: - for (int row = 0; row < 3 && row < shape.length; row++) { - for (int col = 0; col < 3 && col < shape[row].length(); col++) { - if (shape[row].charAt(col) == c) { - indexedGroups.put((byte) (row * shape.length + col), g); - break outter; - } - } - } - - } - - outter: - for (int row = 0; row < 3 && row < shape.length; row++) { - for (int col = 0; col < 3 && col < shape[row].length(); col++) { - if (shape[row].charAt(col) != ' ') { - firstNotEmpty = row * shape.length + col; - break outter; - } - } - } - - RecipeManager.registerAdvancedRecipe(recipe, dummyRecipe, this); - - return new ShapedRecipe[] {recipe}; - } - - - return null; - } - - @Override - public RecipeContext buildContext(CraftingInventory craftingTable, ClickType type) { - RecipeContext context = new RecipeContext(); - context.setPlayer((Player) craftingTable.getViewers().get(0)); - context.setRecipe(craftingTable.getRecipe()); - context.setLocation(craftingTable.getViewers().get(0).getLocation()); - context.setClickType(type); - context.setWorld(context.getLocation().getWorld()); - - return context; - } - - @Override - public Map getInputItems(CraftingInventory craftingInventory) { - int size = craftingInventory.getSize() == 9 ? 3 : 2; - int offset = 0; - outter: - for (int row = 0; row < size; row++) { - for (int col = 0; col < size; col++) { - int currIndex = row * size + col; - if (craftingInventory.getMatrix()[currIndex] != null) { - offset = currIndex - firstNotEmpty; - break outter; - } - } - } - - Map stacks = new HashMap<>(); - - for (byte index : indexedGroups.keySet()) { - int newIndex = offset + index; - - stacks.put(indexedGroups.get(index), craftingInventory.getMatrix()[newIndex]); - } - - return stacks; - } - - //TODO - } - - public static abstract class AdvancedRecipe { - protected boolean previewInRecipeBook; - protected String key; - protected ItemStack output; - protected RecipeModifier preview, craft = (item, map, context) -> item; - protected Map filters = new HashMap<>(); - - protected AdvancedRecipe(String key, ItemStack output) { - this.key = key; - this.output = output; - } - - public Map getFilters() { - return filters; - } - - public boolean shouldPreviewInRecipeBook() { - return previewInRecipeBook; - } - - public ItemStack getOutput() { - return output; - } - - public RecipeModifier getCraftModifier() { - return craft; - } - - public RecipeModifier getPreviewModifier() { - return preview; - } - - public RecipeContext buildContext(CraftingInventory craftingTable, ClickType click) { - - craftingTable.getMatrix(); - return null; - } - - public abstract Map getInputItems(CraftingInventory craftingInventory); - } -} diff --git a/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeContext.java b/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeContext.java deleted file mode 100644 index bf001729..00000000 --- a/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeContext.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.strangeone101.holoitemsapi.recipe; - -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.inventory.Recipe; - -public class RecipeContext { - - private Player player; - private Location location; - private World world; - private ClickType clickType; - private Recipe recipe; - - public Player getPlayer() { - return player; - } - - public void setPlayer(Player player) { - this.player = player; - } - - public Location getLocation() { - return location; - } - - public void setLocation(Location location) { - this.location = location; - } - - public World getWorld() { - return world; - } - - public void setWorld(World world) { - this.world = world; - } - - public boolean isRightClick() { - return getClickType().isRightClick(); - } - - public boolean isShiftClick() { - return getClickType().isShiftClick(); - } - - public Recipe getRecipe() { - return recipe; - } - - public void setRecipe(Recipe recipe) { - this.recipe = recipe; - } - - public ClickType getClickType() { - return clickType; - } - - public void setClickType(ClickType clickType) { - this.clickType = clickType; - } -} diff --git a/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeGroup.java b/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeGroup.java deleted file mode 100644 index 12d6fcb6..00000000 --- a/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeGroup.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.strangeone101.holoitemsapi.recipe; - -public enum RecipeGroup { - GROUP_1, GROUP_2, GROUP_3, - GROUP_4, GROUP_5, GROUP_6, - GROUP_7, GROUP_8, GROUP_9 -} diff --git a/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeManager.java b/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeManager.java index 618a02ac..fceef765 100644 --- a/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeManager.java +++ b/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeManager.java @@ -4,170 +4,56 @@ import org.bukkit.Keyed; import org.bukkit.NamespacedKey; import org.bukkit.inventory.Recipe; -import org.bukkit.inventory.RecipeChoice; -import org.bukkit.inventory.ShapedRecipe; -import org.bukkit.inventory.ShapelessRecipe; -import org.bukkit.inventory.SmithingRecipe; +import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; -import java.io.InvalidObjectException; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; -/** - * Manages all custom recipes used with custom items - */ public class RecipeManager { - private static Map recipes = new HashMap<>(); - private static Map advanced = new HashMap<>(); - private static Set nonConsumableRecipes = new HashSet<>(); + private final HoloItemsRevamp plugin; + private final Map recipeMap = new HashMap<>(); - private static Map dummyToAdvancedMap = new HashMap<>(); //Map of all dummy recipes to the advanced recipe - - /** - * Get a recipe - * @param key The namespace key - * @return The recipe - */ - public static Recipe getRecipe(NamespacedKey key) { - return recipes.get(key); + public RecipeManager(HoloItemsRevamp plugin) { + this.plugin = plugin; } /** - * Register a custom recipe - * @param recipe The recipe + * Registers a recipe in this RecipeManager. Doing this also registers the recipe using Bukkit::addRecipe */ - public static void registerRecipe(Recipe recipe) { - if (recipe == null) { + public void registerRecipe(Recipe recipe) { + if(recipe == null) { return; } - if (!(recipe instanceof Keyed)) { - try { - throw new InvalidObjectException("Recipe of type " + recipe.getClass().getName() + " does not contain a NameSpace key! Use RecipeManager#registerRecipe(recipe, key) instead!"); - } catch (InvalidObjectException e) { - e.printStackTrace(); - return; - } + if(recipe instanceof Keyed keyed) { + var key = keyed.getKey(); + recipeMap.put(key, recipe); + Bukkit.addRecipe(recipe); } - registerRecipe(recipe, ((Keyed)recipe).getKey()); - } - - /** - * Register a custom recipe - * @param recipe The recipe - * @param key The namespace key - */ - public static void registerRecipe(Recipe recipe, NamespacedKey key) { - recipes.put(key, recipe); - if (Bukkit.getRecipe(key) != null) { - Bukkit.removeRecipe(key); + else { + // This is possible for a MerchantRecipe. + throw new IllegalArgumentException( + "Can't register a recipe that doesn't have a NamespacedKey. Recipe:" + recipe); } - Bukkit.addRecipe(recipe); - - if (recipe instanceof ShapedRecipe) { - for (RecipeChoice choice : ((ShapedRecipe) recipe).getChoiceMap().values()) { - if (choice instanceof NonConsumableChoice) - nonConsumableRecipes.add(recipe); - break; - } - } else if (recipe instanceof ShapelessRecipe) { - for (RecipeChoice choice : ((ShapelessRecipe) recipe).getChoiceList()) { - if (choice instanceof NonConsumableChoice) - nonConsumableRecipes.add(recipe); - break; - } - } else if (recipe instanceof SmithingRecipe) { - if (((SmithingRecipe) recipe).getAddition() instanceof NonConsumableChoice || - ((SmithingRecipe) recipe).getBase() instanceof NonConsumableChoice) - nonConsumableRecipes.add(recipe); - - - } - } - - public static void registerAdvancedRecipe(Recipe recipe, Recipe dummyRecipe, RecipeBuilder.AdvancedRecipe advancedShape) { - registerRecipe(recipe); - registerRecipe(dummyRecipe); - advanced.put(((Keyed) recipe).getKey(), advancedShape); - dummyToAdvancedMap.put(((Keyed) dummyRecipe).getKey(), ((Keyed) recipe).getKey()); - } - - public static boolean isAdvancedRecipe(Recipe recipe) { - if (recipe instanceof Keyed) - return advanced.containsKey(((Keyed) recipe).getKey()); - return false; - } - - public static boolean isHiddenRecipe(NamespacedKey key) { - return dummyToAdvancedMap.containsKey(key); - } - - public static boolean isHiddenRecipe(Recipe recipe) { - if (recipe instanceof Keyed) - return dummyToAdvancedMap.containsKey(((Keyed) recipe).getKey()); - return false; - } - - public static RecipeBuilder.AdvancedRecipe getAdvancedRecipe(Recipe recipe) { - if (recipe instanceof Keyed) - return advanced.get(((Keyed) recipe).getKey()); - return null; - } - - public static RecipeBuilder.AdvancedRecipe getAdvancedRecipe(NamespacedKey recipe) { - return advanced.get(recipe); - } - - public static RecipeBuilder.AdvancedRecipe getAdvancedFromDummy(Recipe recipe) { - return advanced.get(dummyToAdvancedMap.get(((Keyed) recipe).getKey())); } /** - * Add a recipe to the registry WITHOUT registering it - * @param recipe The recipe - * @param key The namespace key + * Gets a recipe that's been registered in this RecipeManager */ - public static void addRecipe(Recipe recipe, NamespacedKey key) { - recipes.put(key, recipe); + public Recipe getRegisteredRecipe(NamespacedKey key) { + return this.recipeMap.get(key); } /** - * Unregister all recipes registered. Internal use only. + * Gets a recipe that's been registered in this RecipeManager. This difference between the recipe returned + * by this and the parameter recipe is that the original recipe may have lost its CustomItemRecipeChoice values. */ - public static void unregisterAll() { - for (NamespacedKey key : recipes.keySet()) { - Bukkit.removeRecipe(key); + public Recipe getRegisteredRecipe(Recipe recipe) { + if(recipe instanceof Keyed key) { + return getRegisteredRecipe(key.getKey()); + } + else { + return null; } - } - - /** - * Get whether the recipe is managed by the registry or not - * @param recipe The recipe - * @return True if handled - */ - public static boolean isManagedRecipe(Recipe recipe) { - if (recipe instanceof Keyed) - return recipes.containsKey(((Keyed) recipe).getKey()); - return false; - } - - /** - * Get how many recipes are managed - * @return The amount - */ - public static int getRegisteredAmount() { - return recipes.size(); - } - - /** - * Gets whether the recipe contains an ingredient that shouldn't - * be consumed on use - * @param recipe The recipe - * @return True if it does - */ - public static boolean hasNonConsumable(Recipe recipe) { - return nonConsumableRecipes.contains(recipe); } } diff --git a/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeModifier.java b/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeModifier.java deleted file mode 100644 index cbb3f902..00000000 --- a/src/main/java/com/strangeone101/holoitemsapi/recipe/RecipeModifier.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.strangeone101.holoitemsapi.recipe; - -import org.bukkit.inventory.ItemStack; - -import java.util.Map; - -public interface RecipeModifier { - - ItemStack create(ItemStack baseOutput, Map filters, RecipeContext context); -} diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/HoloItemsBootstrap.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/HoloItemsBootstrap.java new file mode 100644 index 00000000..76c002d0 --- /dev/null +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/HoloItemsBootstrap.java @@ -0,0 +1,14 @@ +package xyz.holocons.mc.holoitemsrevamp; + +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.bootstrap.PluginBootstrap; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; +import io.papermc.paper.registry.RegistryKey; +import org.jetbrains.annotations.NotNull; + +public class HoloItemsBootstrap implements PluginBootstrap { + @Override + public void bootstrap(@NotNull BootstrapContext context) { + + } +} diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/HoloItemsRevamp.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/HoloItemsRevamp.java index 4ae4d8ca..83415d12 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/HoloItemsRevamp.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/HoloItemsRevamp.java @@ -7,7 +7,9 @@ import com.strangeone101.holoitemsapi.item.BlockListener; import com.strangeone101.holoitemsapi.item.CustomItemManager; import com.strangeone101.holoitemsapi.recipe.CraftListener; +import com.strangeone101.holoitemsapi.recipe.RecipeManager; import com.strangeone101.holoitemsapi.tracking.CustomBlockStorage; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; import org.bukkit.plugin.java.JavaPlugin; import xyz.holocons.mc.holoitemsrevamp.collection.CollectionManager; @@ -17,8 +19,9 @@ public final class HoloItemsRevamp extends JavaPlugin { private CollectionManager collectionManager; - private EnchantManager enchantManager; private CustomBlockStorage trackingManager; + private RecipeManager recipeManager; + private EnchantManager enchantManager; @Override public void onLoad() { @@ -27,23 +30,34 @@ public void onLoad() { this.enchantManager = new EnchantManager(this); this.collectionManager = new CollectionManager(this); this.trackingManager = new CustomBlockStorage(this); + this.recipeManager = new RecipeManager(this); Integrations.onLoad(); } + // This is for the (numerous) Lifecycle functions, which are all marked Experimental in 1.21.1, but + // are no longer marked as such in later versions. + @SuppressWarnings("UnstableApiUsage") @Override public void onEnable() { Integrations.onEnable(); - CustomItemManager.lock(); + CustomItemManager.lock(getRecipeManager()); trackingManager.loadTrackedBlocks(); - getServer().getPluginManager().registerEvents(new EnchantmentListener(), this); + getServer().getPluginManager().registerEvents(new EnchantmentListener(this), this); getServer().getPluginManager().registerEvents(new AnvilListener(this), this); getServer().getPluginManager().registerEvents(new CraftListener(this), this); getServer().getPluginManager().registerEvents(new BlockListener(this), this); - getCommand("holoitems").setExecutor(new MainCommand(this)); +// getCommand("holoitems").setExecutor(new MainCommand(this)); + var lifecycleManager = this.getLifecycleManager(); + var mainCommand = new MainCommand(this); + lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS, commands -> { + var registrar = commands.registrar(); + registrar.register("holoitems", mainCommand); + }); + getLogger().info("HoloItems-Revamped [ON]"); } @@ -56,11 +70,15 @@ public CollectionManager getCollectionManager() { return collectionManager; } - public EnchantManager getEnchantManager() { - return enchantManager; - } - public CustomBlockStorage getTrackingManager() { return trackingManager; } + + public RecipeManager getRecipeManager() { + return recipeManager; + } + + public EnchantManager getEnchantManager() { + return enchantManager; + } } diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/Util.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/Util.java index be34f24d..e1fec5fa 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/Util.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/Util.java @@ -56,7 +56,8 @@ public static UUID randomUUID() { /** * Returns a player head with the base64 texture. Mostly used for GUI. * - * @param base64 A base 64 string that contains ONLY the texture + * @param url A url from textures.minecraft.net that represents the skin texture, as stored on Mojang servers. + * Read more here. * @return The ItemStack player head */ public static ItemStack getPlayerHeadFromSkinUrl(String url) { diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/MainCommand.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/MainCommand.java index 34a44f0d..48e9ba6a 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/MainCommand.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/MainCommand.java @@ -1,11 +1,14 @@ package xyz.holocons.mc.holoitemsrevamp.command; +import io.papermc.paper.command.brigadier.BasicCommand; +import io.papermc.paper.command.brigadier.CommandSourceStack; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; +import org.apache.commons.lang3.NotImplementedException; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -14,32 +17,28 @@ import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; import xyz.holocons.mc.holoitemsrevamp.command.subcommand.AcquireCommand; import xyz.holocons.mc.holoitemsrevamp.command.subcommand.CollectionsCommand; -import xyz.holocons.mc.holoitemsrevamp.command.subcommand.EnchantCommand; import xyz.holocons.mc.holoitemsrevamp.command.subcommand.StatsCommand; -import java.util.Arrays; -import java.util.List; -import java.util.Set; +import java.util.*; -public class MainCommand implements TabExecutor { - - private final Set subCommands; +public class MainCommand implements BasicCommand { + + // Maps from the name of a subcommand to that subcommand + private final Map subCommands = new HashMap<>(); private final TextComponent helpComponent; public MainCommand(HoloItemsRevamp plugin) { - this.subCommands = Set.of( - new AcquireCommand(plugin), - new CollectionsCommand(plugin), - new StatsCommand(), - new EnchantCommand(plugin) - ); + addSubCommand(new AcquireCommand(plugin)); + addSubCommand(new CollectionsCommand(plugin)); + addSubCommand(new StatsCommand()); + // Create text component message for help page final var helpComponentBuilder = Component.text() .append(Component.text("=====", NamedTextColor.DARK_AQUA)) .append(Component.text("HoloItems", NamedTextColor.GREEN)) .append(Component.text("======", NamedTextColor.DARK_AQUA)) .append(Component.newline()); - for (var subCommand : subCommands) { + for (var subCommand : subCommands.values()) { helpComponentBuilder.append( Component.text() .append(Component.text("/holoitems ", NamedTextColor.WHITE)) @@ -54,37 +53,50 @@ public MainCommand(HoloItemsRevamp plugin) { } @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if (args.length != 0) { - for (var subCommand : subCommands) { - if (args[0].equalsIgnoreCase(subCommand.getName())) { - if (!subCommand.execute(sender, Arrays.copyOfRange(args, 1, args.length))) { - sender.sendMessage(Component.text("/holoitems " + subCommand.getName() + " " + subCommand.getFormat()) - .decoration(TextDecoration.BOLD, true) - .decoration(TextDecoration.UNDERLINED, true) - .color(NamedTextColor.RED)); - } - return true; - } + public void execute(CommandSourceStack sourceStack, String[] args) { + System.out.println(Arrays.toString(args)); + var sender = sourceStack.getSender(); + if(args.length == 0) { + sender.sendMessage(helpComponent); + return; + } + var subCommand = subCommands.get(args[0]); + if (subCommand != null) { + // found subcommand, attempt to execute: + if (!subCommand.execute(sender, Arrays.copyOfRange(args, 1, args.length))) { + sender.sendMessage(Component.text("/holoitems " + subCommand.getName() + " " + subCommand.getFormat()) + .decoration(TextDecoration.BOLD, true) + .decoration(TextDecoration.UNDERLINED, true) + .color(NamedTextColor.RED)); } - // If no subCommands matched... + } + else { + // no found subcommand: sender.sendMessage(Component.text("Command not found!", NamedTextColor.RED).decoration(TextDecoration.BOLD, true)); } - sender.sendMessage(helpComponent); - return true; } @Override - public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { + public @NotNull Collection suggest(CommandSourceStack sourceStack, String[] args) { if (args.length <= 1) { - return subCommands.stream().map(SubCommand::getName).toList(); + return subCommands.keySet(); } else { - for (var subCommand : subCommands) { - if (args[0].equalsIgnoreCase(subCommand.getName())) { - return subCommand.getAutoComplete(Arrays.copyOfRange(args, 1, args.length)); - } + var subCommand = subCommands.get(args[0]); + if(subCommand == null) { + return List.of(); + } + else { + return subCommand.getAutoComplete(Arrays.copyOfRange(args, 1, args.length)); } } - return null; + } + + @Override + public boolean canUse(CommandSender sender) { + return true; + } + + private void addSubCommand(SubCommand subCommand) { + this.subCommands.put(subCommand.getName(), subCommand); } } diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/subcommand/AcquireCommand.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/subcommand/AcquireCommand.java index 9077c951..6f80c8f9 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/subcommand/AcquireCommand.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/subcommand/AcquireCommand.java @@ -99,15 +99,20 @@ public boolean execute(CommandSender sender, String[] args) { } var itemStack = customItem.buildStack(player); - Map leftoverItems; - if (customItem.isStackable()) { - itemStack.setAmount(amount); - leftoverItems = player.getInventory().addItem(itemStack); - } else { - var itemStacks = new ItemStack[amount]; - Arrays.fill(itemStacks, itemStack); - leftoverItems = player.getInventory().addItem(itemStacks); - } + itemStack.setAmount(customItem.getStackSizeOrDefault()); + + int totalItemStacks = ((amount - 1)/customItem.getStackSizeOrDefault()) + 1; + int lastItemStackSize = amount - ((totalItemStacks - 1) * customItem.getStackSizeOrDefault()); + // Failsafe incase my math was bad (it was one time lol) + lastItemStackSize = Math.clamp(0, lastItemStackSize, customItem.getStackSizeOrDefault()); + ItemStack lastItemStack = itemStack.clone(); + lastItemStack.setAmount(lastItemStackSize); + + var itemStacks = new ItemStack[totalItemStacks]; + Arrays.fill(itemStacks, itemStack); + itemStacks[totalItemStacks - 1] = lastItemStack; + + Map leftoverItems = player.getInventory().addItem(itemStacks); // If items could not fit in player's inventory, drop them in the world leftoverItems.values().forEach(item -> player.getWorld().dropItemNaturally(player.getLocation(), item)); diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/subcommand/EnchantCommand.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/subcommand/EnchantCommand.java deleted file mode 100644 index 12c16f21..00000000 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/command/subcommand/EnchantCommand.java +++ /dev/null @@ -1,102 +0,0 @@ -package xyz.holocons.mc.holoitemsrevamp.command.subcommand; - -import org.bukkit.NamespacedKey; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; -import xyz.holocons.mc.holoitemsrevamp.command.SubCommand; - -import java.util.List; - -public class EnchantCommand implements SubCommand { - - private final HoloItemsRevamp plugin; - - public EnchantCommand(HoloItemsRevamp plugin) { - this.plugin = plugin; - } - - @Override - public String getName() { - return "enchant"; - } - - @Override - public String getDesc() { - return "Enchants an item in your hand"; - } - - @Override - public String getFormat() { - return " [level]"; - } - - @Override - public String getPermission() { - return "holoitems.enchant"; - } - - @Override - public List getAutoComplete(String[] args) { - return switch (args.length) { - case 1 -> plugin.getEnchantManager().enchantmentNames(); - default -> List.of(); - }; - } - - @Override - public boolean execute(CommandSender sender, String[] args) { - if (!(sender instanceof Player player)) { - sender.sendMessage("Do not use this command as console."); - return true; - } - - if (!player.hasPermission(getPermission())) { - player.sendMessage("You do not have the permission to use this command!"); - return true; - } - - if (args.length < 1) { - player.sendMessage("Not enough arguments"); - return false; - } - - var itemStack = player.getInventory().getItemInMainHand(); - var itemMeta = itemStack.getItemMeta(); - - if (itemMeta == null) { - player.sendMessage(Component.translatable("commands.enchant.failed.itemless", NamedTextColor.RED, Component.text(player.getName()))); - return true; - } - - var key = NamespacedKey.fromString(args[0], plugin); - var customEnchantment = CustomEnchantment.getByKey(key); - - if (customEnchantment == null) { - player.sendMessage(args[0] + " is not a valid enchantment!"); - return false; - } - - int level; - try { - level = Integer.parseInt(args[1]); - } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { - level = customEnchantment.getStartLevel(); - } - - if (itemMeta.addEnchant(customEnchantment, level, false)) { - itemStack.setItemMeta(itemMeta); - plugin.getEnchantManager().removeCustomEnchantmentLore(itemStack); - plugin.getEnchantManager().applyCustomEnchantmentLore(itemStack); - player.sendMessage("Enchanted!"); - } else { - player.sendMessage("Could not set enchant!"); - } - return true; - } -} diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Backdash.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Backdash.java index 9c30dd61..056cda7f 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Backdash.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Backdash.java @@ -1,45 +1,21 @@ package xyz.holocons.mc.holoitemsrevamp.enchantment; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.enchantments.EnchantmentTarget; +import org.bukkit.NamespacedKey; import org.bukkit.event.player.PlayerToggleSneakEvent; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; import com.strangeone101.holoitemsapi.enchantment.EnchantmentAbility; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.TextDecoration; import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; import xyz.holocons.mc.holoitemsrevamp.integration.Integrations; -public class Backdash extends CustomEnchantment implements EnchantmentAbility { +public class Backdash implements EnchantmentAbility { - public Backdash(HoloItemsRevamp plugin) { - super(plugin, "backdash"); - } - - @Override - public int getMaxLevel() { - return 1; - } - - @Override - public boolean conflictsWith(@NotNull Enchantment other) { - return false; - } + private final HoloItemsRevamp plugin; - @Override - public boolean canEnchantItem(@NotNull ItemStack item) { - return EnchantmentTarget.ARMOR_FEET.includes(item); - } - - @Override - public @NotNull Component displayName(int level) { - return Component.text("Backdash", NamedTextColor.GRAY) - .decoration(TextDecoration.ITALIC, false); + public Backdash(HoloItemsRevamp plugin) { + this.plugin = plugin; } @Override @@ -51,9 +27,4 @@ public void onPlayerToggleSneak(PlayerToggleSneakEvent event, ItemStack itemStac final var player = event.getPlayer(); player.setVelocity(player.getLocation().getDirection().setY(0).normalize().multiply(-1)); } - - @Override - public int getCostMultiplier() { - return Integer.MAX_VALUE; - } } diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Magnet.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Magnet.java index f29b0524..8c76a7fc 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Magnet.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Magnet.java @@ -1,60 +1,25 @@ package xyz.holocons.mc.holoitemsrevamp.enchantment; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.enchantments.EnchantmentTarget; +import org.bukkit.NamespacedKey; import org.bukkit.entity.Item; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; import com.strangeone101.holoitemsapi.enchantment.EnchantmentAbility; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.TextDecoration; import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; import xyz.holocons.mc.holoitemsrevamp.integration.Integrations; -public class Magnet extends CustomEnchantment implements EnchantmentAbility { +public class Magnet implements EnchantmentAbility { private final HoloItemsRevamp plugin; public Magnet(HoloItemsRevamp plugin) { - super(plugin, "magnet"); this.plugin = plugin; } - @Override - public int getMaxLevel() { - return 1; - } - - @Override - public boolean conflictsWith(@NotNull Enchantment other) { - return false; - } - - @Override - public boolean canEnchantItem(@NotNull ItemStack item) { - return EnchantmentTarget.TOOL.includes(item); - } - - @Override - public @NotNull Component displayName(int level) { - return Component.text() - .color(NamedTextColor.GRAY) - .decoration(TextDecoration.ITALIC, false) - .append(Component.text("Magnet")) - .build(); - } - - @Override - public int getCostMultiplier() { - return 12; - } - @Override public void onBlockBreak(BlockBreakEvent event, ItemStack itemStack) { final var location = event.getBlock().getLocation().toCenterLocation(); diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Memento.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Memento.java index 571c2dce..82eff90e 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Memento.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Memento.java @@ -1,54 +1,22 @@ package xyz.holocons.mc.holoitemsrevamp.enchantment; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; +import org.bukkit.NamespacedKey; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; import com.strangeone101.holoitemsapi.enchantment.EnchantmentAbility; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.TextDecoration; import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; import xyz.holocons.mc.holoitemsrevamp.integration.Integrations; -public class Memento extends CustomEnchantment implements EnchantmentAbility { +public class Memento implements EnchantmentAbility { - public Memento(HoloItemsRevamp plugin) { - super(plugin, "memento"); - } - - @Override - public int getMaxLevel() { - return 1; - } - - @Override - public boolean conflictsWith(@NotNull Enchantment other) { - return true; - } + private final HoloItemsRevamp plugin; - @Override - public boolean canEnchantItem(@NotNull ItemStack item) { - return item.getType() == Material.ENDER_CHEST; - } - - @Override - public @NotNull Component displayName(int level) { - return Component.text() - .color(NamedTextColor.DARK_PURPLE) - .decoration(TextDecoration.ITALIC, false) - .append(Component.text("Memento")) - .build(); - } - - @Override - public int getCostMultiplier() { - return Integer.MAX_VALUE; + public Memento(HoloItemsRevamp plugin) { + this.plugin = plugin; } @Override diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Plow.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Plow.java index 3247a602..fc4b4fd9 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Plow.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/Plow.java @@ -1,59 +1,26 @@ package xyz.holocons.mc.holoitemsrevamp.enchantment; import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; +import org.bukkit.NamespacedKey; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import com.destroystokyo.paper.MaterialTags; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; import com.strangeone101.holoitemsapi.enchantment.EnchantmentAbility; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.TextDecoration; import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; import xyz.holocons.mc.holoitemsrevamp.util.EntityExpiringSet; import xyz.holocons.mc.holoitemsrevamp.util.ExpiringSet; -public class Plow extends CustomEnchantment implements EnchantmentAbility { +public class Plow implements EnchantmentAbility { + + private final HoloItemsRevamp plugin; private final EntityExpiringSet plowMarker = new EntityExpiringSet( new ExpiringSet.ConstantTicksToLiveExpirationPolicy<>(20)); public Plow(HoloItemsRevamp plugin) { - super(plugin, "plow"); - } - - @Override - public int getMaxLevel() { - return 1; - } - - @Override - public boolean conflictsWith(@NotNull Enchantment enchantment) { - return false; - } - - @Override - public boolean canEnchantItem(@NotNull ItemStack itemStack) { - return MaterialTags.SHOVELS.isTagged(itemStack); - } - - @Override - public @NotNull Component displayName(int i) { - return Component.text() - .color(NamedTextColor.GRAY) - .decoration(TextDecoration.ITALIC, false) - .append(Component.text("Plow")) - .build(); - } - - @Override - public int getCostMultiplier() { - // Copied from Magnet - return 12; + this.plugin = plugin; } @Override diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/TideRider.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/TideRider.java index 9f3c56f5..2bed6037 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/TideRider.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/enchantment/TideRider.java @@ -1,11 +1,11 @@ package xyz.holocons.mc.holoitemsrevamp.enchantment; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.Particle; import org.bukkit.Sound; import org.bukkit.block.BlockFace; import org.bukkit.enchantments.Enchantment; -import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; @@ -14,50 +14,19 @@ import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; import com.strangeone101.holoitemsapi.enchantment.EnchantmentAbility; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.TextDecoration; import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; import xyz.holocons.mc.holoitemsrevamp.integration.Integrations; -public class TideRider extends CustomEnchantment implements EnchantmentAbility { +public class TideRider implements EnchantmentAbility { private final HoloItemsRevamp plugin; public TideRider(HoloItemsRevamp plugin) { - super(plugin, "tide_rider"); this.plugin = plugin; } - @Override - public int getMaxLevel() { - return 1; - } - - @Override - public boolean conflictsWith(@NotNull Enchantment other) { - return !other.equals(Enchantment.MENDING) && !other.equals(Enchantment.VANISHING_CURSE); - } - - @Override - public boolean canEnchantItem(@NotNull ItemStack item) { - return EnchantmentTarget.TRIDENT.includes(item); - } - - @Override - public @NotNull Component displayName(int level) { - return Component.text("Tide Rider", NamedTextColor.GRAY) - .decoration(TextDecoration.ITALIC, false); - } - - @Override - public int getCostMultiplier() { - return Integer.MAX_VALUE; - } - @Override public void onPlayerInteract(PlayerInteractEvent event, ItemStack itemStack) { final var player = event.getPlayer(); @@ -95,7 +64,7 @@ public void run() { final var location = player.getLocation(); if (elapsedTicks % 2 != 0) { - world.spawnParticle(Particle.WATER_WAKE, location, 80, 0.2, 0.0, 0.2); + world.spawnParticle(Particle.SPLASH, location, 80, 0.2, 0.0, 0.2); } final var direction = location.getDirection().setY(0.0001).normalize(); diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/integration/WorldGuardHook.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/integration/WorldGuardHook.java index 14713f1e..83dd62ec 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/integration/WorldGuardHook.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/integration/WorldGuardHook.java @@ -3,6 +3,7 @@ import java.util.HashMap; import java.util.Map; +import com.strangeone101.holoitemsapi.enchantment.EnchantmentAbility; import org.bukkit.Location; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -10,14 +11,14 @@ import com.sk89q.worldguard.protection.flags.Flag; import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.regions.RegionContainer; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; +import org.bukkit.NamespacedKey; public interface WorldGuardHook extends Hook { - default void registerEnchantment(CustomEnchantment enchantment) { + default void registerEnchantment(NamespacedKey enchKey, EnchantmentAbility enchantment) { } - default boolean canUseEnchantment(Location location, Class enchantmentCls) { + default boolean canUseEnchantment(Location location, Class enchantmentCls) { return true; } @@ -26,7 +27,7 @@ public class Stub implements WorldGuardHook { public class Integration implements WorldGuardHook { - public static final Map, Flag> ENCHANTMENT_FLAGS = new HashMap<>(); + public static final Map, Flag> ENCHANTMENT_FLAGS = new HashMap<>(); private boolean loaded = false; private RegionContainer regionContainer = null; @@ -46,16 +47,16 @@ public void onEnable() { } @Override - public void registerEnchantment(CustomEnchantment enchantment) { + public void registerEnchantment(NamespacedKey enchKey, EnchantmentAbility enchantment) { if (loaded) { throw new IllegalStateException("New enchantments cannot be registered at this time"); } - final var name = "holoitems-" + enchantment.getKey().getKey().replace('_', '-'); + final var name = "holoitems-" + enchKey.getKey().replace('_', '-'); ENCHANTMENT_FLAGS.put(enchantment.getClass(), new StateFlag(name, true)); } @Override - public boolean canUseEnchantment(Location location, Class enchantmentCls) { + public boolean canUseEnchantment(Location location, Class enchantmentCls) { final var flag = ENCHANTMENT_FLAGS.get(enchantmentCls); final var value = regionContainer.createQuery().queryValue(BukkitAdapter.adapt(location), null, flag); return value != StateFlag.State.DENY; diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/BackdashBoots.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/BackdashBoots.java index 718fc09f..fbf09292 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/BackdashBoots.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/BackdashBoots.java @@ -1,15 +1,12 @@ package xyz.holocons.mc.holoitemsrevamp.item; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; -import com.strangeone101.holoitemsapi.enchantment.EnchantManager; import com.strangeone101.holoitemsapi.item.CustomItem; import com.strangeone101.holoitemsapi.enchantment.Enchantable; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; +import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.ShapedRecipe; @@ -26,12 +23,12 @@ public class BackdashBoots extends CustomItem implements Enchantable { Component.text("Crouch to backdash") ); - private final EnchantManager enchantManager; - public BackdashBoots(HoloItemsRevamp plugin) { super(plugin, name, material, displayName, lore); - this.enchantManager = plugin.getEnchantManager(); - this.setStackable(false); + // TODO: Why was setUnstackable() here? It's boots, they don't stack anyway? + // Should this be removed? + this.setStackSize(1); + this.setBookLike(true); this.register(); } @@ -39,9 +36,9 @@ public BackdashBoots(HoloItemsRevamp plugin) { protected Recipe getRecipe() { final var recipe = new ShapedRecipe(getKey(), buildStack(null)); recipe.shape( - " ", - "A A", - "B B" + " ", + "A A", + "B B" ); recipe.setIngredient('A', Material.PISTON); recipe.setIngredient('B', Material.PHANTOM_MEMBRANE); @@ -49,8 +46,8 @@ protected Recipe getRecipe() { } @Override - public Enchantment getEnchantment() { - return CustomEnchantment.getByKey(getKey()); + public NamespacedKey getEnchantmentKey() { + return getKey(); } @Override @@ -60,8 +57,6 @@ public ItemStack applyEnchantment(ItemStack itemStack) { if (enchantedMeta.addEnchant(getEnchantment(), 1, false)) { enchantedStack.setItemMeta(enchantedMeta); - enchantManager.removeCustomEnchantmentLore(enchantedStack); - enchantManager.applyCustomEnchantmentLore(enchantedStack); return enchantedStack; } else { return null; diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/HolyFireBlock.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/HolyFireBlock.java index 69d7120f..d7a6dee9 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/HolyFireBlock.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/HolyFireBlock.java @@ -1,8 +1,10 @@ package xyz.holocons.mc.holoitemsrevamp.item; import java.time.temporal.ChronoUnit; +import java.util.Arrays; import java.util.List; +import com.strangeone101.holoitemsapi.item.CustomItemManager; import org.bukkit.Material; import org.bukkit.block.Beacon; import org.bukkit.block.BlockFace; @@ -13,6 +15,7 @@ import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.ShapedRecipe; import org.bukkit.util.NumberConversions; @@ -48,12 +51,19 @@ public HolyFireBlock(HoloItemsRevamp plugin) { @Override protected Recipe getRecipe() { - final var recipe = new ShapedRecipe(getKey(), buildStack(null)); - recipe.shape(" a ", "aba", "ccc"); - recipe.setIngredient('a', Material.END_ROD); - recipe.setIngredient('b', new CustomItemRecipeChoice("saint_quartz")); - recipe.setIngredient('c', Material.RAW_GOLD_BLOCK); - recipe.setGroup(name); + final var recipeKey = getKey(); + final var outStack = buildStack(null); + final var recipe = new ShapedRecipe(recipeKey, outStack); + + recipe.shape( + " E ", + "EQE", + "GGG" + ); + recipe.setIngredient('E', Material.END_ROD); + recipe.setIngredient('G', Material.RAW_GOLD_BLOCK); + recipe.setIngredient('Q', new CustomItemRecipeChoice("saint_quartz")); + return recipe; } diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/MagnetBook.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/MagnetBook.java index 3d6a05a8..e9930254 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/MagnetBook.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/MagnetBook.java @@ -1,13 +1,11 @@ package xyz.holocons.mc.holoitemsrevamp.item; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; -import com.strangeone101.holoitemsapi.enchantment.EnchantManager; import com.strangeone101.holoitemsapi.enchantment.Enchantable; import com.strangeone101.holoitemsapi.item.CustomItem; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; +import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.ShapedRecipe; @@ -25,11 +23,8 @@ public class MagnetBook extends CustomItem implements Enchantable { Component.text("Automatically put mined items to your inventory!", NamedTextColor.DARK_PURPLE) ); - private final EnchantManager enchantManager; - public MagnetBook(HoloItemsRevamp plugin) { super(plugin, name, material, displayName, lore); - this.enchantManager = plugin.getEnchantManager(); this.register(); } @@ -37,9 +32,9 @@ public MagnetBook(HoloItemsRevamp plugin) { protected Recipe getRecipe() { final var recipe = new ShapedRecipe(getKey(), buildStack(null)); recipe.shape( - "AAB", - "CDE", - "FGD" + "AAB", + "CDE", + "FGD" ); recipe.setIngredient('A', Material.POWERED_RAIL); recipe.setIngredient('B', Material.IRON_PICKAXE); @@ -52,8 +47,8 @@ protected Recipe getRecipe() { } @Override - public Enchantment getEnchantment() { - return CustomEnchantment.getByKey(getKey()); + public NamespacedKey getEnchantmentKey() { + return getKey(); } @Override @@ -63,8 +58,6 @@ public ItemStack applyEnchantment(ItemStack itemStack) { if (enchantedMeta.addStoredEnchant(getEnchantment(), 1, false)) { enchantedStack.setItemMeta(enchantedMeta); - enchantManager.removeCustomEnchantmentLore(enchantedStack); - enchantManager.applyCustomEnchantmentLore(enchantedStack); return enchantedStack; } else { return null; diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/MementoItem.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/MementoItem.java index ab4b84ea..de7119ee 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/MementoItem.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/MementoItem.java @@ -1,16 +1,14 @@ package xyz.holocons.mc.holoitemsrevamp.item; +import org.bukkit.NamespacedKey; import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.ShapedRecipe; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; -import com.strangeone101.holoitemsapi.enchantment.EnchantManager; import com.strangeone101.holoitemsapi.enchantment.Enchantable; import com.strangeone101.holoitemsapi.item.CustomItem; @@ -28,11 +26,9 @@ public class MementoItem extends CustomItem implements Enchantable { Component.text("Keep your items on death. Consumable.", NamedTextColor.DARK_PURPLE) ); - private final EnchantManager enchantManager; - public MementoItem(HoloItemsRevamp plugin) { super(plugin, name, material, displayName, lore); - this.enchantManager = plugin.getEnchantManager(); + this.setStackSize(99); this.register(); } @@ -40,9 +36,9 @@ public MementoItem(HoloItemsRevamp plugin) { protected Recipe getRecipe() { final var recipe = new ShapedRecipe(getKey(), buildStack(null)); recipe.shape( - "AAA", - "ABA", - "AAA" + "AAA", + "ABA", + "AAA" ); recipe.setIngredient('A', Material.ENDER_CHEST); recipe.setIngredient('B', Material.END_CRYSTAL); @@ -50,8 +46,8 @@ protected Recipe getRecipe() { } @Override - public Enchantment getEnchantment() { - return CustomEnchantment.getByKey(getKey()); + public NamespacedKey getEnchantmentKey() { + return getKey(); } @Override @@ -61,8 +57,6 @@ public ItemStack applyEnchantment(ItemStack itemStack) { if (enchantedMeta.addEnchant(getEnchantment(), 1, false)) { enchantedStack.setItemMeta(enchantedMeta); - enchantManager.removeCustomEnchantmentLore(enchantedStack); - enchantManager.applyCustomEnchantmentLore(enchantedStack); return enchantedStack; } else { return null; diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/PlowBook.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/PlowBook.java index a1f7678d..56e52879 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/PlowBook.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/PlowBook.java @@ -1,13 +1,11 @@ package xyz.holocons.mc.holoitemsrevamp.item; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; -import com.strangeone101.holoitemsapi.enchantment.EnchantManager; import com.strangeone101.holoitemsapi.enchantment.Enchantable; import com.strangeone101.holoitemsapi.item.CustomItem; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; +import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.ShapedRecipe; @@ -24,11 +22,8 @@ public class PlowBook extends CustomItem implements Enchantable { Component.text("Shovel snow!", NamedTextColor.DARK_PURPLE) ); - private final EnchantManager enchantManager; - public PlowBook(HoloItemsRevamp plugin){ super(plugin, name, material, displayName, lore); - this.enchantManager = plugin.getEnchantManager(); this.register(); } @@ -36,9 +31,9 @@ public PlowBook(HoloItemsRevamp plugin){ protected Recipe getRecipe() { ShapedRecipe recipe = new ShapedRecipe(getKey(), buildStack(null)); recipe.shape( - "ABA", - "ACA", - "ACA" + "ABA", + "ACA", + "ACA" ); recipe.setIngredient('A', Material.TINTED_GLASS); recipe.setIngredient('B', Material.OBSIDIAN); @@ -47,8 +42,8 @@ protected Recipe getRecipe() { } @Override - public Enchantment getEnchantment() { - return CustomEnchantment.getByKey(getKey()); + public NamespacedKey getEnchantmentKey() { + return getKey(); } @Override @@ -58,8 +53,6 @@ public ItemStack applyEnchantment(ItemStack itemStack) { if (enchantedMeta.addStoredEnchant(getEnchantment(), 1, false)) { enchantedStack.setItemMeta(enchantedMeta); - enchantManager.removeCustomEnchantmentLore(enchantedStack); - enchantManager.applyCustomEnchantmentLore(enchantedStack); return enchantedStack; } else { return null; diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/TideRiderItem.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/TideRiderItem.java index 7ae4b245..c51fff70 100644 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/TideRiderItem.java +++ b/src/main/java/xyz/holocons/mc/holoitemsrevamp/item/TideRiderItem.java @@ -1,18 +1,15 @@ package xyz.holocons.mc.holoitemsrevamp.item; -import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment; -import com.strangeone101.holoitemsapi.enchantment.EnchantManager; import com.strangeone101.holoitemsapi.enchantment.Enchantable; import com.strangeone101.holoitemsapi.item.CustomItem; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; +import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.ShapedRecipe; -import org.jetbrains.annotations.NotNull; import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp; import java.util.List; @@ -26,11 +23,8 @@ public class TideRiderItem extends CustomItem implements Enchantable { Component.text("Surf the waves") ); - private final EnchantManager enchantManager; - public TideRiderItem(HoloItemsRevamp plugin) { super(plugin, name, material, displayName, lore); - this.enchantManager = plugin.getEnchantManager(); this.register(); } @@ -38,21 +32,19 @@ public TideRiderItem(HoloItemsRevamp plugin) { protected Recipe getRecipe() { final var recipe = new ShapedRecipe(getKey(), buildStack(null)); recipe.shape( - "ABC", - "DEF", - "GDI" + "ATA", + "AG ", + " A " ); recipe.setIngredient('A', Material.PRISMARINE_BRICKS); - recipe.setIngredient('B', Material.TRIDENT); - recipe.setIngredient('C', Material.PRISMARINE_BRICKS); - recipe.setIngredient('E', Material.ENCHANTED_GOLDEN_APPLE); - recipe.setIngredient('D', Material.PRISMARINE_BRICKS); + recipe.setIngredient('T', Material.TRIDENT); + recipe.setIngredient('G', Material.ENCHANTED_GOLDEN_APPLE); return recipe; } @Override - public @NotNull Enchantment getEnchantment() { - return CustomEnchantment.getByKey(getKey()); + public NamespacedKey getEnchantmentKey() { + return getKey(); } @Override @@ -62,8 +54,6 @@ public ItemStack applyEnchantment(ItemStack itemStack) { if (enchantedMeta.addEnchant(getEnchantment(), 1, false)) { enchantedStack.setItemMeta(enchantedMeta); - enchantManager.removeCustomEnchantmentLore(enchantedStack); - enchantManager.applyCustomEnchantmentLore(enchantedStack); return enchantedStack; } else { return null; diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/AbstractPacket.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/AbstractPacket.java deleted file mode 100644 index 24ceb13d..00000000 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/AbstractPacket.java +++ /dev/null @@ -1,33 +0,0 @@ -package xyz.holocons.mc.holoitemsrevamp.packet; - -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.events.PacketContainer; - -public abstract class AbstractPacket { - - protected final PacketContainer handle; - - protected AbstractPacket(PacketType packetType) { - this.handle = new PacketContainer(packetType); - } - - public PacketContainer getHandle() { - return handle; - } - - public void sendPacket(Player player) { - ProtocolLibrary.getProtocolManager().sendServerPacket(player, getHandle()); - } - - public void broadcastNearbyPacket(Location origin, int maxObserverDistance) { - ProtocolLibrary.getProtocolManager().broadcastServerPacket(getHandle(), origin, maxObserverDistance); - } - - public void broadcastServerPacket() { - ProtocolLibrary.getProtocolManager().broadcastServerPacket(getHandle()); - } -} diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/EntityDestroyPacket.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/EntityDestroyPacket.java deleted file mode 100644 index 0f0e47c3..00000000 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/EntityDestroyPacket.java +++ /dev/null @@ -1,15 +0,0 @@ -package xyz.holocons.mc.holoitemsrevamp.packet; - -import com.comphenix.protocol.PacketType; - -import it.unimi.dsi.fastutil.ints.IntList; - -public class EntityDestroyPacket extends AbstractPacket { - - // https://nms.screamingsandals.org/1.18.1/net/minecraft/network/protocol/game/ClientboundRemoveEntitiesPacket.html - public EntityDestroyPacket(int... entityIds) { - super(PacketType.Play.Server.ENTITY_DESTROY); - handle.getIntLists() - .write(0, IntList.of(entityIds)); // entityIds - } -} diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/EntityMetadataPacket.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/EntityMetadataPacket.java deleted file mode 100644 index 7369fb83..00000000 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/EntityMetadataPacket.java +++ /dev/null @@ -1,66 +0,0 @@ -package xyz.holocons.mc.holoitemsrevamp.packet; - -import java.util.List; -import java.util.Optional; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.wrappers.WrappedChatComponent; -import com.comphenix.protocol.wrappers.WrappedDataValue; -import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry; - -import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; - -public class EntityMetadataPacket extends AbstractPacket { - - public static class Metadata { - - private final Int2ObjectArrayMap dataValues; - - // https://wiki.vg/Entity_metadata#Entity_Metadata_Format - public Metadata() { - this.dataValues = new Int2ObjectArrayMap<>(); - } - - public List toList() { - return List.copyOf(dataValues.values()); - } - - private void setObject(int index, Object value, Class clazz) { - dataValues.put(index, new WrappedDataValue(index, Registry.get(clazz), value)); - } - - public void setByte(int index, byte value) { - setObject(index, value, Byte.class); - } - - public void setBoolean(int index, boolean value) { - setObject(index, value, Boolean.class); - } - - public void setVarInt(int index, int value) { - setObject(index, value, Integer.class); - } - - public void setCustomName(Component name) { - final var jsonComponent = GsonComponentSerializer.gson().serialize(name); - final var chatComponent = WrappedChatComponent.fromJson(jsonComponent); - final var optionalChatComponent = Optional.of(chatComponent.getHandle()); - dataValues.put(2, new WrappedDataValue(2, Registry.getChatComponentSerializer(true), optionalChatComponent)); - } - - public void setCustomNameVisible() { - setBoolean(3, true); - } - } - - // https://nms.screamingsandals.org/1.19.3/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.html - public EntityMetadataPacket(int entityId, Metadata metadata) { - super(PacketType.Play.Server.ENTITY_METADATA); - handle.getIntegers() - .write(0, entityId); // id - handle.getDataValueCollectionModifier() - .write(0, metadata.toList()); // packedItems - } -} diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/PlayerAbilitiesPacket.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/PlayerAbilitiesPacket.java deleted file mode 100644 index 93e35461..00000000 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/PlayerAbilitiesPacket.java +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.holocons.mc.holoitemsrevamp.packet; - -import com.comphenix.protocol.PacketType; -import org.bukkit.entity.Player; - -public class PlayerAbilitiesPacket extends AbstractPacket { - - // https://nms.screamingsandals.org/1.18.2/net/minecraft/network/protocol/game/ClientboundPlayerAbilitiesPacket.html - public PlayerAbilitiesPacket(Player player, boolean canInstaBuild) { - super(PacketType.Play.Server.ABILITIES); - handle.getBooleans() - .write(0, player.isInvulnerable()) - .write(1, player.isFlying()) - .write(2, player.getAllowFlight()) - .write(3, canInstaBuild); - handle.getFloat() - .write(0, player.getFlySpeed() / 2) - .write(1, player.getWalkSpeed() / 2); - } -} diff --git a/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/SpawnEntityLivingPacket.java b/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/SpawnEntityLivingPacket.java deleted file mode 100644 index 951939b5..00000000 --- a/src/main/java/xyz/holocons/mc/holoitemsrevamp/packet/SpawnEntityLivingPacket.java +++ /dev/null @@ -1,35 +0,0 @@ -package xyz.holocons.mc.holoitemsrevamp.packet; - -import java.util.UUID; - -import com.comphenix.protocol.PacketType; - -import org.bukkit.Location; -import org.bukkit.entity.EntityType; - -public class SpawnEntityLivingPacket extends AbstractPacket { - - // https://nms.screamingsandals.org/1.19.1/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.html - public SpawnEntityLivingPacket(int entityId, UUID uniqueId, EntityType entityType, Location location) { - super(PacketType.Play.Server.SPAWN_ENTITY); - // https://wiki.vg/Entity_metadata#Mobs - handle.getIntegers() - .write(0, entityId) // id - .write(1, 0) // xa - .write(2, 0) // ya - .write(3, 0) // za - .write(4, 0); // data - handle.getUUIDs() - .write(0, uniqueId); // uuid - handle.getEntityTypeModifier() - .write(0, entityType); // type - handle.getDoubles() - .write(0, location.getX()) // x - .write(1, location.getY()) // y - .write(2, location.getZ()); // z - handle.getBytes() - .write(0, (byte)0) // xRot - .write(1, (byte)0) // yRot - .write(2, (byte)0); // yHeadRot - } -}