Обработка событий в Fabric: руководство

published on 30 September 2024

Хотите создавать крутые моды для Minecraft? Fabric - ваш лучший выбор. Вот что нужно знать об обработке событий:

  • События позволяют модам реагировать на действия в игре
  • Fabric API предоставляет множество готовых событий
  • Можно создавать собственные события
  • Правильная обработка событий - ключ к стабильной работе мода

Основные типы событий:

  • Игрока (смерть, вход на сервер)
  • Блоков (размещение, разрушение)
  • Сущностей (спавн, трансформация)
  • Мира (тики)

Для работы с событиями:

  1. Настройте проект Fabric
  2. Создайте обработчики событий
  3. Зарегистрируйте их в главном классе мода

Пример обработчика:

AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
    if (world.getBlockState(pos).isToolRequired() && player.getMainHandStack().isEmpty()) {
        player.damage(DamageSource.GENERIC, 1.0F);
    }
    return ActionResult.PASS;
});

Этот код наносит урон игроку при попытке сломать блок голыми руками.

Используйте события Fabric для создания эффективных и совместимых модов!

Перед началом работы

Что вам понадобится

Для работы с событиями в Fabric:

  • Java Development Kit (JDK): Java 21+ для Minecraft 1.20.5+, Java 17+ для 1.18+, Java 8+ для старых версий. Скачайте на Adoptium или jdk.java.net.

  • IDE: IntelliJ IDEA с плагином Minecraft Development - лучший выбор.

  • Fabric Loader и API: Основа для создания модов.

Настройка проекта

1. Установка

Скачайте и установите JDK и IntelliJ IDEA.

2. Создание проекта

Два варианта:

  • Копируйте шаблон из fabric-example-mod
  • Используйте генератор в IntelliJ IDEA с плагином Minecraft Development

3. Настройка

Измените:

  • gradle.properties: свойства мода
  • fabric.mod.json: зависимости

4. Проверка

Запустите:

./gradlew runClient

Minecraft должен запуститься без проблем.

"События часто заменяют миксины." - Fabric Wiki

Fabric API не обязателен, но очень полезен для совместимости модов.

Как работают события в Fabric?

Fabric

События в Fabric - это способ для модов реагировать на происходящее в игре. Представьте, что это система оповещений для вашего мода.

Что такое эти события?

По сути, события Fabric - это обратные вызовы. Они позволяют вашему моду "подписаться" на определенные действия в игре.

Каждое событие - это экземпляр класса Event из Fabric API. Этот класс отвечает за хранение и вызов обратных вызовов.

Какие бывают события?

Fabric API предлагает много разных событий:

Тип Что это?
Клиентские Всё, что происходит на стороне клиента
Серверные То, что творится на сервере
Жизненного цикла Запуск и остановка игры или сервера
Игрока Действия игрока (атака, использование предметов)

Вот несколько конкретных примеров:

  • AttackBlockCallback: Срабатывает при ударе по блоку
  • UseItemCallback: Когда игрок использует предмет
  • PlayerBlockBreakEvents: Группа событий о разрушении блоков

Как это работает на практике?

  1. Ваш мод регистрирует обратный вызов для нужного события.
  2. Когда что-то происходит в игре, Fabric API вызывает все зарегистрированные обратные вызовы.
  3. Код вашего мода реагирует на событие.

Вот пример кода:

AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
    BlockState state = world.getBlockState(pos);
    if (!player.isSpectator() && player.getMainHandStack().isEmpty() && state.isToolRequired()) {
        player.damage(world.getDamageSources().generic(), 1.0F);
    }
    return ActionResult.PASS;
});

Этот код наказывает игрока уроном, если он бьет голыми руками по блоку, требующему инструмент.

События Fabric часто проще и надежнее, чем использование миксинов для изменения игры.

Настройка мода

Чтобы работать с событиями Fabric, нужно правильно настроить мод. Вот как это сделать:

Файловая структура

Типичная структура Fabric-мода:

src/
  main/
    java/         # Код
    resources/    # Ресурсы и конфиги
      assets/
      data/
      fabric.mod.json

Главное:

  • java/: весь код
  • resources/: ресурсы и конфиги
  • fabric.mod.json: метаданные мода

Настройка fabric.mod.json

Этот файл - сердце мода. Пример:

