mirror of
https://github.com/YatopiaMC/Yatopia.git
synced 2024-11-25 20:16:09 +01:00
181 lines
8.3 KiB
Diff
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 3f9062d8eca3ce53c0fb9e9e40330aa4e3296c9a..ba16239dd351341bc97a8484369d97ecb655b52b 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);
|
|
}
|