🇺🇦 Українська (Ukrainian - Ukraine)
🇺🇦 Українська (Ukrainian - Ukraine)
Зовнішній вигляд
🇺🇦 Українська (Ukrainian - Ukraine)
🇺🇦 Українська (Ukrainian - Ukraine)
Зовнішній вигляд
Ця сторінка написана для версії:
1.21.4
Ця сторінка написана для версії:
1.21.4
API Fabric надає систему, яка дозволяє модам реагувати на дії або випадки, які також визначаються як події, що відбуваються в грі.
Події — це хуки, які задовольняють звичайні сценарії використання та/або забезпечують покращену сумісність і продуктивність між модами, які підключаються до тих самих областей коду. Використання подій часто замінює використання міксинів.
API Fabric надає події для важливих областей у кодовій базі Minecraft, до яких можуть бути зацікавлені кілька хуків.
Події представлені екземплярами net.fabricmc.fabric.api.event.Event
, які зберігають і викликають callbacks. Часто існує один екземпляр події для зворотного виклику, який зберігається в статичному полі EVENT
інтерфейсу зворотного виклику, але існують також інші шаблони. Наприклад, ClientTickEvents
групує кілька пов’язаних подій разом.
Зворотний виклик — це фрагмент коду, який передається як аргумент події. Коли подія ініціюється грою, переданий фрагмент коду буде виконано.
Кожна подія має відповідний інтерфейс зворотного виклику, умовно названий <EventName>Callback
. Зворотні виклики реєструються шляхом виклику методу register()
для екземпляра події з екземпляром інтерфейсу зворотного виклику як аргументу.
Усі інтерфейси зворотного виклику подій, надані Fabric API, можна знайти в пакеті net.fabricmc.fabric.api.event
.
У цьому прикладі реєструється AttackBlockCallback
, щоб завдати шкоди гравцеві, коли він потрапляє в блоки, з яких не випадає предмет під час видобутку вручну.
AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
BlockState state = world.getBlockState(pos);
// Manual spectator check is necessary because AttackBlockCallbacks fire before the spectator check
if (!player.isSpectator() && player.getMainHandStack().isEmpty() && state.isToolRequired() && world instanceof ServerWorld serverWorld) {
player.damage(serverWorld, world.getDamageSources().generic(), 1.0F);
}
return ActionResult.PASS;
});
Іноді ви можете додати предмети до таблиць здобичі. Наприклад, додавання вашої здобичі до ванілльного блоку або сутності.
Найпростіше рішення, заміна файлу таблиці здобичі, може зламати інші моди. А якщо вони захочуть змінити і їх? Ми розглянемо, як можна додавати предмети до таблиць здобичі, не перевизначаючи таблицю.
Ми додамо яйця до таблиці здобичі вугільної руди.
API Fabric має подію, яка запускається під час завантаження таблиць здобичі, LootTableEvents.MODIFY
. Ви можете зареєструвати зворотний виклик для нього в ініціалізаторі мода. Давайте також перевіримо, чи поточна таблиця здобичі є таблицею здобичі вугільної руди.
// :::2
LootTableEvents.MODIFY.register((key, tableBuilder, source, registries) -> {
// Let's only modify built-in loot tables and leave data pack loot tables untouched by checking the source.
У таблицях здобичі предмети зберігаються в записах пулу здобичі, а записи зберігаються в пулах здобичі. Щоб додати предмет, нам потрібно буде додати пул із записом предмета до таблиці здобичі.
Ми можемо створити пул за допомогою LootPool#builder
і додати його до таблиці здобичі.
Ми можемо створити пул за допомогою LootPool#builder
і додати його до таблиці здобичі.
LootTableEvents.MODIFY.register((key, tableBuilder, source, registries) -> {
// Let's only modify built-in loot tables and leave data pack loot tables untouched by checking the source.
// We also check that the loot table ID is equal to the ID we want.
if (source.isBuiltin() && COAL_ORE_LOOT_TABLE_ID.equals(key)) {
// We make the pool and add an item
LootPool.Builder poolBuilder = LootPool.builder().with(ItemEntry.builder(Items.EGG));
tableBuilder.pool(poolBuilder);
}
});
Деякі області гри не мають хуків, наданих Fabric API, тому ви можете використовувати міксин або створити власну подію.
Ми розглянемо створення події, яка запускається, коли вівцю стрижуть. Процес створення події:
Інтерфейс зворотного виклику описує, що має бути реалізоване слухачами подій, які слухатимуть вашу подію. Інтерфейс зворотного виклику також описує, як подія буде викликана з нашого міксину. Традиційно розміщувати об’єкт Event
як поле в інтерфейсі зворотного виклику, яке ідентифікуватиме нашу фактичну подію.
Для нашої реалізації Event
ми виберемо використання події на основі масиву. Масив міститиме всі слухачі подій, які прослуховують подію.
Наша реалізація буде викликати слухачі подій по порядку, доки один із них не поверне ActionResult.PASS
. Це означає, що слухач може сказати «скасувати це», «затвердити це» або «не хвилюйтеся, залиште це наступному слухачу події», використовуючи його значення, що повертається.
Використання ActionResult
як значення, що повертається, є звичайним способом змусити обробники подій співпрацювати таким чином.
Вам потрібно буде створити інтерфейс, який має екземпляр Event
і метод для реалізації відповіді. Основні налаштування для зворотного виклику стрижки овець:
public interface SheepShearCallback {
Event<SheepShearCallback> EVENT = EventFactory.createArrayBacked(SheepShearCallback.class,
(listeners) -> (player, sheep) -> {
for (SheepShearCallback listener : listeners) {
ActionResult result = listener.interact(player, sheep);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
});
ActionResult interact(PlayerEntity player, SheepEntity sheep);
}
Розгляньмо це глибше. Коли виклик викликається, ми повторюємо всі слухачі:
(listeners) -> (player, sheep) -> {
for (SheepShearCallback listener : listeners) {
Потім ми викликаємо наш метод (у цьому випадку interact
) для слухача, щоб отримати його відповідь:
ActionResult interact(PlayerEntity player, SheepEntity sheep);
Якщо слухач каже, що ми повинні скасувати (ActionResult.FAIL
) або повністю завершити (ActionResult.SUCCESS
), функція зворотного виклику повертає результат і завершує цикл. ActionResult.PASS
переходить до наступного слухача, і в більшості випадків має завершуватися успішно, якщо більше не зареєстровано слухачів:
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
Ми можемо додати коментарі Javadoc у верхній частині класів зворотного виклику, щоб документувати, що робить кожен ActionResult
. У нашому випадку це може бути:
/**
* Callback for shearing a sheep.
* Called before the sheep is sheared, items are dropped, and items are damaged.
* Upon return:
* - SUCCESS cancels further processing and continues with normal shearing behavior.
* - PASS falls back to further processing and defaults to SUCCESS if no other listeners are available
* - FAIL cancels further processing and does not shear the sheep.
*/
Тепер у нас є основна структура подій, але нам потрібно його запустити. Оскільки ми хочемо, щоб подія викликалася, коли гравець намагається підстригти вівцю, ми викликаємо подію invoker
у SheepEntity#interactMob
, коли викликається sheared()
(тобто вівцю можна стригти, якщо гравець тримає ножиці):
@Mixin(SheepEntity.class)
public class SheepEntityMixin {
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/passive/SheepEntity;sheared(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/sound/SoundCategory;Lnet/minecraft/item/ItemStack;)V"), method = "interactMob", cancellable = true)
private void onShear(final PlayerEntity player, final Hand hand, final CallbackInfoReturnable<ActionResult> info) {
ActionResult result = SheepShearCallback.EVENT.invoker().interact(player, (SheepEntity) (Object) this);
if (result == ActionResult.FAIL) {
info.setReturnValue(result);
}
}
}
Тепер нам потрібно перевірити нашу подію. Ви можете зареєструвати слухача у своєму методі ініціалізації (або в іншій області, якщо хочете) і додати туди спеціальну логіку. Ось приклад, коли замість вовни випадає діамант:
SheepShearCallback.EVENT.register((player, sheep) -> {
sheep.setSheared(true);
// Create diamond item entity at sheep's position.
ItemStack stack = new ItemStack(Items.DIAMOND);
ItemEntity itemEntity = new ItemEntity(player.getWorld(), sheep.getX(), sheep.getY(), sheep.getZ(), stack);
player.getWorld().spawnEntity(itemEntity);
return ActionResult.FAIL;
});
Якщо ви входите в гру і стрижете вівцю, замість вовни повинен випасти діамант.