diff --git a/src/main/java/me/youhavetrouble/enchantio/Enchantio.java b/src/main/java/me/youhavetrouble/enchantio/Enchantio.java index 5a4ecac..0c66341 100644 --- a/src/main/java/me/youhavetrouble/enchantio/Enchantio.java +++ b/src/main/java/me/youhavetrouble/enchantio/Enchantio.java @@ -23,6 +23,9 @@ public final class Enchantio extends JavaPlugin { if (EnchantioConfig.ENCHANTS.containsKey(BeheadingEnchant.KEY)) { getServer().getPluginManager().registerEvents(new BeheadingListener(), this); } + if (EnchantioConfig.ENCHANTS.containsKey(SmeltingEnchant.KEY)) { + getServer().getPluginManager().registerEvents(new SmeltingListener(), this); + } } @Override diff --git a/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java b/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java index 200dc57..b112a8d 100644 --- a/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java +++ b/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java @@ -198,6 +198,36 @@ public class EnchantioConfig { ENCHANTS.put(BeheadingEnchant.KEY, beheadingEnchant); } + ConfigurationSection smeltingSection = enchantsSection.getConfigurationSection("smelting"); + if (smeltingSection == null) { + smeltingSection = enchantsSection.createSection("smelting"); + } + + SmeltingEnchant smeltingEnchant = new SmeltingEnchant( + getInt(smeltingSection, "anvilCost", 1), + getInt(smeltingSection, "weight", 10), + EnchantmentRegistryEntry.EnchantmentCost.of( + getInt(smeltingSection, "minimumCost.base", 40), + getInt(smeltingSection, "minimumCost.additionalPerLevel", 3) + ), + EnchantmentRegistryEntry.EnchantmentCost.of( + getInt(smeltingSection, "maximumCost.base", 65), + getInt(smeltingSection, "maximumCost.additionalPerLevel", 1) + ), + getBoolean(smeltingSection, "canGetFromEnchantingTable", true), + getTagsFromList(getStringList( + smeltingSection, + "supportedItemTags", + List.of( + "#minecraft:enchantable/mining" + ) + )) + ); + + if (getBoolean(smeltingSection, "enabled", true)) { + ENCHANTS.put(SmeltingEnchant.KEY, smeltingEnchant); + } + configuration.save(configFile); } diff --git a/src/main/java/me/youhavetrouble/enchantio/enchants/SmeltingEnchant.java b/src/main/java/me/youhavetrouble/enchantio/enchants/SmeltingEnchant.java new file mode 100644 index 0000000..d3e37d5 --- /dev/null +++ b/src/main/java/me/youhavetrouble/enchantio/enchants/SmeltingEnchant.java @@ -0,0 +1,96 @@ +package me.youhavetrouble.enchantio.enchants; + +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.data.EnchantmentRegistryEntry; +import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.tag.TagEntry; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import org.bukkit.inventory.EquipmentSlotGroup; +import org.bukkit.inventory.ItemType; + +import java.util.Set; + +@SuppressWarnings("UnstableApiUsage") +public class SmeltingEnchant implements EnchantioEnchant { + + public static final Key KEY = Key.key("enchantio:smelting"); + + private final int anvilCost, weight; + private final EnchantmentRegistryEntry.EnchantmentCost minimumCost; + private final EnchantmentRegistryEntry.EnchantmentCost maximumCost; + private final boolean canGetFromEnchantingTable; + private final Set> supportedItemTags; + + public SmeltingEnchant( + int anvilCost, + int weight, + EnchantmentRegistryEntry.EnchantmentCost minimumCost, + EnchantmentRegistryEntry.EnchantmentCost maximumCost, + boolean canGetFromEnchantingTable, + Set> supportedItemTags + ) { + this.anvilCost = anvilCost; + this.weight = weight; + this.minimumCost = minimumCost; + this.maximumCost = maximumCost; + this.canGetFromEnchantingTable = canGetFromEnchantingTable; + this.supportedItemTags = supportedItemTags; + } + + @Override + public Key getKey() { + return KEY; + } + + @Override + public Component getDescription() { + return Component.translatable("enchantio.enchant.smelting", "Smelting"); + } + + @Override + public int getAnvilCost() { + return anvilCost; + } + + @Override + public int getMaxLevel() { + return 1; + } + + @Override + public int getWeight() { + return weight; + } + + @Override + public EnchantmentRegistryEntry.EnchantmentCost getMinimumCost() { + return minimumCost; + } + + @Override + public EnchantmentRegistryEntry.EnchantmentCost getMaximumCost() { + return maximumCost; + } + + @Override + public Iterable getActiveSlots() { + return Set.of(EquipmentSlotGroup.ANY); + } + + @Override + public boolean canGetFromEnchantingTable() { + return canGetFromEnchantingTable; + } + + @Override + public TagKey getTagForSupportedItems() { + return TagKey.create(RegistryKey.ITEM, Key.key("enchantio:smelting_enchantable")); + } + + @Override + public Set> getSupportedItems() { + return supportedItemTags; + } + +} diff --git a/src/main/java/me/youhavetrouble/enchantio/listeners/SmeltingListener.java b/src/main/java/me/youhavetrouble/enchantio/listeners/SmeltingListener.java new file mode 100644 index 0000000..54b43b7 --- /dev/null +++ b/src/main/java/me/youhavetrouble/enchantio/listeners/SmeltingListener.java @@ -0,0 +1,66 @@ +package me.youhavetrouble.enchantio.listeners; + +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import me.youhavetrouble.enchantio.enchants.SmeltingEnchant; +import org.bukkit.Bukkit; +import org.bukkit.Registry; +import org.bukkit.block.BlockState; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Item; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockDropItemEvent; +import org.bukkit.inventory.BlockInventoryHolder; +import org.bukkit.inventory.FurnaceRecipe; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class SmeltingListener implements Listener { + + private final Registry registry = RegistryAccess.registryAccess().getRegistry(RegistryKey.ENCHANTMENT); + private final Enchantment smelting = registry.get(SmeltingEnchant.KEY); + private final Map smeltingCache = new HashMap<>(); + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) + public void onSmeltingEnchantSmelt(BlockDropItemEvent event) { + if (smelting == null) return; + ItemStack tool = event.getPlayer().getInventory().getItemInMainHand(); + if (!tool.containsEnchantment(smelting)) return; + + BlockState block = event.getBlockState(); + if (block instanceof BlockInventoryHolder) return; + + for (Item item : event.getItems()) { + int amount = item.getItemStack().getAmount(); + ItemStack smeltedItem = getSmeltedItem(item.getItemStack()); + if (smeltedItem == null) continue; + item.setItemStack(smeltedItem.asQuantity(amount)); + } + } + + /** + * Gets the smelted item from the given item stack. If item stack is not smeltable, returns the item stack itself. + */ + private ItemStack getSmeltedItem(@NotNull ItemStack itemStack) { + ItemStack singleItem = itemStack.asOne(); + if (smeltingCache.containsKey(singleItem)) return smeltingCache.get(singleItem); + + for (@NotNull Iterator it = Bukkit.recipeIterator(); it.hasNext(); ) { + Recipe recipe = it.next(); + if (!(recipe instanceof FurnaceRecipe furnaceRecipe)) continue; + if (!furnaceRecipe.getInputChoice().test(singleItem)) continue; + ItemStack result = furnaceRecipe.getResult(); + smeltingCache.put(singleItem, result); + return result; + } + return null; + } + +}