Przyczyny zdarzenia

Eventy (wydarzenia) są świetne do dołączania dodatkowej logiki do akcji gry, ale mają wadę posiadania braku kontekstu co spowodowało dany event (wydarzenie). Obiekt Cause pozwala dostarczać i otrzymywać dodatkowe informacje na temat kontekstu eventu. Ta informacja może zostać później użyta do modyfikacji zachowania Twojego event listenera (nasłuchiwacza wydarzenia).

Dla przykładu, plugin ochraniający świat potrzebuje informacji o tym, jaki gracz wywołał wydarzenie ChangeBlockEvent zanim zdecyduje czy wydarzenie powinno zostać anulowane czy nie. Zamiast iść tradycyjną ścieżką tworzenia wielu subeventów (pod-wydarzeń) dla różnych warunków źródłowych, ta informacja jest przedstawiona w obiekcie Cause w evencie (wydarzeniu).

Każdy event (wydarzenie) posiada obiekt Cause, który może być wykorzystany w celu uzyskania informacji dotyczących przyczyn, dla których event został uruchomiony. Obiekt Cause (przyczyna) może zostać pobrany z eventu przy pomocy Event#getCause().

Retrieving objects from a Cause

Strukturalnie obiekt Cause zawiera sekwencyjną listę obiektów. Istnieje kilka metod, które można wykorzystać do pobrania informacji z obiektu Przyczyny, które omówimy tutaj. Aby uzyskać kompletną listę zobacz Javadocs <https://jd.spongepowered.org>.

Informacja

The objects within a cause are ordered such that the first object is the most immediate cause of the event, and subsequent objects are of decreasing importance and/or may only provide contextual information.

Cause#root() returns the first object within the cause. This object is the most immediate or direct cause of the event. Since a Cause may not be empty, it is guaranteed to have a root.

Cause#first(Class) returns the first object in the cause chain whose type is either the same as or is a subtype of the given class. For example given a cause which contained a player followed by an entity [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
}

Both optionals would contain the player object as it’s type directly matched request for a Player type and it matched the request for an Entity type as Player is a subtype of Entity.

Cause#last(Class) is similar to Cause#first(Class) except it returns the last value in the cause chain matching the type.

Continuing from the example above, if we instead changed it to call Cause#last(Class) the first optional would contain the player object still, but the second optional would now contain the entity that we passed in the second position of the cause.

Cause#containsType(Class) returns a boolean value and can be used to check if a cause chain contains any object matching the provided type.

Cause#all() simply returns all objects within the cause allowing more advanced handling.

Nazwane przyczyny

Sometimes the ordering of objects within the cause isn’t enough to get the proper idea of what an object represents in relation to the event. This is where NamedCause comes in. Named causes provide a method for tagging objects within a cause with a unique name allowing them to be easily identified and requested. Some examples of use cases for named causes is the Notifier of a ChangeBlockEvent.Grow or the Source of a DamageEntityEvent.

Retrieving a named entry from a cause

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

This example makes use of Cause#get(String, Class<T>) which can be used to retrieve the expected object associated with a name if it is present within the cause chain. Additionally Cause#getNamedCauses() provides a Map<String, Object> which can be used to find all present names and their associated objects.

Informacja

Some common identifying names for NamedCauses are present as static fields in the NamedCause class. Identifiers which are specific to certain events can often be found as static fields on the event class, for example DamageEntityEvent#SOURCE.

Tworzenie niestandardowych przyczyn

Creating a cause to use when firing an event is extremely easy. The hardest part is deciding what information to include in the cause. If you’re firing an event from your plugin which is usually triggered through other means perhaps you want to include your plugin container so other plugins know that the event comes from your plugin. Or if you are firing the event on behalf of a player due to some action it’s usually a good idea to include that player in the cause.

Informacja

Cause objects are immutable therefore cannot be modified once created.

Using Cause#of(NamedCause), you can construct a cause from a series of objects. The objects will be added to the cause chain in the order that they are passed to the method, so the first object parameter will become the root cause. Remember that a Cause may not be empty, so at least one non-null parameter is always required.

If you already have a cause object and would like to append some more objects to the chain you can use Cause#with(NamedCause, NamedCause…). This constructs a new Cause object containing first the objects already present in the original cause, then followed by the additional objects that you provided.

Finally if you wish to add an object to a cause with a defined named first call NamedCause#of(String, Object) and then pass the returned NamedCause instance to the cause chain as you would a normal object.