From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jake Potrebic <jake.m.potrebic@gmail.com> Date: Thu, 7 Oct 2021 14:34:55 -0700 Subject: [PATCH] Custom Potion Mixes diff --git a/src/main/java/io/papermc/paper/potion/PaperPotionMix.java b/src/main/java/io/papermc/paper/potion/PaperPotionMix.java new file mode 100644 index 0000000000000000000000000000000000000000..6b0bed550763f34e18c9e92f9a47ec0c945b2c8b --- /dev/null +++ b/src/main/java/io/papermc/paper/potion/PaperPotionMix.java @@ -0,0 +1,13 @@ +package io.papermc.paper.potion; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.inventory.CraftRecipe; + +public record PaperPotionMix(ItemStack result, Ingredient input, Ingredient ingredient) { + + public PaperPotionMix(PotionMix potionMix) { + this(CraftItemStack.asNMSCopy(potionMix.getResult()), CraftRecipe.toIngredient(potionMix.getInput(), true), CraftRecipe.toIngredient(potionMix.getIngredient(), true)); + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index cd1edd0cb404cab5e71efdb82f3b911c2fe96d01..dca520534feac302b8e0f389ee9286bd719e31a6 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -2033,6 +2033,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa this.worldData.setDataPackConfig(MinecraftServer.getSelectedPacks(this.packRepository)); this.resources.managers.updateRegistryTags(this.registryAccess()); io.papermc.paper.registry.PaperRegistry.clearCaches(); // Paper + net.minecraft.world.item.alchemy.PotionBrewing.reload(); // Paper new io.papermc.paper.event.server.ServerResourcesReloadedEvent(cause).callEvent(); // Paper // Paper start if (Thread.currentThread() != this.serverThread) { diff --git a/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java b/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java index a809e8a903f98fcbcea3184fac6dfd04adc735f9..13720c2df8ac37d020d4a785e48c45877edf74b9 100644 --- a/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java +++ b/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java @@ -168,7 +168,7 @@ public class BrewingStandMenu extends AbstractContainerMenu { } public static boolean mayPlaceItem(ItemStack stack) { - return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE); + return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || PotionBrewing.isCustomInput(stack); // Paper } } diff --git a/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java b/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java index eee96f87f68d9146b1d19d5923d073fb5c39d507..5d86895f93cadcf0b123263c2a6f718fedcb24ac 100644 --- a/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java +++ b/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java @@ -14,6 +14,7 @@ public class PotionBrewing { public static final int BREWING_TIME_SECONDS = 20; private static final List<PotionBrewing.Mix<Potion>> POTION_MIXES = Lists.newArrayList(); private static final List<PotionBrewing.Mix<Item>> CONTAINER_MIXES = Lists.newArrayList(); + private static final it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<org.bukkit.NamespacedKey, io.papermc.paper.potion.PaperPotionMix> CUSTOM_MIXES = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // Paper private static final List<Ingredient> ALLOWED_CONTAINERS = Lists.newArrayList(); private static final Predicate<ItemStack> ALLOWED_CONTAINER = (stack) -> { for(Ingredient ingredient : ALLOWED_CONTAINERS) { @@ -26,7 +27,7 @@ public class PotionBrewing { }; public static boolean isIngredient(ItemStack stack) { - return isContainerIngredient(stack) || isPotionIngredient(stack); + return isContainerIngredient(stack) || isPotionIngredient(stack) || isCustomIngredient(stack); // Paper } protected static boolean isContainerIngredient(ItemStack stack) { @@ -66,6 +67,11 @@ public class PotionBrewing { } public static boolean hasMix(ItemStack input, ItemStack ingredient) { + // Paper start + if (hasCustomMix(input, ingredient)) { + return true; + } + // Paper end if (!ALLOWED_CONTAINER.test(input)) { return false; } else { @@ -103,6 +109,13 @@ public class PotionBrewing { public static ItemStack mix(ItemStack ingredient, ItemStack input) { if (!input.isEmpty()) { + // Paper start + for (var mix : CUSTOM_MIXES.values()) { + if (mix.input().test(input) && mix.ingredient().test(ingredient)) { + return mix.result().copy(); + } + } + // Paper end Potion potion = PotionUtils.getPotion(input); Item item = input.getItem(); int i = 0; @@ -127,6 +140,54 @@ public class PotionBrewing { return input; } + // Paper start + public static boolean isCustomIngredient(ItemStack stack) { + for (var mix : CUSTOM_MIXES.values()) { + if (mix.ingredient().test(stack)) { + return true; + } + } + return false; + } + + public static boolean isCustomInput(ItemStack stack) { + for (var mix : CUSTOM_MIXES.values()) { + if (mix.input().test(stack)) { + return true; + } + } + return false; + } + + private static boolean hasCustomMix(ItemStack input, ItemStack ingredient) { + for (var mix : CUSTOM_MIXES.values()) { + if (mix.input().test(input) && mix.ingredient().test(ingredient)) { + return true; + } + } + return false; + } + + public static void addPotionMix(io.papermc.paper.potion.PotionMix mix) { + if (CUSTOM_MIXES.containsKey(mix.getKey())) { + throw new IllegalArgumentException("Duplicate recipe ignored with ID " + mix.getKey()); + } + CUSTOM_MIXES.putAndMoveToFirst(mix.getKey(), new io.papermc.paper.potion.PaperPotionMix(mix)); + } + + public static boolean removePotionMix(org.bukkit.NamespacedKey key) { + return CUSTOM_MIXES.remove(key) != null; + } + + public static void reload() { + POTION_MIXES.clear(); + CONTAINER_MIXES.clear(); + ALLOWED_CONTAINERS.clear(); + CUSTOM_MIXES.clear(); + bootStrap(); + } + // Paper end + public static void bootStrap() { addContainer(Items.POTION); addContainer(Items.SPLASH_POTION); diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java index 3d688e334c7287f41460bd866bfd1155e8bb55d2..55006724ccec9f3de828ec18693728e9741ff65f 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java @@ -335,7 +335,7 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements @Override public boolean canPlaceItem(int slot, ItemStack stack) { - return slot == 3 ? PotionBrewing.isIngredient(stack) : (slot == 4 ? stack.is(Items.BLAZE_POWDER) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE)) && this.getItem(slot).isEmpty()); + return slot == 3 ? PotionBrewing.isIngredient(stack) : (slot == 4 ? stack.is(Items.BLAZE_POWDER) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || PotionBrewing.isCustomInput(stack)) && this.getItem(slot).isEmpty()); // Paper } @Override diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 8d1992ba6446c2c5a3b4e2410603d98110207d5f..91ba3684c73bb127d67c6385bf55e71d96f69075 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -283,6 +283,7 @@ public final class CraftServer implements Server { private final io.papermc.paper.datapack.PaperDatapackManager datapackManager; // Paper public static Exception excessiveVelEx; // Paper - Velocity warnings private final io.papermc.paper.logging.SysoutCatcher sysoutCatcher = new io.papermc.paper.logging.SysoutCatcher(); // Paper + private final CraftPotionBrewer potionBrewer = new CraftPotionBrewer(); // Paper static { ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); @@ -309,7 +310,7 @@ public final class CraftServer implements Server { Enchantments.SHARPNESS.getClass(); org.bukkit.enchantments.Enchantment.stopAcceptingRegistrations(); - Potion.setPotionBrewer(new CraftPotionBrewer()); + Potion.setPotionBrewer(potionBrewer); // Paper MobEffects.BLINDNESS.getClass(); PotionEffectType.stopAcceptingRegistrations(); // Ugly hack :( @@ -2889,5 +2890,10 @@ public final class CraftServer implements Server { return datapackManager; } + @Override + public CraftPotionBrewer getPotionBrewer() { + return this.potionBrewer; + } + // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java index 10ace7bb17c36bfefc584a6322841ab6ea4c866f..71486c08db28caf89f2366e082f6f6fab5609b71 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java @@ -13,6 +13,11 @@ public interface CraftRecipe extends Recipe { void addToCraftingManager(); default Ingredient toNMS(RecipeChoice bukkit, boolean requireNotEmpty) { + // Paper start + return toIngredient(bukkit, requireNotEmpty); + } + static Ingredient toIngredient(RecipeChoice bukkit, boolean requireNotEmpty) { + // Paper end Ingredient stack; if (bukkit == null) { diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java index 8fdc9a3bb2f1b6bdc6c2c96f8ade7e9cd88ea4e0..a0b0c64b819b8f713eeea78210e276664e30e66e 100644 --- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java +++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java @@ -49,4 +49,21 @@ public class CraftPotionBrewer implements PotionBrewer { public PotionEffect createEffect(PotionEffectType potion, int duration, int amplifier) { return new PotionEffect(potion, potion.isInstant() ? 1 : (int) (duration * potion.getDurationModifier()), amplifier); } + + // Paper start + @Override + public void addPotionMix(io.papermc.paper.potion.PotionMix potionMix) { + net.minecraft.world.item.alchemy.PotionBrewing.addPotionMix(potionMix); + } + + @Override + public void removePotionMix(org.bukkit.NamespacedKey key) { + net.minecraft.world.item.alchemy.PotionBrewing.removePotionMix(key); + } + + @Override + public void resetPotionMixes() { + net.minecraft.world.item.alchemy.PotionBrewing.reload(); + } + // Paper end }