diff --git a/src/main/java/me/zenox/superitems/SuperItems.java b/src/main/java/me/zenox/superitems/SuperItems.java index f8f02bb..7a8cff3 100644 --- a/src/main/java/me/zenox/superitems/SuperItems.java +++ b/src/main/java/me/zenox/superitems/SuperItems.java @@ -13,10 +13,7 @@ import me.zenox.superitems.data.ConfigLoader; import me.zenox.superitems.data.LanguageLoader; import me.zenox.superitems.enchant.EnchantRegistry; -import me.zenox.superitems.events.DimensionLocker; -import me.zenox.superitems.events.InventoryListener; -import me.zenox.superitems.events.OtherEvent; -import me.zenox.superitems.events.PlayerUseItemEvent; +import me.zenox.superitems.events.*; import me.zenox.superitems.item.ItemRegistry; import me.zenox.superitems.item.VanillaItem; import me.zenox.superitems.network.GlowFilter; @@ -83,6 +80,7 @@ private void registerListeners() { new OtherEvent(plugin); new InventoryListener(plugin); new DimensionLocker(plugin); + new CraftEvent(plugin); } public static void registerGlobalGUIItems(){ diff --git a/src/main/java/me/zenox/superitems/abilities/ItemAbility.java b/src/main/java/me/zenox/superitems/abilities/ItemAbility.java index 2b21fd1..7199b78 100644 --- a/src/main/java/me/zenox/superitems/abilities/ItemAbility.java +++ b/src/main/java/me/zenox/superitems/abilities/ItemAbility.java @@ -645,6 +645,8 @@ public void run() { Location giantLocation = arr.getLocation(); giantLocation.setY(arr.getLocation().getY()-1); giant.teleport(giantLocation); + giant.setFireTicks(0); + giant.setVisualFire(false); if(arr.isInBlock() && !contacted){ contacted = true; diff --git a/src/main/java/me/zenox/superitems/events/CraftEvent.java b/src/main/java/me/zenox/superitems/events/CraftEvent.java new file mode 100644 index 0000000..45495ae --- /dev/null +++ b/src/main/java/me/zenox/superitems/events/CraftEvent.java @@ -0,0 +1,157 @@ +package me.zenox.superitems.events; + +import me.zenox.superitems.SuperItems; +import me.zenox.superitems.item.ComplexItem; +import me.zenox.superitems.item.ComplexItemStack; +import me.zenox.superitems.recipe.ComplexChoice; +import me.zenox.superitems.recipe.ComplexRecipe; +import me.zenox.superitems.recipe.ShapedComplexRecipe; +import me.zenox.superitems.recipe.ShapelessComplexRecipe; +import org.bukkit.Bukkit; +import org.bukkit.Keyed; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.inventory.CraftingInventory; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.Map; + +public class CraftEvent implements Listener { + private SuperItems plugin; + + public CraftEvent(SuperItems plugin){ + this.plugin = plugin; + Bukkit.getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void prepareCraftEvent(PrepareItemCraftEvent e){ + if(e.getInventory().getType() != InventoryType.WORKBENCH) return; + + // Get the related complex recipe + for (ComplexRecipe recipe : ComplexRecipe.registeredRecipes) { + if (e.getRecipe() != null && recipe.getKey().equals(((Keyed) e.getRecipe()).getKey())){ + if(recipe instanceof ShapedComplexRecipe){ + // Shaped Logic + if (!testRecipe(recipe, e.getInventory().getMatrix())){ + e.getInventory().setResult(new ItemStack(Material.AIR)); + for(ComplexRecipe complexRecipe : ComplexRecipe.similarRecipeMap.get(recipe)){ + if(testRecipe(complexRecipe, e.getInventory().getMatrix())) { + e.getInventory().setResult(complexRecipe.getResult().getItem()); + break; + } + } + } + } + break; + } else if(recipe instanceof ShapelessComplexRecipe) { + if(testRecipe(recipe, e.getInventory().getMatrix())){ + e.getInventory().setResult(recipe.getResult().getItem()); + } + } + } + + } + + private boolean testRecipe(ComplexRecipe recipe, ItemStack[] matrix){ + if(recipe instanceof ShapedComplexRecipe) { + ShapedComplexRecipe shapedRecipe = (ShapedComplexRecipe) recipe; + int index = 0; + for (String row : shapedRecipe.getShape()) { + for (char c : row.toCharArray()) { + if (!shapedRecipe.getChoiceMap().get(c).test(matrix[index])) { + return false; + } + index++; + } + } + return true; + } else { + ShapelessComplexRecipe shapelessRecipe = (ShapelessComplexRecipe) recipe; + HashMap requiredItems = new HashMap<>(); + for (ComplexChoice choice : shapelessRecipe.getChoiceList()) { + requiredItems.computeIfPresent(((Map.Entry) choice.getChoices().entrySet().toArray()[0]).getKey(), ((complexItem, integer) -> integer + choice.getAmount())); + requiredItems.putIfAbsent(((Map.Entry) choice.getChoices().entrySet().toArray()[0]).getKey(), ((Map.Entry) choice.getChoices().entrySet().toArray()[0]).getValue()); + } + + for (ItemStack item : matrix){ + if(item == null) continue; + ComplexItem cItem = ComplexItemStack.of(item).getComplexItem(); + if(!requiredItems.containsKey(cItem)) return false; + requiredItems.replace(cItem, requiredItems.get(cItem) - item.getAmount()); + } + + for (Map.Entry entry : + requiredItems.entrySet()) { + if(entry.getValue() > 0) return false; + } + + return true; + } + } + + @EventHandler + public void craftEvent(InventoryClickEvent e){ + if(e.getClickedInventory() == null) return; + if(e.getClickedInventory().getType() != InventoryType.WORKBENCH) return; + if(e.getSlot() != 0) return; + CraftingInventory inventory = ((CraftingInventory) e.getClickedInventory()); + // Check that there is something being crafted - and identify what it is + ComplexRecipe recipe = null; + + for (ComplexRecipe recipe1 : ComplexRecipe.registeredRecipes) { + if (testRecipe(recipe1, inventory.getMatrix())){ + recipe = recipe1; + break; + } + } + + if(recipe == null) return; + + if(e.getClick().isShiftClick()){ + if(recipe instanceof ShapedComplexRecipe) { + for (int i = 0; i < 9; i++) { + inventory.getMatrix()[i].setAmount(inventory.getMatrix()[i].getAmount() % ((ShapedComplexRecipe) recipe).getChoiceatIndex(i).getItemStack().getAmount()); + } + } else { + e.setCancelled(true); + } + } else { + if(recipe instanceof ShapedComplexRecipe) { + for (int i = 0; i < 9; i++) { + inventory.getMatrix()[i].setAmount(inventory.getMatrix()[i].getAmount() - ((ShapedComplexRecipe) recipe).getChoiceatIndex(i).getItemStack().getAmount()); + } + } else { + ShapelessComplexRecipe shapelessRecipe = ((ShapelessComplexRecipe) recipe); + HashMap requiredItems = new HashMap<>(); + for (ComplexChoice choice : shapelessRecipe.getChoiceList()) { + requiredItems.computeIfPresent(((Map.Entry) choice.getChoices().entrySet().toArray()[0]).getKey(), ((complexItem, integer) -> integer + choice.getAmount())); + requiredItems.putIfAbsent(((Map.Entry) choice.getChoices().entrySet().toArray()[0]).getKey(), ((Map.Entry) choice.getChoices().entrySet().toArray()[0]).getValue()); + } + + for (int i = 0; i < 9; i++) { + ItemStack item = inventory.getMatrix()[i]; + if(item == null) continue; + ComplexItem cItem = ComplexItemStack.of(item).getComplexItem(); + if(requiredItems.get(cItem) <= 0) { + // Attempt to stop the items from duplicating + item.setAmount(item.getAmount() + 1); + continue; + } + + int amountToSubtract = Math.min(item.getAmount(), requiredItems.get(cItem)); + item.setAmount(item.getAmount() - amountToSubtract); + + requiredItems.replace(cItem, requiredItems.get(cItem) - amountToSubtract); + } + } + } + + } + +} diff --git a/src/main/java/me/zenox/superitems/item/ComplexItemMeta.java b/src/main/java/me/zenox/superitems/item/ComplexItemMeta.java index 9857839..6010f97 100644 --- a/src/main/java/me/zenox/superitems/item/ComplexItemMeta.java +++ b/src/main/java/me/zenox/superitems/item/ComplexItemMeta.java @@ -39,7 +39,7 @@ * */ -public class ComplexItemMeta { +public class ComplexItemMeta implements Cloneable{ public static final NamespacedKey ABILITY_ID = new NamespacedKey(SuperItems.getPlugin(), "ability"); public static final String VAR_PREFIX = "var_"; public static final String ATTRIBUTE_BASE_KEY = "base"; @@ -343,4 +343,13 @@ public List getAbilities() { public List getModifierList() { return modifierList; } + + @Override + protected ComplexItemMeta clone(){ + try { + return ((ComplexItemMeta) super.clone()); + } catch (CloneNotSupportedException e) { + throw new RuntimeException("Cloning not supported here! o_O"); + } + } } diff --git a/src/main/java/me/zenox/superitems/item/ComplexItemStack.java b/src/main/java/me/zenox/superitems/item/ComplexItemStack.java index 1d74b8c..3adf46e 100644 --- a/src/main/java/me/zenox/superitems/item/ComplexItemStack.java +++ b/src/main/java/me/zenox/superitems/item/ComplexItemStack.java @@ -28,7 +28,7 @@ *

* Planned for future implementation */ -public class ComplexItemStack { +public class ComplexItemStack implements Cloneable{ private final ComplexItem complexItem; private final UUID uuid; @@ -151,4 +151,11 @@ public ComplexItem getComplexItem() { public ComplexItemMeta getComplexMeta() { return complexMeta; } + + @Override + public ComplexItemStack clone() { + ComplexItemStack clone = new ComplexItemStack(this.complexItem, this.item.getAmount()); + clone.complexMeta = clone.complexMeta.clone(); + return clone; + } } \ No newline at end of file diff --git a/src/main/java/me/zenox/superitems/item/ItemRegistry.java b/src/main/java/me/zenox/superitems/item/ItemRegistry.java index 076e50e..0e9fd0f 100644 --- a/src/main/java/me/zenox/superitems/item/ItemRegistry.java +++ b/src/main/java/me/zenox/superitems/item/ItemRegistry.java @@ -440,7 +440,6 @@ public static List registerRecipes() { Bukkit.addRecipe(recipe); } catch (IllegalStateException e) { if (recipe instanceof Keyed) { - //Util.logToConsole("Found duplicate recipe, re-adding."); Bukkit.removeRecipe(((Keyed) recipe).getKey()); Bukkit.addRecipe(recipe); } diff --git a/src/main/java/me/zenox/superitems/recipe/ComplexChoice.java b/src/main/java/me/zenox/superitems/recipe/ComplexChoice.java index b86e0d1..03c0f60 100644 --- a/src/main/java/me/zenox/superitems/recipe/ComplexChoice.java +++ b/src/main/java/me/zenox/superitems/recipe/ComplexChoice.java @@ -4,15 +4,15 @@ import com.google.common.collect.ImmutableMap; import me.zenox.superitems.item.ComplexItem; import me.zenox.superitems.item.ComplexItemStack; -import me.zenox.superitems.item.ItemRegistry; +import me.zenox.superitems.item.VanillaItem; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.RecipeChoice; import org.jetbrains.annotations.NotNull; import java.util.Map; import java.util.Objects; -public class ComplexChoice implements RecipeChoice { +public class ComplexChoice { private Map choices; @@ -26,6 +26,21 @@ public ComplexChoice(@NotNull ComplexItem complexItem, Integer amount) { this(Map.of(complexItem, amount)); } + public ComplexChoice(@NotNull Material material, Integer amount) { + this(Map.of(VanillaItem.of(material), amount)); + } + + public ComplexChoice(@NotNull ComplexItem complexItem) { + this(Map.of(complexItem, 1)); + } + + public ComplexChoice(@NotNull ComplexItemStack itemStack){ + this(Map.of(itemStack.getComplexItem(), itemStack.getItem().getAmount())); + } + public ComplexChoice(@NotNull Material material) { + this(Map.of(VanillaItem.of(material), 1)); + } + public ComplexChoice(@NotNull Map choices) { Preconditions.checkArgument(choices != null, "choices"); Preconditions.checkArgument(!choices.isEmpty(), "Must have at least one choice"); @@ -37,9 +52,13 @@ public ComplexChoice(@NotNull Map choices) { } @NotNull - @Override public ItemStack getItemStack() { - return ItemRegistry.byId(((Map.Entry) choices.entrySet().toArray()[0]).getKey()).getItemStack(((Map.Entry) choices.entrySet().toArray()[0]).getValue()); + return new ComplexItemStack(((Map.Entry) choices.entrySet().toArray()[0]).getKey(), ((Map.Entry) choices.entrySet().toArray()[0]).getValue()).getItem(); + } + + @NotNull + public int getAmount(){ + return ((Map.Entry) choices.entrySet().toArray()[0]).getValue(); } public Map getChoices() { @@ -57,14 +76,13 @@ public ComplexChoice clone() { } } - @Override public boolean test(@NotNull ItemStack t) { + ComplexItem cItem = ComplexItemStack.of(t).getComplexItem(); for (Map.Entry match : choices.entrySet()) { - if (ComplexItemStack.of(t).getComplexItem().equals(match) && (t.getAmount() == match.getValue() || match.getValue() == -1)) { + if (cItem.equals(match.getKey()) && (t.getAmount() >= match.getValue() || match.getValue() == -1)) { return true; } } - return false; } diff --git a/src/main/java/me/zenox/superitems/recipe/ComplexRecipe.java b/src/main/java/me/zenox/superitems/recipe/ComplexRecipe.java new file mode 100644 index 0000000..06aa701 --- /dev/null +++ b/src/main/java/me/zenox/superitems/recipe/ComplexRecipe.java @@ -0,0 +1,21 @@ +package me.zenox.superitems.recipe; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import me.zenox.superitems.item.ComplexItemStack; +import org.bukkit.NamespacedKey; + +import java.util.ArrayList; +import java.util.List; + +public interface ComplexRecipe { + List registeredRecipes = new ArrayList<>(); + Multimap similarRecipeMap = ArrayListMultimap.create(); + + NamespacedKey getKey(); + ComplexItemStack getResult(); + ComplexRecipe register(); + + boolean similar(ComplexRecipe other); + +} diff --git a/src/main/java/me/zenox/superitems/recipe/MaterialAmountChoice.java b/src/main/java/me/zenox/superitems/recipe/MaterialAmountChoice.java deleted file mode 100644 index 2300be3..0000000 --- a/src/main/java/me/zenox/superitems/recipe/MaterialAmountChoice.java +++ /dev/null @@ -1,107 +0,0 @@ -package me.zenox.superitems.recipe; - - -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableMap; -import me.zenox.superitems.util.Util; -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.RecipeChoice; -import org.jetbrains.annotations.NotNull; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -/** - * Represents a choice of multiple matching Materials, that also matches an amount. - */ -public class MaterialAmountChoice implements RecipeChoice { - - private Map choices; - - public MaterialAmountChoice(@NotNull Material choice, @NotNull Integer amount) { - this(Map.of(choice, amount)); - } - - public MaterialAmountChoice(@NotNull Map choices) { - Preconditions.checkArgument(choices != null, "choices"); - Preconditions.checkArgument(!choices.isEmpty(), "Must have at least one choice"); - for (Map.Entry choice : choices.entrySet()) { - Preconditions.checkArgument(choice != null, "Cannot have null choice"); - } - - this.choices = new HashMap<>(choices); - } - - @Override - public boolean test(@NotNull ItemStack t) { - for (Map.Entry match : choices.entrySet()) { - Util.logToConsole("Material Value: " + t.getType() + " | " + "Recipe Material Value: " + match.getKey()); - Util.logToConsole("Amount Value: " + t.getAmount() + " | " + "Recipe Amount Value: " + match.getValue()); - if (t.getType() == match.getKey() && t.getAmount() == match.getValue()) { - return true; - } - } - - return false; - } - - @NotNull - @Override - public ItemStack getItemStack() { - ItemStack stack = new ItemStack(((Map.Entry) choices.entrySet().toArray()[0]).getKey()); - stack.setAmount(((Map.Entry) choices.entrySet().toArray()[0]).getValue()); - - // For compat - if (choices.size() > 1) { - stack.setDurability(Short.MAX_VALUE); - } - - return stack; - } - - @NotNull - public Map getChoices() { - return ImmutableMap.copyOf(choices); - } - - @NotNull - @Override - public MaterialAmountChoice clone() { - try { - MaterialAmountChoice clone = (MaterialAmountChoice) super.clone(); - clone.choices = new HashMap<>(choices); - return clone; - } catch (CloneNotSupportedException ex) { - throw new AssertionError(ex); - } - } - - @Override - public int hashCode() { - int hash = 4; - hash = 37 * hash + Objects.hashCode(this.choices); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final MaterialAmountChoice other = (MaterialAmountChoice) obj; - return Objects.equals(this.choices, other.choices); - } - - @Override - public String toString() { - return "MaterialChoice{" + "choices=" + choices + '}'; - } -} diff --git a/src/main/java/me/zenox/superitems/recipe/RecipeRegistry.java b/src/main/java/me/zenox/superitems/recipe/RecipeRegistry.java index a343ea9..9454a4e 100644 --- a/src/main/java/me/zenox/superitems/recipe/RecipeRegistry.java +++ b/src/main/java/me/zenox/superitems/recipe/RecipeRegistry.java @@ -5,273 +5,259 @@ import me.zenox.superitems.util.Util; import org.bukkit.ChatColor; import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.Recipe; -import org.bukkit.inventory.RecipeChoice; - -import java.util.ArrayList; -import java.util.List; public class RecipeRegistry { - public static final List registeredRecipes = new ArrayList<>(); - static { - final Recipe BLAZE_TO_ENCHANTED_BLAZE = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.ENCHANTED_BLAZE_ROD).getItem()) + final ComplexRecipe BLAZE_TO_ENCHANTED_BLAZE = new ShapelessComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.ENCHANTED_BLAZE_ROD)) .id("blaze_to_enchanted_blaze") - .shape("BBB", "BBB", "BBB") - .addChoice('B', new MaterialAmountChoice(Material.BLAZE_ROD, 5)) - .build()); + .addChoice(new ComplexChoice(Material.BLAZE_ROD, 128)) + .register(); - final Recipe ENCHANTED_BLAZE_TO_BLAZE = registerRecipe(new ShapelessRecipeBuilder() - .setResult(new ItemStack(Material.BLAZE_ROD, 9)) + final ComplexRecipe ENCHANTED_BLAZE_TO_BLAZE = new ShapelessComplexRecipe() + .setResult(Material.BLAZE_ROD, 9) .id("enchanted_blaze_to_blaze") - .addChoice(new ComplexChoice(ItemRegistry.ENCHANTED_BLAZE_ROD, -1)).build()); + .addChoice(new ComplexChoice(ItemRegistry.ENCHANTED_BLAZE_ROD, 1)).register(); - final Recipe ENCHANTED_ENDER_PEARL = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.ENCHANTED_ENDER_PEARL).getItem()) + final ComplexRecipe ENCHANTED_ENDER_PEARL = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.ENCHANTED_ENDER_PEARL)) .id("enchanted_ender_pearl") .shape("EEE", "EEE", "EEE") - .addChoice('E', new MaterialAmountChoice(Material.ENDER_PEARL, 9)) - .build()); + .addChoice('E', new ComplexChoice(Material.ENDER_PEARL, 9)) + .register(); - final Recipe ABSOLUTE_ENDER_PEARL = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.ABSOLUTE_ENDER_PEARL).getItem()) + final ComplexRecipe ABSOLUTE_ENDER_PEARL = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.ABSOLUTE_ENDER_PEARL)) .id("absolute_ender_pearl") .shape("EEE", "EEE", "EEE") .addChoice('E', new ComplexChoice(ItemRegistry.ENCHANTED_ENDER_PEARL, 9)) - .build()); + .register(); - final Recipe PURIFIED_MAGMA_DISTILLATE = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.PURIFIED_MAGMA_DISTILLATE).getItem()) + final ComplexRecipe PURIFIED_MAGMA_DISTILLATE = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.PURIFIED_MAGMA_DISTILLATE)) .id("purified_magma_distillate") .shape("TML", "MMM", "LMT") - .addChoice('M', new RecipeChoice.ExactChoice(ItemRegistry.ENCHANTED_MAGMA_BLOCK.getItemStack(1))) - .addChoice('L', new RecipeChoice.MaterialChoice(Material.LAVA_BUCKET)) - .addChoice('T', new RecipeChoice.MaterialChoice(Material.GHAST_TEAR)) - .build()); + .addChoice('M', new ComplexChoice(ItemRegistry.ENCHANTED_MAGMA_BLOCK)) + .addChoice('L', new ComplexChoice(Material.LAVA_BUCKET)) + .addChoice('T', new ComplexChoice(Material.GHAST_TEAR)) + .register(); - final Recipe TITANIUM_CUBE = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.PURIFIED_MAGMA_DISTILLATE).getItem()) + final ComplexRecipe TITANIUM_CUBE = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.PURIFIED_MAGMA_DISTILLATE)) .id("purified_magma_distillate") .shape("III", "III", "III") - .addChoice('I', new RecipeChoice.MaterialChoice(Material.IRON_BLOCK)) - .build()); + .addChoice('I', new ComplexChoice(Material.IRON_BLOCK)) + .register(); - final Recipe MAGIC_TOY_STICK = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.MAGIC_TOY_STICK).getItem()) + final ComplexRecipe MAGIC_TOY_STICK = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.MAGIC_TOY_STICK)) .id("magic_toy_stick") .shape("PHP", "TDT", "TDT") - .addChoice('P', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.PURIFIED_MAGMA_DISTILLATE).getItem())) - .addChoice('H', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.HYPER_CRUX).getItem())) - .addChoice('T', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.TITANIUM_CUBE).getItem())) - .addChoice('P', new RecipeChoice.MaterialChoice(Material.DEBUG_STICK)) - .build()); - - final Recipe SOUL_CRYSTAL = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.SOUL_CRYSTAL).getItem()) + .addChoice('P', new ComplexChoice(new ComplexItemStack(ItemRegistry.PURIFIED_MAGMA_DISTILLATE))) + .addChoice('H', new ComplexChoice(new ComplexItemStack(ItemRegistry.HYPER_CRUX))) + .addChoice('T', new ComplexChoice(new ComplexItemStack(ItemRegistry.TITANIUM_CUBE))) + .addChoice('P', new ComplexChoice(Material.DEBUG_STICK)) + .register(); + + final ComplexRecipe SOUL_CRYSTAL = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.SOUL_CRYSTAL)) .id("soul_crystal") .shape("BEB", "ECE", "BEB") - .addChoice('B', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.ENCHANTED_BLAZE_ROD).getItem())) - .addChoice('E', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.ABSOLUTE_ENDER_PEARL).getItem())) - .addChoice('C', new RecipeChoice.MaterialChoice(Material.END_CRYSTAL)) - .build()); + .addChoice('B', new ComplexChoice(new ComplexItemStack(ItemRegistry.ENCHANTED_BLAZE_ROD))) + .addChoice('E', new ComplexChoice(new ComplexItemStack(ItemRegistry.ABSOLUTE_ENDER_PEARL))) + .addChoice('C', new ComplexChoice(Material.END_CRYSTAL)) + .register(); - final Recipe FIERY_EMBER_STAFF = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.FIERY_EMBER_STAFF).getItem()) + final ComplexRecipe FIERY_EMBER_STAFF = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.FIERY_EMBER_STAFF)) .id("fiery_ember_staff") .shape("FFF", "APA", "MPM") - .addChoice('A', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.BURNING_ASHES).getItem())) - .addChoice('P', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.MOLTEN_POWDER).getItem())) - .addChoice('M', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.PURIFIED_MAGMA_DISTILLATE).getItem())) - .addChoice('F', new RecipeChoice.MaterialChoice(Material.FIRE_CHARGE)) - .build()); - - final Recipe DARK_EMBER_STAFF = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.DARK_EMBER_STAFF).getItem()) + .addChoice('A', new ComplexChoice(new ComplexItemStack(ItemRegistry.BURNING_ASHES))) + .addChoice('P', new ComplexChoice(new ComplexItemStack(ItemRegistry.MOLTEN_POWDER))) + .addChoice('M', new ComplexChoice(new ComplexItemStack(ItemRegistry.PURIFIED_MAGMA_DISTILLATE))) + .addChoice('F', new ComplexChoice(Material.FIRE_CHARGE)) + .register(); + + final ComplexRecipe DARK_EMBER_STAFF = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.DARK_EMBER_STAFF)) .id("dark_ember_staff") .shape("RWR", "PSP", "MPM") - .addChoice('S', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.FIERY_EMBER_STAFF).getItem())) - .addChoice('P', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.MOLTEN_POWDER).getItem())) - .addChoice('M', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.PURIFIED_MAGMA_DISTILLATE).getItem())) - .addChoice('W', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.DARK_SKULL).getItem())) - .addChoice('R', new RecipeChoice.MaterialChoice(Material.WITHER_ROSE)) - .build()); - - final Recipe TORMENTED_BLADE = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.TORMENTED_BLADE).getItem()) + .addChoice('S', new ComplexChoice(new ComplexItemStack(ItemRegistry.FIERY_EMBER_STAFF))) + .addChoice('P', new ComplexChoice(new ComplexItemStack(ItemRegistry.MOLTEN_POWDER))) + .addChoice('M', new ComplexChoice(new ComplexItemStack(ItemRegistry.PURIFIED_MAGMA_DISTILLATE))) + .addChoice('W', new ComplexChoice(new ComplexItemStack(ItemRegistry.DARK_SKULL))) + .addChoice('R', new ComplexChoice(Material.WITHER_ROSE)) + .register(); + + final ComplexRecipe TORMENTED_BLADE = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.TORMENTED_BLADE)) .id("tormented_blade") .shape("ITI", "MBI", " B ") - .addChoice('B', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.ENCHANTED_BLAZE_ROD).getItem())) - .addChoice('M', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.MOLTEN_POWDER).getItem())) - .addChoice('T', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.TORMENTED_SOUL).getItem())) - .addChoice('I', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.TITANIUM_CUBE).getItem())) - .build()); - - final Recipe CRUCIFIED_AMULET = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.CRUCIFIED_AMULET).getItem()) + .addChoice('B', new ComplexChoice(new ComplexItemStack(ItemRegistry.ENCHANTED_BLAZE_ROD))) + .addChoice('M', new ComplexChoice(new ComplexItemStack(ItemRegistry.MOLTEN_POWDER))) + .addChoice('T', new ComplexChoice(new ComplexItemStack(ItemRegistry.TORMENTED_SOUL))) + .addChoice('I', new ComplexChoice(new ComplexItemStack(ItemRegistry.TITANIUM_CUBE))) + .register(); + + final ComplexRecipe CRUCIFIED_AMULET = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.CRUCIFIED_AMULET)) .id("crucified_amulet") .shape("STS", "AHA", "STS") - .addChoice('H', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.HYPER_CRUX).getItem())) - .addChoice('A', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.BURNING_ASHES).getItem())) - .addChoice('T', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.TORMENTED_SOUL).getItem())) - .addChoice('S', new RecipeChoice.MaterialChoice(Material.SOUL_SAND)) - .build()); - - final Recipe PSYCHEDELIC_ORB = registerRecipe(new ShapelessRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.PSYCHEDELIC_ORB).getItem()) + .addChoice('H', new ComplexChoice(new ComplexItemStack(ItemRegistry.HYPER_CRUX))) + .addChoice('A', new ComplexChoice(new ComplexItemStack(ItemRegistry.BURNING_ASHES))) + .addChoice('T', new ComplexChoice(new ComplexItemStack(ItemRegistry.TORMENTED_SOUL))) + .addChoice('S', new ComplexChoice(Material.SOUL_SAND)) + .register(); + + final ComplexRecipe PSYCHEDELIC_ORB = new ShapelessComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.PSYCHEDELIC_ORB)) .id("psychedelic_orb") - .addChoice(new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.HYPER_CRUX).getItem())) - .addChoice(new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.ABSOLUTE_ENDER_PEARL).getItem())) - .build()); + .addChoice(new ComplexChoice(new ComplexItemStack(ItemRegistry.HYPER_CRUX))) + .addChoice(new ComplexChoice(new ComplexItemStack(ItemRegistry.ABSOLUTE_ENDER_PEARL))) + .register(); - final Recipe TOUGH_FABRIC = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.TOUGH_FABRIC).getItem()) + final ComplexRecipe TOUGH_FABRIC = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.TOUGH_FABRIC)) .id("tough_fabric") .shape("SSS", "SSS", "SSS") - .addChoice('S', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.RAVAGER_SKIN).getItem())) - .build()); + .addChoice('S', new ComplexChoice(new ComplexItemStack(ItemRegistry.RAVAGER_SKIN))) + .register(); - final Recipe KEVLAR = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.KEVLAR).getItem()) + final ComplexRecipe KEVLAR = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.KEVLAR)) .id("kevlar") .shape("SSS", "SSS", "SSS") - .addChoice('S', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.TOUGH_FABRIC).getItem())) - .build()); + .addChoice('S', new ComplexChoice(new ComplexItemStack(ItemRegistry.TOUGH_FABRIC))) + .register(); - final Recipe TOTEM_POLE = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.TOTEM_POLE).getItem()) + final ComplexRecipe TOTEM_POLE = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.TOTEM_POLE)) .id("totem_pole") .shape("TCT", "DND", "DND") - .addChoice('C', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.CRULEN_SHARD).getItem())) - .addChoice('D', new RecipeChoice.MaterialChoice(Material.DEBUG_STICK)) - .addChoice('N', new RecipeChoice.MaterialChoice(Material.NETHER_STAR)) - .addChoice('T', new RecipeChoice.MaterialChoice(Material.TOTEM_OF_UNDYING)) - .build()); - - final Recipe PAGES_OF_AGONY = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.PAGES_OF_AGONY).getItem()) + .addChoice('C', new ComplexChoice(new ComplexItemStack(ItemRegistry.CRULEN_SHARD))) + .addChoice('D', new ComplexChoice(Material.DEBUG_STICK)) + .addChoice('N', new ComplexChoice(Material.NETHER_STAR)) + .addChoice('T', new ComplexChoice(Material.TOTEM_OF_UNDYING)) + .register(); + + final ComplexRecipe PAGES_OF_AGONY = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.PAGES_OF_AGONY)) .id("pages_of_agony") .shape("PPP", "PTP", "PPP") - .addChoice('P', new RecipeChoice.MaterialChoice(Material.PAPER)) - .addChoice('T', new RecipeChoice.ExactChoice(ItemRegistry.TORMENTED_SOUL.getItemStack(1))) - .build()); + .addChoice('P', new ComplexChoice(Material.PAPER)) + .addChoice('T', new ComplexChoice(ItemRegistry.TORMENTED_SOUL)) + .register(); - final Recipe DIMENSIONAL_JOURNAL = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.DIMENSIONAL_JOURNAL).getItem()) + final ComplexRecipe DIMENSIONAL_JOURNAL = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.DIMENSIONAL_JOURNAL)) .id("dimensional_journal") .shape("GNE", "PPP", "KKK") - .addChoice('G', new RecipeChoice.MaterialChoice(Material.GRASS_BLOCK)) - .addChoice('N', new RecipeChoice.MaterialChoice(Material.NETHERRACK)) - .addChoice('E', new RecipeChoice.MaterialChoice(Material.END_STONE)) - .addChoice('P', new RecipeChoice.ExactChoice(ItemRegistry.PAGES_OF_AGONY.getItemStack(1))) - .addChoice('K', new RecipeChoice.ExactChoice(ItemRegistry.KEVLAR.getItemStack(1))).build()); - - final Recipe ENCHANTED_OBSIDIAN = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.ENCHANTED_OBSIDIAN).getItem()) + .addChoice('G', new ComplexChoice(Material.GRASS_BLOCK)) + .addChoice('N', new ComplexChoice(Material.NETHERRACK)) + .addChoice('E', new ComplexChoice(Material.END_STONE)) + .addChoice('P', new ComplexChoice(ItemRegistry.PAGES_OF_AGONY)) + .addChoice('K', new ComplexChoice(ItemRegistry.KEVLAR)).register(); + + final ComplexRecipe ENCHANTED_OBSIDIAN = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.ENCHANTED_OBSIDIAN)) .id("enchanted_obsidian") .shape("OOO", "OOO", "OOO") - .addChoice('O', new RecipeChoice.MaterialChoice(Material.OBSIDIAN)) - .build()); + .addChoice('O', new ComplexChoice(Material.OBSIDIAN)) + .register(); - final Recipe COMPACT_OBSIDIAN = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.COMPACT_OBSIDIAN).getItem()) + final ComplexRecipe COMPACT_OBSIDIAN = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.COMPACT_OBSIDIAN)) .id("compact_obsidian") .shape("OOO", "OCO", "OOO") - .addChoice('O', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.ENCHANTED_OBSIDIAN).getItem())) - .addChoice('C', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.CORRUPT_PEARL).getItem())) - .build()); + .addChoice('O', new ComplexChoice(new ComplexItemStack(ItemRegistry.ENCHANTED_OBSIDIAN))) + .addChoice('C', new ComplexChoice(new ComplexItemStack(ItemRegistry.CORRUPT_PEARL))) + .register(); - final Recipe CORRUPT_OBSIDIAN = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.CORRUPT_OBSIDIAN).getItem()) + final ComplexRecipe CORRUPT_OBSIDIAN = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.CORRUPT_OBSIDIAN)) .id("corrupt_obsidian") .shape("COO", "ONO", "OOC") - .addChoice('O', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.COMPACT_OBSIDIAN).getItem())) - .addChoice('C', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.CORRUPT_PEARL).getItem())) - .addChoice('O', new RecipeChoice.MaterialChoice(Material.NETHER_STAR)) - .build()); + .addChoice('O', new ComplexChoice(new ComplexItemStack(ItemRegistry.COMPACT_OBSIDIAN))) + .addChoice('C', new ComplexChoice(new ComplexItemStack(ItemRegistry.CORRUPT_PEARL))) + .addChoice('O', new ComplexChoice(Material.NETHER_STAR)) + .register(); - final Recipe CRESTFALLEN_MONOLITH = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.CRESTFALLEN_MONOLITH).getItem()) + final ComplexRecipe CRESTFALLEN_MONOLITH = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.CRESTFALLEN_MONOLITH)) .id("crestfallen_monolith") .shape("ANO", "C2C", "ONA") - .addChoice('A', new RecipeChoice.ExactChoice(ItemRegistry.ABSOLUTE_ENDER_PEARL.getItemStack(1))) - .addChoice('N', new RecipeChoice.MaterialChoice(Material.NETHER_STAR)) - .addChoice('O', new RecipeChoice.ExactChoice(ItemRegistry.COMPACT_OBSIDIAN.getItemStack(1))) - .addChoice('C', new RecipeChoice.ExactChoice(ItemRegistry.CORRUPT_PEARL.getItemStack(1))) - .addChoice('2', new RecipeChoice.ExactChoice(ItemRegistry.CORRUPT_OBSIDIAN.getItemStack(1))).build()); - - final Recipe VOID_STONE = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.VOID_STONE).getItem()) + .addChoice('A', new ComplexChoice(ItemRegistry.ABSOLUTE_ENDER_PEARL)) + .addChoice('N', new ComplexChoice(Material.NETHER_STAR)) + .addChoice('O', new ComplexChoice(ItemRegistry.COMPACT_OBSIDIAN)) + .addChoice('C', new ComplexChoice(ItemRegistry.CORRUPT_PEARL)) + .addChoice('2', new ComplexChoice(ItemRegistry.CORRUPT_OBSIDIAN)).register(); + + final ComplexRecipe VOID_STONE = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.VOID_STONE)) .id("void_stone") .shape("CKC", "CVC", "CCC") - .addChoice('C', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.CORRUPT_PEARL).getItem())) - .addChoice('K', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.KEVLAR).getItem())) - .addChoice('V', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.ROUGH_VOID_STONE).getItem())) - .build()); + .addChoice('C', new ComplexChoice(new ComplexItemStack(ItemRegistry.CORRUPT_PEARL))) + .addChoice('K', new ComplexChoice(new ComplexItemStack(ItemRegistry.KEVLAR))) + .addChoice('V', new ComplexChoice(new ComplexItemStack(ItemRegistry.ROUGH_VOID_STONE))) + .register(); - final Recipe VOID_HELMET = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.VOID_HELMET).getItem()) + final ComplexRecipe VOID_HELMET = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.VOID_HELMET)) .id("void_helmet") .shape("N2N", "CHC", " ") - .addChoice('N', new RecipeChoice.MaterialChoice(Material.NETHER_STAR)) - .addChoice('H', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.HYPER_CRUX).getItem())) - .addChoice('2', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.CORRUPT_OBSIDIAN).getItem())) - .addChoice('C', new RecipeChoice.ExactChoice(new ComplexItemStack(ItemRegistry.CORRUPT_PEARL).getItem())) - .build()); - - final Recipe VOID_CHESTPLATE = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.VOID_CHESTPLATE).getItem()) + .addChoice('N', new ComplexChoice(Material.NETHER_STAR)) + .addChoice('H', new ComplexChoice(new ComplexItemStack(ItemRegistry.HYPER_CRUX))) + .addChoice('2', new ComplexChoice(new ComplexItemStack(ItemRegistry.CORRUPT_OBSIDIAN))) + .addChoice('C', new ComplexChoice(new ComplexItemStack(ItemRegistry.CORRUPT_PEARL))) + .register(); + + final ComplexRecipe VOID_CHESTPLATE = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.VOID_CHESTPLATE)) .id("void_chestplate") .shape("K K", "DMD", "HOH") - .addChoice('K', new RecipeChoice.ExactChoice(ItemRegistry.KEVLAR.getItemStack(1))) - .addChoice('O', new RecipeChoice.ExactChoice(ItemRegistry.COMPACT_OBSIDIAN.getItemStack(1))) - .addChoice('D', new RecipeChoice.ExactChoice(ItemRegistry.DARK_SKULL.getItemStack(1))) - .addChoice('H', new RecipeChoice.ExactChoice(ItemRegistry.HYPER_CRUX.getItemStack(1))) - .addChoice('M', new RecipeChoice.ExactChoice(ItemRegistry.CRESTFALLEN_MONOLITH.getItemStack(1))) - .build()); - - final Recipe VOID_LEGGINGS = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.VOID_LEGGINGS).getItem()) + .addChoice('K', new ComplexChoice(ItemRegistry.KEVLAR)) + .addChoice('O', new ComplexChoice(ItemRegistry.COMPACT_OBSIDIAN)) + .addChoice('D', new ComplexChoice(ItemRegistry.DARK_SKULL)) + .addChoice('H', new ComplexChoice(ItemRegistry.HYPER_CRUX)) + .addChoice('M', new ComplexChoice(ItemRegistry.CRESTFALLEN_MONOLITH)) + .register(); + + final ComplexRecipe VOID_LEGGINGS = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.VOID_LEGGINGS)) .id("void_leggings") .shape("OMO", "C C", "K K") - .addChoice('K', new RecipeChoice.ExactChoice(ItemRegistry.KEVLAR.getItemStack(1))) - .addChoice('O', new RecipeChoice.ExactChoice(ItemRegistry.COMPACT_OBSIDIAN.getItemStack(1))) - .addChoice('M', new RecipeChoice.ExactChoice(ItemRegistry.CRESTFALLEN_MONOLITH.getItemStack(1))) - .addChoice('C', new RecipeChoice.ExactChoice(ItemRegistry.CORRUPT_PEARL.getItemStack(1))) - .build()); - - final Recipe VOID_BOOTS = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.VOID_BOOTS).getItem()) + .addChoice('K', new ComplexChoice(ItemRegistry.KEVLAR)) + .addChoice('O', new ComplexChoice(ItemRegistry.COMPACT_OBSIDIAN)) + .addChoice('M', new ComplexChoice(ItemRegistry.CRESTFALLEN_MONOLITH)) + .addChoice('C', new ComplexChoice(ItemRegistry.CORRUPT_PEARL)) + .register(); + + final ComplexRecipe VOID_BOOTS = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.VOID_BOOTS)) .id("void_boots") .shape("KDK", "ACA", "OCO") - .addChoice('K', new RecipeChoice.ExactChoice(ItemRegistry.KEVLAR.getItemStack(1))) - .addChoice('O', new RecipeChoice.ExactChoice(ItemRegistry.COMPACT_OBSIDIAN.getItemStack(1))) - .addChoice('D', new RecipeChoice.ExactChoice(ItemRegistry.DARK_SKULL.getItemStack(1))) - .addChoice('C', new RecipeChoice.ExactChoice(ItemRegistry.CORRUPT_PEARL.getItemStack(1))) - .addChoice('A', new RecipeChoice.ExactChoice(ItemRegistry.ABSOLUTE_ENDER_PEARL.getItemStack(1))) - .build()); - - final Recipe TITANIUM_BOOTS = registerRecipe(new ShapedRecipeBuilder() - .setResult(new ComplexItemStack(ItemRegistry.VOID_BOOTS).getItem()) + .addChoice('K', new ComplexChoice(ItemRegistry.KEVLAR)) + .addChoice('O', new ComplexChoice(ItemRegistry.COMPACT_OBSIDIAN)) + .addChoice('D', new ComplexChoice(ItemRegistry.DARK_SKULL)) + .addChoice('C', new ComplexChoice(ItemRegistry.CORRUPT_PEARL)) + .addChoice('A', new ComplexChoice(ItemRegistry.ABSOLUTE_ENDER_PEARL)) + .register(); + + final ComplexRecipe TITANIUM_BOOTS = new ShapedComplexRecipe() + .setResult(new ComplexItemStack(ItemRegistry.VOID_BOOTS)) .id("void_boots") .shape("KDK", "ACA", "AAA") + .addChoice('A', new ComplexChoice(ItemRegistry.TITANIUM_CUBE)) + //if it's more than 1 we have to increase stats + .register(); - .addChoice('A', new RecipeChoice.ExactChoice(ItemRegistry.TITANIUM_CUBE.getItemStack(1))) - //if its more than 1 we have to increase stats - .build()); - } - - private static Recipe registerRecipe(Recipe recipe) { - registeredRecipes.add(recipe); - return recipe; } public static void registerRecipes() { - Util.logToConsole(ChatColor.WHITE + "Registering " + ChatColor.GOLD + registeredRecipes.size() + ChatColor.WHITE + " recipes."); + Util.logToConsole(ChatColor.WHITE + "Registering " + ChatColor.GOLD + ComplexRecipe.registeredRecipes.size() + ChatColor.WHITE + " recipes."); } } diff --git a/src/main/java/me/zenox/superitems/recipe/ShapedComplexRecipe.java b/src/main/java/me/zenox/superitems/recipe/ShapedComplexRecipe.java new file mode 100644 index 0000000..4571331 --- /dev/null +++ b/src/main/java/me/zenox/superitems/recipe/ShapedComplexRecipe.java @@ -0,0 +1,121 @@ +package me.zenox.superitems.recipe; + +import me.zenox.superitems.SuperItems; +import me.zenox.superitems.item.ComplexItemStack; +import org.bukkit.Bukkit; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ShapedRecipe; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ShapedComplexRecipe implements ComplexRecipe{ + + private NamespacedKey id; + private List shape; + private ComplexItemStack result; + private Map choiceMap; + + public ShapedComplexRecipe() { + this.choiceMap = new HashMap<>(); + } + + public NamespacedKey getKey() { + return id; + } + + public ShapedComplexRecipe id(String id) { + this.id = new NamespacedKey(SuperItems.getPlugin(), id); + return this; + } + + public List getShape() { + return shape; + } + + public ShapedComplexRecipe shape(String... shape) { + if (shape.length != 3 || shape[0].length() != 3 || shape[1].length() != 3 || shape[2].length() != 3) { + throw new IllegalArgumentException("Matrix shape in RecipeBuilder#shape(shape) must be size 3x3"); + } + this.shape = List.of(shape); + return this; + } + + public ComplexItemStack getResult() { + return result; + } + + public ShapedComplexRecipe setResult(ComplexItemStack result) { + this.result = result; + return this; + } + + public Map getChoiceMap() { + return choiceMap; + } + + public ShapedComplexRecipe choiceMap(Map choiceMap) { + this.choiceMap = choiceMap; + return this; + } + + public ShapedComplexRecipe addChoice(Character character, ComplexChoice choice) { + this.choiceMap.put(character, choice); + return this; + } + + public ComplexRecipe register() { + // Register vanilla recipe + ShapedRecipe recipe = new ShapedRecipe(id, result.clone().getItem()); + recipe.shape(shape.get(0), shape.get(1), shape.get(2)); + for (Map.Entry entry : choiceMap.entrySet()) { + recipe.setIngredient(entry.getKey(), entry.getValue().getItemStack().getType()); + } + try { + Bukkit.addRecipe(recipe); + } catch (IllegalStateException e) { + if (recipe instanceof Keyed) { + Bukkit.removeRecipe(((Keyed) recipe).getKey()); + Bukkit.addRecipe(recipe); + } + } + + // Check for "similar" recipes + // "similar" recipes are recipes that have the same minecraft representation, but have different complex representation - this helps build a cache of all of those relationships + for (ComplexRecipe recipe1 : registeredRecipes) { + if(recipe1 instanceof ShapedComplexRecipe && similar(recipe1)) { + similarRecipeMap.put(this, recipe1); + similarRecipeMap.put(recipe1, this); + } + } + + // add to registry + registeredRecipes.add(this); + return this; + } + + public ComplexChoice getChoiceatIndex(int index){ + return choiceMap.get(shape.get((index - index % 3) / 3).charAt(index % 3)); + } + + @Override + public boolean similar(ComplexRecipe otherRecipe) { + if(!(otherRecipe instanceof ShapedComplexRecipe)) return false; + ShapedComplexRecipe other = ((ShapedComplexRecipe) otherRecipe); + for (int i = 0;i < 3;i++){ + for (int j = 0;j < 3;j++){ + ComplexChoice thisChoice = choiceMap.get(shape.get(i).charAt(j)); + ComplexChoice otherChoice = other.choiceMap.get(other.shape.get(i).charAt(j)); + if(thisChoice == null && otherChoice == null) continue; + if(thisChoice != null && otherChoice == null) return false; + if(thisChoice == null && otherChoice != null) return false; + if (thisChoice.getItemStack().getType() != + otherChoice.getItemStack().getType()) return false; + } + } + return true; + } + +} diff --git a/src/main/java/me/zenox/superitems/recipe/ShapedRecipeBuilder.java b/src/main/java/me/zenox/superitems/recipe/ShapedRecipeBuilder.java index 010e778..c9bbd32 100644 --- a/src/main/java/me/zenox/superitems/recipe/ShapedRecipeBuilder.java +++ b/src/main/java/me/zenox/superitems/recipe/ShapedRecipeBuilder.java @@ -15,11 +15,10 @@ public class ShapedRecipeBuilder { private String id; private List shape; private ItemStack result; - private Map choiceMap = new HashMap<>(); + private Map choiceMap; public ShapedRecipeBuilder() { this.choiceMap = new HashMap<>(); - } public String getId() { diff --git a/src/main/java/me/zenox/superitems/recipe/ShapelessComplexRecipe.java b/src/main/java/me/zenox/superitems/recipe/ShapelessComplexRecipe.java new file mode 100644 index 0000000..dbffe61 --- /dev/null +++ b/src/main/java/me/zenox/superitems/recipe/ShapelessComplexRecipe.java @@ -0,0 +1,75 @@ +package me.zenox.superitems.recipe; + +import me.zenox.superitems.SuperItems; +import me.zenox.superitems.item.ComplexItemStack; +import me.zenox.superitems.item.VanillaItem; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; + +import java.util.ArrayList; +import java.util.List; + +public class ShapelessComplexRecipe implements ComplexRecipe{ + + private NamespacedKey id; + private ComplexItemStack result; + private List choiceList = new ArrayList<>(); + + public ShapelessComplexRecipe() { + } + + public NamespacedKey getKey() { + return id; + } + + public ShapelessComplexRecipe id(String id) { + this.id = new NamespacedKey(SuperItems.getPlugin(), id); + return this; + } + + public ComplexItemStack getResult() { + return result; + } + + public ShapelessComplexRecipe setResult(ComplexItemStack result) { + this.result = result; + return this; + } + + public ShapelessComplexRecipe setResult(Material material, int amount) { + this.result = new ComplexItemStack(VanillaItem.of(material), amount); + return this; + } + + public List getChoiceList() { + return choiceList; + } + + public ShapelessComplexRecipe choiceList(List choiceMap) { + this.choiceList = choiceMap; + return this; + } + + public ShapelessComplexRecipe addChoice(ComplexChoice choice) { + this.choiceList.add(choice); + return this; + } + + @Override + public ComplexRecipe register() { + // add to registry + registeredRecipes.add(this); + return this; + } + + + public boolean similar(ComplexRecipe other) { + if(!(other instanceof ShapelessComplexRecipe)) return false; + ShapelessComplexRecipe otherRecipe = ((ShapelessComplexRecipe) other); + if(otherRecipe.choiceList.size() != choiceList.size()) return false; + for (int i = 0; i < otherRecipe.choiceList.size(); i++) { + if(choiceList.get(i).getItemStack().getType() != otherRecipe.choiceList.get(i).getItemStack().getType()) return false; + } + return true; + } +} diff --git a/src/main/resources/languages/en_US.yml b/src/main/resources/languages/en_US.yml index 0abb61a..e14ccde 100644 --- a/src/main/resources/languages/en_US.yml +++ b/src/main/resources/languages/en_US.yml @@ -392,13 +392,50 @@ ability-lore-lava_glider: ## ENCHANTMENTS ## ########################################################################## +# Custom Enchantments enchant-name-siphon: Siphon -enchant-name-sharpness: Sharpness -enchant-name-fire_aspect: Fire Aspect enchant-name-darksoul: Darksoul -enchant-name-knockback: Knockback enchant-name-culling: Culling +# Vanilla Enchantments +enchant-name-aqua_affinity: Aqua Affinity +enchant-name-bane_of_arthropods: Bane of Arthropods +enchant-name-blast_protection: Blast Protection +enchant-name-channeling: Channeling +enchant-name-depth_strider: Depth Strider +enchant-name-efficiency: Efficiency +enchant_name-feather_falling: Feather Falling +enchant-name-fire_aspect: Fire Aspect +enchant-name-fire_protection: Fire Protection +enchant-name-flame: Flame +enchant-name-fortune: Fortune +enchant-name-frost_walker: Frost Walker +enchant-name-impaling: Impaling +enchant-name-infinity: Infinity +enchant-name-knockback: Knockback +enchant-name-looting: Looting +enchant-name-loyalty: Loyalty +enchant-name-luck_of_the_sea: Luck of the Sea +enchant-name-lure: Lure +enchant-mending: Mending +enchant-name-multishot: Multishot +enchant-name-piercing: Piercing +enchant-name-power: Power +enchant-name-projectile_protection: Projectile Protection +enchant-name-protection: Protection +enchant-name-punch: Punch +enchant-name-quick_charge: Quick Charge +enchant-name-respiration: Respiration +enchant-name-riptide: Riptide +enchant-name-sharpness: Sharpness +enchant-name-silk_touch: Silk Touch +enchant-name-smite: Smite +enchant-name-soul_speed: Soul Speed +enchant-name-sweeping_edge: Sweeping Edge +enchant-name-swift_sneak: Swift Sneak +enchant-name-thorns: Thorns +enchant-name-unbreaking: Unbreaking + ########################################################################## ## GUIS ## ##########################################################################