Yatopia/patches/server/0061-Heavily-optimize-recipe-lookups-in-CraftingManager.patch
budgidiere c09ee99f7e
Hydrinity optimizations & Lithium generation patches & more
Closes #257 

Ports 2 patches from Purpur: Infinity-bow-settings & Allow-infinite-and-mending-enchantments-together
Added an option for infinity with no arrows too.

Option for custom locale has come! You can put a locale.json file in your server folder to change it. 

We've got the finest patches from Hydrinity ( Mykyta approved & allowed ) too.

We have some amazing new options in yatopia.yml, we're gonna have documentation for them soon so stay tuned!
Last but not least, chunk generation patches. We've tested them extensively so no weirdness happens.

Thanks for using Yatopia as your production server software.

Co-authored-by: Ivan Pekov <ivan@mrivanplays.com>
2020-10-27 21:15:13 +02:00

141 lines
6.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.
GlueList was also used as a replacement for ArrayList as it is substantially faster.
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>
diff --git a/src/main/java/net/minecraft/server/CraftingManager.java b/src/main/java/net/minecraft/server/CraftingManager.java
index 58ecbe1e20581dc9e78cdd2f4ece29cfa014da8a..ddd3a071dde9daeebc3d512dd8fd02594d2071fe 100644
--- a/src/main/java/net/minecraft/server/CraftingManager.java
+++ b/src/main/java/net/minecraft/server/CraftingManager.java
@@ -31,6 +31,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 static final List<IRecipe<?>> ALL_RECIPES_CACHE = new net.yatopia.server.list.GlueList<>();
+ private static final Map<Recipes<?>, List<IRecipe<?>>> TYPES_CACHE = new Object2ObjectLinkedOpenHashMap<>();
+ // Yatopia end
public CraftingManager() {
super(CraftingManager.a, "recipes");
@@ -63,9 +67,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,23 +91,44 @@ 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 net.yatopia.server.list.GlueList<>(getRecipesMap(recipes).values()));
+ // Yatopia end
}
public <C extends IInventory, T extends IRecipe<C>> List<T> b(Recipes<T> recipes, C c0, World world) {
@@ -106,6 +139,7 @@ public class CraftingManager extends ResourceDataJson {
})).collect(Collectors.toList());
}
+ 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 +161,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 +200,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<>());