{
  "schemaVersion": 1,
  "id": "myeventmod",
  "version": "1.0.0",
  "name": "Мой обработчик событий",
  "description": "Обработка событий в Minecraft",
  "authors": ["Я"],
  "contact": {
    "homepage": "https://example.com/",
    "sources": "https://github.com/me/myeventmod"
  },
  "license": "MIT",
  "icon": "assets/myeventmod/icon.png",
  "environment": "*",
  "entrypoints": {
    "main": ["com.example.myeventmod.MyMod"]
  },
  "depends": {
    "fabricloader": ">=0.14.21",
    "minecraft": "~1.20.1",
    "java": ">=17"
  }
}

Ключевые моменты:

  • id: уникальный идентификатор (2-64 символа)
  • version: версия мода
  • entrypoints: главные классы
  • depends: зависимости (версии Fabric, Minecraft, Java)

Что нужно сделать:

  1. Поменять id и name
  2. Указать версию
  3. Обновить entrypoints
  4. Проверить depends

Правильная настройка этого файла - залог успешной работы с событиями Fabric.

Добавление обработчиков событий

Чтобы мод реагировал на события в игре, нужны обработчики событий. Вот как их добавить:

Создание обработчика

  1. Новый класс для обработки событий
  2. Аннотация @EventBusSubscriber к классу
  3. Статические методы для каждого типа события
  4. Аннотация @SubscribeEvent к методам

Пример:

@EventBusSubscriber
public class МойОбработчик {
    @SubscribeEvent(priority = EventPriority.NORMAL, receiveCanceled = true)
    public static void onEvent(EntityConstructing event) {
        // Код обработки
    }
}

Подключение к Fabric

Используйте register() для нужного события:

public class МойМод implements ModInitializer {
    @Override
    public void onInitialize() {
        AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
            BlockState state = world.getBlockState(pos);
            if (state.isToolRequired() && !player.isSpectator() && player.getMainHandStack().isEmpty()) {
                player.damage(DamageSource.field_5869, 1.0F);
            }
            return ActionResult.PASS;
        });
    }
}

Этот код регистрирует обработчик для AttackBlockCallback. Он проверяет, нужен ли инструмент для блока, и бьет игрока, если тот пытается сломать блок голыми руками.

Событие Описание Пример
AttackBlockCallback При атаке блока Изменение разрушения блоков
UseBlockCallback При использовании блока Новые действия с блоками
UseItemCallback При использовании предмета Предметы с особыми эффектами

Важно:

  • EventPriority управляет порядком обработчиков
  • receiveCanceled=true для отмененных событий
  • ActionResult.PASS продолжает обработку другими модами

Грамотное использование обработчиков позволит моду эффективно влиять на игру и взаимодействовать с другими модами.

Распространенные типы событий

Fabric предлагает множество событий для модификации игры. Давайте рассмотрим самые популярные:

События игрока

Эти события реагируют на действия игрока:

Событие Описание Применение
death Смерть игрока Новое сообщение о смерти
join Вход на сервер Приветствие
kill_entity Убийство сущности Награда за определенных мобов
leave Выход с сервера Сохранение данных

События блоков

Изменяют поведение блоков:

  • Before Player Place: До размещения блока
  • Entity Fall On: Падение сущности на блок
  • Player Destroy: Разрушение блока игроком

Пример обработки разрушения блока:

void afterBlockBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, BlockEntity blockEntity) {
    // Код обработки
}

События сущностей

Реагируют на действия мобов и объектов:

  • Entity Spawned: Появление сущности
  • Entity Transformed: Трансформация сущности

Пример пользовательского события:

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);
}

События мира

Реагируют на изменения в игровом мире:

  • Random Tick: Случайный тик (рост растений)
  • Tick: Регулярный тик

"PlayerTick жрет в 2-6 раз больше CPU, чем нужно." - 4HeadTiger, мод-разработчик

Помните о производительности при использовании событий. PlayerTick может вызываться несколько раз за тик, что увеличивает нагрузку на CPU.

sbb-itb-b1cf51d

Написание обработчиков событий

Обработка событий - ключевая часть разработки модов для Fabric. Давайте разберемся, как создавать и использовать обработчики событий эффективно.

Создание пользовательского обработчика

