mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-01 08:20:51 +01:00
de04cbced5
Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: f29cb801 Separate checkstyle-suppressions file is not required 86f99bbe SPIGOT-7540, PR-946: Add ServerTickManager API d4119585 SPIGOT-6903, PR-945: Add BlockData#getMapColor b7a2ed41 SPIGOT-7530, PR-947: Add Player#removeResourcePack 9dd56255 SPIGOT-7527, PR-944: Add WindCharge#explode() 994a6163 Attempt upgrade of resolver libraries CraftBukkit Changes: b3b43a6ad Add Checkstyle check for unused imports 13fb3358e SPIGOT-7544: Scoreboard#getEntries() doesn't get entries but class names 3dda99c06 SPIGOT-7540, PR-1312: Add ServerTickManager API 2ab4508c0 SPIGOT-6903, PR-1311: Add BlockData#getMapColor 1dbdbbed4 PR-1238: Remove unnecessary sign ticking 659728d2a MC-264285, SPIGOT-7439, PR-1237: Fix unbreakable flint and steel is completely consumed while igniting creeper e37e29ce0 Increase outdated build delay c00438b39 SPIGOT-7530, PR-1313: Add Player#removeResourcePack 492dd80ce SPIGOT-7527, PR-1310: Add WindCharge#explode() e11fbb9d7 Upgrade MySQL driver 9f3a0bd2a Attempt upgrade of resolver libraries 60d16d7ca PR-1306: Centralize Bukkit and Minecraft entity conversion Spigot Changes: 06d602e7 Rebuild patches
384 lines
18 KiB
Diff
384 lines
18 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
|
Date: Sun, 25 Jun 2023 23:10:14 -0700
|
|
Subject: [PATCH] Improve exact choice recipe ingredients
|
|
|
|
Fixes exact choices not working with recipe book clicks
|
|
and shapeless recipes.
|
|
|
|
== AT ==
|
|
public net.minecraft.world.item.ItemStackLinkedSet TYPE_AND_TAG
|
|
public net.minecraft.world.entity.player.StackedContents put(II)V
|
|
|
|
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/RecipeBookExactChoiceRecipe.java b/src/main/java/io/papermc/paper/inventory/recipe/RecipeBookExactChoiceRecipe.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..2a2f8327a5bd3983a3a13fd663beb98906f27312
|
|
--- /dev/null
|
|
+++ b/src/main/java/io/papermc/paper/inventory/recipe/RecipeBookExactChoiceRecipe.java
|
|
@@ -0,0 +1,30 @@
|
|
+package io.papermc.paper.inventory.recipe;
|
|
+
|
|
+import net.minecraft.world.Container;
|
|
+import net.minecraft.world.item.crafting.Ingredient;
|
|
+import net.minecraft.world.item.crafting.Recipe;
|
|
+
|
|
+public abstract class RecipeBookExactChoiceRecipe<C extends Container> implements Recipe<C> {
|
|
+
|
|
+ private boolean hasExactIngredients;
|
|
+
|
|
+ protected final void checkExactIngredients() {
|
|
+ // skip any special recipes
|
|
+ if (this.isSpecial()) {
|
|
+ this.hasExactIngredients = false;
|
|
+ return;
|
|
+ }
|
|
+ for (final Ingredient ingredient : this.getIngredients()) {
|
|
+ if (!ingredient.isEmpty() && ingredient.exact) {
|
|
+ this.hasExactIngredients = true;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ this.hasExactIngredients = false;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public final boolean hasExactIngredients() {
|
|
+ return this.hasExactIngredients;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtraMap.java b/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtraMap.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..63db0b843c5bd11f979e613ba6cfac9d9da956bb
|
|
--- /dev/null
|
|
+++ b/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtraMap.java
|
|
@@ -0,0 +1,79 @@
|
|
+package io.papermc.paper.inventory.recipe;
|
|
+
|
|
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|
+import it.unimi.dsi.fastutil.ints.IntArrayList;
|
|
+import it.unimi.dsi.fastutil.ints.IntComparators;
|
|
+import it.unimi.dsi.fastutil.ints.IntList;
|
|
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|
+import it.unimi.dsi.fastutil.objects.Object2IntOpenCustomHashMap;
|
|
+import java.util.IdentityHashMap;
|
|
+import java.util.Map;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+import net.minecraft.core.registries.BuiltInRegistries;
|
|
+import net.minecraft.world.entity.player.StackedContents;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.item.ItemStackLinkedSet;
|
|
+import net.minecraft.world.item.crafting.Ingredient;
|
|
+import net.minecraft.world.item.crafting.Recipe;
|
|
+
|
|
+public final class StackedContentsExtraMap {
|
|
+
|
|
+ private final AtomicInteger idCounter = new AtomicInteger(BuiltInRegistries.ITEM.size()); // start at max vanilla stacked contents idx
|
|
+ private final Object2IntMap<ItemStack> exactChoiceIds = new Object2IntOpenCustomHashMap<>(ItemStackLinkedSet.TYPE_AND_TAG);
|
|
+ private final Int2ObjectMap<ItemStack> idToExactChoice = new Int2ObjectOpenHashMap<>();
|
|
+ private final StackedContents contents;
|
|
+ public final Map<Ingredient, IntList> extraStackingIds = new IdentityHashMap<>();
|
|
+
|
|
+ public StackedContentsExtraMap(final StackedContents contents, final Recipe<?> recipe) {
|
|
+ this.exactChoiceIds.defaultReturnValue(-1);
|
|
+ this.contents = contents;
|
|
+ this.initialize(recipe);
|
|
+ }
|
|
+
|
|
+ private void initialize(final Recipe<?> recipe) {
|
|
+ if (recipe.hasExactIngredients()) {
|
|
+ for (final Ingredient ingredient : recipe.getIngredients()) {
|
|
+ if (!ingredient.isEmpty() && ingredient.exact) {
|
|
+ final net.minecraft.world.item.ItemStack[] items = ingredient.getItems();
|
|
+ final IntList idList = new IntArrayList(items.length);
|
|
+ for (final ItemStack item : items) {
|
|
+ idList.add(this.registerExact(item)); // I think not copying the stack here is safe because cb copies the stack when creating the ingredient
|
|
+ if (!item.hasTag()) {
|
|
+ // add regular index if it's a plain itemstack but still registered as exact
|
|
+ idList.add(StackedContents.getStackingIndex(item));
|
|
+ }
|
|
+ }
|
|
+ idList.sort(IntComparators.NATURAL_COMPARATOR);
|
|
+ this.extraStackingIds.put(ingredient, idList);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private int registerExact(final ItemStack exactChoice) {
|
|
+ final int existing = this.exactChoiceIds.getInt(exactChoice);
|
|
+ if (existing > -1) {
|
|
+ return existing;
|
|
+ }
|
|
+ final int id = this.idCounter.getAndIncrement();
|
|
+ this.exactChoiceIds.put(exactChoice, id);
|
|
+ this.idToExactChoice.put(id, exactChoice);
|
|
+ return id;
|
|
+ }
|
|
+
|
|
+ public ItemStack getById(int id) {
|
|
+ return this.idToExactChoice.get(id);
|
|
+ }
|
|
+
|
|
+ public boolean accountStack(final ItemStack stack, final int count) {
|
|
+ if (!this.exactChoiceIds.isEmpty()) {
|
|
+ final int id = this.exactChoiceIds.getInt(stack);
|
|
+ if (id >= 0) {
|
|
+ this.contents.put(id, count);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/package-info.java b/src/main/java/io/papermc/paper/inventory/recipe/package-info.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..413dfa52760db393ad6a8b5341200ee704a864fc
|
|
--- /dev/null
|
|
+++ b/src/main/java/io/papermc/paper/inventory/recipe/package-info.java
|
|
@@ -0,0 +1,5 @@
|
|
+@DefaultQualifier(NonNull.class)
|
|
+package io.papermc.paper.inventory.recipe;
|
|
+
|
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
|
+import org.checkerframework.framework.qual.DefaultQualifier;
|
|
diff --git a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java b/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
|
index 4303f2b4e55191f8a53170435c6d1263782d1c8d..a65d07cb3d2dae85225921498d1721dc3c6a6bf3 100644
|
|
--- a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
|
+++ b/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
|
@@ -34,6 +34,7 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
|
|
this.inventory = entity.getInventory();
|
|
if (this.testClearGrid() || entity.isCreative()) {
|
|
this.stackedContents.clear();
|
|
+ this.stackedContents.initialize(recipe.value()); // Paper - better exact choice recipes
|
|
entity.getInventory().fillStackedContents(this.stackedContents);
|
|
this.menu.fillCraftSlotsStackedContents(this.stackedContents);
|
|
if (this.stackedContents.canCraft(recipe.value(), (IntList)null)) {
|
|
@@ -80,7 +81,7 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
|
|
int l = k;
|
|
|
|
for(int m : intList) {
|
|
- int n = StackedContents.fromStackingIndex(m).getMaxStackSize();
|
|
+ int n = StackedContents.maxStackSizeFromStackingIndex(m, this.stackedContents); // Paper
|
|
if (n < l) {
|
|
l = n;
|
|
}
|
|
@@ -97,10 +98,21 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
|
|
@Override
|
|
public void addItemToSlot(Iterator<Integer> inputs, int slot, int amount, int gridX, int gridY) {
|
|
Slot slot2 = this.menu.getSlot(slot);
|
|
- ItemStack itemStack = StackedContents.fromStackingIndex(inputs.next());
|
|
+ // Paper start
|
|
+ final int itemId = inputs.next();
|
|
+ ItemStack itemStack = null;
|
|
+ boolean isExact = false;
|
|
+ if (this.stackedContents.extrasMap != null && itemId >= net.minecraft.core.registries.BuiltInRegistries.ITEM.size()) {
|
|
+ itemStack = StackedContents.fromStackingIndexExtras(itemId, this.stackedContents.extrasMap).copy();
|
|
+ isExact = true;
|
|
+ }
|
|
+ if (itemStack == null) {
|
|
+ itemStack = StackedContents.fromStackingIndex(itemId);
|
|
+ }
|
|
+ // Paper end
|
|
if (!itemStack.isEmpty()) {
|
|
for(int i = 0; i < amount; ++i) {
|
|
- this.moveItemToGrid(slot2, itemStack);
|
|
+ this.moveItemToGrid(slot2, itemStack, isExact); // Paper
|
|
}
|
|
}
|
|
|
|
@@ -130,8 +142,14 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
|
|
return i;
|
|
}
|
|
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper
|
|
protected void moveItemToGrid(Slot slot, ItemStack stack) {
|
|
- int i = this.inventory.findSlotMatchingUnusedItem(stack);
|
|
+ // Paper start
|
|
+ this.moveItemToGrid(slot, stack, false);
|
|
+ }
|
|
+ protected void moveItemToGrid(Slot slot, ItemStack stack, final boolean isExact) {
|
|
+ int i = isExact ? this.inventory.findSlotMatchingItem(stack) : this.inventory.findSlotMatchingUnusedItem(stack);
|
|
+ // Paper end
|
|
if (i != -1) {
|
|
ItemStack itemStack = this.inventory.getItem(i);
|
|
if (!itemStack.isEmpty()) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/player/StackedContents.java b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
|
index 5cc5f67284ad01c9154876252450552ed37f24bf..26b236a764177ac16d53f5cbaf83d3e21d015ebc 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
|
@@ -21,8 +21,10 @@ import net.minecraft.world.item.crafting.RecipeHolder;
|
|
public class StackedContents {
|
|
private static final int EMPTY = 0;
|
|
public final Int2IntMap contents = new Int2IntOpenHashMap();
|
|
+ @Nullable public io.papermc.paper.inventory.recipe.StackedContentsExtraMap extrasMap = null; // Paper
|
|
|
|
public void accountSimpleStack(ItemStack stack) {
|
|
+ if (this.extrasMap != null && stack.hasTag() && this.extrasMap.accountStack(stack, Math.min(64, stack.getCount()))) return; // Paper - max of 64 due to accountStack method below
|
|
if (!stack.isDamaged() && !stack.isEnchanted() && !stack.hasCustomHoverName()) {
|
|
this.accountStack(stack);
|
|
}
|
|
@@ -37,6 +39,7 @@ public class StackedContents {
|
|
if (!stack.isEmpty()) {
|
|
int i = getStackingIndex(stack);
|
|
int j = Math.min(maxCount, stack.getCount());
|
|
+ if (this.extrasMap != null && stack.hasTag() && this.extrasMap.accountStack(stack, j)) return; // Paper - if an exact ingredient, don't include it
|
|
this.put(i, j);
|
|
}
|
|
|
|
@@ -84,6 +87,23 @@ public class StackedContents {
|
|
return itemId == 0 ? ItemStack.EMPTY : new ItemStack(Item.byId(itemId));
|
|
}
|
|
|
|
+ // Paper start
|
|
+ public void initialize(final Recipe<?> recipe) {
|
|
+ this.extrasMap = new io.papermc.paper.inventory.recipe.StackedContentsExtraMap(this, recipe);
|
|
+ }
|
|
+
|
|
+ public static int maxStackSizeFromStackingIndex(final int itemId, @Nullable final StackedContents contents) {
|
|
+ if (contents != null && contents.extrasMap != null && itemId >= BuiltInRegistries.ITEM.size()) {
|
|
+ return fromStackingIndexExtras(itemId, contents.extrasMap).getMaxStackSize();
|
|
+ }
|
|
+ return fromStackingIndex(itemId).getMaxStackSize();
|
|
+ }
|
|
+
|
|
+ public static ItemStack fromStackingIndexExtras(final int itemId, final io.papermc.paper.inventory.recipe.StackedContentsExtraMap extrasMap) {
|
|
+ return extrasMap.getById(itemId).copy();
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
public void clear() {
|
|
this.contents.clear();
|
|
}
|
|
@@ -107,7 +127,7 @@ public class StackedContents {
|
|
this.data = new BitSet(this.ingredientCount + this.itemCount + this.ingredientCount + this.ingredientCount * this.itemCount);
|
|
|
|
for(int i = 0; i < this.ingredients.size(); ++i) {
|
|
- IntList intList = this.ingredients.get(i).getStackingIds();
|
|
+ IntList intList = this.getStackingIds(this.ingredients.get(i)); // Paper
|
|
|
|
for(int j = 0; j < this.itemCount; ++j) {
|
|
if (intList.contains(this.items[j])) {
|
|
@@ -171,7 +191,7 @@ public class StackedContents {
|
|
IntCollection intCollection = new IntAVLTreeSet();
|
|
|
|
for(Ingredient ingredient : this.ingredients) {
|
|
- intCollection.addAll(ingredient.getStackingIds());
|
|
+ intCollection.addAll(this.getStackingIds(ingredient)); // Paper
|
|
}
|
|
|
|
IntIterator intIterator = intCollection.iterator();
|
|
@@ -294,7 +314,7 @@ public class StackedContents {
|
|
for(Ingredient ingredient : this.ingredients) {
|
|
int j = 0;
|
|
|
|
- for(int k : ingredient.getStackingIds()) {
|
|
+ for(int k : this.getStackingIds(ingredient)) { // Paper
|
|
j = Math.max(j, StackedContents.this.contents.get(k));
|
|
}
|
|
|
|
@@ -305,5 +325,17 @@ public class StackedContents {
|
|
|
|
return i;
|
|
}
|
|
+
|
|
+ // Paper start - improve exact recipe choices
|
|
+ private IntList getStackingIds(final Ingredient ingredient) {
|
|
+ if (StackedContents.this.extrasMap != null) {
|
|
+ final IntList ids = StackedContents.this.extrasMap.extraStackingIds.get(ingredient);
|
|
+ if (ids != null) {
|
|
+ return ids;
|
|
+ }
|
|
+ }
|
|
+ return ingredient.getStackingIds();
|
|
+ }
|
|
+ // Paper end - improve exact recipe choices
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java b/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
|
|
index ff48b0de1bdf693e01ea04bc1606c5f80d4c401c..43cff6d2fca55192a0a8d9051a0728327c5dcf4b 100644
|
|
--- a/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
|
|
+++ b/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
|
|
@@ -6,7 +6,7 @@ import net.minecraft.world.Container;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.level.Level;
|
|
|
|
-public abstract class AbstractCookingRecipe implements Recipe<Container> {
|
|
+public abstract class AbstractCookingRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<Container> implements Recipe<Container> { // Paper - improve exact recipe choices
|
|
protected final RecipeType<?> type;
|
|
protected final CookingBookCategory category;
|
|
protected final String group;
|
|
@@ -23,6 +23,7 @@ public abstract class AbstractCookingRecipe implements Recipe<Container> {
|
|
this.result = result;
|
|
this.experience = experience;
|
|
this.cookingTime = cookingTime;
|
|
+ this.checkExactIngredients(); // Paper - improve exact recipe choices
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/item/crafting/Recipe.java b/src/main/java/net/minecraft/world/item/crafting/Recipe.java
|
|
index 8b631e457f783e55b7c37dd915b699912a9c5b49..e2d6c8ed586ef429cc712139e501df696ed10f6e 100644
|
|
--- a/src/main/java/net/minecraft/world/item/crafting/Recipe.java
|
|
+++ b/src/main/java/net/minecraft/world/item/crafting/Recipe.java
|
|
@@ -69,4 +69,10 @@ public interface Recipe<C extends Container> {
|
|
}
|
|
|
|
org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id); // CraftBukkit
|
|
+
|
|
+ // Paper start - improved exact choice recipes
|
|
+ default boolean hasExactIngredients() {
|
|
+ return false;
|
|
+ }
|
|
+ // Paper end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java
|
|
index 201897bbde809699b53617e09703f5b22bbbe938..d772cf80fa3831e1c79d601ea09a073da089e2c5 100644
|
|
--- a/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java
|
|
+++ b/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java
|
|
@@ -17,7 +17,7 @@ import org.bukkit.craftbukkit.inventory.CraftShapedRecipe;
|
|
import org.bukkit.inventory.RecipeChoice;
|
|
// CraftBukkit end
|
|
|
|
-public class ShapedRecipe implements CraftingRecipe {
|
|
+public class ShapedRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<CraftingContainer> implements CraftingRecipe { // Paper - improve exact recipe choices
|
|
|
|
final ShapedRecipePattern pattern;
|
|
final ItemStack result;
|
|
@@ -31,6 +31,7 @@ public class ShapedRecipe implements CraftingRecipe {
|
|
this.pattern = raw;
|
|
this.result = result;
|
|
this.showNotification = showNotification;
|
|
+ this.checkExactIngredients(); // Paper - improve exact recipe choices
|
|
}
|
|
|
|
public ShapedRecipe(String group, CraftingBookCategory category, ShapedRecipePattern raw, ItemStack result) {
|
|
diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
|
index 870e07140d835feaa55808101722d4547d5021d0..27b0a79f7a7c47047216aae42944bac2a2151181 100644
|
|
--- a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
|
+++ b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
|
@@ -20,7 +20,7 @@ import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
|
import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe;
|
|
// CraftBukkit end
|
|
|
|
-public class ShapelessRecipe implements CraftingRecipe {
|
|
+public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<CraftingContainer> implements CraftingRecipe { // Paper - improve exact recipe choices
|
|
|
|
final String group;
|
|
final CraftingBookCategory category;
|
|
@@ -32,6 +32,7 @@ public class ShapelessRecipe implements CraftingRecipe {
|
|
this.category = category;
|
|
this.result = result;
|
|
this.ingredients = ingredients;
|
|
+ this.checkExactIngredients(); // Paper - improve exact recipe choices
|
|
}
|
|
|
|
// CraftBukkit start
|
|
@@ -77,6 +78,7 @@ public class ShapelessRecipe implements CraftingRecipe {
|
|
|
|
public boolean matches(CraftingContainer inventory, Level world) {
|
|
StackedContents autorecipestackmanager = new StackedContents();
|
|
+ autorecipestackmanager.initialize(this); // Paper - better exact choice recipes
|
|
int i = 0;
|
|
|
|
for (int j = 0; j < inventory.getContainerSize(); ++j) {
|