- 236
- 4
- 22
Добрый вечер, форумчане. Есть вопрос, касательно интеграции MineTweaker в мод, а точнее - "чтение" ингредиентов из метода. Как я уже понял, изучая код других модов - для интеграции нужно создать класс с аннотацией ZenClass и в нём методы с аннотациями @ZenMethod. И MineTweaker будет сам вызывать эти методы при перезагрузке скриптов, передавая спарсенные данные из скрипта. Вот тут и начинается веселуха: с примитивами и стрингами всё легко и ясно - так и юзаем их в аргументах метода. А вот с айтемстаками... Как я понял для "входящих" стаков нужно юзать IIngredient интерфейс, а для выходных - IItemStack.
Теперь собсна вопрос. Как правильно прочитать айтемы из этих 2 интерфейсов?
Для получения результата я нашёл примерно такой код
А вот с чтением входящих стаков - сложнее. Ведь могут передать как айтемстак (<modid:itemname:meta>), а могут и ore-словарь (<ore:ключ>). Также оба варианта могут быть умножены на необходимое кол-во. Читая исходники Avaritia + пытаясь дебагом разобраться в этой каше я написал примерно такой код:
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 и уже там получать имя словаря
Теперь основной вопрос темы - можно ли это реализовать без рефлексии (то есть создать универсальный преобразователь IIngredient в oreDictionary ключ + количество)? Если да - каким образом
Теперь собсна вопрос. Как правильно прочитать айтемы из этих 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;
}
Код:
@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 ключ + количество)? Если да - каким образом