Merge pull request #272 from Minestom/event-api

Revamped event listening API
This commit is contained in:
TheMode 2021-06-14 14:44:59 +02:00 committed by GitHub
commit 80d0b8def6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
125 changed files with 1896 additions and 868 deletions

View File

@ -299,8 +299,7 @@ public final class MinecraftServer {
*
* @return the global event handler
*/
@NotNull
public static GlobalEventHandler getGlobalEventHandler() {
public static @NotNull GlobalEventHandler getGlobalEventHandler() {
return GLOBAL_EVENT_HANDLER;
}

View File

@ -11,6 +11,7 @@ import net.minestom.server.command.builder.parser.ArgumentQueryResult;
import net.minestom.server.command.builder.parser.CommandParser;
import net.minestom.server.command.builder.parser.CommandQueryResult;
import net.minestom.server.entity.Player;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.PlayerCommandEvent;
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
import net.minestom.server.utils.ArrayUtils;
@ -104,7 +105,7 @@ public final class CommandManager {
Player player = (Player) sender;
PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(player, command);
player.callEvent(PlayerCommandEvent.class, playerCommandEvent);
EventDispatcher.call(playerCommandEvent);
if (playerCommandEvent.isCancelled())
return CommandResult.of(CommandResult.Type.CANCELLED, command);

View File

@ -16,10 +16,13 @@ import net.minestom.server.collision.CollisionUtils;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
import net.minestom.server.entity.metadata.EntityMeta;
import net.minestom.server.event.Event;
import net.minestom.server.event.EventCallback;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.EventFilter;
import net.minestom.server.event.EventNode;
import net.minestom.server.event.entity.*;
import net.minestom.server.event.handler.EventHandler;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
@ -61,7 +64,7 @@ import java.util.function.UnaryOperator;
* <p>
* To create your own entity you probably want to extends {@link LivingEntity} or {@link EntityCreature} instead.
*/
public class Entity implements Viewable, Tickable, EventHandler, DataContainer, PermissionHandler, HoverEventSource<ShowEntity> {
public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, DataContainer, PermissionHandler, HoverEventSource<ShowEntity> {
private static final Map<Integer, Entity> ENTITY_BY_ID = new ConcurrentHashMap<>();
private static final Map<UUID, Entity> ENTITY_BY_UUID = new ConcurrentHashMap<>();
@ -116,8 +119,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
private long lastAbsoluteSynchronizationTime;
// Events
private final Map<Class<? extends Event>, Collection<EventCallback>> eventCallbacks = new ConcurrentHashMap<>();
private final Map<String, Collection<EventCallback<?>>> extensionCallbacks = new ConcurrentHashMap<>();
private final EventNode<EntityEvent> eventNode;
protected Metadata metadata = new Metadata(this);
protected EntityMeta entityMeta;
@ -154,6 +156,8 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
Entity.ENTITY_BY_ID.put(id, this);
Entity.ENTITY_BY_UUID.put(uuid, this);
this.eventNode = EventNode.value("entity-" + uuid, EventFilter.ENTITY, this::equals);
}
public Entity(@NotNull EntityType entityType) {
@ -642,7 +646,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
update(time);
ticks++;
callEvent(EntityTickEvent.class, tickEvent); // reuse tickEvent to avoid recreating it each tick
EventDispatcher.call(tickEvent); // reuse tickEvent to avoid recreating it each tick
// remove expired effects
if (!effects.isEmpty()) {
@ -652,10 +656,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
if (time >= timedPotion.getStartingTime() + potionTime) {
// Send the packet that the potion should no longer be applied
timedPotion.getPotion().sendRemovePacket(this);
callEvent(EntityPotionRemoveEvent.class, new EntityPotionRemoveEvent(
this,
timedPotion.getPotion()
));
EventDispatcher.call(new EntityPotionRemoveEvent(this, timedPotion.getPotion()));
return true;
}
return false;
@ -768,16 +769,17 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
}
}
@NotNull
@Override
public Map<Class<? extends Event>, Collection<EventCallback>> getEventCallbacksMap() {
return eventCallbacks;
public @NotNull EventNode<EntityEvent> getEventNode() {
return eventNode;
}
@NotNull
@Override
public Collection<EventCallback<?>> getExtensionCallbacks(String extension) {
return extensionCallbacks.computeIfAbsent(extension, e -> new CopyOnWriteArrayList<>());
public synchronized <V extends EntityEvent> boolean addEventCallback(@NotNull Class<V> eventClass, @NotNull EventCallback<V> eventCallback) {
if (eventNode.getParent() == null) {
MinecraftServer.getGlobalEventHandler().addChild(eventNode);
}
return EventHandler.super.addEventCallback(eventClass, eventCallback);
}
/**
@ -913,8 +915,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
refreshCurrentChunk(instance.getChunkAt(position.getX(), position.getZ()));
instance.UNSAFE_addEntity(this);
spawn();
EntitySpawnEvent entitySpawnEvent = new EntitySpawnEvent(this, instance);
callEvent(EntitySpawnEvent.class, entitySpawnEvent);
EventDispatcher.call(new EntitySpawnEvent(this, instance));
}
/**
@ -947,7 +948,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
*/
public void setVelocity(@NotNull Vector velocity) {
EntityVelocityEvent entityVelocityEvent = new EntityVelocityEvent(this, velocity);
callCancellableEvent(EntityVelocityEvent.class, entityVelocityEvent, () -> {
EventDispatcher.callCancellable(entityVelocityEvent, () -> {
this.velocity.copy(entityVelocityEvent.getVelocity());
sendPacketToViewersAndSelf(getVelocityPacket());
});
@ -1461,7 +1462,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
removeEffect(potion.getEffect());
this.effects.add(new TimedPotion(potion, System.currentTimeMillis()));
potion.sendAddPacket(this);
callEvent(EntityPotionAddEvent.class, new EntityPotionAddEvent(this, potion));
EventDispatcher.call(new EntityPotionAddEvent(this, potion));
}
/**
@ -1473,10 +1474,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
this.effects.removeIf(timedPotion -> {
if (timedPotion.getPotion().getEffect() == effect) {
timedPotion.getPotion().sendRemovePacket(this);
callEvent(EntityPotionRemoveEvent.class, new EntityPotionRemoveEvent(
this,
timedPotion.getPotion()
));
EventDispatcher.call(new EntityPotionRemoveEvent(this, timedPotion.getPotion()));
return true;
}
return false;
@ -1489,10 +1487,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
public void clearEffects() {
for (TimedPotion timedPotion : effects) {
timedPotion.getPotion().sendRemovePacket(this);
callEvent(EntityPotionRemoveEvent.class, new EntityPotionRemoveEvent(
this,
timedPotion.getPotion()
));
EventDispatcher.call(new EntityPotionRemoveEvent(this, timedPotion.getPotion()));
}
this.effects.clear();
}

View File

@ -6,6 +6,7 @@ import net.minestom.server.entity.ai.EntityAI;
import net.minestom.server.entity.ai.EntityAIGroup;
import net.minestom.server.entity.pathfinding.NavigableEntity;
import net.minestom.server.entity.pathfinding.Navigator;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.utils.Position;
@ -146,7 +147,7 @@ public class EntityCreature extends LivingEntity implements NavigableEntity, Ent
if (swingHand)
swingMainHand();
EntityAttackEvent attackEvent = new EntityAttackEvent(this, target);
callEvent(EntityAttackEvent.class, attackEvent);
EventDispatcher.call(attackEvent);
}
/**

View File

@ -1,5 +1,6 @@
package net.minestom.server.entity;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.entity.EntityItemMergeEvent;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
@ -112,7 +113,7 @@ public class ItemEntity extends ObjectEntity {
final ItemStack result = stackingRule.apply(itemStack, totalAmount);
EntityItemMergeEvent entityItemMergeEvent = new EntityItemMergeEvent(this, itemEntity, result);
callCancellableEvent(EntityItemMergeEvent.class, entityItemMergeEvent, () -> {
EventDispatcher.callCancellable(entityItemMergeEvent, () -> {
setItemStack(entityItemMergeEvent.getResult());
itemEntity.remove();
});

View File

@ -7,6 +7,7 @@ import net.minestom.server.attribute.Attributes;
import net.minestom.server.collision.BoundingBox;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.metadata.LivingEntityMeta;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.entity.EntityDamageEvent;
import net.minestom.server.event.entity.EntityDeathEvent;
import net.minestom.server.event.entity.EntityFireEvent;
@ -17,7 +18,10 @@ import net.minestom.server.instance.block.Block;
import net.minestom.server.inventory.EquipmentHandler;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.server.play.*;
import net.minestom.server.network.packet.server.play.CollectItemPacket;
import net.minestom.server.network.packet.server.play.EntityAnimationPacket;
import net.minestom.server.network.packet.server.play.EntityPropertiesPacket;
import net.minestom.server.network.packet.server.play.SoundEffectPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.scoreboard.Team;
import net.minestom.server.sound.SoundEvent;
@ -193,7 +197,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) {
EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot);
callEvent(EntityEquipEvent.class, entityEquipEvent);
EventDispatcher.call(entityEquipEvent);
return entityEquipEvent.getEquippedItem();
}
@ -232,7 +236,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
if (itemEntity.shouldRemove() || itemEntity.isRemoveScheduled())
continue;
PickupItemEvent pickupItemEvent = new PickupItemEvent(this, itemEntity);
callCancellableEvent(PickupItemEvent.class, pickupItemEvent, () -> {
EventDispatcher.callCancellable(pickupItemEvent, () -> {
final ItemStack item = itemEntity.getItemStack();
CollectItemPacket collectItemPacket = new CollectItemPacket();
@ -305,7 +309,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
}
EntityDeathEvent entityDeathEvent = new EntityDeathEvent(this);
callEvent(EntityDeathEvent.class, entityDeathEvent);
EventDispatcher.call(entityDeathEvent);
}
/**
@ -329,7 +333,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
// Do not start fire event if the fire needs to be removed (< 0 duration)
if (duration > 0) {
callCancellableEvent(EntityFireEvent.class, entityFireEvent, () -> {
EventDispatcher.callCancellable(entityFireEvent, () -> {
final long fireTime = entityFireEvent.getFireTime(TimeUnit.MILLISECOND);
setOnFire(true);
fireExtinguishTime = System.currentTimeMillis() + fireTime;
@ -354,7 +358,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
}
EntityDamageEvent entityDamageEvent = new EntityDamageEvent(this, type, value);
callCancellableEvent(EntityDamageEvent.class, entityDamageEvent, () -> {
EventDispatcher.callCancellable(entityDamageEvent, () -> {
// Set the last damage type since the event is not cancelled
this.lastDamageSource = entityDamageEvent.getDamageType();
@ -602,7 +606,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
public void setFlyingWithElytra(boolean isFlying) {
this.entityMeta.setFlyingWithElytra(isFlying);
}
/**
* Used to change the {@code isDead} internal field.
*

View File

@ -30,6 +30,7 @@ import net.minestom.server.effects.Effects;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.fakeplayer.FakePlayer;
import net.minestom.server.entity.vehicle.PlayerVehicleInformation;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.inventory.InventoryOpenEvent;
import net.minestom.server.event.item.ItemDropEvent;
import net.minestom.server.event.item.ItemUpdateStateEvent;
@ -250,7 +251,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
// Add player to list with spawning skin
PlayerSkinInitEvent skinInitEvent = new PlayerSkinInitEvent(this, skin);
callEvent(PlayerSkinInitEvent.class, skinInitEvent);
EventDispatcher.call(skinInitEvent);
this.skin = skinInitEvent.getSkin();
// FIXME: when using Geyser, this line remove the skin of the client
playerConnection.sendPacket(getAddPlayerToList());
@ -380,7 +381,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
if (experienceOrb.shouldRemove() || experienceOrb.isRemoveScheduled())
continue;
PickupExperienceEvent pickupExperienceEvent = new PickupExperienceEvent(experienceOrb);
callCancellableEvent(PickupExperienceEvent.class, pickupExperienceEvent, () -> {
EventDispatcher.callCancellable(pickupExperienceEvent, () -> {
short experienceCount = pickupExperienceEvent.getExperienceCount(); // TODO give to player
entity.remove();
});
@ -406,7 +407,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
if (isFood) {
PlayerEatEvent playerEatEvent = new PlayerEatEvent(this, foodItem, eatingHand);
callEvent(PlayerEatEvent.class, playerEatEvent);
EventDispatcher.call(playerEatEvent);
}
refreshEating(null);
@ -414,7 +415,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
}
// Tick event
callEvent(PlayerTickEvent.class, playerTickEvent);
EventDispatcher.call(playerTickEvent);
}
@Override
@ -444,7 +445,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
// Call player death event
PlayerDeathEvent playerDeathEvent = new PlayerDeathEvent(this, deathText, chatMessage);
callEvent(PlayerDeathEvent.class, playerDeathEvent);
EventDispatcher.call(playerDeathEvent);
deathText = playerDeathEvent.getDeathText();
chatMessage = playerDeathEvent.getChatMessage();
@ -480,7 +481,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
respawnPacket.isFlat = levelFlat;
getPlayerConnection().sendPacket(respawnPacket);
PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(this);
callEvent(PlayerRespawnEvent.class, respawnEvent);
EventDispatcher.call(respawnEvent);
refreshIsDead(false);
// Runnable called when teleportation is successful (after loading and sending necessary chunk)
@ -502,7 +503,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
if (isRemoved())
return;
callEvent(PlayerDisconnectEvent.class, new PlayerDisconnectEvent(this));
EventDispatcher.call(new PlayerDisconnectEvent(this));
super.remove();
this.packets.clear();
@ -660,7 +661,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
}
PlayerSpawnEvent spawnEvent = new PlayerSpawnEvent(this, instance, firstSpawn);
callEvent(PlayerSpawnEvent.class, spawnEvent);
EventDispatcher.call(spawnEvent);
}
/**
@ -1306,7 +1307,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
}
ItemDropEvent itemDropEvent = new ItemDropEvent(this, item);
callEvent(ItemDropEvent.class, itemDropEvent);
EventDispatcher.call(itemDropEvent);
return !itemDropEvent.isCancelled();
}
@ -1827,7 +1828,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
InventoryOpenEvent inventoryOpenEvent = new InventoryOpenEvent(inventory, this);
callCancellableEvent(InventoryOpenEvent.class, inventoryOpenEvent, () -> {
EventDispatcher.callCancellable(inventoryOpenEvent, () -> {
Inventory openInventory = getOpenInventory();
if (openInventory != null) {
openInventory.removeViewer(this);
@ -2196,7 +2197,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
this.onGround = onGround;
if (this.onGround && this.isFlyingWithElytra()) {
this.setFlyingWithElytra(false);
this.callEvent(PlayerStopFlyingWithElytraEvent.class, new PlayerStopFlyingWithElytraEvent(this));
EventDispatcher.call(new PlayerStopFlyingWithElytraEvent(this));
}
}
@ -2271,7 +2272,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
return null;
ItemUpdateStateEvent itemUpdateStateEvent = new ItemUpdateStateEvent(this, hand, updatedItem);
callEvent(ItemUpdateStateEvent.class, itemUpdateStateEvent);
EventDispatcher.call(itemUpdateStateEvent);
return itemUpdateStateEvent;
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.entity.type.decoration;
import net.minestom.server.entity.*;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.item.EntityEquipEvent;
import net.minestom.server.inventory.EquipmentHandler;
import net.minestom.server.item.ItemStack;
@ -237,7 +238,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) {
EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot);
callEvent(EntityEquipEvent.class, entityEquipEvent);
EventDispatcher.call(entityEquipEvent);
return entityEquipEvent.getEquippedItem();
}
}

View File

@ -4,6 +4,7 @@ import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.metadata.ProjectileMeta;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.entity.EntityShootEvent;
import net.minestom.server.instance.Chunk;
@ -71,14 +72,14 @@ public class EntityProjectile extends Entity {
}
public void shoot(Position to, double power, double spread) {
EntityShootEvent event = new EntityShootEvent(this.shooter, this, to, power, spread);
this.shooter.callEvent(EntityShootEvent.class, event);
if (event.isCancelled()) {
EntityShootEvent shootEvent = new EntityShootEvent(this.shooter, this, to, power, spread);
EventDispatcher.call(shootEvent);
if (shootEvent.isCancelled()) {
remove();
return;
}
Position from = this.shooter.getPosition().clone().add(0D, this.shooter.getEyeHeight(), 0D);
shoot(from, to, event.getPower(), event.getSpread());
shoot(from, to, shootEvent.getPower(), shootEvent.getSpread());
}
private void shoot(@NotNull Position from, @NotNull Position to, double power, double spread) {
@ -193,7 +194,7 @@ public class EntityProjectile extends Entity {
if (victimOptional.isPresent()) {
LivingEntity victim = (LivingEntity) victimOptional.get();
victim.setArrowCount(victim.getArrowCount() + 1);
callEvent(EntityAttackEvent.class, new EntityAttackEvent(this, victim));
EventDispatcher.call(new EntityAttackEvent(this, victim));
remove();
return super.onGround;
}

View File

@ -1,23 +0,0 @@
package net.minestom.server.event;
import net.minestom.server.entity.Entity;
import org.jetbrains.annotations.NotNull;
public class EntityEvent extends Event {
protected final Entity entity;
public EntityEvent(@NotNull Entity entity) {
this.entity = entity;
}
/**
* Gets the entity of this event.
*
* @return the entity
*/
@NotNull
public Entity getEntity() {
return entity;
}
}

View File

@ -1,11 +1,9 @@
package net.minestom.server.event;
import net.minestom.server.event.handler.EventHandler;
/**
* Object which can be listened to by an {@link EventHandler}.
* Event which can be listened to by an {@link EventNode} using {@link EventNode#addListener(EventListener)}.
* <p>
* Called using {@link EventHandler#callEvent(Class, Event)}.
* Called using {@link EventDispatcher#call(Event)}.
*/
public class Event {
public interface Event {
}

View File

@ -0,0 +1,16 @@
package net.minestom.server.event;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.trait.CancellableEvent;
import org.jetbrains.annotations.NotNull;
public class EventDispatcher {
public static void call(@NotNull Event event) {
MinecraftServer.getGlobalEventHandler().call(event);
}
public static void callCancellable(@NotNull CancellableEvent event, @NotNull Runnable successCallback) {
MinecraftServer.getGlobalEventHandler().callCancellable(event, successCallback);
}
}

View File

@ -0,0 +1,67 @@
package net.minestom.server.event;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.*;
import net.minestom.server.instance.Instance;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
/**
* Represents a filter for a specific {@link Event} type.
* <p>
* The handler represents a "target" of the event. This can be used
* to create filters for all events of a specific type using information
* about the target.
* <p>
* For example, the target of a {@link PlayerEvent} is a {@link Player} so
* you could create a player event filter which checks if the target player
* is in creative mode.
*
* @param <E> The event type to filter
* @param <H> The handler type to filter on.
*/
public interface EventFilter<E extends Event, H> {
EventFilter<Event, ?> ALL = from(Event.class, null);
EventFilter<EntityEvent, Entity> ENTITY = from(EntityEvent.class, EntityEvent::getEntity);
EventFilter<PlayerEvent, Player> PLAYER = from(PlayerEvent.class, PlayerEvent::getPlayer);
EventFilter<ItemEvent, ItemStack> ITEM = from(ItemEvent.class, ItemEvent::getItemStack);
EventFilter<InstanceEvent, Instance> INSTANCE = from(InstanceEvent.class, InstanceEvent::getInstance);
EventFilter<InventoryEvent, Inventory> INVENTORY = from(InventoryEvent.class, InventoryEvent::getInventory);
static <E extends Event, H> EventFilter<E, H> from(@NotNull Class<E> eventType,
@Nullable Function<E, H> handlerGetter) {
return new EventFilter<>() {
@Override
public @Nullable H getHandler(@NotNull E event) {
return handlerGetter != null ? handlerGetter.apply(event) : null;
}
@Override
public @NotNull Class<E> getEventType() {
return eventType;
}
};
}
/**
* Gets the handler for the given event instance, or null if the event
* type has no handler.
*
* @param event The event instance
* @return The handler, if it exists for the given event
*/
@Nullable H getHandler(@NotNull E event);
/**
* The event type to filter on.
*
* @return The event type.
*/
@NotNull Class<E> getEventType();
}

View File

@ -0,0 +1,180 @@
package net.minestom.server.event;
import net.minestom.server.event.trait.CancellableEvent;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Represents an event listener (handler) in an event graph.
* <p>
* A listener is responsible for executing some action based on an event triggering.
*
* @param <T> The event type being handled.
*/
public interface EventListener<T extends Event> {
@NotNull Class<T> getEventType();
@NotNull Result run(@NotNull T event);
@Contract(pure = true)
static <T extends Event> EventListener.@NotNull Builder<T> builder(@NotNull Class<T> eventType) {
return new EventListener.Builder<>(eventType);
}
/**
* Create an event listener without any special options. The given listener will be executed
* if the event passes all parent filtering.
*
* @param eventType The event type to handle
* @param listener The handler function
* @param <T> The event type to handle
* @return An event listener with the given properties
*/
@Contract(pure = true)
static <T extends Event> @NotNull EventListener<T> of(@NotNull Class<T> eventType, @NotNull Consumer<@NotNull T> listener) {
return new EventListener<>() {
@Override
public @NotNull Class<T> getEventType() {
return eventType;
}
@Override
public @NotNull Result run(@NotNull T event) {
listener.accept(event);
return Result.SUCCESS;
}
};
}
class Builder<T extends Event> {
private final Class<T> eventType;
private final List<Predicate<T>> filters = new ArrayList<>();
private boolean ignoreCancelled = true;
private int expireCount;
private Predicate<T> expireWhen;
private Consumer<T> handler;
protected Builder(Class<T> eventType) {
this.eventType = eventType;
}
/**
* Adds a filter to the executor of this listener. The executor will only
* be called if this condition passes on the given event.
*/
@Contract(value = "_ -> this")
public @NotNull EventListener.Builder<T> filter(Predicate<T> filter) {
this.filters.add(filter);
return this;
}
/**
* Specifies if the handler should still be called if {@link CancellableEvent#isCancelled()} returns {@code true}.
* <p>
* Default is set to {@code true}.
*
* @param ignoreCancelled True to stop processing the event when cancelled
*/
@Contract(value = "_ -> this")
public @NotNull EventListener.Builder<T> ignoreCancelled(boolean ignoreCancelled) {
this.ignoreCancelled = ignoreCancelled;
return this;
}
/**
* Removes this listener after it has been executed the given number of times.
*
* @param expireCount The number of times to execute
*/
@Contract(value = "_ -> this")
public @NotNull EventListener.Builder<T> expireCount(int expireCount) {
this.expireCount = expireCount;
return this;
}
/**
* Expires this listener when it passes the given condition. The expiration will
* happen before the event is executed.
*
* @param expireWhen The condition to test
*/
@Contract(value = "_ -> this")
public @NotNull EventListener.Builder<T> expireWhen(Predicate<T> expireWhen) {
this.expireWhen = expireWhen;
return this;
}
/**
* Sets the handler for this event listener. This will be executed if the listener passes
* all conditions.
*/
@Contract(value = "_ -> this")
public @NotNull EventListener.Builder<T> handler(Consumer<T> handler) {
this.handler = handler;
return this;
}
@Contract(value = "-> new", pure = true)
public @NotNull EventListener<T> build() {
final boolean ignoreCancelled = this.ignoreCancelled;
AtomicInteger expirationCount = new AtomicInteger(this.expireCount);
final boolean hasExpirationCount = expirationCount.get() > 0;
final Predicate<T> expireWhen = this.expireWhen;
final var filters = new ArrayList<>(this.filters);
final var handler = this.handler;
return new EventListener<>() {
@Override
public @NotNull Class<T> getEventType() {
return eventType;
}
@Override
public @NotNull Result run(@NotNull T event) {
// Event cancellation
if (ignoreCancelled && event instanceof CancellableEvent &&
((CancellableEvent) event).isCancelled()) {
return Result.INVALID;
}
// Expiration predicate
if (expireWhen != null && expireWhen.test(event)) {
return Result.EXPIRED;
}
// Filtering
if (!filters.isEmpty()) {
for (var filter : filters) {
if (!filter.test(event)) {
// Cancelled
return Result.INVALID;
}
}
}
// Handler
if (handler != null) {
handler.accept(event);
}
// Expiration count
if (hasExpirationCount && expirationCount.decrementAndGet() == 0) {
return Result.EXPIRED;
}
return Result.SUCCESS;
}
};
}
}
enum Result {
SUCCESS,
INVALID,
EXPIRED,
EXCEPTION
}
}

View File

@ -0,0 +1,555 @@
package net.minestom.server.event;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.tag.Tag;
import net.minestom.server.tag.TagReadable;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Represents a single node in an event graph.
* <p>
* A node may contain any number of children and/or listeners. When an event is called,
* the node will filter it based on the parameters given at creation and then propagate
* it down to child nodes and listeners if it passes.
*
* @param <T> The event type accepted by this node
*/
public class EventNode<T extends Event> {
/**
* Creates an event node which accepts any event type with no filtering.
*
* @param name The name of the node
* @return An event node with no filtering
*/
@Contract(value = "_ -> new", pure = true)
public static @NotNull EventNode<Event> all(@NotNull String name) {
return type(name, EventFilter.ALL);
}
/**
* Creates an event node which accepts any event of the given type. The type is provided
* by the {@link EventFilter}.
* <p>
* For example, you could create an event filter which only accepts player events with the following
* <p><pre>
* var playerEventNode = EventNode.type("demo", EventFilter.PLAYER);
* </pre>
*
* @param name The name of the event node
* @param filter The event type filter to apply
* @param <E> The resulting event type of the node
* @return A node with just an event type filter
*/
@Contract(value = "_, _ -> new", pure = true)
public static <E extends Event, V> @NotNull EventNode<E> type(@NotNull String name,
@NotNull EventFilter<E, V> filter) {
return create(name, filter, null);
}
/**
* Creates an event node which accepts any event of the given type which passes
* the provided condition. The condition is based on the event object itself.
* <p>
* For example, you could create an event filter which only accepts player events
* where the player is in the pos x/z quadrant of the world.
* <p><pre>{@code
* var playerInPosXZNode = EventNode.event("abc", EventFilter.PLAYER, event -> {
* var position = event.getPlayer().getPosition();
* return position.getX() > 0 && position.getZ() > 0;
* });
* }</pre>
*
* @param name The name of the event node
* @param filter The event type filter to apply
* @param predicate The event condition
* @param <E> The resulting event type of the node
* @return A node with an event type filter as well as a condition on the event.
*/
@Contract(value = "_, _, _ -> new", pure = true)
public static <E extends Event, V> @NotNull EventNode<E> event(@NotNull String name,
@NotNull EventFilter<E, V> filter,
@NotNull Predicate<E> predicate) {
return create(name, filter, (e, h) -> predicate.test(e));
}
/**
* Creates an event node which accepts any event of the given type which passes
* the provided condition. The condition is based on the event object as well as
* the event handler type defined in the {@link EventFilter}.
* <p>
* For example, you could create an event filter which only accepts player events
* where the player is in the pos x/z quadrant of the world.
* <p><pre>{@code
* var playerInPosXZNode = EventNode.type("abc", EventFilter.PLAYER, (event, player) -> {
* var position = player.getPosition();
* return position.getX() > 0 && position.getZ() > 0;
* });
* }</pre>
*
* @param name The name of the event node
* @param filter The event type filter to apply
* @param predicate The event condition
* @param <E> The resulting event type of the node
* @param <V> The handler type of the event filter
* @return A node with an event type filter as well as a condition on the event.
*/
@Contract(value = "_, _, _ -> new", pure = true)
public static <E extends Event, V> @NotNull EventNode<E> type(@NotNull String name,
@NotNull EventFilter<E, V> filter,
@NotNull BiPredicate<E, V> predicate) {
return create(name, filter, predicate);
}
/**
* Creates an event node which accepts any event of the given type which passes
* the provided condition. The condition is based on the event handler defined
* by the {@link EventFilter}.
* <p>
* For example, you could create an event filter which only accepts player events
* where the player is in creative mode.
* <p><pre>
* var playerIsCreative = EventNode.value("abc", EventFilter.PLAYER, Player::isCreative);
* </pre>
*
* @param name The name of the event node
* @param filter The event type filter to apply
* @param predicate The event condition
* @param <E> The resulting event type of the node
* @param <V> The handler type of the event filter
* @return A node with an event type filter as well as a condition on the event.
*/
@Contract(value = "_, _, _ -> new", pure = true)
public static <E extends Event, V> @NotNull EventNode<E> value(@NotNull String name,
@NotNull EventFilter<E, V> filter,
@NotNull Predicate<V> predicate) {
return create(name, filter, (e, h) -> predicate.test(h));
}
/**
* Creates an event node which accepts any event of the given type which has a handler who
* has the given tag.
* <p>
* The {@link EventFilter}'s resulting event type must be {@link TagReadable}.
*
* @param name The name of the event node
* @param filter The event type filter to apply
* @param tag The tag which must be contained on the event handler
* @param <E> The resulting event type of the node
* @return A node with an event type filter as well as a handler with the provided tag
*/
@Contract(value = "_, _, _ -> new", pure = true)
public static <E extends Event> @NotNull EventNode<E> tag(@NotNull String name,
@NotNull EventFilter<E, ? extends TagReadable> filter,
@NotNull Tag<?> tag) {
return create(name, filter, (e, h) -> h.hasTag(tag));
}
/**
* Creates an event node which accepts any event of the given type which has a handler who
* has an applicable tag. An applicable tag means that it passes the given condition.
*
* @param name The name of the event node
* @param filter The event type filter to apply
* @param tag The tag which must be contained on the event handler
* @param consumer The condition to test against the tag, if it exists.
* @param <E> The resulting event type of the node
* @return A node with an event type filter as well as a handler with the provided tag
*/
@Contract(value = "_, _, _, _ -> new", pure = true)
public static <E extends Event, V> @NotNull EventNode<E> tag(@NotNull String name,
@NotNull EventFilter<E, ? extends TagReadable> filter,
@NotNull Tag<V> tag,
@NotNull Predicate<@Nullable V> consumer) {
return create(name, filter, (e, h) -> consumer.test(h.getTag(tag)));
}
private static <E extends Event, V> EventNode<E> create(@NotNull String name,
@NotNull EventFilter<E, V> filter,
@Nullable BiPredicate<E, V> predicate) {
return new EventNode<>(name, filter, predicate != null ? (e, o) -> predicate.test(e, (V) o) : null);
}
private static final Object GLOBAL_CHILD_LOCK = new Object();
private final Object lock = new Object();
private final Map<Class<? extends T>, ListenerEntry<T>> listenerMap = new ConcurrentHashMap<>();
private final Set<EventNode<T>> children = new CopyOnWriteArraySet<>();
protected final String name;
protected final EventFilter<T, ?> filter;
protected final BiPredicate<T, Object> predicate;
protected final Class<T> eventType;
private volatile int priority;
private volatile EventNode<? super T> parent;
protected EventNode(@NotNull String name,
@NotNull EventFilter<T, ?> filter,
@Nullable BiPredicate<T, Object> predicate) {
this.name = name;
this.filter = filter;
this.predicate = predicate;
this.eventType = filter.getEventType();
}
/**
* Condition to enter the node.
*
* @param event the called event
* @return true to enter the node, false otherwise
*/
protected boolean condition(@NotNull T event) {
if (predicate == null)
return true;
final var value = filter.getHandler(event);
try {
return predicate.test(event, value);
} catch (Exception e) {
MinecraftServer.getExceptionManager().handleException(e);
return false;
}
}
/**
* Executes the given event on this node. The event must pass all conditions before
* it will be forwarded to the listeners.
* <p>
* Calling an event on a node will execute all child nodes, however, an event may be
* called anywhere on the event graph and it will propagate down from there only.
*
* @param event the event to execute
*/
public void call(@NotNull T event) {
final var eventClass = event.getClass();
if (!eventType.isAssignableFrom(eventClass)) {
// Invalid event type
return;
}
if (!condition(event)) {
// Cancelled by superclass
return;
}
// Process listener list
final var entry = listenerMap.get(eventClass);
if (entry == null) {
// No listener nor children
return;
}
final var listeners = entry.listeners;
if (!listeners.isEmpty()) {
for (EventListener<T> listener : listeners) {
EventListener.Result result;
try {
result = listener.run(event);
} catch (Exception e) {
result = EventListener.Result.EXCEPTION;
MinecraftServer.getExceptionManager().handleException(e);
}
if (result == EventListener.Result.EXPIRED) {
listeners.remove(listener);
}
}
}
// Process children
if (entry.childCount > 0) {
this.children.stream()
.sorted(Comparator.comparing(EventNode::getPriority))
.forEach(child -> child.call(event));
}
}
/**
* Execute a cancellable event with a callback to execute if the event is successful.
* Event conditions and propagation is the same as {@link #call(Event)}.
*
* @param event The event to execute
* @param successCallback A callback if the event is not cancelled
*/
public void callCancellable(@NotNull T event, @NotNull Runnable successCallback) {
call(event);
if (!(event instanceof CancellableEvent) || !((CancellableEvent) event).isCancelled()) {
successCallback.run();
}
}
@Contract(pure = true)
public @NotNull String getName() {
return name;
}
@Contract(pure = true)
public int getPriority() {
return priority;
}
@Contract(value = "_ -> this")
public @NotNull EventNode<T> setPriority(int priority) {
this.priority = priority;
return this;
}
@Contract(pure = true)
public @Nullable EventNode<? super T> getParent() {
return parent;
}
/**
* Returns an unmodifiable view of the children in this node.
*
* @see #addChild(EventNode)
* @see #removeChild(EventNode)
*/
@Contract(pure = true)
public @NotNull Set<@NotNull EventNode<T>> getChildren() {
return Collections.unmodifiableSet(children);
}
/**
* Locates all child nodes with the given name and event type recursively starting at this node.
*
* @param name The event node name to filter for
* @param eventType The event node type to filter for
* @return All matching event nodes
*/
@Contract(pure = true)
public <E extends T> @NotNull List<EventNode<E>> findChildren(@NotNull String name, Class<E> eventType) {
if (children.isEmpty()) {
return Collections.emptyList();
}
synchronized (GLOBAL_CHILD_LOCK) {
List<EventNode<E>> result = new ArrayList<>();
for (EventNode<T> child : children) {
if (EventNode.equals(child, name, eventType)) {
result.add((EventNode<E>) child);
}
result.addAll(child.findChildren(name, eventType));
}
return result;
}
}
/**
* Locates all child nodes with the given name and event type recursively starting at this node.
*
* @param name The event name to filter for
* @return All matching event nodes
*/
@Contract(pure = true)
public @NotNull List<EventNode<T>> findChildren(@NotNull String name) {
return findChildren(name, eventType);
}
/**
* Replaces all children matching the given name and type recursively starting from this node.
* <p>
* Node: The callee may not be replaced by this call.
*
* @param name The event name to filter for
* @param eventType The event node type to filter for
* @param eventNode The replacement node
*/
public <E extends T> void replaceChildren(@NotNull String name, @NotNull Class<E> eventType, @NotNull EventNode<E> eventNode) {
if (children.isEmpty()) {
return;
}
synchronized (GLOBAL_CHILD_LOCK) {
for (EventNode<T> child : children) {
if (EventNode.equals(child, name, eventType)) {
removeChild(child);
addChild(eventNode);
continue;
}
child.replaceChildren(name, eventType, eventNode);
}
}
}
/**
* Replaces all children matching the given name and type recursively starting from this node.
* <p>
* Node: The callee may not be replaced by this call.
*
* @param name The node name to filter for
* @param eventNode The replacement node
*/
public void replaceChildren(@NotNull String name, @NotNull EventNode<T> eventNode) {
replaceChildren(name, eventType, eventNode);
}
/**
* Recursively removes children with the given name and type starting at this node.
*
* @param name The node name to filter for
* @param eventType The node type to filter for
*/
public void removeChildren(@NotNull String name, @NotNull Class<? extends T> eventType) {
if (children.isEmpty()) {
return;
}
synchronized (GLOBAL_CHILD_LOCK) {
for (EventNode<T> child : children) {
if (EventNode.equals(child, name, eventType)) {
removeChild(child);
continue;
}
child.removeChildren(name, eventType);
}
}
}
/**
* Recursively removes children with the given name starting at this node.
*
* @param name The node name to filter for
*/
public void removeChildren(@NotNull String name) {
removeChildren(name, eventType);
}
/**
* Directly adds a child node to this node.
*
* @param child The child to add
* @return this, can be used for chaining
*/
@Contract(value = "_ -> this")
public @NotNull EventNode<T> addChild(@NotNull EventNode<? extends T> child) {
synchronized (GLOBAL_CHILD_LOCK) {
Check.stateCondition(child.parent != null, "Node already has a parent");
Check.stateCondition(Objects.equals(parent, child), "Cannot have a child as parent");
final boolean result = this.children.add((EventNode<T>) child);
if (result) {
child.parent = this;
// Increase listener count
synchronized (lock) {
child.listenerMap.forEach((eventClass, eventListeners) -> {
final var entry = child.listenerMap.get(eventClass);
if (entry == null)
return;
final int childCount = entry.listeners.size() + entry.childCount;
increaseChildListenerCount(eventClass, childCount);
});
}
}
}
return this;
}
/**
* Directly removes the given child from this node.
*
* @param child The child to remove
* @return this, can be used for chaining
*/
@Contract(value = "_ -> this")
public @NotNull EventNode<T> removeChild(@NotNull EventNode<? extends T> child) {
synchronized (GLOBAL_CHILD_LOCK) {
final boolean result = this.children.remove(child);
if (result) {
child.parent = null;
// Decrease listener count
synchronized (lock) {
child.listenerMap.forEach((eventClass, eventListeners) -> {
final var entry = child.listenerMap.get(eventClass);
if (entry == null)
return;
final int childCount = entry.listeners.size() + entry.childCount;
decreaseChildListenerCount(eventClass, childCount);
});
}
}
}
return this;
}
@Contract(value = "_ -> this")
public @NotNull EventNode<T> addListener(@NotNull EventListener<? extends T> listener) {
synchronized (GLOBAL_CHILD_LOCK) {
final var eventType = listener.getEventType();
var entry = listenerMap.computeIfAbsent(eventType, aClass -> new ListenerEntry<>());
entry.listeners.add((EventListener<T>) listener);
if (parent != null) {
synchronized (parent.lock) {
parent.increaseChildListenerCount(eventType, 1);
}
}
}
return this;
}
@Contract(value = "_, _ -> this")
public <E extends T> @NotNull EventNode<T> addListener(@NotNull Class<E> eventType, @NotNull Consumer<@NotNull E> listener) {
return addListener(EventListener.of(eventType, listener));
}
@Contract(value = "_ -> this")
public @NotNull EventNode<T> removeListener(@NotNull EventListener<? extends T> listener) {
synchronized (GLOBAL_CHILD_LOCK) {
final var eventType = listener.getEventType();
var entry = listenerMap.get(eventType);
if (entry == null)
return this;
var listeners = entry.listeners;
final boolean removed = listeners.remove(listener);
if (removed && parent != null) {
synchronized (parent.lock) {
parent.decreaseChildListenerCount(eventType, 1);
}
}
}
return this;
}
private void increaseChildListenerCount(Class<? extends T> eventClass, int count) {
var entry = listenerMap.computeIfAbsent(eventClass, aClass -> new ListenerEntry<>());
ListenerEntry.addAndGet(entry, count);
if (parent != null) {
parent.increaseChildListenerCount(eventClass, count);
}
}
private void decreaseChildListenerCount(Class<? extends T> eventClass, int count) {
var entry = listenerMap.computeIfAbsent(eventClass, aClass -> new ListenerEntry<>());
final int result = ListenerEntry.addAndGet(entry, -count);
if (result == 0 && entry.listeners.isEmpty()) {
this.listenerMap.remove(eventClass);
} else if (result < 0) {
throw new IllegalStateException("Something wrong happened, listener count: " + result);
}
if (parent != null) {
parent.decreaseChildListenerCount(eventClass, count);
}
}
private static boolean equals(EventNode<?> node, String name, Class<?> eventType) {
final boolean nameCheck = node.getName().equals(name);
final boolean typeCheck = eventType.isAssignableFrom(node.eventType);
return nameCheck && typeCheck;
}
private static class ListenerEntry<T extends Event> {
private static final AtomicIntegerFieldUpdater<ListenerEntry> CHILD_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(ListenerEntry.class, "childCount");
List<EventListener<T>> listeners = new CopyOnWriteArrayList<>();
volatile int childCount;
private static int addAndGet(ListenerEntry<?> entry, int add) {
return CHILD_UPDATER.addAndGet(entry, add);
}
}
}

View File

@ -1,31 +1,23 @@
package net.minestom.server.event;
import net.minestom.server.event.handler.EventHandler;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
/**
* Object containing all the global event listeners.
*/
public final class GlobalEventHandler implements EventHandler {
// Events
private final Map<Class<? extends Event>, Collection<EventCallback>> eventCallbacks = new ConcurrentHashMap<>();
private final Map<String, Collection<EventCallback<?>>> extensionCallbacks = new ConcurrentHashMap<>();
@NotNull
@Override
public Map<Class<? extends Event>, Collection<EventCallback>> getEventCallbacksMap() {
return eventCallbacks;
public final class GlobalEventHandler extends EventNode<Event> {
public GlobalEventHandler() {
super("global", EventFilter.ALL, null);
}
@NotNull
@Override
public Collection<EventCallback<?>> getExtensionCallbacks(String extension) {
return extensionCallbacks.computeIfAbsent(extension, e -> new CopyOnWriteArrayList<>());
/**
* @deprecated use {@link #addListener(Class, Consumer)}
*/
@Deprecated
public <V extends Event> boolean addEventCallback(@NotNull Class<V> eventClass, @NotNull EventCallback<V> eventCallback) {
addListener(eventClass, eventCallback::run);
return true;
}
}

View File

@ -1,23 +0,0 @@
package net.minestom.server.event;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
public class InstanceEvent extends Event {
protected final Instance instance;
public InstanceEvent(@NotNull Instance instance) {
this.instance = instance;
}
/**
* Gets the instance.
*
* @return instance
*/
@NotNull
public Instance getInstance() {
return instance;
}
}

View File

@ -1,23 +0,0 @@
package net.minestom.server.event;
import net.minestom.server.inventory.Inventory;
import org.jetbrains.annotations.Nullable;
public class InventoryEvent extends Event {
protected Inventory inventory;
public InventoryEvent(@Nullable Inventory inventory) {
this.inventory = inventory;
}
/**
* Gets the inventory.
*
* @return the inventory, null if this is a player's inventory
*/
@Nullable
public Inventory getInventory() {
return inventory;
}
}

View File

@ -1,23 +0,0 @@
package net.minestom.server.event;
import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull;
public class PlayerEvent extends Event {
protected final Player player;
public PlayerEvent(@NotNull Player player) {
this.player = player;
}
/**
* Gets the player.
*
* @return the player
*/
@NotNull
public Player getPlayer() {
return player;
}
}

View File

@ -1,22 +1,28 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player does a left click on an entity or with
* {@link net.minestom.server.entity.EntityCreature#attack(Entity)}.
*/
public class EntityAttackEvent extends EntityEvent {
public class EntityAttackEvent implements EntityEvent {
private final Entity entity;
private final Entity target;
public EntityAttackEvent(@NotNull Entity source, @NotNull Entity target) {
super(source);
this.entity = source;
this.target = target;
}
@Override
public @NotNull Entity getEntity() {
return entity;
}
/**
* @return the target of the attack
*/

View File

@ -1,23 +1,25 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called with {@link LivingEntity#damage(DamageType, float)}.
*/
public class EntityDamageEvent extends EntityEvent implements CancellableEvent {
public class EntityDamageEvent implements EntityEvent, CancellableEvent {
private final Entity entity;
private final DamageType damageType;
private float damage;
private boolean cancelled;
public EntityDamageEvent(@NotNull LivingEntity entity, @NotNull DamageType damageType, float damage) {
super(entity);
this.entity = entity;
this.damageType = damageType;
this.damage = damage;
}

View File

@ -1,14 +1,20 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.EntityEvent;
import org.jetbrains.annotations.NotNull;
public class EntityDeathEvent extends EntityEvent {
public class EntityDeathEvent implements EntityEvent {
// TODO cause
private final Entity entity;
public EntityDeathEvent(@NotNull Entity entity) {
super(entity);
this.entity = entity;
}
@Override
public @NotNull Entity getEntity() {
return entity;
}
}

View File

@ -1,19 +1,21 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.utils.time.TimeUnit;
import org.jetbrains.annotations.NotNull;
public class EntityFireEvent extends EntityEvent implements CancellableEvent {
public class EntityFireEvent implements EntityEvent, CancellableEvent {
private final Entity entity;
private int duration;
private TimeUnit timeUnit;
private boolean cancelled;
public EntityFireEvent(Entity entity, int duration, TimeUnit timeUnit) {
super(entity);
this.entity = entity;
setFireTime(duration, timeUnit);
}
@ -43,4 +45,9 @@ public class EntityFireEvent extends EntityEvent implements CancellableEvent {
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Entity getEntity() {
return entity;
}
}

View File

@ -1,23 +1,25 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.ItemEntity;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Called when two {@link ItemEntity} are merging their {@link ItemStack} together to form a sole entity.
*/
public class EntityItemMergeEvent extends EntityEvent implements CancellableEvent {
public class EntityItemMergeEvent implements EntityEvent, CancellableEvent {
private Entity entity;
private final ItemEntity merged;
private ItemStack result;
private boolean cancelled;
public EntityItemMergeEvent(@NotNull ItemEntity source, @NotNull ItemEntity merged, @NotNull ItemStack result) {
super(source);
this.entity = source;
this.merged = merged;
this.result = result;
}

View File

@ -1,19 +1,26 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.potion.Potion;
import org.jetbrains.annotations.NotNull;
public class EntityPotionAddEvent extends EntityEvent {
public class EntityPotionAddEvent implements EntityEvent {
private final Entity entity;
private final Potion potion;
public EntityPotionAddEvent(@NotNull Entity entity, @NotNull Potion potion) {
super(entity);
this.entity = entity;
this.potion = potion;
}
@NotNull
@Override
public Entity getEntity() {
return entity;
}
/**
* Returns the potion that was added.
*

View File

@ -1,16 +1,17 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.potion.Potion;
import org.jetbrains.annotations.NotNull;
public class EntityPotionRemoveEvent extends EntityEvent {
public class EntityPotionRemoveEvent implements EntityEvent {
private final Entity entity;
private final Potion potion;
public EntityPotionRemoveEvent(@NotNull Entity entity, @NotNull Potion potion) {
super(entity);
this.entity = entity;
this.potion = potion;
}
@ -23,4 +24,9 @@ public class EntityPotionRemoveEvent extends EntityEvent {
public Potion getPotion() {
return potion;
}
@Override
public @NotNull Entity getEntity() {
return entity;
}
}

View File

@ -1,16 +1,17 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.utils.Position;
import org.jetbrains.annotations.NotNull;
/**
* Called with {@link net.minestom.server.entity.type.projectile.EntityProjectile#shoot(Position, double, double)}
*/
public class EntityShootEvent extends EntityEvent implements CancellableEvent {
public class EntityShootEvent implements EntityEvent, CancellableEvent {
private final Entity entity;
private final Entity projectile;
private final Position to;
private double power;
@ -19,7 +20,7 @@ public class EntityShootEvent extends EntityEvent implements CancellableEvent {
private boolean cancelled;
public EntityShootEvent(@NotNull Entity entity, @NotNull Entity projectile, @NotNull Position to, double power, double spread) {
super(entity);
this.entity = entity;
this.projectile = projectile;
this.to = to;
this.power = power;
@ -90,4 +91,8 @@ public class EntityShootEvent extends EntityEvent implements CancellableEvent {
this.cancelled = cancel;
}
@Override
public @NotNull Entity getEntity() {
return entity;
}
}

View File

@ -1,19 +1,20 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
/**
* Called when a new instance is set for an entity.
*/
public class EntitySpawnEvent extends EntityEvent {
public class EntitySpawnEvent implements EntityEvent {
private final Entity entity;
private final Instance spawnInstance;
public EntitySpawnEvent(@NotNull Entity entity, @NotNull Instance spawnInstance) {
super(entity);
this.entity = entity;
this.spawnInstance = spawnInstance;
}

View File

@ -1,17 +1,23 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when an entity ticks itself.
* Same event instance used for all tick events for the same entity.
*/
public class EntityTickEvent extends EntityEvent {
public class EntityTickEvent implements EntityEvent {
private final Entity entity;
public EntityTickEvent(@NotNull Entity entity) {
super(entity);
this.entity = entity;
}
@Override
public @NotNull Entity getEntity() {
return entity;
}
}

View File

@ -1,22 +1,23 @@
package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.EntityEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.utils.Vector;
import org.jetbrains.annotations.NotNull;
/**
* Called when a velocity is applied to an entity using {@link Entity#setVelocity(Vector)}.
*/
public class EntityVelocityEvent extends EntityEvent implements CancellableEvent {
public class EntityVelocityEvent implements EntityEvent, CancellableEvent {
private final Entity entity;
private Vector velocity;
private boolean cancelled;
public EntityVelocityEvent(@NotNull Entity entity, @NotNull Vector velocity) {
super(entity);
this.entity = entity;
this.velocity = velocity;
}

View File

@ -1,184 +1,27 @@
package net.minestom.server.event.handler;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.EventCallback;
import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.extensions.IExtensionObserver;
import net.minestom.server.extras.selfmodification.MinestomRootClassLoader;
import net.minestom.server.instance.Instance;
import net.minestom.server.event.EventNode;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Stream;
/**
* Represents an element which can have {@link Event} listeners assigned to it.
* <p>
* Use {@link EventNode} directly.
*/
public interface EventHandler extends IExtensionObserver {
@Deprecated
public interface EventHandler<T extends Event> {
/**
* Gets a {@link Map} containing all the listeners assigned to a specific {@link Event} type.
*
* @return a {@link Map} with all the listeners
*/
@NotNull
Map<Class<? extends Event>, Collection<EventCallback>> getEventCallbacksMap();
@ApiStatus.Internal
@Deprecated(forRemoval = true)
@NotNull EventNode<T> getEventNode();
/**
* Gets a {@link Collection} containing all the listeners assigned to a specific extension (represented by its name).
* Used to unload all callbacks when the extension is unloaded
*
* @return a {@link Collection} with all the listeners
*/
@NotNull
Collection<EventCallback<?>> getExtensionCallbacks(String extension);
/**
* Adds a new event callback for the specified type {@code eventClass}.
*
* @param eventClass the event class
* @param eventCallback the event callback
* @param <E> the event type
* @return true if the callback collection changed as a result of the call
*/
default <E extends Event> boolean addEventCallback(@NotNull Class<E> eventClass, @NotNull EventCallback<E> eventCallback) {
String extensionSource = MinestomRootClassLoader.findExtensionObjectOwner(eventCallback);
if(extensionSource != null) {
MinecraftServer.getExtensionManager().getExtension(extensionSource).observe(this);
getExtensionCallbacks(extensionSource).add(eventCallback);
}
Collection<EventCallback> callbacks = getEventCallbacks(eventClass);
return callbacks.add(eventCallback);
@Deprecated
default <V extends T> boolean addEventCallback(@NotNull Class<V> eventClass, @NotNull EventCallback<V> eventCallback) {
var node = getEventNode();
node.addListener(eventClass, eventCallback::run);
return true;
}
/**
* Removes an event callback.
*
* @param eventClass the event class
* @param eventCallback the event callback
* @param <E> the event type
* @return true if the callback was removed as a result of this call
*/
default <E extends Event> boolean removeEventCallback(@NotNull Class<E> eventClass, @NotNull EventCallback<E> eventCallback) {
Collection<EventCallback> callbacks = getEventCallbacks(eventClass);
String extensionSource = MinestomRootClassLoader.findExtensionObjectOwner(eventCallback);
if(extensionSource != null) {
getExtensionCallbacks(extensionSource).remove(eventCallback);
}
return callbacks.remove(eventCallback);
}
/**
* Gets the event callbacks of a specific event type.
*
* @param eventClass the event class
* @param <E> the event type
* @return all event callbacks for the specified type {@code eventClass}
*/
@NotNull
default <E extends Event> Collection<EventCallback> getEventCallbacks(@NotNull Class<E> eventClass) {
return getEventCallbacksMap().computeIfAbsent(eventClass, clazz -> new CopyOnWriteArraySet<>());
}
/**
* Gets a {@link Stream} containing all the {@link EventCallback}, no matter to which {@link Event} they are linked.
*
* @return a {@link Stream} containing all the callbacks
*/
@NotNull
default Stream<EventCallback> getEventCallbacks() {
return getEventCallbacksMap().values().stream().flatMap(Collection::stream);
}
/**
* Calls the specified {@link Event} with all the assigned {@link EventCallback}.
* <p>
* Events are always called in the current thread.
*
* @param eventClass the event class
* @param event the event object
* @param <E> the event type
*/
default <E extends Event> void callEvent(@NotNull Class<E> eventClass, @NotNull E event) {
try {
// Global listeners
if (!(this instanceof GlobalEventHandler)) {
final GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
runEvent(globalEventHandler.getEventCallbacks(eventClass), event);
}
// Local listeners
final Collection<EventCallback> eventCallbacks = getEventCallbacks(eventClass);
runEvent(eventCallbacks, event);
// Call the same event for the current entity instance
if (this instanceof Entity) {
final Instance instance = ((Entity) this).getInstance();
if (instance != null) {
runEvent(instance.getEventCallbacks(eventClass), event);
}
}
} catch (Exception exception) {
MinecraftServer.getExceptionManager().handleException(exception);
}
}
/**
* Calls a {@link CancellableEvent} and execute {@code successCallback} if the {@link Event} is not cancelled.
* <p>
* Does call {@link #callEvent(Class, Event)} internally.
*
* @param eventClass the event class
* @param event the event object
* @param successCallback the callback called when the event is not cancelled
* @param <E> the event type
* @see #callEvent(Class, Event)
*/
default <E extends Event & CancellableEvent> void callCancellableEvent(@NotNull Class<E> eventClass,
@NotNull E event,
@NotNull Runnable successCallback) {
callEvent(eventClass, event);
if (!event.isCancelled()) {
successCallback.run();
}
}
/**
* Remove all event callbacks owned by the given extension
* @param extension the extension to remove callbacks from
*/
default void removeCallbacksOwnedByExtension(String extension) {
Collection<EventCallback<?>> extensionCallbacks = getExtensionCallbacks(extension);
for(EventCallback<?> callback : extensionCallbacks) {
// try to remove this callback from all callback collections
// we do this because we do not have information about the event class at this point
for(Collection<EventCallback> eventCallbacks : getEventCallbacksMap().values()) {
eventCallbacks.remove(callback);
}
}
extensionCallbacks.clear();
}
private <E extends Event> void runEvent(@NotNull Collection<EventCallback> eventCallbacks, @NotNull E event) {
for (EventCallback<E> eventCallback : eventCallbacks) {
eventCallback.run(event);
}
}
@Override
default void onExtensionUnload(String extensionName) {
removeCallbacksOwnedByExtension(extensionName);
}
}

View File

@ -1,8 +1,9 @@
package net.minestom.server.event.instance;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.InstanceEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.event.trait.InstanceEvent;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
@ -10,17 +11,23 @@ import org.jetbrains.annotations.NotNull;
* Called by an Instance when an entity is added to it.
* Can be used attach data.
*/
public class AddEntityToInstanceEvent extends InstanceEvent implements CancellableEvent {
public class AddEntityToInstanceEvent implements InstanceEvent, EntityEvent, CancellableEvent {
private final Instance instance;
private final Entity entity;
private boolean cancelled;
public AddEntityToInstanceEvent(@NotNull Instance instance, @NotNull Entity entity) {
super(instance);
this.instance = instance;
this.entity = entity;
}
@Override
public @NotNull Instance getInstance() {
return instance;
}
/**
* Entity being added.
*

View File

@ -1,22 +1,28 @@
package net.minestom.server.event.instance;
import net.minestom.server.event.InstanceEvent;
import net.minestom.server.event.trait.InstanceEvent;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
/**
* Called when a chunk in an instance is loaded.
*/
public class InstanceChunkLoadEvent extends InstanceEvent {
public class InstanceChunkLoadEvent implements InstanceEvent {
private final Instance instance;
private final int chunkX, chunkZ;
public InstanceChunkLoadEvent(@NotNull Instance instance, int chunkX, int chunkZ) {
super(instance);
this.instance = instance;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
}
@Override
public @NotNull Instance getInstance() {
return instance;
}
/**
* Gets the chunk X.
*

View File

@ -1,22 +1,28 @@
package net.minestom.server.event.instance;
import net.minestom.server.event.InstanceEvent;
import net.minestom.server.event.trait.InstanceEvent;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
/**
* Called when a chunk in an instance is unloaded.
*/
public class InstanceChunkUnloadEvent extends InstanceEvent {
public class InstanceChunkUnloadEvent implements InstanceEvent {
private final Instance instance;
private final int chunkX, chunkZ;
public InstanceChunkUnloadEvent(@NotNull Instance instance, int chunkX, int chunkZ) {
super(instance);
this.instance = instance;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
}
@Override
public @NotNull Instance getInstance() {
return instance;
}
/**
* Gets the chunk X.
*
@ -34,5 +40,4 @@ public class InstanceChunkUnloadEvent extends InstanceEvent {
public int getChunkZ() {
return chunkZ;
}
}

View File

@ -1,21 +1,27 @@
package net.minestom.server.event.instance;
import net.minestom.server.event.InstanceEvent;
import net.minestom.server.event.trait.InstanceEvent;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
/**
* Called when an instance processes a tick.
*/
public class InstanceTickEvent extends InstanceEvent {
public class InstanceTickEvent implements InstanceEvent {
private final Instance instance;
private final int duration;
public InstanceTickEvent(@NotNull Instance instance, long time, long lastTickAge) {
super(instance);
this.instance = instance;
this.duration = (int) (time - lastTickAge);
}
@Override
public @NotNull Instance getInstance() {
return instance;
}
/**
* Gets the duration of the tick in ms.
*

View File

@ -1,25 +1,32 @@
package net.minestom.server.event.instance;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.InstanceEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.event.trait.InstanceEvent;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
/**
* Called by an Instance when an entity is removed from it.
*/
public class RemoveEntityFromInstanceEvent extends InstanceEvent implements CancellableEvent {
public class RemoveEntityFromInstanceEvent implements InstanceEvent, EntityEvent, CancellableEvent {
private final Instance instance;
private final Entity entity;
private boolean cancelled;
public RemoveEntityFromInstanceEvent(@NotNull Instance instance, @NotNull Entity entity) {
super(instance);
this.instance = instance;
this.entity = entity;
}
@Override
public @NotNull Instance getInstance() {
return instance;
}
/**
* Gets the entity being removed.
*

View File

@ -1,7 +1,8 @@
package net.minestom.server.event.inventory;
import net.minestom.server.entity.Player;
import net.minestom.server.event.InventoryEvent;
import net.minestom.server.event.trait.InventoryEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.click.ClickType;
import net.minestom.server.item.ItemStack;
@ -12,8 +13,9 @@ import org.jetbrains.annotations.Nullable;
* Called after {@link InventoryPreClickEvent}, this event cannot be cancelled and items related to the click
* are already moved.
*/
public class InventoryClickEvent extends InventoryEvent {
public class InventoryClickEvent implements InventoryEvent, PlayerEvent {
private final Inventory inventory;
private final Player player;
private final int slot;
private final ClickType clickType;
@ -23,7 +25,7 @@ public class InventoryClickEvent extends InventoryEvent {
public InventoryClickEvent(@Nullable Inventory inventory, @NotNull Player player,
int slot, @NotNull ClickType clickType,
@NotNull ItemStack clicked, @NotNull ItemStack cursor) {
super(inventory);
this.inventory = inventory;
this.player = player;
this.slot = slot;
this.clickType = clickType;
@ -79,4 +81,9 @@ public class InventoryClickEvent extends InventoryEvent {
public ItemStack getCursorItem() {
return cursorItem;
}
@Override
public @Nullable Inventory getInventory() {
return inventory;
}
}

View File

@ -1,7 +1,8 @@
package net.minestom.server.event.inventory;
import net.minestom.server.entity.Player;
import net.minestom.server.event.InventoryEvent;
import net.minestom.server.event.trait.InventoryEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.inventory.Inventory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -9,13 +10,14 @@ import org.jetbrains.annotations.Nullable;
/**
* Called when an {@link Inventory} is closed by a player.
*/
public class InventoryCloseEvent extends InventoryEvent {
public class InventoryCloseEvent implements InventoryEvent, PlayerEvent {
private final Inventory inventory;
private final Player player;
private Inventory newInventory;
public InventoryCloseEvent(@Nullable Inventory inventory, @NotNull Player player) {
super(inventory);
this.inventory = inventory;
this.player = player;
}
@ -47,4 +49,9 @@ public class InventoryCloseEvent extends InventoryEvent {
public void setNewInventory(@Nullable Inventory newInventory) {
this.newInventory = newInventory;
}
@Override
public @Nullable Inventory getInventory() {
return inventory;
}
}

View File

@ -1,8 +1,9 @@
package net.minestom.server.event.inventory;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.InventoryEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.InventoryEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.inventory.Inventory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -12,14 +13,15 @@ import org.jetbrains.annotations.Nullable;
* <p>
* Executed by {@link Player#openInventory(Inventory)}.
*/
public class InventoryOpenEvent extends InventoryEvent implements CancellableEvent {
public class InventoryOpenEvent implements InventoryEvent, PlayerEvent, CancellableEvent {
private Inventory inventory;
private final Player player;
private boolean cancelled;
public InventoryOpenEvent(@Nullable Inventory inventory, @NotNull Player player) {
super(inventory);
this.inventory = inventory;
this.player = player;
}

View File

@ -1,8 +1,9 @@
package net.minestom.server.event.inventory;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.InventoryEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.InventoryEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.click.ClickType;
import net.minestom.server.item.ItemStack;
@ -12,8 +13,9 @@ import org.jetbrains.annotations.Nullable;
/**
* Called before {@link InventoryClickEvent}, used to potentially cancel the click.
*/
public class InventoryPreClickEvent extends InventoryEvent implements CancellableEvent {
public class InventoryPreClickEvent implements InventoryEvent, PlayerEvent, CancellableEvent {
private final Inventory inventory;
private final Player player;
private final int slot;
private final ClickType clickType;
@ -26,7 +28,7 @@ public class InventoryPreClickEvent extends InventoryEvent implements Cancellabl
@NotNull Player player,
int slot, @NotNull ClickType clickType,
@NotNull ItemStack clicked, @NotNull ItemStack cursor) {
super(inventory);
this.inventory = inventory;
this.player = player;
this.slot = slot;
this.clickType = clickType;
@ -110,4 +112,9 @@ public class InventoryPreClickEvent extends InventoryEvent implements Cancellabl
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @Nullable Inventory getInventory() {
return inventory;
}
}

View File

@ -2,11 +2,12 @@ package net.minestom.server.event.item;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EquipmentSlot;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.event.trait.ItemEvent;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
public class EntityEquipEvent extends Event {
public class EntityEquipEvent implements EntityEvent, ItemEvent {
private final Entity entity;
private ItemStack equippedItem;
@ -18,13 +19,7 @@ public class EntityEquipEvent extends Event {
this.slot = slot;
}
@NotNull
public Entity getEntity() {
return entity;
}
@NotNull
public ItemStack getEquippedItem() {
public @NotNull ItemStack getEquippedItem() {
return equippedItem;
}
@ -32,8 +27,20 @@ public class EntityEquipEvent extends Event {
this.equippedItem = armorItem;
}
@NotNull
public EquipmentSlot getSlot() {
public @NotNull EquipmentSlot getSlot() {
return slot;
}
/**
* Same as {@link #getEquippedItem()}.
*/
@Override
public @NotNull ItemStack getItemStack() {
return equippedItem;
}
@Override
public @NotNull Entity getEntity() {
return entity;
}
}

View File

@ -1,12 +1,13 @@
package net.minestom.server.event.item;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.ItemEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
public class ItemDropEvent extends Event implements CancellableEvent {
public class ItemDropEvent implements PlayerEvent, ItemEvent, CancellableEvent {
private final Player player;
private final ItemStack itemStack;
@ -18,8 +19,8 @@ public class ItemDropEvent extends Event implements CancellableEvent {
this.itemStack = itemStack;
}
@NotNull
public Player getPlayer() {
@Override
public @NotNull Player getPlayer() {
return player;
}
@ -37,4 +38,5 @@ public class ItemDropEvent extends Event implements CancellableEvent {
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
}

View File

@ -1,11 +1,12 @@
package net.minestom.server.event.item;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.ItemEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
public class ItemUpdateStateEvent extends Event {
public class ItemUpdateStateEvent implements PlayerEvent, ItemEvent {
private final Player player;
private final Player.Hand hand;
@ -18,21 +19,11 @@ public class ItemUpdateStateEvent extends Event {
this.itemStack = itemStack;
}
@NotNull
public Player getPlayer() {
return player;
}
@NotNull
public Player.Hand getHand() {
return hand;
}
@NotNull
public ItemStack getItemStack() {
return itemStack;
}
public void setHandAnimation(boolean handAnimation) {
this.handAnimation = handAnimation;
}
@ -40,4 +31,14 @@ public class ItemUpdateStateEvent extends Event {
public boolean hasHandAnimation() {
return handAnimation;
}
@Override
public @NotNull ItemStack getItemStack() {
return itemStack;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,11 +1,10 @@
package net.minestom.server.event.item;
import net.minestom.server.entity.ExperienceOrb;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.CancellableEvent;
import org.jetbrains.annotations.NotNull;
public class PickupExperienceEvent extends Event implements CancellableEvent {
public class PickupExperienceEvent implements CancellableEvent {
private final ExperienceOrb experienceOrb;
private short experienceCount;

View File

@ -1,13 +1,15 @@
package net.minestom.server.event.item;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.ItemEntity;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.EntityEvent;
import net.minestom.server.event.trait.ItemEvent;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
public class PickupItemEvent extends Event implements CancellableEvent {
public class PickupItemEvent implements EntityEvent, ItemEvent, CancellableEvent {
private final LivingEntity livingEntity;
private final ItemEntity itemEntity;
@ -29,10 +31,6 @@ public class PickupItemEvent extends Event implements CancellableEvent {
return itemEntity;
}
/**
* @deprecated use {@link #getItemEntity()} and {@link ItemEntity#getItemStack()}.
*/
@Deprecated
@NotNull
public ItemStack getItemStack() {
return getItemEntity().getItemStack();
@ -47,4 +45,9 @@ public class PickupItemEvent extends Event implements CancellableEvent {
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Entity getEntity() {
return livingEntity;
}
}

View File

@ -2,20 +2,22 @@ package net.minestom.server.event.player;
import net.minestom.server.advancements.AdvancementAction;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a {@link Player} opens the advancement screens or switch the tab
* and when he closes the screen.
*/
public class AdvancementTabEvent extends PlayerEvent {
public class AdvancementTabEvent implements PlayerEvent {
private final Player player;
private final AdvancementAction action;
private final String tabId;
public AdvancementTabEvent(@NotNull Player player, @NotNull AdvancementAction action, @NotNull String tabId) {
super(player);
this.player = player;
this.action = action;
this.tabId = tabId;
}
@ -41,4 +43,9 @@ public class AdvancementTabEvent extends PlayerEvent {
public String getTabId() {
return tabId;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,7 +1,8 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
@ -10,13 +11,14 @@ import java.util.UUID;
* Called before the player initialization, it can be used to kick the player before any connection
* or to change his final username/uuid.
*/
public class AsyncPlayerPreLoginEvent extends PlayerEvent {
public class AsyncPlayerPreLoginEvent implements PlayerEvent {
private final Player player;
private String username;
private UUID playerUuid;
public AsyncPlayerPreLoginEvent(@NotNull Player player, @NotNull String username, @NotNull UUID playerUuid) {
super(player);
this.player = player;
this.username = username;
this.playerUuid = playerUuid;
}
@ -58,4 +60,9 @@ public class AsyncPlayerPreLoginEvent extends PlayerEvent {
public void setPlayerUuid(@NotNull UUID playerUuid) {
this.playerUuid = playerUuid;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -2,8 +2,8 @@ package net.minestom.server.event.player;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.utils.BlockPosition;
@ -11,10 +11,11 @@ import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PlayerBlockBreakEvent extends PlayerEvent implements CancellableEvent {
public class PlayerBlockBreakEvent implements PlayerEvent, CancellableEvent {
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
private final Player player;
private final BlockPosition blockPosition;
private final short blockStateId;
@ -28,7 +29,7 @@ public class PlayerBlockBreakEvent extends PlayerEvent implements CancellableEve
public PlayerBlockBreakEvent(@NotNull Player player, @NotNull BlockPosition blockPosition,
short blockStateId, @Nullable CustomBlock customBlock,
short resultBlockStateId, short resultCustomBlockId) {
super(player);
this.player = player;
this.blockPosition = blockPosition;
@ -151,4 +152,9 @@ public class PlayerBlockBreakEvent extends PlayerEvent implements CancellableEve
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,8 +1,8 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.utils.BlockPosition;
import org.jetbrains.annotations.NotNull;
@ -11,8 +11,9 @@ import org.jetbrains.annotations.NotNull;
* Called when a player interacts with a block (right-click).
* This is also called when a block is placed.
*/
public class PlayerBlockInteractEvent extends PlayerEvent implements CancellableEvent {
public class PlayerBlockInteractEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private final BlockPosition blockPosition;
private final Player.Hand hand;
private final BlockFace blockFace;
@ -27,7 +28,7 @@ public class PlayerBlockInteractEvent extends PlayerEvent implements Cancellable
public PlayerBlockInteractEvent(@NotNull Player player,
@NotNull BlockPosition blockPosition, @NotNull Player.Hand hand, @NotNull BlockFace blockFace) {
super(player);
this.player = player;
this.blockPosition = blockPosition;
this.hand = hand;
this.blockFace = blockFace;
@ -85,4 +86,9 @@ public class PlayerBlockInteractEvent extends PlayerEvent implements Cancellable
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -3,8 +3,8 @@ package net.minestom.server.event.player;
import net.minestom.server.MinecraftServer;
import net.minestom.server.data.Data;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.CustomBlock;
@ -16,10 +16,11 @@ import org.jetbrains.annotations.Nullable;
/**
* Called when a player tries placing a block.
*/
public class PlayerBlockPlaceEvent extends PlayerEvent implements CancellableEvent {
public class PlayerBlockPlaceEvent implements PlayerEvent, CancellableEvent {
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
private final Player player;
private short blockStateId;
private short customBlockId;
private Data blockData;
@ -32,7 +33,7 @@ public class PlayerBlockPlaceEvent extends PlayerEvent implements CancellableEve
public PlayerBlockPlaceEvent(@NotNull Player player, @NotNull Block block,
@NotNull BlockPosition blockPosition, @NotNull Player.Hand hand) {
super(player);
this.player = player;
this.blockStateId = block.getBlockId();
this.blockPosition = blockPosition;
this.hand = hand;
@ -176,4 +177,9 @@ public class PlayerBlockPlaceEvent extends PlayerEvent implements CancellableEve
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,8 +1,8 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
@ -10,14 +10,15 @@ import org.jetbrains.annotations.NotNull;
/**
* Called when a player change his held slot (by pressing 1-9 keys).
*/
public class PlayerChangeHeldSlotEvent extends PlayerEvent implements CancellableEvent {
public class PlayerChangeHeldSlotEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private byte slot;
private boolean cancelled;
public PlayerChangeHeldSlotEvent(@NotNull Player player, byte slot) {
super(player);
this.player = player;
this.slot = slot;
}
@ -50,4 +51,9 @@ public class PlayerChangeHeldSlotEvent extends PlayerEvent implements Cancellabl
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -3,8 +3,8 @@ package net.minestom.server.event.player;
import net.kyori.adventure.text.Component;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -17,8 +17,9 @@ import java.util.function.Supplier;
* Called every time a {@link Player} write and send something in the chat.
* The event can be cancelled to do not send anything, and the format can be changed.
*/
public class PlayerChatEvent extends PlayerEvent implements CancellableEvent {
public class PlayerChatEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private final Collection<Player> recipients;
private final Supplier<Component> defaultChatFormat;
private String message;
@ -29,7 +30,7 @@ public class PlayerChatEvent extends PlayerEvent implements CancellableEvent {
public PlayerChatEvent(@NotNull Player player, @NotNull Collection<Player> recipients,
@NotNull Supplier<Component> defaultChatFormat,
@NotNull String message) {
super(player);
this.player = player;
this.recipients = new ArrayList<>(recipients);
this.defaultChatFormat = defaultChatFormat;
this.message = message;
@ -108,4 +109,9 @@ public class PlayerChatEvent extends PlayerEvent implements CancellableEvent {
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,18 +1,20 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player receive a new chunk data.
*/
public class PlayerChunkLoadEvent extends PlayerEvent {
public class PlayerChunkLoadEvent implements PlayerEvent {
private final Player player;
private final int chunkX, chunkZ;
public PlayerChunkLoadEvent(@NotNull Player player, int chunkX, int chunkZ) {
super(player);
this.player = player;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
}
@ -34,4 +36,9 @@ public class PlayerChunkLoadEvent extends PlayerEvent {
public int getChunkZ() {
return chunkZ;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,7 +1,8 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
@ -9,12 +10,13 @@ import org.jetbrains.annotations.NotNull;
* <p>
* Could be used to unload the chunk internally in order to save memory.
*/
public class PlayerChunkUnloadEvent extends PlayerEvent {
public class PlayerChunkUnloadEvent implements PlayerEvent {
private final Player player;
private final int chunkX, chunkZ;
public PlayerChunkUnloadEvent(@NotNull Player player, int chunkX, int chunkZ) {
super(player);
this.player = player;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
}
@ -36,4 +38,9 @@ public class PlayerChunkUnloadEvent extends PlayerEvent {
public int getChunkZ() {
return chunkZ;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,21 +1,22 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called every time a player send a message starting by '/'.
*/
public class PlayerCommandEvent extends PlayerEvent implements CancellableEvent {
public class PlayerCommandEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private String command;
private boolean cancelled;
public PlayerCommandEvent(@NotNull Player player, @NotNull String command) {
super(player);
this.player = player;
this.command = command;
}
@ -47,4 +48,9 @@ public class PlayerCommandEvent extends PlayerEvent implements CancellableEvent
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -3,15 +3,17 @@ package net.minestom.server.event.player;
import net.kyori.adventure.text.Component;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Called when a player die in {@link Player#kill()}.
*/
public class PlayerDeathEvent extends PlayerEvent {
public class PlayerDeathEvent implements PlayerEvent {
private final Player player;
private Component deathText;
private Component chatMessage;
@ -24,7 +26,7 @@ public class PlayerDeathEvent extends PlayerEvent {
}
public PlayerDeathEvent(@NotNull Player player, Component deathText, Component chatMessage) {
super(player);
this.player = player;
this.deathText = deathText;
this.chatMessage = chatMessage;
}
@ -112,4 +114,9 @@ public class PlayerDeathEvent extends PlayerEvent {
public void setChatMessage(@Nullable Component chatMessage) {
this.chatMessage = chatMessage;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,15 +1,23 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player disconnect.
*/
public class PlayerDisconnectEvent extends PlayerEvent {
public class PlayerDisconnectEvent implements PlayerEvent {
private final Player player;
public PlayerDisconnectEvent(@NotNull Player player) {
super(player);
this.player = player;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,20 +1,22 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player is finished eating.
*/
public class PlayerEatEvent extends PlayerEvent {
public class PlayerEatEvent implements PlayerEvent {
private final Player player;
private final ItemStack foodItem;
private final Player.Hand hand;
public PlayerEatEvent(@NotNull Player player, @NotNull ItemStack foodItem, @NotNull Player.Hand hand) {
super(player);
this.player = player;
this.foodItem = foodItem;
this.hand = hand;
}
@ -31,4 +33,9 @@ public class PlayerEatEvent extends PlayerEvent {
public @NotNull Player.Hand getHand() {
return hand;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -2,19 +2,21 @@ package net.minestom.server.event.player;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a {@link Player} interacts (right-click) with an {@link Entity}.
*/
public class PlayerEntityInteractEvent extends PlayerEvent {
public class PlayerEntityInteractEvent implements PlayerEvent {
private final Player player;
private final Entity entityTarget;
private final Player.Hand hand;
public PlayerEntityInteractEvent(@NotNull Player player, @NotNull Entity entityTarget, @NotNull Player.Hand hand) {
super(player);
this.player = player;
this.entityTarget = entityTarget;
this.hand = hand;
}
@ -38,4 +40,9 @@ public class PlayerEntityInteractEvent extends PlayerEvent {
public Player.Hand getHand() {
return hand;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,21 +1,22 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when the player swings his hand.
*/
public class PlayerHandAnimationEvent extends PlayerEvent implements CancellableEvent {
public class PlayerHandAnimationEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private final Player.Hand hand;
private boolean cancelled;
public PlayerHandAnimationEvent(@NotNull Player player, @NotNull Player.Hand hand) {
super(player);
this.player = player;
this.hand = hand;
}
@ -38,4 +39,9 @@ public class PlayerHandAnimationEvent extends PlayerEvent implements Cancellable
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,8 +1,8 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
@ -10,14 +10,15 @@ import org.jetbrains.annotations.NotNull;
*
* @see ItemAnimationType
*/
public class PlayerItemAnimationEvent extends PlayerEvent implements CancellableEvent {
public class PlayerItemAnimationEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private final ItemAnimationType armAnimationType;
private boolean cancelled;
public PlayerItemAnimationEvent(@NotNull Player player, @NotNull ItemAnimationType armAnimationType) {
super(player);
this.player = player;
this.armAnimationType = armAnimationType;
}
@ -31,6 +32,11 @@ public class PlayerItemAnimationEvent extends PlayerEvent implements Cancellable
return armAnimationType;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
public enum ItemAnimationType {
BOW,
CROSSBOW,

View File

@ -1,7 +1,8 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -16,12 +17,13 @@ import org.jetbrains.annotations.Nullable;
* <p>
* WARNING: defining the spawning instance is MANDATORY.
*/
public class PlayerLoginEvent extends PlayerEvent {
public class PlayerLoginEvent implements PlayerEvent {
private final Player player;
private Instance spawningInstance;
public PlayerLoginEvent(@NotNull Player player) {
super(player);
this.player = player;
}
/**
@ -44,4 +46,9 @@ public class PlayerLoginEvent extends PlayerEvent {
public void setSpawningInstance(@NotNull Instance instance) {
this.spawningInstance = instance;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,22 +1,23 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.utils.Position;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player is modifying his position.
*/
public class PlayerMoveEvent extends PlayerEvent implements CancellableEvent {
public class PlayerMoveEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private Position newPosition;
private boolean cancelled;
public PlayerMoveEvent(@NotNull Player player, @NotNull Position newPosition) {
super(player);
this.player = player;
this.newPosition = newPosition;
}
@ -48,4 +49,9 @@ public class PlayerMoveEvent extends PlayerEvent implements CancellableEvent {
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -0,0 +1,38 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
public class PlayerPacketEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private final ClientPacket packet;
private boolean cancelled;
public PlayerPacketEvent(Player player, ClientPacket packet) {
this.player = player;
this.packet = packet;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
public @NotNull ClientPacket getPacket() {
return packet;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
}

View File

@ -1,19 +1,21 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player send {@link net.minestom.server.network.packet.client.play.ClientPluginMessagePacket}.
*/
public class PlayerPluginMessageEvent extends PlayerEvent {
public class PlayerPluginMessageEvent implements PlayerEvent {
private final Player player;
private final String identifier;
private final byte[] message;
public PlayerPluginMessageEvent(@NotNull Player player, @NotNull String identifier, @NotNull byte[] message) {
super(player);
this.player = player;
this.identifier = identifier;
this.message = message;
}
@ -47,4 +49,9 @@ public class PlayerPluginMessageEvent extends PlayerEvent {
public String getMessageString() {
return new String(message);
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,8 +1,8 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
@ -11,8 +11,9 @@ import org.jetbrains.annotations.NotNull;
* or to cancel its processing, cancelling the event means that the player will
* continue the animation indefinitely.
*/
public class PlayerPreEatEvent extends PlayerEvent implements CancellableEvent {
public class PlayerPreEatEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private final ItemStack foodItem;
private final Player.Hand hand;
private long eatingTime;
@ -20,7 +21,7 @@ public class PlayerPreEatEvent extends PlayerEvent implements CancellableEvent {
private boolean cancelled;
public PlayerPreEatEvent(@NotNull Player player, @NotNull ItemStack foodItem, @NotNull Player.Hand hand, long eatingTime) {
super(player);
this.player = player;
this.foodItem = foodItem;
this.hand = hand;
this.eatingTime = eatingTime;
@ -68,4 +69,9 @@ public class PlayerPreEatEvent extends PlayerEvent implements CancellableEvent {
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,19 +1,21 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.resourcepack.ResourcePackStatus;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player warns the server of a resource pack status.
*/
public class PlayerResourcePackStatusEvent extends PlayerEvent {
public class PlayerResourcePackStatusEvent implements PlayerEvent {
private final Player player;
private final ResourcePackStatus status;
public PlayerResourcePackStatusEvent(@NotNull Player player, @NotNull ResourcePackStatus status) {
super(player);
this.player = player;
this.status = status;
}
@ -26,4 +28,9 @@ public class PlayerResourcePackStatusEvent extends PlayerEvent {
public ResourcePackStatus getStatus() {
return status;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,7 +1,8 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.utils.Position;
import org.jetbrains.annotations.NotNull;
@ -9,12 +10,13 @@ import org.jetbrains.annotations.NotNull;
* Called when {@link Player#respawn()} is executed (for custom respawn or as a result of
* {@link net.minestom.server.network.packet.client.play.ClientStatusPacket}
*/
public class PlayerRespawnEvent extends PlayerEvent {
public class PlayerRespawnEvent implements PlayerEvent {
private final Player player;
private Position respawnPosition;
public PlayerRespawnEvent(@NotNull Player player) {
super(player);
this.player = player;
this.respawnPosition = player.getRespawnPoint();
}
@ -38,4 +40,9 @@ public class PlayerRespawnEvent extends PlayerEvent {
public void setRespawnPosition(@NotNull Position respawnPosition) {
this.respawnPosition = respawnPosition;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,16 +1,19 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called after the player signals the server that his settings has been modified.
*/
public class PlayerSettingsChangeEvent extends PlayerEvent {
public class PlayerSettingsChangeEvent implements PlayerEvent {
private final Player player;
public PlayerSettingsChangeEvent(@NotNull Player player) {
super(player);
this.player = player;
}
/**

View File

@ -2,19 +2,21 @@ package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.PlayerSkin;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Called at the player connection to initialize his skin.
*/
public class PlayerSkinInitEvent extends PlayerEvent {
public class PlayerSkinInitEvent implements PlayerEvent {
private final Player player;
private PlayerSkin skin;
public PlayerSkinInitEvent(@NotNull Player player, @Nullable PlayerSkin currentSkin) {
super(player);
this.player = player;
this.skin = currentSkin;
}
@ -36,4 +38,9 @@ public class PlayerSkinInitEvent extends PlayerEvent {
public void setSkin(@Nullable PlayerSkin skin) {
this.skin = skin;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,20 +1,22 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
/**
* Called when a new instance is set for a player.
*/
public class PlayerSpawnEvent extends PlayerEvent {
public class PlayerSpawnEvent implements PlayerEvent {
private final Player player;
private final Instance spawnInstance;
private final boolean firstSpawn;
public PlayerSpawnEvent(@NotNull Player player, @NotNull Instance spawnInstance, boolean firstSpawn) {
super(player);
this.player = player;
this.spawnInstance = spawnInstance;
this.firstSpawn = firstSpawn;
}
@ -37,4 +39,9 @@ public class PlayerSpawnEvent extends PlayerEvent {
public boolean isFirstSpawn() {
return firstSpawn;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,8 +1,8 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.utils.BlockPosition;
import org.jetbrains.annotations.NotNull;
@ -14,8 +14,9 @@ import org.jetbrains.annotations.NotNull;
* (could be because of high latency or a modified client) so cancelling {@link PlayerBlockBreakEvent} is also necessary.
* Could be fixed in future Minestom version.
*/
public class PlayerStartDiggingEvent extends PlayerEvent implements CancellableEvent {
public class PlayerStartDiggingEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private final BlockPosition blockPosition;
private final int blockStateId;
private final int customBlockId;
@ -23,7 +24,7 @@ public class PlayerStartDiggingEvent extends PlayerEvent implements CancellableE
private boolean cancelled;
public PlayerStartDiggingEvent(@NotNull Player player, @NotNull BlockPosition blockPosition, int blockStateId, int customBlockId) {
super(player);
this.player = player;
this.blockPosition = blockPosition;
this.blockStateId = blockStateId;
this.customBlockId = customBlockId;
@ -66,4 +67,9 @@ public class PlayerStartDiggingEvent extends PlayerEvent implements CancellableE
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,15 +1,23 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player start flying.
*/
public class PlayerStartFlyingEvent extends PlayerEvent {
public class PlayerStartFlyingEvent implements PlayerEvent {
private final Player player;
public PlayerStartFlyingEvent(@NotNull Player player) {
super(player);
this.player = player;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,12 +1,20 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
public class PlayerStartFlyingWithElytraEvent extends PlayerEvent {
public class PlayerStartFlyingWithElytraEvent implements PlayerEvent {
private final Player player;
public PlayerStartFlyingWithElytraEvent(@NotNull Player player) {
super(player);
this.player = player;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,15 +1,23 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player starts sneaking.
*/
public class PlayerStartSneakingEvent extends PlayerEvent {
public class PlayerStartSneakingEvent implements PlayerEvent {
private final Player player;
public PlayerStartSneakingEvent(@NotNull Player player) {
super(player);
this.player = player;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,15 +1,23 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player starts sprinting.
*/
public class PlayerStartSprintingEvent extends PlayerEvent {
public class PlayerStartSprintingEvent implements PlayerEvent {
private final Player player;
public PlayerStartSprintingEvent(@NotNull Player player) {
super(player);
this.player = player;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,15 +1,23 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player stop flying.
*/
public class PlayerStopFlyingEvent extends PlayerEvent {
public class PlayerStopFlyingEvent implements PlayerEvent {
private final Player player;
public PlayerStopFlyingEvent(@NotNull Player player) {
super(player);
this.player = player;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,12 +1,20 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
public class PlayerStopFlyingWithElytraEvent extends PlayerEvent {
public class PlayerStopFlyingWithElytraEvent implements PlayerEvent {
private final Player player;
public PlayerStopFlyingWithElytraEvent(@NotNull Player player) {
super(player);
this.player = player;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,15 +1,23 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player stops sneaking.
*/
public class PlayerStopSneakingEvent extends PlayerEvent {
public class PlayerStopSneakingEvent implements PlayerEvent {
private final Player player;
public PlayerStopSneakingEvent(@NotNull Player player) {
super(player);
this.player = player;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,15 +1,23 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player stops sprinting.
*/
public class PlayerStopSprintingEvent extends PlayerEvent {
public class PlayerStopSprintingEvent implements PlayerEvent {
private final Player player;
public PlayerStopSprintingEvent(@NotNull Player player) {
super(player);
this.player = player;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,23 +1,24 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player is trying to swap his main and off hand item.
*/
public class PlayerSwapItemEvent extends PlayerEvent implements CancellableEvent {
public class PlayerSwapItemEvent implements PlayerEvent, CancellableEvent {
private final Player player;
private ItemStack mainHandItem;
private ItemStack offHandItem;
private boolean cancelled;
public PlayerSwapItemEvent(@NotNull Player player, @NotNull ItemStack mainHandItem, @NotNull ItemStack offHandItem) {
super(player);
this.player = player;
this.mainHandItem = mainHandItem;
this.offHandItem = offHandItem;
}
@ -69,4 +70,9 @@ public class PlayerSwapItemEvent extends PlayerEvent implements CancellableEvent
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,15 +1,22 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called at each player tick.
*/
public class PlayerTickEvent extends PlayerEvent {
public class PlayerTickEvent implements PlayerEvent {
private final Player player;
public PlayerTickEvent(@NotNull Player player) {
super(player);
this.player = player;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,23 +1,25 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.ItemEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Event when an item is used without clicking on a block.
*/
public class PlayerUseItemEvent extends PlayerEvent implements CancellableEvent {
public class PlayerUseItemEvent implements PlayerEvent, ItemEvent, CancellableEvent {
private final Player player;
private final Player.Hand hand;
private final ItemStack itemStack;
private boolean cancelled;
public PlayerUseItemEvent(@NotNull Player player, @NotNull Player.Hand hand, @NotNull ItemStack itemStack) {
super(player);
this.player = player;
this.hand = hand;
this.itemStack = itemStack;
}
@ -51,4 +53,9 @@ public class PlayerUseItemEvent extends PlayerEvent implements CancellableEvent
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -1,7 +1,8 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.PlayerEvent;
import net.minestom.server.event.trait.ItemEvent;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Direction;
@ -10,8 +11,9 @@ import org.jetbrains.annotations.NotNull;
/**
* Used when a player is clicking on a block with an item (but is not a block in item form).
*/
public class PlayerUseItemOnBlockEvent extends PlayerEvent {
public class PlayerUseItemOnBlockEvent implements PlayerEvent, ItemEvent {
private final Player player;
private final Player.Hand hand;
private final ItemStack itemStack;
private final BlockPosition position;
@ -20,7 +22,7 @@ public class PlayerUseItemOnBlockEvent extends PlayerEvent {
public PlayerUseItemOnBlockEvent(@NotNull Player player, @NotNull Player.Hand hand,
@NotNull ItemStack itemStack,
@NotNull BlockPosition position, @NotNull Direction blockFace) {
super(player);
this.player = player;
this.hand = hand;
this.itemStack = itemStack;
this.position = position;
@ -66,4 +68,9 @@ public class PlayerUseItemOnBlockEvent extends PlayerEvent {
public ItemStack getItemStack() {
return itemStack;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
}

View File

@ -5,7 +5,7 @@ import net.minestom.server.network.packet.server.play.TagsPacket;
import org.jetbrains.annotations.NotNull;
@Deprecated
public class UpdateTagListEvent extends Event {
public class UpdateTagListEvent implements Event {
private TagsPacket packet;

View File

@ -1,7 +1,6 @@
package net.minestom.server.event.server;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
@ -14,7 +13,7 @@ import org.jetbrains.annotations.NotNull;
*
* @see ServerListPingEvent
*/
public class ClientPingServerEvent extends Event implements CancellableEvent {
public class ClientPingServerEvent implements CancellableEvent {
private static final UpdateOption DEFAULT_DELAY = new UpdateOption(0, TimeUnit.MILLISECOND);
private final PlayerConnection connection;
@ -27,7 +26,7 @@ public class ClientPingServerEvent extends Event implements CancellableEvent {
* Creates a new client ping server event with 0 delay
*
* @param connection the player connection
* @param payload the payload the client sent
* @param payload the payload the client sent
*/
public ClientPingServerEvent(@NotNull PlayerConnection connection, long payload) {
this.connection = connection;
@ -39,7 +38,7 @@ public class ClientPingServerEvent extends Event implements CancellableEvent {
* Creates a new client ping server event with 0 delay
*
* @param connection the player connection
* @param payload the payload the client sent
* @param payload the payload the client sent
*/
public ClientPingServerEvent(@NotNull PlayerConnection connection, long payload, UpdateOption delay) {
this.connection = connection;
@ -69,8 +68,9 @@ public class ClientPingServerEvent extends Event implements CancellableEvent {
/**
* Sets the payload to respond with.
*
* <p>
* Note: This should be the same as the client sent, however vanilla 1.17 seems to be OK with a different payload.
*
* @param payload the payload
*/
public void setPayload(long payload) {

View File

@ -1,8 +1,7 @@
package net.minestom.server.event.server;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.ping.ResponseData;
import net.minestom.server.ping.ResponseDataConsumer;
@ -16,7 +15,7 @@ import java.util.Objects;
* Called when a {@link PlayerConnection} sends a status packet,
* usually to display information on the server list.
*/
public class ServerListPingEvent extends Event implements CancellableEvent {
public class ServerListPingEvent implements CancellableEvent {
private final PlayerConnection connection;
private final ServerListPingType type;
@ -36,7 +35,7 @@ public class ServerListPingEvent extends Event implements CancellableEvent {
* Creates a new server list ping event.
*
* @param connection the player connection, if the ping type is modern
* @param type the ping type to respond with
* @param type the ping type to respond with
*/
public ServerListPingEvent(@Nullable PlayerConnection connection, @NotNull ServerListPingType type) {
//noinspection deprecation we need to continue doing this until the consumer is removed - todo remove
@ -86,7 +85,7 @@ public class ServerListPingEvent extends Event implements CancellableEvent {
* @return the ping type
*/
public @NotNull ServerListPingType getPingType() {
return type;
return type;
}
@Override

View File

@ -1,9 +1,13 @@
package net.minestom.server.event;
package net.minestom.server.event.trait;
import net.minestom.server.event.Event;
import net.minestom.server.event.EventDispatcher;
/**
* Represents an {@link Event} which can be cancelled.
* Called using {@link EventDispatcher#callCancellable(CancellableEvent, Runnable)}.
*/
public interface CancellableEvent {
public interface CancellableEvent extends Event {
/**
* Gets if the {@link Event} should be cancelled or not.
@ -18,5 +22,4 @@ public interface CancellableEvent {
* @param cancel true if the event should be cancelled, false otherwise
*/
void setCancelled(boolean cancel);
}

View File

@ -0,0 +1,18 @@
package net.minestom.server.event.trait;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.Event;
import org.jetbrains.annotations.NotNull;
/**
* Represents any event called on an {@link Entity}.
*/
public interface EntityEvent extends Event {
/**
* Gets the entity of this event.
*
* @return the entity
*/
@NotNull Entity getEntity();
}

View File

@ -0,0 +1,18 @@
package net.minestom.server.event.trait;
import net.minestom.server.event.Event;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
/**
* Represents any event targeting an {@link Instance}.
*/
public interface InstanceEvent extends Event {
/**
* Gets the instance.
*
* @return instance
*/
@NotNull Instance getInstance();
}

View File

@ -0,0 +1,18 @@
package net.minestom.server.event.trait;
import net.minestom.server.event.Event;
import net.minestom.server.inventory.Inventory;
import org.jetbrains.annotations.Nullable;
/**
* Represents any event inside an {@link Inventory}.
*/
public interface InventoryEvent extends Event {
/**
* Gets the inventory.
*
* @return the inventory, null if this is a player's inventory
*/
@Nullable Inventory getInventory();
}

View File

@ -0,0 +1,12 @@
package net.minestom.server.event.trait;
import net.minestom.server.event.Event;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Represents any event called about an {@link ItemStack}.
*/
public interface ItemEvent extends Event {
@NotNull ItemStack getItemStack();
}

View File

@ -0,0 +1,25 @@
package net.minestom.server.event.trait;
import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Represents any event called on a {@link Player}.
*/
public interface PlayerEvent extends EntityEvent {
/**
* Gets the player.
*
* @return the player
*/
@NotNull Player getPlayer();
/**
* Returns {@link #getPlayer()}.
*/
@Override
default @NotNull Player getEntity() {
return getPlayer();
}
}

View File

@ -1,5 +1,7 @@
package net.minestom.server.extensions;
import net.minestom.server.event.Event;
import net.minestom.server.event.EventNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@ -14,7 +16,9 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
@ -25,6 +29,9 @@ public abstract class Extension {
// Set by reflection
@SuppressWarnings("unused")
private Logger logger;
// Set by reflection
@SuppressWarnings("unused")
private EventNode<Event> eventNode;
/**
* Observers that will be notified of events related to this extension.
@ -78,6 +85,7 @@ public abstract class Extension {
/**
* Gets the logger for the extension
*
* @return The logger for the extension
*/
@NotNull
@ -85,6 +93,10 @@ public abstract class Extension {
return logger;
}
public @NotNull EventNode<Event> getEventNode() {
return eventNode;
}
public @NotNull Path getDataDirectory() {
return getOrigin().getDataDirectory();
}
@ -209,6 +221,7 @@ public abstract class Extension {
/**
* Calls some action on all valid observers of this extension
*
* @param action code to execute on each observer
*/
public void triggerChange(Consumer<IExtensionObserver> action) {
@ -234,7 +247,7 @@ public abstract class Extension {
*/
public void cleanupObservers() {
Reference<? extends IExtensionObserver> ref;
while((ref = observerReferenceQueue.poll()) != null) {
while ((ref = observerReferenceQueue.poll()) != null) {
observers.remove(ref);
}
}

View File

@ -5,6 +5,8 @@ import net.minestom.dependencies.DependencyGetter;
import net.minestom.dependencies.ResolvedDependency;
import net.minestom.dependencies.maven.MavenRepository;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.Event;
import net.minestom.server.event.EventNode;
import net.minestom.server.extras.selfmodification.MinestomExtensionClassLoader;
import net.minestom.server.extras.selfmodification.MinestomRootClassLoader;
import net.minestom.server.ping.ResponseDataConsumer;
@ -25,7 +27,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipFile;
@ -280,6 +281,22 @@ public class ExtensionManager {
LOGGER.error("Main class '{}' in '{}' has no logger field.", mainClass, extensionName, e);
}
// Set event node
try {
EventNode<Event> eventNode = EventNode.all(extensionName); // Use the extension name
Field loggerField = Extension.class.getDeclaredField("eventNode");
loggerField.setAccessible(true);
loggerField.set(extension, eventNode);
MinecraftServer.getGlobalEventHandler().addChild(eventNode);
} catch (IllegalAccessException e) {
// We made it accessible, should not occur
MinecraftServer.getExceptionManager().handleException(e);
} catch (NoSuchFieldException e) {
// This should also not occur
LOGGER.error("Main class '{}' in '{}' has no event node field.", mainClass, extensionName, e);
}
// add dependents to pre-existing extensions, so that they can easily be found during reloading
for (String dependencyName : discoveredExtension.getDependencies()) {
Extension dependency = extensions.get(dependencyName.toLowerCase());
@ -660,6 +677,10 @@ public class ExtensionManager {
ext.triggerChange(observer -> observer.onExtensionUnload(extensionName));
// TODO: more callback types
// Remove event node
EventNode<Event> eventNode = ext.getEventNode();
MinecraftServer.getGlobalEventHandler().removeChild(eventNode);
ext.postTerminate();
ext.unload();

View File

@ -1,6 +1,7 @@
package net.minestom.server.extras.lan;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.server.ServerListPingEvent;
import net.minestom.server.timer.Task;
import net.minestom.server.utils.NetworkUtils;
@ -25,6 +26,7 @@ import static net.minestom.server.ping.ServerListPingType.OPEN_TO_LAN;
* Instead it simply sends the packets needed to trick the Minecraft client into thinking
* that this is a single-player world that has been opened to LANfor it to be displayed on
* the bottom of the server list.
*
* @see <a href="https://wiki.vg/Server_List_Ping#Ping_via_LAN_.28Open_to_LAN_in_Singleplayer.29">wiki.vg</a>
*/
public class OpenToLAN {
@ -37,7 +39,8 @@ public class OpenToLAN {
private static volatile DatagramPacket packet = null;
private static volatile Task task = null;
private OpenToLAN() { }
private OpenToLAN() {
}
/**
* Opens the server to LAN with the default config.
@ -121,7 +124,7 @@ public class OpenToLAN {
if (MinecraftServer.getNettyServer().getPort() != 0) {
if (packet == null || eventCooldown.isReady(System.currentTimeMillis())) {
final ServerListPingEvent event = new ServerListPingEvent(OPEN_TO_LAN);
MinecraftServer.getGlobalEventHandler().callEvent(ServerListPingEvent.class, event);
EventDispatcher.call(event);
final byte[] data = OPEN_TO_LAN.getPingResponse(event.getResponseData()).getBytes(StandardCharsets.UTF_8);
packet = new DatagramPacket(data, data.length, PING_ADDRESS);

View File

@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.extras.query.event.BasicQueryEvent;
import net.minestom.server.extras.query.event.FullQueryEvent;
import net.minestom.server.timer.Task;
@ -28,6 +29,7 @@ import java.util.Random;
/**
* Utility class to manage responses to the GameSpy4 Query Protocol.
*
* @see <a href="https://wiki.vg/Query">wiki.vg</a>
*/
public class Query {
@ -41,7 +43,8 @@ public class Query {
private static volatile Thread thread;
private static volatile Task task;
private Query() { }
private Query() {
}
/**
* Starts the query system, responding to queries on a random port, logging if it could not be started.
@ -190,12 +193,12 @@ public class Query {
if (remaining == 0) { // basic
BasicQueryEvent event = new BasicQueryEvent(sender, sessionID);
MinecraftServer.getGlobalEventHandler().callCancellableEvent(BasicQueryEvent.class, event,
() -> sendResponse(event.getQueryResponse(), sessionID, sender));
EventDispatcher.callCancellable(event, () ->
sendResponse(event.getQueryResponse(), sessionID, sender));
} else if (remaining == 5) { // full
FullQueryEvent event = new FullQueryEvent(sender, sessionID);
MinecraftServer.getGlobalEventHandler().callCancellableEvent(FullQueryEvent.class, event,
() -> sendResponse(event.getQueryResponse(), sessionID, sender));
EventDispatcher.callCancellable(event, () ->
sendResponse(event.getQueryResponse(), sessionID, sender));
}
}
}

View File

@ -1,7 +1,6 @@
package net.minestom.server.extras.query.event;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.Event;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.utils.binary.Writeable;
import org.jetbrains.annotations.NotNull;
@ -13,7 +12,7 @@ import java.util.Objects;
*
* @param <T> the type of the response
*/
public abstract class QueryEvent<T extends Writeable> extends Event implements CancellableEvent {
public abstract class QueryEvent<T extends Writeable> implements CancellableEvent {
private final SocketAddress sender;
private final int sessionID;
@ -23,9 +22,9 @@ public abstract class QueryEvent<T extends Writeable> extends Event implements C
/**
* Creates a new query event.
*
* @param sender the sender
* @param sender the sender
* @param sessionID the session ID of the query sender
* @param response the initial response
* @param response the initial response
*/
public QueryEvent(@NotNull SocketAddress sender, int sessionID, @NotNull T response) {
this.sender = sender;

View File

@ -7,6 +7,7 @@ import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.pathfinding.PFColumnarSpace;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.PlayerChunkLoadEvent;
import net.minestom.server.event.player.PlayerChunkUnloadEvent;
import net.minestom.server.instance.block.Block;
@ -445,7 +446,7 @@ public abstract class Chunk implements Viewable, Tickable, DataContainer {
if (result) {
PlayerChunkLoadEvent playerChunkLoadEvent = new PlayerChunkLoadEvent(player, chunkX, chunkZ);
player.callEvent(PlayerChunkLoadEvent.class, playerChunkLoadEvent);
EventDispatcher.call(playerChunkLoadEvent);
}
return result;
@ -467,7 +468,7 @@ public abstract class Chunk implements Viewable, Tickable, DataContainer {
if (result) {
PlayerChunkUnloadEvent playerChunkUnloadEvent = new PlayerChunkUnloadEvent(player, chunkX, chunkZ);
player.callEvent(PlayerChunkUnloadEvent.class, playerChunkUnloadEvent);
EventDispatcher.call(playerChunkUnloadEvent);
}
return result;

View File

@ -12,12 +12,15 @@ import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.ExperienceOrb;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.pathfinding.PFInstanceSpace;
import net.minestom.server.event.Event;
import net.minestom.server.event.EventCallback;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.EventFilter;
import net.minestom.server.event.EventNode;
import net.minestom.server.event.handler.EventHandler;
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
import net.minestom.server.event.instance.InstanceTickEvent;
import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent;
import net.minestom.server.event.trait.InstanceEvent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.CustomBlock;
@ -42,7 +45,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
/**
@ -56,7 +58,7 @@ import java.util.function.Consumer;
* you need to be sure to signal the {@link UpdateManager} of the changes using
* {@link UpdateManager#signalChunkLoad(Chunk)} and {@link UpdateManager#signalChunkUnload(Chunk)}.
*/
public abstract class Instance implements BlockModifier, Tickable, EventHandler, DataContainer, PacketGroupingAudience {
public abstract class Instance implements BlockModifier, Tickable, EventHandler<InstanceEvent>, DataContainer, PacketGroupingAudience {
protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
protected static final UpdateManager UPDATE_MANAGER = MinecraftServer.getUpdateManager();
@ -79,8 +81,7 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler,
// Field for tick events
private long lastTickAge = System.currentTimeMillis();
private final Map<Class<? extends Event>, Collection<EventCallback>> eventCallbacks = new ConcurrentHashMap<>();
private final Map<String, Collection<EventCallback<?>>> extensionCallbacks = new ConcurrentHashMap<>();
private final EventNode<InstanceEvent> eventNode;
// Entities present in this instance
protected final Set<Entity> entities = ConcurrentHashMap.newKeySet();
@ -119,6 +120,8 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler,
this.dimensionType = dimensionType;
this.worldBorder = new WorldBorder(this);
this.eventNode = EventNode.value("instance-" + uniqueId, EventFilter.INSTANCE, this::equals);
}
/**
@ -833,16 +836,17 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler,
this.data = data;
}
@NotNull
@Override
public Map<Class<? extends Event>, Collection<EventCallback>> getEventCallbacksMap() {
return eventCallbacks;
public @NotNull EventNode<InstanceEvent> getEventNode() {
return eventNode;
}
@NotNull
@Override
public Collection<EventCallback<?>> getExtensionCallbacks(String extension) {
return extensionCallbacks.computeIfAbsent(extension, e -> new CopyOnWriteArrayList<>());
public synchronized <V extends InstanceEvent> boolean addEventCallback(@NotNull Class<V> eventClass, @NotNull EventCallback<V> eventCallback) {
if (eventNode.getParent() == null) {
MinecraftServer.getGlobalEventHandler().addChild(eventNode);
}
return EventHandler.super.addEventCallback(eventClass, eventCallback);
}
// UNSAFE METHODS (need most of time to be synchronized)
@ -862,7 +866,7 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler,
lastInstance.UNSAFE_removeEntity(entity); // If entity is in another instance, remove it from there and add it to this
}
AddEntityToInstanceEvent event = new AddEntityToInstanceEvent(this, entity);
callCancellableEvent(AddEntityToInstanceEvent.class, event, () -> {
EventDispatcher.callCancellable(event, () -> {
final Position entityPosition = entity.getPosition();
final boolean isPlayer = entity instanceof Player;
@ -907,7 +911,7 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler,
return;
RemoveEntityFromInstanceEvent event = new RemoveEntityFromInstanceEvent(this, entity);
callCancellableEvent(RemoveEntityFromInstanceEvent.class, event, () -> {
EventDispatcher.callCancellable(event, () -> {
// Remove this entity from players viewable list and send delete entities packet
entity.getViewers().forEach(entity::removeViewer);
@ -1039,7 +1043,7 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler,
{
// Process tick events
InstanceTickEvent chunkTickEvent = new InstanceTickEvent(this, time, lastTickAge);
callEvent(InstanceTickEvent.class, chunkTickEvent);
EventDispatcher.call(chunkTickEvent);
// Set last tick age
lastTickAge = time;

Some files were not shown because too many files have changed in this diff Show More