Чтобы сделать свой обработчик событий в Fabric:

1. Создайте интерфейс обратного вызова:

public interface СтрижкаОвецCallback {
    Event<СтрижкаОвецCallback> EVENT = EventFactory.createArrayBacked(СтрижкаОвецCallback.class,
        (listeners) -> (player, sheep) -> {
            for (СтрижкаОвецCallback listener : listeners) {
                ActionResult result = listener.interact(player, sheep);
                if(result != ActionResult.PASS) {
                    return result;
                }
            }
            return ActionResult.PASS;
        });
    ActionResult interact(PlayerEntity player, SheepEntity sheep);
}

2. Вызовите событие из Mixin:

@Mixin(SheepEntity.class)
public class SheepShearMixin {
    @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/passive/SheepEntity;dropItems()V"), method = "interactMob", cancellable = true)
    private void onShear(final PlayerEntity player, final Hand hand, final CallbackInfoReturnable<Boolean> info) {
        ActionResult result = СтрижкаОвецCallback.EVENT.invoker().interact(player, (SheepEntity) (Object) this);
        if(result == ActionResult.FAIL) {
            info.cancel();
        }
    }
}

3. Реализуйте и зарегистрируйте обработчик:

СтрижкаОвецCallback.EVENT.register((player, sheep) -> {
    sheep.setSheared(true);
    ItemStack stack = new ItemStack(Items.DIAMOND);
    ItemEntity itemEntity = new ItemEntity(player.world, sheep.x, sheep.y, sheep.z, stack);
    player.world.spawnEntity(itemEntity);
    return ActionResult.FAIL;
});

Советы по обработке событий

  • Используйте ActionResult для управления потоком событий.
  • Не забудьте зарегистрировать Mixin в mixins.json.
  • Возвращайте ActionResult.PASS, если не хотите прерывать цепочку событий.
  • Оптимизируйте код для частых событий.

Пример оптимизированного обработчика:

AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
    BlockState state = world.getBlockState(pos);
    if (state.isToolRequired() && !player.isSpectator() && player.getMainHandStack().isEmpty()) {
        player.damage(DamageSource.field_5869, 1.0F);
    } 
    return ActionResult.PASS;
});

Этот код проверяет условия до выполнения действий, экономя ресурсы.

Продвинутые техники работы с событиями

Создание собственных событий

Иногда стандартных событий Fabric API мало. Вот как создать свое:

1. Создайте интерфейс обратного вызова:

public interface СобытиеСтрижкиОвец {
    Event<СобытиеСтрижкиОвец> EVENT = EventFactory.createArrayBacked(СобытиеСтрижкиОвец.class,
        (listeners) -> (игрок, овца) -> {
            for (СобытиеСтрижкиОвец listener : listeners) {
                ActionResult результат = listener.обработать(игрок, овца);
                if(результат != ActionResult.PASS) {
                    return результат;
                }
            }
            return ActionResult.PASS;
        });
    ActionResult обработать(PlayerEntity игрок, SheepEntity овца);
}

2. Вызовите событие из Mixin:

@Mixin(SheepEntity.class)
public class MixinСтрижкиОвец {
    @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/passive/SheepEntity;sheared(Lnet/minecraft/sound/SoundCategory;)V"), method = "interactMob", cancellable = true)
    private void приСтрижке(PlayerEntity игрок, Hand рука, CallbackInfoReturnable<ActionResult> инфо) {
        ActionResult результат = СобытиеСтрижкиОвец.EVENT.invoker().обработать(игрок, (SheepEntity) (Object) this);
        if(результат == ActionResult.FAIL) {
            инфо.setReturnValue(результат);
        }
    }
}

3. Зарегистрируйте обработчик:

СобытиеСтрижкиОвец.EVENT.register((игрок, овца) -> {
    овца.setSheared(true);
    ItemStack алмаз = new ItemStack(Items.DIAMOND);
    ItemEntity предмет = new ItemEntity(игрок.getWorld(), овца.getX(), овца.getY(), овца.getZ(), алмаз);
    игрок.getWorld().spawnEntity(предмет);
    return ActionResult.FAIL;
});

Этот код создает событие стрижки овец, выдающее алмаз вместо шерсти.

Приоритеты и отмена событий

