Генерація функцій
ПЕРЕДУМОВИ
Спершу переконайтеся, що ви виконали процес налаштування генерації даних.
Генерація функцій світів Minecraft розбита на 3 частини:
- Налаштовані функції: визначають, що таке функція; наприклад, одне дерево
- Розміщення функції: тут визначається, як мають розташовуватися функції, у якому напрямку, відносне розташування тощо; наприклад, розміщення дерев у лісі
- Модифікації біому: це визначає, де у світі розміщені функції; наприклад, координати всього лісу
INFO
Функції Minecraft — це природні або створені шаблони світу, наприклад дерева, квіти, руди чи озера. Функції відрізняються від структур (наприклад, сіл, храмів…), які можна знайти за допомогою команди /locate.
Налаштування
По-перше, нам потрібно створити свого постачальника. Створіть клас, який розширює FabricDynamicRegistryProvider та заповніть базові методи:
java
public class ExampleModWorldgenProvider extends FabricDynamicRegistryProvider {
public ExampleModWorldgenProvider(FabricDataOutput output, CompletableFuture<HolderLookup.Provider> registriesFuture) {
super(output, registriesFuture);
}
@Override
protected void configure(HolderLookup.Provider registries, Entries entries) {
}
@Override
public String getName() {
return "";
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
Потім додайте цього постачальника до свого класу DataGeneratorEntrypoint у методі onInitializeDataGenerator:
java
pack.addProvider(ExampleModWorldgenProvider::new);1
Далі створіть клас для налаштованих функцій і клас для розміщених функцій. Їм не потрібно нічого розширювати.
Налаштований клас функцій і розміщений клас функцій повинні мати загальнодоступний метод для реєстрації та визначення ваших функцій. Його аргумент, який ми назвали context, має бути BootstrapContext<ConfiguredFeature<?, ?>> для налаштованої функції або BootstrapContext<PlacedFeature> для розміщеної функції.
У вашому класі DataGeneratorEntrypoint додайте наведені нижче рядки до методу buildRegistry, замінивши назву методу тим, що ви вибрали:
java
registryBuilder.add(Registries.CONFIGURED_FEATURE, ExampleModWorldConfiguredFeatures::configure);
registryBuilder.add(Registries.PLACED_FEATURE, ExampleModWorldPlacedFeatures::configure);1
2
2
Якщо у вас ще немає методу buildRegistry, створіть його та додайте анотацію @Override.
Налаштовані функції
Щоб функція природно з’явилася в нашому світі, ми повинні почати з визначення налаштованої функції в нашому класі налаштованих функцій. Додаймо спеціальну налаштовану функцію для жили діамантової руди.
Спочатку зареєструйте ключ для ConfiguredFeature у вашому налаштованому класі функцій:
java
public static final ResourceKey<ConfiguredFeature<?, ?>> DIAMOND_BLOCK_VEIN_CONFIGURED_KEY =
ResourceKey.create(
Registries.CONFIGURED_FEATURE,
Identifier.fromNamespaceAndPath(ExampleMod.MOD_ID, "diamond_block_vein")
);1
2
3
4
5
2
3
4
5
TIP
Другий аргумент для Identifier (diamond_block_vein у цьому прикладі) — це те, що ви б використали для появи в структурі за допомогою команди /place, що корисно для налагодження.
Руди
Далі ми створимо RuleTest, який контролює, які блоки ваша функція може замінити. Наприклад, цей RuleTest дозволяє замінювати кожен блок на теґ DEEPSLATE_ORE_REPLACEABLES:
java
RuleTest deepslateReplaceableRule = new TagMatchTest(BlockTags.DEEPSLATE_ORE_REPLACEABLES);1
Далі нам потрібно створити OreConfiguration, який повідомляє грі, чим замінити блоки.
java
List<OreConfiguration.TargetBlockState> diamondBlockOreConfig =
List.of(
OreConfiguration.target(deepslateReplaceableRule, Blocks.DIAMOND_BLOCK.defaultBlockState())
);1
2
3
4
2
3
4
Ви можете мати кілька випадків у списку для різних варіантів. Наприклад, установімо інший варіант для каменю та глиболанцю:
java
List<OreConfiguration.TargetBlockState> ironAndDiamondBlockOreConfig =
List.of(
OreConfiguration.target(deepslateReplaceableRule, Blocks.DIAMOND_BLOCK.defaultBlockState()),
OreConfiguration.target(stoneReplaceableRule, Blocks.IRON_BLOCK.defaultBlockState())
);1
2
3
4
5
2
3
4
5
Нарешті, нам потрібно зареєструвати нашу налаштовану функцію в нашій грі!
java
context.register(
DIAMOND_BLOCK_VEIN_CONFIGURED_KEY,
new ConfiguredFeature<>(
Feature.ORE,
new OreConfiguration(diamondBlockOreConfig, 10)) // 10 is the blocks per vein
);1
2
3
4
5
6
2
3
4
5
6
Дерева
Щоб створити спеціальне дерево, спочатку потрібно створити TreeConfiguration:
java
TreeConfiguration diamondTree = new TreeConfiguration.TreeConfigurationBuilder(
// Trunk / Logs
BlockStateProvider.simple(Blocks.DIAMOND_BLOCK),
new StraightTrunkPlacer(4, 2, 0),
// Leaves
BlockStateProvider.simple(Blocks.GOLD_BLOCK),
new BlobFoliagePlacer(ConstantInt.of(2), ConstantInt.of(0), 3),
new TwoLayersFeatureSize(0, 0, 0)
).build();1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Ось що робить кожен аргумент:
- Визначає тип блока для стовбура дерева; наприклад, блоки діаманта
- Налаштовує форму та висоту стовбура за допомогою розміщувача стовбура
- Визначає тип блока для листя дерева; наприклад, блоки золота
- Визначає форму та розмір листя за допомогою розміщувача листя
- Контролює, як стовбур дерева звужується на різних висотах, переважно для великих стовбурів
TIP
Ми настійно рекомендуємо вам поекспериментувати з цими значеннями, щоб створити спеціальне дерево, яким ви будете задоволені!
Ви можете використовувати вбудовані розміщувачі для стовбура та листя ванільних дерев як орієнтир.
Далі нам потрібно зареєструвати наше дерево, додавши наступний рядок до методу configure ExampleModWorldConfiguredFeatures.
java
context.register(DIAMOND_TREE_CONFIGURED_KEY, new ConfiguredFeature<>(Feature.TREE, diamondTree));1
Функції розміщення
Наступним кроком у додаванні функції до гри є створення її розміщення.
У методі configure вашого розміщеного класу функцій створіть змінну, подібну до наведеної нижче:
java
HolderGetter<ConfiguredFeature<?, ?>> configuredFeatures = context.lookup(Registries.CONFIGURED_FEATURE);1
У вашому класі розміщення функції визначте ключ для розміщеної функції.
java
public static final ResourceKey<PlacedFeature> DIAMOND_BLOCK_ORE_PLACED_KEY =
ResourceKey.create(
Registries.PLACED_FEATURE,
Identifier.fromNamespaceAndPath(ExampleMod.MOD_ID, "diamond_block_ore_placed")
);1
2
3
4
5
2
3
4
5
Модифікатори розміщення
Далі нам потрібно визначити наші модифікатори розміщення, які є атрибутами, які ви встановлюєте під час створення функції. Це може бути що завгодно: від частоти появи до початкового рівня y. Ви можете мати стільки модифікаторів, скільки забажаєте.
java
List<PlacementModifier> diamondBlockVeinModifiers = List.of(
CountPlacement.of(6),
BiomeFilter.biome(),
InSquarePlacement.spread(),
HeightRangePlacement.of(BiasedToBottomHeight.of(VerticalAnchor.BOTTOM, VerticalAnchor.absolute(0), 3))
);1
2
3
4
5
6
2
3
4
5
6
Функції кожного модифікатора в списку такі:
- CountPlacement: Приблизно кількість екземплярів цієї функції (у цьому випадку жил) на чанк
- BiomeFilter: дозволяє нам контролювати, у яких біоми/виміри з'являється (ми зробимо це пізніше)
- InSquarePlacement: розподіляє функції більш псевдовипадково
- HeightRangePlacement: визначає діапазон координат
y, де може з’явитися функція; вона підтримує три основні типи дистрибуції:Uniform: Усі значення
yв межах діапазону з однаковою ймовірністю містять функцію. Якщо ви не впевнені, просто скористайтеся цим.Trapezoid: Значення
y, ближчі до середнього значенняy, мають вищу ймовірність містити функцію.Biased-Bottom: Використовує логарифмічну шкалу, де нижчі значення
yмають більшу ймовірність отримати функцію. Він отримує початкову координатуy, нижче якої функція ніколи не створюється. Другий аргумент — це максимальна висота, на якій може з’явитися функція. Третій аргумент визначає діапазон у блоках, на який поширюється максимальна ймовірність.
TIP
Дерева та інші поверхневі структури мають містити модифікатор PlacedFeatures.WORLD_SURFACE_WG_HEIGHTMAP замість HeightRangePlacement, щоб переконатися, що дерево з’являється на поверхні.
Тепер, коли у нас є модифікатори, ми можемо зареєструвати нашу розміщену функцію:
java
context.register(
DIAMOND_BLOCK_ORE_PLACED_KEY,
new PlacedFeature(
configuredFeatures.getOrThrow(ExampleModWorldConfiguredFeatures.DIAMOND_BLOCK_VEIN_CONFIGURED_KEY),
diamondBlockVeinModifiers
)
);1
2
3
4
5
6
7
2
3
4
5
6
7
Модифікації біому
Нарешті, нам потрібно додати нашу розміщену функцію до BiomeModifications під час ініціалізації мода. Ми можемо зробити це, додавши наступне до нашого ініціалізатора мода:
java
// Spawns everywhere in the overworld
BiomeModifications.addFeature(
BiomeSelectors.foundInOverworld(),
GenerationStep.Decoration.UNDERGROUND_ORES,
ExampleModWorldPlacedFeatures.DIAMOND_BLOCK_ORE_PLACED_KEY
);1
2
3
4
5
6
2
3
4
5
6
TIP
Для дерев другий параметр має бути GenerationStep.Decoration.VEGETAL_DECORATION,
Особливості генерації біому
Змінивши аргумент BiomeSelectors, ми можемо створювати нашу функцію лише в певному типі біому:
java
// Spawns in forest biomes only
BiomeModifications.addFeature(
BiomeSelectors.tag(BiomeTags.IS_FOREST),
GenerationStep.Decoration.VEGETAL_DECORATION,
ExampleModWorldPlacedFeatures.DIAMOND_TREE_PLACED_KEY
);1
2
3
4
5
6
2
3
4
5
6
Це з’явиться лише в біомах, позначених теґом біому minecraft:is_forest.
Запуск генерації даних
Тепер, коли ви запускаєте генерацію, ви маєте побачити файл .json у src/main/generated/data/example-mod/worldgen/configured_feature для кожної налаштованої функції, яку ви додали, а також файл у src/main/generated/data/example-mod/worldgen/placed_feature для кожної розміщеної функції!
Згенерований файл для налаштованої функції
json
{
"type": "minecraft:ore",
"config": {
"discard_chance_on_air_exposure": 0.0,
"size": 10,
"targets": [
{
"state": {
"Name": "minecraft:diamond_block"
},
"target": {
"predicate_type": "minecraft:tag_match",
"tag": "minecraft:deepslate_ore_replaceables"
}
}
]
}
}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
Згенерований файл для розміщеної функції
json
{
"feature": "example-mod:diamond_block_vein",
"placement": [
{
"type": "minecraft:count",
"count": 6
},
{
"type": "minecraft:biome"
},
{
"type": "minecraft:in_square"
},
{
"type": "minecraft:height_range",
"height": {
"type": "minecraft:biased_to_bottom",
"inner": 3,
"max_inclusive": {
"absolute": 0
},
"min_inclusive": {
"above_bottom": 0
}
}
}
]
}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
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28



