13
0
geforkt von Mirrors/Paper

Apply Improve-performance-of-mass-crafts directly

Dieser Commit ist enthalten in:
Jake Potrebic 2024-12-17 11:45:39 +01:00 committet von Nassim Jahnke
Ursprung 05c0d4a6e2
Commit ac69f75d23
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: EF6771C01F6EF02F
5 geänderte Dateien mit 42 neuen und 98 gelöschten Zeilen

Datei anzeigen

@ -1,92 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 13 Aug 2023 15:41:52 -0700
Subject: [PATCH] Improve performance of mass crafts
When the server crafts all available items in CraftingMenu or InventoryMenu the game
checks either 4 or 9 times for each individual craft for a matching recipe for that container.
This check can be expensive if 64 total crafts are being performed with the recipe matching logic
being run 64 * 9 + 64 times. A breakdown of those times is below. This patch caches the last matching
recipe so that it is checked first and only if it doesn't match does the rest of the matching logic run.
Shift-click crafts are processed one at a time, so shift clicking on an item in the result of a iron block craft
where all the 9 inputs are full stacks of iron will run 64 iron block crafts. For each of those crafts, the
'remaining' blocks are calculated. This is due to recipes that have leftover items like buckets. This is done
for each craft, and done once to get the full 9 leftover items which are usually air. Then 1 item is removed
from each of the 9 inputs and each time that happens, logic is triggered to update the result itemstack. So
for each craft, that logic is run 9 times (hence the 64 * 9). The + 64 is from the 64 checks for remaining items.
After this patch, the full iteration over all recipes checking for a match should run once for a full craft to find the
initial recipe match. Then that recipe will be checked first for all future recipe match checks.
diff --git a/src/main/java/net/minecraft/world/inventory/CraftingContainer.java b/src/main/java/net/minecraft/world/inventory/CraftingContainer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/inventory/CraftingContainer.java
+++ b/src/main/java/net/minecraft/world/inventory/CraftingContainer.java
@@ -0,0 +0,0 @@ public interface CraftingContainer extends Container, StackedContentsCompatible
List<ItemStack> getItems();
// CraftBukkit start
- default RecipeHolder<?> getCurrentRecipe() {
+ default RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> getCurrentRecipe() { // Paper - use correct generic
return null;
}
- default void setCurrentRecipe(RecipeHolder<?> recipe) {
+ default void setCurrentRecipe(RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> recipe) { // Paper - use correct generic
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/inventory/CraftingMenu.java b/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
@@ -0,0 +0,0 @@ public class CraftingMenu extends AbstractCraftingMenu {
CraftingInput craftinginput = craftingInventory.asCraftInput();
ServerPlayer entityplayer = (ServerPlayer) player;
ItemStack itemstack = ItemStack.EMPTY;
+ if (recipe == null) recipe = craftingInventory.getCurrentRecipe(); // Paper - Perf: Improve mass crafting; check last recipe used first
Optional<RecipeHolder<CraftingRecipe>> optional = world.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftinginput, world, recipe);
craftingInventory.setCurrentRecipe(optional.orElse(null)); // CraftBukkit
diff --git a/src/main/java/net/minecraft/world/inventory/ResultSlot.java b/src/main/java/net/minecraft/world/inventory/ResultSlot.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/inventory/ResultSlot.java
+++ b/src/main/java/net/minecraft/world/inventory/ResultSlot.java
@@ -0,0 +0,0 @@ public class ResultSlot extends Slot {
private NonNullList<ItemStack> getRemainingItems(CraftingInput input, Level world) {
return world instanceof ServerLevel serverLevel
? serverLevel.recipeAccess()
- .getRecipeFor(RecipeType.CRAFTING, input, serverLevel)
+ .getRecipeFor(RecipeType.CRAFTING, input, serverLevel, this.craftSlots.getCurrentRecipe()) // Paper - Perf: Improve mass crafting; check last recipe used first
.map(recipe -> recipe.value().getRemainingItems(input))
.orElseGet(() -> copyAllInputItems(input))
: CraftingRecipe.defaultCraftingReminder(input);
diff --git a/src/main/java/net/minecraft/world/inventory/TransientCraftingContainer.java b/src/main/java/net/minecraft/world/inventory/TransientCraftingContainer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/inventory/TransientCraftingContainer.java
+++ b/src/main/java/net/minecraft/world/inventory/TransientCraftingContainer.java
@@ -0,0 +0,0 @@ public class TransientCraftingContainer implements CraftingContainer {
// CraftBukkit start - add fields
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
- private RecipeHolder<?> currentRecipe;
+ private RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> currentRecipe; // Paper - use correct generic
public Container resultInventory;
private Player owner;
private int maxStack = MAX_STACK;
@@ -0,0 +0,0 @@ public class TransientCraftingContainer implements CraftingContainer {
}
@Override
- public RecipeHolder<?> getCurrentRecipe() {
+ public RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> getCurrentRecipe() { // Paper - use correct generic
return this.currentRecipe;
}
@Override
- public void setCurrentRecipe(RecipeHolder<?> currentRecipe) {
+ public void setCurrentRecipe(RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> currentRecipe) { // Paper - use correct generic
this.currentRecipe = currentRecipe;
}

Datei anzeigen

@ -5,11 +5,11 @@
List<ItemStack> getItems();
+ // CraftBukkit start
+ default net.minecraft.world.item.crafting.RecipeHolder<?> getCurrentRecipe() {
+ default net.minecraft.world.item.crafting.RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> getCurrentRecipe() {
+ return null;
+ }
+
+ default void setCurrentRecipe(net.minecraft.world.item.crafting.RecipeHolder<?> recipe) {
+ default void setCurrentRecipe(net.minecraft.world.item.crafting.RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> recipe) {
+ }
+ // CraftBukkit end
+

Datei anzeigen

@ -18,9 +18,34 @@
this.access = access;
this.player = playerInventory.player;
this.addResultSlot(this.player, 124, 35);
@@ -56,6 +_,7 @@
@@ -55,7 +_,32 @@
CraftingInput craftInput = craftSlots.asCraftInput();
ServerPlayer serverPlayer = (ServerPlayer)player;
ItemStack itemStack = ItemStack.EMPTY;
+ // Paper start - Perf: Improve mass crafting; check last recipe used first
+ /*
+ When the server crafts all available items in CraftingMenu or InventoryMenu the game
+ checks either 4 or 9 times for each individual craft for a matching recipe for that container.
+ This check can be expensive if 64 total crafts are being performed with the recipe matching logic
+ being run 64 * 9 + 64 times. A breakdown of those times is below. This caches the last matching
+ recipe so that it is checked first and only if it doesn't match does the rest of the matching logic run.
+
+ Shift-click crafts are processed one at a time, so shift clicking on an item in the result of a iron block craft
+ where all the 9 inputs are full stacks of iron will run 64 iron block crafts. For each of those crafts, the
+ 'remaining' blocks are calculated. This is due to recipes that have leftover items like buckets. This is done
+ for each craft, and done once to get the full 9 leftover items which are usually air. Then 1 item is removed
+ from each of the 9 inputs and each time that happens, logic is triggered to update the result itemstack. So
+ for each craft, that logic is run 9 times (hence the 64 * 9). The + 64 is from the 64 checks for remaining items.
+
+ After this change, the full iteration over all recipes checking for a match should run once for a full craft to find the
+ initial recipe match. Then that recipe will be checked first for all future recipe match checks.
+
+ See also: ResultSlot class
+ */
+ if (recipe == null) {
+ recipe = craftSlots.getCurrentRecipe();
+ }
+ // Paper end - Perf: Improve mass crafting; check last recipe used first
Optional<RecipeHolder<CraftingRecipe>> recipeFor = level.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftInput, level, recipe);
+ craftSlots.setCurrentRecipe(recipeFor.orElse(null)); // CraftBukkit
if (recipeFor.isPresent()) {

Datei anzeigen

@ -0,0 +1,11 @@
--- a/net/minecraft/world/inventory/ResultSlot.java
+++ b/net/minecraft/world/inventory/ResultSlot.java
@@ -72,7 +_,7 @@
private NonNullList<ItemStack> getRemainingItems(CraftingInput input, Level level) {
return level instanceof ServerLevel serverLevel
? serverLevel.recipeAccess()
- .getRecipeFor(RecipeType.CRAFTING, input, serverLevel)
+ .getRecipeFor(RecipeType.CRAFTING, input, serverLevel, this.craftSlots.getCurrentRecipe()) // Paper - Perf: Improve mass crafting; check last recipe used first
.map(recipe -> recipe.value().getRemainingItems(input))
.orElseGet(() -> copyAllInputItems(input))
: CraftingRecipe.defaultCraftingReminder(input);

Datei anzeigen

@ -6,7 +6,7 @@
+ // CraftBukkit start - add fields
+ public List<org.bukkit.entity.HumanEntity> transaction = new java.util.ArrayList<>();
+ private net.minecraft.world.item.crafting.RecipeHolder<?> currentRecipe;
+ private net.minecraft.world.item.crafting.RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> currentRecipe;
+ public net.minecraft.world.Container resultInventory;
+ private Player owner;
+ private int maxStack = MAX_STACK;
@ -51,12 +51,12 @@
+ }
+
+ @Override
+ public net.minecraft.world.item.crafting.RecipeHolder<?> getCurrentRecipe() {
+ public net.minecraft.world.item.crafting.RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> getCurrentRecipe() {
+ return this.currentRecipe;
+ }
+
+ @Override
+ public void setCurrentRecipe(net.minecraft.world.item.crafting.RecipeHolder<?> currentRecipe) {
+ public void setCurrentRecipe(net.minecraft.world.item.crafting.RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> currentRecipe) {
+ this.currentRecipe = currentRecipe;
+ }
+