В Fabric API можно управлять порядком обработчиков и отменять события:

  • ActionResult.FAIL отменяет событие
  • ActionResult.PASS позволяет другим обработчикам выполниться
  • Порядок регистрации влияет на приоритет

Пример:

// Высокий приоритет
СобытиеСтрижкиОвец.EVENT.register((игрок, овца) -> {
    System.out.println("Высокий приоритет");
    return ActionResult.PASS;
});

// Низкий приоритет
СобытиеСтрижкиОвец.EVENT.register((игрок, овца) -> {
    System.out.println("Низкий приоритет");
    return ActionResult.FAIL; // Отменяет событие
});

Здесь обработчик с высоким приоритетом выполнится первым, но событие отменится обработчиком с низким приоритетом.

Осторожно с отменой событий - это может конфликтовать с другими модами.

Исправление проблем с обработчиками событий

Работа с событиями в Fabric может быть непростой. Давайте разберем частые проблемы и их решения.

NullPointerException

Эта ошибка появляется, когда вы пытаетесь использовать null-объект:

Error: java.lang.NullPointerException: Cannot invoke 'me.shedaniel.rei.impl.common.entry.type.EntryRegistryList.needsHash()' because 'this.registryList' is null.

Как исправить? Проверяйте объекты на null:

if (this.registryList != null) {
    this.registryList.needsHash();
}

Клиент-серверная синхронизация

Некоторые события работают только на клиенте или сервере. Используйте правильные события:

  • Для клиента:
ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> {
    // Ваш код
});
  • Для сервера:
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
    // Ваш код
});

Краш при отключении от сервера

Проверьте версии модов и библиотек. Иногда проблема решается обновлением CreativeCore для Fabric.

Отладка

  1. Логи: Добавьте логирование в обработчики:
FabricLoader.getInstance().getLogger().info("Событие X: " + параметры);
  1. Отчеты о крашах: Изучайте их внимательно - там много полезной информации.

  2. Отладчик IDE: Используйте для пошагового выполнения кода.

  3. Профилировщик: Для проблем с производительностью попробуйте VisualVM или встроенный профилировщик Minecraft (F3 + L).

Помните, отладка в Minecraft может быть сложной из-за многопоточности и разделения на клиент и сервер. Будьте терпеливы и методичны.

Ускорение обработки событий

Хотите, чтобы ваш мод Fabric летал? Давайте разберемся, как ускорить обработку событий и избежать тормозов.

Быстрее, выше, сильнее

Уменьшите дистанцию прорисовки. 10 чанков - золотая середина между FPS и геймплеем.

Настройки видео - ваш друг:

Настройка Что делаем
Графика Быстрая
Облака Долой
Частицы Минимум
Тени сущностей Выключаем

Предварительная генерация чанков - ваш щит от лагов при быстром перемещении.

Избегайте "тяжелых" мест. Сложные структуры и толпы мобов - враги производительности.

Нет тормозам!

Сеть на максимум:

  • Проводное подключение - ваш выбор
  • Закройте "прожорливые" приложения
  • QoS для игрового трафика
  • Обновите прошивку роутера

Фоновые процессы под контроль:

  • Никаких неожиданных обновлений
  • Остановите загрузки на других устройствах

Умные игровые механики:

  • Выключатели для ферм мобов
  • Не усложняйте механизмы в одном месте

Примените эти советы, и ваш мод Fabric будет работать как часы!

Подведение итогов

Давайте вспомним главное об обработке событий в Fabric:

  • Fabric API использует инъекции, не меняя классы напрямую
  • При создании ресурс-паков или дата-паков важна правильная структура папок
  • Система событий Fabric позволяет модам реагировать на игровые события

Советы

Не используйте java.awt или javax.swing - они могут подвесить Minecraft.

Для пользовательских полей или методов:

  • Добавляйте префикс "[modid]$"
  • Используйте аннотацию @Unique

При работе с сетью обрабатывайте пакеты в сетевом потоке, а остальное - в основном потоке.

Дополнительные ресурсы

Чтобы узнать больше:

  • Изучите официальную документацию Fabric
  • Посетите форумы Fabric
  • Загляните в GitHub репозиторий Fabric

Используя эти знания, вы сможете создавать эффективные моды для Minecraft на Fabric.

Related posts

Read more

Built on Unicorn Platform