Модифікація таблиць здобичі 26.2
Дізнайтеся, як модифікувати таблиці здобичі за допомогою подій, наданих Fabric API.
Система таблиць здобичі визначає, які предмети випадають, коли руйнується блок, гине сутність або відкривається скриня. Fabric API надає кілька способів змінювати, замінювати та додатково обробляти таблиці здобичі під час завантаження, а також коригувати кінцеву здобич безпосередньо під час гри.
Fabric API Здобичі надає кілька подій через клас LootTableEvents:
LootTableEvents.MODIFY: зберегти початкову таблицю здобичі та додати набори й записи.LootTableEvents.REPLACE: відкинути початкову таблицю та надати нову.LootTableEvents.MODIFY_DROPS: зміна кінцевого спискуItemStack, що випадають, після генерації здобичі.LootTableEvents.ALL_LOADED: перегляд або перевірка всіх таблиць після завершення їх завантаження.
Ці події відбуваються в певній послідовності під час процесу завантаження таблиці здобичі:
REPLACEMODIFYALL_LOADEDMODIFY_DROPS
MODIFY_DROPS — це єдина подія, що відбувається під час виконання, тоді як інші трапляються під час завантаження світу.
Під час використання цих подій важливо пам'ятати про цей порядок, оскільки він впливає на те, як ваші зміни взаємодіють з іншими подіями та початковими таблицями здобичі.
Модифікація таблиці здобичі
Використовуйте LootTableEvents.MODIFY, якщо хочете змінити наявну таблицю здобичі, зберігши при цьому її початковий уміст. Зворотний виклик надає вам LootTable.Builder, тож ви можете додавати нові набори або записи до наявних наборів, не перебудовуючи всю таблицю.
Зазвичай це найкращий варіант для додавання предметів до стандартних таблиць або таблиць з пакетів даних — наприклад, щоб додати власний предмет до списку того, що випадає з блока. Ви можете перевірити параметр source, щоб дізнатися, чи походить таблиця з вбудованих ресурсів, пакета даних або іншої події заміни.
Використовуйте MODIFY, якщо початкова таблиця здобичі має залишитися переважно незмінною.
Наприклад, використаймо подію MODIFY, щоб під час убивства білої вівці діамантовим мечем випадав діамант, застосувавши предикат LootItemEntityPropertyCondition.
java
LootTableEvents.MODIFY.register((key, tableBuilder, source, registries) -> {
// If the loot table is for a white sheep, and it is not overridden by a user:
if (source.isBuiltin() && BuiltInLootTables.SHEEP.white().equals(key)) {
// Create a new loot pool that will hold the diamonds.
LootPool.Builder pool = LootPool.lootPool()
// Add diamonds...
.add(LootItem.lootTableItem(Items.DIAMOND))
// ...only if the sheep was killed with a diamond sword.
.when(LootItemEntityPropertyCondition.hasProperties(
LootContext.EntityTarget.ATTACKER,
EntityPredicate.Builder.entity().equipment(
EntityEquipmentPredicate.Builder.equipment().mainhand(
ItemPredicate.Builder.item().of(
registries.lookupOrThrow(Registries.ITEM),
Items.DIAMOND_SWORD
)
)
)
));
// Add the loot pool to the loot table
tableBuilder.withPool(pool);
}
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Ефект наведеного вище прикладу:
Заміна таблиць здобичі
Використовуйте LootTableEvents.REPLACE, якщо хочете відкинути наявну таблицю здобичі та надати нову.
Функція зворотного виклику отримує оригінальну LootTable. Поверніть нову LootTable для заміни або поверніть null, щоб залишити її без змін. Після того як слухач замінює таблицю, жодні інші слухачі заміни для неї викликатися не будуть.
Ця подія стане в пригоді, якщо початкова таблиця несумісна з логікою вашого мода, а зміна окремих наборів здобичі виявилася б складнішою за створення нової таблиці.
Наприклад, використаймо подію REPLACE, щоб замінити таблицю здобичі для коричневої вівці на нову, з якої випадає золотий злиток у разі вбивства золотим мечем, застосувавши предикат LootItemEntityPropertyCondition.
java
LootTableEvents.REPLACE.register((key, original, source, holder) -> {
// If the loot table is for a brown sheep, and it is not overridden by a user:
if (source.isBuiltin() && BuiltInLootTables.SHEEP.brown().equals(key)) {
// Create a new loot pool that will hold the gold ingot.
LootPool.Builder pool = LootPool.lootPool()
// Add gold ingot...
.add(LootItem.lootTableItem(Items.GOLD_INGOT))
// ...only if the sheep was killed with a golden sword.
.when(LootItemEntityPropertyCondition.hasProperties(
LootContext.EntityTarget.ATTACKER,
EntityPredicate.Builder.entity().equipment(
EntityEquipmentPredicate.Builder.equipment().mainhand(
ItemPredicate.Builder.item().of(
holder.lookupOrThrow(Registries.ITEM),
Items.GOLDEN_SWORD
)
)
)
));
// Create a new loot table with the loot pool
return LootTable.lootTable().withPool(pool).build();
}
return null;
});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
WARNING
Завжди повертайте null, якщо ви не замінюєте таблицю здобичі. Повернення початкової таблиці все одно позначає таблицю здобичі як замінену, що перешкоджає виконанню наступних слухачів заміни та призводить до невдалого проходження перевірки isBuiltIn().
Ефект наведеного вище прикладу:
Зміна предметів, що випадають із таблиць здобичі
LootTableEvents.MODIFY_DROPS не спрацьовує, доки здобич не буде згенеровано під час виконання. Ця подія корисна, коли:
- Кількість таблиць здобичі невідома або дуже велика.
- Ті самі правила мають застосовуватися до багатьох таблиць здобичі.
- Ви хочете перевірити
LootContext, наприклад, сутність, інструмент або джерело шкоди. - Додавання власної функції отримання здобичі до кожної таблиці було б незручним.
Список предметів, що випадають, можна безпосередньо змінювати: додавати, видаляти або змінювати стоси предметів. Зауважте: оскільки ця подія відбувається після генерації здобичі, вона не може змінювати набори, записи чи умови таблиці здобичі.
INFO
Здобич, може бути вже розділена на стоси, якщо таблиця здобичі передбачала певний розмір стосу.
Наприклад, використаймо подію MODIFY_DROPS, щоб під час руйнування блоків каменю випадало два блоки каменю замість кругляку.
java
LootTableEvents.MODIFY_DROPS.register((holder, context, drops) -> {
// Replace cobblestone drop in stone loot table with stone in the drops.
if (holder.is(Blocks.STONE.getLootTable().orElseThrow())) {
// Only replace if cobblestone is actually present, so we don't override already modified drops.
if (drops.removeIf(stack -> stack.is(Items.COBBLESTONE))) {
drops.add(new ItemStack(Items.STONE, 2));
}
}
});1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Ефект наведеного вище прикладу:
Постобробка таблиць здобичі
Використовуйте LootTableEvents.ALL_LOADED для дій, які мають виконуватися після завантаження всіх таблиць здобичі та після спрацювання подій REPLACE і MODIFY.
Подія надає ResourceManager сервера та повний реєстр таблиць здобичі. Завдяки цьому його можна використовувати для перевірки завантажених таблиць, їх валідації, збору інформації або виконання додаткового налаштування, що потребує наявності всіх таблиць.
INFO
Ця подія не використовується для додавання предметів під час генерації здобичі. Для зміни таблиці використовуйте MODIFY або REPLACE. Для зміни генерованих стосів предметів використовуйте MODIFY_DROPS.
java
LootTableEvents.ALL_LOADED.register((resourceManager, lootRegistry) -> {
Optional<LootTable> blueWoolTable = lootRegistry.getOptional(Blocks.WOOL.blue().getLootTable().orElse(null));
// Log a warning if the blue wool loot table is empty or missing.
if (blueWoolTable.isEmpty() || blueWoolTable.get() == LootTable.EMPTY) {
ExampleMod.LOGGER.warn("blue wool loot table should not be empty");
}
});1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Предикати
Умови здобичі, які всередині системи називаються предикатами, визначають, чи можна використовувати набір здобичі, запис або функцію. Вони особливо корисні в поєднанні з MODIFY та REPLACE, оскільки дозволяють зробити додавання або заміну здобичі умовними, не обробляючи кожен випадок у коді на Java. Зверніть увагу на виклики .when(...) у наведених вище прикладах MODIFY та REPLACE. Ті самі умови можуть стати в пригоді під час проєктування таблиць для заміни, тоді як MODIFY_DROPS вимагає виконання аналогічних перевірок у зворотному виклику події.
Нижче наведено приклади часто вживаних предикатів, згрупованих за їхнім призначенням. Повний перелік дивіться в пакеті net.minecraft.world.level.storage.loot.predicates та у списку предикатів на Вікі Minecraft:
Логічні предикати
Вони поєднують або інвертують інші умови.
AllOfCondition: усі умови мають бути виконані. Використовуйте це, коли вам потрібна перевірка за умовою AND.AnyOfCondition: має виконуватися принаймні одна умова. Використовуйте це, коли вам потрібна перевірка за умовою OR.InvertedLootItemCondition: інвертує іншу умову, тож вона спрацьовує лише тоді, коли початкова умова не виконується. Використовуйте це, коли вам потрібна логіка NOT.
TIP
Ці логічні предикати можна вкладати один в одного для створення складних умов. Наприклад, можна поєднати AllOfCondition і AnyOfCondition, щоб створити умову, яка вимагає успішного проходження кількох перевірок, водночас забезпечуючи певну гнучкість вимог.
Предикати стану світу
Вони перевіряють параметри навколишнього світу або місце, де генерується здобич.
WeatherCheck: перевіряє, чи йде дощ або гроза.TimeCheck: перевіряє час доби або часовий діапазон.LocationCheck: перевіряє, де саме відбулося випадіння предмета, наприклад, рівень Y або інші дані про місцеперебування.EnvironmentAttributeCheck: перевіряє правила або атрибути середовища, специфічні для світу.
Предикати блоків, інструментів та сутностей
Вони враховують зламаний блок, використовуваний інструмент або сутність, яка спричинила появу здобичі.
ExplosionCondition: забезпечує застосування набору здобичі або запису лише тоді, коли здобич витримує вибух.MatchTool: перевіряє, чи відповідає інструмент, використаний для ламання блока, заданому предмету або предикату предмета.LootItemBlockStatePropertyCondition: перевіряє стан блока до того, як його було зламано; це корисно для врожаю та інших блоків, що мають певний стан.LootItemKilledByPlayerCondition: вимагає, щоб сутність була вбита гравцем.DamageSourceCondition: перевіряє деталі щодо джерела шкоди, наприклад, чи був удар прямим або непрямим.
Предикати на основі шансу
Вони визначають випадіння на основі ймовірності або рівня зачарування.
LootItemRandomChanceCondition: визначає фіксовану випадкову ймовірність випадіння.LootItemRandomChanceWithEnchantedBonusCondition: змінює ймовірність залежно від рівня зачарування.BonusLevelTableCondition: допоміжний елемент для визначення ймовірності отримання здобичі з урахуванням рівня чарів, як-от «Удача».
WARNING
LootItemRandomChanceWithEnchantedBonusCondition і LootItemRandomChanceCondition не слід використовувати разом в одному наборі, оскільки обидві умови визначають базову ймовірність і можуть призвести до неочікуваної поведінки.
Спільні посилання на предикати
ConditionReference: вказує на умову отримання здобичі, що базується на даних, визначена в іншому місці та повторно використовується в кількох таблицях.



