diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 7f95e173a..3346e12ca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -63,6 +63,8 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected final List cachedAllItemSuggestions = new ArrayList<>(); protected final List cachedVanillaItemSuggestions = new ArrayList<>(); protected final List cachedTotemSuggestions = new ArrayList<>(); + // 替代配方材料 + protected final Map> ingredientSubstitutes = new HashMap<>(); protected AbstractItemManager(CraftEngine plugin) { super(plugin); @@ -141,6 +143,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl this.equipments.clear(); this.modernItemModels1_21_4.clear(); this.modernItemModels1_21_2.clear(); + this.ingredientSubstitutes.clear(); } @Override @@ -163,6 +166,15 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return Optional.ofNullable(this.customItemsByPath.get(path)); } + @Override + public List getIngredientSubstitutes(Key item) { + if (VANILLA_ITEMS.contains(item)) { + return Optional.ofNullable(this.ingredientSubstitutes.get(item)).orElse(Collections.emptyList()); + } else { + return Collections.emptyList(); + } + } + @Override public ItemUpdateResult updateItem(Item item, Supplier contextSupplier) { Optional> optionalCustomItem = item.getCustomItem(); @@ -599,6 +611,17 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl AbstractItemManager.this.plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); } + // 替代配方材料 + if (section.containsKey("ingredient-substitute")) { + List substitutes = MiscUtils.getAsStringList(section.get("ingredient-substitute")); + for (String substitute : substitutes) { + Key key = Key.of(substitute); + if (VANILLA_ITEMS.contains(key)) { + AbstractItemManager.this.ingredientSubstitutes.computeIfAbsent(key, k -> new ArrayList<>()).add(uniqueId); + } + } + } + /* * ======================== * diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index e837c541d..1b8a0c7b5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -124,5 +124,7 @@ public interface ItemManager extends Manageable, ModelGenerator { Item build(DatapackRecipeResult result); + List getIngredientSubstitutes(Key item); + ItemUpdateResult updateItem(Item item, Supplier contextSupplier); } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java index 43dd6dfc5..0b9dd5d1d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java @@ -144,13 +144,25 @@ public abstract class AbstractRecipeSerializer> implement Set minecraftItemIds = new HashSet<>(); ItemManager itemManager = CraftEngine.instance().itemManager(); for (String item : items) { - if (item.charAt(0) == '#') itemIds.addAll(itemManager.itemIdsByTag(Key.of(item.substring(1)))); - else { + if (item.charAt(0) == '#') { + List uniqueKeys = itemManager.itemIdsByTag(Key.of(item.substring(1))); + itemIds.addAll(uniqueKeys); + for (UniqueKey uniqueKey : uniqueKeys) { + List ingredientSubstitutes = itemManager.getIngredientSubstitutes(uniqueKey.key()); + if (!ingredientSubstitutes.isEmpty()) { + itemIds.addAll(ingredientSubstitutes); + } + } + } else { Key itemId = Key.of(item); if (itemManager.getBuildableItem(itemId).isEmpty()) { throw new LocalizedResourceConfigException("warning.config.recipe.invalid_ingredient", item); } itemIds.add(UniqueKey.create(itemId)); + List ingredientSubstitutes = itemManager.getIngredientSubstitutes(itemId); + if (!ingredientSubstitutes.isEmpty()) { + itemIds.addAll(ingredientSubstitutes); + } } } boolean hasCustomItem = false; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java index ff5828380..a15b91c71 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java @@ -21,10 +21,11 @@ public abstract class IdSectionConfigParser extends AbstractConfigParser { protected void parseSection(CachedConfigSection cached) { for (Map.Entry configEntry : cached.config().entrySet()) { String key = configEntry.getKey(); + Object value = configEntry.getValue(); Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); - if (!(configEntry.getValue() instanceof Map section)) { + if (!(value instanceof Map section)) { TranslationManager.instance().log("warning.config.structure.not_section", - cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName()); + cached.filePath().toString(), cached.prefix() + "." + key, value == null ? "null" : value.getClass().getSimpleName()); continue; } Map config = castToMap(section, false);