diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index 73d0aee7..276c73a8 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -28,6 +28,7 @@ import com.minelittlepony.unicopia.advancements.UAdvancements; import com.minelittlepony.unicopia.command.Commands; import com.minelittlepony.unicopia.enchanting.AffineIngredients; import com.minelittlepony.unicopia.enchanting.Pages; +import com.minelittlepony.unicopia.enchanting.SpecialRecipe; import com.minelittlepony.unicopia.enchanting.SpellRecipe; import com.minelittlepony.unicopia.forgebullshit.FBS; import com.minelittlepony.unicopia.init.UEntities; @@ -63,6 +64,7 @@ public class Unicopia implements IGuiHandler { super.registerRecipeTypes(types); types.put("unicopia:crafting_spell", SpellRecipe::deserialize); + types.put("unicopia:crafting_special", SpecialRecipe::deserialize); AffineIngredients.instance().load(); } diff --git a/src/main/java/com/minelittlepony/unicopia/enchanting/AbstractSpecialRecipe.java b/src/main/java/com/minelittlepony/unicopia/enchanting/AbstractSpecialRecipe.java new file mode 100644 index 00000000..665583e8 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/enchanting/AbstractSpecialRecipe.java @@ -0,0 +1,125 @@ +package com.minelittlepony.unicopia.enchanting; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.minelittlepony.unicopia.inventory.InventorySpellBook; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.NonNullList; +import net.minecraft.world.World; +import net.minecraftforge.registries.IForgeRegistryEntry.Impl; + +public abstract class AbstractSpecialRecipe extends Impl implements IRecipe { + + private final SpellIngredient spellitem; + + private final NonNullList ingredients; + + static NonNullList parseIngrediants(JsonObject json) { + NonNullList ingredients = NonNullList.create(); + + for (JsonElement i : json.get("ingredients").getAsJsonArray()) { + SpellIngredient ingredient = SpellIngredient.parse(i); + + if (ingredient != null) { + ingredients.add(ingredient); + } + } + + if (ingredients.isEmpty()) { + throw new JsonParseException("Recipe cannot have 0 ingredients"); + } + + return ingredients; + } + + static SpellIngredient parseSingleIngredient(JsonObject json) { + SpellIngredient result = SpellIngredient.parse(json.get("item")); + + if (result == null) { + throw new JsonParseException("Recipe cannot have no enchantable input"); + } + + return result; + } + + public AbstractSpecialRecipe(SpellIngredient spellitem, NonNullList ingredients) { + this.spellitem = spellitem; + this.ingredients = ingredients; + } + + @Override + public boolean matches(InventoryCrafting inv, World worldIn) { + ItemStack enchantedStack = ((InventorySpellBook)inv).getCraftResultMatrix().getStackInSlot(0); + + if (enchantedStack.isEmpty() || enchantedStack.getItem() == null) { + return false; + } + + if (!spellitem.matches(enchantedStack, enchantedStack.getCount())) { + return false; + } + + int materialMult = enchantedStack.getCount(); + + ArrayList toMatch = Lists.newArrayList(ingredients); + + for (int i = 0; i < inv.getSizeInventory(); i++) { + ItemStack stack = inv.getStackInSlot(i); + + if (!stack.isEmpty()) { + if (toMatch.isEmpty() || !removeMatch(toMatch, stack, materialMult)) { + return false; + } + } + } + return toMatch.isEmpty(); + } + + private boolean removeMatch(List toMatch, ItemStack stack, int materialMult) { + return toMatch.stream() + .filter(s -> s.matches(stack, materialMult)) + .findFirst() + .filter(toMatch::remove) + .isPresent(); + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inv) { + return getRecipeOutput(); + } + + @Override + public boolean canFit(int width, int height) { + return width * height < ingredients.size(); + } + + @Override + public ItemStack getRecipeOutput() { + return spellitem.getStack(); + } + + @Override + public NonNullList getRemainingItems(InventoryCrafting inv) { + NonNullList remainers = NonNullList.withSize(inv.getSizeInventory(), ItemStack.EMPTY); + + for (int i = 0; i < remainers.size(); i++) { + ItemStack stack = inv.getStackInSlot(i); + + if (stack != null && stack.getItem().hasContainerItem(stack)) { + remainers.set(i, new ItemStack(stack.getItem().getContainerItem())); + } + } + + return remainers; + } + + +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/enchanting/AffineIngredients.java b/src/main/java/com/minelittlepony/unicopia/enchanting/AffineIngredients.java index 6c195f2d..90060399 100644 --- a/src/main/java/com/minelittlepony/unicopia/enchanting/AffineIngredients.java +++ b/src/main/java/com/minelittlepony/unicopia/enchanting/AffineIngredients.java @@ -32,7 +32,14 @@ public class AffineIngredients { } public SpellIngredient getIngredient(ResourceLocation res) { - return storedIngredients.get(res); + SpellIngredient result = storedIngredients.get(res); + + if (result == null) { + new RuntimeException("Ingredient `" + res + "` was not found.").printStackTrace(); + return SpellIngredient.EMPTY; + } + + return result; } protected void handleJson(ResourceLocation id, JsonObject json) throws JsonParseException { @@ -51,6 +58,11 @@ public class AffineIngredients { this.res = res; } + @Override + public ItemStack getStack() { + return instance().getIngredient(res).getStack(); + } + @Override public boolean matches(ItemStack other, int materialMult) { return instance().getIngredient(res).matches(other, materialMult); diff --git a/src/main/java/com/minelittlepony/unicopia/enchanting/SpecialRecipe.java b/src/main/java/com/minelittlepony/unicopia/enchanting/SpecialRecipe.java new file mode 100644 index 00000000..3be8985f --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/enchanting/SpecialRecipe.java @@ -0,0 +1,30 @@ +package com.minelittlepony.unicopia.enchanting; + +import com.google.gson.JsonObject; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.NonNullList; + +public class SpecialRecipe extends AbstractSpecialRecipe { + + private final SpellIngredient output; + + public static IRecipe deserialize(JsonObject json) { + return new SpecialRecipe( + parseSingleIngredient(json.get("input").getAsJsonObject()), + parseSingleIngredient(json.get("output").getAsJsonObject()), + parseIngrediants(json) + ); + } + + public SpecialRecipe(SpellIngredient input, SpellIngredient output, NonNullList ingredients) { + super(input, ingredients); + + this.output = output; + } + + @Override + public ItemStack getRecipeOutput() { + return output.getStack(); + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/enchanting/SpellIngredient.java b/src/main/java/com/minelittlepony/unicopia/enchanting/SpellIngredient.java index 102b248a..3bd2a816 100644 --- a/src/main/java/com/minelittlepony/unicopia/enchanting/SpellIngredient.java +++ b/src/main/java/com/minelittlepony/unicopia/enchanting/SpellIngredient.java @@ -16,6 +16,8 @@ import net.minecraft.item.ItemStack; public interface SpellIngredient { + static SpellIngredient EMPTY = new Single(ItemStack.EMPTY, false); + @Nullable static SpellIngredient parse(JsonElement json) { if (json.isJsonArray()) { @@ -27,6 +29,8 @@ public interface SpellIngredient { boolean matches(ItemStack other, int materialMult); + ItemStack getStack(); + class Compound implements SpellIngredient { private final List items; @@ -34,6 +38,11 @@ public interface SpellIngredient { this.items = items; } + @Override + public ItemStack getStack() { + return items.get((int)(Math.random() * items.size())).getStack(); + } + @Override public boolean matches(ItemStack other, int materialMult) { return items.stream().anyMatch(item -> item.matches(other, materialMult)); @@ -71,6 +80,11 @@ public interface SpellIngredient { ignoreMeta = meta; } + @Override + public ItemStack getStack() { + return contained; + } + @Override public boolean matches(ItemStack other, int materialMult) { if (other.isEmpty() != contained.isEmpty()) { diff --git a/src/main/java/com/minelittlepony/unicopia/enchanting/SpellRecipe.java b/src/main/java/com/minelittlepony/unicopia/enchanting/SpellRecipe.java index 8909bb5d..4fa4a483 100644 --- a/src/main/java/com/minelittlepony/unicopia/enchanting/SpellRecipe.java +++ b/src/main/java/com/minelittlepony/unicopia/enchanting/SpellRecipe.java @@ -1,132 +1,47 @@ package com.minelittlepony.unicopia.enchanting; -import java.util.ArrayList; -import java.util.List; - -import com.google.common.collect.Lists; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.minelittlepony.unicopia.init.UItems; import com.minelittlepony.unicopia.inventory.InventorySpellBook; import com.minelittlepony.unicopia.spell.SpellRegistry; +import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.util.NonNullList; -import net.minecraft.world.World; -import net.minecraftforge.registries.IForgeRegistryEntry.Impl; - -public class SpellRecipe extends Impl implements IRecipe { - - private final SpellIngredient spellitem; +public class SpellRecipe extends AbstractSpecialRecipe { private final String spellId; - private final NonNullList ingredients; - public static IRecipe deserialize(JsonObject json) { - NonNullList ingredients = NonNullList.create(); + JsonObject resultJson = json.get("result").getAsJsonObject(); - for (JsonElement i : json.get("ingredients").getAsJsonArray()) { - SpellIngredient ingredient = SpellIngredient.parse(i); - - if (ingredient != null) { - ingredients.add(ingredient); - } - } - - if (ingredients.isEmpty()) { - throw new JsonParseException("Recipe cannot have 0 ingredients"); - } - - json = json.get("result").getAsJsonObject(); - - String spellId = json.get("spell").getAsString(); - - SpellIngredient result = SpellIngredient.parse(json.get("item")); - - if (result == null) { - throw new JsonParseException("Recipe cannot have no enchantable input"); - } - - return new SpellRecipe(result, spellId, ingredients); + return new SpellRecipe( + parseSingleIngredient(resultJson), + resultJson.get("spell").getAsString(), + parseIngrediants(json) + ); } public SpellRecipe(SpellIngredient spellitem, String spellName, NonNullList ingredients) { - this.spellitem = spellitem; + super(spellitem, ingredients); this.spellId = spellName; - this.ingredients = ingredients; - } - - @Override - public boolean matches(InventoryCrafting inv, World worldIn) { - ItemStack enchantedStack = ((InventorySpellBook)inv).getCraftResultMatrix().getStackInSlot(0); - - if (enchantedStack.isEmpty() || enchantedStack.getItem() == null) { - return false; - } - - if (!spellitem.matches(enchantedStack, enchantedStack.getCount())) { - return false; - } - - int materialMult = enchantedStack.getCount(); - - ArrayList toMatch = Lists.newArrayList(ingredients); - - for (int i = 0; i < inv.getSizeInventory(); i++) { - ItemStack stack = inv.getStackInSlot(i); - - if (!stack.isEmpty()) { - if (toMatch.isEmpty() || !removeMatch(toMatch, stack, materialMult)) { - return false; - } - } - } - return toMatch.isEmpty(); - } - - private boolean removeMatch(List toMatch, ItemStack stack, int materialMult) { - return toMatch.stream() - .filter(s -> s.matches(stack, materialMult)) - .findFirst() - .filter(toMatch::remove) - .isPresent(); } @Override public ItemStack getCraftingResult(InventoryCrafting inv) { - return getRecipeOutput(); - } + InventorySpellBook inventory = (InventorySpellBook)inv; - @Override - public boolean canFit(int width, int height) { - return width * height < ingredients.size(); + IInventory craftResult = inventory.getCraftResultMatrix(); + ItemStack stackToEnchant = craftResult.getStackInSlot(0); + + return SpellRegistry.instance().enchantStack(stackToEnchant, spellId); } @Override public ItemStack getRecipeOutput() { - return SpellRegistry.instance().enchantStack(new ItemStack(UItems.spell, 1), spellId); + return SpellRegistry.instance().enchantStack(super.getRecipeOutput(), spellId); } - - @Override - public NonNullList getRemainingItems(InventoryCrafting inv) { - NonNullList remainers = NonNullList.withSize(inv.getSizeInventory(), ItemStack.EMPTY); - - for (int i = 0; i < remainers.size(); i++) { - ItemStack stack = inv.getStackInSlot(i); - - if (stack != null && stack.getItem().hasContainerItem(stack)) { - remainers.set(i, new ItemStack(stack.getItem().getContainerItem())); - } - } - - return remainers; - } - - } diff --git a/src/main/java/com/minelittlepony/unicopia/inventory/gui/ContainerSpellBook.java b/src/main/java/com/minelittlepony/unicopia/inventory/gui/ContainerSpellBook.java index 74975949..b3dd1f12 100644 --- a/src/main/java/com/minelittlepony/unicopia/inventory/gui/ContainerSpellBook.java +++ b/src/main/java/com/minelittlepony/unicopia/inventory/gui/ContainerSpellBook.java @@ -8,9 +8,9 @@ import com.minelittlepony.unicopia.enchanting.IPageUnlockListener; import com.minelittlepony.unicopia.inventory.InventorySpellBook; import com.minelittlepony.unicopia.inventory.slot.SlotEnchanting; import com.minelittlepony.unicopia.inventory.slot.SlotEnchantingResult; -import com.minelittlepony.unicopia.item.ItemSpell; import com.minelittlepony.unicopia.player.PlayerSpeciesList; import com.minelittlepony.unicopia.spell.SpellRegistry; +import com.minelittlepony.unicopia.world.UWorld; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; @@ -20,6 +20,7 @@ import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryBasic; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -76,9 +77,30 @@ public class ContainerSpellBook extends Container { ItemStack crafted = Unicopia.getCraftingManager().findMatchingResult(craftMatrix, worldObj); if (!crafted.isEmpty()) { - current = SpellRegistry.instance().enchantStack(current, crafted); - resultSlot.setCrafted(true); + + if (crafted.getItem() != current.getItem()) { + + craftResult.setInventorySlotContents(0, ItemStack.EMPTY); + resultSlot.onTake(player, crafted); + + player.dropItem(crafted, true); + + player.playSound(SoundEvents.BLOCK_NOTE_SNARE, 1, 1); + + worldObj.newExplosion(null, player.posX, player.posY, player.posZ, 0, false, false); + worldObj.newExplosion(null, player.posX, player.posY, player.posZ, 0, false, false); + + worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_HUGE, player.posX, player.posY, player.posZ, 1, 0, 0); + + UWorld.enqueueTask(w -> { + player.closeScreen(); + }); + + return; + } + + current = crafted; player.playSound(SoundEvents.BLOCK_NOTE_CHIME, 1, 1); } else { current = SpellRegistry.instance().disenchantStack(current); @@ -102,7 +124,7 @@ public class ContainerSpellBook extends Container { stack = slotStack.copy(); if (index > 5) { - if (stack.getItem() instanceof ItemSpell) { + if (!resultSlot.getHasStack() && resultSlot.isItemValid(stack)) { if (!mergeItemStack(slotStack, 5, 6, false)) { return ItemStack.EMPTY; } @@ -130,18 +152,14 @@ public class ContainerSpellBook extends Container { @Override public void onContainerClosed(EntityPlayer player) { - super.onContainerClosed(player); + clearContainer(player, worldObj, craftMatrix); + clearContainer(player, worldObj, craftResult); - for (int i = 0; i < craftMatrix.getSizeInventory(); i++) { - if (craftMatrix.getStackInSlot(i) != null) { - player.dropItem(craftMatrix.getStackInSlot(i), false); - craftMatrix.setInventorySlotContents(i, ItemStack.EMPTY); - } - } + ItemStack held = player.inventory.getItemStack(); - if (craftResult.getStackInSlot(0) != null) { - player.dropItem(craftResult.getStackInSlot(0), false); - craftResult.setInventorySlotContents(0, ItemStack.EMPTY); + if (!held.isEmpty()) { + player.inventory.setItemStack(ItemStack.EMPTY); + player.inventory.placeItemBackInInventory(worldObj, held); } } diff --git a/src/main/java/com/minelittlepony/unicopia/inventory/slot/SlotEnchantingResult.java b/src/main/java/com/minelittlepony/unicopia/inventory/slot/SlotEnchantingResult.java index 411deb49..32a30fbc 100644 --- a/src/main/java/com/minelittlepony/unicopia/inventory/slot/SlotEnchantingResult.java +++ b/src/main/java/com/minelittlepony/unicopia/inventory/slot/SlotEnchantingResult.java @@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.spell.SpellRegistry; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemRecord; import net.minecraft.item.ItemStack; import net.minecraft.util.NonNullList; @@ -89,7 +90,8 @@ public class SlotEnchantingResult extends SlotEnchanting { @Override public boolean isItemValid(ItemStack stack) { - return stack.getItem() instanceof ItemSpell && !SpellRegistry.stackHasEnchantment(stack); + return (stack.getItem() instanceof ItemSpell || stack.getItem() instanceof ItemRecord) + && !SpellRegistry.stackHasEnchantment(stack); } @Override diff --git a/src/main/resources/assets/unicopia/enchanting/ingredients/apple_bloom.json b/src/main/resources/assets/unicopia/enchanting/ingredients/apple_bloom.json new file mode 100644 index 00000000..8e428899 --- /dev/null +++ b/src/main/resources/assets/unicopia/enchanting/ingredients/apple_bloom.json @@ -0,0 +1,8 @@ +{ + "items": [ + { "id": "unicopia:regular_apples" }, + { "item": "unicopia:apple_cider" }, + { "item": "unicopia:apple_seeds" }, + { "item": "minecraft:dye", "data": 1 } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/enchanting/ingredients/regular_apples.json b/src/main/resources/assets/unicopia/enchanting/ingredients/regular_apples.json new file mode 100644 index 00000000..7b538461 --- /dev/null +++ b/src/main/resources/assets/unicopia/enchanting/ingredients/regular_apples.json @@ -0,0 +1,8 @@ +{ + "items": [ + { "item": "minecraft:apple" }, + { "item": "unicopia:apple_green" }, + { "item": "unicopia:apple_sweet" }, + { "item": "unicopia:apple_sour" } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/enchanting/ingredients/scootaloo.json b/src/main/resources/assets/unicopia/enchanting/ingredients/scootaloo.json new file mode 100644 index 00000000..a8a0c031 --- /dev/null +++ b/src/main/resources/assets/unicopia/enchanting/ingredients/scootaloo.json @@ -0,0 +1,8 @@ +{ + "items": [ + { "item": "minecraft:chicken" }, + { "item": "minecraft:cooked_chicken" }, + { "item": "minecraft:feather" }, + { "item": "minecraft:string" } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/enchanting/ingredients/sound.json b/src/main/resources/assets/unicopia/enchanting/ingredients/sound.json new file mode 100644 index 00000000..352edf39 --- /dev/null +++ b/src/main/resources/assets/unicopia/enchanting/ingredients/sound.json @@ -0,0 +1,15 @@ +{ + "items": [ + { "item": "minecraft:record_13" }, + { "item": "minecraft:record_cat" }, + { "item": "minecraft:record_blocks" }, + { "item": "minecraft:record_chirp" }, + { "item": "minecraft:record_far" }, + { "item": "minecraft:record_mall" }, + { "item": "minecraft:record_mellohi" }, + { "item": "minecraft:record_stal" }, + { "item": "minecraft:record_strad" }, + { "item": "minecraft:record_ward" }, + { "item": "minecraft:record_wait" } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/enchanting/ingredients/sweetie_belle.json b/src/main/resources/assets/unicopia/enchanting/ingredients/sweetie_belle.json new file mode 100644 index 00000000..f5406c91 --- /dev/null +++ b/src/main/resources/assets/unicopia/enchanting/ingredients/sweetie_belle.json @@ -0,0 +1,7 @@ +{ + "items": [ + { "item": "minecraft:noteblock" }, + { "item": "minecraft:jukebox" }, + { "item": "minecraft:diamond" } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/enchanting/recipes/record_crusade.json b/src/main/resources/assets/unicopia/enchanting/recipes/record_crusade.json new file mode 100644 index 00000000..a0090547 --- /dev/null +++ b/src/main/resources/assets/unicopia/enchanting/recipes/record_crusade.json @@ -0,0 +1,16 @@ +{ + "type": "unicopia:crafting_special", + "ingredients": [ + { "id": "unicopia:apple_bloom" }, + { "id": "unicopia:scootaloo" }, + { "id": "unicopia:sweetie_belle" } + ], + "input": { + "item": [ + { "id": "unicopia:sound"} + ] + }, + "output": { + "item": { "item": "unicopia:record_crusade" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/enchanting/recipes/record_pet.json b/src/main/resources/assets/unicopia/enchanting/recipes/record_pet.json new file mode 100644 index 00000000..4ca4c212 --- /dev/null +++ b/src/main/resources/assets/unicopia/enchanting/recipes/record_pet.json @@ -0,0 +1,16 @@ +{ + "type": "unicopia:crafting_special", + "ingredients": [ + { "item": "unicopia:gem", "spell": "awkward" }, + { "item": "minecraft:feather" }, + { "item": "minecraft:carrot" } + ], + "input": { + "item": [ + { "id": "unicopia:sound" } + ] + }, + "output": { + "item": { "item": "unicopia:record_pet" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/enchanting/recipes/record_popular.json b/src/main/resources/assets/unicopia/enchanting/recipes/record_popular.json new file mode 100644 index 00000000..c9ae36b9 --- /dev/null +++ b/src/main/resources/assets/unicopia/enchanting/recipes/record_popular.json @@ -0,0 +1,16 @@ +{ + "type": "unicopia:crafting_special", + "ingredients": [ + { "item": "minecraft:diamond" }, + { "item": "minecraft:diamond" }, + { "item": "minecraft:diamond" } + ], + "input": { + "item": [ + { "id": "unicopia:sound"} + ] + }, + "output": { + "item": { "item": "unicopia:record_popular" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/enchanting/recipes/record_shuffle.json b/src/main/resources/assets/unicopia/enchanting/recipes/record_shuffle.json new file mode 100644 index 00000000..ca4bb929 --- /dev/null +++ b/src/main/resources/assets/unicopia/enchanting/recipes/record_shuffle.json @@ -0,0 +1,16 @@ +{ + "type": "unicopia:crafting_special", + "ingredients": [ + { "item": "unicopia:gem", "spell": "awkward" }, + { "item": "unicopia:gem", "spell": "awkward" }, + { "item": "unicopia:gem", "spell": "awkward" } + ], + "input": { + "item": [ + { "id": "unicopia:sound"} + ] + }, + "output": { + "item": { "id": "unicopia:sound" } + } +} \ No newline at end of file