From 0b5d7ad8d624ff970d4d006b6035fe54339d797e Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Thu, 7 Oct 2021 14:34:55 -0700 Subject: [PATCH] Custom Potion Mixes == AT == public-f net.minecraft.server.MinecraftServer potionBrewing --- .../server/MinecraftServer.java.patch | 63 ++++++------ .../inventory/BrewingStandMenu.java.patch | 58 ++++++++++- .../item/alchemy/PotionBrewing.java.patch | 96 +++++++++++++++++++ .../entity/BrewingStandBlockEntity.java.patch | 15 +++ .../paper/potion/PaperPotionBrewer.java | 56 +++++++++++ .../papermc/paper/potion/PaperPotionMix.java | 21 ++++ .../org/bukkit/craftbukkit/CraftServer.java | 6 ++ .../craftbukkit/inventory/CraftRecipe.java | 5 + 8 files changed, 286 insertions(+), 34 deletions(-) create mode 100644 paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch create mode 100644 paper-server/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java create mode 100644 paper-server/src/main/java/io/papermc/paper/potion/PaperPotionMix.java diff --git a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch index 1d306dc5b5..40752ad5f1 100644 --- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -564,12 +564,10 @@ if (!iworlddataserver.isInitialized()) { try { -@@ -425,32 +724,10 @@ - } - +@@ -427,30 +726,8 @@ iworlddataserver.setInitialized(true); -- } -- + } + - this.getPlayerList().addWorldborderListener(worldserver); - if (this.worldData.getCustomBossEvents() != null) { - this.getCustomBossEvents().load(this.worldData.getCustomBossEvents(), this.registryAccess()); @@ -590,8 +588,8 @@ - worldborder.addListener(new BorderChangeListener.DelegateBorderChangeListener(worldserver1.getWorldBorder())); - this.levels.put(resourcekey1, worldserver1); - } - } - +- } +- - worldborder.applySettings(iworlddataserver.getWorldBorder()); } + // CraftBukkit end @@ -870,7 +868,7 @@ while (this.running) { long i; -@@ -744,12 +1161,31 @@ +@@ -744,11 +1161,30 @@ if (j > MinecraftServer.OVERLOADED_THRESHOLD_NANOS + 20L * i && this.nextTickTimeNanos - this.lastOverloadWarningNanos >= MinecraftServer.OVERLOADED_WARNING_INTERVAL_NANOS + 100L * i) { long k = j / i; @@ -889,7 +887,7 @@ + tps1.add(currentTps, diff); + tps5.add(currentTps, diff); + tps15.add(currentTps, diff); - ++ + // Backwards compat with bad plugins + this.recentTps[0] = tps1.getAverage(); + this.recentTps[1] = tps5.getAverage(); @@ -898,10 +896,9 @@ + } + // Paper end - further improve server tick loop + // Spigot end -+ + boolean flag = i == 0L; - if (this.debugCommandProfilerDelayStart) { @@ -757,6 +1193,8 @@ this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount); } @@ -1247,7 +1244,7 @@ }, this).thenCompose((immutablelist) -> { MultiPackResourceManager resourcemanager = new MultiPackResourceManager(PackType.SERVER_DATA, immutablelist); List> list = TagLoader.loadTagsForExistingRegistries(resourcemanager, this.registries.compositeAccess()); -@@ -1654,6 +2189,7 @@ +@@ -1654,17 +2189,21 @@ }).thenAcceptAsync((minecraftserver_reloadableresources) -> { this.resources.close(); this.resources = minecraftserver_reloadableresources; @@ -1255,7 +1252,12 @@ this.packRepository.setSelected(dataPacks); WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(MinecraftServer.getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()); -@@ -1665,6 +2201,8 @@ + this.worldData.setDataConfiguration(worlddataconfiguration); + this.resources.managers.updateStaticRegistryTags(); + this.resources.managers.getRecipeManager().finalizeRecipeLoading(this.worldData.enabledFeatures()); ++ this.potionBrewing = this.potionBrewing.reload(this.worldData.enabledFeatures()); // Paper - Custom Potion Mixes + this.getPlayerList().saveAll(); + this.getPlayerList().reloadResources(); this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary()); this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager); this.fuelValues = FuelValues.vanillaBurnTimes(this.registries.compositeAccess(), this.worldData.enabledFeatures()); @@ -1264,7 +1266,7 @@ }, this); if (this.isSameThread()) { -@@ -1789,14 +2327,15 @@ +@@ -1789,14 +2328,15 @@ if (this.isEnforceWhitelist()) { PlayerList playerlist = source.getServer().getPlayerList(); UserWhiteList whitelist = playerlist.getWhiteList(); @@ -1282,7 +1284,7 @@ } } -@@ -1952,7 +2491,7 @@ +@@ -1952,7 +2492,7 @@ final List list = Lists.newArrayList(); final GameRules gamerules = this.getGameRules(); @@ -1291,7 +1293,7 @@ @Override public > void visit(GameRules.Key key, GameRules.Type type) { list.add(String.format(Locale.ROOT, "%s=%s\n", key.getId(), gamerules.getRule(key))); -@@ -2058,7 +2597,7 @@ +@@ -2058,7 +2598,7 @@ try { label51: { @@ -1300,22 +1302,19 @@ try { arraylist = Lists.newArrayList(NativeModuleLister.listModules()); -@@ -2105,9 +2644,24 @@ - if (bufferedwriter != null) { - bufferedwriter.close(); - } -+ -+ } -+ +@@ -2108,6 +2648,21 @@ + + } + + // CraftBukkit start + public boolean isDebugging() { + return false; + } - ++ + public static MinecraftServer getServer() { + return SERVER; // Paper - } - ++ } ++ + @Deprecated + public static RegistryAccess getDefaultRegistryAccess() { + return CraftRegistry.getMinecraftRegistry(); @@ -1325,7 +1324,7 @@ private ProfilerFiller createProfiler() { if (this.willStartRecordingMetrics) { this.metricsRecorder = ActiveMetricsRecorder.createStarted(new ServerMetricsSamplersProvider(Util.timeSource, this.isDedicatedServer()), Util.timeSource, Util.ioPool(), new MetricsPersister("server"), this.onMetricsRecordingStopped, (path) -> { -@@ -2225,18 +2779,24 @@ +@@ -2225,18 +2780,24 @@ } public void logChatMessage(Component message, ChatType.Bound params, @Nullable String prefix) { @@ -1354,11 +1353,13 @@ } public boolean logIPs() { -@@ -2379,4 +2939,30 @@ - public static record ServerResourcePackInfo(UUID id, String url, String hash, boolean isRequired, @Nullable Component prompt) { - +@@ -2377,6 +2938,32 @@ } + + public static record ServerResourcePackInfo(UUID id, String url, String hash, boolean isRequired, @Nullable Component prompt) { + ++ } + + // Paper start - Add tick times API and /mspt command + public static class TickTimes { + private final long[] times; @@ -1382,6 +1383,6 @@ + } + return ((double) total / (double) times.length) * 1.0E-6D; + } -+ } + } + // Paper end - Add tick times API and /mspt command } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/BrewingStandMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/BrewingStandMenu.java.patch index 0c1256203d..5649df7a88 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/BrewingStandMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/BrewingStandMenu.java.patch @@ -11,7 +11,7 @@ public class BrewingStandMenu extends AbstractContainerMenu { -@@ -35,12 +39,18 @@ +@@ -35,21 +39,29 @@ public final ContainerData brewingStandData; private final Slot ingredientSlot; @@ -30,7 +30,21 @@ checkContainerSize(inventory, 5); checkContainerDataCount(propertyDelegate, 2); this.brewingStand = inventory; -@@ -58,6 +68,7 @@ + this.brewingStandData = propertyDelegate; + PotionBrewing potionbrewer = playerInventory.player.level().potionBrewing(); + +- this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 0, 56, 51)); +- this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 1, 79, 58)); +- this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 2, 102, 51)); ++ // Paper start - custom potion mixes ++ this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 0, 56, 51, potionbrewer)); ++ this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 1, 79, 58, potionbrewer)); ++ this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 2, 102, 51, potionbrewer)); ++ // Paper end - custom potion mixes + this.ingredientSlot = this.addSlot(new BrewingStandMenu.IngredientsSlot(potionbrewer, inventory, 3, 79, 17)); + this.addSlot(new BrewingStandMenu.FuelSlot(inventory, 4, 17, 17)); + this.addDataSlots(propertyDelegate); +@@ -58,6 +70,7 @@ @Override public boolean stillValid(Player player) { @@ -38,7 +52,45 @@ return this.brewingStand.stillValid(player); } -@@ -198,4 +209,17 @@ +@@ -79,7 +92,7 @@ + if (!this.moveItemStackTo(itemstack1, 3, 4, false)) { + return ItemStack.EMPTY; + } +- } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(itemstack)) { ++ } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(itemstack, this.player.player.level().potionBrewing())) { // Paper - custom potion mixes + if (!this.moveItemStackTo(itemstack1, 0, 3, false)) { + return ItemStack.EMPTY; + } +@@ -128,13 +141,15 @@ + + private static class PotionSlot extends Slot { + +- public PotionSlot(Container inventory, int index, int x, int y) { ++ private final PotionBrewing potionBrewing; // Paper - custom potion mixes ++ public PotionSlot(Container inventory, int index, int x, int y, PotionBrewing potionBrewing) { // Paper - custom potion mixes + super(inventory, index, x, y); ++ this.potionBrewing = potionBrewing; // Paper - custom potion mixes + } + + @Override + public boolean mayPlace(ItemStack stack) { +- return PotionSlot.mayPlaceItem(stack); ++ return PotionSlot.mayPlaceItem(stack, this.potionBrewing); // Paper - custom potion mixes + } + + @Override +@@ -153,8 +168,8 @@ + super.onTake(player, stack); + } + +- 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); ++ public static boolean mayPlaceItem(ItemStack stack, PotionBrewing potionBrewing) { // Paper - custom potion mixes ++ return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionBrewing.isCustomInput(stack); // Paper - Custom Potion Mixes + } + + @Override +@@ -198,4 +213,17 @@ return BrewingStandMenu.EMPTY_SLOT_FUEL; } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch b/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch new file mode 100644 index 0000000000..c9c0b22f57 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch @@ -0,0 +1,96 @@ +--- a/net/minecraft/world/item/alchemy/PotionBrewing.java ++++ b/net/minecraft/world/item/alchemy/PotionBrewing.java +@@ -19,6 +19,7 @@ + private final List containers; + private final List> potionMixes; + private final List> containerMixes; ++ private final it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap customMixes = 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 boolean isIngredient(ItemStack stack) { +- return this.isContainerIngredient(stack) || this.isPotionIngredient(stack); ++ return this.isContainerIngredient(stack) || this.isPotionIngredient(stack) || this.isCustomIngredient(stack); // Paper - Custom Potion Mixes + } + + private boolean isContainer(ItemStack stack) { +@@ -71,6 +72,11 @@ + } + + public boolean hasMix(ItemStack input, ItemStack ingredient) { ++ // Paper start - Custom Potion Mixes ++ if (this.hasCustomMix(input, ingredient)) { ++ return true; ++ } ++ // Paper end - Custom Potion Mixes + return this.isContainer(input) && (this.hasContainerMix(input, ingredient) || this.hasPotionMix(input, ingredient)); + } + +@@ -103,6 +109,13 @@ + if (input.isEmpty()) { + return input; + } else { ++ // Paper start - Custom Potion Mixes ++ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { ++ if (mix.input().test(input) && mix.ingredient().test(ingredient)) { ++ return mix.result().copy(); ++ } ++ } ++ // Paper end - Custom Potion Mixes + Optional> optional = input.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).potion(); + if (optional.isEmpty()) { + return input; +@@ -190,6 +203,50 @@ + builder.addMix(Potions.SLOW_FALLING, Items.REDSTONE, Potions.LONG_SLOW_FALLING); + } + ++ // Paper start - Custom Potion Mixes ++ public boolean isCustomIngredient(ItemStack stack) { ++ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { ++ if (mix.ingredient().test(stack)) { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ public boolean isCustomInput(ItemStack stack) { ++ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { ++ if (mix.input().test(stack)) { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ private boolean hasCustomMix(ItemStack input, ItemStack ingredient) { ++ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { ++ if (mix.input().test(input) && mix.ingredient().test(ingredient)) { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ public void addPotionMix(io.papermc.paper.potion.PotionMix mix) { ++ if (this.customMixes.containsKey(mix.getKey())) { ++ throw new IllegalArgumentException("Duplicate recipe ignored with ID " + mix.getKey()); ++ } ++ this.customMixes.putAndMoveToFirst(mix.getKey(), new io.papermc.paper.potion.PaperPotionMix(mix)); ++ } ++ ++ public boolean removePotionMix(org.bukkit.NamespacedKey key) { ++ return this.customMixes.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/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch index 3732e9afc7..635b5aa5eb 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch @@ -179,3 +179,18 @@ } @Override +@@ -231,12 +316,12 @@ + + @Override + public boolean canPlaceItem(int slot, ItemStack stack) { ++ PotionBrewing potionbrewer = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY; // Paper - move up + if (slot == 3) { +- PotionBrewing potionbrewer = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY; + + return potionbrewer.isIngredient(stack); + } else { +- return slot == 4 ? stack.is(ItemTags.BREWING_FUEL) : (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(ItemTags.BREWING_FUEL) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionbrewer.isCustomInput(stack)) && this.getItem(slot).isEmpty(); // Paper - Custom Potion Mixes + } + } + diff --git a/paper-server/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java b/paper-server/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java new file mode 100644 index 0000000000..d9390227a2 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java @@ -0,0 +1,56 @@ +package io.papermc.paper.potion; + +import com.google.common.base.Preconditions; +import java.util.Collection; +import net.minecraft.server.MinecraftServer; +import org.bukkit.NamespacedKey; +import org.bukkit.potion.PotionBrewer; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionType; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; + +@DefaultQualifier(NonNull.class) +public class PaperPotionBrewer implements PotionBrewer { + + private final MinecraftServer minecraftServer; + + public PaperPotionBrewer(final MinecraftServer minecraftServer) { + this.minecraftServer = minecraftServer; + } + + @Override + @Deprecated(forRemoval = true) + 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 void addPotionMix(final PotionMix potionMix) { + this.minecraftServer.potionBrewing().addPotionMix(potionMix); + } + + @Override + public void removePotionMix(final NamespacedKey key) { + this.minecraftServer.potionBrewing.removePotionMix(key); + } + + @Override + public void resetPotionMixes() { + this.minecraftServer.potionBrewing = this.minecraftServer.potionBrewing().reload(this.minecraftServer.getWorldData().enabledFeatures()); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/potion/PaperPotionMix.java b/paper-server/src/main/java/io/papermc/paper/potion/PaperPotionMix.java new file mode 100644 index 0000000000..7ea357ac2f --- /dev/null +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 75bd961716..82e1c4713e 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -311,6 +311,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 io.papermc.paper.potion.PaperPotionBrewer potionBrewer; // Paper - Custom Potion Mixes static { ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); @@ -394,6 +395,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 io.papermc.paper.potion.PaperPotionBrewer(console); // Paper - custom potion mixes datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper } @@ -3076,5 +3078,9 @@ public final class CraftServer implements Server { return datapackManager; } + @Override + public io.papermc.paper.potion.PaperPotionBrewer getPotionBrewer() { + return this.potionBrewer; + } // Paper end } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java index fa47232eeb..5b176cd5f8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java @@ -23,6 +23,11 @@ public interface CraftRecipe extends Recipe { } 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) {