diff options
author | Jake Potrebic <[email protected]> | 2024-12-17 11:45:39 +0100 |
---|---|---|
committer | Nassim Jahnke <[email protected]> | 2024-12-17 11:45:39 +0100 |
commit | ac69f75d23618d914c0d705b578ac47dbac2bff0 (patch) | |
tree | 72d17a6b0bf990c81c13bdeef0668fc33f2b01f9 | |
parent | 05c0d4a6e2acfc1558f6af6384625c4938fd8554 (diff) | |
download | Paper-ac69f75d23618d914c0d705b578ac47dbac2bff0.tar.gz Paper-ac69f75d23618d914c0d705b578ac47dbac2bff0.zip |
Apply Improve-performance-of-mass-crafts directly
5 files changed, 42 insertions, 98 deletions
diff --git a/feature-patches/1065-Improve-performance-of-mass-crafts.patch b/feature-patches/1065-Improve-performance-of-mass-crafts.patch deleted file mode 100644 index c09f2cf750..0000000000 --- a/feature-patches/1065-Improve-performance-of-mass-crafts.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic <[email protected]> -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; - } - diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/CraftingContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/CraftingContainer.java.patch index 2225d1d404..2aef7bff97 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/CraftingContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/CraftingContainer.java.patch @@ -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 + diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/CraftingMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/CraftingMenu.java.patch index f490a6a0d3..d04a6f281e 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/CraftingMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/CraftingMenu.java.patch @@ -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()) { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/ResultSlot.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/ResultSlot.java.patch new file mode 100644 index 0000000000..c8c1e2c156 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/inventory/ResultSlot.java.patch @@ -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); diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/TransientCraftingContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/TransientCraftingContainer.java.patch index 898f5850c4..85f7ca8636 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/TransientCraftingContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/TransientCraftingContainer.java.patch @@ -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; + } + |