Удаление и возврат рецептов

Удаление и возврат рецептов

Версия(и) Minecraft
1.12.2
Всем добра-бобра. Решил выложить свой вариант того, как удалять и возвращать рецепты в кубаче.
1.Ну-с, Удаление рецепта:
Для начала стоит завести отдельный класс для всего этого. Я обозвал его CraftManager.
Вторым делом заведем метод, который будет искать рецепт в общем массиве ForgeRegistries.
Java:
public static ArrayList<CraftPOJO> removedRecipe = new ArrayList<>(); //Завожу лист, куда буду класть удалённые рецепты.
//Если не собираешься делать возврат крафта - можно не заводить.
public static IRecipe getRecipe(ItemStack removed) {
        try {
            ArrayList<IRecipe> recipes = Lists.newArrayList(ForgeRegistries.RECIPES.getValues()); //получаем лист рецептов и сверяемся с ним.
            for (IRecipe recipe : recipes) {
                if (recipe.getRecipeOutput().getItem() != Items.AIR //проверка на воздух на всякий.
//Я встречал краши из-за этого
                        && !removed.isEmpty()
                        && removed.getItem() == recipe.getRecipeOutput().getItem() // я вкурсе, что это можно было бы заменить
//одним методом из класса ItemStack, но мне лень :D
                        && recipe.getRecipeOutput().getMetadata() == removed.getMetadata()) {
                    return recipe //возвращаем наш рецепт.
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
После этого можно написать метод, удаляющий данный рецепт.
Java:
public static void removeCrafting(IRecipe recipe) {
        try {
            ForgeRegistry<IRecipe> recipeRegistry = (ForgeRegistry<IRecipe>) ForgeRegistries.RECIPES;
            recipeRegistry.unfreeze(); //Обязательная размарозка, иначе получим краш/ошибку/т.п.
            removedRecipe.add(new CraftPOJO(recipe.getRegistryName(), recipe, recipeRegistry.getID(recipe))); //Я создал простенький POJO,в котором храню копию рецепта,стак который удалял и т.п. Необходимо, если надо будет потом когда-то возвращать рецепт обратно в майн.
            recipeRegistry.remove(recipe.getRegistryName());// Ну и удаляем рецепт

            recipeRegistry.freeze(); //Замораживаем изменения
            Main.Logger.info(ChatForm.prefix + "Removed recipe: " + recipe.getRecipeOutput().getDisplayName() + ":" + recipe.getRecipeOutput().getMetadata());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
Сам класс CraftPOJO нам нужен только для хранения рецепта, который мы хотим вернуть.
Java:
public class CraftPOJO {

    private final ResourceLocation location;
    private final IRecipe recipe;
    private final int id;
    private final ItemStack is;
    private boolean delete = false;

    public CraftPOJO(ResourceLocation location, IRecipe recipe, int id) {
        this.location = location;
        this.recipe = recipe;
        this.id = id;
        this.is = recipe.getRecipeOutput();
    }

    public ItemStack getIs() {
        return is;
    }

    public ResourceLocation getLocation() {
        return location;
    }

    public IRecipe getRecipe() {
        return recipe;
    }

    public int getId() {
        return id;
    }

    public void setDelete() {
        delete = true;
    }

    public boolean getDelete() {
        return delete;
    }
}
Ну вот и всё).
2. Рецепт то мы удалили. А как его вернуть?
Сразу оговорюсь. тут используется рефлексия. т.к. AT не может взять эти поля, а использовать миксины/хуки - слишком жирно.
Для того,что-бы вернуть рецепт нам необходимо вернуть его обратно прямо в 2 мапы
Java:
public static void bringBack(ItemStack is) {
        try {
            if (!is.isEmpty() && contains(is)) {//сверяем is на пустоту и если is содержится в ArrayList<CraftPOJO>
// который мы создали в самом начале - продолжаем
                ForgeRegistry<IRecipe> recipeRegistry = (ForgeRegistry<IRecipe>) ForgeRegistries.RECIPES;
                CraftPOJO pojo = get(is); //получаю pojo по IS
                if (pojo == null) { //доп. проверка
                    System.err.println(is.getDisplayName() + " in POJO == null");
                    return;
                }
                Field namesF = recipeRegistry.getClass().getDeclaredField("names"); //получаем поле names из класса рецептов
                namesF.setAccessible(true);
                BiMap<ResourceLocation, IRecipe> names = (BiMap<ResourceLocation, IRecipe>) namesF.get(recipeRegistry); //получаем копию Biмапы

                Field idsF = recipeRegistry.getClass().getDeclaredField("ids");
                idsF.setAccessible(true);
                BiMap<Integer, IRecipe> ids = (BiMap<Integer, IRecipe>) idsF.get(recipeRegistry);
               
                recipeRegistry.unfreeze(); //анфриз, как и п.1.
                names.put(pojo.getLocation(), pojo.getRecipe()); //кладём обратно рецепт
                ids.put(pojo.getId(), pojo.getRecipe());//кладём обратно ид рецепта
                recipeRegistry.freeze(); //фризим
                pojo.setDelete(); //Так как я делаю это всё в переборе - сетаем булеву в тру,
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
Весь класс можно посмотреть в открытой репе моего мода - src/main/java/ru/will0376/OpenBlocker/common/CraftManager.java · master · Will0376 / OpenBlocker
В нём я использую пересыл удаляемых блоков с сервера и т.п. Так что то,что там - немного отличается от приведённого тут.
З.ы. try-catch везде - на всякий.
Автор
will0376
Просмотры
201
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху