--- a/net/minecraft/world/item/crafting/CraftingManager.java +++ b/net/minecraft/world/item/crafting/CraftingManager.java @@ -34,11 +34,13 @@ import net.minecraft.world.level.World; import org.slf4j.Logger; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; // CraftBukkit + public class CraftingManager extends ResourceDataJson { private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().disableHtmlEscaping().create(); private static final Logger LOGGER = LogUtils.getLogger(); - public Map, Map>> recipes = ImmutableMap.of(); + public Map, Object2ObjectLinkedOpenHashMap>> recipes = ImmutableMap.of(); // CraftBukkit private Map> byName = ImmutableMap.of(); private boolean hasErrors; @@ -48,7 +50,12 @@ protected void apply(Map map, IResourceManager iresourcemanager, GameProfilerFiller gameprofilerfiller) { this.hasErrors = false; - Map, Builder>> map1 = Maps.newHashMap(); + // CraftBukkit start - SPIGOT-5667 make sure all types are populated and mutable + Map, Object2ObjectLinkedOpenHashMap>> map1 = Maps.newHashMap(); + for (Recipes recipeType : IRegistry.RECIPE_TYPE) { + map1.put(recipeType, new Object2ObjectLinkedOpenHashMap<>()); + } + // CraftBukkit end Builder> builder = ImmutableMap.builder(); Iterator iterator = map.entrySet().iterator(); @@ -59,8 +66,10 @@ try { IRecipe irecipe = fromJson(minecraftkey, ChatDeserializer.convertToJsonObject((JsonElement) entry.getValue(), "top element")); - ((Builder) map1.computeIfAbsent(irecipe.getType(), (recipes) -> { - return ImmutableMap.builder(); + // CraftBukkit start + (map1.computeIfAbsent(irecipe.getType(), (recipes) -> { + return new Object2ObjectLinkedOpenHashMap<>(); + // CraftBukkit end })).put(minecraftkey, irecipe); builder.put(minecraftkey, irecipe); } catch (IllegalArgumentException | JsonParseException jsonparseexception) { @@ -69,27 +78,44 @@ } this.recipes = (Map) map1.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry1) -> { - return ((Builder) entry1.getValue()).build(); + return (entry1.getValue()); // CraftBukkit })); - this.byName = builder.build(); + this.byName = Maps.newHashMap(builder.build()); // CraftBukkit CraftingManager.LOGGER.info("Loaded {} recipes", map1.size()); } + // CraftBukkit start + public void addRecipe(IRecipe irecipe) { + Object2ObjectLinkedOpenHashMap> map = this.recipes.get(irecipe.getType()); // CraftBukkit + + if (byName.containsKey(irecipe.getId()) || map.containsKey(irecipe.getId())) { + throw new IllegalStateException("Duplicate recipe ignored with ID " + irecipe.getId()); + } else { + map.putAndMoveToFirst(irecipe.getId(), irecipe); // CraftBukkit - SPIGOT-4638: last recipe gets priority + byName.put(irecipe.getId(), irecipe); + } + } + // CraftBukkit end + public boolean hadErrorsLoading() { return this.hasErrors; } public > Optional getRecipeFor(Recipes recipes, C c0, World world) { - return this.byType(recipes).values().stream().filter((irecipe) -> { + // CraftBukkit start + Optional recipe = this.byType(recipes).values().stream().filter((irecipe) -> { return irecipe.matches(c0, world); }).findFirst(); + c0.setCurrentRecipe(recipe.orElse(null)); // CraftBukkit - Clear recipe when no recipe is found + // CraftBukkit end + return recipe; } public > Optional> getRecipeFor(Recipes recipes, C c0, World world, @Nullable MinecraftKey minecraftkey) { Map map = this.byType(recipes); if (minecraftkey != null) { - T t0 = (IRecipe) map.get(minecraftkey); + T t0 = map.get(minecraftkey); // CraftBukkit - decompile error if (t0 != null && t0.matches(c0, world)) { return Optional.of(Pair.of(minecraftkey, t0)); @@ -99,7 +125,7 @@ return map.entrySet().stream().filter((entry) -> { return ((IRecipe) entry.getValue()).matches(c0, world); }).findFirst().map((entry) -> { - return Pair.of((MinecraftKey) entry.getKey(), (IRecipe) entry.getValue()); + return Pair.of((MinecraftKey) entry.getKey(), entry.getValue()); // CraftBukkit - decompile error }); } @@ -116,7 +142,7 @@ } private > Map byType(Recipes recipes) { - return (Map) this.recipes.getOrDefault(recipes, Collections.emptyMap()); + return (Map) this.recipes.getOrDefault(recipes, new Object2ObjectLinkedOpenHashMap<>()); // CraftBukkit } public > NonNullList getRemainingItemsFor(Recipes recipes, C c0, World world) { @@ -136,7 +162,7 @@ } public Optional> byKey(MinecraftKey minecraftkey) { - return Optional.ofNullable((IRecipe) this.byName.get(minecraftkey)); + return Optional.ofNullable(this.byName.get(minecraftkey)); // CraftBukkit - decompile error } public Collection> getRecipes() { @@ -161,12 +187,12 @@ public void replaceRecipes(Iterable> iterable) { this.hasErrors = false; - Map, Map>> map = Maps.newHashMap(); + Map, Object2ObjectLinkedOpenHashMap>> map = Maps.newHashMap(); // CraftBukkit Builder> builder = ImmutableMap.builder(); iterable.forEach((irecipe) -> { Map> map1 = (Map) map.computeIfAbsent(irecipe.getType(), (recipes) -> { - return Maps.newHashMap(); + return new Object2ObjectLinkedOpenHashMap<>(); // CraftBukkit }); MinecraftKey minecraftkey = irecipe.getId(); IRecipe irecipe1 = (IRecipe) map1.put(minecraftkey, irecipe); @@ -177,8 +203,28 @@ } }); this.recipes = ImmutableMap.copyOf(map); - this.byName = builder.build(); + this.byName = Maps.newHashMap(builder.build()); // CraftBukkit + } + + // CraftBukkit start + public boolean removeRecipe(MinecraftKey mcKey) { + for (Object2ObjectLinkedOpenHashMap> recipes : recipes.values()) { + recipes.remove(mcKey); + } + + return byName.remove(mcKey) != null; + } + + public void clearRecipes() { + this.recipes = Maps.newHashMap(); + + for (Recipes recipeType : IRegistry.RECIPE_TYPE) { + this.recipes.put(recipeType, new Object2ObjectLinkedOpenHashMap<>()); + } + + this.byName = Maps.newHashMap(); } + // CraftBukkit end public static > CraftingManager.a createCheck(final Recipes recipes) { return new CraftingManager.a() { @@ -194,7 +240,7 @@ Pair pair = (Pair) optional.get(); this.lastRecipe = (MinecraftKey) pair.getFirst(); - return Optional.of((IRecipe) pair.getSecond()); + return Optional.of(pair.getSecond()); // CraftBukkit - decompile error } else { return Optional.empty(); }