mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-02 13:07:06 +01:00
90fe0d58a5
Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 897a0a23 SPIGOT-5753: Back PotionType by a minecraft registry 255b2aa1 SPIGOT-7080: Add World#locateNearestBiome ff984826 Remove javadoc.io doc links CraftBukkit Changes: 71b0135cc SPIGOT-5753: Back PotionType by a minecraft registry a6bcb8489 SPIGOT-7080: Add World#locateNearestBiome ad0e57434 SPIGOT-7502: CraftMetaItem - cannot deserialize BlockStateTag b3efca57a SPIGOT-6400: Use Mockito instead of InvocationHandler 38c599f9d PR-1272: Only allow one entity in CraftItem instead of two f065271ac SPIGOT-7498: ChunkSnapshot.getBlockEmittedLight() gets 64 blocks upper in Overworld Spigot Changes: e0e223fe Remove javadoc.io doc links
83 lines
6.2 KiB
Diff
83 lines
6.2 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.
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/CraftingMenu.java b/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
|
|
index a7aa2a4845cbf5a0843dcb93f7bdc5501f62a145..4c8ce073094e55ea0df67fe02c0d1cc8aef76562 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
|
|
@@ -76,7 +76,8 @@ public class CraftingMenu extends RecipeBookMenu<CraftingContainer> {
|
|
if (!world.isClientSide) {
|
|
ServerPlayer entityplayer = (ServerPlayer) player;
|
|
ItemStack itemstack = ItemStack.EMPTY;
|
|
- Optional<RecipeHolder<CraftingRecipe>> optional = world.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftingInventory, world);
|
|
+ final RecipeHolder<?> currentRecipe = craftingInventory.getCurrentRecipe(); // Paper - check last recipe used first
|
|
+ Optional<RecipeHolder<CraftingRecipe>> optional = currentRecipe == null ? world.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftingInventory, world) : world.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftingInventory, world, currentRecipe.id()).map(com.mojang.datafixers.util.Pair::getSecond); // Paper - check last recipe used first
|
|
|
|
if (optional.isPresent()) {
|
|
RecipeHolder<CraftingRecipe> recipeholder = (RecipeHolder) optional.get();
|
|
diff --git a/src/main/java/net/minecraft/world/inventory/ResultSlot.java b/src/main/java/net/minecraft/world/inventory/ResultSlot.java
|
|
index 525ba0bdc4c6782480930bea94f73a72efe6fc4c..2554f7b1d687f83f42d69bf8ab54336ba793e301 100644
|
|
--- a/src/main/java/net/minecraft/world/inventory/ResultSlot.java
|
|
+++ b/src/main/java/net/minecraft/world/inventory/ResultSlot.java
|
|
@@ -59,7 +59,7 @@ public class ResultSlot extends Slot {
|
|
@Override
|
|
public void onTake(Player player, ItemStack stack) {
|
|
this.checkTakeAchievements(stack);
|
|
- NonNullList<ItemStack> nonNullList = player.level().getRecipeManager().getRemainingItemsFor(RecipeType.CRAFTING, this.craftSlots, player.level());
|
|
+ NonNullList<ItemStack> nonNullList = player.level().getRecipeManager().getRemainingItemsFor(RecipeType.CRAFTING, this.craftSlots, player.level(), this.craftSlots.getCurrentRecipe() != null ? this.craftSlots.getCurrentRecipe().id() : null); // Paper - check last recipe used first
|
|
|
|
for(int i = 0; i < nonNullList.size(); ++i) {
|
|
ItemStack itemStack = this.craftSlots.getItem(i);
|
|
diff --git a/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java b/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java
|
|
index bf16c44e2d61dccb662eceeef89a143a25ba40b0..666fc85bc2079cb367b340f2605f29fe002f4d22 100644
|
|
--- a/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java
|
|
+++ b/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java
|
|
@@ -122,13 +122,16 @@ public class RecipeManager extends SimpleJsonResourceReloadListener {
|
|
RecipeHolder<T> recipeholder = (RecipeHolder) map.get(id);
|
|
|
|
if (recipeholder != null && recipeholder.value().matches(inventory, world)) {
|
|
+ inventory.setCurrentRecipe(recipeholder); // Paper
|
|
return Optional.of(Pair.of(id, recipeholder));
|
|
}
|
|
}
|
|
|
|
+ inventory.setCurrentRecipe(null); // Paper - clear before it might be set again
|
|
return map.entrySet().stream().filter((entry) -> {
|
|
return ((RecipeHolder) entry.getValue()).value().matches(inventory, world);
|
|
}).findFirst().map((entry) -> {
|
|
+ inventory.setCurrentRecipe(entry.getValue()); // Paper
|
|
return Pair.of((ResourceLocation) entry.getKey(), (RecipeHolder) entry.getValue());
|
|
});
|
|
}
|
|
@@ -150,7 +153,12 @@ public class RecipeManager extends SimpleJsonResourceReloadListener {
|
|
}
|
|
|
|
public <C extends Container, T extends Recipe<C>> NonNullList<ItemStack> getRemainingItemsFor(RecipeType<T> type, C inventory, Level world) {
|
|
- Optional<RecipeHolder<T>> optional = this.getRecipeFor(type, inventory, world);
|
|
+ // Paper start - check last recipe used first
|
|
+ return this.getRemainingItemsFor(type, inventory, world, null);
|
|
+ }
|
|
+ public <C extends Container, T extends Recipe<C>> NonNullList<ItemStack> getRemainingItemsFor(RecipeType<T> type, C inventory, Level world, @Nullable ResourceLocation firstToCheck) {
|
|
+ Optional<RecipeHolder<T>> optional = firstToCheck == null ? this.getRecipeFor(type, inventory, world) : this.getRecipeFor(type, inventory, world, firstToCheck).map(Pair::getSecond);
|
|
+ // Paper end
|
|
|
|
if (optional.isPresent()) {
|
|
return ((RecipeHolder) optional.get()).value().getRemainingItems(inventory);
|