fix exact choice shapeless recipes (#10973)

This commit is contained in:
Jake Potrebic 2024-07-17 12:48:31 -07:00 committed by GitHub
parent 2df5bba16a
commit 44c3dd0d4c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -9,6 +9,7 @@ and shapeless recipes.
== AT ==
public net.minecraft.world.item.ItemStackLinkedSet TYPE_AND_TAG
public net.minecraft.world.entity.player.StackedContents put(II)V
public net.minecraft.world.entity.player.StackedContents take(II)I
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
@ -48,12 +49,15 @@ index 0000000000000000000000000000000000000000..ef68600f6b59674ddea6c77f7e412902
+}
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..2258d4556a1c608e2b0ece38471350646718eb19
index 0000000000000000000000000000000000000000..568ba6aed2e74b8d84f4e82c1e785ef1587e2617
--- /dev/null
+++ b/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtraMap.java
@@ -0,0 +1,79 @@
@@ -0,0 +1,109 @@
+package io.papermc.paper.inventory.recipe;
+
+import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
+import it.unimi.dsi.fastutil.ints.Int2IntMap;
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
@ -68,13 +72,14 @@ index 0000000000000000000000000000000000000000..2258d4556a1c608e2b0ece3847135064
+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.CraftingInput;
+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);
+ public 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<>();
@ -120,6 +125,32 @@ index 0000000000000000000000000000000000000000..2258d4556a1c608e2b0ece3847135064
+ return this.idToExactChoice.get(id);
+ }
+
+ public Int2IntMap regularRemoved = new Int2IntArrayMap();
+ public void accountInput(final CraftingInput input) {
+ // similar logic to the CraftingInput constructor
+ for (final ItemStack item : input.items()) {
+ if (!item.isEmpty()) {
+ if (this.accountStack(item, 1)) {
+ // remove one of the items if it was added to the contents as a non-extra item
+ final int plainStackIdx = StackedContents.getStackingIndex(item);
+ if (this.contents.take(plainStackIdx, 1) == plainStackIdx) {
+ this.regularRemoved.put(plainStackIdx, 1);
+ }
+ }
+ }
+ }
+ }
+
+ public void resetExtras() {
+ // clear previous extra ids
+ for (final int extraId : this.exactChoiceIds.values()) {
+ this.contents.contents.remove(extraId);
+ }
+ for (final Int2IntMap.Entry entry : this.regularRemoved.int2IntEntrySet()) {
+ this.contents.put(entry.getIntKey(), entry.getIntValue());
+ }
+ }
+
+ public boolean accountStack(final ItemStack stack, final int count) {
+ if (!this.exactChoiceIds.isEmpty()) {
+ final int id = this.exactChoiceIds.getInt(stack);
@ -143,14 +174,14 @@ index 0000000000000000000000000000000000000000..413dfa52760db393ad6a8b5341200ee7
+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 0bd749af8014dd437229594ef6981a2ead803990..25acc13ba1adcc31a83f9cf29563760285f2ba7a 100644
index 0bd749af8014dd437229594ef6981a2ead803990..6d1f9c15dc99917a2ac966ea38ef1970f4f0289c 100644
--- a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
+++ b/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
@@ -31,6 +31,7 @@ public class ServerPlaceRecipe<I extends RecipeInput, R extends Recipe<I>> imple
this.inventory = entity.getInventory();
if (this.testClearGrid() || entity.isCreative()) {
this.stackedContents.clear();
+ this.stackedContents.initialize(recipe.value()); // Paper - Improve exact choice recipe ingredients
+ this.stackedContents.initializeExtras(recipe.value(), null); // Paper - Improve exact choice recipe ingredients
entity.getInventory().fillStackedContents(this.stackedContents);
this.menu.fillCraftSlotsStackedContents(this.stackedContents);
if (this.stackedContents.canCraft(recipe.value(), null)) {
@ -206,7 +237,7 @@ index 0bd749af8014dd437229594ef6981a2ead803990..25acc13ba1adcc31a83f9cf295637602
return -1;
} else {
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 b11121e0846183ceeb7f4ad536aab2ee89ea9d26..0a58698dcd62adf3dc06a8c7dc782aada50409f5 100644
index fa5576e41baec4b52c7ebb877924eb91d3775a2d..fcabf630ce1e4949d00f485a5bff66dd1e54a277 100644
--- a/src/main/java/net/minecraft/world/entity/player/StackedContents.java
+++ b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
@@ -22,8 +22,10 @@ import net.minecraft.world.item.crafting.RecipeHolder;
@ -228,13 +259,21 @@ index b11121e0846183ceeb7f4ad536aab2ee89ea9d26..0a58698dcd62adf3dc06a8c7dc782aad
this.put(i, j);
}
}
@@ -83,6 +86,23 @@ public class StackedContents {
@@ -83,6 +86,31 @@ public class StackedContents {
return itemId == 0 ? ItemStack.EMPTY : new ItemStack(Item.byId(itemId));
}
+ // Paper start - Improve exact choice recipe ingredients
+ public void initialize(final Recipe<?> recipe) {
+ public void initializeExtras(final Recipe<?> recipe, @Nullable final net.minecraft.world.item.crafting.CraftingInput input) {
+ this.extrasMap = new io.papermc.paper.inventory.recipe.StackedContentsExtraMap(this, recipe);
+ if (input != null) this.extrasMap.accountInput(input);
+ }
+
+ public void resetExtras() {
+ if (this.extrasMap != null && !this.contents.isEmpty()) {
+ this.extrasMap.resetExtras();
+ }
+ this.extrasMap = null;
+ }
+
+ public static ItemStack fromStackingIndexWithExtras(final int itemId, @Nullable final StackedContents contents) {
@ -252,7 +291,7 @@ index b11121e0846183ceeb7f4ad536aab2ee89ea9d26..0a58698dcd62adf3dc06a8c7dc782aad
public void clear() {
this.contents.clear();
}
@@ -106,7 +126,7 @@ public class StackedContents {
@@ -106,7 +134,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++) {
@ -261,7 +300,7 @@ index b11121e0846183ceeb7f4ad536aab2ee89ea9d26..0a58698dcd62adf3dc06a8c7dc782aad
for (int j = 0; j < this.itemCount; j++) {
if (intList.contains(this.items[j])) {
@@ -169,7 +189,7 @@ public class StackedContents {
@@ -169,7 +197,7 @@ public class StackedContents {
IntCollection intCollection = new IntAVLTreeSet();
for (Ingredient ingredient : this.ingredients) {
@ -270,7 +309,7 @@ index b11121e0846183ceeb7f4ad536aab2ee89ea9d26..0a58698dcd62adf3dc06a8c7dc782aad
}
IntIterator intIterator = intCollection.iterator();
@@ -298,7 +318,7 @@ public class StackedContents {
@@ -298,7 +326,7 @@ public class StackedContents {
for (Ingredient ingredient : this.ingredients) {
int j = 0;
@ -279,7 +318,7 @@ index b11121e0846183ceeb7f4ad536aab2ee89ea9d26..0a58698dcd62adf3dc06a8c7dc782aad
j = Math.max(j, StackedContents.this.contents.get(k));
}
@@ -309,5 +329,17 @@ public class StackedContents {
@@ -309,5 +337,17 @@ public class StackedContents {
return i;
}
@ -355,7 +394,7 @@ index 59372daacd6fef45373c0557ccebb6ff5f16f174..63cf2b66f51df68aa3f6d98c69368ce4
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 62401d045245ec7e303ec526c09b5e6fa4c9f17b..5740296b55827f11c0029e89a86eaab1a24f560c 100644
index 62401d045245ec7e303ec526c09b5e6fa4c9f17b..213ee4aa988dd4c2a5a7be99b1d13f67338e5209 100644
--- a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
+++ b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
@@ -19,7 +19,7 @@ import org.bukkit.craftbukkit.inventory.CraftRecipe;
@ -375,7 +414,7 @@ index 62401d045245ec7e303ec526c09b5e6fa4c9f17b..5740296b55827f11c0029e89a86eaab1
}
// CraftBukkit start
@@ -75,7 +76,16 @@ public class ShapelessRecipe implements CraftingRecipe {
@@ -75,7 +76,18 @@ public class ShapelessRecipe implements CraftingRecipe {
}
public boolean matches(CraftingInput input, Level world) {
@ -387,8 +426,10 @@ index 62401d045245ec7e303ec526c09b5e6fa4c9f17b..5740296b55827f11c0029e89a86eaab1
+ if (input.size() == 1 && this.ingredients.size() == 1) {
+ return this.ingredients.getFirst().test(input.getItem(0));
+ }
+ input.stackedContents().initialize(this); // setup stacked contents for this recipe
+ return input.stackedContents().canCraft(this, null);
+ input.stackedContents().initializeExtras(this, input); // setup stacked contents for this recipe
+ final boolean canCraft = input.stackedContents().canCraft(this, null);
+ input.stackedContents().resetExtras();
+ return canCraft;
+ // Paper end - unwrap ternary & better exact choice recipes
}