Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asynchronous event handling with functional non-thread-blocking chunk loading [PROPOSAL] #129

Closed
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shanyu Juneja <shanyujuneja@gmail.com>
Date: Tue, 11 Jul 2023 05:59:35 +0200
Subject: [PATCH] Deprecate callEvent and implement asynchronous events


diff --git a/src/main/java/org/bukkit/event/Event.java b/src/main/java/org/bukkit/event/Event.java
index 8ec56cd6b8e0f5c5dd8c7c88b4671e18dcf109d0..b9716f1b96292bf9112df5bda879c81658eeaceb 100644
--- a/src/main/java/org/bukkit/event/Event.java
+++ b/src/main/java/org/bukkit/event/Event.java
@@ -1,9 +1,12 @@
package org.bukkit.event;

+import org.bukkit.Location;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;

+import java.util.concurrent.CompletableFuture;
+
/**
* Represents an event.
*
@@ -41,6 +44,7 @@ public abstract class Event {
*
* @return false if event was cancelled, if cancellable. otherwise true.
*/
+ @Deprecated // Folia - event handler
public boolean callEvent() {
org.bukkit.Bukkit.getPluginManager().callEvent(this);
if (this instanceof Cancellable) {
@@ -51,6 +55,25 @@ public abstract class Event {
}
// Paper end

+ // Folia start
+ /**
+ * Calls the event and tests if cancelled.
+ *
+ * @return false if event was cancelled, if cancellable. otherwise true.
+ */
+ public CompletableFuture<Event> callEventAsync() {
+ return callEventAsync(null);
+ }
+
+ public CompletableFuture<Event> callEventAsync(final Location origin) {
+ return org.bukkit.Bukkit.getPluginManager().callEventAsync(this, origin);
+ }
+
+ public boolean isCancelled() {
+ return false;
+ }
+ // Folia end
+
/**
* Convenience method for providing a user-friendly identifier. By
* default, it is the event's class's {@linkplain Class#getSimpleName()
diff --git a/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java b/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java
index 6818e9f0ba32ca1a1e612703f7526b29f5a6438f..e9f8d1b471020bc7a35e7ad6aa00cf07899080a2 100644
--- a/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java
+++ b/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java
@@ -1,6 +1,7 @@
package org.bukkit.event.entity;

import org.bukkit.Location;
+import org.bukkit.PortalType;
import org.bukkit.entity.Entity;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
@@ -11,10 +12,16 @@ import org.jetbrains.annotations.NotNull;
public class EntityPortalEnterEvent extends EntityEvent {
private static final HandlerList handlers = new HandlerList();
private final Location location;
+ private final PortalType type;

public EntityPortalEnterEvent(@NotNull final Entity entity, @NotNull final Location location) {
- super(entity);
+ this(entity, location, PortalType.CUSTOM);
+ }
+
+ public EntityPortalEnterEvent(@NotNull final Entity what, @NotNull final Location location, PortalType type) {
+ super(what);
this.location = location;
+ this.type = type;
}

/**
@@ -27,6 +34,16 @@ public class EntityPortalEnterEvent extends EntityEvent {
return location;
}

+ /**
+ * Gets the type of portal the entity is touching
+ *
+ * @return The type of portal the entity is touching
+ */
+ @NotNull
+ public PortalType getType() {
+ return type;
+ }
+
@NotNull
@Override
public HandlerList getHandlers() {
diff --git a/src/main/java/org/bukkit/plugin/PluginManager.java b/src/main/java/org/bukkit/plugin/PluginManager.java
index 03213fde8315384ec56c16031cfc606ade2e8091..cdd80b6874c37b7255b28f91cd416468e5145496 100644
--- a/src/main/java/org/bukkit/plugin/PluginManager.java
+++ b/src/main/java/org/bukkit/plugin/PluginManager.java
@@ -2,6 +2,9 @@ package org.bukkit.plugin;

import java.io.File;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+import org.bukkit.Location;
import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -109,9 +112,46 @@ public interface PluginManager extends io.papermc.paper.plugin.PermissionManager
* <p>
* <i>Note: This is best-effort basis, and should not be used to test
* synchronized state. This is an indicator for flawed flow logic.</i>
+ *
+ * @deprecated This method should not be used when possible
*/
+ @Deprecated
public void callEvent(@NotNull Event event) throws IllegalStateException;

+ /**
+ * Calls an event with the given details, iterating in a thread safe
+ * manner for every registered listener, ensuring no issue with concurrency
+ *
+ * @param event Event details
+ * @throws IllegalStateException Thrown when an asynchronous event is
+ * fired from synchronous code.
+ * <p>
+ * <i>Note: This is best-effort basis, and should not be used to test
+ * synchronized state. This is an indicator for flawed flow logic.</i>
+ *
+ * @return Future to be completed with the event result
+ */
+ public default CompletableFuture<Event> callEventAsync(@NotNull Event event) throws IllegalStateException {
+ return callEventAsync(event, null);
+ }
+
+
+ /**
+ * Calls an event with the given details, iterating in a thread safe
+ * manner for every registered listener, ensuring no issue with concurrency
+ *
+ * @param event Event details
+ * @param origin Location of the event caller
+ * @throws IllegalStateException Thrown when an asynchronous event is
+ * fired from synchronous code.
+ * <p>
+ * <i>Note: This is best-effort basis, and should not be used to test
+ * synchronized state. This is an indicator for flawed flow logic.</i>
+ *
+ * @return Future to be completed with the event result
+ */
+ public CompletableFuture<Event> callEventAsync(@NotNull Event event, @Nullable Location origin) throws IllegalStateException;
+
/**
* Registers all the events in the given listener class
*
diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
index 06149045a44148bf0af5f52952ff0092fe2c70cb..745873baadb340d7cc1f56f3606634c017a64c75 100644
--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java
+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
@@ -21,9 +21,12 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
+import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+
+import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.command.Command;
@@ -629,6 +632,13 @@ public final class SimplePluginManager implements PluginManager {
fireEvent(event);
}

+ // Folia start - event handling
+ @Override
+ public CompletableFuture<Event> callEventAsync(@NotNull Event event, @Nullable Location origin) throws IllegalStateException {
+ return this.paperPluginManager.callEventAsync(event, origin);
+ }
+ // Folia end
+
private void fireEvent(@NotNull Event event) {
HandlerList handlers = event.getHandlers();
RegisteredListener[] listeners = handlers.getRegisteredListeners();
Loading