2022-02-23 04:09:15 +01:00
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
2024-04-27 01:17:13 +02:00
== AT ==
public-f net.minecraft.server.MinecraftServer potionBrewing
2022-02-23 04:09:15 +01:00
2024-04-27 01:17:13 +02:00
diff --git a/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java b/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9390227a2bba4e03aa9ee592ca157127633c41b
--- /dev/null
+++ b/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<PotionEffect> 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());
+ }
+}
2022-02-23 04:09:15 +01:00
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
2023-10-11 01:07:21 +02:00
index 0000000000000000000000000000000000000000..7ea357ac2f3a93db4ebdf24b5072be7d1cad3e33
2022-02-23 04:09:15 +01:00
--- /dev/null
+++ b/src/main/java/io/papermc/paper/potion/PaperPotionMix.java
2023-10-11 01:07:21 +02:00
@@ -0,0 +1,21 @@
2022-02-23 04:09:15 +01:00
+package io.papermc.paper.potion;
+
2023-10-11 01:07:21 +02:00
+import java.util.function.Predicate;
2022-02-23 04:09:15 +01:00
+import net.minecraft.world.item.ItemStack;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
2023-10-11 01:07:21 +02:00
+import org.bukkit.inventory.RecipeChoice;
2022-02-23 04:09:15 +01:00
+
2023-10-11 01:07:21 +02:00
+public record PaperPotionMix(ItemStack result, Predicate<ItemStack> input, Predicate<ItemStack> ingredient) {
2022-02-23 04:09:15 +01:00
+
+ public PaperPotionMix(PotionMix potionMix) {
2023-10-11 01:07:21 +02:00
+ this(CraftItemStack.asNMSCopy(potionMix.getResult()), convert(potionMix.getInput()), convert(potionMix.getIngredient()));
+ }
+
+ static Predicate<ItemStack> convert(final RecipeChoice choice) {
+ if (choice instanceof PredicateRecipeChoice predicateRecipeChoice) {
+ return stack -> predicateRecipeChoice.test(CraftItemStack.asBukkitCopy(stack));
+ }
+ return CraftRecipe.toIngredient(choice, true);
2022-02-23 04:09:15 +01:00
+ }
+}
2023-12-06 17:39:37 +01:00
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
2024-12-03 19:54:10 +01:00
index 03ee72a20330dd9ba6ff2808c1252454a6c217bc..fcc00d5b0be3d2adb92c8243ccca8d0190fcc413 100644
2023-12-06 17:39:37 +01:00
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
2024-10-27 18:11:15 +01:00
@@ -2196,6 +2196,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2023-12-06 17:39:37 +01:00
this.worldData.setDataConfiguration(worlddataconfiguration);
2024-10-23 22:52:43 +02:00
this.resources.managers.updateStaticRegistryTags();
this.resources.managers.getRecipeManager().finalizeRecipeLoading(this.worldData.enabledFeatures());
2024-04-26 17:33:00 +02:00
+ this.potionBrewing = this.potionBrewing.reload(this.worldData.enabledFeatures()); // Paper - Custom Potion Mixes
2024-01-23 12:06:27 +01:00
this.getPlayerList().saveAll();
this.getPlayerList().reloadResources();
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary());
2022-02-23 04:09:15 +01:00
diff --git a/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java b/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java
2024-12-03 19:54:10 +01:00
index 6acc06ab49549ebd80e9871dce7f3fe6ebde9498..d2688ca4430e2e45b35b97b0b3b7c79b5aac23a4 100644
2022-02-23 04:09:15 +01:00
--- a/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java
2024-12-03 19:54:10 +01:00
@@ -57,9 +57,11 @@ public class BrewingStandMenu extends AbstractContainerMenu {
2024-04-27 01:17:13 +02:00
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);
2024-12-03 19:54:10 +01:00
@@ -90,7 +92,7 @@ public class BrewingStandMenu extends AbstractContainerMenu {
2024-04-27 01:17:13 +02:00
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;
}
2024-12-03 19:54:10 +01:00
@@ -139,13 +141,15 @@ public class BrewingStandMenu extends AbstractContainerMenu {
2024-04-27 01:17:13 +02:00
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
2022-02-23 04:09:15 +01:00
}
2024-04-27 01:17:13 +02:00
@Override
public boolean mayPlace(ItemStack stack) {
- return PotionSlot.mayPlaceItem(stack);
+ return PotionSlot.mayPlaceItem(stack, this.potionBrewing); // Paper - custom potion mixes
}
@Override
2024-12-03 19:54:10 +01:00
@@ -164,8 +168,8 @@ public class BrewingStandMenu extends AbstractContainerMenu {
2024-04-27 01:17:13 +02:00
super.onTake(player, stack);
}
- public static boolean mayPlaceItem(ItemStack stack) {
2022-02-23 04:09:15 +01:00
- return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE);
2024-04-27 01:17:13 +02:00
+ 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
2022-02-23 04:09:15 +01:00
}
2024-12-03 19:54:10 +01:00
@Override
2022-02-23 04:09:15 +01:00
diff --git a/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java b/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java
2024-04-27 01:17:13 +02:00
index 50e81e3babd331077eda8daa769eb2b3f99e8ca2..ca01f3344005b295c7ae98f6d5b03f79513b12a4 100644
2022-02-23 04:09:15 +01:00
--- a/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java
+++ b/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java
2024-04-24 22:05:42 +02:00
@@ -19,6 +19,7 @@ public class PotionBrewing {
private final List<Ingredient> containers;
private final List<PotionBrewing.Mix<Potion>> potionMixes;
private final List<PotionBrewing.Mix<Item>> containerMixes;
2024-04-27 01:17:13 +02:00
+ private final it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<org.bukkit.NamespacedKey, io.papermc.paper.potion.PaperPotionMix> customMixes = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // Paper - Custom Potion Mixes
2022-02-23 04:09:15 +01:00
2024-04-24 22:05:42 +02:00
PotionBrewing(List<Ingredient> potionTypes, List<PotionBrewing.Mix<Potion>> potionRecipes, List<PotionBrewing.Mix<Item>> itemRecipes) {
this.containers = potionTypes;
@@ -27,7 +28,7 @@ public class PotionBrewing {
2022-02-23 04:09:15 +01:00
}
2024-04-24 22:05:42 +02:00
public boolean isIngredient(ItemStack stack) {
- return this.isContainerIngredient(stack) || this.isPotionIngredient(stack);
2024-04-27 01:17:13 +02:00
+ return this.isContainerIngredient(stack) || this.isPotionIngredient(stack) || this.isCustomIngredient(stack); // Paper - Custom Potion Mixes
2022-02-23 04:09:15 +01:00
}
2024-04-24 22:05:42 +02:00
private boolean isContainer(ItemStack stack) {
@@ -71,6 +72,11 @@ public class PotionBrewing {
}
public boolean hasMix(ItemStack input, ItemStack ingredient) {
2024-01-18 18:52:00 +01:00
+ // Paper start - Custom Potion Mixes
2024-04-27 01:17:13 +02:00
+ if (this.hasCustomMix(input, ingredient)) {
2022-02-23 04:09:15 +01:00
+ return true;
+ }
2024-01-18 18:52:00 +01:00
+ // Paper end - Custom Potion Mixes
2024-04-24 22:05:42 +02:00
return this.isContainer(input) && (this.hasContainerMix(input, ingredient) || this.hasPotionMix(input, ingredient));
2024-04-12 21:14:06 +02:00
}
2024-04-27 01:17:13 +02:00
@@ -103,6 +109,13 @@ public class PotionBrewing {
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<Holder<Potion>> optional = input.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).potion();
2024-04-24 22:05:42 +02:00
if (optional.isEmpty()) {
return input;
2024-04-26 17:33:00 +02:00
@@ -190,6 +203,50 @@ public class PotionBrewing {
2024-04-24 22:05:42 +02:00
builder.addMix(Potions.SLOW_FALLING, Items.REDSTONE, Potions.LONG_SLOW_FALLING);
2022-02-23 04:09:15 +01:00
}
2024-01-18 18:52:00 +01:00
+ // Paper start - Custom Potion Mixes
2024-04-27 01:17:13 +02:00
+ public boolean isCustomIngredient(ItemStack stack) {
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
2022-02-23 04:09:15 +01:00
+ if (mix.ingredient().test(stack)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
2024-04-27 01:17:13 +02:00
+ public boolean isCustomInput(ItemStack stack) {
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
2022-02-23 04:09:15 +01:00
+ if (mix.input().test(stack)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
2024-04-27 01:17:13 +02:00
+ private boolean hasCustomMix(ItemStack input, ItemStack ingredient) {
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
2022-02-23 04:09:15 +01:00
+ if (mix.input().test(input) && mix.ingredient().test(ingredient)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
2024-04-27 01:17:13 +02:00
+ public void addPotionMix(io.papermc.paper.potion.PotionMix mix) {
+ if (this.customMixes.containsKey(mix.getKey())) {
2022-02-23 04:09:15 +01:00
+ throw new IllegalArgumentException("Duplicate recipe ignored with ID " + mix.getKey());
+ }
2024-04-27 01:17:13 +02:00
+ this.customMixes.putAndMoveToFirst(mix.getKey(), new io.papermc.paper.potion.PaperPotionMix(mix));
2022-02-23 04:09:15 +01:00
+ }
+
2024-04-27 01:17:13 +02:00
+ public boolean removePotionMix(org.bukkit.NamespacedKey key) {
+ return this.customMixes.remove(key) != null;
2022-02-23 04:09:15 +01:00
+ }
+
2024-04-26 17:33:00 +02:00
+ public PotionBrewing reload(FeatureFlagSet flags) {
+ return bootstrap(flags);
2022-02-23 04:09:15 +01:00
+ }
2024-01-18 18:52:00 +01:00
+ // Paper end - Custom Potion Mixes
2022-02-23 04:09:15 +01:00
+
2024-04-24 22:05:42 +02:00
public static class Builder {
private final List<Ingredient> containers = new ArrayList<>();
private final List<PotionBrewing.Mix<Potion>> potionMixes = new ArrayList<>();
2022-02-23 04:09:15 +01:00
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
2024-10-23 22:52:43 +02:00
index e167c2834f1b7899a7d11cef782940deeb739a9c..2bafacd7bc56186d9105d2031180f8c4a6940018 100644
2022-02-23 04:09:15 +01:00
--- a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
2024-10-23 22:52:43 +02:00
@@ -316,12 +316,12 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
2024-04-27 01:17:13 +02:00
@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;
2022-02-23 04:09:15 +01:00
2024-04-24 22:05:42 +02:00
return potionbrewer.isIngredient(stack);
} else {
2024-10-23 22:52:43 +02:00
- 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
2024-04-24 22:05:42 +02:00
}
2022-02-23 04:09:15 +01:00
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
Rework async chunk api implementation
Firstly, the old methods all routed to the CompletableFuture method.
However, the CF method could not guarantee that if the caller
was off-main that the future would be "completed" on-main. Since
the callback methods used the CF one, this meant that the callback
methods did not guarantee that the callbacks were to be called on
the main thread.
Now, all methods route to getChunkAtAsync(x, z, gen, urgent, cb)
so that the methods with the callback are guaranteed to invoke
the callback on the main thread. The CF behavior remains unchanged;
it may still appear to complete on main if invoked off-main.
Secondly, remove the scheduleOnMain invocation in the async
chunk completion. This unnecessarily delays the callback
by 1 tick.
Thirdly, add getChunksAtAsync(minX, minZ, maxX, maxZ, ...) which
will load chunks within an area. This method is provided as a helper
as keeping all chunks loaded within an area can be complicated to
implement for plugins (due to the lacking ticket API), and is
already implemented internally anyways.
Fourthly, remove the ticket addition that occured with getChunkAt
and getChunkAtAsync. The ticket addition may delay the unloading
of the chunk unnecessarily. It also fixes a very rare timing bug
where the future/callback would be completed after the chunk
unloads.
2024-11-19 07:34:32 +01:00
index 75bd9617164c63a641602bf772a5e0f15a322c7e..82e1c4713e043c4903b1f0154609da4558f90aef 100644
2022-02-23 04:09:15 +01:00
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
2024-10-23 22:52:43 +02:00
@@ -311,6 +311,7 @@ public final class CraftServer implements Server {
2022-02-23 04:09:15 +01:00
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
2024-04-27 01:17:13 +02:00
+ private final io.papermc.paper.potion.PaperPotionBrewer potionBrewer; // Paper - Custom Potion Mixes
2022-02-23 04:09:15 +01:00
static {
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
2024-10-27 18:11:15 +01:00
@@ -394,6 +395,7 @@ public final class CraftServer implements Server {
2024-04-25 19:42:24 +02:00
if (this.configuration.getBoolean("settings.use-map-color-cache")) {
MapPalette.setMapColorCache(new CraftMapColorCache(this.logger));
}
2024-04-27 01:17:13 +02:00
+ this.potionBrewer = new io.papermc.paper.potion.PaperPotionBrewer(console); // Paper - custom potion mixes
2024-04-25 19:42:24 +02:00
datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper
}
2024-11-09 17:01:35 +01:00
@@ -3076,5 +3078,9 @@ public final class CraftServer implements Server {
2022-02-23 04:09:15 +01:00
return datapackManager;
}
+ @Override
2024-04-27 01:17:13 +02:00
+ public io.papermc.paper.potion.PaperPotionBrewer getPotionBrewer() {
2022-02-23 04:09:15 +01:00
+ 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
2024-12-03 19:54:10 +01:00
index fa47232eeb36ed92b5a526bb00398f08b6c0ab41..5b176cd5f80a49e3a2afbcbf4fe2958143719bce 100644
2022-02-23 04:09:15 +01:00
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
2024-12-03 19:54:10 +01:00
@@ -23,6 +23,11 @@ public interface CraftRecipe extends Recipe {
2024-10-23 22:52:43 +02:00
}
2022-02-23 04:09:15 +01:00
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) {