Причины Событий

События великолепно подходят для добавления дополнительной логики в действия игры, однако также у них есть механизм для получения причины по которой событие случилось. Объект Cause позволяет предоставлять и получать дополнительную информацию о событии. Эта информации может быть использована для изменения поведения вашего слушателя.

К примеру, плагин для защиты мира требует для работы информацию, какой игрок вызвал ChangeBlockEvent для того чтобы решить, нужно ли отменять событие. Вместо создания большего количество дочерних событий для различных исходных данных, вся информации уже помещена в Cause события.

Каждое событие предоставляет объект Cause для получения информации из-за чего событие было вызвано. Объект Cause может быть получен с любого события вызовом метода Event#getCause().

Получения объектов из Cause

Структурно, объект Cause содержит последовательный список объектов. Есть несколько способов получения нужной информации из Cause которые мы здесь и обсудим, для более подробной информации смотрите javadocs.

Примечание

Объекты внутри Cause построены так, что первый объект является наиболее важной причиной события, последующие объекты отсортированы в порядке сокращения важности и/или предоставляют контекстную информацию.

Cause#root() возвращает первый объект внутри Cause. Этот объект является самой важной причиной вызова события. Поскольку Cause`не может быть пустым, это гарантирует наличие ``root.

:javadoc:“Cause#First(class)“ возвращает первый объект в цепочке причин, тип которого либо совпадает или является подтипом данного класса. Пример Cause, которая содержит игрока и последующую сущность ``[Player, Entity,…] ``

@Listener
public void onEvent(ExampleCauseEvent event) {
    Cause cause = event.getCause(); // [Player, Entity]
    Optional<Player> firstPlayer = cause.first(Player.class); // 1
    Optional<Entity> firstEntity = cause.first(Entity.class); // 2
}

Оба варианты будут содержать объект игрока, так как его класс подходит для обоих вариантов, из-за того что класс Player унаследован от класса Entity.

Cause#last(Class) подобен методу Cause#first(Class) за исключением того, что этот метод возвращает последнее значение соответствующего типа(Class).

Продолжая пример сверху, в случае если мы сменим метод Cause#first(Class) на Cause#last(Class) первый объект все так-же будет игроком, а вот второй объект уже будет той-самой сущностью что хранится второй в Cause.

Cause#containsType(Class) возвращает логическое значение которое может быть использовано для проверки, содержит ли Cause объект нужного типа.

Cause#all() возвращает все объекты из Cause для более расширенной обработки.

Именованные причины

Иногда порядка объектов внутри cause недостаточно, чтобы получить правильное представление о том, что объект представляет по отношению к событию. Вот где это возможно: NamedCause. Именованные причины предоставляют метод для пометки объектов внутри cause с ** уникальным ** именем, позволяющим их легко идентифицировать и запросить. Некоторыми примерами использования для именованных причин является Notifier :javadoc: ChangeBlockEvent.Grow или Source DamageEntityEvent.

Получение именованной записи из cause

@Listener
public void onGrow(ChangeBlockEvent.Grow event) {
    Optional<Player> notifier = event.getCause().get(NamedCause.NOTIFIER, Player.class);
}

В этом примере используется метод Cause#get(String, Class<T>), который может использоваться для извлечения ожидаемого объекта, связанного с именем, если он присутствует в цепочке причин. Кроме того Cause#getNamedCauses() предоставляет Map<String, Object>, который можно использовать для поиска всех существующих имен и связанных с ними объектов.

Примечание

Некоторые общие идентификационные имена для NamedCauses присутствуют как статические поля в классе NamedCause. Идентификаторы, специфичные для определенных событий, часто можно найти как статические поля в классе событий, например DamageEntityEvent#SOURCE.

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

Создание cause для использования при запуске события чрезвычайно просто. Самая сложная часть - решить, какую информацию включить в cause. Если вы запускаете событие из своего плагина, которое обычно запускается с помощью других средств, возможно, вы хотите включить свой плагин-контейнер, чтобы другие плагины знали, что это событие происходит из вашего плагина. Или, если вы запускаете событие от имени игрока из-за какого-либо действия, то хорошей идеей будет включить этого игрока в cause.

Примечание

Объекты Cause неизменны и следовательно не могут быть изменены после создания.

Используя Cause#of(NamedCause) вы можете построить cause из серии объектов. Объекты будут добавлены в цепочку причин в том порядке, в котором они будут переданы методу, поэтому первый параметр объекта станет основной причиной. Помните, что Cause не может быть пустым, поэтому всегда требуется хотя бы один ненулевой параметр.

Если у вас уже есть cause объект и вы хотите добавить еще несколько объектов в цепочку, вы можете использовать Cause#with(NamedCause, NamedCause…). Это создает новый объект Cause, содержащий сначала объекты, уже присутствующие в исходной причине, а затем дополнительные дополнительные объекты, которые вы указали.

Наконец, если вы хотите добавить объект к cause с определенным именованием сначала вызовите NamedCause#of(String, Object), а затем передайте возвращенный экземпляр NamedCause в цепочку причин как обычный объект.