Implement simple event system

This commit is contained in:
RednedEpic 2022-01-15 22:54:08 -06:00
parent 778f004d99
commit b82c661688
14 changed files with 677 additions and 1 deletions

View file

@ -32,6 +32,12 @@
<version>${adventure.version}</version> <version>${adventure.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>event-api</artifactId>
<version>3.0.0</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>base-api</artifactId> <artifactId>base-api</artifactId>

View file

@ -30,6 +30,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.api.Geyser; import org.geysermc.api.Geyser;
import org.geysermc.api.GeyserApiBase; import org.geysermc.api.GeyserApiBase;
import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.connection.GeyserConnection;
import org.geysermc.geyser.api.event.EventBus;
import org.geysermc.geyser.api.extension.ExtensionManager; import org.geysermc.geyser.api.extension.ExtensionManager;
import java.util.List; import java.util.List;
@ -88,6 +89,14 @@ public interface GeyserApi extends GeyserApiBase {
*/ */
ExtensionManager extensionManager(); ExtensionManager extensionManager();
/**
* Gets the {@link EventBus} for handling
* Geyser events.
*
* @return the event bus
*/
EventBus eventBus();
/** /**
* Gets the current {@link GeyserApiBase} instance. * Gets the current {@link GeyserApiBase} instance.
* *

View file

@ -28,7 +28,7 @@ package org.geysermc.geyser.api.connection;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
/** /**
* Represents a player session used in Geyser. * Represents a player connection used in Geyser.
*/ */
public interface GeyserConnection extends Connection { public interface GeyserConnection extends Connection {
} }

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.event;
/**
* Represents a cancellable event.
*/
public interface Cancellable {
/**
* Gets if the event is cancelled.
*
* @return if the event is cancelled
*/
boolean isCancelled();
/**
* Cancels the event.
*
* @param cancelled if the event is cancelled
*/
void setCancelled(boolean cancelled);
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.event;
/**
* Represents an event.
*/
public interface Event {
/**
* Gets if the event is async.
*
* @return if the event is async
*/
default boolean isAsync() {
return false;
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.event;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.extension.Extension;
import java.util.Set;
import java.util.function.Consumer;
/**
* Represents a bus capable of subscribing
* or "listening" to events and firing them.
*/
public interface EventBus {
/**
* Subscribes to the given event see {@link EventSubscription}.
*
* @param eventClass the class of the event
* @param consumer the consumer for handling the event
* @param <T> the event class
* @return the event subscription
*/
@NonNull
<T extends Event> EventSubscription<T> subscribe(@NonNull Class<T> eventClass, @NonNull Consumer<? super T> consumer);
/**
* Subscribes to the given event see {@link EventSubscription}.
*
* The difference between this method and {@link #subscribe(Class, Consumer)}
* is that this method takes in an extension parameter which allows for
* the event to be unsubscribed upon extension disable and reloads.
*
* @param extension the extension to subscribe the event to
* @param eventClass the class of the event
* @param consumer the consumer for handling the event
* @param <T> the event class
* @return the event subscription
*/
@NonNull
<T extends Event> EventSubscription<T> subscribe(@NonNull Extension extension, @NonNull Class<T> eventClass, @NonNull Consumer<? super T> consumer);
/**
* Unsubscribes the given {@link EventSubscription}.
*
* @param subscription the event subscription
*/
<T extends Event> void unsubscribe(@NonNull EventSubscription<T> subscription);
/**
* Registers events for the given listener.
*
* @param extension the extension registering the event
* @param eventHolder the listener
*/
void register(@NonNull Extension extension, @NonNull Object eventHolder);
/**
* Fires the given {@link Event}.
*
* @param event the event to fire
*
* @return true if the event successfully fired
*/
boolean fire(@NonNull Event event);
/**
* Gets the subscriptions for the given event class.
*
* @param eventClass the event class
* @param <T> the value
* @return the subscriptions for the event class
*/
@NonNull
<T extends Event> Set<EventSubscription<T>> subscriptions(@NonNull Class<T> eventClass);
}

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.event;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.extension.Extension;
import java.util.function.Consumer;
/**
* Represents a subscribed listener to a {@link Event}. Wraps around
* the event and is capable of unsubscribing from the event or give
* information about it.
*
* @param <T> the class of the event
*/
public interface EventSubscription<T extends Event> {
/**
* Gets the event class.
*
* @return the event class
*/
@NonNull
Class<T> eventClass();
/**
* Gets the consumer responsible for handling
* this event.
*
* @return the consumer responsible for this event
*/
@NonNull
Consumer<? super T> eventConsumer();
/**
* Gets the {@link Extension} that owns this
* event subscription.
*
* @return the extension that owns this subscription
*/
@NonNull
Extension owner();
/**
* Gets the priority of this event subscription.
*
* @return the priority of this event subscription
*/
Subscribe.Priority priority();
/**
* Gets if this event subscription is active.
*
* @return if this event subscription is active
*/
boolean isActive();
/**
* Unsubscribes from this event listener
*/
void unsubscribe();
/**
* Invokes the given event
*
* @param event the event
*/
void invoke(@NonNull T event) throws Throwable;
}

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.event;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.Accessors;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An annotation used to signify the given method is
* an {@link Event}. Only should be applied to methods
* where the class containing them is designated for
* events specifically.
*
* When using {@link EventBus#subscribe}, this annotation should
* not be applied whatsoever as it will have no use and potentially
* throw errors due to it being used wrongly.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Subscribe {
/**
* The {@link Priority} of the event
*
* @return the priority of the event
*/
@NonNull
Priority priority() default Priority.NORMAL;
/**
* Represents the priority of an event.
*/
@Accessors(fluent = true)
@Getter
@AllArgsConstructor
enum Priority {
/**
* The lowest priority. Called first to
* allow for other events to customize
* the outcome
*/
LOWEST(net.kyori.event.PostOrders.FIRST),
/**
* The second lowest priority.
*/
LOW(net.kyori.event.PostOrders.EARLY),
/**
* Normal priority. Event is neither
* important nor unimportant
*/
NORMAL(net.kyori.event.PostOrders.NORMAL),
/**
* The second highest priority
*/
HIGH(net.kyori.event.PostOrders.LATE),
/**
* The highest of importance! Event is called
* last and has the final say in the outcome
*/
HIGHEST(net.kyori.event.PostOrders.LAST);
private final int postOrder;
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.event.lifecycle;
import org.geysermc.geyser.api.event.Event;
/**
* Called when Geyser has completed initializing.
*/
public class GeyserPostInitializeEvent implements Event {
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.event.lifecycle;
import org.geysermc.geyser.api.event.Event;
/**
* Called when Geyser is shutting down.
*/
public class GeyserShutdownEvent implements Event {
}

View file

@ -244,6 +244,13 @@
<version>${adventure.version}</version> <version>${adventure.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<!-- Kyori Misc -->
<dependency>
<groupId>net.kyori</groupId>
<artifactId>event-api</artifactId>
<version>3.0.0</version>
<scope>compile</scope>
</dependency>
<!-- Other --> <!-- Other -->
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>

View file

@ -49,9 +49,13 @@ import org.geysermc.floodgate.crypto.Base64Topping;
import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.news.NewsItemAction; import org.geysermc.floodgate.news.NewsItemAction;
import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.GeyserApi;
import org.geysermc.geyser.api.event.EventBus;
import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent;
import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent;
import org.geysermc.geyser.command.CommandManager; import org.geysermc.geyser.command.CommandManager;
import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.event.GeyserEventBus;
import org.geysermc.geyser.extension.GeyserExtensionManager; import org.geysermc.geyser.extension.GeyserExtensionManager;
import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.network.ConnectorServerEventHandler; import org.geysermc.geyser.network.ConnectorServerEventHandler;
@ -123,6 +127,7 @@ public class GeyserImpl implements GeyserApi {
private final PlatformType platformType; private final PlatformType platformType;
private final GeyserBootstrap bootstrap; private final GeyserBootstrap bootstrap;
private final EventBus eventBus;
private final GeyserExtensionManager extensionManager; private final GeyserExtensionManager extensionManager;
private Metrics metrics; private Metrics metrics;
@ -158,6 +163,7 @@ public class GeyserImpl implements GeyserApi {
MinecraftLocale.init(); MinecraftLocale.init();
/* Load Extensions */ /* Load Extensions */
this.eventBus = new GeyserEventBus();
this.extensionManager = new GeyserExtensionManager(); this.extensionManager = new GeyserExtensionManager();
this.extensionManager.init(); this.extensionManager.init();
@ -411,6 +417,8 @@ public class GeyserImpl implements GeyserApi {
} }
newsHandler.handleNews(null, NewsItemAction.ON_SERVER_STARTED); newsHandler.handleNews(null, NewsItemAction.ON_SERVER_STARTED);
this.eventBus.fire(new GeyserPostInitializeEvent());
} }
@Override @Override
@ -466,6 +474,8 @@ public class GeyserImpl implements GeyserApi {
ResourcePack.PACKS.clear(); ResourcePack.PACKS.clear();
this.eventBus.fire(new GeyserShutdownEvent());
this.extensionManager.disableExtensions(); this.extensionManager.disableExtensions();
bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done")); bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done"));
@ -494,6 +504,11 @@ public class GeyserImpl implements GeyserApi {
return this.extensionManager; return this.extensionManager;
} }
@Override
public EventBus eventBus() {
return this.eventBus;
}
public static GeyserImpl start(PlatformType platformType, GeyserBootstrap bootstrap) { public static GeyserImpl start(PlatformType platformType, GeyserBootstrap bootstrap) {
if (instance == null) { if (instance == null) {
return new GeyserImpl(platformType, bootstrap); return new GeyserImpl(platformType, bootstrap);

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.event;
import net.kyori.event.SimpleEventBus;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.event.Event;
import org.geysermc.geyser.api.event.EventBus;
import org.geysermc.geyser.api.event.EventSubscription;
import org.geysermc.geyser.api.event.Subscribe;
import org.geysermc.geyser.api.extension.Extension;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class GeyserEventBus implements EventBus {
private final SimpleEventBus<Event> bus = new SimpleEventBus<>(Event.class);
@NonNull
@Override
public <T extends Event> EventSubscription<T> subscribe(@NonNull Class<T> eventClass, @NonNull Consumer<? super T> consumer) {
return this.subscribe(eventClass, consumer, null, Subscribe.Priority.NORMAL);
}
@NonNull
@Override
public <T extends Event> EventSubscription<T> subscribe(@NonNull Extension extension, @NonNull Class<T> eventClass, @NonNull Consumer<? super T> consumer) {
return this.subscribe(eventClass, consumer, extension, Subscribe.Priority.NORMAL);
}
@Override
public <T extends Event> void unsubscribe(@NonNull EventSubscription<T> subscription) {
this.bus.unregister((GeyserEventSubscription<T>) subscription);
}
@SuppressWarnings("unchecked")
@Override
public void register(@NonNull Extension extension, @NonNull Object eventHolder) {
for (Method method : eventHolder.getClass().getMethods()) {
if (!method.isAnnotationPresent(Subscribe.class)) {
continue;
}
if (method.getParameterCount() > 1) {
continue;
}
if (!Event.class.isAssignableFrom(method.getParameters()[0].getType())) {
continue;
}
Subscribe subscribe = method.getAnnotation(Subscribe.class);
this.subscribe((Class<? extends Event>) method.getParameters()[0].getType(), (event) -> {
try {
method.invoke(eventHolder, event);
} catch (IllegalAccessException | InvocationTargetException ex) {
ex.printStackTrace();
}
}, extension, subscribe.priority());
}
}
@Override
public boolean fire(@NonNull Event event) {
return this.bus.post(event).wasSuccessful();
}
@SuppressWarnings("unchecked")
@NonNull
@Override
public <T extends Event> Set<EventSubscription<T>> subscriptions(@NonNull Class<T> eventClass) {
return bus.subscribers().values()
.stream()
.filter(sub -> sub instanceof EventSubscription && ((EventSubscription<?>) sub).eventClass().isAssignableFrom(eventClass))
.map(sub -> ((EventSubscription<T>) sub))
.collect(Collectors.toSet());
}
private <T extends Event> EventSubscription<T> subscribe(Class<T> eventClass, Consumer<? super T> handler, Extension extension, Subscribe.Priority priority) {
GeyserEventSubscription<T> eventSubscription = new GeyserEventSubscription<>(this, eventClass, handler, extension, priority);
this.bus.register(eventClass, eventSubscription);
return eventSubscription;
}
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.event;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Accessors;
import net.kyori.event.EventSubscriber;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.event.Event;
import org.geysermc.geyser.api.event.EventBus;
import org.geysermc.geyser.api.event.EventSubscription;
import org.geysermc.geyser.api.event.Subscribe;
import org.geysermc.geyser.api.extension.Extension;
import java.util.function.Consumer;
@Getter
@Accessors(fluent = true)
@RequiredArgsConstructor
public class GeyserEventSubscription<T extends Event> implements EventSubscription<T>, EventSubscriber<T> {
private final EventBus eventBus;
private final Class<T> eventClass;
private final Consumer<? super T> eventConsumer;
private final Extension owner;
private final Subscribe.Priority priority;
@Getter(AccessLevel.NONE) private boolean active;
@Override
public boolean isActive() {
return this.active;
}
@Override
public void unsubscribe() {
if (!this.active) {
return;
}
this.active = false;
this.eventBus.unsubscribe(this);
}
@Override
public void invoke(@NonNull T event) throws Throwable {
try {
this.eventConsumer.accept(event);
} catch (Throwable ex) {
this.owner.logger().warning("Unable to fire event " + event.getClass().getSimpleName() + " with subscription " + this.eventConsumer.getClass().getSimpleName());
ex.printStackTrace();
}
}
@Override
public int postOrder() {
return this.priority.postOrder();
}
}