mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-02 04:56:50 +01:00
fe53b0e76f
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: 1d522878 PR-966: Introduce getRespawnLocation as a replacement for getBedSpawnLocation cc01b745 PR-965: Add DragonBattle#setPreviouslyKilled 28e3702f SPIGOT-6921, PR-957: Add methods to remove all enchantments on an ItemStack 8872404e PR-961: Add BlockData#copyTo 4054cc7b PR-956: Add method to get an offline player's location CraftBukkit Changes: 292ec79e0 SPIGOT-7568: Call EntityChangeBlockEvent for DecoratedPot b44bf5aa8 SPIGOT-7575: SuspiciousStewMeta creates invalid PotionEffect data 161784713 PR-1340: Centralize the conversion from and to Minecraft / Bukkit registry items even more and add a test case for them b93c5a30d PR-1338: Introduce getRespawnLocation as a replacement for getBedSpawnLocation fb973486c SPIGOT-7570: PrepareItemCraftEvent#isRepair() always returns false c9c24535e PR-1337: Add DragonBattle#setPreviouslyKilled c8b4da803 SPIGOT-6921, PR-1330: Add methods to remove all enchantments on an ItemStack 95bc1c4f5 PR-1333: Add BlockData#copyTo 36e2f9ce1 PR-1329: Add method to get an offline player's location Spigot Changes: c198da22 SPIGOT-7563: Update to latest release of bungeecord-chat
83 lines
6.5 KiB
Diff
83 lines
6.5 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 7a0c1a55a211035bbca7b97293e94b04ae308bae..c3800bdd5096cb06e085e28f6bf0f65586ecf11e 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 - Perf: Improve mass crafting; 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 - Perf: Improve mass crafting; 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 7b2ac37e8bd305919f04ded043e50f13b3fe4253..245731757f2593c736916ac6ee59e2c91d179934 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 - Perf: Improve mass crafting; 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 a0ab3c55826af292d1cdac05648139b4d31f1376..d87124f5356180a37e581febc6141fdc5f1395a7 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 - Perf: Improve mass crafting
|
|
return Optional.of(Pair.of(id, recipeholder));
|
|
}
|
|
}
|
|
|
|
+ inventory.setCurrentRecipe(null); // Paper - Perf: Improve mass crafting;; 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 - Perf: Improve mass crafting
|
|
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 - Perf: Improve mass crafting;; 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 - Perf: Improve mass crafting
|
|
|
|
if (optional.isPresent()) {
|
|
return ((RecipeHolder) optional.get()).value().getRemainingItems(inventory);
|