Yatopia/patches/server/0041-Heavily-optimize-recipe-lookups-in-CraftingManager.patch
Simon Gardling c4a68471e4
Updated Upstream and Sidestream(s) (Paper/Tuinity/Purpur) (#435)
* Updated Upstream and Sidestream(s) (Paper/Tuinity/Purpur)

Upstream/An Sidestream has released updates that appears to apply and compile correctly
This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing.

Paper Changes:
d80e43647 [CI-SKIP] Removal from the MIT list (#5345)

Tuinity Changes:
c303521 Change license from MIT to LGPLv3

Purpur Changes:
3044036 Re-enable timings by default
4f85cbe Include all Airplane patches
7b5feba [ci-skip] Tuinity license change
210ff8f [ci-skip] revert last commit. wasnt what i thought it was :3
47e8965 [ci-skip] Add maven repositories for Adventure API
3930ac4 It's muffin time!
e535225 Updated Upstream (Paper & Tuinity)

* whoops

* this actually fixes it (I was being stupid)

* [CI-SKIP] fix akarin link in Licensing/LICENSE.md

* Updated Upstream and Sidestream(s) (Paper/Airplane/Akarin/Empirecraft)

Upstream/An Sidestream has released updates that appears to apply and compile correctly
This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing.

Paper Changes:
39c487b37 Add per-command perms for paper command
cdbf2578c Add Item Rarity API (#5352)

Airplane Changes:
5df9825 Remove iterators from inventory contains
18d2be1 Merge pull request #14 from violetwtf/patch-1
f716d4c Merge pull request #13 from violetwtf/master
128cbe5 Reduce entity chunk ticking checks from 3 to 1
03ac093 Skip copying unloading tile entities
97dd027 Smaller pool size for tracking
9e9f57b Only set up Flare if token is available
580f380 Updated Upstream (Tuinity)
97df206 Update README to reflect support changes
cf161dd Change blog URL to more helpful one

Akarin Changes:
6be3d57 Update Jenkinsfile
3aa2e99 Merge pull request #198 from HookWoods/ver/1.16.5
c548038 try to fix velocity repo
5b03eb1 Update patches to 1.16.5

Empirecraft Changes:
81545aaf Updated Paper

Airplane Changes:
82253fd Early return optimization for target finding
9572643 Cache entityhuman display name

* Updated Upstream and Sidestream(s) (Tuinity/Purpur/Airplane)

Upstream/An Sidestream has released updates that appears to apply and compile correctly
This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing.

Tuinity Changes:
aea6b83 Merge dev/playerchunkloading
722c7ca Use hash table for maintaing changed block set
98ae59d Custom table implementation for blockstate state lookups
8b8704f Oprimise map impl for tracked players
ea71d6b Optimise snow & ice in chunk ticking
9871d4c Remove chunk lookup & lambda allocation from counting mobs
5a4a35f Add patreon
7d93d96 Refactor data management for region manager

Purpur Changes:
37591fe Add config to use no-tick vd for tracker (#195)

Airplane Changes:
cc00c69 Updated Upstream (Tuinity)
2021-03-14 14:20:20 -05:00

181 lines
8.3 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mykyta Komarn <nkomarn@hotmail.com>
Date: Thu, 1 Oct 2020 06:57:43 -0700
Subject: [PATCH] Heavily optimize recipe lookups in CraftingManager
Recipe lookups are now cached in CraftingManager, which prevent unnecessary ArrayLists being created for every lookup. Additionally, an EMPTY_MAP variable was added to prevent bottlenecks during map creation, since that map is only ever iterated.
These changes knock off an extra ~10ms of tick duration with a sample of ~7,700 running furnaces on a server.
Co-authored-by: Ivan Pekov <ivan@mrivanplays.com>
Co-authored-by: ishland <ishlandmc@yeah.net>
diff --git a/src/main/java/net/minecraft/server/CraftingManager.java b/src/main/java/net/minecraft/server/CraftingManager.java
index 58ecbe1e20581dc9e78cdd2f4ece29cfa014da8a..6f3754d88e6d98fce5859fd2d58a9fc2e40f604a 100644
--- a/src/main/java/net/minecraft/server/CraftingManager.java
+++ b/src/main/java/net/minecraft/server/CraftingManager.java
@@ -24,6 +24,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; // CraftBukkit
+import it.unimi.dsi.fastutil.objects.ObjectArrayList; // Yatopia
public class CraftingManager extends ResourceDataJson {
@@ -31,6 +32,10 @@ public class CraftingManager extends ResourceDataJson {
private static final Logger LOGGER = LogManager.getLogger();
public Map<Recipes<?>, Object2ObjectLinkedOpenHashMap<MinecraftKey, IRecipe<?>>> recipes = ImmutableMap.of(); // CraftBukkit
private boolean d;
+ // Yatopia start
+ private final List<IRecipe<?>> ALL_RECIPES_CACHE = new ObjectArrayList<>();
+ private final Map<Recipes<?>, List<IRecipe<?>>> TYPES_CACHE = new Object2ObjectLinkedOpenHashMap<>();
+ // Yatopia end
public CraftingManager() {
super(CraftingManager.a, "recipes");
@@ -38,6 +43,7 @@ public class CraftingManager extends ResourceDataJson {
protected void a(Map<MinecraftKey, JsonElement> map, IResourceManager iresourcemanager, GameProfilerFiller gameprofilerfiller) {
this.d = false;
+ clearRecipes(); // Yatopia
// CraftBukkit start - SPIGOT-5667 make sure all types are populated and mutable
Map<Recipes<?>, Object2ObjectLinkedOpenHashMap<MinecraftKey, IRecipe<?>>> map1 = Maps.newHashMap();
for (Recipes<?> recipeType : IRegistry.RECIPE_TYPE) {
@@ -63,9 +69,17 @@ public class CraftingManager extends ResourceDataJson {
}
}
+ // Yatopia start - nuke stream & cache all recipes for constant access in b()
+ /*
this.recipes = (Map) map1.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry1) -> {
return entry1.getValue(); // CraftBukkit // Paper - decompile fix - *shrugs internally*
}));
+ */
+ this.recipes = ImmutableMap.copyOf(map1);
+ for (Object2ObjectLinkedOpenHashMap<MinecraftKey, IRecipe<?>> recipesMap : map1.values()) {
+ ALL_RECIPES_CACHE.addAll(recipesMap.values());
+ }
+ // Yatopia end
CraftingManager.LOGGER.info("Loaded {} recipes", map1.size());
}
@@ -79,33 +93,65 @@ public class CraftingManager extends ResourceDataJson {
} else {
map.putAndMoveToFirst(irecipe.getKey(), irecipe); // CraftBukkit - SPIGOT-4638: last recipe gets priority
}
+ ALL_RECIPES_CACHE.add(irecipe); // Yatopia
}
// CraftBukkit end
public <C extends IInventory, T extends IRecipe<C>> Optional<T> craft(Recipes<T> recipes, C c0, World world) {
// CraftBukkit start
+ // Yatopia start - replace stream
+ /*
Optional<T> recipe = this.b(recipes).values().stream().flatMap((irecipe) -> {
return SystemUtils.a(recipes.a(irecipe, world, c0));
}).findFirst();
+ */
+ // Yatopia start - replace stream
+ Collection<IRecipe<C>> allTypes = this.b(recipes).values();
+ Optional<T> recipe = Optional.empty();
+
+ for (IRecipe<C> possible : allTypes) {
+ Optional<T> possibleRecipe = recipes.a(possible, world, c0);
+ if (possibleRecipe.isPresent()) {
+ recipe = possibleRecipe;
+ break;
+ }
+ }
+ // Yatopia end
c0.setCurrentRecipe(recipe.orElse(null)); // CraftBukkit - Clear recipe when no recipe is found
// CraftBukkit end
return recipe;
}
public <C extends IInventory, T extends IRecipe<C>> List<T> a(Recipes<T> recipes) {
+ // Yatopia start - replaced logic
+ /*
return (List) this.b(recipes).values().stream().map((irecipe) -> {
return irecipe;
}).collect(Collectors.toList());
+ */
+ return (List) TYPES_CACHE.computeIfAbsent(recipes, recipes1 -> new me.jellysquid.mods.lithium.common.util.collections.HashedList<>(new ObjectArrayList<>(getRecipesMap(recipes).values())));
+ // Yatopia end
}
public <C extends IInventory, T extends IRecipe<C>> List<T> b(Recipes<T> recipes, C c0, World world) {
+ // Yatopia start - replace stream
+ /*
return (List) this.b(recipes).values().stream().flatMap((irecipe) -> {
return SystemUtils.a(recipes.a(irecipe, world, c0));
}).sorted(Comparator.comparing((irecipe) -> {
return irecipe.getResult().j();
})).collect(Collectors.toList());
+ */
+ List<T> ret = new ObjectArrayList<>();
+ for (IRecipe<C> recipe : this.b(recipes).values()) {
+ recipes.a(recipe, world, c0).ifPresent(ret::add);
+ }
+ ret.sort(Comparator.comparing(recipe -> recipe.getResult().getTranslationKey()));
+ return ret;
+ // Yatopia end
}
+ private <C extends IInventory, T extends IRecipe<C>> Map<MinecraftKey, IRecipe<C>> getRecipesMap(Recipes<T> recipes) { return b(recipes); } // Yatopia - OBFHELPER
private <C extends IInventory, T extends IRecipe<C>> Map<MinecraftKey, IRecipe<C>> b(Recipes<T> recipes) {
return (Map) this.recipes.getOrDefault(recipes, new Object2ObjectLinkedOpenHashMap<>()); // CraftBukkit
}
@@ -127,15 +173,26 @@ public class CraftingManager extends ResourceDataJson {
}
public Optional<? extends IRecipe<?>> getRecipe(MinecraftKey minecraftkey) {
+ // Yatopia start - replace stream
+ /*
return this.recipes.values().stream().map((map) -> {
return map.get(minecraftkey); // CraftBukkit - decompile error
}).filter(Objects::nonNull).findFirst();
+ */
+ for (Map<MinecraftKey, IRecipe<?>> map : recipes.values()) {
+ IRecipe<?> recipe = map.get(minecraftkey);
+ if (recipe != null) {
+ return Optional.of(recipe);
+ }
+ }
+ return Optional.empty();
+ // Yatopia end
}
public Collection<IRecipe<?>> b() {
- return (Collection) this.recipes.values().stream().flatMap((map) -> {
- return map.values().stream();
- }).collect(Collectors.toSet());
+ // Yatopia start - O(1) constant complexity
+ return ALL_RECIPES_CACHE;
+ // Yatopia end
}
public Stream<MinecraftKey> d() {
@@ -155,6 +212,10 @@ public class CraftingManager extends ResourceDataJson {
// CraftBukkit start
public void clearRecipes() {
this.recipes = Maps.newHashMap();
+ // Yatopia start - also clear cache
+ ALL_RECIPES_CACHE.clear();
+ TYPES_CACHE.clear();
+ // Yatopia end
for (Recipes<?> recipeType : IRegistry.RECIPE_TYPE) {
this.recipes.put(recipeType, new Object2ObjectLinkedOpenHashMap<>());
diff --git a/src/main/java/net/minecraft/server/ItemStack.java b/src/main/java/net/minecraft/server/ItemStack.java
index 47e3ac6bcebacd9c424ddcc49774e06e05f02fe2..cf3e4382aecd4c44c45877386eaf8fcc49657029 100644
--- a/src/main/java/net/minecraft/server/ItemStack.java
+++ b/src/main/java/net/minecraft/server/ItemStack.java
@@ -585,6 +585,7 @@ public final class ItemStack {
return !this.e() ? this.doMaterialsMatch(itemstack) : !itemstack.isEmpty() && this.getItem() == itemstack.getItem();
}
+ public final String getTranslationKey() { return j(); } // Yatopia - OBFHELPER
public String j() {
return this.getItem().f(this);
}