From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: lexikiq Date: Tue, 13 Jul 2021 17:27:45 -0400 Subject: [PATCH] Add Furnace Recipe API Temporary API to get the result of smelting an item in a (type of) furnace. Will eventually (hopefully) be replaced by a more extensive Paper PR with support for all recipes. diff --git a/src/main/java/gg/projecteden/parchment/inventory/CraftRecipeType.java b/src/main/java/gg/projecteden/parchment/inventory/CraftRecipeType.java new file mode 100644 index 0000000000000000000000000000000000000000..5549da2a0b0790699abff627148a6b15ca37febf --- /dev/null +++ b/src/main/java/gg/projecteden/parchment/inventory/CraftRecipeType.java @@ -0,0 +1,44 @@ +package gg.projecteden.parchment.inventory; + +import net.minecraft.world.item.crafting.AbstractCookingRecipe; + +public class CraftRecipeType { + public static net.minecraft.world.item.crafting.RecipeType asNMS(RecipeType recipeType) { + return switch (recipeType) { + case CRAFTING -> net.minecraft.world.item.crafting.RecipeType.CRAFTING; + case SMELTING -> net.minecraft.world.item.crafting.RecipeType.SMELTING; + case BLASTING -> net.minecraft.world.item.crafting.RecipeType.BLASTING; + case SMOKING -> net.minecraft.world.item.crafting.RecipeType.SMOKING; + case CAMPFIRE_COOKING -> net.minecraft.world.item.crafting.RecipeType.CAMPFIRE_COOKING; + case STONECUTTING -> net.minecraft.world.item.crafting.RecipeType.STONECUTTING; + case SMITHING -> net.minecraft.world.item.crafting.RecipeType.SMITHING; + }; + } + + public static RecipeType asBukkit(net.minecraft.world.item.crafting.RecipeType recipeType) { + if (recipeType == net.minecraft.world.item.crafting.RecipeType.CRAFTING) { + return RecipeType.CRAFTING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.SMELTING) { + return RecipeType.SMELTING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.BLASTING) { + return RecipeType.BLASTING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.SMOKING) { + return RecipeType.SMOKING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.CAMPFIRE_COOKING) { + return RecipeType.CAMPFIRE_COOKING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.STONECUTTING) { + return RecipeType.STONECUTTING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.SMITHING) { + return RecipeType.SMITHING; + } + throw new IllegalArgumentException("Unknown recipe type"); + } + + public static net.minecraft.world.item.crafting.RecipeType asCookingRecipe(RecipeType recipeType) { + try { + return (net.minecraft.world.item.crafting.RecipeType) asNMS(recipeType); + } catch (ClassCastException exc) { + throw new IllegalArgumentException("Recipe type must be a cooking recipe"); + } + } +} diff --git a/src/main/java/gg/projecteden/parchment/inventory/SingletonContainer.java b/src/main/java/gg/projecteden/parchment/inventory/SingletonContainer.java new file mode 100644 index 0000000000000000000000000000000000000000..e7114e456f818d7bdd4081620f4b9b9376679145 --- /dev/null +++ b/src/main/java/gg/projecteden/parchment/inventory/SingletonContainer.java @@ -0,0 +1,151 @@ +package gg.projecteden.parchment.inventory; + +import com.google.common.base.Preconditions; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * A container which holds only one item and returns similar values to that of + * {@link net.minecraft.world.SimpleContainer SimpleContainer}, meaning it will raise + * {@link IndexOutOfBoundsException IndexOutOfBoundsExceptions} and return empty item stacks + * where applicable to mirror that class. + */ +public class SingletonContainer implements net.minecraft.world.Container { + + private @NotNull ItemStack item; + private int maxStackSize = Container.MAX_STACK; + + public SingletonContainer() { + this.item = ItemStack.EMPTY; + } + + public SingletonContainer(@NotNull ItemStack item) { + this.item = Preconditions.checkNotNull(item, "item"); + } + + public SingletonContainer(org.bukkit.inventory.@NotNull ItemStack item) { + this.item = CraftItemStack.asNMSCopy(Preconditions.checkNotNull(item, "item")); + } + + public SingletonContainer(@NotNull Material material) { + this(new org.bukkit.inventory.ItemStack(Preconditions.checkNotNull(material, "material"))); + } + + private static void throwIndexException(int index) { + throw new IndexOutOfBoundsException("Received slot " + index + ", expected 0"); + } + + @Override + public int getContainerSize() { + return 1; + } + + @Override + public boolean isEmpty() { + return item.isEmpty(); + } + + @Override + public ItemStack getItem(int slot) { + if (slot < 0) { + throwIndexException(slot); + } + return slot == 0 ? item : ItemStack.EMPTY; + } + + @Override + public ItemStack removeItem(int slot, int amount) { + if (slot < 0) { + throwIndexException(slot); + } + ItemStack itemStack = slot == 0 && !item.isEmpty() ? item.split(amount) : ItemStack.EMPTY; + if (!itemStack.isEmpty()) { + setChanged(); + } + return itemStack; + } + + @Override + public ItemStack removeItemNoUpdate(int slot) { + if (slot != 0) { + throwIndexException(slot); + } + ItemStack oldItem = item; + item = ItemStack.EMPTY; + return oldItem.isEmpty() ? ItemStack.EMPTY : oldItem; + } + + @Override + public void setItem(int slot, ItemStack stack) { + if (slot != 0) { + throwIndexException(slot); + } + item = stack; + } + + @Override + public int getMaxStackSize() { + return maxStackSize; + } + + @Override + public void setMaxStackSize(int size) { + maxStackSize = size; + } + + @Override + public void setChanged() { + + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public List getContents() { + return Collections.singletonList(item); + } + + @Override + public void onOpen(CraftHumanEntity who) { + + } + + @Override + public void onClose(CraftHumanEntity who) { + + } + + @Override + public List getViewers() { + return Collections.emptyList(); + } + + @Override + public InventoryHolder getOwner() { + return null; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public void clearContent() { + item = ItemStack.EMPTY; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 89514af7f3771db496e7e2a40fa4e7fdf527f095..5e6a5b7bf9ecea3445ae3f8de1e8b826afc3ccab 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -2430,4 +2430,11 @@ public class CraftWorld extends CraftRegionAccessor implements World { return this.adventure$pointers; } // Paper end + + // Parchment start + @Override + public ItemStack smeltItem(ItemStack toSmelt, gg.projecteden.parchment.inventory.RecipeType recipeType) { + return world.getRecipeManager().getRecipeFor(gg.projecteden.parchment.inventory.CraftRecipeType.asCookingRecipe(recipeType), new gg.projecteden.parchment.inventory.SingletonContainer(toSmelt), world).map(recipe -> recipe.getResultItem(world.registryAccess()).getBukkitStack()).orElse(null); + } + // Parchment end }