- Версия(и) Minecraft
- 1.12.2
Всем добра-бобра. Решил выложить свой вариант того, как удалять и возвращать рецепты в кубаче.
1.Ну-с, Удаление рецепта:
Для начала стоит завести отдельный класс для всего этого. Я обозвал его CraftManager.
Вторым делом заведем метод, который будет искать рецепт в общем массиве ForgeRegistries.
После этого можно написать метод, удаляющий данный рецепт.
Сам класс CraftPOJO нам нужен только для хранения рецепта, который мы хотим вернуть.
Ну вот и всё).
2. Рецепт то мы удалили. А как его вернуть?
Сразу оговорюсь. тут используется рефлексия. т.к. AT не может взять эти поля, а использовать миксины/хуки - слишком жирно.
Для того,что-бы вернуть рецепт нам необходимо вернуть его обратно прямо в 2 мапы
Весь класс можно посмотреть в открытой репе моего мода - src/main/java/ru/will0376/OpenBlocker/common/CraftManager.java · master · Will0376 / OpenBlocker
В нём я использую пересыл удаляемых блоков с сервера и т.п. Так что то,что там - немного отличается от приведённого тут.
З.ы. try-catch везде - на всякий.
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();
}
}
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();
}
}
В нём я использую пересыл удаляемых блоков с сервера и т.п. Так что то,что там - немного отличается от приведённого тут.
З.ы. try-catch везде - на всякий.