geforkt von Mirrors/Paper
Apply Improve-performance-of-mass-crafts directly
Dieser Commit ist enthalten in:
Ursprung
05c0d4a6e2
Commit
ac69f75d23
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -5,11 +5,11 @@
|
|||||||
List<ItemStack> getItems();
|
List<ItemStack> getItems();
|
||||||
|
|
||||||
+ // CraftBukkit start
|
+ // 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;
|
+ 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
|
+ // CraftBukkit end
|
||||||
+
|
+
|
||||||
|
@ -18,9 +18,34 @@
|
|||||||
this.access = access;
|
this.access = access;
|
||||||
this.player = playerInventory.player;
|
this.player = playerInventory.player;
|
||||||
this.addResultSlot(this.player, 124, 35);
|
this.addResultSlot(this.player, 124, 35);
|
||||||
@@ -56,6 +_,7 @@
|
@@ -55,7 +_,32 @@
|
||||||
|
CraftingInput craftInput = craftSlots.asCraftInput();
|
||||||
ServerPlayer serverPlayer = (ServerPlayer)player;
|
ServerPlayer serverPlayer = (ServerPlayer)player;
|
||||||
ItemStack itemStack = ItemStack.EMPTY;
|
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);
|
Optional<RecipeHolder<CraftingRecipe>> recipeFor = level.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftInput, level, recipe);
|
||||||
+ craftSlots.setCurrentRecipe(recipeFor.orElse(null)); // CraftBukkit
|
+ craftSlots.setCurrentRecipe(recipeFor.orElse(null)); // CraftBukkit
|
||||||
if (recipeFor.isPresent()) {
|
if (recipeFor.isPresent()) {
|
||||||
|
@ -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);
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
+ // CraftBukkit start - add fields
|
+ // CraftBukkit start - add fields
|
||||||
+ public List<org.bukkit.entity.HumanEntity> transaction = new java.util.ArrayList<>();
|
+ 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;
|
+ public net.minecraft.world.Container resultInventory;
|
||||||
+ private Player owner;
|
+ private Player owner;
|
||||||
+ private int maxStack = MAX_STACK;
|
+ private int maxStack = MAX_STACK;
|
||||||
@ -51,12 +51,12 @@
|
|||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ @Override
|
+ @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;
|
+ return this.currentRecipe;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ @Override
|
+ @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;
|
+ this.currentRecipe = currentRecipe;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren