Рецепт с применением NBT

Версия Minecraft
1.16.5
API
Fabric

WantaSanchez

Опоздун
633
17
150
Доброго времени суток! Нужно сделать рецепт, в котором один из ингредиентов является бутыль с водой. Этот бутыль с водой есть как предмет minecraft:potion что говорит нам, что бутыль с водой это уже подтип зелий, который указан в NBT. Только вот в рецептах вроде как нельзя использовать NBT (по крайней мере в json) хотя есть сторонняя модификация, которая расширяет функционал json рецептов вплоть до использования в них NBT. Но у меня нет желания делать свою модификацию зависимой от какой-то левой. Пока что я не могу смотреть код ванильных класов, однако я узнал, что в json для стрел с эффектами (для выдачи рецептов) указан кастомный тип рецептов (по идее и со всеми рецептами для тех же стрел). Кто обладает инфой по этой теме? В поиске ничего внятного не нашёл (или плохо искал 🤷‍♂️).
 

Sainthozier

Стрелочник
623
11
369
Подобные решения искать нужно не на форумах, а в репозиториях модов. Найди на курсе какой-то мод на апгрейд/создание инструментов, оружия и т.п., ну или в таком духе, где было бы вполне логично предположить наличие рецепта с NBT, и чекни сурцы. Наверняка найдёшь то, что подойдёт
 
7,099
324
1,510
Можно запилить рецепт кодом. Пример с двумя рецептами:
Java:
package hohserg.rainbow.lenses.recipe;

import hohserg.rainbow.lenses.Main;
import hohserg.rainbow.lenses.init.RLItems;
import hohserg.rainbow.lenses.lens.ActivationLens;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipeSerializer;
import net.minecraft.item.crafting.SpecialRecipe;
import net.minecraft.item.crafting.SpecialRecipeSerializer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Mod.EventBusSubscriber(modid = Main.modid, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
public class ActivationLensRecipes {

    @SubscribeEvent
    public static void registerRecipeSerializers(RegistryEvent.Register<IRecipeSerializer<?>> event) {
        event.getRegistry().register(ClearingRecipe.SERIALIZER.setRegistryName(new ResourceLocation(Main.modid, "clearing_activation_lens")));
        event.getRegistry().register(InsertToolRecipe.SERIALIZER.setRegistryName(new ResourceLocation(Main.modid, "insert_tool_activation_lens")));
    }

    private static class ClearingRecipe extends SpecialRecipe {
        public ClearingRecipe(ResourceLocation idIn) {
            super(idIn);
        }

        @Override
        public boolean matches(CraftingInventory inv, World worldIn) {
            List<ItemStack> itemStacks = IntStream.range(0, inv.getSizeInventory()).mapToObj(inv::getStackInSlot).filter(i -> !i.isEmpty()).collect(Collectors.toList());
            if (itemStacks.stream().anyMatch(i -> i.getItem() == RLItems.activationLens.get()))
                return itemStacks.size() == 1;
            else
                return false;
        }

        @Override
        public ItemStack getCraftingResult(CraftingInventory inv) {
            return IntStream.range(0, inv.getSizeInventory())
                    .mapToObj(inv::getStackInSlot)
                    .filter(i -> i.getItem() == RLItems.activationLens.get())
                    .findAny()
                    .map(ItemStack::copy)
                    .map(i -> {
                        ActivationLens.setTool(i, ItemStack.EMPTY);
                        return i;
                    }).orElse(ItemStack.EMPTY);
        }

        @Override
        public boolean canFit(int width, int height) {
            return width * height >= 1;
        }

        @Override
        public IRecipeSerializer<?> getSerializer() {
            return SERIALIZER;
        }

        public static final SpecialRecipeSerializer<ClearingRecipe> SERIALIZER = new SpecialRecipeSerializer<>(ClearingRecipe::new);
    }

    private static class InsertToolRecipe extends SpecialRecipe {
        public InsertToolRecipe(ResourceLocation idIn) {
            super(idIn);
        }

        @Override
        public boolean matches(CraftingInventory inv, World worldIn) {
            List<ItemStack> itemStacks = IntStream.range(0, inv.getSizeInventory()).mapToObj(inv::getStackInSlot).filter(i -> !i.isEmpty()).collect(Collectors.toList());
            return itemStacks.size() == 2 &&
                    itemStacks.stream().anyMatch(i -> i.getItem() == RLItems.activationLens.get()) &&
                    itemStacks.stream().anyMatch(i -> i.getItem() != RLItems.activationLens.get());
        }

        @Override
        public ItemStack getCraftingResult(CraftingInventory inv) {
            List<ItemStack> itemStacks = IntStream.range(0, inv.getSizeInventory()).mapToObj(inv::getStackInSlot).filter(i -> !i.isEmpty()).collect(Collectors.toList());

            ItemStack first = itemStacks.get(0);
            ItemStack second = itemStacks.get(1);

            ItemStack lens = first.getItem() == RLItems.activationLens.get() ? first : second;
            ItemStack tool = first.getItem() == RLItems.activationLens.get() ? second : first;

            ItemStack copy = lens.copy();
            ActivationLens.setTool(copy, tool);
            return copy;
        }

        @Override
        public boolean canFit(int width, int height) {
            return width * height >= 2;
        }

        @Override
        public IRecipeSerializer<?> getSerializer() {
            return SERIALIZER;
        }

        public static final SpecialRecipeSerializer<InsertToolRecipe> SERIALIZER = new SpecialRecipeSerializer<>(InsertToolRecipe::new);
    }
}
 
7,099
324
1,510
Тогда придется куда-то вставить миксин, чтобы воспроизвести эту фичу форжа для добавления рецепта кодом
 
Сверху