From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jake Potrebic 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..7ea357ac2f3a93db4ebdf24b5072be7d1cad3e33 --- /dev/null +++ b/src/main/java/io/papermc/paper/potion/PaperPotionMix.java @@ -0,0 +1,21 @@ +package io.papermc.paper.potion; + +import java.util.function.Predicate; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.inventory.CraftRecipe; +import org.bukkit.inventory.RecipeChoice; + +public record PaperPotionMix(ItemStack result, Predicate input, Predicate ingredient) { + + public PaperPotionMix(PotionMix potionMix) { + this(CraftItemStack.asNMSCopy(potionMix.getResult()), convert(potionMix.getInput()), convert(potionMix.getIngredient())); + } + + static Predicate convert(final RecipeChoice choice) { + if (choice instanceof PredicateRecipeChoice predicateRecipeChoice) { + return stack -> predicateRecipeChoice.test(CraftItemStack.asBukkitCopy(stack)); + } + return CraftRecipe.toIngredient(choice, true); + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index ea442883eda28e5673cef9470145d5c40ac66159..25ce1b9dbaa77e2c8541d995a2c28f894cee9d38 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -291,7 +291,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop public (remove final) private volatile boolean isSaving; // CraftBukkit start @@ -2141,6 +2141,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop containers; private final List> potionMixes; private final List> containerMixes; + private static final it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap CUSTOM_MIXES = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // Paper - Custom Potion Mixes PotionBrewing(List potionTypes, List> potionRecipes, List> itemRecipes) { this.containers = potionTypes; @@ -27,7 +28,7 @@ public class PotionBrewing { } public boolean isIngredient(ItemStack stack) { - return this.isContainerIngredient(stack) || this.isPotionIngredient(stack); + return this.isContainerIngredient(stack) || this.isPotionIngredient(stack) || isCustomIngredient(stack); // Paper - Custom Potion Mixes } private boolean isContainer(ItemStack stack) { @@ -71,6 +72,11 @@ public class PotionBrewing { } public boolean hasMix(ItemStack input, ItemStack ingredient) { + // Paper start - Custom Potion Mixes + if (hasCustomMix(input, ingredient)) { + return true; + } + // Paper end - Custom Potion Mixes return this.isContainer(input) && (this.hasContainerMix(input, ingredient) || this.hasPotionMix(input, ingredient)); } @@ -107,6 +113,13 @@ public class PotionBrewing { if (optional.isEmpty()) { return input; } else { + // Paper start - Custom Potion Mixes + for (var mix : CUSTOM_MIXES.values()) { + if (mix.input().test(input) && mix.ingredient().test(ingredient)) { + return mix.result().copy(); + } + } + // Paper end - Custom Potion Mixes for (PotionBrewing.Mix mix : this.containerMixes) { if (input.is(mix.from) && mix.ingredient.test(ingredient)) { return PotionContents.createItemStack(mix.to.value(), optional.get()); @@ -190,6 +203,50 @@ public class PotionBrewing { builder.addMix(Potions.SLOW_FALLING, Items.REDSTONE, Potions.LONG_SLOW_FALLING); } + // Paper start - Custom Potion Mixes + 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 PotionBrewing reload(FeatureFlagSet flags) { + return bootstrap(flags); + } + // Paper end - Custom Potion Mixes + public static class Builder { private final List containers = new ArrayList<>(); private final List> potionMixes = new ArrayList<>(); 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 3ebfd564d4bbf00da5919e966f3d047285845640..c1254088fc65fe46101c82cf2629cf0269711d39 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 @@ -316,7 +316,7 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements return potionbrewer.isIngredient(stack); } else { - return 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 == 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 - Custom Potion Mixes } } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index e25dc948bfd59b8d0a9350c0ffe496f53d042ab8..e1903d551e2183cc92dfb4fc832ec5bf961475d1 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -308,6 +308,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 org.bukkit.craftbukkit.potion.CraftPotionBrewer potionBrewer; // Paper - Custom Potion Mixes static { ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); @@ -389,6 +390,7 @@ public final class CraftServer implements Server { if (this.configuration.getBoolean("settings.use-map-color-cache")) { MapPalette.setMapColorCache(new CraftMapColorCache(this.logger)); } + this.potionBrewer = new org.bukkit.craftbukkit.potion.CraftPotionBrewer(playerList.getServer()); // Paper - custom potion mixes datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper } @@ -3100,5 +3102,10 @@ public final class CraftServer implements Server { return datapackManager; } + @Override + public org.bukkit.craftbukkit.potion.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 139dff90561ac6c51954c6289918a07aeea13a1b..6ba29875d78ede4aa7978ff689e588f7fed11528 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java @@ -15,6 +15,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 new file mode 100644 index 0000000000000000000000000000000000000000..bb47c776cf1d92ef85a5a10d1c42f120457d21c1 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java @@ -0,0 +1,66 @@ +package org.bukkit.craftbukkit.potion; + +import com.google.common.base.Preconditions; +import java.util.ArrayList; +import java.util.Collection; +import org.bukkit.potion.PotionBrewer; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; + +public class CraftPotionBrewer implements PotionBrewer { + + private final net.minecraft.server.MinecraftServer minecraftServer; + + public CraftPotionBrewer(net.minecraft.server.MinecraftServer minecraftServer) { + this.minecraftServer = minecraftServer; + } + + // Paper start - keep old spigot methods, removal in 1.20.6 + @Override + public Collection getEffects(PotionType type, boolean upgraded, boolean extended) { + final org.bukkit.NamespacedKey key = type.getKey(); + + Preconditions.checkArgument(!key.getKey().startsWith("strong_"), "Strong potion type cannot be used directly, got %s", key); + Preconditions.checkArgument(!key.getKey().startsWith("long_"), "Extended potion type cannot be used directly, got %s", key); + + org.bukkit.NamespacedKey effectiveKey = key; + if (upgraded) { + effectiveKey = new org.bukkit.NamespacedKey(key.namespace(), "strong_" + key.key()); + } else if (extended) { + effectiveKey = new org.bukkit.NamespacedKey(key.namespace(), "long_" + key.key()); + } + + final org.bukkit.potion.PotionType effectivePotionType = org.bukkit.Registry.POTION.get(effectiveKey); + Preconditions.checkNotNull(type, "Unknown potion type from data " + effectiveKey.asMinimalString()); // Legacy error message in 1.20.4 + return effectivePotionType.getPotionEffects(); + } + + @Override + public Collection getEffectsFromDamage(int damage) { + return new ArrayList<>(); + } + + @Override + public PotionEffect createEffect(PotionEffectType potion, int duration, int amplifier) { + return new PotionEffect(potion, potion.isInstant() ? 1 : duration, amplifier); + } + // Paper end - keep old spigot methods, removal in 1.20.6 + + // 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() { + this.minecraftServer.potionBrewing = this.minecraftServer.potionBrewing().reload(this.minecraftServer.getWorldData().enabledFeatures()); + } + // Paper end +}