Отладка модов (Debugging Mods) 26.1.2
Описание: Узнай всё об использовании логов, точек останова и других полезных инструментов для отладки.
В программировании даже самые опытные разработчики сталкиваются с ошибками, багами и неточностями.
Это руководство описывает общие шаги, которые помогут тебе находить и исправлять проблемы — даже без помощи других. Решая проблемы самостоятельно, ты не только многому научишься, но и получишь удовлетворение от результата.
Однако если ты застрял и не можешь найти решение — не стесняйся просить помощи!
Консоль и LOGGER
Самый простой и быстрый способ найти проблему — использовать логирование в консоль.
Во время работы программы можно выводить значения переменных, чтобы понимать текущее состояние кода и проще находить ошибки.
Вы можете создать логгер с помощью LoggerFactory, передав туда имя для отображения в логе рядом с выводимыми сообщениями:
java
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);1
TIP
Инициализатор в шаблонном моде уже содержит в себе логгер по умолчанию, использующий идентификатор вашего мода.
Когда нужно узнать значение переменной в определённом месте кода — используй LOGGER, передав в метод строку с нужной информацией.
java
ExampleMod.LOGGER.info("You interacted with an entity!");1
Логгер может выводить сообщения в консоль в разных режимах. Цвет строки в консоли зависит от того, какой режим логгера используется.
java
ExampleMod.LOGGER.debug("Debug message for development...");
ExampleMod.LOGGER.info("Neutral, informative text...");
ExampleMod.LOGGER.warn("Non-critical issues...");
ExampleMod.LOGGER.error("Critical exceptions, bugs..."); 1
2
3
4
2
3
4
INFO
Все режимы логгера поддерживают несколько перегрузок методов — можно, например, передавать стек вызовов (stack trace).
Например, добавим вывод состояния в консоль, когда TestItem используется на существе:
java
@Override
public InteractionResult interactLivingEntity(ItemStack stack, Player user, LivingEntity entity, InteractionHand hand) {
Level level = user.level();
// Extra parameters will be interpolated into the format string
ExampleMod.LOGGER.info(
"Is Client World: {} | Health: {} / {} | The item was used with the {}",
level.isClientSide(), entity.getHealth(), entity.getMaxHealth(), hand
);
if (!level.isClientSide()) {
// you can log non-critical issues differently as a warning
ExampleMod.LOGGER.warn("Don't touch that!");
// The LOGGER can print the Stacktrace too in addition to the logging message
if (stack.getCount() > 1) {
IllegalArgumentException exception = new IllegalArgumentException("Only one item is allowed");
ExampleMod.LOGGER.error("Error while interacting with an entity", exception);
throw exception;
}
}
return InteractionResult.SUCCESS;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

В зарегистрированной строке вы можете найти:
- Time — время, когда сообщение было выведено
Thread— поток, в котором было выполнено печатание. Часто в логах встречаются потоки render thread; и render thread — они указывают, на какой стороне (серверной или клиентской) выполнялся кодName— имя регистратора. Лучше всего использовать здесь свой ID мода, чтобы в журналах и отчетах об ошибках отображалось, какой мод был зарегистрирован- Message — краткое, но понятное сообщение Включите соответствующие значения или контекст
- Stack Trace — стек вызовов, если лог содержит исключение
Поддержание чистоты консоли
Имей в виду: всё, что ты логируешь, также выводится в других средах, где используется мод.
Чтобы ваш мод не засорял файлы логов, выберите подходящий уровень логирования. Если записываемые данные важны только во время разработки, настоятельно рекомендуется использовать уровень debug.
WARNING
Уровень debug скрыт по умолчанию. О том, как включить его отображение во время разработки, cм. ниже в разделе «Debug логирование».
Если вы до сих пор не уверены, какой уровень логирования выбрать, то лучше использовать уровни, отличные от debug, только в случае возникновения каких-либо проблем. Игроков и разработчиков сборок не интересует, например, инициализация предметов — но важно знать, если, например, датапак не загрузился.
Debug логирование
Уровень логирования debug скрыт по умолчанию, но его можно специально включить в среде разработки с помощью определенной конфигурации.
Для этого создайте конфигурационный файл log4j-dev.xml в корневом каталоге проекта и добавьте в него следующее содержимое. Обязательно замените значение атрибута name на ваш modid. Эта конфигурация позволит выводить debug-логи твоего мода в консоль.
xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Loggers>
<Logger name="example-mod" level="debug" additivity="false">
<AppenderRef ref="SysOut"/>
<AppenderRef ref="ServerGuiConsole"/>
</Logger>
</Loggers>
</Configuration>1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Затем в файле build.gradle укажите Loom использовать нашу новую конфигурацию.
gradle
loom.log4jConfigs.from "log4j-dev.xml"1
Теперь, когда мы будем отправлять отладочные сообщения, мы сможем видеть их в консоли.
java
ExampleMod.LOGGER.debug("Debug logging is enabled");1

TIP
Если debug-сообщения по-прежнему не видны, возможно, конфигурации запуска устарели. Чтобы исправить это, сгенерируйте их заново с помощью Gradle-таски.
Поиск ошибок
Логгер выводит ID вашего мода перед строкой. Вы можете выполнить поиск (⌘/CTRL+F), чтобы выделить его.
Отсутствующие ресурсы и текстуры (фиолетово-чёрная заглушка) тоже создают предупреждение в консоли с указанием недостающего пути.


Name — имя логгера (рекомендуется использовать ID мода)
Точки останова (Breakpoints)
Более продвинутый способ отладки — использование точек останова (breakpoints) в IDE. Они позволяют приостановить выполнение кода в нужной строке и изучить текущее состояние программы.
TIP
Чтобы использовать точки останова, запускай игру в режиме Debug, а не Run.

Давайте снова воспользуемся нашим пользовательским элементом в качестве примера. Рассмотрим пример: предмет должен менять своё имя (CUSTOM_NAME) при использовании на блоке камня, но этого не происходит. Однако в этом примере предмет всегда вызывает анимацию руки «успех», но название «булыжник» не меняется.
Как мы можем решить эти две проблемы? Давайте рассмотрим...
java
// problematic example code:
public class TestItem extends Item {
public TestItem(Properties properties) {
super(properties);
}
@Override
public InteractionResult useOn(UseOnContext context) {
Level level = context.getLevel();
Player user = context.getPlayer();
BlockPos targetPos = context.getBlockPos();
ItemStack itemStack = context.getItemInHand();
BlockState state = level.getBlockState(targetPos);
if (state.is(ConventionalBlockTags.STONES)) {
Component newName = Component.literal("[").append(state.getBlock().getName()).append(Component.literal("]"));
itemStack.set(DataComponents.CUSTOM_NAME, newName);
if (user != null) {
user.displayClientMessage(Component.literal("Changed Item Name"), true);
}
}
return InteractionResult.SUCCESS;
}
}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
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
Поставь точку останова, кликнув по номеру строки. При необходимости можно разместить сразу несколько. Выполнение кода остановится непосредственно перед выбранной строкой.

Затем позвольте запущенному экземпляру Minecraft выполнить эту часть кода. Вы также можете устанавливать точки останова во время игры.
В этом случае пользовательский элемент необходимо использовать в блоке. Когда выполнение дойдёт до неё, Minecraft замёрзнет, а в IntelliJ появится стрелка, указывающая место остановки.
В нижней части экрана откроется окно Debug, где автоматически будет выбрана вкладка Threads & Variables. В окне Debug стрелками можно пошагово управлять выполнением кода. Такой способ перемещения по коду называется «stepping» — пошаговое выполнение.

| Действие | Тип данных |
|---|---|
| Шаг с обходом | Переходит к следующей строке кода, продолжая выполнение программы |
| Шаг с заходом | Позволяет зайти внутрь метода и посмотреть, что происходит внутри. Если в строке несколько методов, можно выбрать нужный кликом мыши. Этот способ также используется для перехода внутрь лямбда-функций. |
| Выполнить до курсора | Продолжает выполнение по коду до позиции курсора. Это полезно, чтобы пропустить большие участки кода. |
| Показать точку выполнения | Перемещает отображение окна кода к тому месту, где в данный момент находится отладчик. Это работает даже тогда, когда вы находитесь в других файлах или вкладках. |
INFO
Действия «Шаг с обходом» F8 и «Шаг с заходом» F7 являются наиболее распространенными, поэтому постарайтесь привыкнуть к этим сочетаниям клавиш!
Если вы закончили текущую проверку, вы можете нажать зеленую кнопку «Возобновить программу» (F9). После этого Minecraft «разморозится», и можно будет продолжить тестирование, пока не будет достигнута следующая точка останова. Но пока давайте продолжим смотреть на окно Debug.
В верхней части вы можете увидеть все запущенные в данный момент экземпляры. Если оба работают, вы можете переключаться между клиентом и серверным экземпляром. Ниже находятся действия и элементы управления отладки. Вы также можете переключиться в режим просмотра Console, если вам нужно посмотреть журналы.
Слева вы можете увидеть активную в данный момент ветку, а под ней — трассировку стека.
Справа вы можете просматривать и изменять загруженные значения и объекты. Вы также можете навести курсор на значения в коде: если они находятся в области видимости и все еще загружены, во всплывающем окне также будут отображены их конкретные значения.
Если вас интересует содержание конкретного объекта, вы можете воспользоваться маленьким значком стрелки рядом с ним. Это развернет все вложенные данные.
Значения явно не загружаются, если точка выполнения не прошла мимо них или если они находятся в совершенно другом контексте.
Обратись к сообществу
Вы можете использовать строку ввода в окне Debug для многих различных целей, например, для доступа к загруженным объектам и использования методов для работы с ними. Это добавит новую запись ниже, показывающую запрошенные данные.
Во время выполнения программы можно выводить значения переменных в консоль, чтобы понимать текущее состояние кода и анализировать поведение или ошибки.
Давайте перейдем к нашему примеру, чтобы загрузить переменную BlockState. Теперь мы можем проверить, действительно ли BlockState целевого блока находится в теге Block.
TIP
Нажмите значок «+» справа от строки ввода, чтобы закрепить результат для текущей сессии отладки.

Как мы видим, тег ConventionalBlockTags.STONES не включает булыжник, поскольку для него существует отдельный тег.
Условные точки останова
Иногда нужно приостанавливать код только при определённом условии. Для этого создайте точку останова и щелкните по ней ПКМ, чтобы открыть ее настройки. В этом окне можно указать условие в виде логического выражения.
Пустые иконки точек останова показывают, что они неактивны — такие точки не приостанавливают работу Minecraft. Включить или отключить точку останова можно в её настройках или просто кликнув по ней средней кнопкой мыши.
Все точки останова отображаются в окне Bookmarks IntelliJ.

Откроется окно Debug, где можно смотреть потоки, переменные, и управлять выполнением (пошагово, вход в методы и т.п.).
Горячая замена кода (Hotswapping)
Можно вносить ограниченные изменения в код во время работы экземпляра программы, используя действие Build > Build Project (значок с молотком). Вы также можете поместить значок рядом с раскрывающимся элементом «Run Configuration» (Запуск конфигурации), щелкнув правой кнопкой мыши по пустому месту в верхней строке меню IntelliJ.

Этот процесс, также называемый «горячей заменой», требует запуска экземпляра Minecraft в режиме Debug вместо режима Run (см. выше).
При этом вам не нужно заново перезапускать экземпляр Minecraft. Это также ускоряет тестирование выравнивания элементов экрана и других функций балансировки. IntelliJ уведомит вас, если «горячая замена» прошла успешно.

Миксины являются исключением. Вы можете настроить конфигурацию запуска, чтобы они могли изменяться и во время выполнения. Для получения дополнительной информации см. Hotswapping Mixins.
Другие изменения можно перезагрузить в игре.
- изменения в папке
assets/-> нажмите F3+T - изменения в папке
data/-> используйте команду/reload
Чтобы завершить пример из предыдущего раздела, добавим условие к оператору. Как только мы достигаем точки останова, мы видим, что всегда получаем анимацию руки «успех», потому что мы никогда не возвращали ничего другого.
Примените исправления и воспользуйтесь функцией «горячей» замены, чтобы сразу увидеть изменения в игре.
java
@Override
public InteractionResult useOn(UseOnContext context) {
Level level = context.getLevel();
Player user = context.getPlayer();
BlockPos targetPos = context.getClickedPos();
ItemStack itemStack = context.getItemInHand();
BlockState state = level.getBlockState(targetPos);
if (state.is(ConventionalBlockTags.STONES) || state.is(ConventionalBlockTags.COBBLESTONES)) {
Component newName = Component.literal("[").append(state.getBlock().getName()).append(Component.literal("]"));
itemStack.set(DataComponents.CUSTOM_NAME, newName);
if (user != null) {
user.sendOverlayMessage(Component.literal("Changed Item Name"));
}
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Логи и краши
Консоли ранее выполненных экземпляров экспортируются в виде файлов журналов, расположенных в каталоге logs экземпляра Minecraft. Новейший журнал обычно называется latest.log.
Пользователи смогут поделиться этим файлом с разработчиком мода для дальнейшей проверки, как описано в разделе Загрузка журналов.
В среде разработки предыдущие журналы можно найти в папке «run > logs» окна «Project», а отчеты о сбоях — в папке «run > crash-reports».
Спросите сообщество!
Все еще не можете понять, что происходит? Вы можете присоединиться к Fabric Discord Server и пообщаться с сообществом!
Также можно заглянуть на официальную вики Fabric (https://wiki.fabricmc.net/start) для более продвинутых тем.



