MineTweaker интеграция

Версия Minecraft
1.7.10
API
Forge
166
2
7
Добрый вечер, форумчане. Есть вопрос, касательно интеграции MineTweaker в мод, а точнее - "чтение" ингредиентов из метода. Как я уже понял, изучая код других модов - для интеграции нужно создать класс с аннотацией ZenClass и в нём методы с аннотациями @ZenMethod. И MineTweaker будет сам вызывать эти методы при перезагрузке скриптов, передавая спарсенные данные из скрипта. Вот тут и начинается веселуха: с примитивами и стрингами всё легко и ясно - так и юзаем их в аргументах метода. А вот с айтемстаками... Как я понял для "входящих" стаков нужно юзать IIngredient интерфейс, а для выходных - IItemStack.

Теперь собсна вопрос. Как правильно прочитать айтемы из этих 2 интерфейсов?
Для получения результата я нашёл примерно такой код

Код:
 @Nullable
    public static ItemStack toStack(IItemStack item)
    {
        if (item == null) return null;
        Object internal = item.getInternal();
        if (internal instanceof ItemStack)
            return (ItemStack) internal;
        MineTweakerAPI.getLogger().logError("Not a valid item stack: " + item);
        return null;
    }
А вот с чтением входящих стаков - сложнее. Ведь могут передать как айтемстак (<modid:itemname:meta>), а могут и ore-словарь (<ore:ключ>). Также оба варианта могут быть умножены на необходимое кол-во. Читая исходники Avaritia + пытаясь дебагом разобраться в этой каше я написал примерно такой код:

Код:
@Nonnull
    protected static InputStack toInputStack(IIngredient ingredient)
    {
        if (ingredient instanceof IOreDictEntry)
            return new InputStack(((IOreDictEntry) ingredient).getName(), ingredient.getAmount());
        else if(ingredient instanceof IItemStack)
            return new InputStack(toStack((IItemStack) ingredient));
        else return new InputStack();
    }


Pss: InputStack - мой класс, который имеет пустой конструктор (пустой слот), конструктор по String-ключу из oreDictionary и по ItemStack`у. Опционально во всех случаях можно дописать требуемое кол-во (например new InputStack("ingotCopper", 10) - 10 любых слитков меди). На этом классе у меня построены все менеджеры рецептов и тайлы.


Когда я начал тестить это, оказалось, что если юзать <ore:ключ> - ингредиент является IOreDictEntry. Если юзать <modid:itemname> / <modid:itemname:meta> / <modid:itemname> * число / <modid:itemname:meta> * число - IItemStack. А вот если <ore:ключ> * число - IngredientStack.
В итоге в последнем случае мой код просто возвращает пустой стак - я не могу в скрипте юзнуть <ore:имя>* кол-во, что крайне не удобно. Тогда я начал думать что же делать мне, ведь у IIngredient, который реализуется всеми этими интерфейсами(классом) не имеет метода getName(), только getAmount(). Мне пришлось прибегнуть к рефлексии, т.к. в IngredientStack есть приватная константа IIngredient и кол-во. Для кол-ва есть геттер, а вот сам ингредиент приходится рефлексией читать, кастить к IOreDictEntry и уже там получать имя словаря
Код:
@Nonnull
    protected static InputStack toInputStack(IIngredient ingredient)
    {
        if (ingredient instanceof IOreDictEntry)
            return new InputStack(((IOreDictEntry) ingredient).getName(), ingredient.getAmount());
        else if(ingredient instanceof IItemStack)
            return new InputStack(toStack((IItemStack) ingredient));
        else if(ingredient instanceof IngredientStack) {
            try {
                Field f = IngredientStack.class.getDeclaredField("ingredient");
                f.setAccessible(true);
                IIngredient value = (IIngredient)f.get(ingredient);
                return value instanceof IOreDictEntry ? new InputStack(((IOreDictEntry)value).getName(), ingredient.getAmount()) : new InputStack();
            } catch (Exception error) {
                return new InputStack();
            }
        } else return new InputStack();
    }

Теперь основной вопрос темы - можно ли это реализовать без рефлексии (то есть создать универсальный преобразователь IIngredient в oreDictionary ключ + количество)? Если да - каким образом
 
1618999995618.png

Чекни ModTweaker, там есть много интеграций где можно указывать предметы по словарю. К примеру - арканский верстак из таума. Я не сильно глубоко копнул в код, но вроде InputHelper как-то преобразует ингридиенты в стаки без лишних танцев с бубном.
 
Последнее редактирование:
Сверху