mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-12 04:06:52 +01:00
8c5b837e05
Firstly, the old methods all routed to the CompletableFuture method. However, the CF method could not guarantee that if the caller was off-main that the future would be "completed" on-main. Since the callback methods used the CF one, this meant that the callback methods did not guarantee that the callbacks were to be called on the main thread. Now, all methods route to getChunkAtAsync(x, z, gen, urgent, cb) so that the methods with the callback are guaranteed to invoke the callback on the main thread. The CF behavior remains unchanged; it may still appear to complete on main if invoked off-main. Secondly, remove the scheduleOnMain invocation in the async chunk completion. This unnecessarily delays the callback by 1 tick. Thirdly, add getChunksAtAsync(minX, minZ, maxX, maxZ, ...) which will load chunks within an area. This method is provided as a helper as keeping all chunks loaded within an area can be complicated to implement for plugins (due to the lacking ticket API), and is already implemented internally anyways. Fourthly, remove the ticket addition that occured with getChunkAt and getChunkAtAsync. The ticket addition may delay the unloading of the chunk unnecessarily. It also fixes a very rare timing bug where the future/callback would be completed after the chunk unloads.
95 lines
6.0 KiB
Diff
95 lines
6.0 KiB
Diff
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.
|
|
|
|
Feature patch
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/CraftingContainer.java b/src/main/java/net/minecraft/world/inventory/CraftingContainer.java
|
|
index 779d107a4d07820529273af5931421c09d1dc27f..4f6c8c43f5150e340704682accfbe2a5b1c5db19 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/CraftingContainer.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/CraftingContainer.java
|
|
@@ -18,11 +18,11 @@ 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 6b3006a8543265664a2e54898ece92c66afb9c21..2e4043248c3ac7a54d894d76b99adc26518d3866 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
|
|
@@ -56,6 +56,7 @@ 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 1ea4f0800598a75ba74ce033378749d1abe4009b..ff30071f3ef37d1b28cf86e26ce4f7477335a07a 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/ResultSlot.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/ResultSlot.java
|
|
@@ -72,7 +72,7 @@ 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 32d49d759f95d27ca04b843bbb2c2fd22ebd7e4a..a458f7b8270dc1d5902e0d131dbf9e66209e26be 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/TransientCraftingContainer.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/TransientCraftingContainer.java
|
|
@@ -27,7 +27,7 @@ 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;
|
|
@@ -72,12 +72,12 @@ 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;
|
|
}
|
|
|