Генерация моделей предметов 26.1.2
Руководство по генерации моделей предметов с помощью datagen.
ТРЕБОВАНИЯ
Убедитесь что вы завершили установку datagen и создали свой первый предмет.
Для каждой модели предмета, которую мы хотим сгенерировать, необходимо создать два отдельных JSON-файла:
- Модель предмета (Item model): определяет текстуры, вращение и общий вид предмета. Сохраняется в директорию
generated/assets/example-mod/models/item. - Клиентский предмет (Client item): определяет, какая модель должна использоваться на основе различных критериев (компоненты, взаимодействия и т. д.). Сохраняется в директорию
generated/assets/example-mod/items.
Настройка
Сначала необходимо создать наш провайдер моделей.
TIP
Вы можете повторно использовать класс FabricModelProvider, созданный на этапе генерации моделей блоков.
Создайте класс, расширяющий FabricModelProvider и реализуйте оба абстрактных метода: generateBlockStateModels и generateItemModels. Затем создайте конструктор, соответствующий суперклассу (super).
java
public class ExampleModModelProvider extends FabricModelProvider {
public ExampleModModelProvider(FabricPackOutput output) {
super(output);
}
@Override
public void generateBlockStateModels(BlockModelGenerators blockStateModelGenerator) {
}
@Override
public void generateItemModels(ItemModelGenerators itemModelGenerator) {
}
@Override
public String getName() {
return "ExampleModModelProvider";
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Зарегистрируйте этот класс в вашем DataGeneratorEntrypoint внутри метода onInitializeDataGenerator.
java
pack.addProvider(ExampleModModelProvider::new);1
Встроенные модели предметов
Для создания моделей предметов мы будем использовать метод generateItemModels. Его параметр ItemModelGenerators itemModelGenerator отвечает за генерацию моделей и содержит необходимые для этого методы.
Ниже приведено описание наиболее часто используемых методов генератора моделей предметов.
Простые
Простые модели предметов используются по умолчанию для большинства предметов в Minecraft. Их родительской моделью (parent model) является GENERATED. В инвентаре они используют 2D-текстуру, а в игре рендерятся в 3D. Примеры: лодки, свечи или красители.
java
itemModelGenerator.generateFlatItem(ModItems.RUBY, ModelTemplates.FLAT_ITEM);1
Удерживаемые в руке
Модели типа Handheld обычно используются для инструментов и оружия (топоры, мечи, трезубец). Они повернуты и расположены в пространстве немного иначе, чем простые модели, чтобы выглядеть в руке более естественно.
java
itemModelGenerator.generateFlatItem(ModItems.GUIDITE_AXE, ModelTemplates.FLAT_HANDHELD_ITEM);1
Окрашиваемые
Метод для окрашиваемых предметов генерирует простую модель предмета и клиентский предмет, который задает цвет оттенка (tint color). Этому методу требуется дефолтное десятичное значение цвета, которое используется, когда предмет не окрашен. Дефолтное значение для кожи — 0xFFA06540.
java
itemModelGenerator.generateDyedItem(ModItems.LEATHER_GLOVES, 0xFFA06540);1
ВАЖНО
Вам необходимо создать DyeRecipe для вашего предмета, чтобы его можно было окрашивать в инвентаре!
Условные
Далее мы рассмотрим генерацию моделей предметов, которые меняют свой внешний вид при выполнении определенного условия, задаваемого вторым параметром BooleanProperty. Вот некоторые из них:
| Свойство | Описание |
|---|---|
IsKeybindDown | Значение «True», если нажата указанная клавиша. |
IsUsingItem | Значение «True», если предмет используется (например, при блокировании щитом). |
Broken | Значение «True», если у предмета прочность равна 0 (например, у элитр текстура меняется, когда они сломаны). |
HasComponent | Значение «True», если у предмета есть определённый компонент. |
Третий и четвертый параметры — это модели, которые будут использоваться, когда свойство принимает значения true или false соответственно.
java
itemModelGenerator.generateBooleanDispatch(
ModItems.FLASHLIGHT,
ItemModelUtils.isUsingItem(),
ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.FLASHLIGHT, "_lit", ModelTemplates.FLAT_ITEM)),
ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.FLASHLIGHT, ModelTemplates.FLAT_ITEM))
);1
2
3
4
5
6
2
3
4
5
6
ВАЖНО
Чтобы получить Identifier, который передается в ItemModelUtils.plainModel(), всегда используйте itemModelGenerator.createFlatItemModel(). В противном случае будут сгенерированы только клиентские предметы, а не сами модели!
Составные
Составные модели предметов состоят из одной или нескольких текстур, наложенных друг на друга слоями. Для этого в ванильной игре нет готовых методов; вам нужно использовать поле itemModelOutput объекта itemModelGenerator и вызвать на нем метод accept().
java
ItemModel.Unbaked hoe = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.ENHANCED_HOE, ModelTemplates.FLAT_HANDHELD_ITEM));
ItemModel.Unbaked hoePlus = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.ENHANCED_HOE, "_plus", ModelTemplates.FLAT_HANDHELD_ITEM));
itemModelGenerator.itemModelOutput.accept(
ModItems.ENHANCED_HOE,
ItemModelUtils.composite(hoe, hoePlus)
);1
2
3
4
5
6
7
2
3
4
5
6
7
Выборочные
Рендерит модель предмета на основе значения определенного свойства. Вот некоторые из них:
| Свойство | Описание |
|---|---|
ContextDimension | Отображает модель предмета в зависимости от измерения, в котором находится игрок (Overworld, Nether, End). |
MainHand | Отображает модель предмета, когда он находится в основной руке игрока. |
DisplayContext | Отображает модель предмета в зависимости от того, где он находится (ground - на земле, fixed - на фиксированном объекте, head - на голове и т. д.). |
ContextEntityType | Отображает модель предмета в зависимости от сущности, удерживающей этот предмет. |
В этом примере текстура предмета меняется при перемещении между измерениями: в обычном мире он зелёный, в нижнем мире — красный, а в мире края — чёрный.
java
ItemModel.Unbaked crystalOverworld = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.DIMENSIONAL_CRYSTAL, "_overworld", ModelTemplates.FLAT_ITEM));
ItemModel.Unbaked crystalNether = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.DIMENSIONAL_CRYSTAL, "_nether", ModelTemplates.FLAT_ITEM));
ItemModel.Unbaked crystalEnd = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.DIMENSIONAL_CRYSTAL, "_end", ModelTemplates.FLAT_ITEM));
itemModelGenerator.itemModelOutput.accept(
ModItems.DIMENSIONAL_CRYSTAL,
ItemModelUtils.select(new ContextDimension(),
ItemModelUtils.when(Level.OVERWORLD, crystalOverworld),
ItemModelUtils.when(Level.NETHER, crystalNether),
ItemModelUtils.when(Level.END, crystalEnd)
)
);1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
Распределение по диапазону
Рендерит модель предмета на основе значения числового свойства (numeric property). Принимает предмет и список вариантов, каждый из которых привязан к конкретному значению. Примеры: компас, лук и кисть.
Существует много поддерживаемых свойств, вот некоторые из них:
| Свойство | Описание |
|---|---|
Cooldown | Рендерит модель предмета на основе оставшегося времени перезарядки предмета. |
Count | Рендерит модель предмета на основе количества предметов в слоте. |
UseDuration | Рендерит модель предмета на основе того, как долго предмет уже используется. |
Damage | Рендерит модель предмета на основе урона от атаки (компонент minecraft:damage). |
В данном примере используется свойство Count, которое меняет текстуру от одного до трех ножей в зависимости от количества предметов в слоте.
java
ItemModel.Unbaked knifeOne = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.THROWING_KNIVES, "_one", ModelTemplates.FLAT_ITEM));
ItemModel.Unbaked knifeTwo = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.THROWING_KNIVES, "_two", ModelTemplates.FLAT_ITEM));
ItemModel.Unbaked knifeThree = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.THROWING_KNIVES, "_three", ModelTemplates.FLAT_ITEM));
itemModelGenerator.itemModelOutput.accept(
ModItems.THROWING_KNIVES,
ItemModelUtils.rangeSelect(
new Count(false),
List.of(
ItemModelUtils.override(knifeOne, 1.0F),
ItemModelUtils.override(knifeTwo, 2.0F),
ItemModelUtils.override(knifeThree, 3.0F)
)
)
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Пользовательские модели предметов
Генерация моделей предметов не ограничивается только ванильными методами; вы, конечно же, можете создавать свои собственные. В этом разделе мы создадим модель для предмета «Воздушный шар» (balloon).
Все поля и методы для этой части руководства объявлены в статическом внутреннем классе (static inner class) CustomItemModelGenerator.
Показать CustomItemModelGenerator
java
public static class CustomItemModelGenerator {
public static final ModelTemplate SCALED2X = item("scaled2x", TextureSlot.LAYER0);
public static void registerScaled2x(Item item, ItemModelGenerators generator) {
Identifier itemModel = SCALED2X.create(item, TextureMapping.singleSlot(TextureSlot.LAYER0, new Material(ModelLocationUtils.getModelLocation(item))), generator.modelOutput);
generator.itemModelOutput.accept(item, ItemModelUtils.plainModel(itemModel));
}
@SuppressWarnings("SameParameterValue")
private static ModelTemplate item(String parent, TextureSlot requiredTextureKeys) {
return new ModelTemplate(Optional.of(Identifier.fromNamespaceAndPath(ExampleMod.MOD_ID, "item/" + parent)), Optional.empty(), requiredTextureKeys);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Создание родительской модели
Сначала давайте создадим родительскую модель предмета (parent item model), которая определяет, как предмет выглядит в игре. Допустим, мы хотим, чтобы воздушный шар выглядел как простая модель предмета, но в увеличенном масштабе.
Для этого мы создадим файл resources/assets/example-mod/models/item/scaled2x.json, укажем в качестве родителя (parent) модель item/generated, а затем переопределим параметры масштабирования (scaling).
json
{
"parent": "item/generated",
"display": {
"ground": {
"rotation": [0, 0, 0],
"translation": [0, 2, 0],
"scale": [1, 1, 1]
},
"head": {
"rotation": [0, 180, 0],
"translation": [0, 13, 7],
"scale": [2, 2, 2]
},
"thirdperson_righthand": {
"rotation": [0, 0, 0],
"translation": [0, 3, 1],
"scale": [1.1, 1.1, 1.1]
},
"firstperson_righthand": {
"rotation": [0, -90, 25],
"translation": [1.13, 3.2, 1.13],
"scale": [1.36, 1.36, 1.36]
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Это сделает модель визуально в два раза больше, чем простые модели.
Создание ModelTemplate
Далее нам нужно создать экземпляр класса ModelTemplate. Он будет представлять фактическую родительскую модель предмета внутри нашего мода.
java
public static final ModelTemplate SCALED2X = item("scaled2x", TextureSlot.LAYER0);
private static ModelTemplate item(String parent, TextureSlot requiredTextureKeys) {
return new ModelTemplate(Optional.of(Identifier.fromNamespaceAndPath(ExampleMod.MOD_ID, "item/" + parent)), Optional.empty(), requiredTextureKeys);
}1
2
3
4
5
2
3
4
5
Метод item() создает новый экземпляр ModelTemplate, указывая на файл scaled2x.json, который мы создали ранее.
Слот текстуры TextureSlot LAYER0 представляет переменную текстуры #layer0, которая затем будет заменена на идентификатор, указывающий на конкретную текстуру.
Добавление кастомного метода Datagen
Последний шаг — создание кастомного метода, который будет вызываться в методе generateItemModels() и отвечать за генерацию наших моделей предметов.
java
public static void registerScaled2x(Item item, ItemModelGenerators generator) {
Identifier itemModel = SCALED2X.create(item, TextureMapping.singleSlot(TextureSlot.LAYER0, new Material(ModelLocationUtils.getModelLocation(item))), generator.modelOutput);
generator.itemModelOutput.accept(item, ItemModelUtils.plainModel(itemModel));
}1
2
3
4
2
3
4
Давайте разберем, за что отвечают параметры:
Item item: предмет, для которого мы генерируем модели.ItemModelGenerators generator: тот же объект, который передается в методgenerateItemModels(). Используется ради его полей.
Сначала мы получаем Identifier предмета с помощью SCALED2X.create(), передавая туда TextureMapping и modelOutput из нашего параметра generator.
Затем мы используем еще одно его поле — itemModelOutput (которое по сути работает как потребитель/consumer) — и вызываем метод accept(), чтобы модели действительно сгенерировались.
Вызов кастомного метода
Теперь нам осталось только вызвать наш метод внутри метода generateItemModels().
java
CustomItemModelGenerator.registerScaled2x(ModItems.BALLOON, itemModelGenerator);1
Не забудьте добавить файл текстуры!





