Compare commits

...

13 commits

Author SHA1 Message Date
Pedro
4430e96e1b
Add AnvilView#bypassEnchantmentLevelRestriction (#11475) 2024-10-12 23:10:05 +02:00
Lulu13022002
b16c0ae023
Add offline PDC API (#8117) 2024-10-12 21:38:18 +02:00
TonytheMacaroni
57c75a4b67
Fix CraftMagicNumbers#getTag (#11484) 2024-10-09 21:58:13 +01:00
Nassim Jahnke
7cd4f2c15f
Check if leash tag has a uuid 2024-10-03 17:10:27 +02:00
Nassim Jahnke
fb768404aa
[ci skip] Add section on nullability annotations (#11461) 2024-10-02 14:32:20 +02:00
Jake Potrebic
709f0f2919
Use components properly in ProfileWhitelistVerifyEvent (#11456) 2024-10-02 14:32:05 +02:00
Nassim Jahnke
69ffbec34a
Fix hex color check 2024-10-02 13:49:39 +02:00
Jake Potrebic
e7e1ab56ca
Finish converting most of the undeprecated api to jspecify 2024-09-30 16:02:52 -07:00
Jake Potrebic
ba3c29b92e
Finish converting all events to jspecify annotations 2024-09-29 19:13:41 -07:00
Bjarne Koll
ea00be3aaa
Do not NPE on uuid resolution in player profile (#11449)
Band-aid fix for the player profile api resolution for a profile with
name but without uuid. The real solution is a proper refactoring of the
completeFromCache and complete method internally, however this needs
further consideration regarding existing faulty behaviour around name
lookups from uuid-only profiles.
2024-09-30 00:26:44 +02:00
Axionize
b410fe8697
Configurable per-world void damage offset/damage(#11436) 2024-09-30 00:06:13 +02:00
Noah van der Aa
e3c8a8eef1
Add PlayerInsertLecternBookEvent [1.20 port] (#7305)
* Add PlayerInsertLecternBookEvent

* Rebase

Additionally, moves the event call higher up and removes the lectern
block state clone from the event.

* jSpecify

* Shrink correctly

* style fixups

* move methods

* rename param to cancel

* fix javadocs

* more javadoc fixes

* fix co-author on patch from yesterday

* last fix

---------

Co-authored-by: Mariell Hoversholm <proximyst@proximyst.com>
Co-authored-by: Bjarne Koll <lynxplay101@gmail.com>
2024-09-29 14:28:48 -07:00
Jake Potrebic
f9c7f2a5c1
Begin switching to JSpecify annotations (#11448)
* Begin switching to JSpecify annotations

* more

* fixes
2024-09-29 12:52:13 -07:00
184 changed files with 3295 additions and 2992 deletions

View file

@ -249,6 +249,17 @@ instead of adding a new import to the top of the file. If you are using a type a
can add an import with a comment. However, if its only used a couple of times, the FQN is preferred to prevent future
patch conflicts in the import section of the file.
### Nullability annotations
We are in the process of switching nullability annotation libraries, so you might need to use one or the other:
**For classes we add**: Fields, method parameters and return types that are nullable should be marked via the
`@Nullable` annotation from `org.jspecify.annotations`. Whenever you create a new class, add `@NullMarked`, meaning types
are assumed to be non-null by default. For less obvious placing such as on generics or arrays, see the [JSpecify docs](https://jspecify.dev/docs/user-guide/).
**For classes added by upstream**: Keep using both `@Nullable` and `@NotNull` from `org.jetbrains.annotations`. These
will be replaced later.
```java
import org.bukkit.event.Event;
// don't add import here, use FQN like below

View file

@ -5,10 +5,10 @@ Subject: [PATCH] Build system changes
diff --git a/build.gradle.kts b/build.gradle.kts
index 6271e2bad0ed937c2c46a8c8fdf186c46b0b620e..a918fd14c95e714e935758d60bccd72755e00b11 100644
index 6271e2bad0ed937c2c46a8c8fdf186c46b0b620e..78aadebda145fe83327ceb430c4b38f9a8e45a2b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -18,15 +18,26 @@ dependencies {
@@ -18,15 +18,27 @@ dependencies {
api("net.md-5:bungeecord-chat:$bungeeCordChatVersion")
api("org.yaml:snakeyaml:2.2")
api("org.joml:joml:1.10.5")
@ -32,11 +32,12 @@ index 6271e2bad0ed937c2c46a8c8fdf186c46b0b620e..a918fd14c95e714e935758d60bccd727
+ compileOnlyApi(checkerQual)
+ testCompileOnly(checkerQual)
+ // Paper end
+ api("org.jspecify:jspecify:1.0.0") // Paper - add jspecify
+
testImplementation("org.apache.commons:commons-lang3:3.12.0")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
testImplementation("org.hamcrest:hamcrest:2.2")
@@ -69,8 +80,12 @@ tasks.withType<Javadoc> {
@@ -69,8 +81,13 @@ tasks.withType<Javadoc> {
options.links(
"https://guava.dev/releases/32.1.2-jre/api/docs/",
"https://javadoc.io/doc/org.yaml/snakeyaml/2.2/",
@ -46,11 +47,12 @@ index 6271e2bad0ed937c2c46a8c8fdf186c46b0b620e..a918fd14c95e714e935758d60bccd727
+ // Paper start - add missing javadoc links
+ "https://javadoc.io/doc/org.joml/joml/1.10.5/index.html",
+ "https://www.javadoc.io/doc/com.google.code.gson/gson/2.10.1",
+ "https://jspecify.dev/docs/api/",
+ // Paper end
)
options.tags("apiNote:a:API Note:")
@@ -89,3 +104,14 @@ tasks.withType<Javadoc> {
@@ -89,3 +106,14 @@ tasks.withType<Javadoc> {
tasks.test {
useJUnitPlatform()
}

View file

@ -12,10 +12,10 @@ Co-authored-by: Riley Park <rileysebastianpark@gmail.com>
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/build.gradle.kts b/build.gradle.kts
index a918fd14c95e714e935758d60bccd72755e00b11..768024b2b4584fd7dd86f068c0e79c89ffc5faa1 100644
index 78aadebda145fe83327ceb430c4b38f9a8e45a2b..8c7a5be5193ae397ec324d78566edce90608ed57 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -105,6 +105,12 @@ tasks.test {
@@ -107,6 +107,12 @@ tasks.test {
useJUnitPlatform()
}
@ -66,7 +66,7 @@ index 0000000000000000000000000000000000000000..77154095cfb8b259bdb318e8ff40cb6f
+ }
+}
diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java
index 64e7aef6220097edefdff3b98a771b988365930d..d9091ba1e5a55e03adca98305233cce9d6888609 100644
index 64e7aef6220097edefdff3b98a771b988365930d..7ff939ea41417bad3a436a87c89d5efa7ecefe86 100644
--- a/src/test/java/org/bukkit/AnnotationTest.java
+++ b/src/test/java/org/bukkit/AnnotationTest.java
@@ -29,7 +29,13 @@ public class AnnotationTest {
@ -103,7 +103,19 @@ index 64e7aef6220097edefdff3b98a771b988365930d..d9091ba1e5a55e03adca98305233cce9
};
@Test
@@ -67,14 +83,48 @@ public class AnnotationTest {
@@ -61,20 +77,60 @@ public class AnnotationTest {
continue;
}
+ // Paper start - skip class if it's @NullMarked
+ if (isClassNullMarked(clazz)) {
+ return;
+ }
+ // Paper end - skip class if it's @NullMarked
+
for (MethodNode method : clazz.methods) {
if (!isMethodIncluded(clazz, method, foundClasses)) {
continue;
}
if (mustBeAnnotated(Type.getReturnType(method.desc)) && !isWellAnnotated(method.invisibleAnnotations)) {
@ -152,7 +164,7 @@ index 64e7aef6220097edefdff3b98a771b988365930d..d9091ba1e5a55e03adca98305233cce9
ParameterNode paramNode = parameters == null ? null : parameters.get(i);
String paramName = paramNode == null ? null : paramNode.name;
@@ -91,13 +141,18 @@ public class AnnotationTest {
@@ -91,13 +147,18 @@ public class AnnotationTest {
Collections.sort(errors);
@ -175,7 +187,20 @@ index 64e7aef6220097edefdff3b98a771b988365930d..d9091ba1e5a55e03adca98305233cce9
}
private static void collectClasses(@NotNull File from, @NotNull Map<String, ClassNode> to) throws IOException {
@@ -140,6 +195,11 @@ public class AnnotationTest {
@@ -125,6 +186,12 @@ public class AnnotationTest {
}
}
+ // Paper start - skip class if it's @NullMarked
+ private static boolean isClassNullMarked(@NotNull ClassNode clazz) {
+ return clazz.visibleAnnotations != null && clazz.visibleAnnotations.stream().anyMatch(node -> "Lorg/jspecify/annotations/NullMarked;".equals(node.desc));
+ }
+ // Paper end - skip class if it's @NullMarked
+
private static boolean isClassIncluded(@NotNull ClassNode clazz, @NotNull Map<String, ClassNode> allClasses) {
// Exclude private, synthetic or deprecated classes and annotations, since their members can't be null
if ((clazz.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED | Opcodes.ACC_ANNOTATION)) != 0) {
@@ -140,6 +207,11 @@ public class AnnotationTest {
// Exceptions are excluded
return false;
}
@ -187,7 +212,7 @@ index 64e7aef6220097edefdff3b98a771b988365930d..d9091ba1e5a55e03adca98305233cce9
for (String excludedClass : EXCLUDED_CLASSES) {
if (excludedClass.equals(clazz.name)) {
@@ -152,7 +212,7 @@ public class AnnotationTest {
@@ -152,7 +224,7 @@ public class AnnotationTest {
private static boolean isMethodIncluded(@NotNull ClassNode clazz, @NotNull MethodNode method, @NotNull Map<String, ClassNode> allClasses) {
// Exclude private, synthetic and deprecated methods
@ -196,7 +221,7 @@ index 64e7aef6220097edefdff3b98a771b988365930d..d9091ba1e5a55e03adca98305233cce9
return false;
}
@@ -170,11 +230,30 @@ public class AnnotationTest {
@@ -170,11 +242,30 @@ public class AnnotationTest {
if ("<init>".equals(method.name) && isAnonymous(clazz)) {
return false;
}

View file

@ -7,7 +7,7 @@ Currently includes generated key holder classes for types
used in the Registry Modification API
diff --git a/build.gradle.kts b/build.gradle.kts
index 768024b2b4584fd7dd86f068c0e79c89ffc5faa1..f11a22ab01e97e51619c96f2d8a78a99297efc59 100644
index 8c7a5be5193ae397ec324d78566edce90608ed57..877ea06c0ea8c8c0c73d23fbb996f6692c100d98 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,6 +1,7 @@
@ -18,7 +18,7 @@ index 768024b2b4584fd7dd86f068c0e79c89ffc5faa1..f11a22ab01e97e51619c96f2d8a78a99
}
java {
@@ -45,6 +46,22 @@ dependencies {
@@ -46,6 +47,22 @@ dependencies {
testImplementation("org.ow2.asm:asm-tree:9.7")
}
@ -41,7 +41,7 @@ index 768024b2b4584fd7dd86f068c0e79c89ffc5faa1..f11a22ab01e97e51619c96f2d8a78a99
configure<PublishingExtension> {
publications.create<MavenPublication>("maven") {
from(components["java"])
@@ -121,3 +138,14 @@ tasks.check {
@@ -123,3 +140,14 @@ tasks.check {
dependsOn(scanJar)
}
// Paper end
@ -85,10 +85,10 @@ index 0000000000000000000000000000000000000000..2512dba27edfdccbc4430815b6cba048
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e2765d296decbb3e61b8434e78b5e0214f8fee0
index 0000000000000000000000000000000000000000..8410d7213370f01cbedbf7fac29bac96f150c49a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java
@@ -0,0 +1,177 @@
@@ -0,0 +1,179 @@
+package io.papermc.paper.registry;
+
+import net.kyori.adventure.key.Keyed;
@ -121,6 +121,7 @@ index 0000000000000000000000000000000000000000..1e2765d296decbb3e61b8434e78b5e02
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.potion.PotionType;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+import static io.papermc.paper.registry.RegistryKeyImpl.create;
+
@ -137,6 +138,7 @@ index 0000000000000000000000000000000000000000..1e2765d296decbb3e61b8434e78b5e02
+ * @param <T> the value type
+ */
+@SuppressWarnings("unused")
+@NullMarked
+public sealed interface RegistryKey<T> extends Keyed permits RegistryKeyImpl {
+
+ /* ******************* *
@ -268,19 +270,21 @@ index 0000000000000000000000000000000000000000..1e2765d296decbb3e61b8434e78b5e02
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..791813220b2504214b1adecc69093cd600fb0f8c
index 0000000000000000000000000000000000000000..80e3e64f47ac55a4978c9e5b430e2f2d1c871d1b
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
@@ -0,0 +1,24 @@
@@ -0,0 +1,26 @@
+package io.papermc.paper.registry;
+
+import com.google.common.collect.Sets;
+import java.util.Set;
+import net.kyori.adventure.key.Key;
+import org.intellij.lang.annotations.Subst;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+record RegistryKeyImpl<T>(@NotNull Key key) implements RegistryKey<T> {
+@NullMarked
+record RegistryKeyImpl<T>(Key key) implements RegistryKey<T> {
+
+ static final Set<RegistryKey<?>> REGISTRY_KEYS = Sets.newIdentityHashSet();
+
@ -298,16 +302,16 @@ index 0000000000000000000000000000000000000000..791813220b2504214b1adecc69093cd6
+}
diff --git a/src/main/java/io/papermc/paper/registry/TypedKey.java b/src/main/java/io/papermc/paper/registry/TypedKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f5a062ba7ee7173468ecea3c1855a233bf3855e
index 0000000000000000000000000000000000000000..cb2e1a4a6d583787573eeefab24e3188c43d148f
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/TypedKey.java
@@ -0,0 +1,44 @@
@@ -0,0 +1,45 @@
+package io.papermc.paper.registry;
+
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.key.Keyed;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents a key for a value in a specific registry.
@ -315,6 +319,7 @@ index 0000000000000000000000000000000000000000..6f5a062ba7ee7173468ecea3c1855a23
+ * @param <T> the value type for the registry
+ */
+@ApiStatus.Experimental
+@NullMarked
+public sealed interface TypedKey<T> extends Keyed permits TypedKeyImpl {
+
+ /**
@ -323,7 +328,7 @@ index 0000000000000000000000000000000000000000..6f5a062ba7ee7173468ecea3c1855a23
+ * @return the value's key
+ */
+ @Override
+ @NotNull Key key();
+ Key key();
+
+ /**
+ * Gets the registry key for the value this key
@ -331,7 +336,7 @@ index 0000000000000000000000000000000000000000..6f5a062ba7ee7173468ecea3c1855a23
+ *
+ * @return the registry key
+ */
+ @NotNull RegistryKey<T> registryKey();
+ RegistryKey<T> registryKey();
+
+ /**
+ * Create a typed key from a key and a registry key.
@ -342,23 +347,23 @@ index 0000000000000000000000000000000000000000..6f5a062ba7ee7173468ecea3c1855a23
+ * @return a new key for the value key and registry key
+ */
+ @ApiStatus.Experimental
+ static <T> @NotNull TypedKey<T> create(final @NotNull RegistryKey<T> registryKey, final @NotNull Key key) {
+ static <T> TypedKey<T> create(final RegistryKey<T> registryKey, final Key key) {
+ return new TypedKeyImpl<>(key, registryKey);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a97b3359c4ece5c29131da7c3f208aaa8fab66e
index 0000000000000000000000000000000000000000..99375deaa6b90b33cd6a77e0df651236d304874e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java
@@ -0,0 +1,8 @@
+package io.papermc.paper.registry;
+
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.key.Keyed;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+record TypedKeyImpl<T>(@NotNull Key key, @NotNull RegistryKey<T> registryKey) implements TypedKey<T> {
+@NullMarked
+record TypedKeyImpl<T>(Key key, RegistryKey<T> registryKey) implements TypedKey<T> {
+}
diff --git a/src/main/java/org/bukkit/MinecraftExperimental.java b/src/main/java/org/bukkit/MinecraftExperimental.java
index a86b87e4c3332202e40e484c3f9c6562b419c70f..305532968f9f7dd497c77259ed147ea2f081bc74 100644

View file

@ -8,7 +8,7 @@ Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
Co-authored-by: Yannick Lamprecht <yannicklamprecht@live.de>
diff --git a/build.gradle.kts b/build.gradle.kts
index 2f266350a787a4cfdfda1b0e760bfb7604cac43c..af3514113abdf3f42c41f1e7ff0f930cc1a417f5 100644
index 3383fb91249ea53740326b538abd905f84ff0e3c..74f0e2b812c1e2e922b136fefe505fc8cbe33e83 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -11,12 +11,28 @@ java {
@ -55,7 +55,7 @@ index 2f266350a787a4cfdfda1b0e760bfb7604cac43c..af3514113abdf3f42c41f1e7ff0f930c
// Paper end
compileOnly("org.apache.maven:maven-resolver-provider:3.9.6")
@@ -99,14 +122,31 @@ tasks.withType<Javadoc> {
@@ -100,15 +123,32 @@ tasks.withType<Javadoc> {
"https://guava.dev/releases/32.1.2-jre/api/docs/",
"https://javadoc.io/doc/org.yaml/snakeyaml/2.2/",
"https://javadoc.io/doc/org.jetbrains/annotations/$annotationsVersion/", // Paper - we don't want Java 5 annotations
@ -64,6 +64,7 @@ index 2f266350a787a4cfdfda1b0e760bfb7604cac43c..af3514113abdf3f42c41f1e7ff0f930c
// Paper start - add missing javadoc links
"https://javadoc.io/doc/org.joml/joml/1.10.5/index.html",
"https://www.javadoc.io/doc/com.google.code.gson/gson/2.10.1",
"https://jspecify.dev/docs/api/",
// Paper end
+ // Paper start
+ "https://jd.advntr.dev/api/$adventureVersion/",
@ -90,23 +91,25 @@ index 2f266350a787a4cfdfda1b0e760bfb7604cac43c..af3514113abdf3f42c41f1e7ff0f930c
doLast {
diff --git a/src/main/java/io/papermc/paper/chat/ChatRenderer.java b/src/main/java/io/papermc/paper/chat/ChatRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..ffe0a921cc1ebbb95104f22b57e0e3af85e287a6
index 0000000000000000000000000000000000000000..1288cdeafe587e9e78e7c5087742ea054ba8423d
--- /dev/null
+++ b/src/main/java/io/papermc/paper/chat/ChatRenderer.java
@@ -0,0 +1,71 @@
@@ -0,0 +1,70 @@
+package io.papermc.paper.chat;
+
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.Component;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A chat renderer is responsible for rendering chat messages sent by {@link Player}s to the server.
+ */
+@NullMarked
+@FunctionalInterface
+public interface ChatRenderer {
+
+ /**
+ * Renders a chat message. This will be called once for each receiving {@link Audience}.
+ *
@ -117,15 +120,13 @@ index 0000000000000000000000000000000000000000..ffe0a921cc1ebbb95104f22b57e0e3af
+ * @return a rendered chat message
+ */
+ @ApiStatus.OverrideOnly
+ @NotNull
+ Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message, @NotNull Audience viewer);
+ Component render(Player source, Component sourceDisplayName, Component message, Audience viewer);
+
+ /**
+ * Create a new instance of the default {@link ChatRenderer}.
+ *
+ * @return a new {@link ChatRenderer}
+ */
+ @NotNull
+ static ChatRenderer defaultRenderer() {
+ return new ViewerUnawareImpl.Default((source, sourceDisplayName, message) -> Component.translatable("chat.type.text", sourceDisplayName, message));
+ }
@ -141,8 +142,7 @@ index 0000000000000000000000000000000000000000..ffe0a921cc1ebbb95104f22b57e0e3af
+ * @param renderer the viewer unaware renderer
+ * @return a new {@link ChatRenderer}
+ */
+ @NotNull
+ static ChatRenderer viewerUnaware(final @NotNull ViewerUnaware renderer) {
+ static ChatRenderer viewerUnaware(final ViewerUnaware renderer) {
+ return new ViewerUnawareImpl(renderer);
+ }
+
@ -152,6 +152,7 @@ index 0000000000000000000000000000000000000000..ffe0a921cc1ebbb95104f22b57e0e3af
+ * @see ChatRenderer#viewerUnaware(ViewerUnaware)
+ */
+ interface ViewerUnaware {
+
+ /**
+ * Renders a chat message.
+ *
@ -161,24 +162,26 @@ index 0000000000000000000000000000000000000000..ffe0a921cc1ebbb95104f22b57e0e3af
+ * @return a rendered chat message
+ */
+ @ApiStatus.OverrideOnly
+ @NotNull
+ Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message);
+ Component render(Player source, Component sourceDisplayName, Component message);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java b/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ad76b1751ba707f7ae0d283aa1cbaf6c9619da9
index 0000000000000000000000000000000000000000..e1ef23b4bdf60a299d6d37099cef777b3de13ac7
--- /dev/null
+++ b/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java
@@ -0,0 +1,35 @@
@@ -0,0 +1,38 @@
+package io.papermc.paper.chat;
+
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.Component;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+@ApiStatus.Internal
+@NullMarked
+sealed class ViewerUnawareImpl implements ChatRenderer, ChatRenderer.ViewerUnaware permits ViewerUnawareImpl.Default {
+ private final ViewerUnaware unaware;
+ private @Nullable Component message;
@ -188,12 +191,12 @@ index 0000000000000000000000000000000000000000..2ad76b1751ba707f7ae0d283aa1cbaf6
+ }
+
+ @Override
+ public @NotNull Component render(final @NotNull Player source, final @NotNull Component sourceDisplayName, final @NotNull Component message, final @NotNull Audience viewer) {
+ public Component render(final Player source, final Component sourceDisplayName, final Component message, final Audience viewer) {
+ return this.render(source, sourceDisplayName, message);
+ }
+
+ @Override
+ public @NotNull Component render(final @NotNull Player source, final @NotNull Component sourceDisplayName, final @NotNull Component message) {
+ public Component render(final Player source, final Component sourceDisplayName, final Component message) {
+ if (this.message == null) {
+ this.message = this.unaware.render(source, sourceDisplayName, message);
+ }
@ -208,13 +211,14 @@ index 0000000000000000000000000000000000000000..2ad76b1751ba707f7ae0d283aa1cbaf6
+}
diff --git a/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803a7017a28
index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0facfaa305
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java
@@ -0,0 +1,127 @@
@@ -0,0 +1,122 @@
+package io.papermc.paper.event.player;
+
+import io.papermc.paper.chat.ChatRenderer;
+import java.util.Set;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.chat.SignedMessage;
+import net.kyori.adventure.text.Component;
@ -222,9 +226,7 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+import org.jspecify.annotations.NullMarked;
+
+import static java.util.Objects.requireNonNull;
+
@ -232,6 +234,7 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+ * An abstract implementation of a chat event, handling shared logic.
+ */
+@ApiStatus.NonExtendable
+@NullMarked
+public abstract class AbstractChatEvent extends PlayerEvent implements Cancellable {
+
+ private final Set<Audience> viewers;
@ -242,7 +245,7 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+
+ private boolean cancelled;
+
+ AbstractChatEvent(final boolean async, final @NotNull Player player, final @NotNull Set<Audience> viewers, final @NotNull ChatRenderer renderer, final @NotNull Component message, final @NotNull Component originalMessage, final @NotNull SignedMessage signedMessage) {
+ AbstractChatEvent(final boolean async, final Player player, final Set<Audience> viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) {
+ super(player, async);
+ this.viewers = viewers;
+ this.renderer = renderer;
@ -259,7 +262,6 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+ *
+ * @return a mutable set of {@link Audience audiences} who will receive the chat message
+ */
+ @NotNull
+ public final Set<Audience> viewers() {
+ return this.viewers;
+ }
@ -270,7 +272,7 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+ * @param renderer the chat renderer
+ * @throws NullPointerException if {@code renderer} is {@code null}
+ */
+ public final void renderer(final @NotNull ChatRenderer renderer) {
+ public final void renderer(final ChatRenderer renderer) {
+ this.renderer = requireNonNull(renderer, "renderer");
+ }
+
@ -279,7 +281,6 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+ *
+ * @return the chat renderer
+ */
+ @NotNull
+ public final ChatRenderer renderer() {
+ return this.renderer;
+ }
@ -290,7 +291,6 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+ *
+ * @return the user-supplied message
+ */
+ @NotNull
+ public final Component message() {
+ return this.message;
+ }
@ -301,7 +301,7 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+ * @param message the user-supplied message
+ * @throws NullPointerException if {@code message} is {@code null}
+ */
+ public final void message(final @NotNull Component message) {
+ public final void message(final Component message) {
+ this.message = requireNonNull(message, "message");
+ }
+
@ -312,7 +312,6 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+ *
+ * @return the original user-supplied message
+ */
+ @NotNull
+ public final Component originalMessage() {
+ return this.originalMessage;
+ }
@ -324,7 +323,6 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+ *
+ * @return the signed message
+ */
+ @NotNull
+ public final SignedMessage signedMessage() {
+ return this.signedMessage;
+ }
@ -341,41 +339,42 @@ index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803
+}
diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..01cf89d3558132912c4d0eb48c98cd8c06e46a67
index 0000000000000000000000000000000000000000..ddd4c90f83b5cb8f069ff53760abb3c4adfd1168
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java
@@ -0,0 +1,28 @@
@@ -0,0 +1,29 @@
+package io.papermc.paper.event.player;
+
+import net.kyori.adventure.text.Component;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+@ApiStatus.Experimental
+@NullMarked
+public class AsyncChatCommandDecorateEvent extends AsyncChatDecorateEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @ApiStatus.Internal
+ public AsyncChatCommandDecorateEvent(@Nullable Player player, @NotNull Component originalMessage) {
+ public AsyncChatCommandDecorateEvent(final @Nullable Player player, final Component originalMessage) {
+ super(player, originalMessage);
+ }
+
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static @NotNull HandlerList getHandlerList() {
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e492f4cd179135bd40ad951ab23acb562be2f06
index 0000000000000000000000000000000000000000..9e5ea0cd006bd9744b84923620841f07fa40c2cb
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java
@@ -0,0 +1,105 @@
@ -387,9 +386,8 @@ index 0000000000000000000000000000000000000000..2e492f4cd179135bd40ad951ab23acb5
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.server.ServerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * This event is fired when the server decorates a component for chat purposes. This is called
@ -401,18 +399,19 @@ index 0000000000000000000000000000000000000000..2e492f4cd179135bd40ad951ab23acb5
+ * See {@link AsyncChatCommandDecorateEvent} for the decoration of messages sent via commands
+ */
+@ApiStatus.Experimental
+@NullMarked
+public class AsyncChatDecorateEvent extends ServerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final Player player;
+ private final @Nullable Player player;
+ private final Component originalMessage;
+ private Component result;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public AsyncChatDecorateEvent(final @Nullable Player player, final @NotNull Component originalMessage) {
+ public AsyncChatDecorateEvent(final @Nullable Player player, final Component originalMessage) {
+ super(true);
+ this.player = player;
+ this.originalMessage = originalMessage;
@ -436,7 +435,7 @@ index 0000000000000000000000000000000000000000..2e492f4cd179135bd40ad951ab23acb5
+ *
+ * @return the input
+ */
+ public @NotNull Component originalMessage() {
+ public Component originalMessage() {
+ return this.originalMessage;
+ }
+
@ -447,7 +446,7 @@ index 0000000000000000000000000000000000000000..2e492f4cd179135bd40ad951ab23acb5
+ *
+ * @return the result
+ */
+ public @NotNull Component result() {
+ public Component result() {
+ return this.result;
+ }
+
@ -456,7 +455,7 @@ index 0000000000000000000000000000000000000000..2e492f4cd179135bd40ad951ab23acb5
+ *
+ * @param result the result
+ */
+ public void result(@NotNull Component result) {
+ public void result(final Component result) {
+ this.result = result;
+ }
+
@ -471,36 +470,36 @@ index 0000000000000000000000000000000000000000..2e492f4cd179135bd40ad951ab23acb5
+ * component.
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static @NotNull HandlerList getHandlerList() {
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..4adae8b8a8640ffbd6a86b0908ca21fded737b88
index 0000000000000000000000000000000000000000..50c3e117dec63811823b4e6395bf4f090692ee8c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java
@@ -0,0 +1,45 @@
@@ -0,0 +1,44 @@
+package io.papermc.paper.event.player;
+
+import java.util.Set;
+import io.papermc.paper.chat.ChatRenderer;
+import java.util.Set;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.chat.SignedMessage;
+import net.kyori.adventure.text.Component;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * An event fired when a {@link Player} sends a chat message to the server.
@ -515,36 +514,35 @@ index 0000000000000000000000000000000000000000..4adae8b8a8640ffbd6a86b0908ca21fd
+ * Care should be taken to check {@link #isAsynchronous()} and treat the event
+ * appropriately.
+ */
+@NullMarked
+public final class AsyncChatEvent extends AbstractChatEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @ApiStatus.Internal
+ public AsyncChatEvent(final boolean async, final @NotNull Player player, final @NotNull Set<Audience> viewers, final @NotNull ChatRenderer renderer, final @NotNull Component message, final @NotNull Component originalMessage, final @NotNull SignedMessage signedMessage) {
+ public AsyncChatEvent(final boolean async, final Player player, final Set<Audience> viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) {
+ super(async, player, viewers, renderer, message, originalMessage, signedMessage);
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/io/papermc/paper/event/player/ChatEvent.java b/src/main/java/io/papermc/paper/event/player/ChatEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..7411f58f9f36beaadcc47c2264a4af313956ee03
index 0000000000000000000000000000000000000000..42a82ce2316a4aad2883d24c7e2ff95d95f5881a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/ChatEvent.java
@@ -0,0 +1,41 @@
@@ -0,0 +1,40 @@
+package io.papermc.paper.event.player;
+
+import java.util.Set;
+import io.papermc.paper.chat.ChatRenderer;
+import java.util.Set;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.chat.SignedMessage;
+import net.kyori.adventure.text.Component;
@ -552,7 +550,7 @@ index 0000000000000000000000000000000000000000..7411f58f9f36beaadcc47c2264a4af31
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * An event fired when a {@link Player} sends a chat message to the server.
@ -562,34 +560,34 @@ index 0000000000000000000000000000000000000000..7411f58f9f36beaadcc47c2264a4af31
+ */
+@Deprecated
+@Warning(reason = "Listening to this event forces chat to wait for the main thread, delaying chat messages.")
+@NullMarked
+public final class ChatEvent extends AbstractChatEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @ApiStatus.Internal
+ public ChatEvent(final @NotNull Player player, final @NotNull Set<Audience> viewers, final @NotNull ChatRenderer renderer, final @NotNull Component message, final @NotNull Component originalMessage, final @NotNull SignedMessage signedMessage) {
+ public ChatEvent(final Player player, final Set<Audience> viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) {
+ super(false, player, viewers, renderer, message, originalMessage, signedMessage);
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/io/papermc/paper/text/PaperComponents.java b/src/main/java/io/papermc/paper/text/PaperComponents.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b9042d0bb
index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bde50e0147
--- /dev/null
+++ b/src/main/java/io/papermc/paper/text/PaperComponents.java
@@ -0,0 +1,177 @@
@@ -0,0 +1,180 @@
+package io.papermc.paper.text;
+
+import java.io.IOException;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.flattener.ComponentFlattener;
+import net.kyori.adventure.text.format.NamedTextColor;
@ -600,15 +598,15 @@ index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Entity;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Paper API-specific methods for working with {@link Component}s and related.
+ */
+@NullMarked
+public final class PaperComponents {
+
+ private PaperComponents() {
+ throw new RuntimeException("PaperComponents is not to be instantiated!");
+ }
@ -638,7 +636,7 @@ index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b
+ * @return the resolved component
+ * @throws IOException if a syntax error tripped during resolving
+ */
+ public static @NotNull Component resolveWithContext(@NotNull Component input, @Nullable CommandSender context, @Nullable Entity scoreboardSubject) throws IOException {
+ public static Component resolveWithContext(final Component input, final @Nullable CommandSender context, final @Nullable Entity scoreboardSubject) throws IOException {
+ return resolveWithContext(input, context, scoreboardSubject, true);
+ }
+
@ -669,7 +667,8 @@ index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b
+ * @return the resolved component
+ * @throws IOException if a syntax error tripped during resolving
+ */
+ public static @NotNull Component resolveWithContext(@NotNull Component input, @Nullable CommandSender context, @Nullable Entity scoreboardSubject, boolean bypassPermissions) throws IOException {
+ @SuppressWarnings("deprecation") // using unsafe as a bridge
+ public static Component resolveWithContext(final Component input, final @Nullable CommandSender context, final @Nullable Entity scoreboardSubject, final boolean bypassPermissions) throws IOException {
+ return Bukkit.getUnsafe().resolveWithContext(input, context, scoreboardSubject, bypassPermissions);
+ }
+
@ -678,7 +677,8 @@ index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b
+ *
+ * @return a component flattener
+ */
+ public static @NotNull ComponentFlattener flattener() {
+ @SuppressWarnings("deprecation") // using unsafe as a bridge
+ public static ComponentFlattener flattener() {
+ return Bukkit.getUnsafe().componentFlattener();
+ }
+
@ -693,7 +693,7 @@ index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b
+ * @deprecated will be removed in adventure 5.0.0, use {@link PlainTextComponentSerializer#plainText()}
+ */
+ @Deprecated(forRemoval = true, since = "1.18.1")
+ public static @NotNull PlainComponentSerializer plainSerializer() {
+ public static PlainComponentSerializer plainSerializer() {
+ return Bukkit.getUnsafe().plainComponentSerializer();
+ }
+
@ -708,7 +708,7 @@ index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b
+ * @deprecated use {@link PlainTextComponentSerializer#plainText()}
+ */
+ @Deprecated(forRemoval = true, since = "1.18.2")
+ public static @NotNull PlainTextComponentSerializer plainTextSerializer() {
+ public static PlainTextComponentSerializer plainTextSerializer() {
+ return Bukkit.getUnsafe().plainTextSerializer();
+ }
+
@ -724,7 +724,7 @@ index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b
+ * @deprecated use {@link GsonComponentSerializer#gson()}
+ */
+ @Deprecated(forRemoval = true, since = "1.18.2")
+ public static @NotNull GsonComponentSerializer gsonSerializer() {
+ public static GsonComponentSerializer gsonSerializer() {
+ return Bukkit.getUnsafe().gsonComponentSerializer();
+ }
+
@ -741,7 +741,7 @@ index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b
+ * @deprecated use {@link GsonComponentSerializer#colorDownsamplingGson()}
+ */
+ @Deprecated(forRemoval = true, since = "1.18.2")
+ public static @NotNull GsonComponentSerializer colorDownsamplingGsonSerializer() {
+ public static GsonComponentSerializer colorDownsamplingGsonSerializer() {
+ return Bukkit.getUnsafe().colorDownsamplingGsonComponentSerializer();
+ }
+
@ -761,7 +761,7 @@ index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b
+ * @deprecated use {@link LegacyComponentSerializer#legacySection()}
+ */
+ @Deprecated(forRemoval = true, since = "1.18.2")
+ public static @NotNull LegacyComponentSerializer legacySectionSerializer() {
+ public static LegacyComponentSerializer legacySectionSerializer() {
+ return Bukkit.getUnsafe().legacyComponentSerializer();
+ }
+}

View file

@ -6,22 +6,25 @@ Subject: [PATCH] Paper Utils
diff --git a/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java b/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java
new file mode 100644
index 0000000000000000000000000000000000000000..9db0056ab94145819628b3ad8d8d26130d117fcf
index 0000000000000000000000000000000000000000..fbcd82b513b4cb9839f9d2b38d9c6c73148e30a6
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java
@@ -0,0 +1,16 @@
@@ -0,0 +1,19 @@
+package com.destroystokyo.paper.util;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+public class SneakyThrow {
+@ApiStatus.Internal
+@NullMarked
+public final class SneakyThrow {
+
+ public static void sneaky(@NotNull Throwable exception) {
+ SneakyThrow.<RuntimeException>throwSneaky(exception);
+ public static void sneaky(final Throwable exception) {
+ SneakyThrow.throwSneaky(exception);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T extends Throwable> void throwSneaky(@NotNull Throwable exception) throws T {
+ private static <T extends Throwable> void throwSneaky(final Throwable exception) throws T {
+ throw (T) exception;
+ }
+

View file

@ -6,7 +6,7 @@ Subject: [PATCH] Use ASM for event executors.
Uses method handles for private or static methods.
diff --git a/build.gradle.kts b/build.gradle.kts
index af3514113abdf3f42c41f1e7ff0f930cc1a417f5..ed0b67ac322aa22b191cd35502ae5b4f20af19f8 100644
index 74f0e2b812c1e2e922b136fefe505fc8cbe33e83..1f627e81622e77b81b1228a467fbb9e6fd979e7a 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -47,6 +47,9 @@ dependencies {
@ -21,127 +21,138 @@ index af3514113abdf3f42c41f1e7ff0f930cc1a417f5..ed0b67ac322aa22b191cd35502ae5b4f
compileOnly("org.apache.maven:maven-resolver-provider:3.9.6")
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b28e9b1daba7834af67dbc193dd656bedd9a994
index 0000000000000000000000000000000000000000..5a702481d28d90cb503faad0d9b9c3231bbff940
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java
@@ -0,0 +1,42 @@
@@ -0,0 +1,46 @@
+package com.destroystokyo.paper.event.executor;
+
+import com.destroystokyo.paper.util.SneakyThrow;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+
+import com.destroystokyo.paper.util.SneakyThrow;
+import org.bukkit.event.Event;
+import org.bukkit.event.EventException;
+import org.bukkit.event.Listener;
+import org.bukkit.plugin.EventExecutor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+@ApiStatus.Internal
+@NullMarked
+public class MethodHandleEventExecutor implements EventExecutor {
+
+ private final Class<? extends Event> eventClass;
+ private final MethodHandle handle;
+
+ public MethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull MethodHandle handle) {
+ public MethodHandleEventExecutor(final Class<? extends Event> eventClass, final MethodHandle handle) {
+ this.eventClass = eventClass;
+ this.handle = handle;
+ }
+
+ public MethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull Method m) {
+ public MethodHandleEventExecutor(final Class<? extends Event> eventClass, final Method m) {
+ this.eventClass = eventClass;
+ try {
+ m.setAccessible(true);
+ this.handle = MethodHandles.lookup().unreflect(m);
+ } catch (IllegalAccessException e) {
+ } catch (final IllegalAccessException e) {
+ throw new AssertionError("Unable to set accessible", e);
+ }
+ }
+
+ @Override
+ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException {
+ if (!eventClass.isInstance(event)) return;
+ public void execute(final Listener listener, final Event event) throws EventException {
+ if (!this.eventClass.isInstance(event)) return;
+ try {
+ handle.invoke(listener, event);
+ } catch (Throwable t) {
+ this.handle.invoke(listener, event);
+ } catch (final Throwable t) {
+ SneakyThrow.sneaky(t);
+ }
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..827f2b27f70a7ec0bc11d039305c3e58c02a4ef4
index 0000000000000000000000000000000000000000..bbdb5b472df116b71c459bdc6cc4b74267ea0f5e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java
@@ -0,0 +1,42 @@
@@ -0,0 +1,44 @@
+package com.destroystokyo.paper.event.executor;
+
+import com.destroystokyo.paper.util.SneakyThrow;
+import com.google.common.base.Preconditions;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import com.destroystokyo.paper.util.SneakyThrow;
+import com.google.common.base.Preconditions;
+
+import org.bukkit.event.Event;
+import org.bukkit.event.EventException;
+import org.bukkit.event.Listener;
+import org.bukkit.plugin.EventExecutor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+@ApiStatus.Internal
+@NullMarked
+public class StaticMethodHandleEventExecutor implements EventExecutor {
+
+ private final Class<? extends Event> eventClass;
+ private final MethodHandle handle;
+
+ public StaticMethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull Method m) {
+ public StaticMethodHandleEventExecutor(final Class<? extends Event> eventClass, final Method m) {
+ Preconditions.checkArgument(Modifier.isStatic(m.getModifiers()), "Not a static method: %s", m);
+ Preconditions.checkArgument(eventClass != null, "eventClass is null");
+ this.eventClass = eventClass;
+ try {
+ m.setAccessible(true);
+ this.handle = MethodHandles.lookup().unreflect(m);
+ } catch (IllegalAccessException e) {
+ } catch (final IllegalAccessException e) {
+ throw new AssertionError("Unable to set accessible", e);
+ }
+ }
+
+ @Override
+ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException {
+ if (!eventClass.isInstance(event)) return;
+ public void execute(final Listener listener, final Event event) throws EventException {
+ if (!this.eventClass.isInstance(event)) return;
+ try {
+ handle.invoke(event);
+ } catch (Throwable throwable) {
+ this.handle.invoke(event);
+ } catch (final Throwable throwable) {
+ SneakyThrow.sneaky(throwable);
+ }
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..084c31af1a7ba32bb4c3dc8f16f67fd09ce0b6a4
index 0000000000000000000000000000000000000000..abfcb6e8383ff311940d82afe4ff990649a082dc
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java
@@ -0,0 +1,54 @@
@@ -0,0 +1,59 @@
+package com.destroystokyo.paper.event.executor.asm;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.bukkit.plugin.EventExecutor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.GeneratorAdapter;
+
+import static org.objectweb.asm.Opcodes.*;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+import static org.objectweb.asm.Opcodes.V1_8;
+
+public class ASMEventExecutorGenerator {
+@ApiStatus.Internal
+@NullMarked
+public final class ASMEventExecutorGenerator {
+
+ private static final String EXECUTE_DESCRIPTOR = "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Event;)V";
+
+ @NotNull
+ public static byte[] generateEventExecutor(@NotNull Method m, @NotNull String name) {
+ ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+ writer.visit(V1_8, ACC_PUBLIC, name.replace('.', '/'), null, Type.getInternalName(Object.class), new String[] {Type.getInternalName(EventExecutor.class)});
+ public static byte[] generateEventExecutor(final Method m, final String name) {
+ final ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+ writer.visit(V1_8, ACC_PUBLIC, name.replace('.', '/'), null, Type.getInternalName(Object.class), new String[]{Type.getInternalName(EventExecutor.class)});
+ // Generate constructor
+ GeneratorAdapter methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null), ACC_PUBLIC, "<init>", "()V");
+ methodGenerator.loadThis();
@ -169,22 +180,25 @@ index 0000000000000000000000000000000000000000..084c31af1a7ba32bb4c3dc8f16f67fd0
+ }
+
+ public static AtomicInteger NEXT_ID = new AtomicInteger(1);
+ @NotNull
+
+ public static String generateName() {
+ int id = NEXT_ID.getAndIncrement();
+ final int id = NEXT_ID.getAndIncrement();
+ return "com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor" + id;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java
new file mode 100644
index 0000000000000000000000000000000000000000..f79685b48bb581277a6891927988b6f7a4389dc4
index 0000000000000000000000000000000000000000..581561fbd32c81ab1774ba8f0b7f3cec9392d99a
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java
@@ -0,0 +1,34 @@
@@ -0,0 +1,35 @@
+package com.destroystokyo.paper.event.executor.asm;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+@ApiStatus.Internal
+@NullMarked
+public interface ClassDefiner {
+
+ /**
@ -192,7 +206,7 @@ index 0000000000000000000000000000000000000000..f79685b48bb581277a6891927988b6f7
+ *
+ * @return if classes bypass access checks
+ */
+ public default boolean isBypassAccessChecks() {
+ default boolean isBypassAccessChecks() {
+ return false;
+ }
+
@ -206,79 +220,79 @@ index 0000000000000000000000000000000000000000..f79685b48bb581277a6891927988b6f7
+ * @throws ClassFormatError if the class data is invalid
+ * @throws NullPointerException if any of the arguments are null
+ */
+ @NotNull
+ public Class<?> defineClass(@NotNull ClassLoader parentLoader, @NotNull String name, @NotNull byte[] data);
+ Class<?> defineClass(ClassLoader parentLoader, String name, byte[] data);
+
+ @NotNull
+ public static ClassDefiner getInstance() {
+ static ClassDefiner getInstance() {
+ return SafeClassDefiner.INSTANCE;
+ }
+
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java
new file mode 100644
index 0000000000000000000000000000000000000000..abcc966d8ee01d73c1d1480237ab46fa0ab55fdc
index 0000000000000000000000000000000000000000..48bcc72293c2a31b6e2dd2dcd6a79d618c72a137
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java
@@ -0,0 +1,64 @@
@@ -0,0 +1,66 @@
+package com.destroystokyo.paper.event.executor.asm;
+
+import java.util.concurrent.ConcurrentMap;
+
+import com.google.common.base.Preconditions;
+
+import com.google.common.collect.MapMaker;
+import org.jetbrains.annotations.NotNull;
+import java.util.concurrent.ConcurrentMap;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+@ApiStatus.Internal
+@NullMarked
+public class SafeClassDefiner implements ClassDefiner {
+
+ /* default */ static final SafeClassDefiner INSTANCE = new SafeClassDefiner();
+
+ private SafeClassDefiner() {}
+ private SafeClassDefiner() {
+ }
+
+ private final ConcurrentMap<ClassLoader, GeneratedClassLoader> loaders = new MapMaker().weakKeys().makeMap();
+
+ @NotNull
+ @Override
+ public Class<?> defineClass(@NotNull ClassLoader parentLoader, @NotNull String name, @NotNull byte[] data) {
+ GeneratedClassLoader loader = loaders.computeIfAbsent(parentLoader, GeneratedClassLoader::new);
+ public Class<?> defineClass(final ClassLoader parentLoader, final String name, final byte[] data) {
+ final GeneratedClassLoader loader = this.loaders.computeIfAbsent(parentLoader, GeneratedClassLoader::new);
+ synchronized (loader.getClassLoadingLock(name)) {
+ Preconditions.checkState(!loader.hasClass(name), "%s already defined", name);
+ Class<?> c = loader.define(name, data);
+ final Class<?> c = loader.define(name, data);
+ assert c.getName().equals(name);
+ return c;
+ }
+ }
+
+ private static class GeneratedClassLoader extends ClassLoader {
+
+ static {
+ ClassLoader.registerAsParallelCapable();
+ }
+
+ protected GeneratedClassLoader(@NotNull ClassLoader parent) {
+ protected GeneratedClassLoader(final ClassLoader parent) {
+ super(parent);
+ }
+
+ private Class<?> define(@NotNull String name, byte[] data) {
+ synchronized (getClassLoadingLock(name)) {
+ assert !hasClass(name);
+ Class<?> c = defineClass(name, data, 0, data.length);
+ resolveClass(c);
+ private Class<?> define(final String name, final byte[] data) {
+ synchronized (this.getClassLoadingLock(name)) {
+ assert !this.hasClass(name);
+ final Class<?> c = this.defineClass(name, data, 0, data.length);
+ this.resolveClass(c);
+ return c;
+ }
+ }
+
+ @Override
+ @NotNull
+ public Object getClassLoadingLock(@NotNull String name) {
+ public Object getClassLoadingLock(final String name) {
+ return super.getClassLoadingLock(name);
+ }
+
+ public boolean hasClass(@NotNull String name) {
+ synchronized (getClassLoadingLock(name)) {
+ public boolean hasClass(final String name) {
+ synchronized (this.getClassLoadingLock(name)) {
+ try {
+ Class.forName(name);
+ return true;
+ } catch (ClassNotFoundException e) {
+ } catch (final ClassNotFoundException e) {
+ return false;
+ }
+ }

View file

@ -5,7 +5,7 @@ Subject: [PATCH] Paper Plugins
diff --git a/build.gradle.kts b/build.gradle.kts
index ed0b67ac322aa22b191cd35502ae5b4f20af19f8..258d7010d24c529c9bbc76cc26adf226c641ee58 100644
index 1f627e81622e77b81b1228a467fbb9e6fd979e7a..3c50362de25617d878ef58f14f67c240005ff624 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -52,7 +52,7 @@ dependencies {
@ -17,7 +17,7 @@ index ed0b67ac322aa22b191cd35502ae5b4f20af19f8..258d7010d24c529c9bbc76cc26adf226
compileOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
compileOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18")
@@ -139,6 +139,7 @@ tasks.withType<Javadoc> {
@@ -141,6 +141,7 @@ tasks.withType<Javadoc> {
"https://jd.advntr.dev/text-serializer-plain/$adventureVersion/",
"https://jd.advntr.dev/text-logger-slf4j/$adventureVersion/",
// Paper end
@ -27,26 +27,26 @@ index ed0b67ac322aa22b191cd35502ae5b4f20af19f8..258d7010d24c529c9bbc76cc26adf226
diff --git a/src/main/java/io/papermc/paper/plugin/PermissionManager.java b/src/main/java/io/papermc/paper/plugin/PermissionManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c27846933
index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1dac94e481
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/PermissionManager.java
@@ -0,0 +1,171 @@
@@ -0,0 +1,166 @@
+package io.papermc.paper.plugin;
+
+import org.bukkit.permissions.Permissible;
+import org.bukkit.permissions.Permission;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Set;
+import org.bukkit.permissions.Permissible;
+import org.bukkit.permissions.Permission;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * A permission manager implementation to keep backwards compatibility partially alive with existing plugins that used
+ * the bukkit one before.
+ */
+@ApiStatus.Experimental
+@NullMarked
+public interface PermissionManager {
+
+ /**
@ -55,8 +55,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param name Name of the permission
+ * @return Permission, or null if none
+ */
+ @Nullable
+ Permission getPermission(@NotNull String name);
+ @Nullable Permission getPermission(String name);
+
+ /**
+ * Adds a {@link Permission} to this plugin manager.
@ -68,7 +67,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @throws IllegalArgumentException Thrown when a permission with the same
+ * name already exists
+ */
+ void addPermission(@NotNull Permission perm);
+ void addPermission(Permission perm);
+
+ /**
+ * Removes a {@link Permission} registration from this plugin manager.
@ -81,7 +80,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ *
+ * @param perm Permission to remove
+ */
+ void removePermission(@NotNull Permission perm);
+ void removePermission(Permission perm);
+
+ /**
+ * Removes a {@link Permission} registration from this plugin manager.
@ -94,7 +93,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ *
+ * @param name Permission to remove
+ */
+ void removePermission(@NotNull String name);
+ void removePermission(String name);
+
+ /**
+ * Gets the default permissions for the given op status
@ -102,7 +101,6 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param op Which set of default permissions to get
+ * @return The default permissions
+ */
+ @NotNull
+ Set<Permission> getDefaultPermissions(boolean op);
+
+ /**
@ -113,7 +111,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ *
+ * @param perm Permission to recalculate
+ */
+ void recalculatePermissionDefaults(@NotNull Permission perm);
+ void recalculatePermissionDefaults(Permission perm);
+
+ /**
+ * Subscribes the given Permissible for information about the requested
@ -125,7 +123,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param permission Permission to subscribe to
+ * @param permissible Permissible subscribing
+ */
+ void subscribeToPermission(@NotNull String permission, @NotNull Permissible permissible);
+ void subscribeToPermission(String permission, Permissible permissible);
+
+ /**
+ * Unsubscribes the given Permissible for information about the requested
@ -134,7 +132,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param permission Permission to unsubscribe from
+ * @param permissible Permissible subscribing
+ */
+ void unsubscribeFromPermission(@NotNull String permission, @NotNull Permissible permissible);
+ void unsubscribeFromPermission(String permission, Permissible permissible);
+
+ /**
+ * Gets a set containing all subscribed {@link Permissible}s to the given
@ -143,8 +141,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param permission Permission to query for
+ * @return Set containing all subscribed permissions
+ */
+ @NotNull
+ Set<Permissible> getPermissionSubscriptions(@NotNull String permission);
+ Set<Permissible> getPermissionSubscriptions(String permission);
+
+ /**
+ * Subscribes to the given Default permissions by operator status
@ -155,7 +152,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param op Default list to subscribe to
+ * @param permissible Permissible subscribing
+ */
+ void subscribeToDefaultPerms(boolean op, @NotNull Permissible permissible);
+ void subscribeToDefaultPerms(boolean op, Permissible permissible);
+
+ /**
+ * Unsubscribes from the given Default permissions by operator status
@ -163,7 +160,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param op Default list to unsubscribe from
+ * @param permissible Permissible subscribing
+ */
+ void unsubscribeFromDefaultPerms(boolean op, @NotNull Permissible permissible);
+ void unsubscribeFromDefaultPerms(boolean op, Permissible permissible);
+
+ /**
+ * Gets a set containing all subscribed {@link Permissible}s to the given
@ -172,7 +169,6 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param op Default list to query for
+ * @return Set containing all subscribed permissions
+ */
+ @NotNull
+ Set<Permissible> getDefaultPermSubscriptions(boolean op);
+
+ /**
@ -182,7 +178,6 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ *
+ * @return Set containing all current registered permissions
+ */
+ @NotNull
+ Set<Permission> getPermissions();
+
+ /**
@ -192,7 +187,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ *
+ * @param perm permission
+ */
+ void addPermissions(@NotNull List<Permission> perm);
+ void addPermissions(List<Permission> perm);
+
+ /**
+ * Clears the current registered permissinos.
@ -204,13 +199,14 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+}
diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..70d5f9802f90605a5120ff2a000a2e9395f0aecc
index 0000000000000000000000000000000000000000..4c47414fc08e1183b1e59369bacc4d7f7042f262
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java
@@ -0,0 +1,14 @@
@@ -0,0 +1,16 @@
+package io.papermc.paper.plugin.bootstrap;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents the context provided to a {@link PluginBootstrap} during both the bootstrapping and plugin
@ -219,12 +215,13 @@ index 0000000000000000000000000000000000000000..70d5f9802f90605a5120ff2a000a2e93
+ * like the plugin's configuration or logger during the plugins bootstrap.
+ */
+@ApiStatus.Experimental
+@NullMarked
+@ApiStatus.NonExtendable
+public interface BootstrapContext extends PluginProviderContext {
+}
diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrap.java b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrap.java
new file mode 100644
index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8d287a11f
index 0000000000000000000000000000000000000000..e6696dcd8049e869bd1733f7c67ff802c54d7c37
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrap.java
@@ -0,0 +1,41 @@
@ -233,7 +230,7 @@ index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8
+import io.papermc.paper.plugin.provider.util.ProviderUtil;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A plugin bootstrap is meant for loading certain parts of the plugin before the server is loaded.
@ -245,8 +242,9 @@ index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8
+ * <p>
+ * <b>All calls to Bukkit may throw a NullPointerExceptions or return null unexpectedly. You should only call api methods that are explicitly documented to work in the bootstrapper</b>
+ */
+@ApiStatus.OverrideOnly
+@ApiStatus.Experimental
+@NullMarked
+@ApiStatus.OverrideOnly
+public interface PluginBootstrap {
+
+ /**
@ -254,7 +252,7 @@ index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8
+ *
+ * @param context the server provided context
+ */
+ void bootstrap(@NotNull BootstrapContext context);
+ void bootstrap(BootstrapContext context);
+
+ /**
+ * Called by the server to instantiate your main class.
@ -264,25 +262,23 @@ index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8
+ * @param context the server created bootstrap object
+ * @return the server requested instance of the plugins main class.
+ */
+ @NotNull
+ default JavaPlugin createPlugin(@NotNull PluginProviderContext context) {
+ default JavaPlugin createPlugin(final PluginProviderContext context) {
+ return ProviderUtil.loadClass(context.getConfiguration().getMainClass(), JavaPlugin.class, this.getClass().getClassLoader());
+ }
+}
diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginProviderContext.java b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginProviderContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba46282bea5d1a
index 0000000000000000000000000000000000000000..19bb302ab264b72306d9bd15e9c40ade6dde7ee7
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginProviderContext.java
@@ -0,0 +1,52 @@
@@ -0,0 +1,48 @@
+package io.papermc.paper.plugin.bootstrap;
+
+import io.papermc.paper.plugin.configuration.PluginMeta;
+import java.nio.file.Path;
+import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.nio.file.Path;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents the context provided to a {@link PluginBootstrap} during both the bootstrapping and plugin
@ -290,8 +286,9 @@ index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba4628
+ * A bootstrap context may be used to access data or logic usually provided to {@link org.bukkit.plugin.Plugin} instances
+ * like the plugin's configuration or logger during the plugins bootstrap.
+ */
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental
+@NullMarked
+@ApiStatus.NonExtendable
+public interface PluginProviderContext {
+
+ /**
@ -299,7 +296,6 @@ index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba4628
+ *
+ * @return the plugin's configuration
+ */
+ @NotNull
+ PluginMeta getConfiguration();
+
+ /**
@ -307,7 +303,6 @@ index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba4628
+ *
+ * @return the previously described path
+ */
+ @NotNull
+ Path getDataDirectory();
+
+ /**
@ -315,7 +310,6 @@ index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba4628
+ *
+ * @return the logger instance
+ */
+ @NotNull
+ ComponentLogger getLogger();
+
+ /**
@ -323,33 +317,32 @@ index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba4628
+ *
+ * @return the previously described path
+ */
+ @NotNull
+ Path getPluginSource();
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/configuration/PluginMeta.java b/src/main/java/io/papermc/paper/plugin/configuration/PluginMeta.java
new file mode 100644
index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9ada2e585f
index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c85670bad8
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/configuration/PluginMeta.java
@@ -0,0 +1,203 @@
@@ -0,0 +1,186 @@
+package io.papermc.paper.plugin.configuration;
+
+import java.util.List;
+import org.bukkit.permissions.Permission;
+import org.bukkit.permissions.PermissionDefault;
+import org.bukkit.plugin.PluginLoadOrder;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * This class acts as an abstraction for a plugin configuration.
+ */
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental // Subject to change!
+@NullMarked
+@ApiStatus.NonExtendable
+public interface PluginMeta {
+
+ /**
@ -369,7 +362,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return the name of the plugin
+ */
+ @NotNull
+ String getName();
+
+ /**
@ -377,7 +369,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return a descriptive name of the plugin and respective version
+ */
+ @NotNull
+ default String getDisplayName() {
+ return this.getName() + " v" + this.getVersion();
+ }
@ -388,7 +379,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return the fully qualified class name of the plugin's main class.
+ */
+ @NotNull
+ String getMainClass();
+
+ /**
@ -397,7 +387,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ * @return the plugin load order
+ * @see PluginLoadOrder for further details regards the available load orders.
+ */
+ @NotNull
+ PluginLoadOrder getLoadOrder();
+
+ /**
@ -407,7 +396,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return the string representation of the plugin's version
+ */
+ @NotNull
+ String getVersion();
+
+ /**
@ -418,8 +406,7 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ * @return the specific overwrite of the logger prefix as defined by the plugin. If the plugin did not define a
+ * custom logger prefix, this method will return null
+ */
+ @Nullable
+ String getLoggerPrefix();
+ @Nullable String getLoggerPrefix();
+
+ /**
+ * Provides a list of dependencies that are required for this plugin to load.
@ -430,7 +417,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return an immutable list of required dependency names
+ */
+ @NotNull
+ List<String> getPluginDependencies();
+
+ /**
@ -443,7 +429,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return immutable list of soft dependencies
+ */
+ @NotNull
+ List<String> getPluginSoftDependencies();
+
+ /**
@ -456,7 +441,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return immutable list of plugins to load before this plugin
+ */
+ @NotNull
+ List<String> getLoadBeforePlugins();
+
+ /**
@ -466,7 +450,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return immutable list of provided plugins/dependencies
+ */
+ @NotNull
+ List<String> getProvidedPlugins();
+
+ /**
@ -475,7 +458,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return an immutable list of the plugin's authors
+ */
+ @NotNull
+ List<String> getAuthors();
+
+ /**
@ -484,7 +466,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return an immutable list of the plugin's contributors
+ */
+ @NotNull
+ List<String> getContributors();
+
+ /**
@ -493,8 +474,7 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return description or null if the plugin did not define a human readable description.
+ */
+ @Nullable
+ String getDescription();
+ @Nullable String getDescription();
+
+ /**
+ * Provides the website for the plugin or the plugin's author.
@ -502,8 +482,7 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return a string representation of the website that serves as the main hub for this plugin/its author.
+ */
+ @Nullable
+ String getWebsite();
+ @Nullable String getWebsite();
+
+ /**
+ * Provides the list of permissions that are defined via the plugin meta instance.
@ -511,7 +490,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ * @return an immutable list of permissions
+ */
+ // TODO: Do we even want this? Why not just use the bootstrapper
+ @NotNull
+ List<Permission> getPermissions();
+
+ /**
@ -521,7 +499,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ * @see #getPermissions()
+ */
+ // TODO: Do we even want this? Why not just use the bootstrapper
+ @NotNull
+ PermissionDefault getPermissionDefault();
+
+ /**
@ -532,8 +509,7 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ * @return the version string made up of the major and minor version (e.g. 1.18 or 1.19). Minor versions like 1.18.2
+ * are unified to their major release version (in this example 1.18)
+ */
+ @Nullable
+ String getAPIVersion();
+ @Nullable String getAPIVersion();
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/configuration/package-info.java b/src/main/java/io/papermc/paper/plugin/configuration/package-info.java
@ -552,10 +528,10 @@ index 0000000000000000000000000000000000000000..ddb3076124365d0d1a5caa32d4dcb1f4
+package io.papermc.paper.plugin.configuration;
diff --git a/src/main/java/io/papermc/paper/plugin/loader/PluginClasspathBuilder.java b/src/main/java/io/papermc/paper/plugin/loader/PluginClasspathBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..28cbc09b7c1ded1f4515969cef4a669adac85703
index 0000000000000000000000000000000000000000..ddb768057cdfd9202e4386494fd5f643692c73a1
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/PluginClasspathBuilder.java
@@ -0,0 +1,38 @@
@@ -0,0 +1,37 @@
+package io.papermc.paper.plugin.loader;
+
+import io.papermc.paper.plugin.bootstrap.PluginProviderContext;
@ -563,14 +539,15 @@ index 0000000000000000000000000000000000000000..28cbc09b7c1ded1f4515969cef4a669a
+import io.papermc.paper.plugin.loader.library.LibraryStore;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A mutable builder that may be used to collect and register all {@link ClassPathLibrary} instances a
+ * {@link PluginLoader} aims to provide to its plugin at runtime.
+ */
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental
+@NullMarked
+@ApiStatus.NonExtendable
+public interface PluginClasspathBuilder {
+
+ /**
@ -587,23 +564,21 @@ index 0000000000000000000000000000000000000000..28cbc09b7c1ded1f4515969cef4a669a
+ * @see io.papermc.paper.plugin.loader.library.impl.JarLibrary
+ * @see io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver
+ */
+ @NotNull
+ @Contract("_ -> this")
+ PluginClasspathBuilder addLibrary(@NotNull ClassPathLibrary classPathLibrary);
+ PluginClasspathBuilder addLibrary(ClassPathLibrary classPathLibrary);
+
+ @NotNull
+ PluginProviderContext getContext();
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/PluginLoader.java b/src/main/java/io/papermc/paper/plugin/loader/PluginLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..c9e31f78ff6ff969436c6d99755845786c4d383f
index 0000000000000000000000000000000000000000..c2d029e4474cc00c84e5b3f7fceec4c3f30b486b
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/PluginLoader.java
@@ -0,0 +1,30 @@
@@ -0,0 +1,31 @@
+package io.papermc.paper.plugin.loader;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A plugin loader is responsible for creating certain aspects of a plugin before it is created.
@ -615,8 +590,9 @@ index 0000000000000000000000000000000000000000..c9e31f78ff6ff969436c6d9975584578
+ * It should be noted that this class will be called from a different classloader, this will cause any static values
+ * set in this class/any other classes loaded not to persist when the plugin loads.
+ */
+@ApiStatus.OverrideOnly
+@ApiStatus.Experimental
+@NullMarked
+@ApiStatus.OverrideOnly
+public interface PluginLoader {
+
+ /**
@ -627,23 +603,24 @@ index 0000000000000000000000000000000000000000..c9e31f78ff6ff969436c6d9975584578
+ * @param classpathBuilder a mutable classpath builder that may be used to register custom runtime dependencies
+ * for the plugin the loader was registered for.
+ */
+ void classloader(@NotNull PluginClasspathBuilder classpathBuilder);
+ void classloader(PluginClasspathBuilder classpathBuilder);
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/ClassPathLibrary.java b/src/main/java/io/papermc/paper/plugin/loader/library/ClassPathLibrary.java
new file mode 100644
index 0000000000000000000000000000000000000000..1347b535d90c2c281c184d0459e7ac59c0350c9f
index 0000000000000000000000000000000000000000..8a07333a592056bab1d26d811316bb5ea5f30e18
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/ClassPathLibrary.java
@@ -0,0 +1,20 @@
@@ -0,0 +1,21 @@
+package io.papermc.paper.plugin.loader.library;
+
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * The classpath library interface represents libraries that are capable of registering themselves via
+ * {@link #register(LibraryStore)} on any given {@link LibraryStore}.
+ */
+@NullMarked
+public interface ClassPathLibrary {
+
+ /**
@ -654,7 +631,7 @@ index 0000000000000000000000000000000000000000..1347b535d90c2c281c184d0459e7ac59
+ * @param store the library store instance to register this library into
+ * @throws LibraryLoadingException if library loading failed for this classpath library
+ */
+ void register(@NotNull LibraryStore store) throws LibraryLoadingException;
+ void register(LibraryStore store) throws LibraryLoadingException;
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/LibraryLoadingException.java b/src/main/java/io/papermc/paper/plugin/loader/library/LibraryLoadingException.java
new file mode 100644
@ -679,16 +656,15 @@ index 0000000000000000000000000000000000000000..79ba423a364b50588f3ee87fdc69155c
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/LibraryStore.java b/src/main/java/io/papermc/paper/plugin/loader/library/LibraryStore.java
new file mode 100644
index 0000000000000000000000000000000000000000..0546fa1e9dcd7155086a8650806a8c086b6fc458
index 0000000000000000000000000000000000000000..93ef8e369a158c25bc4fdd553faf13c1826ad872
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/LibraryStore.java
@@ -0,0 +1,26 @@
+package io.papermc.paper.plugin.loader.library;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.nio.file.Path;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents a storage that stores library jars.
@ -699,6 +675,7 @@ index 0000000000000000000000000000000000000000..0546fa1e9dcd7155086a8650806a8c08
+ * @see io.papermc.paper.plugin.loader.PluginLoader
+ */
+@ApiStatus.Internal
+@NullMarked
+public interface LibraryStore {
+
+ /**
@ -706,12 +683,12 @@ index 0000000000000000000000000000000000000000..0546fa1e9dcd7155086a8650806a8c08
+ *
+ * @param library path to the libraries jar file on the disk
+ */
+ void addLibrary(@NotNull Path library);
+ void addLibrary(Path library);
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/impl/JarLibrary.java b/src/main/java/io/papermc/paper/plugin/loader/library/impl/JarLibrary.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff25961ee79fb
index 0000000000000000000000000000000000000000..9efcd9a62d6439eb27fc4e08498b4b7fbbdecb3c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/JarLibrary.java
@@ -0,0 +1,45 @@
@ -720,10 +697,9 @@ index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff259
+import io.papermc.paper.plugin.loader.library.ClassPathLibrary;
+import io.papermc.paper.plugin.loader.library.LibraryLoadingException;
+import io.papermc.paper.plugin.loader.library.LibraryStore;
+import org.jetbrains.annotations.NotNull;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A simple jar library implementation of the {@link ClassPathLibrary} that allows {@link io.papermc.paper.plugin.loader.PluginLoader}s to
@ -738,6 +714,7 @@ index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff259
+ * <p>
+ * The jar library implementation will error if the file does not exist at the specified path.
+ */
+@NullMarked
+public class JarLibrary implements ClassPathLibrary {
+
+ private final Path path;
@ -747,12 +724,12 @@ index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff259
+ *
+ * @param path the path, relative to the JVMs start directory.
+ */
+ public JarLibrary(@NotNull Path path) {
+ public JarLibrary(final Path path) {
+ this.path = path;
+ }
+
+ @Override
+ public void register(@NotNull LibraryStore store) throws LibraryLoadingException {
+ public void register(final LibraryStore store) throws LibraryLoadingException {
+ if (Files.notExists(this.path)) {
+ throw new LibraryLoadingException("Could not find library at " + this.path);
+ }
@ -762,7 +739,7 @@ index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff259
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19a94791ab
index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0bc3b03831
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java
@@ -0,0 +1,133 @@
@ -771,6 +748,9 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+import io.papermc.paper.plugin.loader.library.ClassPathLibrary;
+import io.papermc.paper.plugin.loader.library.LibraryLoadingException;
+import io.papermc.paper.plugin.loader.library.LibraryStore;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
@ -791,14 +771,10 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+import org.eclipse.aether.transfer.TransferCancelledException;
+import org.eclipse.aether.transfer.TransferEvent;
+import org.eclipse.aether.transport.http.HttpTransporterFactory;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The maven library resolver acts as a resolver for yet to be resolved jar libraries that may be pulled from a
+ * remote maven repository.
@ -813,12 +789,13 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ * "central", "default", "https://repo1.maven.org/maven2/"
+ * ).build());
+ * }</pre>
+ *
+ * <p>
+ * Plugins may create and register a {@link MavenLibraryResolver} after configuring it.
+ */
+@NullMarked
+public class MavenLibraryResolver implements ClassPathLibrary {
+
+ private static final Logger logger = LoggerFactory.getLogger("MavenLibraryResolver");
+ private static final Logger LOGGER = LoggerFactory.getLogger("MavenLibraryResolver");
+
+ private final RepositorySystem repository;
+ private final DefaultRepositorySystemSession session;
@ -834,7 +811,7 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ * submitting the {@link MavenLibraryResolver} to the {@link io.papermc.paper.plugin.loader.PluginClasspathBuilder}.
+ */
+ public MavenLibraryResolver() {
+ DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
+ final DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
+ locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
+ locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
+
@ -846,8 +823,8 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ this.session.setLocalRepositoryManager(this.repository.newLocalRepositoryManager(this.session, new LocalRepository("libraries")));
+ this.session.setTransferListener(new AbstractTransferListener() {
+ @Override
+ public void transferInitiated(@NotNull TransferEvent event) throws TransferCancelledException {
+ logger.info("Downloading {}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
+ public void transferInitiated(final TransferEvent event) throws TransferCancelledException {
+ LOGGER.info("Downloading {}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
+ }
+ });
+ this.session.setReadOnly();
@ -860,7 +837,7 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ * @param dependency the definition of the dependency the maven library resolver should resolve when running
+ * @see MavenLibraryResolver#addRepository(RemoteRepository)
+ */
+ public void addDependency(@NotNull Dependency dependency) {
+ public void addDependency(final Dependency dependency) {
+ this.dependencies.add(dependency);
+ }
+
@ -870,9 +847,9 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ * repository.
+ *
+ * @param remoteRepository the configuration that defines the maven repository this library resolver should fetch
+ * dependencies from
+ * dependencies from
+ */
+ public void addRepository(@NotNull RemoteRepository remoteRepository) {
+ public void addRepository(final RemoteRepository remoteRepository) {
+ this.repositories.add(remoteRepository);
+ }
+
@ -883,32 +860,32 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ * @throws LibraryLoadingException if resolving a dependency failed
+ */
+ @Override
+ public void register(@NotNull LibraryStore store) throws LibraryLoadingException {
+ List<RemoteRepository> repos = this.repository.newResolutionRepositories(this.session, this.repositories);
+ public void register(final LibraryStore store) throws LibraryLoadingException {
+ final List<RemoteRepository> repos = this.repository.newResolutionRepositories(this.session, this.repositories);
+
+ DependencyResult result;
+ final DependencyResult result;
+ try {
+ result = this.repository.resolveDependencies(this.session, new DependencyRequest(new CollectRequest((Dependency) null, this.dependencies, repos), null));
+ } catch (DependencyResolutionException ex) {
+ } catch (final DependencyResolutionException ex) {
+ throw new LibraryLoadingException("Error resolving libraries", ex);
+ }
+
+ for (ArtifactResult artifact : result.getArtifactResults()) {
+ File file = artifact.getArtifact().getFile();
+ for (final ArtifactResult artifact : result.getArtifactResults()) {
+ final File file = artifact.getArtifact().getFile();
+ store.addLibrary(file.toPath());
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/ClassLoaderAccess.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/ClassLoaderAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..64e46fdfa4d404cb08c67a456e5990b729296b98
index 0000000000000000000000000000000000000000..75fe408ec742319c3cba2461b33b2a6e8b22d231
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/ClassLoaderAccess.java
@@ -0,0 +1,34 @@
@@ -0,0 +1,35 @@
+package io.papermc.paper.plugin.provider.classloader;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * The class loader access interface is an <b>internal</b> representation of a class accesses' ability to see types
@ -919,6 +896,7 @@ index 0000000000000000000000000000000000000000..64e46fdfa4d404cb08c67a456e5990b7
+ * is owned by a direct or transitive dependency of the plugin, preventing the plugin for accidentally discovering and
+ * using class types that are supplied by plugins/libraries the plugin did not actively define as a dependency.
+ */
+@NullMarked
+@ApiStatus.Internal
+public interface ClassLoaderAccess {
+
@ -941,19 +919,18 @@ index 0000000000000000000000000000000000000000..64e46fdfa4d404cb08c67a456e5990b7
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/ConfiguredPluginClassLoader.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/ConfiguredPluginClassLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..a21bdc57564aef7caf43dde3b2bcb2fc7f30461c
index 0000000000000000000000000000000000000000..7c23e0a1a38f8b89484aee160647f751088903cd
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/ConfiguredPluginClassLoader.java
@@ -0,0 +1,71 @@
@@ -0,0 +1,70 @@
+package io.papermc.paper.plugin.provider.classloader;
+
+import io.papermc.paper.plugin.configuration.PluginMeta;
+import java.io.Closeable;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.Closeable;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * The configured plugin class loader represents an <b>internal</b> abstraction over the classloaders used by the server
@ -962,6 +939,7 @@ index 0000000000000000000000000000000000000000..a21bdc57564aef7caf43dde3b2bcb2fc
+ * It implements {@link Closeable} to define the ability to shutdown and close the classloader that implements this
+ * interface.
+ */
+@NullMarked
+@ApiStatus.Internal
+public interface ConfiguredPluginClassLoader extends Closeable {
+
@ -987,7 +965,7 @@ index 0000000000000000000000000000000000000000..a21bdc57564aef7caf43dde3b2bcb2fc
+ * @see ClassLoader#loadClass(String)
+ * @see Class#forName(String, boolean, ClassLoader)
+ */
+ Class<?> loadClass(@NotNull String name,
+ Class<?> loadClass(String name,
+ boolean resolve,
+ boolean checkGlobal,
+ boolean checkLibraries) throws ClassNotFoundException;
@ -1013,8 +991,7 @@ index 0000000000000000000000000000000000000000..a21bdc57564aef7caf43dde3b2bcb2fc
+ * that is used by the underlying classloader
+ * @return classloader
+ */
+ @Nullable
+ PluginClassLoaderGroup getGroup();
+ @Nullable PluginClassLoaderGroup getGroup();
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/PaperClassLoaderStorage.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/PaperClassLoaderStorage.java
new file mode 100644
@ -1139,15 +1116,16 @@ index 0000000000000000000000000000000000000000..2c0e5ba6f8eba7a632180491843071b8
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/PluginClassLoaderGroup.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/PluginClassLoaderGroup.java
new file mode 100644
index 0000000000000000000000000000000000000000..885151cb932d9b8c09a7887edc879e154225f416
index 0000000000000000000000000000000000000000..dd3bfbf8a30c9ac6a82dcbdf879bbf120d920e20
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/PluginClassLoaderGroup.java
@@ -0,0 +1,65 @@
@@ -0,0 +1,66 @@
+package io.papermc.paper.plugin.provider.classloader;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * A plugin classloader group represents a group of classloaders that a plugins classloader may access.
@ -1155,6 +1133,7 @@ index 0000000000000000000000000000000000000000..885151cb932d9b8c09a7887edc879e15
+ * An example of this would be a classloader group that holds all direct and transitive dependencies a plugin declared,
+ * allowing a plugins classloader to access classes included in these dependencies via this group.
+ */
+@NullMarked
+@ApiStatus.Internal
+public interface PluginClassLoaderGroup {
+
@ -1172,8 +1151,7 @@ index 0000000000000000000000000000000000000000..885151cb932d9b8c09a7887edc879e15
+ * will be returned.
+ * @see ConfiguredPluginClassLoader#loadClass(String, boolean, boolean, boolean)
+ */
+ @Nullable
+ Class<?> getClassByName(String name, boolean resolve, ConfiguredPluginClassLoader requester);
+ @Nullable Class<?> getClassByName(String name, boolean resolve, ConfiguredPluginClassLoader requester);
+
+ /**
+ * Removes a configured plugin classloader from this class loader group.
@ -1210,15 +1188,15 @@ index 0000000000000000000000000000000000000000..885151cb932d9b8c09a7887edc879e15
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/entrypoint/DependencyContext.java b/src/main/java/io/papermc/paper/plugin/provider/entrypoint/DependencyContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..44d630c3eb2670c36134b9907519dc986b3761b4
index 0000000000000000000000000000000000000000..338dc25d5161b7378dd17b17d6f603c92eb0a894
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/entrypoint/DependencyContext.java
@@ -0,0 +1,48 @@
@@ -0,0 +1,49 @@
+package io.papermc.paper.plugin.provider.entrypoint;
+
+import io.papermc.paper.plugin.configuration.PluginMeta;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A dependency context is a read-only abstraction of a type/concept that can resolve dependencies between plugins.
@ -1226,6 +1204,7 @@ index 0000000000000000000000000000000000000000..44d630c3eb2670c36134b9907519dc98
+ * This may for example be the server wide plugin manager itself, capable of validating if a dependency exists between
+ * two {@link PluginMeta} instances, however the implementation is not limited to such a concrete use-case.
+ */
+@NullMarked
+@ApiStatus.Internal
+public interface DependencyContext {
+
@ -1245,7 +1224,7 @@ index 0000000000000000000000000000000000000000..44d630c3eb2670c36134b9907519dc98
+ * @param depend the potential transitive dependency of the {@code plugin} parameter.
+ * @return a simple boolean flag indicating if {@code plugin} considers {@code depend} as a transitive dependency.
+ */
+ boolean isTransitiveDependency(@NotNull PluginMeta plugin, @NotNull PluginMeta depend);
+ boolean isTransitiveDependency(PluginMeta plugin, PluginMeta depend);
+
+ /**
+ * Computes if this dependency context is aware of a dependency that provides/matches the passed identifier.
@ -1259,29 +1238,30 @@ index 0000000000000000000000000000000000000000..44d630c3eb2670c36134b9907519dc98
+ * @return a plain boolean flag indicating if this dependency context is aware of a potential dependency with the
+ * passed identifier.
+ */
+ boolean hasDependency(@NotNull String pluginIdentifier);
+ boolean hasDependency(String pluginIdentifier);
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java b/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..6bf3d212a6156ad9ab0e82d1ca0a04f83f6e4b83
index 0000000000000000000000000000000000000000..48a67c1b6070292dbf4ea3081f89b530207f9f6d
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java
@@ -0,0 +1,78 @@
@@ -0,0 +1,77 @@
+package io.papermc.paper.plugin.provider.util;
+
+import com.destroystokyo.paper.util.SneakyThrow;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * An <b>internal</b> utility type that holds logic for loading a provider-like type from a classloaders.
+ * Provides, at least in the context of this utility, define themselves as implementations of a specific parent
+ * interface/type, e.g. {@link org.bukkit.plugin.java.JavaPlugin} and implement a no-args constructor.
+ */
+@NullMarked
+@ApiStatus.Internal
+public class ProviderUtil {
+public final class ProviderUtil {
+
+ /**
+ * Loads the class found at the provided fully qualified class name from the passed classloader, creates a new
@ -1294,8 +1274,7 @@ index 0000000000000000000000000000000000000000..6bf3d212a6156ad9ab0e82d1ca0a04f8
+ * @param <T> the generic type of the parent class the created object will be cast to
+ * @return the object instantiated from the class found at the provided FQN, cast to the parent type
+ */
+ @NotNull
+ public static <T> T loadClass(@NotNull String clazz, @NotNull Class<T> classType, @NotNull ClassLoader loader) {
+ public static <T> T loadClass(final String clazz, final Class<T> classType, final ClassLoader loader) {
+ return loadClass(clazz, classType, loader, null);
+ }
+
@ -1312,30 +1291,29 @@ index 0000000000000000000000000000000000000000..6bf3d212a6156ad9ab0e82d1ca0a04f8
+ * @return the object instantiated from the class found at the provided fully qualified class name, cast to the
+ * parent type
+ */
+ @NotNull
+ public static <T> T loadClass(@NotNull String clazz, @NotNull Class<T> classType, @NotNull ClassLoader loader, @Nullable Runnable onError) {
+ public static <T> T loadClass(final String clazz, final Class<T> classType, final ClassLoader loader, final @Nullable Runnable onError) {
+ try {
+ T clazzInstance;
+ final T clazzInstance;
+
+ try {
+ Class<?> jarClass = Class.forName(clazz, true, loader);
+ final Class<?> jarClass = Class.forName(clazz, true, loader);
+
+ Class<? extends T> pluginClass;
+ final Class<? extends T> pluginClass;
+ try {
+ pluginClass = jarClass.asSubclass(classType);
+ } catch (ClassCastException ex) {
+ } catch (final ClassCastException ex) {
+ throw new ClassCastException("class '%s' does not extend '%s'".formatted(clazz, classType));
+ }
+
+ clazzInstance = pluginClass.getDeclaredConstructor().newInstance();
+ } catch (IllegalAccessException exception) {
+ } catch (final IllegalAccessException exception) {
+ throw new RuntimeException("No public constructor");
+ } catch (InstantiationException exception) {
+ } catch (final InstantiationException exception) {
+ throw new RuntimeException("Abnormal class instantiation", exception);
+ }
+
+ return clazzInstance;
+ } catch (Throwable e) {
+ } catch (final Throwable e) {
+ if (onError != null) {
+ onError.run();
+ }

View file

@ -6,25 +6,27 @@ Subject: [PATCH] Add Position
diff --git a/src/main/java/io/papermc/paper/math/BlockPosition.java b/src/main/java/io/papermc/paper/math/BlockPosition.java
new file mode 100644
index 0000000000000000000000000000000000000000..f0fdabce4af640da2a406412e67020761ded3ac1
index 0000000000000000000000000000000000000000..c358bfdefc9bc7598dbd0d89a6b0b8a9408b5bb3
--- /dev/null
+++ b/src/main/java/io/papermc/paper/math/BlockPosition.java
@@ -0,0 +1,98 @@
@@ -0,0 +1,100 @@
+package io.papermc.paper.math;
+
+import org.bukkit.Axis;
+import org.bukkit.block.BlockFace;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A position represented with integers.
+ * <p>
+ * <b>May see breaking changes until Experimental annotation is removed.</b>
+ *
+ * @see FinePosition
+ */
+@ApiStatus.Experimental
+@NullMarked
+public interface BlockPosition extends Position {
+
+ @Override
@ -53,17 +55,17 @@ index 0000000000000000000000000000000000000000..f0fdabce4af640da2a406412e6702076
+ }
+
+ @Override
+ default @NotNull BlockPosition toBlock() {
+ default BlockPosition toBlock() {
+ return this;
+ }
+
+ @Override
+ default @NotNull BlockPosition offset(int x, int y, int z) {
+ default BlockPosition offset(final int x, final int y, final int z) {
+ return x == 0 && y == 0 && z == 0 ? this : new BlockPositionImpl(this.blockX() + x, this.blockY() + y, this.blockZ() + z);
+ }
+
+ @Override
+ default @NotNull FinePosition offset(double x, double y, double z) {
+ default FinePosition offset(final double x, final double y, final double z) {
+ return new FinePositionImpl(this.blockX() + x, this.blockY() + y, this.blockZ() + z);
+ }
+
@ -74,7 +76,7 @@ index 0000000000000000000000000000000000000000..f0fdabce4af640da2a406412e6702076
+ * @return the offset block position
+ */
+ @Contract(value = "_ -> new", pure = true)
+ default @NotNull BlockPosition offset(@NotNull BlockFace blockFace) {
+ default BlockPosition offset(final BlockFace blockFace) {
+ return this.offset(blockFace, 1);
+ }
+
@ -87,7 +89,7 @@ index 0000000000000000000000000000000000000000..f0fdabce4af640da2a406412e6702076
+ * @return the offset block position
+ */
+ @Contract(pure = true)
+ default @NotNull BlockPosition offset(@NotNull BlockFace blockFace, int amount) {
+ default BlockPosition offset(final BlockFace blockFace, final int amount) {
+ return amount == 0 ? this : new BlockPositionImpl(this.blockX() + (blockFace.getModX() * amount), this.blockY() + (blockFace.getModY() * amount), this.blockZ() + (blockFace.getModZ() * amount));
+ }
+
@ -100,7 +102,7 @@ index 0000000000000000000000000000000000000000..f0fdabce4af640da2a406412e6702076
+ * @return the offset block position
+ */
+ @Contract(pure = true)
+ default @NotNull BlockPosition offset(@NotNull Axis axis, int amount) {
+ default BlockPosition offset(final Axis axis, final int amount) {
+ return amount == 0 ? this : switch (axis) {
+ case X -> new BlockPositionImpl(this.blockX() + amount, this.blockY(), this.blockZ());
+ case Y -> new BlockPositionImpl(this.blockX(), this.blockY() + amount, this.blockZ());
@ -120,24 +122,25 @@ index 0000000000000000000000000000000000000000..eb5a3f26c7ba56c6715827f52c0013a8
+}
diff --git a/src/main/java/io/papermc/paper/math/FinePosition.java b/src/main/java/io/papermc/paper/math/FinePosition.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8df70d731573cf2446044925f218876d62fd7cf
index 0000000000000000000000000000000000000000..b9c0065d8a9dedc3bd1a2d8bfbedfbc7f952ff93
--- /dev/null
+++ b/src/main/java/io/papermc/paper/math/FinePosition.java
@@ -0,0 +1,56 @@
@@ -0,0 +1,57 @@
+package io.papermc.paper.math;
+
+import org.bukkit.util.NumberConversions;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A position represented with doubles.
+ * <p>
+ * <b>May see breaking changes until Experimental annotation is removed.</b>
+ *
+ * @see BlockPosition
+ */
+@ApiStatus.Experimental
+@NullMarked
+public interface FinePosition extends Position {
+
+ @Override
@ -166,17 +169,17 @@ index 0000000000000000000000000000000000000000..d8df70d731573cf2446044925f218876
+ }
+
+ @Override
+ default @NotNull BlockPosition toBlock() {
+ default BlockPosition toBlock() {
+ return new BlockPositionImpl(this.blockX(), this.blockY(), this.blockZ());
+ }
+
+ @Override
+ default @NotNull FinePosition offset(int x, int y, int z) {
+ default FinePosition offset(final int x, final int y, final int z) {
+ return this.offset((double) x, y, z);
+ }
+
+ @Override
+ default @NotNull FinePosition offset(double x, double y, double z) {
+ default FinePosition offset(final double x, final double y, final double z) {
+ return x == 0.0 && y == 0.0 && z == 0.0 ? this : new FinePositionImpl(this.x() + x, this.y() + y, this.z() + z);
+ }
+}
@ -192,10 +195,10 @@ index 0000000000000000000000000000000000000000..93476aaf8d21efb5a30b6d2cc2eeda81
+}
diff --git a/src/main/java/io/papermc/paper/math/Position.java b/src/main/java/io/papermc/paper/math/Position.java
new file mode 100644
index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d9f242740
index 0000000000000000000000000000000000000000..0e6a6a6738353b118e0ed093994dda06750700c4
--- /dev/null
+++ b/src/main/java/io/papermc/paper/math/Position.java
@@ -0,0 +1,191 @@
@@ -0,0 +1,192 @@
+package io.papermc.paper.math;
+
+import org.bukkit.Location;
@ -203,7 +206,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Common interface for {@link FinePosition} and {@link BlockPosition}.
@ -211,6 +214,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * <b>May see breaking changes until Experimental annotation is removed.</b>
+ */
+@ApiStatus.Experimental
+@NullMarked
+public interface Position {
+
+ FinePosition FINE_ZERO = new FinePositionImpl(0, 0, 0);
@ -287,7 +291,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * @param z z value to offset
+ * @return the offset position
+ */
+ @NotNull Position offset(int x, int y, int z);
+ Position offset(int x, int y, int z);
+
+ /**
+ * Returns a position offset by the specified amounts.
@ -297,7 +301,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * @param z z value to offset
+ * @return the offset position
+ */
+ @NotNull FinePosition offset(double x, double y, double z);
+ FinePosition offset(double x, double y, double z);
+
+ /**
+ * Returns a new position at the center of the block position this represents
@ -305,7 +309,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * @return a new center position
+ */
+ @Contract(value = "-> new", pure = true)
+ default @NotNull FinePosition toCenter() {
+ default FinePosition toCenter() {
+ return new FinePositionImpl(this.blockX() + 0.5, this.blockY() + 0.5, this.blockZ() + 0.5);
+ }
+
@ -316,7 +320,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * @return the block position
+ */
+ @Contract(pure = true)
+ @NotNull BlockPosition toBlock();
+ BlockPosition toBlock();
+
+ /**
+ * Converts this position to a vector
@ -324,7 +328,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * @return a new vector
+ */
+ @Contract(value = "-> new", pure = true)
+ default @NotNull Vector toVector() {
+ default Vector toVector() {
+ return new Vector(this.x(), this.y(), this.z());
+ }
+
@ -335,7 +339,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * @return a new location
+ */
+ @Contract(value = "_ -> new", pure = true)
+ default @NotNull Location toLocation(@NotNull World world) {
+ default Location toLocation(final World world) {
+ return new Location(world, this.x(), this.y(), this.z());
+ }
+
@ -348,7 +352,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * @return a position with those coords
+ */
+ @Contract(value = "_, _, _ -> new", pure = true)
+ static @NotNull BlockPosition block(int x, int y, int z) {
+ static BlockPosition block(final int x, final int y, final int z) {
+ return new BlockPositionImpl(x, y, z);
+ }
+
@ -359,7 +363,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * @return a new position at that location
+ */
+ @Contract(value = "_ -> new", pure = true)
+ static @NotNull BlockPosition block(@NotNull Location location) {
+ static BlockPosition block(final Location location) {
+ return new BlockPositionImpl(location.getBlockX(), location.getBlockY(), location.getBlockZ());
+ }
+
@ -372,7 +376,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * @return a position with those coords
+ */
+ @Contract(value = "_, _, _ -> new", pure = true)
+ static @NotNull FinePosition fine(double x, double y, double z) {
+ static FinePosition fine(final double x, final double y, final double z) {
+ return new FinePositionImpl(x, y, z);
+ }
+
@ -383,7 +387,7 @@ index 0000000000000000000000000000000000000000..26bc5a0fa67855af87c8fd4cd8229b4d
+ * @return a new position at that location
+ */
+ @Contract(value = "_ -> new", pure = true)
+ static @NotNull FinePosition fine(@NotNull Location location) {
+ static FinePosition fine(final Location location) {
+ return new FinePositionImpl(location.getX(), location.getY(), location.getZ());
+ }
+}

View file

@ -10,18 +10,21 @@ Co-authored-by: Riley Park <rileysebastianpark@gmail.com>
diff --git a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..a736d7bcdc5861a01b66ba36158db1c716339346
index 0000000000000000000000000000000000000000..023cc52a9e28e1238c7452c0f3f577f2850fd861
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java
@@ -0,0 +1,45 @@
@@ -0,0 +1,47 @@
+package com.destroystokyo.paper.util;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import org.bukkit.Bukkit;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public interface VersionFetcher {
+
+ /**
+ * Amount of time to cache results for in milliseconds
+ * <p>
@ -39,9 +42,9 @@ index 0000000000000000000000000000000000000000..a736d7bcdc5861a01b66ba36158db1c7
+ * @param serverVersion the current version of the server (will match {@link Bukkit#getVersion()})
+ * @return the message to show when requesting a version
+ */
+ @NotNull
+ Component getVersionMessage(@NotNull String serverVersion);
+ Component getVersionMessage(String serverVersion);
+
+ @ApiStatus.Internal
+ class DummyVersionFetcher implements VersionFetcher {
+
+ @Override
@ -49,9 +52,8 @@ index 0000000000000000000000000000000000000000..a736d7bcdc5861a01b66ba36158db1c7
+ return -1;
+ }
+
+ @NotNull
+ @Override
+ public Component getVersionMessage(@NotNull String serverVersion) {
+ public Component getVersionMessage(final String serverVersion) {
+ Bukkit.getLogger().warning("Version provider has not been set, cannot check for updates!");
+ Bukkit.getLogger().info("Override the default implementation of org.bukkit.UnsafeValues#getVersionFetcher()");
+ new Throwable().printStackTrace();
@ -61,10 +63,10 @@ index 0000000000000000000000000000000000000000..a736d7bcdc5861a01b66ba36158db1c7
+}
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfo.java b/src/main/java/io/papermc/paper/ServerBuildInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..9df9d09aa477d4cd3c496ba0933c816df1ef0964
index 0000000000000000000000000000000000000000..652ff54e7c50412503725d628bfe72ed03059790
--- /dev/null
+++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java
@@ -0,0 +1,121 @@
@@ -0,0 +1,122 @@
+package io.papermc.paper;
+
+import java.time.Instant;
@ -73,11 +75,12 @@ index 0000000000000000000000000000000000000000..9df9d09aa477d4cd3c496ba0933c816d
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.util.Services;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Information about the current server build.
+ */
+@NullMarked
+@ApiStatus.NonExtendable
+public interface ServerBuildInfo {
+ /**
@ -90,7 +93,7 @@ index 0000000000000000000000000000000000000000..9df9d09aa477d4cd3c496ba0933c816d
+ *
+ * @return the {@code ServerBuildInfo}
+ */
+ static @NotNull ServerBuildInfo buildInfo() {
+ static ServerBuildInfo buildInfo() {
+ //<editor-fold defaultstate="collapsed" desc="Holder">
+ final class Holder {
+ static final Optional<ServerBuildInfo> INSTANCE = Services.service(ServerBuildInfo.class);
@ -104,7 +107,7 @@ index 0000000000000000000000000000000000000000..9df9d09aa477d4cd3c496ba0933c816d
+ *
+ * @return the brand id of the server (e.g. "papermc:paper")
+ */
+ @NotNull Key brandId();
+ Key brandId();
+
+ /**
+ * Checks if the current server supports the specified brand.
@ -113,56 +116,56 @@ index 0000000000000000000000000000000000000000..9df9d09aa477d4cd3c496ba0933c816d
+ * @return {@code true} if the server supports the specified brand
+ */
+ @ApiStatus.Experimental
+ boolean isBrandCompatible(final @NotNull Key brandId);
+ boolean isBrandCompatible(final Key brandId);
+
+ /**
+ * Gets the brand name of the server.
+ *
+ * @return the brand name of the server (e.g. "Paper")
+ */
+ @NotNull String brandName();
+ String brandName();
+
+ /**
+ * Gets the Minecraft version id.
+ *
+ * @return the Minecraft version id (e.g. "1.20.4", "1.20.2-pre2", "23w31a")
+ */
+ @NotNull String minecraftVersionId();
+ String minecraftVersionId();
+
+ /**
+ * Gets the Minecraft version name.
+ *
+ * @return the Minecraft version name (e.g. "1.20.4", "1.20.2 Pre-release 2", "23w31a")
+ */
+ @NotNull String minecraftVersionName();
+ String minecraftVersionName();
+
+ /**
+ * Gets the build number.
+ *
+ * @return the build number
+ */
+ @NotNull OptionalInt buildNumber();
+ OptionalInt buildNumber();
+
+ /**
+ * Gets the build time.
+ *
+ * @return the build time
+ */
+ @NotNull Instant buildTime();
+ Instant buildTime();
+
+ /**
+ * Gets the git commit branch.
+ *
+ * @return the git commit branch
+ */
+ @NotNull Optional<String> gitBranch();
+ Optional<String> gitBranch();
+
+ /**
+ * Gets the git commit hash.
+ *
+ * @return the git commit hash
+ */
+ @NotNull Optional<String> gitCommit();
+ Optional<String> gitCommit();
+
+ /**
+ * Creates a string representation of the server build information.
@ -170,7 +173,7 @@ index 0000000000000000000000000000000000000000..9df9d09aa477d4cd3c496ba0933c816d
+ * @param representation the type of representation
+ * @return a string
+ */
+ @NotNull String asString(final @NotNull StringRepresentation representation);
+ String asString(final StringRepresentation representation);
+
+ /**
+ * String representation types.
@ -188,10 +191,10 @@ index 0000000000000000000000000000000000000000..9df9d09aa477d4cd3c496ba0933c816d
+}
diff --git a/src/main/java/io/papermc/paper/util/JarManifests.java b/src/main/java/io/papermc/paper/util/JarManifests.java
new file mode 100644
index 0000000000000000000000000000000000000000..909617079db61b675cc7b60b44ef96b306076343
index 0000000000000000000000000000000000000000..7915a70d676b1205dcae39259f670af258a1ab9b
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/JarManifests.java
@@ -0,0 +1,37 @@
@@ -0,0 +1,38 @@
+package io.papermc.paper.util;
+
+import java.io.IOException;
@ -202,9 +205,10 @@ index 0000000000000000000000000000000000000000..909617079db61b675cc7b60b44ef96b3
+import java.util.WeakHashMap;
+import java.util.jar.Manifest;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+@NullMarked
+@ApiStatus.Internal
+public final class JarManifests {
+ private JarManifests() {
@ -212,7 +216,7 @@ index 0000000000000000000000000000000000000000..909617079db61b675cc7b60b44ef96b3
+
+ private static final Map<ClassLoader, Manifest> MANIFESTS = Collections.synchronizedMap(new WeakHashMap<>());
+
+ public static @Nullable Manifest manifest(final @NotNull Class<?> clazz) {
+ public static @Nullable Manifest manifest(final Class<?> clazz) {
+ return MANIFESTS.computeIfAbsent(clazz.getClassLoader(), classLoader -> {
+ final String classLocation = "/" + clazz.getName().replace(".", "/") + ".class";
+ final URL resource = clazz.getResource(classLocation);

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add BeaconEffectEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java b/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..7270c1feece2dc15a4a0503c4bca93a1288f8f13
index 0000000000000000000000000000000000000000..741d0e73bc635a545c94c4b1254cee8f41ba8925
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java
@@ -0,0 +1,91 @@
@@ -0,0 +1,88 @@
+package com.destroystokyo.paper.event.block;
+
+import org.bukkit.block.Block;
@ -19,11 +19,12 @@ index 0000000000000000000000000000000000000000..7270c1feece2dc15a4a0503c4bca93a1
+import org.bukkit.event.block.BlockEvent;
+import org.bukkit.potion.PotionEffect;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a beacon effect is being applied to a player.
+ */
+@NullMarked
+public class BeaconEffectEvent extends BlockEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -35,7 +36,7 @@ index 0000000000000000000000000000000000000000..7270c1feece2dc15a4a0503c4bca93a1
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public BeaconEffectEvent(@NotNull Block block, @NotNull PotionEffect effect, @NotNull Player player, boolean primary) {
+ public BeaconEffectEvent(final Block block, final PotionEffect effect, final Player player, final boolean primary) {
+ super(block);
+ this.effect = effect;
+ this.player = player;
@ -47,7 +48,6 @@ index 0000000000000000000000000000000000000000..7270c1feece2dc15a4a0503c4bca93a1
+ *
+ * @return Potion effect
+ */
+ @NotNull
+ public PotionEffect getEffect() {
+ return this.effect;
+ }
@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..7270c1feece2dc15a4a0503c4bca93a1
+ *
+ * @param effect Potion effect
+ */
+ public void setEffect(@NotNull PotionEffect effect) {
+ public void setEffect(final PotionEffect effect) {
+ this.effect = effect;
+ }
+
@ -66,7 +66,6 @@ index 0000000000000000000000000000000000000000..7270c1feece2dc15a4a0503c4bca93a1
+ *
+ * @return Affected player
+ */
+ @NotNull
+ public Player getPlayer() {
+ return this.player;
+ }
@ -86,17 +85,15 @@ index 0000000000000000000000000000000000000000..7270c1feece2dc15a4a0503c4bca93a1
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,30 +6,31 @@ Subject: [PATCH] Add exception reporting event
diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..9377ee1c2368ce058397037952d17bc010f66957
index 0000000000000000000000000000000000000000..95a5a59e6bd88345177fca0b12008ddd689cb448
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java
@@ -0,0 +1,45 @@
@@ -0,0 +1,43 @@
+package com.destroystokyo.paper.event.server;
+
+import com.destroystokyo.paper.exception.ServerException;
+import org.bukkit.Bukkit;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import com.destroystokyo.paper.exception.ServerException;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called whenever an exception is thrown in a recoverable section of the server.
+ */
+@NullMarked
+public class ServerExceptionEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final ServerException exception;
+ private final ServerException exception;
+
+ @ApiStatus.Internal
+ public ServerExceptionEvent(@NotNull ServerException exception) {
+ public ServerExceptionEvent(final ServerException exception) {
+ super(!Bukkit.isPrimaryThread());
+ this.exception = exception;
+ }
@ -39,18 +40,15 @@ index 0000000000000000000000000000000000000000..9377ee1c2368ce058397037952d17bc0
+ *
+ * @return Exception thrown
+ */
+ @NotNull
+ public ServerException getException() {
+ return this.exception;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Entity AddTo/RemoveFrom World Events
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityAddToWorldEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityAddToWorldEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..1d8e3c93a139bba11affca74b742269f24300d2c
index 0000000000000000000000000000000000000000..11f8540a4752cf4d2112eff48bcca3b935c9f8b1
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityAddToWorldEvent.java
@@ -0,0 +1,45 @@
@@ -0,0 +1,44 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.World;
@ -18,21 +18,22 @@ index 0000000000000000000000000000000000000000..1d8e3c93a139bba11affca74b742269f
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired any time an entity is being added to the world for any reason (including a chunk loading).
+ * <p>
+ * Not to be confused with {@link CreatureSpawnEvent}
+ */
+@NullMarked
+public class EntityAddToWorldEvent extends EntityEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final World world;
+ private final World world;
+
+ @ApiStatus.Internal
+ public EntityAddToWorldEvent(@NotNull Entity entity, @NotNull World world) {
+ public EntityAddToWorldEvent(final Entity entity, final World world) {
+ super(entity);
+ this.world = world;
+ }
@ -40,27 +41,25 @@ index 0000000000000000000000000000000000000000..1d8e3c93a139bba11affca74b742269f
+ /**
+ * @return The world that the entity is being added to
+ */
+ @NotNull
+ public World getWorld() {
+ return this.world;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityRemoveFromWorldEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityRemoveFromWorldEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..d75e6a8334c7408ea8c3f155414fc14dc427f190
index 0000000000000000000000000000000000000000..5ad5632d4d47d8b42e4f2af19c0fe6cf94ac5643
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityRemoveFromWorldEvent.java
@@ -0,0 +1,43 @@
@@ -0,0 +1,42 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.World;
@ -68,20 +67,21 @@ index 0000000000000000000000000000000000000000..d75e6a8334c7408ea8c3f155414fc14d
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired any time an entity is being removed from a world for any reason (including a chunk unloading).
+ * Note: The entity is updated prior to this event being called, as such, the entity's world may not be equal to {@link #getWorld()}.
+ */
+@NullMarked
+public class EntityRemoveFromWorldEvent extends EntityEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final World world;
+ private final World world;
+
+ @ApiStatus.Internal
+ public EntityRemoveFromWorldEvent(@NotNull Entity entity, @NotNull World world) {
+ public EntityRemoveFromWorldEvent(final Entity entity, final World world) {
+ super(entity);
+ this.world = world;
+ }
@ -89,17 +89,15 @@ index 0000000000000000000000000000000000000000..d75e6a8334c7408ea8c3f155414fc14d
+ /**
+ * @return The world that the entity is being removed from
+ */
+ @NotNull
+ public World getWorld() {
+ return this.world;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -7,10 +7,10 @@ Fires when an Entity decides to start moving to a location.
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityPathfindEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityPathfindEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..8267e8f1f0ade29a284831069e1268ee4b29e109
index 0000000000000000000000000000000000000000..8624e0a528985c9b118f5e8a0f33d3286af2fc36
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityPathfindEvent.java
@@ -0,0 +1,87 @@
@@ -0,0 +1,84 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.Location;
@ -19,8 +19,8 @@ index 0000000000000000000000000000000000000000..8267e8f1f0ade29a284831069e1268ee
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Fired when an Entity decides to start moving towards a location.
@ -28,16 +28,17 @@ index 0000000000000000000000000000000000000000..8267e8f1f0ade29a284831069e1268ee
+ * This event does not fire for the entities actual movement. Only when it
+ * is choosing to start moving to a location.
+ */
+@NullMarked
+public class EntityPathfindEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @Nullable private final Entity targetEntity;
+ @NotNull private final Location location;
+ private final @Nullable Entity targetEntity;
+ private final Location location;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EntityPathfindEvent(@NotNull Entity entity, @NotNull Location location, @Nullable Entity targetEntity) {
+ public EntityPathfindEvent(final Entity entity, final Location location, final @Nullable Entity targetEntity) {
+ super(entity);
+ this.targetEntity = targetEntity;
+ this.location = location;
@ -48,7 +49,7 @@ index 0000000000000000000000000000000000000000..8267e8f1f0ade29a284831069e1268ee
+ *
+ * @return The Entity that is pathfinding.
+ */
+ @NotNull
+ @Override
+ public Entity getEntity() {
+ return this.entity;
+ }
@ -56,12 +57,11 @@ index 0000000000000000000000000000000000000000..8267e8f1f0ade29a284831069e1268ee
+ /**
+ * If the Entity is trying to pathfind to an entity, this is the entity in relation.
+ * <br>
+ * Otherwise this will return {@code null}.
+ * Otherwise, this will return {@code null}.
+ *
+ * @return The entity target or {@code null}
+ */
+ @Nullable
+ public Entity getTargetEntity() {
+ public @Nullable Entity getTargetEntity() {
+ return this.targetEntity;
+ }
+
@ -72,7 +72,6 @@ index 0000000000000000000000000000000000000000..8267e8f1f0ade29a284831069e1268ee
+ *
+ * @return Location of where the entity is trying to pathfind to.
+ */
+ @NotNull
+ public Location getLoc() {
+ return this.location.clone();
+ }
@ -83,17 +82,15 @@ index 0000000000000000000000000000000000000000..8267e8f1f0ade29a284831069e1268ee
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -10,10 +10,10 @@ Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..dbb635686e9108b9d3df5d373e6972cca07c0621
index 0000000000000000000000000000000000000000..9ff2bbf7f99df45cc626cad60bec4d14a8a04e3e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java
@@ -0,0 +1,86 @@
@@ -0,0 +1,85 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.entity.Player;
@ -23,8 +23,8 @@ index 0000000000000000000000000000000000000000..dbb635686e9108b9d3df5d373e6972cc
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Represents an event that is called when a player right-clicks an unknown entity.
@ -33,17 +33,18 @@ index 0000000000000000000000000000000000000000..dbb635686e9108b9d3df5d373e6972cc
+ * This event may be called multiple times per interaction with different interaction hands
+ * and with or without the clicked position.
+ */
+@NullMarked
+public class PlayerUseUnknownEntityEvent extends PlayerEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final int entityId;
+ private final boolean attack;
+ private final @NotNull EquipmentSlot hand;
+ private final EquipmentSlot hand;
+ private final @Nullable Vector clickedPosition;
+
+ @ApiStatus.Internal
+ public PlayerUseUnknownEntityEvent(@NotNull Player player, int entityId, boolean attack, @NotNull EquipmentSlot hand, @Nullable Vector clickedPosition) {
+ public PlayerUseUnknownEntityEvent(final Player player, final int entityId, final boolean attack, final EquipmentSlot hand, final @Nullable Vector clickedPosition) {
+ super(player);
+ this.entityId = entityId;
+ this.attack = attack;
@ -74,7 +75,7 @@ index 0000000000000000000000000000000000000000..dbb635686e9108b9d3df5d373e6972cc
+ *
+ * @return the hand used to interact
+ */
+ public @NotNull EquipmentSlot getHand() {
+ public EquipmentSlot getHand() {
+ return this.hand;
+ }
+
@ -89,13 +90,11 @@ index 0000000000000000000000000000000000000000..dbb635686e9108b9d3df5d373e6972cc
+ return this.clickedPosition != null ? this.clickedPosition.clone() : null;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -7,13 +7,14 @@ Subject: [PATCH] Add handshake event to allow plugins to handle client
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4ce03ef477
index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a0b953c45
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java
@@ -0,0 +1,267 @@
@@ -0,0 +1,257 @@
+package com.destroystokyo.paper.event.player;
+
+import com.google.common.base.Preconditions;
+import java.util.UUID;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
@ -21,10 +22,8 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.UUID;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * This event is fired during a player handshake.
@ -34,16 +33,17 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * <p>WARNING: TAMPERING WITH THIS EVENT CAN BE DANGEROUS</p>
+ */
+@NullMarked
+public class PlayerHandshakeEvent extends Event implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final String originalHandshake;
+ @NotNull private final String originalSocketAddressHostname;
+ @Nullable private String serverHostname;
+ @Nullable private String socketAddressHostname;
+ @Nullable private UUID uniqueId;
+ @Nullable private String propertiesJson;
+ private final String originalHandshake;
+ private final String originalSocketAddressHostname;
+ private @Nullable String serverHostname;
+ private @Nullable String socketAddressHostname;
+ private @Nullable UUID uniqueId;
+ private @Nullable String propertiesJson;
+ private boolean failed;
+ private Component failMessage = Component.text("If you wish to use IP forwarding, please enable it in your BungeeCord config as well!", NamedTextColor.YELLOW);
+
@ -51,12 +51,12 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+
+ @Deprecated
+ @ApiStatus.Internal
+ public PlayerHandshakeEvent(@NotNull String originalHandshake, boolean cancelled) {
+ public PlayerHandshakeEvent(final String originalHandshake, final boolean cancelled) {
+ this(originalHandshake, "127.0.0.1", cancelled);
+ }
+
+ @ApiStatus.Internal
+ public PlayerHandshakeEvent(@NotNull String originalHandshake, @NotNull String originalSocketAddressHostname, boolean cancelled) {
+ public PlayerHandshakeEvent(final String originalHandshake, final String originalSocketAddressHostname, final boolean cancelled) {
+ super(true);
+ this.originalHandshake = originalHandshake;
+ this.originalSocketAddressHostname = originalSocketAddressHostname;
@ -85,7 +85,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ * @param cancel {@code true} if this event is cancelled, {@code false} otherwise
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
@ -94,7 +94,6 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @return the original handshake string
+ */
+ @NotNull
+ public String getOriginalHandshake() {
+ return this.originalHandshake;
+ }
@ -107,7 +106,6 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @return the original socket address hostname
+ */
+ @NotNull
+ public String getOriginalSocketAddressHostname() {
+ return this.originalSocketAddressHostname;
+ }
@ -119,8 +117,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @return the server hostname string
+ */
+ @Nullable
+ public String getServerHostname() {
+ public @Nullable String getServerHostname() {
+ return this.serverHostname;
+ }
+
@ -131,7 +128,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @param serverHostname the server hostname string
+ */
+ public void setServerHostname(@NotNull String serverHostname) {
+ public void setServerHostname(final String serverHostname) {
+ this.serverHostname = serverHostname;
+ }
+
@ -142,8 +139,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @return the socket address hostname string
+ */
+ @Nullable
+ public String getSocketAddressHostname() {
+ public @Nullable String getSocketAddressHostname() {
+ return this.socketAddressHostname;
+ }
+
@ -154,7 +150,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @param socketAddressHostname the socket address hostname string
+ */
+ public void setSocketAddressHostname(@NotNull String socketAddressHostname) {
+ public void setSocketAddressHostname(final String socketAddressHostname) {
+ this.socketAddressHostname = socketAddressHostname;
+ }
+
@ -163,8 +159,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @return the unique id
+ */
+ @Nullable
+ public UUID getUniqueId() {
+ public @Nullable UUID getUniqueId() {
+ return this.uniqueId;
+ }
+
@ -173,7 +168,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @param uniqueId the unique id
+ */
+ public void setUniqueId(@NotNull UUID uniqueId) {
+ public void setUniqueId(final UUID uniqueId) {
+ this.uniqueId = uniqueId;
+ }
+
@ -184,8 +179,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @return the profile properties, as JSON
+ */
+ @Nullable
+ public String getPropertiesJson() {
+ public @Nullable String getPropertiesJson() {
+ return this.propertiesJson;
+ }
+
@ -209,7 +203,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @param failed {@code true} if authentication failed, {@code false} otherwise
+ */
+ public void setFailed(boolean failed) {
+ public void setFailed(final boolean failed) {
+ this.failed = failed;
+ }
+
@ -220,7 +214,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @param propertiesJson the profile properties, as JSON
+ */
+ public void setPropertiesJson(@NotNull String propertiesJson) {
+ public void setPropertiesJson(final String propertiesJson) {
+ this.propertiesJson = propertiesJson;
+ }
+
@ -229,7 +223,6 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @return the message to display to the client
+ */
+ @NotNull
+ public Component failMessage() {
+ return this.failMessage;
+ }
@ -239,7 +232,7 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ *
+ * @param failMessage the message to display to the client
+ */
+ public void failMessage(@NotNull Component failMessage) {
+ public void failMessage(final Component failMessage) {
+ this.failMessage = failMessage;
+ }
+
@ -249,7 +242,6 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ * @return the message to display to the client
+ * @deprecated use {@link #failMessage()}
+ */
+ @NotNull
+ @Deprecated
+ public String getFailMessage() {
+ return LegacyComponentSerializer.legacySection().serialize(this.failMessage());
@ -262,18 +254,16 @@ index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4c
+ * @deprecated use {@link #failMessage(Component)}
+ */
+ @Deprecated
+ public void setFailMessage(@NotNull String failMessage) {
+ public void setFailMessage(final String failMessage) {
+ Preconditions.checkArgument(failMessage != null && !failMessage.isEmpty(), "fail message cannot be null or empty");
+ this.failMessage(LegacyComponentSerializer.legacySection().deserialize(failMessage));
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -12,96 +12,98 @@ Provides methods to determine players looted state for an object
diff --git a/src/main/java/com/destroystokyo/paper/loottable/LootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/LootableBlockInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..92d7b853a2ccaae5afa8ac141bead840942944ef
index 0000000000000000000000000000000000000000..6a03252d66a3e13c1960568ea23f6dcc673f34af
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/LootableBlockInventory.java
@@ -0,0 +1,17 @@
+package com.destroystokyo.paper.loottable;
+
+import org.bukkit.block.Block;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents an Inventory that can generate loot, such as Chests inside of Fortresses and Mineshafts
+ */
+@NullMarked
+public interface LootableBlockInventory extends LootableInventory {
+
+ /**
+ * Gets the block that is lootable
+ * @return The Block
+ */
+ @NotNull
+ Block getBlock();
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/LootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/LootableEntityInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..b387894fe8001edb41ad2ad2b70ebabe065b682e
index 0000000000000000000000000000000000000000..31ca54dea65dc0363a0ff7991ba5be3b06533876
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/LootableEntityInventory.java
@@ -0,0 +1,17 @@
+package com.destroystokyo.paper.loottable;
+
+import org.bukkit.entity.Entity;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents an Inventory that can generate loot, such as Minecarts inside of Mineshafts
+ */
+@NullMarked
+public interface LootableEntityInventory extends LootableInventory {
+
+ /**
+ * Gets the entity that is lootable
+ * @return The Entity
+ */
+ @NotNull
+ Entity getEntity();
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/LootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/LootableInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..b18a0b50c12fe8d8c954e5c070f2ecd1854a2583
index 0000000000000000000000000000000000000000..9fb621200fb3969e8e440341e906acc3547b4039
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/LootableInventory.java
@@ -0,0 +1,124 @@
@@ -0,0 +1,128 @@
+package com.destroystokyo.paper.loottable;
+
+import java.util.UUID;
+import org.bukkit.entity.Player;
+import org.bukkit.loot.Lootable;
+
+import java.util.UUID;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Represents an Inventory that contains a Loot Table associated to it that will
+ * automatically fill on first open.
+ *
+ * <p>
+ * A new feature and API is provided to support automatically refreshing the contents
+ * of the inventory based on that Loot Table after a configurable amount of time has passed.
+ *
+ * <p>
+ * The behavior of how the Inventory is filled based on the loot table may vary based
+ * on Minecraft versions and the Loot Table feature.
+ */
+@NullMarked
+public interface LootableInventory extends Lootable {
+
+ /**
+ * Server owners have to enable whether or not an object in a world should refill
+ * Server owners have to enable whether an object in a world should refill
+ *
+ * @return If the world this inventory is currently in has Replenishable Lootables enabled
+ */
+ boolean isRefillEnabled();
+
+ /**
+ * Whether or not this object has ever been filled
+ * Whether this object has ever been filled
+ *
+ * @return Has ever been filled
+ */
+ boolean hasBeenFilled();
+
+ /**
+ * Has this player ever looted this block
+ *
+ * @param player The player to check
+ * @return Whether or not this player has looted this block
+ * @return Whether this player has looted this block
+ */
+ default boolean hasPlayerLooted(final @NotNull Player player) {
+ default boolean hasPlayerLooted(final Player player) {
+ return this.hasPlayerLooted(player.getUniqueId());
+ }
+
@ -109,17 +111,17 @@ index 0000000000000000000000000000000000000000..b18a0b50c12fe8d8c954e5c070f2ecd1
+ * Checks if this player can loot this block. Takes into account the "restrict player reloot" settings
+ *
+ * @param player the player to check
+ *
+ * @return Whether this player can loot this block
+ */
+ boolean canPlayerLoot(@NotNull UUID player);
+ boolean canPlayerLoot(UUID player);
+
+ /**
+ * Has this player ever looted this block
+ *
+ * @param player The player to check
+ * @return Whether or not this player has looted this block
+ * @return Whether this player has looted this block
+ */
+ boolean hasPlayerLooted(@NotNull UUID player);
+ boolean hasPlayerLooted(UUID player);
+
+ /**
+ * Gets the timestamp, in milliseconds, of when the player last looted this object
@ -127,7 +129,7 @@ index 0000000000000000000000000000000000000000..b18a0b50c12fe8d8c954e5c070f2ecd1
+ * @param player The player to check
+ * @return Timestamp last looted, or null if player has not looted this object
+ */
+ default @Nullable Long getLastLooted(final @NotNull Player player) {
+ default @Nullable Long getLastLooted(final Player player) {
+ return this.getLastLooted(player.getUniqueId());
+ }
+
@ -137,29 +139,31 @@ index 0000000000000000000000000000000000000000..b18a0b50c12fe8d8c954e5c070f2ecd1
+ * @param player The player to check
+ * @return Timestamp last looted, or null if player has not looted this object
+ */
+ @Nullable
+ Long getLastLooted(@NotNull UUID player);
+ @Nullable Long getLastLooted(UUID player);
+
+ /**
+ * Change the state of whether or not a player has looted this block
+ * Change the state of whether a player has looted this block
+ *
+ * @param player The player to change state for
+ * @param looted true to add player to looted list, false to remove
+ * @return The previous state of whether the player had looted this or not
+ */
+ default boolean setHasPlayerLooted(final @NotNull Player player, final boolean looted) {
+ default boolean setHasPlayerLooted(final Player player, final boolean looted) {
+ return this.setHasPlayerLooted(player.getUniqueId(), looted);
+ }
+
+ /**
+ * Change the state of whether or not a player has looted this block
+ * Change the state of whether a player has looted this block
+ *
+ * @param player The player to change state for
+ * @param looted true to add player to looted list, false to remove
+ * @return The previous state of whether the player had looted this or not
+ */
+ boolean setHasPlayerLooted(@NotNull UUID player, boolean looted);
+ boolean setHasPlayerLooted(UUID player, boolean looted);
+
+ /**
+ * Returns Whether or not this object has been filled and now has a pending refill
+ * Returns Whether this object has been filled and now has a pending refill
+ *
+ * @return Has pending refill
+ */
+ boolean hasPendingRefill();
@ -188,10 +192,10 @@ index 0000000000000000000000000000000000000000..b18a0b50c12fe8d8c954e5c070f2ecd1
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java b/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ee1a04aaaa4ef09559f2cf757811e463e2a1be6
index 0000000000000000000000000000000000000000..994c2183db89fc40d5991d5e1906e4bd04db6291
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java
@@ -0,0 +1,47 @@
@@ -0,0 +1,46 @@
+package com.destroystokyo.paper.loottable;
+
+import org.bukkit.entity.Player;
@ -199,22 +203,22 @@ index 0000000000000000000000000000000000000000..5ee1a04aaaa4ef09559f2cf757811e46
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public class LootableInventoryReplenishEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final LootableInventory inventory;
+ private final LootableInventory inventory;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public LootableInventoryReplenishEvent(@NotNull Player player, @NotNull LootableInventory inventory) {
+ public LootableInventoryReplenishEvent(final Player player, final LootableInventory inventory) {
+ super(player);
+ this.inventory = inventory;
+ }
+
+ @NotNull
+ public LootableInventory getInventory() {
+ return this.inventory;
+ }
@ -225,16 +229,15 @@ index 0000000000000000000000000000000000000000..5ee1a04aaaa4ef09559f2cf757811e46
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,34 +6,34 @@ Subject: [PATCH] Add EntityZapEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityZapEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityZapEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc6d15975a47e68c5bd939e68ddd2773028a6ac8
index 0000000000000000000000000000000000000000..af2b1629f845ffe1559e7d580b482636cc6441d9
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityZapEvent.java
@@ -0,0 +1,69 @@
@@ -0,0 +1,65 @@
+package com.destroystokyo.paper.event.entity;
+
+import java.util.Collections;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LightningStrike;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityTransformEvent;
+
+import java.util.Collections;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when lightning strikes an entity
+ */
+@NullMarked
+public class EntityZapEvent extends EntityTransformEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final LightningStrike bolt;
+ private final LightningStrike bolt;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EntityZapEvent(@NotNull final Entity entity, @NotNull final LightningStrike bolt, @NotNull final Entity replacementEntity) {
+ public EntityZapEvent(final Entity entity, final LightningStrike bolt, final Entity replacementEntity) {
+ super(entity, Collections.singletonList(replacementEntity), TransformReason.LIGHTNING);
+ this.bolt = bolt;
+ }
@ -43,7 +43,6 @@ index 0000000000000000000000000000000000000000..dc6d15975a47e68c5bd939e68ddd2773
+ *
+ * @return The lightning bolt responsible for this event
+ */
+ @NotNull
+ public LightningStrike getBolt() {
+ return this.bolt;
+ }
@ -53,7 +52,6 @@ index 0000000000000000000000000000000000000000..dc6d15975a47e68c5bd939e68ddd2773
+ *
+ * @return The entity that will replace the struck entity
+ */
+ @NotNull
+ public Entity getReplacementEntity() {
+ return super.getTransformedEntity();
+ }
@ -64,17 +62,15 @@ index 0000000000000000000000000000000000000000..dc6d15975a47e68c5bd939e68ddd2773
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,41 +6,44 @@ Subject: [PATCH] Misc Utils
diff --git a/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java b/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bb677ce585b856b3d3e589e29786a29619c56a7
index 0000000000000000000000000000000000000000..ebaa12ecacd169f00e184fed95720d047eda8b9d
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java
@@ -0,0 +1,34 @@
@@ -0,0 +1,37 @@
+package com.destroystokyo.paper.utils;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+@NullMarked
+@ApiStatus.Internal
+public class CachedSizeConcurrentLinkedQueue<E> extends ConcurrentLinkedQueue<E> {
+
+ private final LongAdder cachedSize = new LongAdder();
+
+ @Override
+ public boolean add(@NotNull E e) {
+ boolean result = super.add(e);
+ public boolean add(final E e) {
+ final boolean result = super.add(e);
+ if (result) {
+ cachedSize.increment();
+ this.cachedSize.increment();
+ }
+ return result;
+ }
+
+ @Nullable
+ @Override
+ public E poll() {
+ E result = super.poll();
+ public @Nullable E poll() {
+ final E result = super.poll();
+ if (result != null) {
+ cachedSize.decrement();
+ this.cachedSize.decrement();
+ }
+ return result;
+ }
+
+ @Override
+ public int size() {
+ return cachedSize.intValue();
+ return this.cachedSize.intValue();
+ }
+}

View file

@ -7,7 +7,7 @@ Allows you to access the Gateway being used in a teleport event
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerTeleportEndGatewayEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerTeleportEndGatewayEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..40bd79fbe30f19bc93e34da52d2b2bf0768be974
index 0000000000000000000000000000000000000000..4488154d3f99f4281b08eef8a44c13fd896e538f
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerTeleportEndGatewayEvent.java
@@ -0,0 +1,32 @@
@ -18,17 +18,18 @@ index 0000000000000000000000000000000000000000..40bd79fbe30f19bc93e34da52d2b2bf0
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a teleport is triggered for an End Gateway
+ */
+@NullMarked
+public class PlayerTeleportEndGatewayEvent extends PlayerTeleportEvent {
+
+ @NotNull private final EndGateway gateway;
+ private final EndGateway gateway;
+
+ @ApiStatus.Internal
+ public PlayerTeleportEndGatewayEvent(@NotNull Player player, @NotNull Location from, @NotNull Location to, @NotNull EndGateway gateway) {
+ public PlayerTeleportEndGatewayEvent(final Player player, final Location from, final Location to, final EndGateway gateway) {
+ super(player, from, to, PlayerTeleportEvent.TeleportCause.END_GATEWAY);
+ this.gateway = gateway;
+ }
@ -38,7 +39,6 @@ index 0000000000000000000000000000000000000000..40bd79fbe30f19bc93e34da52d2b2bf0
+ *
+ * @return EndGateway used
+ */
+ @NotNull
+ public EndGateway getGateway() {
+ return this.gateway;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] PlayerAttemptPickupItemEvent
diff --git a/src/main/java/org/bukkit/event/player/PlayerAttemptPickupItemEvent.java b/src/main/java/org/bukkit/event/player/PlayerAttemptPickupItemEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..13e4b1309ea9965a07fc8b276d5a7e606e205824
index 0000000000000000000000000000000000000000..eff29875f6282d8bd04a33cb572c90090742d3b2
--- /dev/null
+++ b/src/main/java/org/bukkit/event/player/PlayerAttemptPickupItemEvent.java
@@ -0,0 +1,96 @@
@@ -0,0 +1,94 @@
+package org.bukkit.event.player;
+
+import org.bukkit.entity.Item;
@ -17,16 +17,17 @@ index 0000000000000000000000000000000000000000..13e4b1309ea9965a07fc8b276d5a7e60
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Thrown when a player attempts to pick an item up from the ground
+ */
+@NullMarked
+public class PlayerAttemptPickupItemEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Item item;
+ private final Item item;
+ private final int remaining;
+ private boolean flyAtPlayer = true;
+
@ -34,12 +35,12 @@ index 0000000000000000000000000000000000000000..13e4b1309ea9965a07fc8b276d5a7e60
+
+ @Deprecated // Remove in 1.13 // Remove in 1.14?
+ @ApiStatus.Internal
+ public PlayerAttemptPickupItemEvent(@NotNull final Player player, @NotNull final Item item) {
+ public PlayerAttemptPickupItemEvent(final Player player, final Item item) {
+ this(player, item, 0);
+ }
+
+ @ApiStatus.Internal
+ public PlayerAttemptPickupItemEvent(@NotNull final Player player, @NotNull final Item item, final int remaining) {
+ public PlayerAttemptPickupItemEvent(final Player player, final Item item, final int remaining) {
+ super(player);
+ this.item = item;
+ this.remaining = remaining;
@ -50,7 +51,6 @@ index 0000000000000000000000000000000000000000..13e4b1309ea9965a07fc8b276d5a7e60
+ *
+ * @return Item
+ */
+ @NotNull
+ public Item getItem() {
+ return this.item;
+ }
@ -95,13 +95,11 @@ index 0000000000000000000000000000000000000000..13e4b1309ea9965a07fc8b276d5a7e60
+ this.flyAtPlayer = !cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add UnknownCommandEvent
diff --git a/src/main/java/org/bukkit/event/command/UnknownCommandEvent.java b/src/main/java/org/bukkit/event/command/UnknownCommandEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bdeeecdb6021d61fd9141270011e56b06a58a76
index 0000000000000000000000000000000000000000..58fe8f60ad5e7ca0ffddebb7ba5748bbfb129ddd
--- /dev/null
+++ b/src/main/java/org/bukkit/event/command/UnknownCommandEvent.java
@@ -0,0 +1,110 @@
@@ -0,0 +1,105 @@
+package org.bukkit.event.command;
+
+import net.kyori.adventure.text.Component;
@ -19,22 +19,23 @@ index 0000000000000000000000000000000000000000..9bdeeecdb6021d61fd9141270011e56b
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Thrown when a player executes a command that is not defined
+ */
+@NullMarked
+public class UnknownCommandEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final CommandSender sender;
+ @NotNull private final String commandLine;
+ @Nullable private Component message;
+ private final CommandSender sender;
+ private final String commandLine;
+ private @Nullable Component message;
+
+ @ApiStatus.Internal
+ public UnknownCommandEvent(@NotNull final CommandSender sender, @NotNull final String commandLine, @Nullable final Component message) {
+ public UnknownCommandEvent(final CommandSender sender, final String commandLine, final @Nullable Component message) {
+ super(false);
+ this.sender = sender;
+ this.commandLine = commandLine;
@ -46,7 +47,6 @@ index 0000000000000000000000000000000000000000..9bdeeecdb6021d61fd9141270011e56b
+ *
+ * @return Sender of the command
+ */
+ @NotNull
+ public CommandSender getSender() {
+ return this.sender;
+ }
@ -56,7 +56,6 @@ index 0000000000000000000000000000000000000000..9bdeeecdb6021d61fd9141270011e56b
+ *
+ * @return Command sent
+ */
+ @NotNull
+ public String getCommandLine() {
+ return this.commandLine;
+ }
@ -67,9 +66,8 @@ index 0000000000000000000000000000000000000000..9bdeeecdb6021d61fd9141270011e56b
+ * @return Unknown command message
+ * @deprecated use {@link #message()}
+ */
+ @Nullable
+ @Deprecated
+ public String getMessage() {
+ public @Nullable String getMessage() {
+ return this.message == null ? null : LegacyComponentSerializer.legacySection().serialize(this.message);
+ }
+
@ -91,9 +89,8 @@ index 0000000000000000000000000000000000000000..9bdeeecdb6021d61fd9141270011e56b
+ *
+ * @return Unknown command message
+ */
+ @Nullable
+ @Contract(pure = true)
+ public Component message() {
+ public @Nullable Component message() {
+ return this.message;
+ }
+
@ -108,13 +105,11 @@ index 0000000000000000000000000000000000000000..9bdeeecdb6021d61fd9141270011e56b
+ this.message = message;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -7,29 +7,30 @@ Provides basic elements of a PlayerProfile to be used by future API/events
diff --git a/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java b/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java
new file mode 100644
index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c274a1ec4cd
index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9298a5e00
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java
@@ -0,0 +1,234 @@
@@ -0,0 +1,246 @@
+package com.destroystokyo.paper.profile;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.UUID;
+
+import java.util.concurrent.CompletableFuture;
+import org.bukkit.profile.PlayerTextures;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Represents a players profile for the game, such as UUID, Name, and textures.
+ */
+@NullMarked
+public interface PlayerProfile extends org.bukkit.profile.PlayerProfile {
+
+ /**
+ * @return The players name, if set
+ */
+ @Override
+ @Nullable
+ String getName();
+
@ -39,14 +40,14 @@ index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c27
+ * @param name The new Name
+ * @return The previous Name
+ */
+ @NotNull
+ @Deprecated(forRemoval = true, since = "1.18.1")
+ String setName(@Nullable String name);
+
+ /**
+ * @return The players unique identifier, if set
+ */
+ @Nullable UUID getId();
+ @Nullable
+ UUID getId();
+
+ /**
+ * Sets this profiles UUID
@ -54,8 +55,8 @@ index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c27
+ * @param uuid The new UUID
+ * @return The previous UUID
+ */
+ @Nullable
+ @Deprecated(forRemoval = true, since = "1.18.1")
+ @Nullable
+ UUID setId(@Nullable UUID uuid);
+
+ /**
@ -65,7 +66,7 @@ index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c27
+ *
+ * @return the textures, not <code>null</code>
+ */
+ @NotNull
+ @Override
+ PlayerTextures getTextures();
+
+ /**
@ -74,16 +75,18 @@ index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c27
+ * @param textures the textures to copy, or <code>null</code> to clear the
+ * textures
+ */
+ @Override
+ void setTextures(@Nullable PlayerTextures textures);
+
+ /**
+ * @return A Mutable set of this players properties, such as textures.
+ * Values specified here are subject to implementation details.
+ */
+ @NotNull Set<ProfileProperty> getProperties();
+ Set<ProfileProperty> getProperties();
+
+ /**
+ * Check if the Profile has the specified property
+ *
+ * @param property Property name to check
+ * @return If the property is set
+ */
@ -95,17 +98,19 @@ index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c27
+ * @param property Property to set.
+ * @throws IllegalArgumentException if setting the property results in more than 16 properties
+ */
+ void setProperty(@NotNull ProfileProperty property);
+ void setProperty(ProfileProperty property);
+
+ /**
+ * Sets multiple properties. If any of the set properties already exist, it will be replaced
+ *
+ * @param properties The properties to set
+ * @throws IllegalArgumentException if the number of properties exceeds 16
+ */
+ void setProperties(@NotNull Collection<ProfileProperty> properties);
+ void setProperties(Collection<ProfileProperty> properties);
+
+ /**
+ * Removes a specific property from this profile
+ *
+ * @param property The property to remove
+ * @return If a property was removed
+ */
@ -113,22 +118,24 @@ index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c27
+
+ /**
+ * Removes a specific property from this profile
+ *
+ * @param property The property to remove
+ * @return If a property was removed
+ */
+ default boolean removeProperty(@NotNull ProfileProperty property) {
+ return removeProperty(property.getName());
+ default boolean removeProperty(final ProfileProperty property) {
+ return this.removeProperty(property.getName());
+ }
+
+ /**
+ * Removes all properties in the collection
+ *
+ * @param properties The properties to remove
+ * @return If any property was removed
+ */
+ default boolean removeProperties(@NotNull Collection<ProfileProperty> properties) {
+ default boolean removeProperties(final Collection<ProfileProperty> properties) {
+ boolean removed = false;
+ for (ProfileProperty property : properties) {
+ if (removeProperty(property)) {
+ for (final ProfileProperty property : properties) {
+ if (this.removeProperty(property)) {
+ removed = true;
+ }
+ }
@ -143,6 +150,7 @@ index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c27
+ /**
+ * @return If the profile is now complete (has UUID and Name)
+ */
+ @Override
+ boolean isComplete();
+
+ /**
@ -175,21 +183,23 @@ index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c27
+ /**
+ * If this profile is not complete, then make the API call to complete it.
+ * This is a blocking operation and should be done asynchronously.
+ *
+ * <p>
+ * This will also complete textures. If you do not want to load textures, use {{@link #complete(boolean)}}
+ *
+ * @return If the profile is now complete (has UUID and Name) (if you get rate limited, this operation may fail)
+ */
+ default boolean complete() {
+ return complete(true);
+ return this.complete(true);
+ }
+
+ /**
+ * If this profile is not complete, then make the API call to complete it.
+ * This is a blocking operation and should be done asynchronously.
+ *
+ * <p>
+ * Optionally will also fill textures.
+ *
+ * <p>
+ * Online mode will be automatically determined
+ *
+ * @param textures controls if we should fill the profile with texture properties
+ * @return If the profile is now complete (has UUID and Name) (if you get rate limited, this operation may fail)
+ */
@ -198,8 +208,9 @@ index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c27
+ /**
+ * If this profile is not complete, then make the API call to complete it.
+ * This is a blocking operation and should be done asynchronously.
+ *
+ * <p>
+ * Optionally will also fill textures.
+ *
+ * @param textures controls if we should fill the profile with texture properties
+ * @param onlineMode Treat this server as online mode or not
+ * @return If the profile is now complete (has UUID and Name) (if you get rate limited, this operation may fail)
@ -235,43 +246,45 @@ index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c27
+ * </pre>
+ */
+ @Override
+ @NotNull CompletableFuture<PlayerProfile> update();
+ CompletableFuture<PlayerProfile> update();
+
+ /**
+ * Whether this Profile has textures associated to it
+ *
+ * @return If it has a textures property
+ */
+ default boolean hasTextures() {
+ return hasProperty("textures");
+ return this.hasProperty("textures");
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java b/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f913a078dd692a9feafb98a6e6c9583f3253bd4
index 0000000000000000000000000000000000000000..35341d8f1ac2d80f339084ef80d099a545027554
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java
@@ -0,0 +1,75 @@
@@ -0,0 +1,73 @@
+package com.destroystokyo.paper.profile;
+
+import com.google.common.base.Preconditions;
+
+import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Represents a property on a {@link PlayerProfile}
+ */
+public class ProfileProperty {
+@NullMarked
+public final class ProfileProperty {
+
+ private final String name;
+ private final String value;
+ private final String signature;
+ private final @Nullable String signature;
+
+ public ProfileProperty(@NotNull String name, @NotNull String value) {
+ public ProfileProperty(final String name, final String value) {
+ this(name, value, null);
+ }
+
+ public ProfileProperty(@NotNull String name, @NotNull String value, @Nullable String signature) {
+ public ProfileProperty(final String name, final String value, final @Nullable String signature) {
+ this.name = Preconditions.checkNotNull(name, "ProfileProperty name can not be null");
+ this.value = Preconditions.checkNotNull(value, "ProfileProperty value can not be null");
+ this.signature = signature;
@ -283,25 +296,22 @@ index 0000000000000000000000000000000000000000..8f913a078dd692a9feafb98a6e6c9583
+ /**
+ * @return The property name, ie "textures"
+ */
+ @NotNull
+ public String getName() {
+ return name;
+ return this.name;
+ }
+
+ /**
+ * @return The property value, likely to be base64 encoded
+ */
+ @NotNull
+ public String getValue() {
+ return value;
+ return this.value;
+ }
+
+ /**
+ * @return A signature from Mojang for signed properties
+ */
+ @Nullable
+ public String getSignature() {
+ return signature;
+ public @Nullable String getSignature() {
+ return this.signature;
+ }
+
+ /**
@ -312,18 +322,18 @@ index 0000000000000000000000000000000000000000..8f913a078dd692a9feafb98a6e6c9583
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ public boolean equals(final @Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ProfileProperty that = (ProfileProperty) o;
+ return Objects.equals(name, that.name) &&
+ Objects.equals(value, that.value) &&
+ Objects.equals(signature, that.signature);
+ if (o == null || this.getClass() != o.getClass()) return false;
+ final ProfileProperty that = (ProfileProperty) o;
+ return Objects.equals(this.name, that.name) &&
+ Objects.equals(this.value, that.value) &&
+ Objects.equals(this.signature, that.signature);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name);
+ return Objects.hash(this.name);
+ }
+}
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java

View file

@ -8,19 +8,18 @@ profiles that had to be looked up.
diff --git a/src/main/java/com/destroystokyo/paper/event/profile/LookupProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/LookupProfileEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ad2782aafe76f8b10565c0f0419d6b9c665b267
index 0000000000000000000000000000000000000000..9e8ae0ab13cac9a260c9959eb6bf5b93a3c15018
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/profile/LookupProfileEvent.java
@@ -0,0 +1,48 @@
@@ -0,0 +1,45 @@
+package com.destroystokyo.paper.event.profile;
+
+import com.destroystokyo.paper.profile.PlayerProfile;
+import org.bukkit.Bukkit;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Allows a plugin to be notified anytime AFTER a Profile has been looked up from the Mojang API
@ -29,14 +28,15 @@ index 0000000000000000000000000000000000000000..2ad2782aafe76f8b10565c0f0419d6b9
+ * No guarantees are made about thread execution context for this event. If you need to know, check
+ * {@link Event#isAsynchronous()}
+ */
+@NullMarked
+public class LookupProfileEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final PlayerProfile profile;
+ private final PlayerProfile profile;
+
+ @ApiStatus.Internal
+ public LookupProfileEvent(@NotNull PlayerProfile profile) {
+ public LookupProfileEvent(final PlayerProfile profile) {
+ super(!Bukkit.isPrimaryThread());
+ this.profile = profile;
+ }
@ -44,41 +44,37 @@ index 0000000000000000000000000000000000000000..2ad2782aafe76f8b10565c0f0419d6b9
+ /**
+ * @return The profile that was recently looked up. This profile can be mutated
+ */
+ @NotNull
+ public PlayerProfile getPlayerProfile() {
+ return this.profile;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..3f73ec52f9b581001bef3a19a5f1533dfa474356
index 0000000000000000000000000000000000000000..07416cc9e2b8156be2cc92d6d974b881b427fd99
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java
@@ -0,0 +1,112 @@
@@ -0,0 +1,107 @@
+package com.destroystokyo.paper.event.profile;
+
+import com.destroystokyo.paper.profile.ProfileProperty;
+import org.bukkit.Bukkit;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+import org.bukkit.Bukkit;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Allows a plugin to intercept a Profile Lookup for a Profile by name
@ -90,17 +86,18 @@ index 0000000000000000000000000000000000000000..3f73ec52f9b581001bef3a19a5f1533d
+ * No guarantees are made about thread execution context for this event. If you need to know, check
+ * {@link Event#isAsynchronous()}
+ */
+@NullMarked
+public class PreLookupProfileEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final String name;
+ private final String name;
+
+ private UUID uuid;
+ @NotNull private Set<ProfileProperty> properties = new HashSet<>();
+ private @Nullable UUID uuid;
+ private Set<ProfileProperty> properties = new HashSet<>();
+
+ @ApiStatus.Internal
+ public PreLookupProfileEvent(@NotNull String name) {
+ public PreLookupProfileEvent(final String name) {
+ super(!Bukkit.isPrimaryThread());
+ this.name = name;
+ }
@ -108,7 +105,6 @@ index 0000000000000000000000000000000000000000..3f73ec52f9b581001bef3a19a5f1533d
+ /**
+ * @return Name of the profile
+ */
+ @NotNull
+ public String getName() {
+ return this.name;
+ }
@ -120,8 +116,7 @@ index 0000000000000000000000000000000000000000..3f73ec52f9b581001bef3a19a5f1533d
+ *
+ * @return The UUID of the profile if it has already been provided by a plugin
+ */
+ @Nullable
+ public UUID getUUID() {
+ public @Nullable UUID getUUID() {
+ return this.uuid;
+ }
+
@ -132,7 +127,7 @@ index 0000000000000000000000000000000000000000..3f73ec52f9b581001bef3a19a5f1533d
+ *
+ * @param uuid the UUID to set for the profile or {@code null} to reset
+ */
+ public void setUUID(@Nullable UUID uuid) {
+ public void setUUID(final @Nullable UUID uuid) {
+ this.uuid = uuid;
+ }
+
@ -140,7 +135,6 @@ index 0000000000000000000000000000000000000000..3f73ec52f9b581001bef3a19a5f1533d
+ * @return The currently pending pre-populated properties.
+ * Any property in this Set will be automatically prefilled on this Profile
+ */
+ @NotNull
+ public Set<ProfileProperty> getProfileProperties() {
+ return this.properties;
+ }
@ -151,7 +145,7 @@ index 0000000000000000000000000000000000000000..3f73ec52f9b581001bef3a19a5f1533d
+ *
+ * @param properties The properties to add
+ */
+ public void setProfileProperties(@NotNull Set<ProfileProperty> properties) {
+ public void setProfileProperties(final Set<ProfileProperty> properties) {
+ this.properties = new HashSet<>();
+ this.properties.addAll(properties);
+ }
@ -162,17 +156,15 @@ index 0000000000000000000000000000000000000000..3f73ec52f9b581001bef3a19a5f1533d
+ *
+ * @param properties The properties to add
+ */
+ public void addProfileProperties(@NotNull Set<ProfileProperty> properties) {
+ public void addProfileProperties(final Set<ProfileProperty> properties) {
+ this.properties.addAll(properties);
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -8,14 +8,16 @@ and access their saddle state separately from an interface shared with Armor.
diff --git a/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java b/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..163ffe8ff76ded6265d865901d5110fb6a56950d
index 0000000000000000000000000000000000000000..994f34ac2062c092c2b4e5ff364067482d19588c
--- /dev/null
+++ b/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java
@@ -0,0 +1,21 @@
@@ -0,0 +1,22 @@
+package org.bukkit.inventory;
+
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+@NullMarked
+public interface ArmoredHorseInventory extends AbstractHorseInventory {
+
+ /**
@ -23,8 +25,7 @@ index 0000000000000000000000000000000000000000..163ffe8ff76ded6265d865901d5110fb
+ *
+ * @return the armor item
+ */
+ @Nullable
+ ItemStack getArmor();
+ @Nullable ItemStack getArmor();
+
+ /**
+ * Sets the item in the horse's armor slot.
@ -74,10 +75,14 @@ index 2fa2c9d07ecbafaf2396d913af90f1f4d432b238..5ac1afb8a213fa0fe344db4730ecbc5d
* Gets the item in the llama's decor slot.
diff --git a/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java b/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..7944f26a3e2a92601c3be0e55c00c39cc16cf177
index 0000000000000000000000000000000000000000..0f508a8df87f1e23764152d00e02a3da5131f034
--- /dev/null
+++ b/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java
@@ -0,0 +1,3 @@
@@ -0,0 +1,7 @@
+package org.bukkit.inventory;
+
+public interface SaddledHorseInventory extends AbstractHorseInventory {}
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public interface SaddledHorseInventory extends AbstractHorseInventory {
+}

View file

@ -9,10 +9,10 @@ Allows you to do dynamic whitelisting and change of kick message
diff --git a/src/main/java/com/destroystokyo/paper/event/profile/ProfileWhitelistVerifyEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/ProfileWhitelistVerifyEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..52959c2d19c5b73ccd85afce6b2ab8133478f7c6
index 0000000000000000000000000000000000000000..901efb61fdc02b3228cc25649926d691c4617512
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/profile/ProfileWhitelistVerifyEvent.java
@@ -0,0 +1,147 @@
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017 - Daniel Ennis (Aikar) - MIT License
+ *
@ -44,8 +44,9 @@ index 0000000000000000000000000000000000000000..52959c2d19c5b73ccd85afce6b2ab813
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.Contract;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Fires when the server needs to verify if a player is whitelisted.
@ -53,24 +54,25 @@ index 0000000000000000000000000000000000000000..52959c2d19c5b73ccd85afce6b2ab813
+ * Plugins may override/control the servers whitelist with this event,
+ * and dynamically change the kick message.
+ */
+@NullMarked
+public class ProfileWhitelistVerifyEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final PlayerProfile profile;
+ private final PlayerProfile profile;
+ private final boolean whitelistEnabled;
+ private final boolean isOp;
+ private boolean whitelisted;
+ @Nullable private Component kickMessage;
+ private @Nullable Component kickMessage;
+
+ @Deprecated
+ @ApiStatus.Internal
+ public ProfileWhitelistVerifyEvent(@NotNull final PlayerProfile profile, boolean whitelistEnabled, boolean whitelisted, boolean isOp, @Nullable String kickMessage) {
+ public ProfileWhitelistVerifyEvent(final PlayerProfile profile, final boolean whitelistEnabled, final boolean whitelisted, final boolean isOp, final @Nullable String kickMessage) {
+ this(profile, whitelistEnabled, whitelisted, isOp, kickMessage == null ? null : LegacyComponentSerializer.legacySection().deserialize(kickMessage));
+ }
+
+ @ApiStatus.Internal
+ public ProfileWhitelistVerifyEvent(@NotNull final PlayerProfile profile, boolean whitelistEnabled, boolean whitelisted, boolean isOp, @Nullable Component kickMessage) {
+ public ProfileWhitelistVerifyEvent(final PlayerProfile profile, final boolean whitelistEnabled, final boolean whitelisted, final boolean isOp, final @Nullable Component kickMessage) {
+ this.profile = profile;
+ this.whitelistEnabled = whitelistEnabled;
+ this.whitelisted = whitelisted;
@ -83,8 +85,7 @@ index 0000000000000000000000000000000000000000..52959c2d19c5b73ccd85afce6b2ab813
+ * @deprecated use {@link #kickMessage()}
+ */
+ @Deprecated
+ @Nullable
+ public String getKickMessage() {
+ public @Nullable String getKickMessage() {
+ return this.kickMessage == null ? null : LegacyComponentSerializer.legacySection().serialize(this.kickMessage);
+ }
+
@ -93,35 +94,34 @@ index 0000000000000000000000000000000000000000..52959c2d19c5b73ccd85afce6b2ab813
+ * @deprecated Use {@link #kickMessage(Component)}
+ */
+ @Deprecated
+ public void setKickMessage(@Nullable String kickMessage) {
+ public void setKickMessage(final @Nullable String kickMessage) {
+ this.kickMessage(kickMessage == null ? null : LegacyComponentSerializer.legacySection().deserialize(kickMessage));
+ }
+
+ /**
+ * @return the currently planned message to send to the user if they are not whitelisted
+ */
+ @Nullable
+ public Component kickMessage() {
+ @Contract(pure = true)
+ public @Nullable Component kickMessage() {
+ return this.kickMessage;
+ }
+
+ /**
+ * @param kickMessage The message to send to the player on kick if not whitelisted. May set to {@code null} to use the server configured default
+ */
+ public void kickMessage(@Nullable Component kickMessage) {
+ public void kickMessage(final @Nullable Component kickMessage) {
+ this.kickMessage = kickMessage;
+ }
+
+ /**
+ * @return The profile of the player trying to connect
+ */
+ @NotNull
+ public PlayerProfile getPlayerProfile() {
+ return this.profile;
+ }
+
+ /**
+ * @return Whether the player is whitelisted to play on this server (whitelist may be off is why its true)
+ * @return Whether the player is whitelisted to play on this server (whitelist may be off is why it's true)
+ */
+ public boolean isWhitelisted() {
+ return this.whitelisted;
@ -129,9 +129,10 @@ index 0000000000000000000000000000000000000000..52959c2d19c5b73ccd85afce6b2ab813
+
+ /**
+ * Changes the players whitelisted state. {@code false} will deny the login
+ *
+ * @param whitelisted The new whitelisted state
+ */
+ public void setWhitelisted(boolean whitelisted) {
+ public void setWhitelisted(final boolean whitelisted) {
+ this.whitelisted = whitelisted;
+ }
+
@ -149,13 +150,11 @@ index 0000000000000000000000000000000000000000..52959c2d19c5b73ccd85afce6b2ab813
+ return this.whitelistEnabled;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -14,7 +14,7 @@ it without having to shade it in the plugin and going through
several layers of logging abstraction.
diff --git a/build.gradle.kts b/build.gradle.kts
index 258d7010d24c529c9bbc76cc26adf226c641ee58..4da053d427f3f9c5e7fc144408836ebef80026c6 100644
index 3c50362de25617d878ef58f14f67c240005ff624..76aa23da778b0fe8a093429c56cb29b044359b40 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -12,6 +12,8 @@ java {
@ -35,7 +35,7 @@ index 258d7010d24c529c9bbc76cc26adf226c641ee58..4da053d427f3f9c5e7fc144408836ebe
implementation("org.ow2.asm:asm:9.7")
implementation("org.ow2.asm:asm-commons:9.7")
@@ -138,6 +142,8 @@ tasks.withType<Javadoc> {
@@ -140,6 +144,8 @@ tasks.withType<Javadoc> {
"https://jd.advntr.dev/text-serializer-legacy/$adventureVersion/",
"https://jd.advntr.dev/text-serializer-plain/$adventureVersion/",
"https://jd.advntr.dev/text-logger-slf4j/$adventureVersion/",
@ -45,7 +45,7 @@ index 258d7010d24c529c9bbc76cc26adf226c641ee58..4da053d427f3f9c5e7fc144408836ebe
"https://javadoc.io/doc/org.apache.maven.resolver/maven-resolver-api/1.7.3", // Paper
)
diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java
index 8c76716249e44ed8bf6be94c1f5c7b6d9bb35be2..4eb639fbb46a0848be207149ea433455550fae1c 100644
index 68a0ed5f0ed25e98f4ab4d1e482ec2ccfda9cd3a..46fc37a36403c8fbc4c0c9f863d4d57eb3896bd4 100644
--- a/src/main/java/org/bukkit/plugin/Plugin.java
+++ b/src/main/java/org/bukkit/plugin/Plugin.java
@@ -198,6 +198,22 @@ public interface Plugin extends TabExecutor {

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add PlayerJumpEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerJumpEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerJumpEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c2fd2c1120d634052f9bc345365272ad3a67b6f
index 0000000000000000000000000000000000000000..1d07c3d6bf3b9283371ca45698178979113085fa
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerJumpEvent.java
@@ -0,0 +1,106 @@
@@ -0,0 +1,105 @@
+package com.destroystokyo.paper.event.player;
+
+import com.google.common.base.Preconditions;
@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..8c2fd2c1120d634052f9bc345365272a
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when the server detects the player is jumping.
@ -29,17 +29,18 @@ index 0000000000000000000000000000000000000000..8c2fd2c1120d634052f9bc345365272a
+ * when checking for jumps via {@link PlayerMoveEvent}, this event is fired whenever
+ * the server detects that the player is jumping.
+ */
+@NullMarked
+public class PlayerJumpEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Location to;
+ @NotNull private Location from;
+ private final Location to;
+ private Location from;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerJumpEvent(@NotNull final Player player, @NotNull final Location from, @NotNull final Location to) {
+ public PlayerJumpEvent(final Player player, final Location from, final Location to) {
+ super(player);
+ this.from = from;
+ this.to = to;
@ -54,6 +55,7 @@ index 0000000000000000000000000000000000000000..8c2fd2c1120d634052f9bc345365272a
+ *
+ * @return {@code true} if this event is cancelled
+ */
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
@ -67,7 +69,8 @@ index 0000000000000000000000000000000000000000..8c2fd2c1120d634052f9bc345365272a
+ *
+ * @param cancel {@code true} if you wish to cancel this event
+ */
+ public void setCancelled(boolean cancel) {
+ @Override
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
@ -76,7 +79,6 @@ index 0000000000000000000000000000000000000000..8c2fd2c1120d634052f9bc345365272a
+ *
+ * @return Location the player jumped from
+ */
+ @NotNull
+ public Location getFrom() {
+ return this.from;
+ }
@ -86,7 +88,7 @@ index 0000000000000000000000000000000000000000..8c2fd2c1120d634052f9bc345365272a
+ *
+ * @param from New location to mark as the players previous location
+ */
+ public void setFrom(@NotNull Location from) {
+ public void setFrom(final Location from) {
+ Preconditions.checkArgument(from != null, "Cannot use null from location!");
+ Preconditions.checkArgument(from.getWorld() != null, "Cannot use from location with null world!");
+ this.from = from;
@ -100,18 +102,15 @@ index 0000000000000000000000000000000000000000..8c2fd2c1120d634052f9bc345365272a
+ *
+ * @return Location the player jumped to
+ */
+ @NotNull
+ public Location getTo() {
+ return this.to.clone();
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -14,33 +14,31 @@ parent of the plugin logger to avoid this.
diff --git a/src/main/java/com/destroystokyo/paper/utils/PaperPluginLogger.java b/src/main/java/com/destroystokyo/paper/utils/PaperPluginLogger.java
new file mode 100644
index 0000000000000000000000000000000000000000..087ee57fe5485bc760fadd45a176d4d90a18f9f8
index 0000000000000000000000000000000000000000..c78a359566a11904d2dd41098ced556a91a7fa36
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/utils/PaperPluginLogger.java
@@ -0,0 +1,48 @@
@@ -0,0 +1,46 @@
+package com.destroystokyo.paper.utils;
+
+import io.papermc.paper.plugin.configuration.PluginMeta;
+import org.bukkit.plugin.PluginDescriptionFile;
+
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+import org.jetbrains.annotations.NotNull;
+import org.bukkit.plugin.PluginDescriptionFile;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Prevents plugins (e.g. Essentials) from changing the parent of the plugin logger.
+ */
+@NullMarked
+public class PaperPluginLogger extends Logger {
+
+ @Deprecated(forRemoval = true)
+ @NotNull
+ public static Logger getLogger(@NotNull PluginDescriptionFile description) {
+ public static Logger getLogger(final PluginDescriptionFile description) {
+ return getLogger((PluginMeta) description);
+ }
+
+ @NotNull
+ public static Logger getLogger(@NotNull PluginMeta meta) {
+ public static Logger getLogger(final PluginMeta meta) {
+ Logger logger = new PaperPluginLogger(meta);
+ if (!LogManager.getLogManager().addLogger(logger)) {
+ // Disable this if it's going to happen across reloads anyways...
@ -51,14 +49,14 @@ index 0000000000000000000000000000000000000000..087ee57fe5485bc760fadd45a176d4d9
+ return logger;
+ }
+
+ private PaperPluginLogger(@NotNull PluginMeta meta) {
+ private PaperPluginLogger(final PluginMeta meta) {
+ super(meta.getLoggerPrefix() != null ? meta.getLoggerPrefix() : meta.getName(), null);
+ }
+
+ @Override
+ public void setParent(@NotNull Logger parent) {
+ if (getParent() != null) {
+ warning("Ignoring attempt to change parent of plugin logger");
+ public void setParent(final Logger parent) {
+ if (this.getParent() != null) {
+ this.warning("Ignoring attempt to change parent of plugin logger");
+ } else {
+ this.log(Level.FINE, "Setting plugin logger parent to {0}", parent);
+ super.setParent(parent);
@ -67,7 +65,7 @@ index 0000000000000000000000000000000000000000..087ee57fe5485bc760fadd45a176d4d9
+
+}
diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
index f81e335a4e533221529355bec2f5d588aa79e60c..d359ea9b02952f981b9cf9d778c56eb995454c60 100644
index 801578de8599d6b546cde63b3f2655fab48eee03..2d64fc065d53dcd8c01d05215c3e63aaf4428177 100644
--- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
+++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
@@ -292,10 +292,10 @@ public abstract class JavaPlugin extends PluginBase {

View file

@ -6,22 +6,21 @@ Subject: [PATCH] Add PlayerArmorChangeEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab08219497f7e362f113321c4bcfd180b335bf20
index 0000000000000000000000000000000000000000..c7cc612ec81b0c7da6ee6676167e047e69347966
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java
@@ -0,0 +1,127 @@
@@ -0,0 +1,120 @@
+package com.destroystokyo.paper.event.player;
+
+import java.util.Set;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.Set;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+import static org.bukkit.Material.*;
+
@ -30,16 +29,17 @@ index 0000000000000000000000000000000000000000..ab08219497f7e362f113321c4bcfd180
+ * <p>
+ * Not currently called for environmental factors though it <strong>MAY BE IN THE FUTURE</strong>
+ */
+@NullMarked
+public class PlayerArmorChangeEvent extends PlayerEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final SlotType slotType;
+ @NotNull private final ItemStack oldItem;
+ @NotNull private final ItemStack newItem;
+ private final SlotType slotType;
+ private final ItemStack oldItem;
+ private final ItemStack newItem;
+
+ @ApiStatus.Internal
+ public PlayerArmorChangeEvent(@NotNull Player player, @NotNull SlotType slotType, @NotNull ItemStack oldItem, @NotNull ItemStack newItem) {
+ public PlayerArmorChangeEvent(final Player player, final SlotType slotType, final ItemStack oldItem, final ItemStack newItem) {
+ super(player);
+ this.slotType = slotType;
+ this.oldItem = oldItem;
@ -51,7 +51,6 @@ index 0000000000000000000000000000000000000000..ab08219497f7e362f113321c4bcfd180
+ *
+ * @return type of slot being altered
+ */
+ @NotNull
+ public SlotType getSlotType() {
+ return this.slotType;
+ }
@ -61,7 +60,6 @@ index 0000000000000000000000000000000000000000..ab08219497f7e362f113321c4bcfd180
+ *
+ * @return old item
+ */
+ @NotNull
+ public ItemStack getOldItem() {
+ return this.oldItem;
+ }
@ -71,18 +69,15 @@ index 0000000000000000000000000000000000000000..ab08219497f7e362f113321c4bcfd180
+ *
+ * @return new item
+ */
+ @NotNull
+ public ItemStack getNewItem() {
+ return this.newItem;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
@ -95,7 +90,7 @@ index 0000000000000000000000000000000000000000..ab08219497f7e362f113321c4bcfd180
+
+ private final Set<Material> types;
+
+ SlotType(Material... types) {
+ SlotType(final Material... types) {
+ this.types = Set.of(types);
+ }
+
@ -105,7 +100,6 @@ index 0000000000000000000000000000000000000000..ab08219497f7e362f113321c4bcfd180
+ *
+ * @return immutable set of material types
+ */
+ @NotNull
+ public Set<Material> getTypes() {
+ return this.types;
+ }
@ -116,9 +110,8 @@ index 0000000000000000000000000000000000000000..ab08219497f7e362f113321c4bcfd180
+ * @param material material to get slot by
+ * @return slot type the material will go in, or {@code null} if it won't
+ */
+ @Nullable
+ public static SlotType getByMaterial(@NotNull Material material) {
+ for (SlotType slotType : values()) {
+ public static @Nullable SlotType getByMaterial(final Material material) {
+ for (final SlotType slotType : values()) {
+ if (slotType.getTypes().contains(material)) {
+ return slotType;
+ }
@ -132,7 +125,7 @@ index 0000000000000000000000000000000000000000..ab08219497f7e362f113321c4bcfd180
+ * @param material material to check
+ * @return whether this material can be equipped
+ */
+ public static boolean isEquipable(@NotNull Material material) {
+ public static boolean isEquipable(final Material material) {
+ return getByMaterial(material) != null;
+ }
+ }

View file

@ -17,10 +17,10 @@ Co-authored-by: Aikar <aikar@aikar.co>
diff --git a/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java b/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98d2e9595f
index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f3449bbe7b5
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java
@@ -0,0 +1,339 @@
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License
+ *
@ -48,6 +48,10 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+
+import com.google.common.base.Preconditions;
+import io.papermc.paper.util.TransformingRandomAccessList;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Stream;
+import net.kyori.adventure.text.Component;
+import net.kyori.examination.Examinable;
+import net.kyori.examination.ExaminableProperty;
@ -58,14 +62,9 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Stream;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Allows plugins to compute tab completion results asynchronously.
@ -76,15 +75,15 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ * <p>
+ * Only 1 process will be allowed to provide completions, the Async Event, or the standard process.
+ */
+@NullMarked
+public class AsyncTabCompleteEvent extends Event implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final CommandSender sender;
+ @NotNull private final String buffer;
+ private final CommandSender sender;
+ private final String buffer;
+ private final boolean isCommand;
+ @Nullable
+ private final Location location;
+ private final @Nullable Location location;
+ private final List<Completion> completions = new ArrayList<>();
+ private final List<String> stringCompletions = new TransformingRandomAccessList<>(
+ this.completions,
@ -95,7 +94,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public AsyncTabCompleteEvent(@NotNull CommandSender sender, @NotNull String buffer, boolean isCommand, @Nullable Location loc) {
+ public AsyncTabCompleteEvent(final CommandSender sender, final String buffer, final boolean isCommand, final @Nullable Location loc) {
+ super(true);
+ this.sender = sender;
+ this.buffer = buffer;
@ -105,7 +104,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+
+ @Deprecated
+ @ApiStatus.Internal
+ public AsyncTabCompleteEvent(@NotNull CommandSender sender, @NotNull List<String> completions, @NotNull String buffer, boolean isCommand, @Nullable Location loc) {
+ public AsyncTabCompleteEvent(final CommandSender sender, final List<String> completions, final String buffer, final boolean isCommand, final @Nullable Location loc) {
+ super(true);
+ this.sender = sender;
+ this.completions.addAll(fromStrings(completions));
@ -119,7 +118,6 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ *
+ * @return the {@link CommandSender} instance
+ */
+ @NotNull
+ public CommandSender getSender() {
+ return this.sender;
+ }
@ -134,7 +132,6 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ *
+ * @return a list of offered completions
+ */
+ @NotNull
+ public List<String> getCompletions() {
+ return this.stringCompletions;
+ }
@ -149,7 +146,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ *
+ * @param completions the new completions
+ */
+ public void setCompletions(@NotNull List<String> completions) {
+ public void setCompletions(final List<String> completions) {
+ Preconditions.checkArgument(completions != null, "Completions list cannot be null");
+ if (completions == this.stringCompletions) {
+ return;
@ -168,7 +165,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ *
+ * @return a list of offered completions
+ */
+ public @NotNull List<Completion> completions() {
+ public List<Completion> completions() {
+ return this.completions;
+ }
+
@ -182,7 +179,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ *
+ * @param newCompletions the new completions
+ */
+ public void completions(final @NotNull List<Completion> newCompletions) {
+ public void completions(final List<Completion> newCompletions) {
+ Preconditions.checkArgument(newCompletions != null, "new completions cannot be null");
+ this.completions.clear();
+ this.completions.addAll(newCompletions);
@ -193,7 +190,6 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ *
+ * @return command buffer, as entered
+ */
+ @NotNull
+ public String getBuffer() {
+ return this.buffer;
+ }
@ -208,8 +204,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ /**
+ * @return The position looked at by the sender, or {@code null} if none
+ */
+ @Nullable
+ public Location getLocation() {
+ public @Nullable Location getLocation() {
+ return this.location != null ? this.location.clone() : null;
+ }
+
@ -230,7 +225,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ *
+ * @param handled if this completion should be marked as being handled
+ */
+ public void setHandled(boolean handled) {
+ public void setHandled(final boolean handled) {
+ this.handled = handled;
+ }
+
@ -245,21 +240,20 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ * Will provide no completions, and will not fire the synchronous process
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+
+ private static @NotNull List<Completion> fromStrings(final @NotNull List<String> suggestions) {
+ private static List<Completion> fromStrings(final List<String> suggestions) {
+ final List<Completion> list = new ArrayList<>(suggestions.size());
+ for (final String suggestion : suggestions) {
+ list.add(new CompletionImpl(suggestion, null));
@ -277,7 +271,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ *
+ * @return suggestion string
+ */
+ @NotNull String suggestion();
+ String suggestion();
+
+ /**
+ * Get the suggestion tooltip for this {@link Completion}.
@ -287,7 +281,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ @Nullable Component tooltip();
+
+ @Override
+ default @NotNull Stream<? extends ExaminableProperty> examinableProperties() {
+ default Stream<? extends ExaminableProperty> examinableProperties() {
+ return Stream.of(ExaminableProperty.of("suggestion", this.suggestion()), ExaminableProperty.of("tooltip", this.tooltip()));
+ }
+
@ -297,7 +291,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ * @param suggestion suggestion string
+ * @return new completion instance
+ */
+ static @NotNull Completion completion(final @NotNull String suggestion) {
+ static Completion completion(final String suggestion) {
+ return new CompletionImpl(suggestion, null);
+ }
+
@ -310,7 +304,7 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ * @param tooltip tooltip component, or {@code null}
+ * @return new completion instance
+ */
+ static @NotNull Completion completion(final @NotNull String suggestion, final @Nullable Component tooltip) {
+ static Completion completion(final String suggestion, final @Nullable Component tooltip) {
+ return new CompletionImpl(suggestion, tooltip);
+ }
+ }
@ -319,15 +313,15 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ static final class CompletionImpl implements Completion {
+
+ private final String suggestion;
+ private final Component tooltip;
+ private final @Nullable Component tooltip;
+
+ CompletionImpl(final @NotNull String suggestion, final @Nullable Component tooltip) {
+ CompletionImpl(final String suggestion, final @Nullable Component tooltip) {
+ this.suggestion = suggestion;
+ this.tooltip = tooltip;
+ }
+
+ @Override
+ public @NotNull String suggestion() {
+ public String suggestion() {
+ return this.suggestion;
+ }
+
@ -355,22 +349,19 @@ index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98
+ }
+
+ @Override
+ public @NotNull String toString() {
+ public String toString() {
+ return StringExaminer.simpleEscaping().examine(this);
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java b/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276118c1c7b
index 0000000000000000000000000000000000000000..488250fdcdc93ca1aba5042f63fb6286db518014
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java
@@ -0,0 +1,169 @@
@@ -0,0 +1,172 @@
+package io.papermc.paper.util;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.AbstractList;
+import java.util.Iterator;
+import java.util.List;
@ -378,6 +369,8 @@ index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276
+import java.util.RandomAccess;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
@ -387,7 +380,10 @@ index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276
+ * @param <F> backing list element type
+ * @param <T> transformed list element type
+ */
+@NullMarked
+@ApiStatus.Internal
+public final class TransformingRandomAccessList<F, T> extends AbstractList<T> implements RandomAccess {
+
+ final List<F> fromList;
+ final Function<? super F, ? extends T> toFunction;
+ final Function<? super T, ? extends F> fromFunction;
@ -395,14 +391,14 @@ index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276
+ /**
+ * Create a new {@link TransformingRandomAccessList}.
+ *
+ * @param fromList backing list
+ * @param toFunction function mapping backing list element type to transformed list element type
+ * @param fromList backing list
+ * @param toFunction function mapping backing list element type to transformed list element type
+ * @param fromFunction function mapping transformed list element type to backing list element type
+ */
+ public TransformingRandomAccessList(
+ final @NonNull List<F> fromList,
+ final @NonNull Function<? super F, ? extends T> toFunction,
+ final @NonNull Function<? super T, ? extends F> fromFunction
+ final List<F> fromList,
+ final Function<? super F, ? extends T> toFunction,
+ final Function<? super T, ? extends F> fromFunction
+ ) {
+ this.fromList = checkNotNull(fromList);
+ this.toFunction = checkNotNull(toFunction);
@ -415,25 +411,25 @@ index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276
+ }
+
+ @Override
+ public T get(int index) {
+ public T get(final int index) {
+ return this.toFunction.apply(this.fromList.get(index));
+ }
+
+ @Override
+ public @NotNull Iterator<T> iterator() {
+ public Iterator<T> iterator() {
+ return this.listIterator();
+ }
+
+ @Override
+ public @NotNull ListIterator<T> listIterator(int index) {
+ return new TransformedListIterator<F, T>(this.fromList.listIterator(index)) {
+ public ListIterator<T> listIterator(final int index) {
+ return new TransformedListIterator<>(this.fromList.listIterator(index)) {
+ @Override
+ T transform(F from) {
+ T transform(final F from) {
+ return TransformingRandomAccessList.this.toFunction.apply(from);
+ }
+
+ @Override
+ F transformBack(T from) {
+ F transformBack(final T from) {
+ return TransformingRandomAccessList.this.fromFunction.apply(from);
+ }
+ };
@ -445,13 +441,13 @@ index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276
+ }
+
+ @Override
+ public boolean removeIf(Predicate<? super T> filter) {
+ public boolean removeIf(final Predicate<? super T> filter) {
+ checkNotNull(filter);
+ return this.fromList.removeIf(element -> filter.test(this.toFunction.apply(element)));
+ }
+
+ @Override
+ public T remove(int index) {
+ public T remove(final int index) {
+ return this.toFunction.apply(this.fromList.remove(index));
+ }
+
@ -461,19 +457,20 @@ index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276
+ }
+
+ @Override
+ public T set(int i, T t) {
+ public T set(final int i, final T t) {
+ return this.toFunction.apply(this.fromList.set(i, this.fromFunction.apply(t)));
+ }
+
+ @Override
+ public void add(int i, T t) {
+ public void add(final int i, final T t) {
+ this.fromList.add(i, this.fromFunction.apply(t));
+ }
+
+ static abstract class TransformedListIterator<F, T> implements ListIterator<T>, Iterator<T> {
+ abstract static class TransformedListIterator<F, T> implements ListIterator<T>, Iterator<T> {
+
+ final Iterator<F> backingIterator;
+
+ TransformedListIterator(ListIterator<F> backingIterator) {
+ TransformedListIterator(final ListIterator<F> backingIterator) {
+ this.backingIterator = checkNotNull((Iterator<F>) backingIterator);
+ }
+
@ -481,7 +478,7 @@ index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276
+ return cast(this.backingIterator);
+ }
+
+ static <A> ListIterator<A> cast(Iterator<A> iterator) {
+ static <A> ListIterator<A> cast(final Iterator<A> iterator) {
+ return (ListIterator<A>) iterator;
+ }
+
@ -506,12 +503,12 @@ index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276
+ }
+
+ @Override
+ public void set(T element) {
+ public void set(final T element) {
+ this.backingIterator().set(this.transformBack(element));
+ }
+
+ @Override
+ public void add(T element) {
+ public void add(final T element) {
+ this.backingIterator().add(this.transformBack(element));
+ }
+
@ -599,7 +596,7 @@ index 270e6d8ad4358baa256cee5f16cff281f063ce3b..6465e290c090d82986352d5ab7ba5dc6
@Override
diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java
index d9091ba1e5a55e03adca98305233cce9d6888609..b82f07a2879412f6b30643ca93a97439aa49a98a 100644
index 7ff939ea41417bad3a436a87c89d5efa7ecefe86..88d5db2995829cba919d78f988d5c735cf70cb1b 100644
--- a/src/test/java/org/bukkit/AnnotationTest.java
+++ b/src/test/java/org/bukkit/AnnotationTest.java
@@ -48,6 +48,8 @@ public class AnnotationTest {

View file

@ -11,20 +11,20 @@ Add a NetworkClient interface that provides access to:
diff --git a/src/main/java/com/destroystokyo/paper/network/NetworkClient.java b/src/main/java/com/destroystokyo/paper/network/NetworkClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b2af1bd72dfbcf4e962a982940fc49b851aa04f
index 0000000000000000000000000000000000000000..c84ce3fc874eea3d8f0b1cf5273996d9b4af6225
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/network/NetworkClient.java
@@ -0,0 +1,41 @@
@@ -0,0 +1,39 @@
+package com.destroystokyo.paper.network;
+
+import java.net.InetSocketAddress;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Represents a client connected to the server.
+ */
+@NullMarked
+public interface NetworkClient {
+
+ /**
@ -32,7 +32,6 @@ index 0000000000000000000000000000000000000000..7b2af1bd72dfbcf4e962a982940fc49b
+ *
+ * @return The client's socket address
+ */
+ @NotNull
+ InetSocketAddress getAddress();
+
+ /**
@ -52,8 +51,7 @@ index 0000000000000000000000000000000000000000..7b2af1bd72dfbcf4e962a982940fc49b
+ *
+ * @return The client's virtual host, or {@code null} if unknown
+ */
+ @Nullable
+ InetSocketAddress getVirtualHost();
+ @Nullable InetSocketAddress getVirtualHost();
+
+}
diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java

View file

@ -7,10 +7,10 @@ Allows plugins to cancel a player picking up an experience orb
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerPickupExperienceEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerPickupExperienceEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ef10ac6bac990837e21520c800d89420a18e3d4
index 0000000000000000000000000000000000000000..0c6ddf0724780245ad01a3b5a5b0e477c25fc62e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerPickupExperienceEvent.java
@@ -0,0 +1,83 @@
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License
+ *
@ -42,20 +42,21 @@ index 0000000000000000000000000000000000000000..0ef10ac6bac990837e21520c800d8942
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a player is attempting to pick up an experience orb
+ */
+@NullMarked
+public class PlayerPickupExperienceEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final ExperienceOrb experienceOrb;
+ private final ExperienceOrb experienceOrb;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerPickupExperienceEvent(@NotNull Player player, @NotNull ExperienceOrb experienceOrb) {
+ public PlayerPickupExperienceEvent(final Player player, final ExperienceOrb experienceOrb) {
+ super(player);
+ this.experienceOrb = experienceOrb;
+ }
@ -63,7 +64,6 @@ index 0000000000000000000000000000000000000000..0ef10ac6bac990837e21520c800d8942
+ /**
+ * @return Returns the Orb that the player is picking up
+ */
+ @NotNull
+ public ExperienceOrb getExperienceOrb() {
+ return this.experienceOrb;
+ }
@ -79,17 +79,15 @@ index 0000000000000000000000000000000000000000..0ef10ac6bac990837e21520c800d8942
+ * If {@code true}, cancels picking up the experience orb, leaving it in the world
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -12,10 +12,10 @@ Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/ExperienceOrbMergeEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/ExperienceOrbMergeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..c520e5517861c4686806df233d1ef5e6bfb76ad3
index 0000000000000000000000000000000000000000..5902e6d6c0516a1249c72b405a49dfc5cc490e0e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/ExperienceOrbMergeEvent.java
@@ -0,0 +1,91 @@
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License
+ *
@ -46,22 +46,23 @@ index 0000000000000000000000000000000000000000..c520e5517861c4686806df233d1ef5e6
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired anytime the server is about to merge 2 experience orbs into one
+ */
+@NullMarked
+public class ExperienceOrbMergeEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final ExperienceOrb mergeTarget;
+ @NotNull private final ExperienceOrb mergeSource;
+ private final ExperienceOrb mergeTarget;
+ private final ExperienceOrb mergeSource;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public ExperienceOrbMergeEvent(@NotNull ExperienceOrb mergeTarget, @NotNull ExperienceOrb mergeSource) {
+ public ExperienceOrbMergeEvent(final ExperienceOrb mergeTarget, final ExperienceOrb mergeSource) {
+ super(mergeTarget);
+ this.mergeTarget = mergeTarget;
+ this.mergeSource = mergeSource;
@ -70,7 +71,6 @@ index 0000000000000000000000000000000000000000..c520e5517861c4686806df233d1ef5e6
+ /**
+ * @return The orb that will absorb the other experience orb
+ */
+ @NotNull
+ public ExperienceOrb getMergeTarget() {
+ return this.mergeTarget;
+ }
@ -78,7 +78,6 @@ index 0000000000000000000000000000000000000000..c520e5517861c4686806df233d1ef5e6
+ /**
+ * @return The orb that is subject to being removed and merged into the target orb
+ */
+ @NotNull
+ public ExperienceOrb getMergeSource() {
+ return this.mergeSource;
+ }
@ -92,17 +91,15 @@ index 0000000000000000000000000000000000000000..c520e5517861c4686806df233d1ef5e6
+ * @param cancel {@code true} if you wish to cancel this event, and prevent the orbs from merging
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -16,10 +16,10 @@ See: https://github.com/PaperMC/Paper/issues/917
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PreCreatureSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PreCreatureSpawnEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..633ef4dcc701916f2dbfefbbebd5994f93ffc2a4
index 0000000000000000000000000000000000000000..c1c96f93a4a5450381cb5bdb198b056a37ba0fbe
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/PreCreatureSpawnEvent.java
@@ -0,0 +1,109 @@
@@ -0,0 +1,105 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.Location;
@ -29,7 +29,7 @@ index 0000000000000000000000000000000000000000..633ef4dcc701916f2dbfefbbebd5994f
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * WARNING: This event only fires for a limited number of cases, and not for every case that {@link CreatureSpawnEvent} does.
@ -41,19 +41,20 @@ index 0000000000000000000000000000000000000000..633ef4dcc701916f2dbfefbbebd5994f
+ * Currently: NATURAL and SPAWNER based reasons. <!-- Please submit a Pull Request for future additions. -->
+ * Also, Plugins that replace Entity Registrations with their own custom entities might not fire this event.
+ */
+@NullMarked
+public class PreCreatureSpawnEvent extends Event implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Location location;
+ @NotNull private final EntityType type;
+ @NotNull private final CreatureSpawnEvent.SpawnReason reason;
+ private final Location location;
+ private final EntityType type;
+ private final CreatureSpawnEvent.SpawnReason reason;
+ private boolean shouldAbortSpawn;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PreCreatureSpawnEvent(@NotNull Location location, @NotNull EntityType type, @NotNull CreatureSpawnEvent.SpawnReason reason) {
+ public PreCreatureSpawnEvent(final Location location, final EntityType type, final CreatureSpawnEvent.SpawnReason reason) {
+ this.location = location;
+ this.type = type;
+ this.reason = reason;
@ -62,7 +63,6 @@ index 0000000000000000000000000000000000000000..633ef4dcc701916f2dbfefbbebd5994f
+ /**
+ * @return The location this creature is being spawned at
+ */
+ @NotNull
+ public Location getSpawnLocation() {
+ return this.location.clone();
+ }
@ -70,7 +70,6 @@ index 0000000000000000000000000000000000000000..633ef4dcc701916f2dbfefbbebd5994f
+ /**
+ * @return The type of creature being spawned
+ */
+ @NotNull
+ public EntityType getType() {
+ return this.type;
+ }
@ -78,7 +77,6 @@ index 0000000000000000000000000000000000000000..633ef4dcc701916f2dbfefbbebd5994f
+ /**
+ * @return Reason this creature is spawning (ie, NATURAL vs SPAWNER)
+ */
+ @NotNull
+ public CreatureSpawnEvent.SpawnReason getReason() {
+ return this.reason;
+ }
@ -96,7 +94,7 @@ index 0000000000000000000000000000000000000000..633ef4dcc701916f2dbfefbbebd5994f
+ *
+ * @param shouldAbortSpawn Set if the spawn process should be aborted vs trying more attempts
+ */
+ public void setShouldAbortSpawn(boolean shouldAbortSpawn) {
+ public void setShouldAbortSpawn(final boolean shouldAbortSpawn) {
+ this.shouldAbortSpawn = shouldAbortSpawn;
+ }
+
@ -114,17 +112,15 @@ index 0000000000000000000000000000000000000000..633ef4dcc701916f2dbfefbbebd5994f
+ * @param cancel {@code true} if you wish to cancel this event, and abort the spawn of this creature
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -10,10 +10,10 @@ Also a highly more effecient way to blanket block spawns in a world
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PlayerNaturallySpawnCreaturesEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PlayerNaturallySpawnCreaturesEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..7fcee73d61347165cefef7b92f0e63e0bed8ad73
index 0000000000000000000000000000000000000000..a3267a283b39e8db1e9b7e5338d2909320f1421c
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/PlayerNaturallySpawnCreaturesEvent.java
@@ -0,0 +1,66 @@
@@ -0,0 +1,65 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Player;
@ -21,11 +21,12 @@ index 0000000000000000000000000000000000000000..7fcee73d61347165cefef7b92f0e63e0
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when the server is calculating what chunks to try to spawn monsters in every Monster Spawn Tick event
+ */
+@NullMarked
+public class PlayerNaturallySpawnCreaturesEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -34,7 +35,7 @@ index 0000000000000000000000000000000000000000..7fcee73d61347165cefef7b92f0e63e0
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerNaturallySpawnCreaturesEvent(@NotNull Player player, byte radius) {
+ public PlayerNaturallySpawnCreaturesEvent(final Player player, final byte radius) {
+ super(player);
+ this.radius = radius;
+ }
@ -49,12 +50,12 @@ index 0000000000000000000000000000000000000000..7fcee73d61347165cefef7b92f0e63e0
+ /**
+ * @param radius The radius of chunks around this player to be included in natural spawn selection
+ */
+ public void setSpawnRadius(byte radius) {
+ public void setSpawnRadius(final byte radius) {
+ this.radius = radius;
+ }
+
+ /**
+ * @return If this players chunks will be excluded from natural spawns
+ * @return If this player's chunks will be excluded from natural spawns
+ */
+ @Override
+ public boolean isCancelled() {
@ -62,20 +63,18 @@ index 0000000000000000000000000000000000000000..7fcee73d61347165cefef7b92f0e63e0
+ }
+
+ /**
+ * @param cancel {@code true} if you wish to cancel this event, and not include this players chunks for natural spawning
+ * @param cancel {@code true} if you wish to cancel this event, and not include this player's chunks for natural spawning
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -7,10 +7,10 @@ Co-authored-by: The456gamer <the456gamer@the456gamer.dev>
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerAdvancementCriterionGrantEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerAdvancementCriterionGrantEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..9502f94b3567fc22c4b61fea5aa251d738dde7ae
index 0000000000000000000000000000000000000000..0fb316e34ec9728610237a08f37fffb61fd5afa8
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerAdvancementCriterionGrantEvent.java
@@ -0,0 +1,84 @@
@@ -0,0 +1,80 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.advancement.Advancement;
@ -20,24 +20,25 @@ index 0000000000000000000000000000000000000000..9502f94b3567fc22c4b61fea5aa251d7
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called after a player is granted a criteria in an advancement.
+ * If cancelled the criteria will be revoked.
+ */
+@NullMarked
+public class PlayerAdvancementCriterionGrantEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Advancement advancement;
+ @NotNull private final String criterion;
+ @NotNull private final AdvancementProgress advancementProgress;
+ private final Advancement advancement;
+ private final String criterion;
+ private final AdvancementProgress advancementProgress;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerAdvancementCriterionGrantEvent(@NotNull Player player, @NotNull Advancement advancement, @NotNull String criterion) {
+ public PlayerAdvancementCriterionGrantEvent(final Player player, final Advancement advancement, final String criterion) {
+ super(player);
+ this.advancement = advancement;
+ this.criterion = criterion;
@ -49,7 +50,6 @@ index 0000000000000000000000000000000000000000..9502f94b3567fc22c4b61fea5aa251d7
+ *
+ * @return affected advancement
+ */
+ @NotNull
+ public Advancement getAdvancement() {
+ return this.advancement;
+ }
@ -59,7 +59,6 @@ index 0000000000000000000000000000000000000000..9502f94b3567fc22c4b61fea5aa251d7
+ *
+ * @return granted criterion
+ */
+ @NotNull
+ public String getCriterion() {
+ return this.criterion;
+ }
@ -69,7 +68,6 @@ index 0000000000000000000000000000000000000000..9502f94b3567fc22c4b61fea5aa251d7
+ *
+ * @return advancement progress
+ */
+ @NotNull
+ public AdvancementProgress getAdvancementProgress() {
+ return this.advancementProgress;
+ }
@ -80,17 +78,15 @@ index 0000000000000000000000000000000000000000..9502f94b3567fc22c4b61fea5aa251d7
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -12,10 +12,10 @@ This is useful for implementing a ProfileCache for Player Skulls
diff --git a/src/main/java/com/destroystokyo/paper/event/profile/FillProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/FillProfileEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..c97ded9f9ef1c550cca7d0a3a3b09a85e5999cdf
index 0000000000000000000000000000000000000000..8625d60eb822f39140152f2f74ec5bfe5ecd0039
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/profile/FillProfileEvent.java
@@ -0,0 +1,79 @@
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
+ *
@ -43,24 +43,24 @@ index 0000000000000000000000000000000000000000..c97ded9f9ef1c550cca7d0a3a3b09a85
+
+import com.destroystokyo.paper.profile.PlayerProfile;
+import com.destroystokyo.paper.profile.ProfileProperty;
+import java.util.Set;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+import java.util.Set;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired once a profiles additional properties (such as textures) has been filled
+ */
+@NullMarked
+public class FillProfileEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final PlayerProfile profile;
+ private final PlayerProfile profile;
+
+ @ApiStatus.Internal
+ public FillProfileEvent(@NotNull PlayerProfile profile) {
+ public FillProfileEvent(final PlayerProfile profile) {
+ super(!org.bukkit.Bukkit.isPrimaryThread());
+ this.profile = profile;
+ }
@ -68,7 +68,6 @@ index 0000000000000000000000000000000000000000..c97ded9f9ef1c550cca7d0a3a3b09a85
+ /**
+ * @return The Profile that had properties filled
+ */
+ @NotNull
+ public PlayerProfile getPlayerProfile() {
+ return this.profile;
+ }
@ -76,31 +75,28 @@ index 0000000000000000000000000000000000000000..c97ded9f9ef1c550cca7d0a3a3b09a85
+ /**
+ * Same as .getPlayerProfile().getProperties()
+ *
+ * @see PlayerProfile#getProperties()
+ * @return The new properties on the profile.
+ * @see PlayerProfile#getProperties()
+ */
+ @NotNull
+ public Set<ProfileProperty> getProperties() {
+ return this.profile.getProperties();
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/profile/PreFillProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/PreFillProfileEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..e2a47c4af2c368a361e4a370a01111abe8e48062
index 0000000000000000000000000000000000000000..177c23274d6dad709b05706117303b70ae8b4c7b
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/profile/PreFillProfileEvent.java
@@ -0,0 +1,81 @@
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
+ *
@ -128,26 +124,26 @@ index 0000000000000000000000000000000000000000..e2a47c4af2c368a361e4a370a01111ab
+
+import com.destroystokyo.paper.profile.PlayerProfile;
+import com.destroystokyo.paper.profile.ProfileProperty;
+import java.util.Collection;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+import java.util.Collection;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when the server is requesting to fill in properties of an incomplete profile, such as textures.
+ * <p>
+ * Allows plugins to pre-populate cached properties and avoid a call to the Mojang API
+ */
+@NullMarked
+public class PreFillProfileEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final PlayerProfile profile;
+ private final PlayerProfile profile;
+
+ @ApiStatus.Internal
+ public PreFillProfileEvent(@NotNull PlayerProfile profile) {
+ public PreFillProfileEvent(final PlayerProfile profile) {
+ super(!org.bukkit.Bukkit.isPrimaryThread());
+ this.profile = profile;
+ }
@ -155,7 +151,6 @@ index 0000000000000000000000000000000000000000..e2a47c4af2c368a361e4a370a01111ab
+ /**
+ * @return The profile that needs its properties filled
+ */
+ @NotNull
+ public PlayerProfile getPlayerProfile() {
+ return this.profile;
+ }
@ -163,21 +158,19 @@ index 0000000000000000000000000000000000000000..e2a47c4af2c368a361e4a370a01111ab
+ /**
+ * Sets the properties on the profile, avoiding the call to the Mojang API
+ * Same as .getPlayerProfile().setProperties(properties);
+ *
+ * @see PlayerProfile#setProperties(Collection)
+ *
+ * @param properties The properties to set/append
+ * @see PlayerProfile#setProperties(Collection)
+ */
+ public void setProperties(@NotNull Collection<ProfileProperty> properties) {
+ public void setProperties(final Collection<ProfileProperty> properties) {
+ this.profile.setProperties(properties);
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -8,7 +8,7 @@ client that does not support all of the features provided in the
event.
diff --git a/src/main/java/com/destroystokyo/paper/network/StatusClient.java b/src/main/java/com/destroystokyo/paper/network/StatusClient.java
index 517d15238ed117f38bbd39f570874014cecf7bb5..ffda9f6a8b094942009aa78b331d22d9dcca2802 100644
index 517d15238ed117f38bbd39f570874014cecf7bb5..a8437bbd80b3a20772352a3b1797990ea13806ad 100644
--- a/src/main/java/com/destroystokyo/paper/network/StatusClient.java
+++ b/src/main/java/com/destroystokyo/paper/network/StatusClient.java
@@ -10,4 +10,16 @@ import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
@ -17,7 +17,7 @@ index 517d15238ed117f38bbd39f570874014cecf7bb5..ffda9f6a8b094942009aa78b331d22d9
+ /**
+ * Returns whether the client is using an older version that doesn't
+ * support all of the features in {@link PaperServerListPingEvent}.
+ * support all the features in {@link PaperServerListPingEvent}.
+ *
+ * <p>For Vanilla, this returns {@code true} for all clients older than 1.7.</p>
+ *

View file

@ -9,10 +9,10 @@ You may cancel this, enabling ranged attacks to damage the enderman for example.
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6be848c44d5efaca3fbc03c3be7451411943c24
index 0000000000000000000000000000000000000000..ae72916972dbe86bfbca499eb7b6f97b1a6eae25
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java
@@ -0,0 +1,86 @@
@@ -0,0 +1,83 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Enderman;
@ -20,22 +20,22 @@ index 0000000000000000000000000000000000000000..f6be848c44d5efaca3fbc03c3be74514
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public class EndermanEscapeEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Reason reason;
+ private final Reason reason;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EndermanEscapeEvent(@NotNull Enderman entity, @NotNull Reason reason) {
+ public EndermanEscapeEvent(final Enderman entity, final Reason reason) {
+ super(entity);
+ this.reason = reason;
+ }
+
+ @NotNull
+ @Override
+ public Enderman getEntity() {
+ return (Enderman) super.getEntity();
@ -44,7 +44,6 @@ index 0000000000000000000000000000000000000000..f6be848c44d5efaca3fbc03c3be74514
+ /**
+ * @return The reason the enderman is trying to escape
+ */
+ @NotNull
+ public Reason getReason() {
+ return this.reason;
+ }
@ -57,21 +56,19 @@ index 0000000000000000000000000000000000000000..f6be848c44d5efaca3fbc03c3be74514
+ /**
+ * Cancels the escape.
+ * <p>
+ * If this escape normally would of resulted in damage avoidance such as indirect,
+ * If this escape normally had resulted in damage avoidance such as indirect,
+ * the enderman will now take damage.
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -10,46 +10,45 @@ This adds a new Builder API which is much friendlier to use.
diff --git a/src/main/java/com/destroystokyo/paper/ParticleBuilder.java b/src/main/java/com/destroystokyo/paper/ParticleBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c769aca67e
index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a7191206f3ff
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/ParticleBuilder.java
@@ -0,0 +1,609 @@
@@ -0,0 +1,582 @@
+package com.destroystokyo.paper;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.bukkit.Color;
+import org.bukkit.Location;
+import org.bukkit.Particle;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.bukkit.util.NumberConversions;
+
+import java.util.Collection;
+import java.util.List;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Helps prepare a particle to be sent to players.
+ *
+ * <p>
+ * Usage of the builder is preferred over the super long {@link World#spawnParticle(Particle, Location, int, double, double, double, double, Object)} API
+ */
+@NullMarked
+public class ParticleBuilder implements Cloneable {
+
+ private Particle particle;
+ private List<Player> receivers;
+ private Player source;
+ private Location location;
+ private @Nullable List<Player> receivers;
+ private @Nullable Player source;
+ private @Nullable Location location;
+ private int count = 1;
+ private double offsetX = 0, offsetY = 0, offsetZ = 0;
+ private double extra = 1;
+ private Object data;
+ private @Nullable Object data;
+ private boolean force = true;
+
+ public ParticleBuilder(@NotNull Particle particle) {
+ public ParticleBuilder(final Particle particle) {
+ this.particle = particle;
+ }
+
@ -59,14 +58,14 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ *
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder spawn() {
+ if (this.location == null) {
+ throw new IllegalStateException("Please specify location for this particle");
+ }
+ location.getWorld().spawnParticle(particle, receivers, source,
+ location.getX(), location.getY(), location.getZ(),
+ count, offsetX, offsetY, offsetZ, extra, data, force
+ this.location.getWorld().spawnParticle(
+ this.particle, this.receivers, this.source,
+ this.location.getX(), this.location.getY(), this.location.getZ(),
+ this.count, this.offsetX, this.offsetY, this.offsetZ, this.extra, this.data, this.force
+ );
+ return this;
+ }
@ -74,9 +73,8 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ /**
+ * @return The particle going to be sent
+ */
+ @NotNull
+ public Particle particle() {
+ return particle;
+ return this.particle;
+ }
+
+ /**
@ -85,8 +83,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param particle The particle
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder particle(@NotNull Particle particle) {
+ public ParticleBuilder particle(final Particle particle) {
+ this.particle = particle;
+ return this;
+ }
@ -94,32 +91,30 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ /**
+ * @return List of players who will receive the particle, or null for all in world
+ */
+ @Nullable
+ public List<Player> receivers() {
+ return receivers;
+ public @Nullable List<Player> receivers() {
+ return this.receivers;
+ }
+
+ /**
+ * Example use:
+ *
+ * <p>
+ * builder.receivers(16); if (builder.hasReceivers()) { sendParticleAsync(builder); }
+ *
+ * @return If this particle is going to be sent to someone
+ */
+ public boolean hasReceivers() {
+ return (receivers == null && !location.getWorld().getPlayers().isEmpty()) || (
+ receivers != null && !receivers.isEmpty());
+ return (this.receivers == null && this.location != null && !this.location.getWorld().getPlayers().isEmpty()) || (
+ this.receivers != null && !this.receivers.isEmpty());
+ }
+
+ /**
+ * Sends this particle to all players in the world. This is rather silly and you should likely not
+ * Sends this particle to all players in the world. This is rather silly, and you should likely not
+ * be doing this.
+ *
+ * <p>
+ * Just be a logical person and use receivers by radius or collection.
+ *
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder allPlayers() {
+ this.receivers = null;
+ return this;
@ -127,11 +122,10 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+
+ /**
+ * @param receivers List of players to receive this particle, or null for all players in the
+ * world
+ * world
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder receivers(@Nullable List<Player> receivers) {
+ public ParticleBuilder receivers(final @Nullable List<Player> receivers) {
+ // Had to keep this as we first made API List<> and not Collection, but removing this may break plugins compiled on older jars
+ // TODO: deprecate?
+ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null;
@ -140,22 +134,20 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+
+ /**
+ * @param receivers List of players to receive this particle, or null for all players in the
+ * world
+ * world
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder receivers(@Nullable Collection<Player> receivers) {
+ public ParticleBuilder receivers(final @Nullable Collection<Player> receivers) {
+ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null;
+ return this;
+ }
+
+ /**
+ * @param receivers List of players to be receive this particle, or null for all players in the
+ * world
+ * @param receivers List of players to receive this particle, or null for all players in the
+ * world
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder receivers(@Nullable Player... receivers) {
+ public ParticleBuilder receivers(final Player @Nullable... receivers) {
+ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null;
+ return this;
+ }
@ -168,9 +160,8 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param radius amount to add on all axis
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder receivers(int radius) {
+ return receivers(radius, radius);
+ public ParticleBuilder receivers(final int radius) {
+ return this.receivers(radius, radius);
+ }
+
+ /**
@ -178,22 +169,24 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * false, behavior uses cuboid selection the same as {@link #receivers(int, int)} If byDistance is
+ * true, radius is tested by distance in a spherical shape
+ *
+ * @param radius amount to add on each axis
+ * @param radius amount to add on each axis
+ * @param byDistance true to use a spherical radius, false to use a cuboid
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder receivers(int radius, boolean byDistance) {
+ public ParticleBuilder receivers(final int radius, final boolean byDistance) {
+ if (!byDistance) {
+ return receivers(radius, radius, radius);
+ return this.receivers(radius, radius, radius);
+ } else {
+ if (this.location == null) {
+ throw new IllegalStateException("Please set location first");
+ }
+ this.receivers = Lists.newArrayList();
+ for (Player nearbyPlayer : location.getWorld()
+ .getNearbyPlayers(location, radius, radius, radius)) {
+ Location loc = nearbyPlayer.getLocation();
+ double x = NumberConversions.square(location.getX() - loc.getX());
+ double y = NumberConversions.square(location.getY() - loc.getY());
+ double z = NumberConversions.square(location.getZ() - loc.getZ());
+ for (final Player nearbyPlayer : this.location.getWorld()
+ .getNearbyPlayers(this.location, radius, radius, radius)) {
+ final Location loc = nearbyPlayer.getLocation();
+ final double x = NumberConversions.square(this.location.getX() - loc.getX());
+ final double y = NumberConversions.square(this.location.getY() - loc.getY());
+ final double z = NumberConversions.square(this.location.getZ() - loc.getZ());
+ if (Math.sqrt(x + y + z) > radius) {
+ continue;
+ }
@ -210,12 +203,11 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * see {@link #receivers(int, boolean)}
+ *
+ * @param xzRadius amount to add on the x/z axis
+ * @param yRadius amount to add on the y axis
+ * @param yRadius amount to add on the y axis
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder receivers(int xzRadius, int yRadius) {
+ return receivers(xzRadius, yRadius, xzRadius);
+ public ParticleBuilder receivers(final int xzRadius, final int yRadius) {
+ return this.receivers(xzRadius, yRadius, xzRadius);
+ }
+
+ /**
@ -223,25 +215,28 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * false, behavior uses cuboid selection the same as {@link #receivers(int, int)} If byDistance is
+ * true, radius is tested by distance on the y plane and on the x/z plane, in a cylinder shape.
+ *
+ * @param xzRadius amount to add on the x/z axis
+ * @param yRadius amount to add on the y axis
+ * @param xzRadius amount to add on the x/z axis
+ * @param yRadius amount to add on the y axis
+ * @param byDistance true to use a cylinder shape, false to use cuboid
+ * @return a reference to this object.
+ * @throws IllegalStateException if a location hasn't been specified yet
+ */
+ @NotNull
+ public ParticleBuilder receivers(int xzRadius, int yRadius, boolean byDistance) {
+ public ParticleBuilder receivers(final int xzRadius, final int yRadius, final boolean byDistance) {
+ if (!byDistance) {
+ return receivers(xzRadius, yRadius, xzRadius);
+ return this.receivers(xzRadius, yRadius, xzRadius);
+ } else {
+ if (this.location == null) {
+ throw new IllegalStateException("Please set location first");
+ }
+ this.receivers = Lists.newArrayList();
+ for (Player nearbyPlayer : location.getWorld()
+ .getNearbyPlayers(location, xzRadius, yRadius, xzRadius)) {
+ Location loc = nearbyPlayer.getLocation();
+ for (final Player nearbyPlayer : this.location.getWorld()
+ .getNearbyPlayers(this.location, xzRadius, yRadius, xzRadius)) {
+ final Location loc = nearbyPlayer.getLocation();
+ if (Math.abs(loc.getY() - this.location.getY()) > yRadius) {
+ continue;
+ }
+ double x = NumberConversions.square(location.getX() - loc.getX());
+ double z = NumberConversions.square(location.getZ() - loc.getZ());
+ final double x = NumberConversions.square(this.location.getX() - loc.getX());
+ final double z = NumberConversions.square(this.location.getZ() - loc.getZ());
+ if (x + z > NumberConversions.square(xzRadius)) {
+ continue;
+ }
@ -261,20 +256,18 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param zRadius amount to add on the z axis
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder receivers(int xRadius, int yRadius, int zRadius) {
+ if (location == null) {
+ public ParticleBuilder receivers(final int xRadius, final int yRadius, final int zRadius) {
+ if (this.location == null) {
+ throw new IllegalStateException("Please set location first");
+ }
+ return receivers(location.getWorld().getNearbyPlayers(location, xRadius, yRadius, zRadius));
+ return this.receivers(this.location.getWorld().getNearbyPlayers(this.location, xRadius, yRadius, zRadius));
+ }
+
+ /**
+ * @return The player considered the source of this particle (for Visibility concerns), or null
+ */
+ @Nullable
+ public Player source() {
+ return source;
+ public @Nullable Player source() {
+ return this.source;
+ }
+
+ /**
@ -283,8 +276,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param source The player who is considered the source
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder source(@Nullable Player source) {
+ public ParticleBuilder source(final @Nullable Player source) {
+ this.source = source;
+ return this;
+ }
@ -292,9 +284,8 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ /**
+ * @return Location of where the particle will spawn
+ */
+ @Nullable
+ public Location location() {
+ return location;
+ public @Nullable Location location() {
+ return this.location;
+ }
+
+ /**
@ -303,8 +294,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param location The location of the particle
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder location(@NotNull Location location) {
+ public ParticleBuilder location(final Location location) {
+ this.location = location.clone();
+ return this;
+ }
@ -313,13 +303,12 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * Sets the location of where to spawn the particle
+ *
+ * @param world World to spawn particle in
+ * @param x X location
+ * @param y Y location
+ * @param z Z location
+ * @param x X location
+ * @param y Y location
+ * @param z Z location
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder location(@NotNull World world, double x, double y, double z) {
+ public ParticleBuilder location(final World world, final double x, final double y, final double z) {
+ this.location = new Location(world, x, y, z);
+ return this;
+ }
@ -328,7 +317,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @return Number of particles to spawn
+ */
+ public int count() {
+ return count;
+ return this.count;
+ }
+
+ /**
@ -337,8 +326,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param count Number of particles
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder count(int count) {
+ public ParticleBuilder count(final int count) {
+ this.count = count;
+ return this;
+ }
@ -349,7 +337,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @return Particle offset X.
+ */
+ public double offsetX() {
+ return offsetX;
+ return this.offsetX;
+ }
+
+ /**
@ -358,7 +346,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @return Particle offset Y.
+ */
+ public double offsetY() {
+ return offsetY;
+ return this.offsetY;
+ }
+
+ /**
@ -367,7 +355,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @return Particle offset Z.
+ */
+ public double offsetZ() {
+ return offsetZ;
+ return this.offsetZ;
+ }
+
+ /**
@ -378,8 +366,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param offsetZ Particle offset Z
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder offset(double offsetX, double offsetY, double offsetZ) {
+ public ParticleBuilder offset(final double offsetX, final double offsetY, final double offsetZ) {
+ this.offsetX = offsetX;
+ this.offsetY = offsetY;
+ this.offsetZ = offsetZ;
@ -392,7 +379,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @return the extra particle data
+ */
+ public double extra() {
+ return extra;
+ return this.extra;
+ }
+
+ /**
@ -401,8 +388,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param extra the extra particle data
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder extra(double extra) {
+ public ParticleBuilder extra(final double extra) {
+ this.extra = extra;
+ return this;
+ }
@ -413,21 +399,19 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param <T> The Particle data type
+ * @return the ParticleData for this particle
+ */
+ @Nullable
+ public <T> T data() {
+ public @Nullable <T> T data() {
+ //noinspection unchecked
+ return (T) data;
+ return (T) this.data;
+ }
+
+ /**
+ * Sets the particle custom data. Varies by particle on how this is used
+ *
+ * @param data The new particle data
+ * @param <T> The Particle data type
+ * @param <T> The Particle data type
+ * @return a reference to this object.
+ */
+ @NotNull
+ public <T> ParticleBuilder data(@Nullable T data) {
+ public <T> ParticleBuilder data(final @Nullable T data) {
+ this.data = data;
+ return this;
+ }
@ -436,7 +420,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @return whether the particle is forcefully shown to players.
+ */
+ public boolean force() {
+ return force;
+ return this.force;
+ }
+
+ /**
@ -447,8 +431,7 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param force true to force, false for normal
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder force(boolean force) {
+ public ParticleBuilder force(final boolean force) {
+ this.force = force;
+ return this;
+ }
@ -460,12 +443,11 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param color the new particle color
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder color(@Nullable Color color) {
+ if (particle.getDataType() == Color.class) {
+ return data(color);
+ public ParticleBuilder color(final @Nullable Color color) {
+ if (this.particle.getDataType() == Color.class) {
+ return this.data(color);
+ }
+ return color(color, 1);
+ return this.color(color, 1);
+ }
+
+ /**
@ -473,25 +455,24 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * Only valid for particles with a data type of {@link Particle.DustOptions}.
+ *
+ * @param color the new particle color
+ * @param size the size of the particle
+ * @param size the size of the particle
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder color(@Nullable Color color, float size) {
+ if (particle.getDataType() != Particle.DustOptions.class && color != null) {
+ public ParticleBuilder color(final @Nullable Color color, final float size) {
+ if (this.particle.getDataType() != Particle.DustOptions.class && color != null) {
+ throw new IllegalStateException("The combination of Color and size cannot be set on this particle type.");
+ }
+
+ // We don't officially support reusing these objects, but here we go
+ if (color == null) {
+ if (data instanceof Particle.DustOptions) {
+ return data(null);
+ if (this.data instanceof Particle.DustOptions) {
+ return this.data(null);
+ } else {
+ return this;
+ }
+ }
+
+ return data(new Particle.DustOptions(color, size));
+ return this.data(new Particle.DustOptions(color, size));
+ }
+
+ /**
@ -503,9 +484,8 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param b blue color component
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder color(int r, int g, int b) {
+ return color(Color.fromRGB(r, g, b));
+ public ParticleBuilder color(final int r, final int g, final int b) {
+ return this.color(Color.fromRGB(r, g, b));
+ }
+
+ /**
@ -519,13 +499,12 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * the color is treated as RGB. Otherwise, it is treated as ARGB.
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder color(final int color) {
+ int alpha = (color >> 24) & 0xFF;
+ final int alpha = (color >> 24) & 0xFF;
+ if (alpha == 0) {
+ return color(Color.fromRGB(color));
+ return this.color(Color.fromRGB(color));
+ }
+ return color(Color.fromARGB(color));
+ return this.color(Color.fromARGB(color));
+ }
+
+ /**
@ -538,9 +517,8 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * @param b blue color component
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder color(final int a, final int r, final int g, final int b) {
+ return color(Color.fromARGB(a, r, g, b));
+ return this.color(Color.fromARGB(a, r, g, b));
+ }
+
+ /**
@ -548,69 +526,64 @@ index 0000000000000000000000000000000000000000..970084a788ab5547d16a5e08d4e9d9c7
+ * Only valid for {@link Particle#DUST_COLOR_TRANSITION}.
+ *
+ * @param fromColor the new particle from color
+ * @param toColor the new particle to color
+ * @param toColor the new particle to color
+ * @return a reference to this object.
+ * @throws IllegalArgumentException if the particle builder's {@link #particle()} isn't {@link Particle#DUST_COLOR_TRANSITION}.
+ */
+ @NotNull
+ public ParticleBuilder colorTransition(@NotNull final Color fromColor, @NotNull final Color toColor) {
+ return colorTransition(fromColor, toColor, 1);
+ public ParticleBuilder colorTransition(final Color fromColor, final Color toColor) {
+ return this.colorTransition(fromColor, toColor, 1);
+ }
+
+ /**
+ * Sets the particle Color Transition.
+ * Only valid for {@link Particle#DUST_COLOR_TRANSITION}.
+ *
+ * @param fromRed red color component for the from color
+ * @param fromGreen green color component for the from color
+ * @param fromBlue blue color component for the from color
+ * @param toRed red color component for the to color
+ * @param toGreen green color component for the to color
+ * @param toBlue blue color component for the to color
+ * @param fromRed red color component for the "from" color
+ * @param fromGreen green color component for the "from" color
+ * @param fromBlue blue color component for the "from" color
+ * @param toRed red color component for the to color
+ * @param toGreen green color component for the to color
+ * @param toBlue blue color component for the to color
+ * @return a reference to this object.
+ * @throws IllegalArgumentException if the particle builder's {@link #particle()} isn't {@link Particle#DUST_COLOR_TRANSITION}.
+ */
+ @NotNull
+ public ParticleBuilder colorTransition(final int fromRed, final int fromGreen, final int fromBlue,
+ final int toRed, final int toGreen, final int toBlue) {
+ return colorTransition(Color.fromRGB(fromRed, fromGreen, fromBlue), Color.fromRGB(toRed, toGreen, toBlue));
+ public ParticleBuilder colorTransition(
+ final int fromRed, final int fromGreen, final int fromBlue,
+ final int toRed, final int toGreen, final int toBlue
+ ) {
+ return this.colorTransition(Color.fromRGB(fromRed, fromGreen, fromBlue), Color.fromRGB(toRed, toGreen, toBlue));
+ }
+
+ /**
+ * Sets the particle Color Transition.
+ * Only valid for {@link Particle#DUST_COLOR_TRANSITION}.
+ *
+ * @param fromRgb an integer representing the red, green, and blue color components for the from color
+ * @param toRgb an integer representing the red, green, and blue color components for the to color
+ * @param fromRgb an integer representing the red, green, and blue color components for the "from" color
+ * @param toRgb an integer representing the red, green, and blue color components for the "to" color
+ * @return a reference to this object.
+ * @throws IllegalArgumentException if the particle builder's {@link #particle()} isn't {@link Particle#DUST_COLOR_TRANSITION}.
+ */
+ @NotNull
+ public ParticleBuilder colorTransition(final int fromRgb, final int toRgb) {
+ return colorTransition(Color.fromRGB(fromRgb), Color.fromRGB(toRgb));
+ return this.colorTransition(Color.fromRGB(fromRgb), Color.fromRGB(toRgb));
+ }
+
+ /**
+ * Sets the particle Color Transition and size.
+ * Only valid for {@link Particle#DUST_COLOR_TRANSITION}.
+ *
+ * @param fromColor the new particle color for the from color.
+ * @param toColor the new particle color for the to color.
+ * @param size the size of the particle
+ * @param fromColor the new particle color for the "from" color.
+ * @param toColor the new particle color for the "to" color.
+ * @param size the size of the particle
+ * @return a reference to this object.
+ * @throws IllegalArgumentException if the particle builder's {@link #particle()} isn't {@link Particle#DUST_COLOR_TRANSITION}.
+ */
+ @NotNull
+ public ParticleBuilder colorTransition(@NotNull final Color fromColor,
+ @NotNull final Color toColor,
+ final float size) {
+ public ParticleBuilder colorTransition(final Color fromColor, final Color toColor, final float size) {
+ Preconditions.checkArgument(fromColor != null, "Cannot define color transition with null fromColor.");
+ Preconditions.checkArgument(toColor != null, "Cannot define color transition with null toColor.");
+ Preconditions.checkArgument(this.particle() == Particle.DUST_COLOR_TRANSITION, "Can only define a color transition on particle DUST_COLOR_TRANSITION.");
+ return data(new Particle.DustTransition(fromColor, toColor, size));
+ return this.data(new Particle.DustTransition(fromColor, toColor, size));
+ }
+
+ @NotNull
+ @Override
+ public ParticleBuilder clone() {
+ try {

View file

@ -9,10 +9,10 @@ This allows you to override/extend the pumpkin/stare logic.
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae34e679723a2ef436da04c116038272743a8f35
index 0000000000000000000000000000000000000000..34adc77de2d1f06b2b10cc26b60240c6a3ef259c
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java
@@ -0,0 +1,101 @@
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
+ *
@ -44,7 +44,7 @@ index 0000000000000000000000000000000000000000..ae34e679723a2ef436da04c116038272
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when an Enderman determines if it should attack a player or not.
@ -52,15 +52,16 @@ index 0000000000000000000000000000000000000000..ae34e679723a2ef436da04c116038272
+ * Starts off cancelled if the player is wearing a pumpkin head or is not looking
+ * at the Enderman, according to Vanilla rules.
+ */
+@NullMarked
+public class EndermanAttackPlayerEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Player player;
+ private final Player player;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EndermanAttackPlayerEvent(@NotNull Enderman entity, @NotNull Player player) {
+ public EndermanAttackPlayerEvent(final Enderman entity, final Player player) {
+ super(entity);
+ this.player = player;
+ }
@ -70,7 +71,6 @@ index 0000000000000000000000000000000000000000..ae34e679723a2ef436da04c116038272
+ *
+ * @return The enderman considering attacking
+ */
+ @NotNull
+ @Override
+ public Enderman getEntity() {
+ return (Enderman) super.getEntity();
@ -81,7 +81,6 @@ index 0000000000000000000000000000000000000000..ae34e679723a2ef436da04c116038272
+ *
+ * @return The player the Enderman is considering attacking
+ */
+ @NotNull
+ public Player getPlayer() {
+ return this.player;
+ }
@ -100,16 +99,15 @@ index 0000000000000000000000000000000000000000..ae34e679723a2ef436da04c116038272
+ * Cancels if the Enderman will attack this player
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -7,10 +7,10 @@ Fires when a witch consumes the potion in their hand
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchConsumePotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchConsumePotionEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..773079aa92280bb97e9b4c0e62d9ead08135610a
index 0000000000000000000000000000000000000000..43ee765dedf5001fadf1af317b6ab323fde34851
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchConsumePotionEvent.java
@@ -0,0 +1,73 @@
@@ -0,0 +1,71 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Witch;
@ -19,26 +19,26 @@ index 0000000000000000000000000000000000000000..773079aa92280bb97e9b4c0e62d9ead0
+import org.bukkit.event.entity.EntityEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Fired when a witch consumes the potion in their hand to buff themselves.
+ */
+@NullMarked
+public class WitchConsumePotionEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @Nullable private ItemStack potion;
+ private @Nullable ItemStack potion;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public WitchConsumePotionEvent(@NotNull Witch witch, @Nullable ItemStack potion) {
+ public WitchConsumePotionEvent(final Witch witch, final @Nullable ItemStack potion) {
+ super(witch);
+ this.potion = potion;
+ }
+
+ @NotNull
+ @Override
+ public Witch getEntity() {
+ return (Witch) super.getEntity();
@ -47,8 +47,7 @@ index 0000000000000000000000000000000000000000..773079aa92280bb97e9b4c0e62d9ead0
+ /**
+ * @return the potion the witch will consume and have the effects applied.
+ */
+ @Nullable
+ public ItemStack getPotion() {
+ public @Nullable ItemStack getPotion() {
+ return this.potion;
+ }
+
@ -57,7 +56,7 @@ index 0000000000000000000000000000000000000000..773079aa92280bb97e9b4c0e62d9ead0
+ *
+ * @param potion The potion
+ */
+ public void setPotion(@Nullable ItemStack potion) {
+ public void setPotion(final @Nullable ItemStack potion) {
+ this.potion = potion != null ? potion.clone() : null;
+ }
+
@ -70,16 +69,15 @@ index 0000000000000000000000000000000000000000..773079aa92280bb97e9b4c0e62d9ead0
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -7,10 +7,10 @@ Fired when a witch throws a potion at a player
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..f1d546a3576a170ecb3608e07befa0f621ea043a
index 0000000000000000000000000000000000000000..02395582b680f4baa3dc2251a8a79f41241b96ec
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java
@@ -0,0 +1,85 @@
@@ -0,0 +1,81 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.LivingEntity;
@ -20,28 +20,28 @@ index 0000000000000000000000000000000000000000..f1d546a3576a170ecb3608e07befa0f6
+import org.bukkit.event.entity.EntityEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Fired when a witch throws a potion at a player
+ */
+@NullMarked
+public class WitchThrowPotionEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final LivingEntity target;
+ @Nullable private ItemStack potion;
+ private final LivingEntity target;
+ private @Nullable ItemStack potion;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public WitchThrowPotionEvent(@NotNull Witch witch, @NotNull LivingEntity target, @Nullable ItemStack potion) {
+ public WitchThrowPotionEvent(final Witch witch, final LivingEntity target, final @Nullable ItemStack potion) {
+ super(witch);
+ this.target = target;
+ this.potion = potion;
+ }
+
+ @NotNull
+ @Override
+ public Witch getEntity() {
+ return (Witch) super.getEntity();
@ -50,7 +50,6 @@ index 0000000000000000000000000000000000000000..f1d546a3576a170ecb3608e07befa0f6
+ /**
+ * @return The target of the potion
+ */
+ @NotNull
+ public LivingEntity getTarget() {
+ return this.target;
+ }
@ -58,8 +57,7 @@ index 0000000000000000000000000000000000000000..f1d546a3576a170ecb3608e07befa0f6
+ /**
+ * @return The potion the witch will throw at a player
+ */
+ @Nullable
+ public ItemStack getPotion() {
+ public @Nullable ItemStack getPotion() {
+ return this.potion;
+ }
+
@ -68,7 +66,7 @@ index 0000000000000000000000000000000000000000..f1d546a3576a170ecb3608e07befa0f6
+ *
+ * @param potion The potion
+ */
+ public void setPotion(@Nullable ItemStack potion) {
+ public void setPotion(final @Nullable ItemStack potion) {
+ this.potion = potion != null ? potion.clone() : null;
+ }
+
@ -81,17 +79,15 @@ index 0000000000000000000000000000000000000000..f1d546a3576a170ecb3608e07befa0f6
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -7,10 +7,10 @@ Control what potion the witch readies to use
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..7feca06e72bd585bbfa219df38a2161b77e8d4c4
index 0000000000000000000000000000000000000000..bda48563cc9e00bd9a537ddec0c730b5e784c9a4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java
@@ -0,0 +1,68 @@
@@ -0,0 +1,65 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Witch;
@ -19,23 +19,23 @@ index 0000000000000000000000000000000000000000..7feca06e72bd585bbfa219df38a2161b
+import org.bukkit.event.entity.EntityEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+@NullMarked
+public class WitchReadyPotionEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private ItemStack potion;
+ private @Nullable ItemStack potion;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public WitchReadyPotionEvent(@NotNull Witch witch, @Nullable ItemStack potion) {
+ public WitchReadyPotionEvent(final Witch witch, final @Nullable ItemStack potion) {
+ super(witch);
+ this.potion = potion;
+ }
+
+ @NotNull
+ @Override
+ public Witch getEntity() {
+ return (Witch) super.getEntity();
@ -44,8 +44,7 @@ index 0000000000000000000000000000000000000000..7feca06e72bd585bbfa219df38a2161b
+ /**
+ * @return the potion the witch is readying to use
+ */
+ @Nullable
+ public ItemStack getPotion() {
+ public @Nullable ItemStack getPotion() {
+ return this.potion;
+ }
+
@ -54,7 +53,7 @@ index 0000000000000000000000000000000000000000..7feca06e72bd585bbfa219df38a2161b
+ *
+ * @param potion The potion
+ */
+ public void setPotion(@Nullable ItemStack potion) {
+ public void setPotion(final @Nullable ItemStack potion) {
+ this.potion = potion != null ? potion.clone() : null;
+ }
+
@ -64,17 +63,15 @@ index 0000000000000000000000000000000000000000..7feca06e72bd585bbfa219df38a2161b
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,7 +6,7 @@ Subject: [PATCH] Add EntityTeleportEndGatewayEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityTeleportEndGatewayEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityTeleportEndGatewayEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..88b9c059f9d66877260c66496443ad0aefaf8f47
index 0000000000000000000000000000000000000000..cea029bfbd526d21509dee69bbfad44323107cf2
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityTeleportEndGatewayEvent.java
@@ -0,0 +1,33 @@
@ -17,17 +17,18 @@ index 0000000000000000000000000000000000000000..88b9c059f9d66877260c66496443ad0a
+import org.bukkit.entity.Entity;
+import org.bukkit.event.entity.EntityTeleportEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired any time an entity attempts to teleport in an end gateway
+ */
+@NullMarked
+public class EntityTeleportEndGatewayEvent extends EntityTeleportEvent {
+
+ @NotNull private final EndGateway gateway;
+ private final EndGateway gateway;
+
+ @ApiStatus.Internal
+ public EntityTeleportEndGatewayEvent(@NotNull Entity entity, @NotNull Location from, @NotNull Location to, @NotNull EndGateway gateway) {
+ public EntityTeleportEndGatewayEvent(final Entity entity, final Location from, final Location to, final EndGateway gateway) {
+ super(entity, from, to);
+ this.gateway = gateway;
+ }
@ -37,7 +38,6 @@ index 0000000000000000000000000000000000000000..88b9c059f9d66877260c66496443ad0a
+ *
+ * @return EndGateway used
+ */
+ @NotNull
+ public EndGateway getGateway() {
+ return this.gateway;
+ }

View file

@ -8,10 +8,10 @@ Plugins can skip selection of certain arrows and control which is used.
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerReadyArrowEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerReadyArrowEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..f30c4c372c92a79fb6c3fe80c4b51b5c8c0d4d3b
index 0000000000000000000000000000000000000000..3eadfae8860a4f6cde107cc3c7048368ade29d28
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerReadyArrowEvent.java
@@ -0,0 +1,94 @@
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
+ *
@ -42,21 +42,22 @@ index 0000000000000000000000000000000000000000..f30c4c372c92a79fb6c3fe80c4b51b5c
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a player is firing a bow and the server is choosing an arrow to use.
+ */
+@NullMarked
+public class PlayerReadyArrowEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final ItemStack bow;
+ @NotNull private final ItemStack arrow;
+ private final ItemStack bow;
+ private final ItemStack arrow;
+
+ private boolean cancelled;
+
+ public PlayerReadyArrowEvent(@NotNull Player player, @NotNull ItemStack bow, @NotNull ItemStack arrow) {
+ public PlayerReadyArrowEvent(final Player player, final ItemStack bow, final ItemStack arrow) {
+ super(player);
+ this.bow = bow;
+ this.arrow = arrow;
@ -65,7 +66,6 @@ index 0000000000000000000000000000000000000000..f30c4c372c92a79fb6c3fe80c4b51b5c
+ /**
+ * @return the player is using to fire the arrow
+ */
+ @NotNull
+ public ItemStack getBow() {
+ return this.bow;
+ }
@ -73,7 +73,6 @@ index 0000000000000000000000000000000000000000..f30c4c372c92a79fb6c3fe80c4b51b5c
+ /**
+ * @return the arrow that is attempting to be used
+ */
+ @NotNull
+ public ItemStack getArrow() {
+ return this.arrow;
+ }
@ -92,16 +91,15 @@ index 0000000000000000000000000000000000000000..f30c4c372c92a79fb6c3fe80c4b51b5c
+ * Cancel use of this arrow. On cancel, the server will try the next arrow available and fire another event.
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -12,10 +12,10 @@ Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..beb1715e30ec476e3031c247285d0d3219e8a8ea
index 0000000000000000000000000000000000000000..6f376e1ac0f2f44255993b3d5b144f5559d13cc3
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java
@@ -0,0 +1,51 @@
@@ -0,0 +1,52 @@
+package com.destroystokyo.paper.event.entity;
+
+import io.papermc.paper.event.entity.EntityKnockbackEvent;
@ -23,19 +23,20 @@ index 0000000000000000000000000000000000000000..beb1715e30ec476e3031c247285d0d32
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.util.Vector;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when an Entity is knocked back by the hit of another Entity. The acceleration
+ * vector can be modified. If this event is cancelled, the entity is not knocked back.
+ */
+@NullMarked
+public class EntityKnockbackByEntityEvent extends EntityPushedByEntityAttackEvent {
+
+ private final float knockbackStrength;
+
+ @ApiStatus.Internal
+ public EntityKnockbackByEntityEvent(final @NonNull LivingEntity entity, final @NonNull Entity hitBy, final EntityKnockbackEvent.@NonNull Cause cause, final float knockbackStrength, final @NonNull Vector knockback) {
+ public EntityKnockbackByEntityEvent(final LivingEntity entity, final Entity hitBy, final EntityKnockbackEvent.Cause cause, final float knockbackStrength, final Vector knockback) {
+ super(entity, cause, hitBy, knockback);
+ this.knockbackStrength = knockbackStrength;
+ }
@ -44,7 +45,7 @@ index 0000000000000000000000000000000000000000..beb1715e30ec476e3031c247285d0d32
+ * @return the entity which was knocked back
+ */
+ @Override
+ public @NonNull LivingEntity getEntity() {
+ public LivingEntity getEntity() {
+ return (LivingEntity) super.getEntity();
+ }
+
@ -62,17 +63,17 @@ index 0000000000000000000000000000000000000000..beb1715e30ec476e3031c247285d0d32
+ *
+ * @return the Entity which hit
+ */
+ public @NonNull Entity getHitBy() {
+ public Entity getHitBy() {
+ return super.getPushedBy();
+ }
+
+}
diff --git a/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..8aaafa4ea837f54b32497010d121f02b103e03a6
index 0000000000000000000000000000000000000000..bc120d4928dc41ea827e2a06f7d30d0e3d484ce0
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java
@@ -0,0 +1,116 @@
@@ -0,0 +1,117 @@
+package io.papermc.paper.event.entity;
+
+import com.google.common.base.Preconditions;
@ -81,14 +82,15 @@ index 0000000000000000000000000000000000000000..8aaafa4ea837f54b32497010d121f02b
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.bukkit.util.Vector;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when an entity receives knockback.
+ * @see EntityPushedByEntityAttackEvent
+ * @see com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent
+ */
+@NullMarked
+public class EntityKnockbackEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -98,7 +100,7 @@ index 0000000000000000000000000000000000000000..8aaafa4ea837f54b32497010d121f02b
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EntityKnockbackEvent(final @NonNull Entity entity, final EntityKnockbackEvent.@NonNull Cause cause, final @NonNull Vector knockback) {
+ public EntityKnockbackEvent(final Entity entity, final EntityKnockbackEvent.Cause cause, final Vector knockback) {
+ super(entity);
+ this.cause = cause;
+ this.knockback = knockback;
@ -109,7 +111,7 @@ index 0000000000000000000000000000000000000000..8aaafa4ea837f54b32497010d121f02b
+ *
+ * @return the cause of the knockback
+ */
+ public EntityKnockbackEvent.@NonNull Cause getCause() {
+ public EntityKnockbackEvent.Cause getCause() {
+ return this.cause;
+ }
+
@ -121,7 +123,7 @@ index 0000000000000000000000000000000000000000..8aaafa4ea837f54b32497010d121f02b
+ *
+ * @return the knockback
+ */
+ public @NonNull Vector getKnockback() {
+ public Vector getKnockback() {
+ return this.knockback.clone();
+ }
+
@ -130,7 +132,7 @@ index 0000000000000000000000000000000000000000..8aaafa4ea837f54b32497010d121f02b
+ *
+ * @param knockback the knockback
+ */
+ public void setKnockback(final @NonNull Vector knockback) {
+ public void setKnockback(final Vector knockback) {
+ Preconditions.checkArgument(knockback != null, "knockback");
+ this.knockback = knockback.clone();
+ }
@ -146,11 +148,11 @@ index 0000000000000000000000000000000000000000..8aaafa4ea837f54b32497010d121f02b
+ }
+
+ @Override
+ public @NonNull HandlerList getHandlers() {
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static @NonNull HandlerList getHandlerList() {
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+
@ -191,17 +193,17 @@ index 0000000000000000000000000000000000000000..8aaafa4ea837f54b32497010d121f02b
+}
diff --git a/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9d2a7a5bc4e67d8c36047da616046cbedce1d4a
index 0000000000000000000000000000000000000000..7655c3694b9d6b37206fc46bf892004686e0a7dd
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java
@@ -0,0 +1,66 @@
@@ -0,0 +1,67 @@
+package io.papermc.paper.event.entity;
+
+import org.bukkit.entity.Entity;
+import org.bukkit.event.Cancellable;
+import org.bukkit.util.Vector;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when an entity is pushed by another entity's attack. The acceleration vector can be
@ -210,12 +212,13 @@ index 0000000000000000000000000000000000000000..b9d2a7a5bc4e67d8c36047da616046cb
+ * Note: Some entities might trigger this multiple times on the same entity
+ * as multiple acceleration calculations are done.
+ */
+@NullMarked
+public class EntityPushedByEntityAttackEvent extends EntityKnockbackEvent implements Cancellable {
+
+ private final Entity pushedBy;
+
+ @ApiStatus.Internal
+ public EntityPushedByEntityAttackEvent(final @NonNull Entity entity, final EntityKnockbackEvent.@NonNull Cause cause, final @NonNull Entity pushedBy, final @NonNull Vector knockback) {
+ public EntityPushedByEntityAttackEvent(final Entity entity, final EntityKnockbackEvent.Cause cause, final Entity pushedBy, final Vector knockback) {
+ super(entity, cause, knockback);
+ this.pushedBy = pushedBy;
+ }
@ -225,7 +228,7 @@ index 0000000000000000000000000000000000000000..b9d2a7a5bc4e67d8c36047da616046cb
+ *
+ * @return the pushing entity
+ */
+ public @NonNull Entity getPushedBy() {
+ public Entity getPushedBy() {
+ return this.pushedBy;
+ }
+
@ -236,7 +239,7 @@ index 0000000000000000000000000000000000000000..b9d2a7a5bc4e67d8c36047da616046cb
+ * @deprecated use {@link #getKnockback()}
+ */
+ @Deprecated(since = "1.20.6", forRemoval = true)
+ public @NonNull Vector getAcceleration() {
+ public Vector getAcceleration() {
+ return this.knockback; // TODO Clone in 1.21 to not instantly break what was technically already modifiable (call super.getKnockback())
+ }
+
@ -247,7 +250,7 @@ index 0000000000000000000000000000000000000000..b9d2a7a5bc4e67d8c36047da616046cb
+ * @deprecated use {@link #setKnockback(Vector)}
+ */
+ @Deprecated(since = "1.20.6", forRemoval = true)
+ public void setAcceleration(final @NonNull Vector acceleration) {
+ public void setAcceleration(final Vector acceleration) {
+ super.setKnockback(acceleration);
+ }
+

View file

@ -5,7 +5,7 @@ Subject: [PATCH] Expand Explosions API
Add Entity as a Source capability, and add more API choices, and on Location.
Co-authored-by: Slqmy <90862990+Slqmy@users.noreply.github.com>
Co-authored-by: Esoteric Enderman <90862990+EsotericEnderman@users.noreply.github.com>
Co-authored-by: Bjarne Koll <lynxplay101@gmail.com>
diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java

View file

@ -8,16 +8,17 @@ and to perform an attack.
diff --git a/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java b/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..46e0e62d620def237dab44ad24708f1b93a8a1a7
index 0000000000000000000000000000000000000000..09c82908f63233febfe1e07fe756f1c39d23d44f
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java
@@ -0,0 +1,35 @@
@@ -0,0 +1,36 @@
+package com.destroystokyo.paper.entity;
+
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Mob;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public interface RangedEntity extends Mob {
+ /**
+ * Attack the specified entity using a ranged attack.
@ -26,7 +27,7 @@ index 0000000000000000000000000000000000000000..46e0e62d620def237dab44ad24708f1b
+ * @param charge How "charged" the attack is (how far back the bow was pulled for Bow attacks).
+ * This should be a value between 0 and 1, represented as targetDistance/maxDistance.
+ */
+ void rangedAttack(@NotNull LivingEntity target, float charge);
+ void rangedAttack(LivingEntity target, float charge);
+
+ /**
+ * Sets that the Entity is "charging" up an attack, by raising its hands
@ -44,7 +45,7 @@ index 0000000000000000000000000000000000000000..46e0e62d620def237dab44ad24708f1b
+ */
+ @Deprecated(since = "1.19.2")
+ default boolean isChargingAttack() {
+ return isHandRaised();
+ return this.isHandRaised();
+ }
+}
diff --git a/src/main/java/org/bukkit/entity/AbstractSkeleton.java b/src/main/java/org/bukkit/entity/AbstractSkeleton.java

View file

@ -6,36 +6,36 @@ Subject: [PATCH] EnderDragon Events
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFireballHitEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFireballHitEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf5f82c8ba36bd245e1536fd4f654487aa8f6e21
index 0000000000000000000000000000000000000000..242eb9c07866365568c036819be2b4f882319aa1
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFireballHitEvent.java
@@ -0,0 +1,79 @@
@@ -0,0 +1,74 @@
+package com.destroystokyo.paper.event.entity;
+
+import java.util.Collection;
+import org.bukkit.entity.AreaEffectCloud;
+import org.bukkit.entity.DragonFireball;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+
+import java.util.Collection;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a DragonFireball collides with a block/entity and spawns an AreaEffectCloud
+ */
+@NullMarked
+public class EnderDragonFireballHitEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Collection<LivingEntity> targets;
+ @NotNull private final AreaEffectCloud areaEffectCloud;
+ private final Collection<LivingEntity> targets;
+ private final AreaEffectCloud areaEffectCloud;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EnderDragonFireballHitEvent(@NotNull DragonFireball fireball, @NotNull Collection<LivingEntity> targets, @NotNull AreaEffectCloud areaEffectCloud) {
+ public EnderDragonFireballHitEvent(final DragonFireball fireball, final Collection<LivingEntity> targets, final AreaEffectCloud areaEffectCloud) {
+ super(fireball);
+ this.targets = targets;
+ this.areaEffectCloud = areaEffectCloud;
@ -44,7 +44,6 @@ index 0000000000000000000000000000000000000000..bf5f82c8ba36bd245e1536fd4f654487
+ /**
+ * The fireball involved in this event
+ */
+ @NotNull
+ @Override
+ public DragonFireball getEntity() {
+ return (DragonFireball) super.getEntity();
@ -55,7 +54,6 @@ index 0000000000000000000000000000000000000000..bf5f82c8ba36bd245e1536fd4f654487
+ *
+ * @return the targets
+ */
+ @NotNull
+ public Collection<LivingEntity> getTargets() {
+ return this.targets;
+ }
@ -63,7 +61,6 @@ index 0000000000000000000000000000000000000000..bf5f82c8ba36bd245e1536fd4f654487
+ /**
+ * @return The area effect cloud spawned in this collision
+ */
+ @NotNull
+ public AreaEffectCloud getAreaEffectCloud() {
+ return this.areaEffectCloud;
+ }
@ -74,27 +71,25 @@ index 0000000000000000000000000000000000000000..bf5f82c8ba36bd245e1536fd4f654487
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFlameEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFlameEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a61878152c95a07160f4216e78b042ca45d24b3
index 0000000000000000000000000000000000000000..47cf33ef97ce1b92bc13c4d3a6c49d050e344eb1
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFlameEvent.java
@@ -0,0 +1,63 @@
@@ -0,0 +1,61 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.AreaEffectCloud;
@ -103,20 +98,21 @@ index 0000000000000000000000000000000000000000..4a61878152c95a07160f4216e78b042c
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when an EnderDragon spawns an AreaEffectCloud by shooting flames
+ */
+@NullMarked
+public class EnderDragonFlameEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final AreaEffectCloud areaEffectCloud;
+ private final AreaEffectCloud areaEffectCloud;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EnderDragonFlameEvent(@NotNull EnderDragon enderDragon, @NotNull AreaEffectCloud areaEffectCloud) {
+ public EnderDragonFlameEvent(final EnderDragon enderDragon, final AreaEffectCloud areaEffectCloud) {
+ super(enderDragon);
+ this.areaEffectCloud = areaEffectCloud;
+ }
@ -124,7 +120,6 @@ index 0000000000000000000000000000000000000000..4a61878152c95a07160f4216e78b042c
+ /**
+ * The enderdragon involved in this event
+ */
+ @NotNull
+ @Override
+ public EnderDragon getEntity() {
+ return (EnderDragon) super.getEntity();
@ -133,7 +128,6 @@ index 0000000000000000000000000000000000000000..4a61878152c95a07160f4216e78b042c
+ /**
+ * @return The area effect cloud spawned in this collision
+ */
+ @NotNull
+ public AreaEffectCloud getAreaEffectCloud() {
+ return this.areaEffectCloud;
+ }
@ -144,26 +138,25 @@ index 0000000000000000000000000000000000000000..4a61878152c95a07160f4216e78b042c
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonShootFireballEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonShootFireballEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c6c3db37d91aad3638aef107a3bf8ca1d4f7085
index 0000000000000000000000000000000000000000..7dd6e17b648868cf5d549f1e779e5d92439751dd
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonShootFireballEvent.java
@@ -0,0 +1,64 @@
@@ -0,0 +1,61 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.DragonFireball;
@ -172,20 +165,21 @@ index 0000000000000000000000000000000000000000..3c6c3db37d91aad3638aef107a3bf8ca
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when an EnderDragon shoots a fireball
+ */
+@NullMarked
+public class EnderDragonShootFireballEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final DragonFireball fireball;
+ private final DragonFireball fireball;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EnderDragonShootFireballEvent(@NotNull EnderDragon entity, @NotNull DragonFireball fireball) {
+ public EnderDragonShootFireballEvent(final EnderDragon entity, final DragonFireball fireball) {
+ super(entity);
+ this.fireball = fireball;
+ }
@ -193,7 +187,6 @@ index 0000000000000000000000000000000000000000..3c6c3db37d91aad3638aef107a3bf8ca
+ /**
+ * The enderdragon shooting the fireball
+ */
+ @NotNull
+ @Override
+ public EnderDragon getEntity() {
+ return (EnderDragon) super.getEntity();
@ -202,7 +195,6 @@ index 0000000000000000000000000000000000000000..3c6c3db37d91aad3638aef107a3bf8ca
+ /**
+ * @return The fireball being shot
+ */
+ @NotNull
+ public DragonFireball getFireball() {
+ return this.fireball;
+ }
@ -213,17 +205,15 @@ index 0000000000000000000000000000000000000000..3c6c3db37d91aad3638aef107a3bf8ca
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] PlayerElytraBoostEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerElytraBoostEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerElytraBoostEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ebac41c22b8866df616020d409e5e1a49cddca5
index 0000000000000000000000000000000000000000..7d41a5c2dc6ca659bfad41e70cbeac2349c2b0f3
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerElytraBoostEvent.java
@@ -0,0 +1,104 @@
@@ -0,0 +1,99 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.entity.Firework;
@ -20,25 +20,25 @@ index 0000000000000000000000000000000000000000..9ebac41c22b8866df616020d409e5e1a
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a player boosts elytra flight with a firework
+ */
+@NullMarked
+public class PlayerElytraBoostEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final ItemStack itemStack;
+ @NotNull private final Firework firework;
+ private final ItemStack itemStack;
+ private final Firework firework;
+ private boolean consume = true;
+ @NotNull
+ private final EquipmentSlot hand;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerElytraBoostEvent(@NotNull Player player, @NotNull ItemStack itemStack, @NotNull Firework firework, @NotNull EquipmentSlot hand) {
+ public PlayerElytraBoostEvent(final Player player, final ItemStack itemStack, final Firework firework, final EquipmentSlot hand) {
+ super(player);
+ this.itemStack = itemStack;
+ this.firework = firework;
@ -50,7 +50,6 @@ index 0000000000000000000000000000000000000000..9ebac41c22b8866df616020d409e5e1a
+ *
+ * @return ItemStack of firework
+ */
+ @NotNull
+ public ItemStack getItemStack() {
+ return this.itemStack;
+ }
@ -60,7 +59,6 @@ index 0000000000000000000000000000000000000000..9ebac41c22b8866df616020d409e5e1a
+ *
+ * @return Firework entity
+ */
+ @NotNull
+ public Firework getFirework() {
+ return this.firework;
+ }
@ -79,7 +77,7 @@ index 0000000000000000000000000000000000000000..9ebac41c22b8866df616020d409e5e1a
+ *
+ * @param consume {@code true} to consume
+ */
+ public void setShouldConsume(boolean consume) {
+ public void setShouldConsume(final boolean consume) {
+ this.consume = consume;
+ }
+
@ -88,7 +86,6 @@ index 0000000000000000000000000000000000000000..9ebac41c22b8866df616020d409e5e1a
+ *
+ * @return interaction hand
+ */
+ @NotNull
+ public EquipmentSlot getHand() {
+ return this.hand;
+ }
@ -99,17 +96,15 @@ index 0000000000000000000000000000000000000000..9ebac41c22b8866df616020d409e5e1a
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] PlayerLaunchProjectileEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..efd947eb0aa0633891d9c6a8bde66d33e29020d7
index 0000000000000000000000000000000000000000..a6d483e6be8b8527d7cfd676f6056179e8e9bf33
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java
@@ -0,0 +1,95 @@
@@ -0,0 +1,92 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.entity.Player;
@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..efd947eb0aa0633891d9c6a8bde66d33
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a player shoots a projectile.
@ -29,18 +29,19 @@ index 0000000000000000000000000000000000000000..efd947eb0aa0633891d9c6a8bde66d33
+ * of a bow or crossbow. A plugin may listen to {@link EntityShootBowEvent}
+ * for these actions instead.
+ */
+@NullMarked
+public class PlayerLaunchProjectileEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Projectile projectile;
+ @NotNull private final ItemStack itemStack;
+ private final Projectile projectile;
+ private final ItemStack itemStack;
+ private boolean consumeItem = true;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerLaunchProjectileEvent(@NotNull Player shooter, @NotNull ItemStack itemStack, @NotNull Projectile projectile) {
+ public PlayerLaunchProjectileEvent(final Player shooter, final ItemStack itemStack, final Projectile projectile) {
+ super(shooter);
+ this.itemStack = itemStack;
+ this.projectile = projectile;
@ -51,7 +52,6 @@ index 0000000000000000000000000000000000000000..efd947eb0aa0633891d9c6a8bde66d33
+ *
+ * @return the launched projectile
+ */
+ @NotNull
+ public Projectile getProjectile() {
+ return this.projectile;
+ }
@ -61,7 +61,6 @@ index 0000000000000000000000000000000000000000..efd947eb0aa0633891d9c6a8bde66d33
+ *
+ * @return The ItemStack used
+ */
+ @NotNull
+ public ItemStack getItemStack() {
+ return this.itemStack;
+ }
@ -80,7 +79,7 @@ index 0000000000000000000000000000000000000000..efd947eb0aa0633891d9c6a8bde66d33
+ *
+ * @param consumeItem {@code true} to consume
+ */
+ public void setShouldConsume(boolean consumeItem) {
+ public void setShouldConsume(final boolean consumeItem) {
+ this.consumeItem = consumeItem;
+ }
+
@ -90,17 +89,15 @@ index 0000000000000000000000000000000000000000..efd947eb0aa0633891d9c6a8bde66d33
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,26 +6,26 @@ Subject: [PATCH] SkeletonHorse Additions
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SkeletonHorseTrapEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SkeletonHorseTrapEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6724e6e5754996ac10888aaa92baf2dcc6134d3
index 0000000000000000000000000000000000000000..a70f4972a012f955b45a91fe20ca5df7e2123528
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SkeletonHorseTrapEvent.java
@@ -0,0 +1,68 @@
@@ -0,0 +1,64 @@
+package com.destroystokyo.paper.event.entity;
+
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.SkeletonHorse;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Event called when a player gets close to a skeleton horse and triggers the lightning trap
+ */
+@NullMarked
+public class SkeletonHorseTrapEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -35,23 +35,21 @@ index 0000000000000000000000000000000000000000..f6724e6e5754996ac10888aaa92baf2d
+
+ @Deprecated
+ @ApiStatus.Internal
+ public SkeletonHorseTrapEvent(@NotNull SkeletonHorse horse) {
+ public SkeletonHorseTrapEvent(final SkeletonHorse horse) {
+ this(horse, ImmutableList.of());
+ }
+
+ @ApiStatus.Internal
+ public SkeletonHorseTrapEvent(@NotNull SkeletonHorse horse, @NotNull List<HumanEntity> eligibleHumans) {
+ public SkeletonHorseTrapEvent(final SkeletonHorse horse, final List<HumanEntity> eligibleHumans) {
+ super(horse);
+ this.eligibleHumans = eligibleHumans;
+ }
+
+ @NotNull
+ @Override
+ public SkeletonHorse getEntity() {
+ return (SkeletonHorse) super.getEntity();
+ }
+
+ @NotNull
+ public List<HumanEntity> getEligibleHumans() {
+ return this.eligibleHumans;
+ }
@ -62,17 +60,15 @@ index 0000000000000000000000000000000000000000..f6724e6e5754996ac10888aaa92baf2d
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -12,18 +12,19 @@ Co-authored-by: SoSeDiK <mrsosedik@gmail.com>
diff --git a/src/main/java/io/papermc/paper/math/Rotations.java b/src/main/java/io/papermc/paper/math/Rotations.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ac1618113699ac50b9c35294bf23fb9fb7cfbad
index 0000000000000000000000000000000000000000..2a8e1aa29ab87c69a02f72615fbf1374714f54cf
--- /dev/null
+++ b/src/main/java/io/papermc/paper/math/Rotations.java
@@ -0,0 +1,100 @@
@@ -0,0 +1,101 @@
+package io.papermc.paper.math;
+
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Rotations is an immutable object that stores rotations
+ * in degrees on each axis (X, Y, Z).
+ */
+@NullMarked
+public interface Rotations {
+
+ /**
@ -39,7 +40,7 @@ index 0000000000000000000000000000000000000000..0ac1618113699ac50b9c35294bf23fb9
+ * @param z the angle for the Z axis in degrees
+ * @return Rotations instance holding the provided rotations
+ */
+ static @NotNull Rotations ofDegrees(double x, double y, double z) {
+ static Rotations ofDegrees(final double x, final double y, final double z) {
+ return new RotationsImpl(x, y, z);
+ }
+
@ -71,7 +72,7 @@ index 0000000000000000000000000000000000000000..0ac1618113699ac50b9c35294bf23fb9
+ * @param x the angle in degrees
+ * @return the resultant Rotations
+ */
+ @NotNull Rotations withX(double x);
+ Rotations withX(double x);
+
+ /**
+ * Returns a new Rotations instance which is the result
@ -80,7 +81,7 @@ index 0000000000000000000000000000000000000000..0ac1618113699ac50b9c35294bf23fb9
+ * @param y the angle in degrees
+ * @return the resultant Rotations
+ */
+ @NotNull Rotations withY(double y);
+ Rotations withY(double y);
+
+ /**
+ * Returns a new Rotations instance which is the result
@ -89,7 +90,7 @@ index 0000000000000000000000000000000000000000..0ac1618113699ac50b9c35294bf23fb9
+ * @param z the angle in degrees
+ * @return the resultant Rotations
+ */
+ @NotNull Rotations withZ(double z);
+ Rotations withZ(double z);
+
+ /**
+ * Returns a new Rotations instance which is the result of adding
@ -100,7 +101,7 @@ index 0000000000000000000000000000000000000000..0ac1618113699ac50b9c35294bf23fb9
+ * @param z the angle to add to the Z axis in degrees
+ * @return the resultant Rotations
+ */
+ @NotNull Rotations add(double x, double y, double z);
+ Rotations add(double x, double y, double z);
+
+ /**
+ * Returns a new Rotations instance which is the result of subtracting
@ -111,40 +112,41 @@ index 0000000000000000000000000000000000000000..0ac1618113699ac50b9c35294bf23fb9
+ * @param z the angle to subtract from the Z axis in degrees
+ * @return the resultant Rotations
+ */
+ default @NotNull Rotations subtract(double x, double y, double z) {
+ return add(-x, -y, -z);
+ default Rotations subtract(final double x, final double y, final double z) {
+ return this.add(-x, -y, -z);
+ }
+
+}
diff --git a/src/main/java/io/papermc/paper/math/RotationsImpl.java b/src/main/java/io/papermc/paper/math/RotationsImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..53359ab4a6659bce895deef6a21cde848d3cadcd
index 0000000000000000000000000000000000000000..35b493b870240f2cb142ea0c3bc2a5b2a89af25b
--- /dev/null
+++ b/src/main/java/io/papermc/paper/math/RotationsImpl.java
@@ -0,0 +1,27 @@
@@ -0,0 +1,28 @@
+package io.papermc.paper.math;
+
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+record RotationsImpl(double x, double y, double z) implements Rotations {
+
+ @Override
+ public @NotNull RotationsImpl withX(double x) {
+ return new RotationsImpl(x, y, z);
+ public RotationsImpl withX(final double x) {
+ return new RotationsImpl(x, this.y, this.z);
+ }
+
+ @Override
+ public @NotNull RotationsImpl withY(double y) {
+ return new RotationsImpl(x, y, z);
+ public RotationsImpl withY(final double y) {
+ return new RotationsImpl(this.x, y, this.z);
+ }
+
+ @Override
+ public @NotNull RotationsImpl withZ(double z) {
+ return new RotationsImpl(x, y, z);
+ public RotationsImpl withZ(final double z) {
+ return new RotationsImpl(this.x, this.y, z);
+ }
+
+ @Override
+ public @NotNull RotationsImpl add(double x, double y, double z) {
+ public RotationsImpl add(final double x, final double y, final double z) {
+ return new RotationsImpl(this.x + x, this.y + y, this.z + z);
+ }
+

View file

@ -6,10 +6,10 @@ Subject: [PATCH] AnvilDamageEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/block/AnvilDamagedEvent.java b/src/main/java/com/destroystokyo/paper/event/block/AnvilDamagedEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816337666d7
index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3bb365dca
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/block/AnvilDamagedEvent.java
@@ -0,0 +1,154 @@
@@ -0,0 +1,149 @@
+package com.destroystokyo.paper.event.block;
+
+import org.bukkit.Material;
@ -20,12 +20,13 @@ index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816
+import org.bukkit.inventory.AnvilInventory;
+import org.bukkit.inventory.InventoryView;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Called when an anvil is damaged from being used
+ */
+@NullMarked
+public class AnvilDamagedEvent extends InventoryEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -34,12 +35,11 @@ index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public AnvilDamagedEvent(@NotNull InventoryView inventory, @Nullable BlockData blockData) {
+ public AnvilDamagedEvent(final InventoryView inventory, final @Nullable BlockData blockData) {
+ super(inventory);
+ this.damageState = DamageState.getState(blockData);
+ }
+
+ @NotNull
+ @Override
+ public AnvilInventory getInventory() {
+ return (AnvilInventory) super.getInventory();
@ -50,7 +50,6 @@ index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816
+ *
+ * @return Damage state
+ */
+ @NotNull
+ public DamageState getDamageState() {
+ return this.damageState;
+ }
@ -60,7 +59,7 @@ index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816
+ *
+ * @param damageState Damage state
+ */
+ public void setDamageState(@NotNull DamageState damageState) {
+ public void setDamageState(final DamageState damageState) {
+ this.damageState = damageState;
+ }
+
@ -78,7 +77,7 @@ index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816
+ *
+ * @param breaking {@code true} if breaking
+ */
+ public void setBreaking(boolean breaking) {
+ public void setBreaking(final boolean breaking) {
+ if (breaking) {
+ this.damageState = DamageState.BROKEN;
+ } else if (this.damageState == DamageState.BROKEN) {
@ -92,16 +91,15 @@ index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
@ -117,7 +115,7 @@ index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816
+
+ private final Material material;
+
+ DamageState(@NotNull Material material) {
+ DamageState(final Material material) {
+ this.material = material;
+ }
+
@ -126,7 +124,6 @@ index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816
+ *
+ * @return Material
+ */
+ @NotNull
+ public Material getMaterial() {
+ return this.material;
+ }
@ -138,8 +135,7 @@ index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816
+ * @return DamageState
+ * @throws IllegalArgumentException If non anvil block data is given
+ */
+ @NotNull
+ public static DamageState getState(@Nullable BlockData blockData) {
+ public static DamageState getState(final @Nullable BlockData blockData) {
+ return blockData == null ? BROKEN : getState(blockData.getMaterial());
+ }
+
@ -150,12 +146,11 @@ index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816
+ * @return DamageState
+ * @throws IllegalArgumentException If non anvil material is given
+ */
+ @NotNull
+ public static DamageState getState(@Nullable Material material) {
+ public static DamageState getState(final @Nullable Material material) {
+ if (material == null) {
+ return BROKEN;
+ }
+ for (DamageState state : values()) {
+ for (final DamageState state : values()) {
+ if (state.getMaterial() == material) {
+ return state;
+ }

View file

@ -6,15 +6,15 @@ Subject: [PATCH] Slime Pathfinder Events
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeChangeDirectionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeChangeDirectionEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..30864539574e23bbe9e4c5dc73ad6614de782ac2
index 0000000000000000000000000000000000000000..a5d4442b53c4bd70165c3240c7dbd3d56b6bf0ae
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeChangeDirectionEvent.java
@@ -0,0 +1,40 @@
@@ -0,0 +1,41 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Slime;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a Slime decides to change its facing direction.
@ -22,12 +22,13 @@ index 0000000000000000000000000000000000000000..30864539574e23bbe9e4c5dc73ad6614
+ * This event does not fire for the entity's actual movement. Only when it
+ * is choosing to change direction.
+ */
+@NullMarked
+public class SlimeChangeDirectionEvent extends SlimePathfindEvent {
+
+ private float yaw;
+
+ @ApiStatus.Internal
+ public SlimeChangeDirectionEvent(@NotNull Slime slime, float yaw) {
+ public SlimeChangeDirectionEvent(final Slime slime, final float yaw) {
+ super(slime);
+ this.yaw = yaw;
+ }
@ -46,13 +47,13 @@ index 0000000000000000000000000000000000000000..30864539574e23bbe9e4c5dc73ad6614
+ *
+ * @param yaw Chosen yaw
+ */
+ public void setNewYaw(float yaw) {
+ public void setNewYaw(final float yaw) {
+ this.yaw = yaw;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimePathfindEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimePathfindEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..706ed85a5415d688aaa5f138cbf583b9e2bab27d
index 0000000000000000000000000000000000000000..d481d116452fb5a702bc88a08da3c28cd0401a70
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimePathfindEvent.java
@@ -0,0 +1,56 @@
@ -63,7 +64,7 @@ index 0000000000000000000000000000000000000000..706ed85a5415d688aaa5f138cbf583b9
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a Slime decides to start pathfinding.
@ -71,6 +72,7 @@ index 0000000000000000000000000000000000000000..706ed85a5415d688aaa5f138cbf583b9
+ * This event does not fire for the entity's actual movement. Only when it
+ * is choosing to start moving.
+ */
+@NullMarked
+public class SlimePathfindEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -78,7 +80,7 @@ index 0000000000000000000000000000000000000000..706ed85a5415d688aaa5f138cbf583b9
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public SlimePathfindEvent(@NotNull Slime slime) {
+ public SlimePathfindEvent(final Slime slime) {
+ super(slime);
+ }
+
@ -87,7 +89,7 @@ index 0000000000000000000000000000000000000000..706ed85a5415d688aaa5f138cbf583b9
+ *
+ * @return The Slime that is pathfinding.
+ */
+ @NotNull
+ @Override
+ public Slime getEntity() {
+ return (Slime) super.getEntity();
+ }
@ -98,31 +100,30 @@ index 0000000000000000000000000000000000000000..706ed85a5415d688aaa5f138cbf583b9
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeSwimEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeSwimEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..65e8a29751e338b0f0acda7bef9e014852a73e6e
index 0000000000000000000000000000000000000000..4233ea3012c03660c42e3ec93832a6e019440eba
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeSwimEvent.java
@@ -0,0 +1,19 @@
@@ -0,0 +1,20 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Slime;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a Slime decides to start jumping while swimming in water/lava.
@ -130,16 +131,17 @@ index 0000000000000000000000000000000000000000..65e8a29751e338b0f0acda7bef9e0148
+ * This event does not fire for the entity's actual movement. Only when it
+ * is choosing to start jumping.
+ */
+@NullMarked
+public class SlimeSwimEvent extends SlimeWanderEvent {
+
+ @ApiStatus.Internal
+ public SlimeSwimEvent(@NotNull Slime slime) {
+ public SlimeSwimEvent(final Slime slime) {
+ super(slime);
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeTargetLivingEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeTargetLivingEntityEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..87c64b04dfec232e98361c3ec29da7664498c65b
index 0000000000000000000000000000000000000000..ba7369aab0c257acafda7d3a43a41e409240bf1d
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeTargetLivingEntityEvent.java
@@ -0,0 +1,33 @@
@ -148,7 +150,7 @@ index 0000000000000000000000000000000000000000..87c64b04dfec232e98361c3ec29da766
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Slime;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a Slime decides to change direction to target a LivingEntity.
@ -156,12 +158,13 @@ index 0000000000000000000000000000000000000000..87c64b04dfec232e98361c3ec29da766
+ * This event does not fire for the entity's actual movement. Only when it
+ * is choosing to start moving.
+ */
+@NullMarked
+public class SlimeTargetLivingEntityEvent extends SlimePathfindEvent {
+
+ @NotNull private final LivingEntity target;
+ private final LivingEntity target;
+
+ @ApiStatus.Internal
+ public SlimeTargetLivingEntityEvent(@NotNull Slime slime, @NotNull LivingEntity target) {
+ public SlimeTargetLivingEntityEvent(final Slime slime, final LivingEntity target) {
+ super(slime);
+ this.target = target;
+ }
@ -171,22 +174,21 @@ index 0000000000000000000000000000000000000000..87c64b04dfec232e98361c3ec29da766
+ *
+ * @return Targeted entity
+ */
+ @NotNull
+ public LivingEntity getTarget() {
+ return this.target;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeWanderEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeWanderEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ad9cc1673ffbb8b48349e461d1154d1d4ec2874
index 0000000000000000000000000000000000000000..0ea085c4a1cf663e2333444cebda876db321164d
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeWanderEvent.java
@@ -0,0 +1,19 @@
@@ -0,0 +1,20 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Slime;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a Slime decides to start wandering.
@ -194,10 +196,11 @@ index 0000000000000000000000000000000000000000..2ad9cc1673ffbb8b48349e461d1154d1
+ * This event does not fire for the entity's actual movement. Only when it
+ * is choosing to start moving.
+ */
+@NullMarked
+public class SlimeWanderEvent extends SlimePathfindEvent {
+
+ @ApiStatus.Internal
+ public SlimeWanderEvent(@NotNull Slime slime) {
+ public SlimeWanderEvent(final Slime slime) {
+ super(slime);
+ }
+}

View file

@ -6,7 +6,7 @@ Subject: [PATCH] Add PhantomPreSpawnEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PhantomPreSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PhantomPreSpawnEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff7d9ff618ab821eeece6923a694a9a4eea8585d
index 0000000000000000000000000000000000000000..e465222aa8218a7fef85f2e1df1a919a88499eab
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/PhantomPreSpawnEvent.java
@@ -0,0 +1,32 @@
@ -17,17 +17,18 @@ index 0000000000000000000000000000000000000000..ff7d9ff618ab821eeece6923a694a9a4
+import org.bukkit.entity.EntityType;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a phantom is spawned for an exhausted player
+ */
+@NullMarked
+public class PhantomPreSpawnEvent extends PreCreatureSpawnEvent {
+
+ @NotNull private final Entity entity;
+ private final Entity entity;
+
+ @ApiStatus.Internal
+ public PhantomPreSpawnEvent(@NotNull Location location, @NotNull Entity entity, @NotNull CreatureSpawnEvent.SpawnReason reason) {
+ public PhantomPreSpawnEvent(final Location location, final Entity entity, final CreatureSpawnEvent.SpawnReason reason) {
+ super(location, EntityType.PHANTOM, reason);
+ this.entity = entity;
+ }
@ -37,7 +38,6 @@ index 0000000000000000000000000000000000000000..ff7d9ff618ab821eeece6923a694a9a4
+ *
+ * @return the Entity
+ */
+ @NotNull
+ public Entity getSpawningEntity() {
+ return this.entity;
+ }

View file

@ -6,7 +6,7 @@ Subject: [PATCH] Add More Creeper API
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/CreeperIgniteEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/CreeperIgniteEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..e86500337f26fcb6bb04545c68c67df32021ce25
index 0000000000000000000000000000000000000000..8b97cc830aa8bdb09dec3c4b8ebe4fb22d279f46
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/CreeperIgniteEvent.java
@@ -0,0 +1,60 @@
@ -17,13 +17,14 @@ index 0000000000000000000000000000000000000000..e86500337f26fcb6bb04545c68c67df3
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a Creeper is ignited either by a
+ * flint and steel, {@link Creeper#ignite()} or
+ * {@link Creeper#setIgnited(boolean)}.
+ */
+@NullMarked
+public class CreeperIgniteEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -32,12 +33,11 @@ index 0000000000000000000000000000000000000000..e86500337f26fcb6bb04545c68c67df3
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public CreeperIgniteEvent(@NotNull Creeper creeper, boolean ignited) {
+ public CreeperIgniteEvent(final Creeper creeper, final boolean ignited) {
+ super(creeper);
+ this.ignited = ignited;
+ }
+
+ @NotNull
+ @Override
+ public Creeper getEntity() {
+ return (Creeper) super.getEntity();
@ -47,25 +47,25 @@ index 0000000000000000000000000000000000000000..e86500337f26fcb6bb04545c68c67df3
+ return this.ignited;
+ }
+
+ public void setIgnited(boolean ignited) {
+ public void setIgnited(final boolean ignited) {
+ this.ignited = ignited;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ public void setCancelled(boolean cancel) {
+ @Override
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -13,30 +13,28 @@ You can use EntityPathfindEvent to cancel new pathfinds from overriding your cur
diff --git a/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java b/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c1e2c93d923a683cc0455af77c43784ef12270e
index 0000000000000000000000000000000000000000..5f6d6e222f9f1ac1648a11b6d4a240371c4f07e9
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java
@@ -0,0 +1,220 @@
@@ -0,0 +1,221 @@
+package com.destroystokyo.paper.entity;
+
+import java.util.List;
+import org.bukkit.Location;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Mob;
+
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Handles pathfinding operations for an Entity
+ */
+@NullMarked
+public interface Pathfinder {
+
+ /**
+ *
+ * @return The entity that is controlled by this pathfinder
+ */
+ @NotNull
+ Mob getEntity();
+
+ /**
@ -46,6 +44,7 @@ index 0000000000000000000000000000000000000000..3c1e2c93d923a683cc0455af77c43784
+
+ /**
+ * If the entity is currently trying to navigate to a destination, this will return true
+ *
+ * @return true if the entity is navigating to a destination
+ */
+ boolean hasPath();
@ -53,86 +52,88 @@ index 0000000000000000000000000000000000000000..3c1e2c93d923a683cc0455af77c43784
+ /**
+ * @return The location the entity is trying to navigate to, or null if there is no destination
+ */
+ @Nullable
+ PathResult getCurrentPath();
+ @Nullable PathResult getCurrentPath();
+
+ /**
+ * Calculates a destination for the Entity to navigate to, but does not set it
+ * as the current target. Useful for calculating what would happen before setting it.
+ *
+ * @param loc Location to navigate to
+ * @return The closest Location the Entity can get to for this navigation, or null if no path could be calculated
+ */
+ @Nullable PathResult findPath(@NotNull Location loc);
+ @Nullable PathResult findPath(Location loc);
+
+ /**
+ * Calculates a destination for the Entity to navigate to to reach the target entity,
+ * but does not set it as the current target.
+ * Useful for calculating what would happen before setting it.
+ *
+ * <p>
+ * The behavior of this PathResult is subject to the games pathfinding rules, and may
+ * result in the pathfinding automatically updating to follow the target Entity.
+ *
+ * <p>
+ * However, this behavior is not guaranteed, and is subject to the games behavior.
+ *
+ * @param target the Entity to navigate to
+ * @return The closest Location the Entity can get to for this navigation, or null if no path could be calculated
+ */
+ @Nullable PathResult findPath(@NotNull LivingEntity target);
+ @Nullable PathResult findPath(LivingEntity target);
+
+ /**
+ * Calculates a destination for the Entity to navigate to, and sets it with default speed
+ * as the current target.
+ *
+ * @param loc Location to navigate to
+ * @return If the pathfinding was successfully started
+ */
+ default boolean moveTo(@NotNull Location loc) {
+ return moveTo(loc, 1);
+ default boolean moveTo(Location loc) {
+ return this.moveTo(loc, 1);
+ }
+
+ /**
+ * Calculates a destination for the Entity to navigate to, with desired speed
+ * as the current target.
+ * @param loc Location to navigate to
+ *
+ * @param loc Location to navigate to
+ * @param speed Speed multiplier to navigate at, where 1 is 'normal'
+ * @return If the pathfinding was successfully started
+ */
+ default boolean moveTo(@NotNull Location loc, double speed) {
+ PathResult path = findPath(loc);
+ return path != null && moveTo(path, speed);
+ default boolean moveTo(Location loc, double speed) {
+ PathResult path = this.findPath(loc);
+ return path != null && this.moveTo(path, speed);
+ }
+
+ /**
+ * Calculates a destination for the Entity to navigate to to reach the target entity,
+ * and sets it with default speed.
+ *
+ * <p>
+ * The behavior of this PathResult is subject to the games pathfinding rules, and may
+ * result in the pathfinding automatically updating to follow the target Entity.
+ *
+ * <p>
+ * However, this behavior is not guaranteed, and is subject to the games behavior.
+ *
+ * @param target the Entity to navigate to
+ * @return If the pathfinding was successfully started
+ */
+ default boolean moveTo(@NotNull LivingEntity target) {
+ return moveTo(target, 1);
+ default boolean moveTo(LivingEntity target) {
+ return this.moveTo(target, 1);
+ }
+
+ /**
+ * Calculates a destination for the Entity to navigate to to reach the target entity,
+ * and sets it with specified speed.
+ *
+ * <p>
+ * The behavior of this PathResult is subject to the games pathfinding rules, and may
+ * result in the pathfinding automatically updating to follow the target Entity.
+ *
+ * <p>
+ * However, this behavior is not guaranteed, and is subject to the games behavior.
+ *
+ * @param target the Entity to navigate to
+ * @param speed Speed multiplier to navigate at, where 1 is 'normal'
+ * @param speed Speed multiplier to navigate at, where 1 is 'normal'
+ * @return If the pathfinding was successfully started
+ */
+ default boolean moveTo(@NotNull LivingEntity target, double speed) {
+ PathResult path = findPath(target);
+ return path != null && moveTo(path, speed);
+ default boolean moveTo(LivingEntity target, double speed) {
+ PathResult path = this.findPath(target);
+ return path != null && this.moveTo(path, speed);
+ }
+
+ /**
@ -142,19 +143,19 @@ index 0000000000000000000000000000000000000000..3c1e2c93d923a683cc0455af77c43784
+ * @param path The Path to start following
+ * @return If the pathfinding was successfully started
+ */
+ default boolean moveTo(@NotNull PathResult path) {
+ return moveTo(path, 1);
+ default boolean moveTo(PathResult path) {
+ return this.moveTo(path, 1);
+ }
+
+ /**
+ * Takes the result of a previous pathfinding calculation and sets it
+ * as the active pathfinding,
+ *
+ * @param path The Path to start following
+ * @param path The Path to start following
+ * @param speed Speed multiplier to navigate at, where 1 is 'normal'
+ * @return If the pathfinding was successfully started
+ */
+ boolean moveTo(@NotNull PathResult path, double speed);
+ boolean moveTo(PathResult path, double speed);
+
+ /**
+ * Checks if this pathfinder allows passing through closed doors.
@ -205,11 +206,11 @@ index 0000000000000000000000000000000000000000..3c1e2c93d923a683cc0455af77c43784
+
+ /**
+ * All currently calculated points to follow along the path to reach the destination location
+ *
+ * <p>
+ * Will return points the entity has already moved past, see {@link #getNextPointIndex()}
+ *
+ * @return List of points
+ */
+ @NotNull
+ List<Location> getPoints();
+
+ /**

View file

@ -12,7 +12,7 @@ Dropped as it does not apply due to the earlier PreCreatureSpawnEvent patch not
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PreSpawnerSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PreSpawnerSpawnEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2910f0bf929d918c86510f29d9361bbc19411256
index 0000000000000000000000000000000000000000..679b37056be9515c69922285affbf0301f5335e3
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/PreSpawnerSpawnEvent.java
@@ -0,0 +1,29 @@
@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..2910f0bf929d918c86510f29d9361bbc
+import org.bukkit.entity.EntityType;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called before an entity is spawned into a world by a spawner.
@ -30,17 +30,17 @@ index 0000000000000000000000000000000000000000..2910f0bf929d918c86510f29d9361bbc
+ * This only includes the spawner's location and not the full BlockState snapshot for performance reasons.
+ * If you really need it you have to get the spawner yourself.
+ */
+@NullMarked
+public class PreSpawnerSpawnEvent extends PreCreatureSpawnEvent {
+
+ @NotNull private final Location spawnerLocation;
+ private final Location spawnerLocation;
+
+ @ApiStatus.Internal
+ public PreSpawnerSpawnEvent(@NotNull Location location, @NotNull EntityType type, @NotNull Location spawnerLocation) {
+ public PreSpawnerSpawnEvent(final Location location, final EntityType type, final Location spawnerLocation) {
+ super(location, type, CreatureSpawnEvent.SpawnReason.SPAWNER);
+ this.spawnerLocation = spawnerLocation;
+ }
+
+ @NotNull
+ public Location getSpawnerLocation() {
+ return this.spawnerLocation.clone();
+ }

View file

@ -6,7 +6,7 @@ Subject: [PATCH] Turtle API
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/TurtleGoHomeEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/TurtleGoHomeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfbc8aaf862ac90e794ee38bf8a6cb9ea414b13e
index 0000000000000000000000000000000000000000..91cede0e53cf6f1089e549053ebc2e2b190a1aab
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleGoHomeEvent.java
@@ -0,0 +1,53 @@
@ -17,11 +17,12 @@ index 0000000000000000000000000000000000000000..cfbc8aaf862ac90e794ee38bf8a6cb9e
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a Turtle decides to go home
+ */
+@NullMarked
+public class TurtleGoHomeEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -29,7 +30,7 @@ index 0000000000000000000000000000000000000000..cfbc8aaf862ac90e794ee38bf8a6cb9e
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public TurtleGoHomeEvent(@NotNull Turtle turtle) {
+ public TurtleGoHomeEvent(final Turtle turtle) {
+ super(turtle);
+ }
+
@ -38,7 +39,7 @@ index 0000000000000000000000000000000000000000..cfbc8aaf862ac90e794ee38bf8a6cb9e
+ *
+ * @return The turtle
+ */
+ @NotNull
+ @Override
+ public Turtle getEntity() {
+ return (Turtle) super.getEntity();
+ }
@ -49,26 +50,25 @@ index 0000000000000000000000000000000000000000..cfbc8aaf862ac90e794ee38bf8a6cb9e
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..3029e406cd684efb5645e38711dff9c0bb7b01e4
index 0000000000000000000000000000000000000000..1492d168aa1dc538b732b0ff262074cc7c9900e6
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java
@@ -0,0 +1,92 @@
@@ -0,0 +1,90 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.Location;
@ -77,23 +77,23 @@ index 0000000000000000000000000000000000000000..3029e406cd684efb5645e38711dff9c0
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a Turtle lays eggs
+ */
+@NullMarked
+public class TurtleLayEggEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull
+ private final Location location;
+ private int eggCount;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public TurtleLayEggEvent(@NotNull Turtle turtle, @NotNull Location location, int eggCount) {
+ public TurtleLayEggEvent(final Turtle turtle, final Location location, final int eggCount) {
+ super(turtle);
+ this.location = location;
+ this.eggCount = eggCount;
@ -104,7 +104,7 @@ index 0000000000000000000000000000000000000000..3029e406cd684efb5645e38711dff9c0
+ *
+ * @return The turtle
+ */
+ @NotNull
+ @Override
+ public Turtle getEntity() {
+ return (Turtle) super.getEntity();
+ }
@ -114,7 +114,6 @@ index 0000000000000000000000000000000000000000..3029e406cd684efb5645e38711dff9c0
+ *
+ * @return Location of eggs
+ */
+ @NotNull
+ public Location getLocation() {
+ return this.location.clone();
+ }
@ -133,7 +132,7 @@ index 0000000000000000000000000000000000000000..3029e406cd684efb5645e38711dff9c0
+ *
+ * @param eggCount Number of eggs
+ */
+ public void setEggCount(int eggCount) {
+ public void setEggCount(final int eggCount) {
+ if (eggCount < 1) {
+ this.cancelled = true;
+ return;
@ -147,26 +146,25 @@ index 0000000000000000000000000000000000000000..3029e406cd684efb5645e38711dff9c0
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a2fa4a11b47e4982d1644830d7e28f12b4378ec
index 0000000000000000000000000000000000000000..a84101fb1b478f3018f283bc47d3e73a7ae5bbc8
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java
@@ -0,0 +1,66 @@
@@ -0,0 +1,65 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.Location;
@ -175,20 +173,21 @@ index 0000000000000000000000000000000000000000..7a2fa4a11b47e4982d1644830d7e28f1
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a Turtle starts digging to lay eggs
+ */
+@NullMarked
+public class TurtleStartDiggingEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Location location;
+ private final Location location;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public TurtleStartDiggingEvent(@NotNull Turtle turtle, @NotNull Location location) {
+ public TurtleStartDiggingEvent(final Turtle turtle, final Location location) {
+ super(turtle);
+ this.location = location;
+ }
@ -198,7 +197,7 @@ index 0000000000000000000000000000000000000000..7a2fa4a11b47e4982d1644830d7e28f1
+ *
+ * @return The turtle
+ */
+ @NotNull
+ @Override
+ public Turtle getEntity() {
+ return (Turtle) super.getEntity();
+ }
@ -208,7 +207,6 @@ index 0000000000000000000000000000000000000000..7a2fa4a11b47e4982d1644830d7e28f1
+ *
+ * @return Location where digging
+ */
+ @NotNull
+ public Location getLocation() {
+ return this.location.clone();
+ }
@ -219,16 +217,15 @@ index 0000000000000000000000000000000000000000..7a2fa4a11b47e4982d1644830d7e28f1
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -8,10 +8,10 @@ Subject: [PATCH] Add spectator target events
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerStartSpectatingEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerStartSpectatingEntityEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..a70a64d2273414d95d77e601a41a208cce78e345
index 0000000000000000000000000000000000000000..5ce2f30c094608cc547d2f2517f0ac2546bab85a
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerStartSpectatingEntityEvent.java
@@ -0,0 +1,71 @@
@@ -0,0 +1,68 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.entity.Entity;
@ -20,22 +20,23 @@ index 0000000000000000000000000000000000000000..a70a64d2273414d95d77e601a41a208c
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Triggered when a player starts spectating an entity in spectator mode.
+ */
+@NullMarked
+public class PlayerStartSpectatingEntityEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Entity currentSpectatorTarget;
+ @NotNull private final Entity newSpectatorTarget;
+ private final Entity currentSpectatorTarget;
+ private final Entity newSpectatorTarget;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerStartSpectatingEntityEvent(@NotNull Player player, @NotNull Entity currentSpectatorTarget, @NotNull Entity newSpectatorTarget) {
+ public PlayerStartSpectatingEntityEvent(final Player player, final Entity currentSpectatorTarget, final Entity newSpectatorTarget) {
+ super(player);
+ this.currentSpectatorTarget = currentSpectatorTarget;
+ this.newSpectatorTarget = newSpectatorTarget;
@ -46,7 +47,6 @@ index 0000000000000000000000000000000000000000..a70a64d2273414d95d77e601a41a208c
+ *
+ * @return The entity the player is currently spectating (before they start spectating the new target).
+ */
+ @NotNull
+ public Entity getCurrentSpectatorTarget() {
+ return this.currentSpectatorTarget;
+ }
@ -56,7 +56,6 @@ index 0000000000000000000000000000000000000000..a70a64d2273414d95d77e601a41a208c
+ *
+ * @return The entity the player is now going to be spectating.
+ */
+ @NotNull
+ public Entity getNewSpectatorTarget() {
+ return this.newSpectatorTarget;
+ }
@ -67,17 +66,15 @@ index 0000000000000000000000000000000000000000..a70a64d2273414d95d77e601a41a208c
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
@ -85,10 +82,10 @@ index 0000000000000000000000000000000000000000..a70a64d2273414d95d77e601a41a208c
+
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerStopSpectatingEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerStopSpectatingEntityEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6a5ebc534cc380740ba42790149c8b85f52aabb
index 0000000000000000000000000000000000000000..ebda87b7914995a28abce844654ee4f5089c416e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerStopSpectatingEntityEvent.java
@@ -0,0 +1,57 @@
@@ -0,0 +1,55 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.entity.Entity;
@ -97,20 +94,21 @@ index 0000000000000000000000000000000000000000..a6a5ebc534cc380740ba42790149c8b8
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Triggered when a player stops spectating an entity in spectator mode.
+ */
+@NullMarked
+public class PlayerStopSpectatingEntityEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Entity spectatorTarget;
+ private final Entity spectatorTarget;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerStopSpectatingEntityEvent(@NotNull Player player, @NotNull Entity spectatorTarget) {
+ public PlayerStopSpectatingEntityEvent(final Player player, final Entity spectatorTarget) {
+ super(player);
+ this.spectatorTarget = spectatorTarget;
+ }
@ -120,7 +118,6 @@ index 0000000000000000000000000000000000000000..a6a5ebc534cc380740ba42790149c8b8
+ *
+ * @return The entity the player is currently spectating (before they will stop).
+ */
+ @NotNull
+ public Entity getSpectatorTarget() {
+ return this.spectatorTarget;
+ }
@ -131,17 +128,15 @@ index 0000000000000000000000000000000000000000..a6a5ebc534cc380740ba42790149c8b8
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -35,21 +35,20 @@ is undefined.
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..d0fb13adc140f1ca74d0c3448f92baa60684f3e2
index 0000000000000000000000000000000000000000..5f5afcdb3c9e669ed0e730c720ad91d16b95602c
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java
@@ -0,0 +1,88 @@
@@ -0,0 +1,83 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+import java.net.InetAddress;
+import java.util.UUID;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * <p>
@ -76,16 +75,17 @@ index 0000000000000000000000000000000000000000..d0fb13adc140f1ca74d0c3448f92baa6
+ * The event may be invoked asynchronously or synchronously. Plugins should check
+ * {@link Event#isAsynchronous()} and handle accordingly.
+ */
+@NullMarked
+public class PlayerConnectionCloseEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final UUID playerUniqueId;
+ @NotNull private final String playerName;
+ @NotNull private final InetAddress ipAddress;
+ private final UUID playerUniqueId;
+ private final String playerName;
+ private final InetAddress ipAddress;
+
+ @ApiStatus.Internal
+ public PlayerConnectionCloseEvent(@NotNull final UUID playerUniqueId, @NotNull final String playerName, @NotNull final InetAddress ipAddress, final boolean async) {
+ public PlayerConnectionCloseEvent(final UUID playerUniqueId, final String playerName, final InetAddress ipAddress, final boolean async) {
+ super(async);
+ this.playerUniqueId = playerUniqueId;
+ this.playerName = playerName;
@ -95,7 +95,6 @@ index 0000000000000000000000000000000000000000..d0fb13adc140f1ca74d0c3448f92baa6
+ /**
+ * Returns the {@code UUID} of the player disconnecting.
+ */
+ @NotNull
+ public UUID getPlayerUniqueId() {
+ return this.playerUniqueId;
+ }
@ -103,7 +102,6 @@ index 0000000000000000000000000000000000000000..d0fb13adc140f1ca74d0c3448f92baa6
+ /**
+ * Returns the name of the player disconnecting.
+ */
+ @NotNull
+ public String getPlayerName() {
+ return this.playerName;
+ }
@ -111,18 +109,15 @@ index 0000000000000000000000000000000000000000..d0fb13adc140f1ca74d0c3448f92baa6
+ /**
+ * Returns the player's IP address.
+ */
+ @NotNull
+ public InetAddress getIpAddress() {
+ return this.ipAddress;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -12,10 +12,10 @@ This can replace many uses of BlockPhysicsEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java b/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0742b58ca2c098c27394915b624889ece1a9168
index 0000000000000000000000000000000000000000..122ccdef02c292c5705a6ac0a96e6095d28bd7bf
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java
@@ -0,0 +1,122 @@
@@ -0,0 +1,120 @@
+package com.destroystokyo.paper.event.block;
+
+import org.bukkit.block.Block;
@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..c0742b58ca2c098c27394915b624889e
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.block.BlockExpEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired anytime the server intends to 'destroy' a block through some triggering reason.
@ -36,11 +36,12 @@ index 0000000000000000000000000000000000000000..c0742b58ca2c098c27394915b624889e
+ * <p>
+ * Events such as leaves decaying, pistons retracting (where the block is moving), does NOT fire this event.
+ */
+@NullMarked
+public class BlockDestroyEvent extends BlockExpEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final BlockData newState;
+ private final BlockData newState;
+ private boolean willDrop;
+ private boolean playEffect = true;
+ private BlockData effectBlock;
@ -48,7 +49,7 @@ index 0000000000000000000000000000000000000000..c0742b58ca2c098c27394915b624889e
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public BlockDestroyEvent(@NotNull Block block, @NotNull BlockData newState, @NotNull BlockData effectBlock, int xp, boolean willDrop) {
+ public BlockDestroyEvent(final Block block, final BlockData newState, final BlockData effectBlock, final int xp, final boolean willDrop) {
+ super(block, xp);
+ this.newState = newState;
+ this.effectBlock = effectBlock;
@ -60,7 +61,6 @@ index 0000000000000000000000000000000000000000..c0742b58ca2c098c27394915b624889e
+ *
+ * @return block break effect
+ */
+ @NotNull
+ public BlockData getEffectBlock() {
+ return this.effectBlock;
+ }
@ -72,14 +72,14 @@ index 0000000000000000000000000000000000000000..c0742b58ca2c098c27394915b624889e
+ *
+ * @param effectBlock block effect
+ */
+ public void setEffectBlock(@NotNull BlockData effectBlock) {
+ public void setEffectBlock(final BlockData effectBlock) {
+ this.effectBlock = effectBlock;
+ }
+
+ /**
+ * @return The new state of this block (Air, or a Fluid type)
+ */
+ public @NotNull BlockData getNewState() {
+ public BlockData getNewState() {
+ return this.newState.clone();
+ }
+
@ -93,7 +93,7 @@ index 0000000000000000000000000000000000000000..c0742b58ca2c098c27394915b624889e
+ /**
+ * @param willDrop If the server is going to drop the block in question with this destroy event
+ */
+ public void setWillDrop(boolean willDrop) {
+ public void setWillDrop(final boolean willDrop) {
+ this.willDrop = willDrop;
+ }
+
@ -107,7 +107,7 @@ index 0000000000000000000000000000000000000000..c0742b58ca2c098c27394915b624889e
+ /**
+ * @param playEffect If the server should play the sound effect for this destruction
+ */
+ public void setPlayEffect(boolean playEffect) {
+ public void setPlayEffect(final boolean playEffect) {
+ this.playEffect = playEffect;
+ }
+
@ -123,17 +123,15 @@ index 0000000000000000000000000000000000000000..c0742b58ca2c098c27394915b624889e
+ * If the event is cancelled, the block will remain in its previous state.
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,22 +6,23 @@ Subject: [PATCH] Add WhitelistToggleEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/server/WhitelistToggleEvent.java b/src/main/java/com/destroystokyo/paper/event/server/WhitelistToggleEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..22fa169c278639f31aec2695259963038de0af8a
index 0000000000000000000000000000000000000000..b9a59a28c1dec6c174885892ff40d3caaaf409a4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/WhitelistToggleEvent.java
@@ -0,0 +1,43 @@
@@ -0,0 +1,42 @@
+package com.destroystokyo.paper.event.server;
+
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * This event is fired when whitelist is toggled
+ *
+ * @author Mark Vainomaa
+ */
+@NullMarked
+public class WhitelistToggleEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -29,7 +30,7 @@ index 0000000000000000000000000000000000000000..22fa169c278639f31aec269525996303
+ private final boolean enabled;
+
+ @ApiStatus.Internal
+ public WhitelistToggleEvent(boolean enabled) {
+ public WhitelistToggleEvent(final boolean enabled) {
+ this.enabled = enabled;
+ }
+
@ -42,13 +43,11 @@ index 0000000000000000000000000000000000000000..22fa169c278639f31aec269525996303
+ return this.enabled;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,25 +6,25 @@ Subject: [PATCH] Add GS4 Query event
diff --git a/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097291978a6
index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd70c7a3d96
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java
@@ -0,0 +1,424 @@
@@ -0,0 +1,395 @@
+package com.destroystokyo.paper.event.server;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import org.bukkit.Server;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import org.bukkit.Server;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * This event is fired if server is getting queried over GS4 Query protocol.
@ -33,6 +33,7 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @author Mark Vainomaa
+ */
+@NullMarked
+public final class GS4QueryEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -42,7 +43,7 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ private QueryResponse response;
+
+ @ApiStatus.Internal
+ public GS4QueryEvent(@NotNull QueryType queryType, @NotNull InetAddress querierAddress, @NotNull QueryResponse response) {
+ public GS4QueryEvent(final QueryType queryType, final InetAddress querierAddress, final QueryResponse response) {
+ super(true); // should always be called async
+ this.queryType = queryType;
+ this.querierAddress = querierAddress;
@ -54,7 +55,6 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return query type
+ */
+ @NotNull
+ public QueryType getQueryType() {
+ return this.queryType;
+ }
@ -64,7 +64,6 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return querier address
+ */
+ @NotNull
+ public InetAddress getQuerierAddress() {
+ return this.querierAddress;
+ }
@ -74,7 +73,6 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return query response
+ */
+ @NotNull
+ public QueryResponse getResponse() {
+ return this.response;
+ }
@ -84,17 +82,15 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @param response query response
+ */
+ public void setResponse(@NotNull QueryResponse response) {
+ public void setResponse(final QueryResponse response) {
+ this.response = Preconditions.checkNotNull(response, "response");
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
@ -115,7 +111,7 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ FULL
+ }
+
+ public final static class QueryResponse {
+ public static final class QueryResponse {
+
+ private final String motd;
+ private final String gameVersion;
@ -128,7 +124,7 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ private final String serverVersion;
+ private final Collection<PluginInformation> plugins;
+
+ private QueryResponse(String motd, String gameVersion, String map, int currentPlayers, int maxPlayers, String hostname, int port, Collection<String> players, String serverVersion, Collection<PluginInformation> plugins) {
+ private QueryResponse(final String motd, final String gameVersion, final String map, final int currentPlayers, final int maxPlayers, final String hostname, final int port, final Collection<String> players, final String serverVersion, final Collection<PluginInformation> plugins) {
+ this.motd = motd;
+ this.gameVersion = gameVersion;
+ this.map = map;
@ -142,21 +138,19 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ }
+
+ /**
+ * Get motd which will be used to reply to the query. By default it is {@link Server#getMotd()}.
+ * Get motd which will be used to reply to the query. By default, it is {@link Server#getMotd()}.
+ *
+ * @return motd
+ */
+ @NotNull
+ public String getMotd() {
+ return this.motd;
+ }
+
+ /**
+ * Get game version which will be used to reply to the query. By default supported Minecraft versions range is sent.
+ * Get game version which will be used to reply to the query. By default, supported Minecraft versions range is sent.
+ *
+ * @return game version
+ */
+ @NotNull
+ public String getGameVersion() {
+ return this.gameVersion;
+ }
@ -166,7 +160,6 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return map name
+ */
+ @NotNull
+ public String getMap() {
+ return this.map;
+ }
@ -194,7 +187,6 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return server hostname
+ */
+ @NotNull
+ public String getHostname() {
+ return this.hostname;
+ }
@ -213,7 +205,6 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return collection of players
+ */
+ @NotNull
+ public Collection<String> getPlayers() {
+ return this.players;
+ }
@ -223,7 +214,6 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return server software
+ */
+ @NotNull
+ public String getServerVersion() {
+ return this.serverVersion;
+ }
@ -233,7 +223,6 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return collection of plugins
+ */
+ @NotNull
+ public Collection<PluginInformation> getPlugins() {
+ return this.plugins;
+ }
@ -243,19 +232,18 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return {@link QueryResponse} builder
+ */
+ @NotNull
+ public Builder toBuilder() {
+ return QueryResponse.builder()
+ .motd(getMotd())
+ .gameVersion(getGameVersion())
+ .map(getMap())
+ .currentPlayers(getCurrentPlayers())
+ .maxPlayers(getMaxPlayers())
+ .hostname(getHostname())
+ .port(getPort())
+ .players(getPlayers())
+ .serverVersion(getServerVersion())
+ .plugins(getPlugins());
+ .motd(this.getMotd())
+ .gameVersion(this.getGameVersion())
+ .map(this.getMap())
+ .currentPlayers(this.getCurrentPlayers())
+ .maxPlayers(this.getMaxPlayers())
+ .hostname(this.getHostname())
+ .port(this.getPort())
+ .players(this.getPlayers())
+ .serverVersion(this.getServerVersion())
+ .plugins(this.getPlugins());
+ }
+
+ /**
@ -263,7 +251,6 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return {@link QueryResponse} builder
+ */
+ @NotNull
+ public static Builder builder() {
+ return new Builder();
+ }
@ -272,11 +259,12 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ * A builder for {@link QueryResponse} objects.
+ */
+ public static final class Builder {
+ private String motd;
+ private String gameVersion;
+ private String map;
+ private String hostname;
+ private String serverVersion;
+
+ private @MonotonicNonNull String motd;
+ private @MonotonicNonNull String gameVersion;
+ private @MonotonicNonNull String map;
+ private @MonotonicNonNull String hostname;
+ private @MonotonicNonNull String serverVersion;
+
+ private int currentPlayers;
+ private int maxPlayers;
@ -285,90 +273,77 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ private final List<String> players = new ArrayList<>();
+ private final List<PluginInformation> plugins = new ArrayList<>();
+
+ private Builder() {}
+ private Builder() {
+ }
+
+ @NotNull
+ public Builder motd(@NotNull String motd) {
+ public Builder motd(final String motd) {
+ this.motd = Preconditions.checkNotNull(motd, "motd");
+ return this;
+ }
+
+ @NotNull
+ public Builder gameVersion(@NotNull String gameVersion) {
+ public Builder gameVersion(final String gameVersion) {
+ this.gameVersion = Preconditions.checkNotNull(gameVersion, "gameVersion");
+ return this;
+ }
+
+ @NotNull
+ public Builder map(@NotNull String map) {
+ public Builder map(final String map) {
+ this.map = Preconditions.checkNotNull(map, "map");
+ return this;
+ }
+
+ @NotNull
+ public Builder currentPlayers(int currentPlayers) {
+ public Builder currentPlayers(final int currentPlayers) {
+ Preconditions.checkArgument(currentPlayers >= 0, "currentPlayers cannot be negative");
+ this.currentPlayers = currentPlayers;
+ return this;
+ }
+
+ @NotNull
+ public Builder maxPlayers(int maxPlayers) {
+ public Builder maxPlayers(final int maxPlayers) {
+ Preconditions.checkArgument(maxPlayers >= 0, "maxPlayers cannot be negative");
+ this.maxPlayers = maxPlayers;
+ return this;
+ }
+
+ @NotNull
+ public Builder hostname(@NotNull String hostname) {
+ public Builder hostname(final String hostname) {
+ this.hostname = Preconditions.checkNotNull(hostname, "hostname");
+ return this;
+ }
+
+ @NotNull
+ public Builder port(int port) {
+ public Builder port(final int port) {
+ Preconditions.checkArgument(port >= 1 && port <= 65535, "port must be between 1-65535");
+ this.port = port;
+ return this;
+ }
+
+ @NotNull
+ public Builder players(@NotNull Collection<String> players) {
+ public Builder players(final Collection<String> players) {
+ this.players.addAll(Preconditions.checkNotNull(players, "players"));
+ return this;
+ }
+
+ @NotNull
+ public Builder players(@NotNull String... players) {
+ public Builder players(final String... players) {
+ this.players.addAll(Arrays.asList(Preconditions.checkNotNull(players, "players")));
+ return this;
+ }
+
+ @NotNull
+ public Builder clearPlayers() {
+ this.players.clear();
+ return this;
+ }
+
+ @NotNull
+ public Builder serverVersion(@NotNull String serverVersion) {
+ public Builder serverVersion(final String serverVersion) {
+ this.serverVersion = Preconditions.checkNotNull(serverVersion, "serverVersion");
+ return this;
+ }
+
+ @NotNull
+ public Builder plugins(@NotNull Collection<PluginInformation> plugins) {
+ public Builder plugins(final Collection<PluginInformation> plugins) {
+ this.plugins.addAll(Preconditions.checkNotNull(plugins, "plugins"));
+ return this;
+ }
+
+ @NotNull
+ public Builder plugins(@NotNull PluginInformation... plugins) {
+ public Builder plugins(final PluginInformation... plugins) {
+ this.plugins.addAll(Arrays.asList(Preconditions.checkNotNull(plugins, "plugins")));
+ return this;
+ }
+
+ @NotNull
+ public Builder clearPlugins() {
+ this.plugins.clear();
+ return this;
@ -379,19 +354,18 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ *
+ * @return response
+ */
+ @NotNull
+ public QueryResponse build() {
+ return new QueryResponse(
+ Preconditions.checkNotNull(motd, "motd"),
+ Preconditions.checkNotNull(gameVersion, "gameVersion"),
+ Preconditions.checkNotNull(map, "map"),
+ currentPlayers,
+ maxPlayers,
+ Preconditions.checkNotNull(hostname, "hostname"),
+ port,
+ ImmutableList.copyOf(players),
+ Preconditions.checkNotNull(serverVersion, "serverVersion"),
+ ImmutableList.copyOf(plugins)
+ Preconditions.checkNotNull(this.motd, "motd"),
+ Preconditions.checkNotNull(this.gameVersion, "gameVersion"),
+ Preconditions.checkNotNull(this.map, "map"),
+ this.currentPlayers,
+ this.maxPlayers,
+ Preconditions.checkNotNull(this.hostname, "hostname"),
+ this.port,
+ ImmutableList.copyOf(this.players),
+ Preconditions.checkNotNull(this.serverVersion, "serverVersion"),
+ ImmutableList.copyOf(this.plugins)
+ );
+ }
+ }
@ -404,31 +378,28 @@ index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097
+ private String name;
+ private String version;
+
+ public PluginInformation(@NotNull String name, @NotNull String version) {
+ public PluginInformation(final String name, final String version) {
+ this.name = Preconditions.checkNotNull(name, "name");
+ this.version = Preconditions.checkNotNull(version, "version");
+ }
+
+ @NotNull
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(@NotNull String name) {
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public void setVersion(@NotNull String version) {
+ public void setVersion(final String version) {
+ this.version = version;
+ }
+
+ @NotNull
+ public String getVersion() {
+ return this.version;
+ }
+
+ @NotNull
+ public static PluginInformation of(@NotNull String name, @NotNull String version) {
+ public static PluginInformation of(final String name, final String version) {
+ return new PluginInformation(name, version);
+ }
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add PlayerPostRespawnEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerPostRespawnEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerPostRespawnEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..16961aac061e78fb84029f8435ab5f7c493b1362
index 0000000000000000000000000000000000000000..e82446ec3d706c47ac9a544f70d0c19b658665d5
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerPostRespawnEvent.java
@@ -0,0 +1,56 @@
@@ -0,0 +1,54 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.Location;
@ -17,20 +17,21 @@ index 0000000000000000000000000000000000000000..16961aac061e78fb84029f8435ab5f7c
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired after a player has respawned
+ */
+@NullMarked
+public class PlayerPostRespawnEvent extends PlayerEvent {
+
+ private final static HandlerList HANDLER_LIST = new HandlerList();
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final Location respawnedLocation;
+ private final boolean isBedSpawn;
+
+ @ApiStatus.Internal
+ public PlayerPostRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnedLocation, final boolean isBedSpawn) {
+ public PlayerPostRespawnEvent(final Player respawnPlayer, final Location respawnedLocation, final boolean isBedSpawn) {
+ super(respawnPlayer);
+ this.respawnedLocation = respawnedLocation;
+ this.isBedSpawn = isBedSpawn;
@ -41,7 +42,6 @@ index 0000000000000000000000000000000000000000..16961aac061e78fb84029f8435ab5f7c
+ *
+ * @return location of the respawned player
+ */
+ @NotNull
+ public Location getRespawnedLocation() {
+ return this.respawnedLocation.clone();
+ }
@ -56,12 +56,10 @@ index 0000000000000000000000000000000000000000..16961aac061e78fb84029f8435ab5f7c
+ }
+
+ @Override
+ @NotNull
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -7,7 +7,7 @@ Fires event at start and end of a server tick
diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerTickEndEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerTickEndEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..17e9f39ce1cc7489e936c96f95b8b0579528b222
index 0000000000000000000000000000000000000000..c879588693c930226049e60393f2f23aad1588b9
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/ServerTickEndEvent.java
@@ -0,0 +1,62 @@
@ -16,11 +16,12 @@ index 0000000000000000000000000000000000000000..17e9f39ce1cc7489e936c96f95b8b057
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when the server has finished ticking the main loop
+ */
+@NullMarked
+public class ServerTickEndEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -30,7 +31,7 @@ index 0000000000000000000000000000000000000000..17e9f39ce1cc7489e936c96f95b8b057
+ private final long timeEnd;
+
+ @ApiStatus.Internal
+ public ServerTickEndEvent(int tickNumber, double tickDuration, long timeRemaining) {
+ public ServerTickEndEvent(final int tickNumber, final double tickDuration, final long timeRemaining) {
+ this.tickNumber = tickNumber;
+ this.tickDuration = tickDuration;
+ this.timeEnd = System.nanoTime() + timeRemaining;
@ -63,19 +64,18 @@ index 0000000000000000000000000000000000000000..17e9f39ce1cc7489e936c96f95b8b057
+ return this.timeEnd - System.nanoTime();
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb5bbfffea8b883e4c8769484a2b64dd895cb617
index 0000000000000000000000000000000000000000..890153657ea5b756a8a3a038d6b53857e0d17fea
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java
@@ -0,0 +1,35 @@
@ -84,8 +84,9 @@ index 0000000000000000000000000000000000000000..fb5bbfffea8b883e4c8769484a2b64dd
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public class ServerTickStartEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -93,7 +94,7 @@ index 0000000000000000000000000000000000000000..fb5bbfffea8b883e4c8769484a2b64dd
+ private final int tickNumber;
+
+ @ApiStatus.Internal
+ public ServerTickStartEvent(int tickNumber) {
+ public ServerTickStartEvent(final int tickNumber) {
+ this.tickNumber = tickNumber;
+ }
+
@ -104,12 +105,11 @@ index 0000000000000000000000000000000000000000..fb5bbfffea8b883e4c8769484a2b64dd
+ return this.tickNumber;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -8,10 +8,10 @@ Adds a new event similar to PlayerEggThrowEvent, but without the Player requirem
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/ThrownEggHatchEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/ThrownEggHatchEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..092bab9be36acc0f04c7ea5b3510879169a0a125
index 0000000000000000000000000000000000000000..26526049a4c7f7ebe6bea27a9c5a638df3ef8854
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/ThrownEggHatchEvent.java
@@ -0,0 +1,120 @@
@@ -0,0 +1,117 @@
+package com.destroystokyo.paper.event.entity;
+
+import com.google.common.base.Preconditions;
@ -20,13 +20,14 @@ index 0000000000000000000000000000000000000000..092bab9be36acc0f04c7ea5b35108791
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a thrown egg might hatch.
+ * <p>
+ * This event fires for all thrown eggs that may hatch, players, dispensers, etc.
+ */
+@NullMarked
+public class ThrownEggHatchEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -37,7 +38,7 @@ index 0000000000000000000000000000000000000000..092bab9be36acc0f04c7ea5b35108791
+ private EntityType hatchType;
+
+ @ApiStatus.Internal
+ public ThrownEggHatchEvent(@NotNull final Egg egg, final boolean hatching, final byte numHatches, @NotNull final EntityType hatchingType) {
+ public ThrownEggHatchEvent(final Egg egg, final boolean hatching, final byte numHatches, final EntityType hatchingType) {
+ this.egg = egg;
+ this.hatching = hatching;
+ this.numHatches = numHatches;
@ -49,7 +50,6 @@ index 0000000000000000000000000000000000000000..092bab9be36acc0f04c7ea5b35108791
+ *
+ * @return the egg involved in this event
+ */
+ @NotNull
+ public Egg getEgg() {
+ return this.egg;
+ }
@ -68,9 +68,9 @@ index 0000000000000000000000000000000000000000..092bab9be36acc0f04c7ea5b35108791
+ * Sets whether the egg will hatch or not.
+ *
+ * @param hatching {@code true} if you want the egg to hatch, {@code false} if you want it
+ * not to
+ * not to
+ */
+ public void setHatching(boolean hatching) {
+ public void setHatching(final boolean hatching) {
+ this.hatching = hatching;
+ }
+
@ -79,7 +79,6 @@ index 0000000000000000000000000000000000000000..092bab9be36acc0f04c7ea5b35108791
+ *
+ * @return The type of the mob being hatched by the egg
+ */
+ @NotNull
+ public EntityType getHatchingType() {
+ return this.hatchType;
+ }
@ -89,13 +88,13 @@ index 0000000000000000000000000000000000000000..092bab9be36acc0f04c7ea5b35108791
+ *
+ * @param hatchType The type of the mob being hatched by the egg
+ */
+ public void setHatchingType(@NotNull EntityType hatchType) {
+ public void setHatchingType(final EntityType hatchType) {
+ Preconditions.checkArgument(hatchType.isSpawnable(), "Can't spawn that entity type from an egg!");
+ this.hatchType = hatchType;
+ }
+
+ /**
+ * Get the number of mob hatches from the egg. By default the number will
+ * Get the number of mob hatches from the egg. By default, the number will
+ * be the number the server would've done
+ * <ul>
+ * <li>7/8 chance of being 0
@ -117,17 +116,15 @@ index 0000000000000000000000000000000000000000..092bab9be36acc0f04c7ea5b35108791
+ *
+ * @param numHatches The number of mobs coming out of the egg
+ */
+ public void setNumHatches(byte numHatches) {
+ public void setNumHatches(final byte numHatches) {
+ this.numHatches = numHatches;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,7 +6,7 @@ Subject: [PATCH] Entity Jump API
diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityJumpEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityJumpEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6306c957fcacdcbcc8037b4ee33a167d21ff29e
index 0000000000000000000000000000000000000000..b49b72608573ad5b98fc6e0070f6ef105bf177e4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityJumpEvent.java
@@ -0,0 +1,50 @@
@ -17,13 +17,14 @@ index 0000000000000000000000000000000000000000..a6306c957fcacdcbcc8037b4ee33a167
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when an entity jumps
+ * <p>
+ * Cancelling the event will stop the entity from jumping
+ */
+@NullMarked
+public class EntityJumpEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -31,31 +32,30 @@ index 0000000000000000000000000000000000000000..a6306c957fcacdcbcc8037b4ee33a167
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EntityJumpEvent(@NotNull LivingEntity entity) {
+ public EntityJumpEvent(final LivingEntity entity) {
+ super(entity);
+ }
+
+ @NotNull
+ @Override
+ public LivingEntity getEntity() {
+ return (LivingEntity) super.getEntity();
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ public void setCancelled(boolean cancel) {
+ @Override
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,18 +6,18 @@ Subject: [PATCH] Add Player Client Options API
diff --git a/src/main/java/com/destroystokyo/paper/ClientOption.java b/src/main/java/com/destroystokyo/paper/ClientOption.java
new file mode 100644
index 0000000000000000000000000000000000000000..f89bfeba29e6988db849957a508ca97ff5322242
index 0000000000000000000000000000000000000000..ed08f823e0620289392f7fc2ff0ac721cff60478
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/ClientOption.java
@@ -0,0 +1,52 @@
@@ -0,0 +1,51 @@
+package com.destroystokyo.paper;
+
+import net.kyori.adventure.translation.Translatable;
+import net.kyori.adventure.util.Index;
+import org.jetbrains.annotations.NotNull;
+
+import org.bukkit.inventory.MainHand;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public final class ClientOption<T> {
+
+ public static final ClientOption<SkinParts> SKIN_PARTS = new ClientOption<>(SkinParts.class);
@ -31,13 +31,12 @@ index 0000000000000000000000000000000000000000..f89bfeba29e6988db849957a508ca97f
+
+ private final Class<T> type;
+
+ private ClientOption(@NotNull Class<T> type) {
+ private ClientOption(final Class<T> type) {
+ this.type = type;
+ }
+
+ @NotNull
+ public Class<T> getType() {
+ return type;
+ return this.type;
+ }
+
+ public enum ChatVisibility implements Translatable {
@ -46,15 +45,15 @@ index 0000000000000000000000000000000000000000..f89bfeba29e6988db849957a508ca97f
+ HIDDEN("hidden"),
+ UNKNOWN("unknown");
+
+ public static Index<String, ChatVisibility> NAMES = Index.create(ChatVisibility.class, chatVisibility -> chatVisibility.name);
+ public static final Index<String, ChatVisibility> NAMES = Index.create(ChatVisibility.class, chatVisibility -> chatVisibility.name);
+ private final String name;
+
+ ChatVisibility(String name) {
+ ChatVisibility(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public @NotNull String translationKey() {
+ public String translationKey() {
+ if (this == UNKNOWN) {
+ throw new UnsupportedOperationException(this.name + " doesn't have a translation key");
+ }
@ -90,27 +89,27 @@ index 0000000000000000000000000000000000000000..4a0c39405d4fbed457787e3c6ded4cc6
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerClientOptionsChangeEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerClientOptionsChangeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..1757055d821d9ec7c728aa6c1b52fa6aea591ae5
index 0000000000000000000000000000000000000000..6cf6aa876278d0d3e75148608951fc5865ad5aee
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerClientOptionsChangeEvent.java
@@ -0,0 +1,136 @@
@@ -0,0 +1,130 @@
+package com.destroystokyo.paper.event.player;
+
+import com.destroystokyo.paper.ClientOption;
+import com.destroystokyo.paper.ClientOption.ChatVisibility;
+import com.destroystokyo.paper.SkinParts;
+import java.util.Map;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.MainHand;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when the player changes their client settings
+ */
+@NullMarked
+public class PlayerClientOptionsChangeEvent extends PlayerEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -125,7 +124,7 @@ index 0000000000000000000000000000000000000000..1757055d821d9ec7c728aa6c1b52fa6a
+ private final boolean textFilteringEnabled;
+
+ @Deprecated
+ public PlayerClientOptionsChangeEvent(@NotNull Player player, @NotNull String locale, int viewDistance, @NotNull ChatVisibility chatVisibility, boolean chatColors, @NotNull SkinParts skinParts, @NotNull MainHand mainHand) {
+ public PlayerClientOptionsChangeEvent(final Player player, final String locale, final int viewDistance, final ChatVisibility chatVisibility, final boolean chatColors, final SkinParts skinParts, final MainHand mainHand) {
+ super(player);
+ this.locale = locale;
+ this.viewDistance = viewDistance;
@ -138,7 +137,7 @@ index 0000000000000000000000000000000000000000..1757055d821d9ec7c728aa6c1b52fa6a
+ }
+
+ @ApiStatus.Internal
+ public PlayerClientOptionsChangeEvent(@NotNull Player player, @NotNull Map<ClientOption<?>, ?> options) {
+ public PlayerClientOptionsChangeEvent(final Player player, final Map<ClientOption<?>, ?> options) {
+ super(player);
+
+ this.locale = (String) options.get(ClientOption.LOCALE);
@ -151,7 +150,6 @@ index 0000000000000000000000000000000000000000..1757055d821d9ec7c728aa6c1b52fa6a
+ this.textFilteringEnabled = (boolean) options.get(ClientOption.TEXT_FILTERING_ENABLED);
+ }
+
+ @NotNull
+ public String getLocale() {
+ return this.locale;
+ }
@ -168,7 +166,6 @@ index 0000000000000000000000000000000000000000..1757055d821d9ec7c728aa6c1b52fa6a
+ return this.viewDistance != this.player.getClientOption(ClientOption.VIEW_DISTANCE);
+ }
+
+ @NotNull
+ public ChatVisibility getChatVisibility() {
+ return this.chatVisibility;
+ }
@ -185,7 +182,6 @@ index 0000000000000000000000000000000000000000..1757055d821d9ec7c728aa6c1b52fa6a
+ return this.chatColors != this.player.getClientOption(ClientOption.CHAT_COLORS_ENABLED);
+ }
+
+ @NotNull
+ public SkinParts getSkinParts() {
+ return this.skinparts;
+ }
@ -194,7 +190,6 @@ index 0000000000000000000000000000000000000000..1757055d821d9ec7c728aa6c1b52fa6a
+ return this.skinparts.getRaw() != this.player.getClientOption(ClientOption.SKIN_PARTS).getRaw();
+ }
+
+ @NotNull
+ public MainHand getMainHand() {
+ return this.mainHand;
+ }
@ -220,12 +215,10 @@ index 0000000000000000000000000000000000000000..1757055d821d9ec7c728aa6c1b52fa6a
+ }
+
+ @Override
+ @NotNull
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,7 +6,7 @@ Subject: [PATCH] Add PlayerAttackEntityCooldownResetEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerAttackEntityCooldownResetEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerAttackEntityCooldownResetEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ceaff1a499d08575ddcdcbead8e2cef6cfbea47
index 0000000000000000000000000000000000000000..2cd5c9c344cacbabe64dae8ec87babb506b5fb09
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerAttackEntityCooldownResetEvent.java
@@ -0,0 +1,77 @@
@ -18,22 +18,23 @@ index 0000000000000000000000000000000000000000..5ceaff1a499d08575ddcdcbead8e2cef
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when processing a player's attack on an entity when the player's attack strength cooldown is reset
+ */
+@NullMarked
+public class PlayerAttackEntityCooldownResetEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private final Entity attackedEntity;
+ private final Entity attackedEntity;
+ private final float cooledAttackStrength;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerAttackEntityCooldownResetEvent(@NotNull Player player, @NotNull Entity attackedEntity, float cooledAttackStrength) {
+ public PlayerAttackEntityCooldownResetEvent(final Player player, final Entity attackedEntity, final float cooledAttackStrength) {
+ super(player);
+ this.attackedEntity = attackedEntity;
+ this.cooledAttackStrength = cooledAttackStrength;
@ -53,7 +54,6 @@ index 0000000000000000000000000000000000000000..5ceaff1a499d08575ddcdcbead8e2cef
+ *
+ * @return the entity attacked by the player
+ */
+ @NotNull
+ public Entity getAttackedEntity() {
+ return this.attackedEntity;
+ }
@ -74,16 +74,16 @@ index 0000000000000000000000000000000000000000..5ceaff1a499d08575ddcdcbead8e2cef
+ * Cancelling this event will prevent the target player from having their cooldown reset from attacking this entity
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static @NotNull HandlerList getHandlerList() {
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}

View file

@ -6,21 +6,20 @@ Subject: [PATCH] Add Mob Goal API
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java
new file mode 100644
index 0000000000000000000000000000000000000000..c57c5416c88e2070a082403ab0dda9d7f08d2a57
index 0000000000000000000000000000000000000000..88f64a84c6b81246a4936e37c9f0410eefc847fd
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java
@@ -0,0 +1,66 @@
@@ -0,0 +1,63 @@
+package com.destroystokyo.paper.entity.ai;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EnumSet;
+
+import org.bukkit.entity.Mob;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents an AI goal of an entity
+ */
+@NullMarked
+public interface Goal<T extends Mob> {
+
+ /**
@ -36,7 +35,7 @@ index 0000000000000000000000000000000000000000..c57c5416c88e2070a082403ab0dda9d7
+ * @return if this goal should stay active
+ */
+ default boolean shouldStayActive() {
+ return shouldActivate();
+ return this.shouldActivate();
+ }
+
+ /**
@ -63,86 +62,79 @@ index 0000000000000000000000000000000000000000..c57c5416c88e2070a082403ab0dda9d7
+ *
+ * @return the goal key
+ */
+ @NotNull
+ GoalKey<T> getKey();
+
+ /**
+ * Returns a list of all applicable flags for this goal.<br>
+ *
+ * <p>
+ * This method is only called on construction.
+ *
+ * @return the subtypes.
+ */
+ @NotNull
+ EnumSet<GoalType> getTypes();
+}
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cd98c6fcfa3eb439d9013ef76ef4661175a0e5a
index 0000000000000000000000000000000000000000..fb626065c642a3f43075f2ae751419e23431763c
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java
@@ -0,0 +1,64 @@
@@ -0,0 +1,59 @@
+package com.destroystokyo.paper.entity.ai;
+
+import com.google.common.base.Objects;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.StringJoiner;
+
+import org.bukkit.NamespacedKey;
+import org.bukkit.entity.Mob;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ *
+ * Used to identify a Goal. Consists of a {@link NamespacedKey} and the type of mob the goal can be applied to
+ *
+ * @param <T> the type of mob the goal can be applied to
+ */
+public class GoalKey<T extends Mob> {
+@NullMarked
+public final class GoalKey<T extends Mob> {
+
+ private final Class<T> entityClass;
+ private final NamespacedKey namespacedKey;
+
+ private GoalKey(@NotNull Class<T> entityClass, @NotNull NamespacedKey namespacedKey) {
+ private GoalKey(Class<T> entityClass, NamespacedKey namespacedKey) {
+ this.entityClass = entityClass;
+ this.namespacedKey = namespacedKey;
+ }
+
+ @NotNull
+ public Class<T> getEntityClass() {
+ return entityClass;
+ return this.entityClass;
+ }
+
+ @NotNull
+ public NamespacedKey getNamespacedKey() {
+ return namespacedKey;
+ return this.namespacedKey;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (o == null || this.getClass() != o.getClass()) return false;
+ GoalKey<?> goalKey = (GoalKey<?>) o;
+ return Objects.equal(entityClass, goalKey.entityClass) &&
+ Objects.equal(namespacedKey, goalKey.namespacedKey);
+ return Objects.equal(this.entityClass, goalKey.entityClass) &&
+ Objects.equal(this.namespacedKey, goalKey.namespacedKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(entityClass, namespacedKey);
+ return Objects.hashCode(this.entityClass, this.namespacedKey);
+ }
+
+ @Override
+ public String toString() {
+ return new StringJoiner(", ", GoalKey.class.getSimpleName() + "[", "]")
+ .add("entityClass=" + entityClass)
+ .add("namespacedKey=" + namespacedKey)
+ .add("entityClass=" + this.entityClass)
+ .add("namespacedKey=" + this.namespacedKey)
+ .toString();
+ }
+
+ @NotNull
+ public static <A extends Mob> GoalKey<A> of(@NotNull Class<A> entityClass, @NotNull NamespacedKey namespacedKey) {
+ public static <A extends Mob> GoalKey<A> of(Class<A> entityClass, NamespacedKey namespacedKey) {
+ return new GoalKey<>(entityClass, namespacedKey);
+ }
+}
@ -171,59 +163,51 @@ index 0000000000000000000000000000000000000000..7024c8f484d2460abf3abfe65a29771d
+}
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java
new file mode 100644
index 0000000000000000000000000000000000000000..e21f7574763dd4f13794f91bbef192ef66a8f5e9
index 0000000000000000000000000000000000000000..0203e7efbb8c729ed378c53c2630a523b697314f
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java
@@ -0,0 +1,50 @@
@@ -0,0 +1,42 @@
+package com.destroystokyo.paper.entity.ai;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+import org.bukkit.entity.Mob;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Represents a part of the "brain" of a mob. It tracks all tasks (running or not), allows adding and removing goals
+ */
+@NullMarked
+public interface MobGoals {
+
+ <T extends Mob> void addGoal(@NotNull T mob, int priority, @NotNull Goal<T> goal);
+ <T extends Mob> void addGoal(T mob, int priority, Goal<T> goal);
+
+ <T extends Mob> void removeGoal(@NotNull T mob, @NotNull Goal<T> goal);
+ <T extends Mob> void removeGoal(T mob, Goal<T> goal);
+
+ <T extends Mob> void removeAllGoals(@NotNull T mob);
+ <T extends Mob> void removeAllGoals(T mob);
+
+ <T extends Mob> void removeAllGoals(@NotNull T mob, @NotNull GoalType type);
+ <T extends Mob> void removeAllGoals(T mob, GoalType type);
+
+ <T extends Mob> void removeGoal(@NotNull T mob, @NotNull GoalKey<T> key);
+ <T extends Mob> void removeGoal(T mob, GoalKey<T> key);
+
+ <T extends Mob> boolean hasGoal(@NotNull T mob, @NotNull GoalKey<T> key);
+ <T extends Mob> boolean hasGoal(T mob, GoalKey<T> key);
+
+ @Nullable
+ <T extends Mob> Goal<T> getGoal(@NotNull T mob, @NotNull GoalKey<T> key);
+ <T extends Mob> @Nullable Goal<T> getGoal(T mob, GoalKey<T> key);
+
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getGoals(@NotNull T mob, @NotNull GoalKey<T> key);
+ <T extends Mob> Collection<Goal<T>> getGoals(T mob, GoalKey<T> key);
+
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getAllGoals(@NotNull T mob);
+ <T extends Mob> Collection<Goal<T>> getAllGoals(T mob);
+
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getAllGoals(@NotNull T mob, @NotNull GoalType type);
+ <T extends Mob> Collection<Goal<T>> getAllGoals(T mob, GoalType type);
+
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getAllGoalsWithout(@NotNull T mob, @NotNull GoalType type);
+ <T extends Mob> Collection<Goal<T>> getAllGoalsWithout(T mob, GoalType type);
+
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(@NotNull T mob);
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob);
+
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(@NotNull T mob, @NotNull GoalType type);
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob, GoalType type);
+
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getRunningGoalsWithout(@NotNull T mob, @NotNull GoalType type);
+ <T extends Mob> Collection<Goal<T>> getRunningGoalsWithout(T mob, GoalType type);
+}
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
index 54626b927444ab3fc6b7d9ac9e326ff368b0cd25..1a671331ec4ab21430d7d52e9a4f45510ef39944 100644

View file

@ -6,31 +6,30 @@ Subject: [PATCH] Add villager reputation API
diff --git a/src/main/java/com/destroystokyo/paper/entity/villager/Reputation.java b/src/main/java/com/destroystokyo/paper/entity/villager/Reputation.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a69e21b0b3001c9cc50951b4b8bd593f6fa74be
index 0000000000000000000000000000000000000000..cbbf70507c2df922e75b686c36500f6f85f92db6
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/villager/Reputation.java
@@ -0,0 +1,57 @@
@@ -0,0 +1,56 @@
+package com.destroystokyo.paper.entity.villager;
+
+import com.google.common.base.Preconditions;
+
+import java.util.EnumMap;
+import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A reputation score for a player on a villager.
+ */
+@NullMarked
+public final class Reputation {
+
+ @NotNull
+ private final Map<ReputationType, Integer> reputation;
+
+ public Reputation() {
+ this(new EnumMap<>(ReputationType.class));
+ }
+
+ public Reputation(@NotNull Map<ReputationType, Integer> reputation) {
+ public Reputation(final Map<ReputationType, Integer> reputation) {
+ Preconditions.checkNotNull(reputation, "reputation cannot be null");
+ this.reputation = reputation;
+ }
@ -41,7 +40,7 @@ index 0000000000000000000000000000000000000000..0a69e21b0b3001c9cc50951b4b8bd593
+ * @param type The {@link ReputationType type} of reputation to get.
+ * @return The value of the {@link ReputationType type}.
+ */
+ public int getReputation(@NotNull ReputationType type) {
+ public int getReputation(final ReputationType type) {
+ Preconditions.checkNotNull(type, "the reputation type cannot be null");
+ return this.reputation.getOrDefault(type, 0);
+ }
@ -52,7 +51,7 @@ index 0000000000000000000000000000000000000000..0a69e21b0b3001c9cc50951b4b8bd593
+ * @param type The {@link ReputationType type} of reputation to set.
+ * @param value The value of the {@link ReputationType type}.
+ */
+ public void setReputation(@NotNull ReputationType type, int value) {
+ public void setReputation(final ReputationType type, final int value) {
+ Preconditions.checkNotNull(type, "the reputation type cannot be null");
+ this.reputation.put(type, value);
+ }
@ -63,7 +62,7 @@ index 0000000000000000000000000000000000000000..0a69e21b0b3001c9cc50951b4b8bd593
+ * @param type The {@link ReputationType type} to check
+ * @return If there is a value for this {@link ReputationType type} set.
+ */
+ public boolean hasReputationSet(@NotNull ReputationType type) {
+ public boolean hasReputationSet(final ReputationType type) {
+ return this.reputation.containsKey(type);
+ }
+}

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add and implement PlayerRecipeBookClickEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerRecipeBookClickEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerRecipeBookClickEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..c38ac6d0e0ac4ecbdc73d2bedd7731ff34c9d192
index 0000000000000000000000000000000000000000..a7becccb2cf3b72744fcac4efa52d7c61e607765
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerRecipeBookClickEvent.java
@@ -0,0 +1,89 @@
@@ -0,0 +1,87 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.NamespacedKey;
@ -18,22 +18,23 @@ index 0000000000000000000000000000000000000000..c38ac6d0e0ac4ecbdc73d2bedd7731ff
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a player clicks a recipe in the recipe book
+ */
+@NullMarked
+public class PlayerRecipeBookClickEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull private NamespacedKey recipe;
+ private NamespacedKey recipe;
+ private boolean makeAll;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerRecipeBookClickEvent(@NotNull Player player, @NotNull NamespacedKey recipe, boolean makeAll) {
+ public PlayerRecipeBookClickEvent(final Player player, final NamespacedKey recipe, final boolean makeAll) {
+ super(player);
+ this.recipe = recipe;
+ this.makeAll = makeAll;
@ -44,7 +45,6 @@ index 0000000000000000000000000000000000000000..c38ac6d0e0ac4ecbdc73d2bedd7731ff
+ *
+ * @return The namespaced key of the recipe
+ */
+ @NotNull
+ public NamespacedKey getRecipe() {
+ return this.recipe;
+ }
@ -54,7 +54,7 @@ index 0000000000000000000000000000000000000000..c38ac6d0e0ac4ecbdc73d2bedd7731ff
+ *
+ * @param recipe The key of the recipe that should be requested
+ */
+ public void setRecipe(@NotNull NamespacedKey recipe) {
+ public void setRecipe(final NamespacedKey recipe) {
+ this.recipe = recipe;
+ }
+
@ -74,7 +74,7 @@ index 0000000000000000000000000000000000000000..c38ac6d0e0ac4ecbdc73d2bedd7731ff
+ *
+ * @param makeAll {@code true} if the request should attempt to make the maximum amount of results
+ */
+ public void setMakeAll(boolean makeAll) {
+ public void setMakeAll(final boolean makeAll) {
+ this.makeAll = makeAll;
+ }
+
@ -84,17 +84,15 @@ index 0000000000000000000000000000000000000000..c38ac6d0e0ac4ecbdc73d2bedd7731ff
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -48,28 +48,29 @@ index 0000000000000000000000000000000000000000..f75933948cdf0aa0c9bb2f06da5418f1
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/inventory/PrepareResultEvent.java b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareResultEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..c305c606bef93866993095cec5f50e191c5a382a
index 0000000000000000000000000000000000000000..8ca7858613bb78ee1f9453b55fc38e00414fefb5
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareResultEvent.java
@@ -0,0 +1,40 @@
@@ -0,0 +1,42 @@
+package com.destroystokyo.paper.event.inventory;
+
+import org.bukkit.event.inventory.PrepareInventoryResultEvent;
+import org.bukkit.inventory.InventoryView;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Called when an item is put in an inventory containing a result slot
+ */
+@NullMarked
+public class PrepareResultEvent extends PrepareInventoryResultEvent {
+
+ // HandlerList on PrepareInventoryResultEvent to ensure api compat
+
+ @ApiStatus.Internal
+ public PrepareResultEvent(@NotNull InventoryView inventory, @Nullable ItemStack result) {
+ public PrepareResultEvent(final InventoryView inventory, final @Nullable ItemStack result) {
+ super(inventory, result);
+ }
+
@ -78,8 +79,8 @@ index 0000000000000000000000000000000000000000..c305c606bef93866993095cec5f50e19
+ *
+ * @return result item
+ */
+ @Nullable
+ public ItemStack getResult() {
+ @Override
+ public @Nullable ItemStack getResult() {
+ return super.getResult();
+ }
+
@ -88,7 +89,8 @@ index 0000000000000000000000000000000000000000..c305c606bef93866993095cec5f50e19
+ *
+ * @param result result item
+ */
+ public void setResult(@Nullable ItemStack result) {
+ @Override
+ public void setResult(final @Nullable ItemStack result) {
+ super.setResult(result);
+ }
+}

View file

@ -6,17 +6,17 @@ Subject: [PATCH] Add moon phase API
diff --git a/src/main/java/io/papermc/paper/world/MoonPhase.java b/src/main/java/io/papermc/paper/world/MoonPhase.java
new file mode 100644
index 0000000000000000000000000000000000000000..df05153397b42930cd53d37b30824c7e5f008f7e
index 0000000000000000000000000000000000000000..0b24e1a92bba4fed0ca2d4336a3b8351a800f93a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/world/MoonPhase.java
@@ -0,0 +1,36 @@
@@ -0,0 +1,35 @@
+package io.papermc.paper.world;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public enum MoonPhase {
+ FULL_MOON(0L),
+ WANING_GIBBOUS(1L),
@ -29,20 +29,19 @@ index 0000000000000000000000000000000000000000..df05153397b42930cd53d37b30824c7e
+
+ private final long day;
+
+ MoonPhase(long day) {
+ MoonPhase(final long day) {
+ this.day = day;
+ }
+
+ private static final Map<Long, MoonPhase> BY_DAY = new HashMap<>();
+
+ static {
+ for (MoonPhase phase : values()) {
+ for (final MoonPhase phase : values()) {
+ BY_DAY.put(phase.day, phase);
+ }
+ }
+
+ @NotNull
+ public static MoonPhase getPhase(long day) {
+ public static MoonPhase getPhase(final long day) {
+ return BY_DAY.get(day % 8L);
+ }
+}

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add PlayerItemCooldownEvent
diff --git a/src/main/java/io/papermc/paper/event/player/PlayerItemCooldownEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerItemCooldownEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..c2764ffd51831351b934568e1301b2e4073dc0c4
index 0000000000000000000000000000000000000000..07b3a93ea09f0ae7d0e7a5af3633a0c669d36fcf
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/PlayerItemCooldownEvent.java
@@ -0,0 +1,82 @@
@@ -0,0 +1,79 @@
+package io.papermc.paper.event.player;
+
+import com.google.common.base.Preconditions;
@ -19,23 +19,23 @@ index 0000000000000000000000000000000000000000..c2764ffd51831351b934568e1301b2e4
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Fired when a player receives an item cooldown.
+ */
+@NullMarked
+public class PlayerItemCooldownEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull
+ private final Material type;
+ private int cooldown;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerItemCooldownEvent(@NotNull Player player, @NotNull Material type, int cooldown) {
+ public PlayerItemCooldownEvent(final Player player, final Material type, final int cooldown) {
+ super(player);
+ this.type = type;
+ this.cooldown = cooldown;
@ -46,7 +46,6 @@ index 0000000000000000000000000000000000000000..c2764ffd51831351b934568e1301b2e4
+ *
+ * @return material affected by the cooldown
+ */
+ @NotNull
+ public Material getType() {
+ return this.type;
+ }
@ -66,7 +65,7 @@ index 0000000000000000000000000000000000000000..c2764ffd51831351b934568e1301b2e4
+ *
+ * @param cooldown cooldown in ticks, has to be a positive number
+ */
+ public void setCooldown(int cooldown) {
+ public void setCooldown(final int cooldown) {
+ Preconditions.checkArgument(cooldown >= 0, "The cooldown has to be equal to or greater than 0!");
+ this.cooldown = cooldown;
+ }
@ -77,17 +76,15 @@ index 0000000000000000000000000000000000000000..c2764ffd51831351b934568e1301b2e4
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,12 +6,13 @@ Subject: [PATCH] Add PlayerShearBlockEvent
diff --git a/src/main/java/io/papermc/paper/event/block/PlayerShearBlockEvent.java b/src/main/java/io/papermc/paper/event/block/PlayerShearBlockEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bb4a79320eac7d662d9d04765664b6a7e955a4f
index 0000000000000000000000000000000000000000..33c6e1868e1bad4802bcadecebc2b46633690fce
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/block/PlayerShearBlockEvent.java
@@ -0,0 +1,113 @@
@@ -0,0 +1,107 @@
+package io.papermc.paper.event.block;
+
+import java.util.List;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
@ -20,9 +21,7 @@ index 0000000000000000000000000000000000000000..9bb4a79320eac7d662d9d04765664b6a
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a player uses sheers on a block.
@ -32,6 +31,7 @@ index 0000000000000000000000000000000000000000..9bb4a79320eac7d662d9d04765664b6a
+ * <p>
+ * Examples include shearing a pumpkin to turn it into a carved pumpkin or shearing a beehive to get honeycomb.
+ */
+@NullMarked
+public class PlayerShearBlockEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -44,7 +44,7 @@ index 0000000000000000000000000000000000000000..9bb4a79320eac7d662d9d04765664b6a
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerShearBlockEvent(@NotNull Player player, @NotNull Block block, @NotNull ItemStack item, @NotNull EquipmentSlot hand, @NotNull List<ItemStack> drops) {
+ public PlayerShearBlockEvent(final Player player, final Block block, final ItemStack item, final EquipmentSlot hand, final List<ItemStack> drops) {
+ super(player);
+ this.block = block;
+ this.item = item;
@ -57,7 +57,6 @@ index 0000000000000000000000000000000000000000..9bb4a79320eac7d662d9d04765664b6a
+ *
+ * @return The {@link Block} which block is being sheared in this event.
+ */
+ @NotNull
+ public Block getBlock() {
+ return this.block;
+ }
@ -67,7 +66,6 @@ index 0000000000000000000000000000000000000000..9bb4a79320eac7d662d9d04765664b6a
+ *
+ * @return The {@link ItemStack} of the shears.
+ */
+ @NotNull
+ public ItemStack getItem() {
+ return this.item;
+ }
@ -77,7 +75,6 @@ index 0000000000000000000000000000000000000000..9bb4a79320eac7d662d9d04765664b6a
+ *
+ * @return Either {@link EquipmentSlot#HAND} OR {@link EquipmentSlot#OFF_HAND}.
+ */
+ @NotNull
+ public EquipmentSlot getHand() {
+ return this.hand;
+ }
@ -85,9 +82,8 @@ index 0000000000000000000000000000000000000000..9bb4a79320eac7d662d9d04765664b6a
+ /**
+ * Gets the resulting drops of this event.
+ *
+ * @return A {@link List list} of {@link ItemStack items} that will be dropped as result of this event.
+ * @return A mutable {@link List list} of {@link ItemStack items} that will be dropped as result of this event.
+ */
+ @NotNull
+ public List<ItemStack> getDrops() {
+ return this.drops;
+ }
@ -108,17 +104,15 @@ index 0000000000000000000000000000000000000000..9bb4a79320eac7d662d9d04765664b6a
+ * @param cancel whether the shearing of the block should be cancelled or not.
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Player Chunk Load/Unload Events
diff --git a/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java b/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ddbc099a13df939b3912f30b54e7635840ba5a4
index 0000000000000000000000000000000000000000..2815c5802eb38e5a48f9db42b9247e24c27db134
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java
@@ -0,0 +1,45 @@
@@ -0,0 +1,43 @@
+package io.papermc.paper.event.packet;
+
+import org.bukkit.Chunk;
@ -17,7 +17,7 @@ index 0000000000000000000000000000000000000000..3ddbc099a13df939b3912f30b54e7635
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.world.ChunkEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Is called when a {@link Player} receives a {@link Chunk}
@ -27,6 +27,7 @@ index 0000000000000000000000000000000000000000..3ddbc099a13df939b3912f30b54e7635
+ * Should only be used for packet/clientside related stuff.
+ * Not intended for modifying server side state.
+ */
+@NullMarked
+public class PlayerChunkLoadEvent extends ChunkEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -34,33 +35,30 @@ index 0000000000000000000000000000000000000000..3ddbc099a13df939b3912f30b54e7635
+ private final Player player;
+
+ @ApiStatus.Internal
+ public PlayerChunkLoadEvent(@NotNull Chunk chunk, @NotNull Player player) {
+ public PlayerChunkLoadEvent(final Chunk chunk, final Player player) {
+ super(chunk);
+ this.player = player;
+ }
+
+ @NotNull
+ public Player getPlayer() {
+ return this.player;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java b/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2cac7e27991c04a9ced261f2dd8ad8657ccddf6b
index 0000000000000000000000000000000000000000..3ebb35b680193109cc751398675e935eed746750
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java
@@ -0,0 +1,43 @@
@@ -0,0 +1,41 @@
+package io.papermc.paper.event.packet;
+
+import org.bukkit.Chunk;
@ -68,7 +66,7 @@ index 0000000000000000000000000000000000000000..2cac7e27991c04a9ced261f2dd8ad865
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.world.ChunkEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Is called when a {@link Player} receives a chunk unload packet.
@ -76,6 +74,7 @@ index 0000000000000000000000000000000000000000..2cac7e27991c04a9ced261f2dd8ad865
+ * Should only be used for packet/clientside related stuff.
+ * Not intended for modifying server side.
+ */
+@NullMarked
+public class PlayerChunkUnloadEvent extends ChunkEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -83,23 +82,20 @@ index 0000000000000000000000000000000000000000..2cac7e27991c04a9ced261f2dd8ad865
+ private final Player player;
+
+ @ApiStatus.Internal
+ public PlayerChunkUnloadEvent(@NotNull Chunk chunk, @NotNull Player player) {
+ public PlayerChunkUnloadEvent(final Chunk chunk, final Player player) {
+ super(chunk);
+ this.player = player;
+ }
+
+ @NotNull
+ public Player getPlayer() {
+ return this.player;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -13,10 +13,10 @@ event being about villager trades.
diff --git a/src/main/java/io/papermc/paper/event/player/PlayerPurchaseEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerPurchaseEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..61c62877c38e27eacc20aa43ef02dc43e9b50bfc
index 0000000000000000000000000000000000000000..1691b53f157f17117116e841cbfc769ea0e14364
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/PlayerPurchaseEvent.java
@@ -0,0 +1,109 @@
@@ -0,0 +1,104 @@
+package io.papermc.paper.event.player;
+
+import com.google.common.base.Preconditions;
@ -26,11 +26,12 @@ index 0000000000000000000000000000000000000000..61c62877c38e27eacc20aa43ef02dc43
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.MerchantRecipe;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a player trades with a standalone merchant GUI.
+ */
+@NullMarked
+public class PlayerPurchaseEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -42,12 +43,9 @@ index 0000000000000000000000000000000000000000..61c62877c38e27eacc20aa43ef02dc43
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerPurchaseEvent(@NotNull Player player,
+ @NotNull MerchantRecipe trade,
+ boolean rewardExp,
+ boolean increaseTradeUses) {
+ public PlayerPurchaseEvent(final Player player, final MerchantRecipe trade, final boolean rewardExp, final boolean increaseTradeUses) {
+ super(player);
+ setTrade(trade);
+ this.trade = trade;
+ this.rewardExp = rewardExp;
+ this.increaseTradeUses = increaseTradeUses;
+ }
@ -57,7 +55,6 @@ index 0000000000000000000000000000000000000000..61c62877c38e27eacc20aa43ef02dc43
+ *
+ * @return the trade
+ */
+ @NotNull
+ public MerchantRecipe getTrade() {
+ return this.trade;
+ }
@ -67,7 +64,7 @@ index 0000000000000000000000000000000000000000..61c62877c38e27eacc20aa43ef02dc43
+ *
+ * @param trade the trade to use
+ */
+ public void setTrade(@NotNull MerchantRecipe trade) {
+ public void setTrade(final MerchantRecipe trade) {
+ Preconditions.checkArgument(trade != null, "Trade cannot be null!");
+ this.trade = trade;
+ }
@ -84,7 +81,7 @@ index 0000000000000000000000000000000000000000..61c62877c38e27eacc20aa43ef02dc43
+ *
+ * @param rewardExp try to reward exp
+ */
+ public void setRewardExp(boolean rewardExp) {
+ public void setRewardExp(final boolean rewardExp) {
+ this.rewardExp = rewardExp;
+ }
+
@ -100,7 +97,7 @@ index 0000000000000000000000000000000000000000..61c62877c38e27eacc20aa43ef02dc43
+ *
+ * @param increaseTradeUses {@code true} to count, {@code false} otherwise
+ */
+ public void setIncreaseTradeUses(boolean increaseTradeUses) {
+ public void setIncreaseTradeUses(final boolean increaseTradeUses) {
+ this.increaseTradeUses = increaseTradeUses;
+ }
+
@ -110,17 +107,15 @@ index 0000000000000000000000000000000000000000..61c62877c38e27eacc20aa43ef02dc43
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
@ -128,7 +123,7 @@ index 0000000000000000000000000000000000000000..61c62877c38e27eacc20aa43ef02dc43
+}
diff --git a/src/main/java/io/papermc/paper/event/player/PlayerTradeEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerTradeEvent.java
new file mode 100755
index 0000000000000000000000000000000000000000..559d1a3c783e6c726f48d1c88b2ff8c0888890ac
index 0000000000000000000000000000000000000000..46bdc178c19feb7dbb71eebee6d0774cf16c1042
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/PlayerTradeEvent.java
@@ -0,0 +1,32 @@
@ -138,17 +133,18 @@ index 0000000000000000000000000000000000000000..559d1a3c783e6c726f48d1c88b2ff8c0
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.MerchantRecipe;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a player trades with a villager or wandering trader
+ */
+@NullMarked
+public class PlayerTradeEvent extends PlayerPurchaseEvent {
+
+ private final AbstractVillager villager;
+
+ @ApiStatus.Internal
+ public PlayerTradeEvent(@NotNull Player player, @NotNull AbstractVillager villager, @NotNull MerchantRecipe trade, boolean rewardExp, boolean increaseTradeUses) {
+ public PlayerTradeEvent(final Player player, final AbstractVillager villager, final MerchantRecipe trade, final boolean rewardExp, final boolean increaseTradeUses) {
+ super(player, trade, rewardExp, increaseTradeUses);
+ this.villager = villager;
+ }
@ -158,7 +154,6 @@ index 0000000000000000000000000000000000000000..559d1a3c783e6c726f48d1c88b2ff8c0
+ *
+ * @return the villager or wandering trader
+ */
+ @NotNull
+ public AbstractVillager getVillager() {
+ return this.villager;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add TargetHitEvent API
diff --git a/src/main/java/io/papermc/paper/event/block/TargetHitEvent.java b/src/main/java/io/papermc/paper/event/block/TargetHitEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..5247e7f78e0076089c1e1bdea2afbb455c43732a
index 0000000000000000000000000000000000000000..6555bf7f4485eacd8d35113d5b21b73f0693a950
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/block/TargetHitEvent.java
@@ -0,0 +1,61 @@
@@ -0,0 +1,60 @@
+package io.papermc.paper.event.block;
+
+import com.google.common.base.Preconditions;
@ -19,8 +19,8 @@ index 0000000000000000000000000000000000000000..5247e7f78e0076089c1e1bdea2afbb45
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.ProjectileHitEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Range;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a Target Block is hit by a projectile.
@ -29,6 +29,7 @@ index 0000000000000000000000000000000000000000..5247e7f78e0076089c1e1bdea2afbb45
+ * and in the case that the shooter is a player, will stop them from receiving
+ * advancement criteria.
+ */
+@NullMarked
+public class TargetHitEvent extends ProjectileHitEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -36,7 +37,7 @@ index 0000000000000000000000000000000000000000..5247e7f78e0076089c1e1bdea2afbb45
+ private int signalStrength;
+
+ @ApiStatus.Internal
+ public TargetHitEvent(@NotNull Projectile projectile, @NotNull Block block, @NotNull BlockFace blockFace, int signalStrength) {
+ public TargetHitEvent(final Projectile projectile, final Block block, final BlockFace blockFace, final int signalStrength) {
+ super(projectile, null, block, blockFace);
+ this.signalStrength = signalStrength;
+ }
@ -55,18 +56,16 @@ index 0000000000000000000000000000000000000000..5247e7f78e0076089c1e1bdea2afbb45
+ *
+ * @param signalStrength the strength of the redstone signal to be emitted
+ */
+ public void setSignalStrength(@Range(from = 0, to = 15) int signalStrength) {
+ public void setSignalStrength(final @Range(from = 0, to = 15) int signalStrength) {
+ Preconditions.checkArgument(signalStrength >= 0 && signalStrength <= 15, "Signal strength out of range (%s), must be in range [0,15]", signalStrength);
+ this.signalStrength = signalStrength;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add PlayerFlowerPotManipulateEvent
diff --git a/src/main/java/io/papermc/paper/event/player/PlayerFlowerPotManipulateEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerFlowerPotManipulateEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..373a6ec68fb575b82b06bf250768c1a6909efe38
index 0000000000000000000000000000000000000000..03881ae56b3dd68a0aa600382b4689f213ec05f3
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/PlayerFlowerPotManipulateEvent.java
@@ -0,0 +1,85 @@
@@ -0,0 +1,80 @@
+package io.papermc.paper.event.player;
+
+import org.bukkit.block.Block;
@ -19,25 +19,24 @@ index 0000000000000000000000000000000000000000..373a6ec68fb575b82b06bf250768c1a6
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a player places an item in or takes an item out of a flowerpot.
+ */
+@NullMarked
+public class PlayerFlowerPotManipulateEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @NotNull
+ private final Block flowerpot;
+ @NotNull
+ private final ItemStack item;
+ private final boolean placing;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerFlowerPotManipulateEvent(@NotNull final Player player, @NotNull final Block flowerpot, @NotNull final ItemStack item, final boolean placing) {
+ public PlayerFlowerPotManipulateEvent(final Player player, final Block flowerpot, final ItemStack item, final boolean placing) {
+ super(player);
+ this.flowerpot = flowerpot;
+ this.item = item;
@ -49,7 +48,6 @@ index 0000000000000000000000000000000000000000..373a6ec68fb575b82b06bf250768c1a6
+ *
+ * @return the flowerpot that is involved with this event
+ */
+ @NotNull
+ public Block getFlowerpot() {
+ return this.flowerpot;
+ }
@ -60,7 +58,6 @@ index 0000000000000000000000000000000000000000..373a6ec68fb575b82b06bf250768c1a6
+ *
+ * @return the item placed, or taken from, the flowerpot
+ */
+ @NotNull
+ public ItemStack getItem() {
+ return this.item;
+ }
@ -80,17 +77,15 @@ index 0000000000000000000000000000000000000000..373a6ec68fb575b82b06bf250768c1a6
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add EntityLoadCrossbowEvent
diff --git a/src/main/java/io/papermc/paper/event/entity/EntityLoadCrossbowEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityLoadCrossbowEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..8434ea803e3135380f9351c82a414ccb65c478a9
index 0000000000000000000000000000000000000000..f7631a5ac0f2ccfa6b81bea9ab54b30fbb3278dd
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/entity/EntityLoadCrossbowEvent.java
@@ -0,0 +1,96 @@
@@ -0,0 +1,92 @@
+package io.papermc.paper.event.entity;
+
+import org.bukkit.entity.LivingEntity;
@ -19,11 +19,12 @@ index 0000000000000000000000000000000000000000..8434ea803e3135380f9351c82a414ccb
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a LivingEntity loads a crossbow with a projectile.
+ */
+@NullMarked
+public class EntityLoadCrossbowEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -35,13 +36,12 @@ index 0000000000000000000000000000000000000000..8434ea803e3135380f9351c82a414ccb
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EntityLoadCrossbowEvent(@NotNull LivingEntity entity, @NotNull ItemStack crossbow, @NotNull EquipmentSlot hand) {
+ public EntityLoadCrossbowEvent(final LivingEntity entity, final ItemStack crossbow, final EquipmentSlot hand) {
+ super(entity);
+ this.crossbow = crossbow;
+ this.hand = hand;
+ }
+
+ @NotNull
+ @Override
+ public LivingEntity getEntity() {
+ return (LivingEntity) super.getEntity();
@ -52,7 +52,6 @@ index 0000000000000000000000000000000000000000..8434ea803e3135380f9351c82a414ccb
+ *
+ * @return the crossbow involved in this event
+ */
+ @NotNull
+ public ItemStack getCrossbow() {
+ return this.crossbow;
+ }
@ -62,7 +61,6 @@ index 0000000000000000000000000000000000000000..8434ea803e3135380f9351c82a414ccb
+ *
+ * @return the hand
+ */
+ @NotNull
+ public EquipmentSlot getHand() {
+ return this.hand;
+ }
@ -77,7 +75,7 @@ index 0000000000000000000000000000000000000000..8434ea803e3135380f9351c82a414ccb
+ /**
+ * @param consume should the item be consumed
+ */
+ public void setConsumeItem(boolean consume) {
+ public void setConsumeItem(final boolean consume) {
+ this.consumeItem = consume;
+ }
+
@ -91,17 +89,15 @@ index 0000000000000000000000000000000000000000..8434ea803e3135380f9351c82a414ccb
+ * projectile that would be loaded into the crossbow will not be consumed.
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Added WorldGameRuleChangeEvent
diff --git a/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java b/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2831fb8ad22e457f85523f65be9cba2432109f01
index 0000000000000000000000000000000000000000..4d259e31c4b1bb01318c727d8e340b6b23084067
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java
@@ -0,0 +1,92 @@
@@ -0,0 +1,88 @@
+package io.papermc.paper.event.world;
+
+import org.bukkit.GameRule;
@ -19,23 +19,24 @@ index 0000000000000000000000000000000000000000..2831fb8ad22e457f85523f65be9cba24
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.world.WorldEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Called when a world's gamerule is changed, either by command or by api.
+ */
+@NullMarked
+public class WorldGameRuleChangeEvent extends WorldEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final CommandSender commandSender;
+ private final @Nullable CommandSender commandSender;
+ private final GameRule<?> gameRule;
+ private String value;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public WorldGameRuleChangeEvent(@NotNull World world, @Nullable CommandSender commandSender, @NotNull GameRule<?> gameRule, @NotNull String value) {
+ public WorldGameRuleChangeEvent(final World world, final @Nullable CommandSender commandSender, final GameRule<?> gameRule, final String value) {
+ super(world);
+ this.commandSender = commandSender;
+ this.gameRule = gameRule;
@ -47,8 +48,7 @@ index 0000000000000000000000000000000000000000..2831fb8ad22e457f85523f65be9cba24
+ *
+ * @return {@code null} if the gamerule was changed via api, otherwise the {@link CommandSender}.
+ */
+ @Nullable
+ public CommandSender getCommandSender() {
+ public @Nullable CommandSender getCommandSender() {
+ return this.commandSender;
+ }
+
@ -57,7 +57,6 @@ index 0000000000000000000000000000000000000000..2831fb8ad22e457f85523f65be9cba24
+ *
+ * @return the gamerule being changed.
+ */
+ @NotNull
+ public GameRule<?> getGameRule() {
+ return this.gameRule;
+ }
@ -67,7 +66,6 @@ index 0000000000000000000000000000000000000000..2831fb8ad22e457f85523f65be9cba24
+ *
+ * @return the new value of the gamerule.
+ */
+ @NotNull
+ public String getValue() {
+ return this.value;
+ }
@ -77,7 +75,7 @@ index 0000000000000000000000000000000000000000..2831fb8ad22e457f85523f65be9cba24
+ *
+ * @param value the new value of the gamerule.
+ */
+ public void setValue(@NotNull String value) {
+ public void setValue(final String value) {
+ this.value = value;
+ }
+
@ -87,17 +85,15 @@ index 0000000000000000000000000000000000000000..2831fb8ad22e457f85523f65be9cba24
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,22 +6,23 @@ Subject: [PATCH] Added ServerResourcesReloadedEvent
diff --git a/src/main/java/io/papermc/paper/event/server/ServerResourcesReloadedEvent.java b/src/main/java/io/papermc/paper/event/server/ServerResourcesReloadedEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7ed7d6b6469e175d3949ffa9c502cbfde609215
index 0000000000000000000000000000000000000000..468bbfcaa3fed60dc73726f4e5ace93009f92507
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/server/ServerResourcesReloadedEvent.java
@@ -0,0 +1,49 @@
@@ -0,0 +1,47 @@
+package io.papermc.paper.event.server;
+
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.server.ServerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when resources such as datapacks are reloaded (e.g. /minecraft:reload)
+ * <p>
+ * Intended for use to re-register custom recipes, advancements that may be lost during a reload like this.
+ */
+@NullMarked
+public class ServerResourcesReloadedEvent extends ServerEvent {
+
+ public static final HandlerList HANDLER_LIST = new HandlerList();
@ -29,7 +30,7 @@ index 0000000000000000000000000000000000000000..a7ed7d6b6469e175d3949ffa9c502cbf
+ private final Cause cause;
+
+ @ApiStatus.Internal
+ public ServerResourcesReloadedEvent(@NotNull Cause cause) {
+ public ServerResourcesReloadedEvent(final Cause cause) {
+ this.cause = cause;
+ }
+
@ -38,17 +39,14 @@ index 0000000000000000000000000000000000000000..a7ed7d6b6469e175d3949ffa9c502cbf
+ *
+ * @return the reload cause
+ */
+ @NotNull
+ public Cause getCause() {
+ return this.cause;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;

View file

@ -6,21 +6,22 @@ Subject: [PATCH] Add BlockFailedDispenseEvent
diff --git a/src/main/java/io/papermc/paper/event/block/BlockFailedDispenseEvent.java b/src/main/java/io/papermc/paper/event/block/BlockFailedDispenseEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..d531b034b49b163e5095e840a5c9c4fe5eb73319
index 0000000000000000000000000000000000000000..483139950f80588ae13204a624b9d60c44fac730
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/block/BlockFailedDispenseEvent.java
@@ -0,0 +1,56 @@
@@ -0,0 +1,57 @@
+package io.papermc.paper.event.block;
+
+import org.bukkit.block.Block;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.block.BlockEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a block tries to dispense an item, but its inventory is empty.
+ */
+@NullMarked
+public class BlockFailedDispenseEvent extends BlockEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -28,7 +29,7 @@ index 0000000000000000000000000000000000000000..d531b034b49b163e5095e840a5c9c4fe
+ private boolean shouldPlayEffect = true;
+
+ @ApiStatus.Internal
+ public BlockFailedDispenseEvent(@NotNull Block theBlock) {
+ public BlockFailedDispenseEvent(final Block theBlock) {
+ super(theBlock);
+ }
+
@ -44,7 +45,7 @@ index 0000000000000000000000000000000000000000..d531b034b49b163e5095e840a5c9c4fe
+ *
+ * @param playEffect if the effect should be played
+ */
+ public void shouldPlayEffect(boolean playEffect) {
+ public void shouldPlayEffect(final boolean playEffect) {
+ this.shouldPlayEffect = playEffect;
+ }
+
@ -58,11 +59,11 @@ index 0000000000000000000000000000000000000000..d531b034b49b163e5095e840a5c9c4fe
+ }
+
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static @NotNull HandlerList getHandlerList() {
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Added PlayerLecternPageChangeEvent
diff --git a/src/main/java/io/papermc/paper/event/player/PlayerLecternPageChangeEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerLecternPageChangeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..6ed2a6c8c033937d933b6d4834953b8112a98bb3
index 0000000000000000000000000000000000000000..6126182db48dab1286924f9642fb259087efabb3
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/PlayerLecternPageChangeEvent.java
@@ -0,0 +1,117 @@
@@ -0,0 +1,113 @@
+package io.papermc.paper.event.player;
+
+import org.bukkit.block.Lectern;
@ -19,8 +19,9 @@ index 0000000000000000000000000000000000000000..6ed2a6c8c033937d933b6d4834953b81
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public class PlayerLecternPageChangeEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -34,7 +35,7 @@ index 0000000000000000000000000000000000000000..6ed2a6c8c033937d933b6d4834953b81
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerLecternPageChangeEvent(@NotNull Player player, @NotNull Lectern lectern, @NotNull ItemStack book, @NotNull PageChangeDirection pageChangeDirection, int oldPage, int newPage) {
+ public PlayerLecternPageChangeEvent(final Player player, final Lectern lectern, final ItemStack book, final PageChangeDirection pageChangeDirection, final int oldPage, final int newPage) {
+ super(player);
+ this.lectern = lectern;
+ this.book = book;
@ -48,7 +49,6 @@ index 0000000000000000000000000000000000000000..6ed2a6c8c033937d933b6d4834953b81
+ *
+ * @return the Lectern
+ */
+ @NotNull
+ public Lectern getLectern() {
+ return this.lectern;
+ }
@ -58,7 +58,6 @@ index 0000000000000000000000000000000000000000..6ed2a6c8c033937d933b6d4834953b81
+ *
+ * @return the ItemStack on the Lectern
+ */
+ @NotNull
+ public ItemStack getBook() {
+ return this.book;
+ }
@ -68,7 +67,6 @@ index 0000000000000000000000000000000000000000..6ed2a6c8c033937d933b6d4834953b81
+ *
+ * @return the page change direction
+ */
+ @NotNull
+ public PageChangeDirection getPageChangeDirection() {
+ return this.pageChangeDirection;
+ }
@ -97,7 +95,7 @@ index 0000000000000000000000000000000000000000..6ed2a6c8c033937d933b6d4834953b81
+ *
+ * @param newPage the new paged changed to
+ */
+ public void setNewPage(int newPage) {
+ public void setNewPage(final int newPage) {
+ this.newPage = newPage;
+ }
+
@ -107,17 +105,15 @@ index 0000000000000000000000000000000000000000..6ed2a6c8c033937d933b6d4834953b81
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Added PlayerLoomPatternSelectEvent
diff --git a/src/main/java/io/papermc/paper/event/player/PlayerLoomPatternSelectEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerLoomPatternSelectEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..c614bd1a725adee0c434a9331099d0c35d7411f6
index 0000000000000000000000000000000000000000..5d4a334ba97cc0c17db8a157f2e2fd99dafbdbcc
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/PlayerLoomPatternSelectEvent.java
@@ -0,0 +1,80 @@
@@ -0,0 +1,77 @@
+package io.papermc.paper.event.player;
+
+import org.bukkit.block.banner.PatternType;
@ -19,11 +19,12 @@ index 0000000000000000000000000000000000000000..c614bd1a725adee0c434a9331099d0c3
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.LoomInventory;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a player selects a banner patten in a loom inventory.
+ */
+@NullMarked
+public class PlayerLoomPatternSelectEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -34,7 +35,7 @@ index 0000000000000000000000000000000000000000..c614bd1a725adee0c434a9331099d0c3
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerLoomPatternSelectEvent(@NotNull Player player, @NotNull LoomInventory loomInventory, @NotNull PatternType patternType) {
+ public PlayerLoomPatternSelectEvent(final Player player, final LoomInventory loomInventory, final PatternType patternType) {
+ super(player);
+ this.loomInventory = loomInventory;
+ this.patternType = patternType;
@ -45,7 +46,6 @@ index 0000000000000000000000000000000000000000..c614bd1a725adee0c434a9331099d0c3
+ *
+ * @return the loom inventory
+ */
+ @NotNull
+ public LoomInventory getLoomInventory() {
+ return this.loomInventory;
+ }
@ -55,7 +55,6 @@ index 0000000000000000000000000000000000000000..c614bd1a725adee0c434a9331099d0c3
+ *
+ * @return the pattern type
+ */
+ @NotNull
+ public PatternType getPatternType() {
+ return this.patternType;
+ }
@ -65,7 +64,7 @@ index 0000000000000000000000000000000000000000..c614bd1a725adee0c434a9331099d0c3
+ *
+ * @param patternType the pattern type
+ */
+ public void setPatternType(@NotNull PatternType patternType) {
+ public void setPatternType(final PatternType patternType) {
+ this.patternType = patternType;
+ }
+
@ -75,17 +74,15 @@ index 0000000000000000000000000000000000000000..c614bd1a725adee0c434a9331099d0c3
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -96,23 +96,24 @@ index 0000000000000000000000000000000000000000..f29e76a6b66ddfec12ddf8db6dcb2df6
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryAccess.java b/src/main/java/io/papermc/paper/registry/RegistryAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..86ab67ff5023bf6adea80b02648b6f67476e30e5
index 0000000000000000000000000000000000000000..00a3a4a196808b4b5c84ecccbfb1ea0e3825146a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryAccess.java
@@ -0,0 +1,49 @@
@@ -0,0 +1,50 @@
+package io.papermc.paper.registry;
+
+import org.bukkit.Keyed;
+import org.bukkit.Registry;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Used for accessing different {@link Registry} instances
+ * by a {@link RegistryKey}. Get the main instance of {@link RegistryAccess}
+ * with {@link RegistryAccess#registryAccess()}.
+ */
+@NullMarked
+@ApiStatus.NonExtendable
+public interface RegistryAccess {
+
@ -121,7 +122,7 @@ index 0000000000000000000000000000000000000000..86ab67ff5023bf6adea80b02648b6f67
+ *
+ * @return the RegistryAccess instance
+ */
+ static @NotNull RegistryAccess registryAccess() {
+ static RegistryAccess registryAccess() {
+ return RegistryAccessHolder.INSTANCE.orElseThrow(() -> new IllegalStateException("No RegistryAccess implementation found"));
+ }
+
@ -134,7 +135,7 @@ index 0000000000000000000000000000000000000000..86ab67ff5023bf6adea80b02648b6f67
+ * @deprecated use {@link #getRegistry(RegistryKey)} with keys from {@link RegistryKey}
+ */
+ @Deprecated(since = "1.20.6", forRemoval = true)
+ <T extends Keyed> @Nullable Registry<T> getRegistry(@NotNull Class<T> type);
+ <T extends Keyed> @Nullable Registry<T> getRegistry(Class<T> type);
+
+ /**
+ * Gets the registry with the specified key.
@ -147,7 +148,7 @@ index 0000000000000000000000000000000000000000..86ab67ff5023bf6adea80b02648b6f67
+ */
+ // Future note: We should have no trouble removing this generic qualifier when
+ // registry types no longer have to be "keyed" as it shouldn't break ABI or API.
+ <T extends Keyed> @NotNull Registry<T> getRegistry(@NotNull RegistryKey<T> registryKey);
+ <T extends Keyed> Registry<T> getRegistry(RegistryKey<T> registryKey);
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java b/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java
new file mode 100644
@ -168,16 +169,16 @@ index 0000000000000000000000000000000000000000..b89e19c070f97c9662f1e16309446494
+ }
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
index 791813220b2504214b1adecc69093cd600fb0f8c..47fe5b0d5d031110c27210a0a256c260b35d9ba1 100644
index 80e3e64f47ac55a4978c9e5b430e2f2d1c871d1b..ac68dfce754dc7e014bb31bba32d9b246ffd411c 100644
--- a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
+++ b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
@@ -10,6 +10,17 @@ record RegistryKeyImpl<T>(@NotNull Key key) implements RegistryKey<T> {
@@ -12,6 +12,17 @@ record RegistryKeyImpl<T>(Key key) implements RegistryKey<T> {
static final Set<RegistryKey<?>> REGISTRY_KEYS = Sets.newIdentityHashSet();
+ // override equals and hashCode to this can be used to simulate an "identity" hashmap
+ @Override
+ public boolean equals(final Object obj) {
+ public boolean equals(final @Nullable Object obj) {
+ return obj == this;
+ }
+

View file

@ -7,10 +7,10 @@ Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/io/papermc/paper/event/world/StructuresLocateEvent.java b/src/main/java/io/papermc/paper/event/world/StructuresLocateEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7e8d1edf7
index 0000000000000000000000000000000000000000..d39b3dc48079fc83f1fd8e7ecde0d4ae77b635ce
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/world/StructuresLocateEvent.java
@@ -0,0 +1,176 @@
@@ -0,0 +1,177 @@
+package io.papermc.paper.event.world;
+
+import io.papermc.paper.math.Position;
@ -24,9 +24,9 @@ index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7
+import org.bukkit.generator.structure.Structure;
+import org.bukkit.generator.structure.StructureType;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.UnmodifiableView;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Called <b>before</b> a set of configured structures is located.
@ -41,12 +41,13 @@ index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7
+ * <li>{@link World#locateNearestStructure(Location, Structure, int, boolean)} is invoked.</li>
+ * </ul>
+ */
+@NullMarked
+public class StructuresLocateEvent extends WorldEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final Location origin;
+ private Result result;
+ private @Nullable Result result;
+ private List<Structure> structures;
+ private int radius;
+ private boolean findUnexplored;
@ -54,7 +55,7 @@ index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public StructuresLocateEvent(@NotNull World world, @NotNull Location origin, @NotNull List<Structure> structures, int radius, boolean findUnexplored) {
+ public StructuresLocateEvent(final World world, final Location origin, final List<Structure> structures, final int radius, final boolean findUnexplored) {
+ super(world);
+ this.origin = origin;
+ this.structures = structures;
@ -67,7 +68,7 @@ index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7
+ *
+ * @return {@link Location} where search begins
+ */
+ public @NotNull Location getOrigin() {
+ public Location getOrigin() {
+ return this.origin.clone();
+ }
+
@ -90,7 +91,7 @@ index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7
+ *
+ * @param result the {@link Location} and {@link Structure} of the search.
+ */
+ public void setResult(@Nullable Result result) {
+ public void setResult(final @Nullable Result result) {
+ this.result = result;
+ }
+
@ -99,7 +100,7 @@ index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7
+ *
+ * @return an unmodifiable list of Structures
+ */
+ public @NotNull @UnmodifiableView List<Structure> getStructures() {
+ public @UnmodifiableView List<Structure> getStructures() {
+ return Collections.unmodifiableList(this.structures);
+ }
+
@ -108,7 +109,7 @@ index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7
+ *
+ * @param structures a list of Structures targets
+ */
+ public void setStructures(final @NotNull List<Structure> structures) {
+ public void setStructures(final List<Structure> structures) {
+ this.structures = structures;
+ }
+
@ -130,7 +131,7 @@ index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7
+ *
+ * @param radius the search radius (in chunks)
+ */
+ public void setRadius(int radius) {
+ public void setRadius(final int radius) {
+ this.radius = radius;
+ }
+
@ -152,7 +153,7 @@ index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7
+ *
+ * @param findUnexplored Whether to search for only unexplored structures.
+ */
+ public void setFindUnexplored(boolean findUnexplored) {
+ public void setFindUnexplored(final boolean findUnexplored) {
+ this.findUnexplored = findUnexplored;
+ }
+
@ -162,26 +163,26 @@ index 0000000000000000000000000000000000000000..41ea65c9ecf6339bb50864a6d28e53c7
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static @NotNull HandlerList getHandlerList() {
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+
+ /**
+ * Result for {@link StructuresLocateEvent}.
+ */
+ public record Result(@NotNull Position pos, @NotNull Structure structure) {
+ public record Result(Position pos, Structure structure) {
+
+ @Deprecated(forRemoval = true)
+ public @NotNull Location position() {
+ public Location position() {
+ //noinspection DataFlowIssue
+ return this.pos.toLocation(null);
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add BlockPreDispenseEvent
diff --git a/src/main/java/io/papermc/paper/event/block/BlockPreDispenseEvent.java b/src/main/java/io/papermc/paper/event/block/BlockPreDispenseEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..62547d5853e7355a805fa1e7f1e5f56d06fca4ba
index 0000000000000000000000000000000000000000..2e13e18e2b8411dfb7886663de7125330a65fa62
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/block/BlockPreDispenseEvent.java
@@ -0,0 +1,65 @@
@@ -0,0 +1,64 @@
+package io.papermc.paper.event.block;
+
+import org.bukkit.block.Block;
@ -18,8 +18,9 @@ index 0000000000000000000000000000000000000000..62547d5853e7355a805fa1e7f1e5f56d
+import org.bukkit.event.block.BlockEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public class BlockPreDispenseEvent extends BlockEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -30,7 +31,7 @@ index 0000000000000000000000000000000000000000..62547d5853e7355a805fa1e7f1e5f56d
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public BlockPreDispenseEvent(@NotNull Block block, @NotNull ItemStack itemStack, int slot) {
+ public BlockPreDispenseEvent(final Block block, final ItemStack itemStack, final int slot) {
+ super(block);
+ this.itemStack = itemStack;
+ this.slot = slot;
@ -41,7 +42,6 @@ index 0000000000000000000000000000000000000000..62547d5853e7355a805fa1e7f1e5f56d
+ *
+ * @return The item to be dispensed
+ */
+ @NotNull
+ public ItemStack getItemStack() {
+ return this.itemStack;
+ }
@ -61,16 +61,15 @@ index 0000000000000000000000000000000000000000..62547d5853e7355a805fa1e7f1e5f56d
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Added PlayerChangeBeaconEffectEvent
diff --git a/src/main/java/io/papermc/paper/event/player/PlayerChangeBeaconEffectEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerChangeBeaconEffectEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..1cc5dfb6d31f312f07acb1d5fb4719d6f4c2c4ff
index 0000000000000000000000000000000000000000..580f01754ce082c926240b9bf4842cde1320f987
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/PlayerChangeBeaconEffectEvent.java
@@ -0,0 +1,137 @@
@@ -0,0 +1,136 @@
+package io.papermc.paper.event.player;
+
+import org.bukkit.block.Block;
@ -19,25 +19,26 @@ index 0000000000000000000000000000000000000000..1cc5dfb6d31f312f07acb1d5fb4719d6
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.potion.PotionEffectType;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Called when a player sets the effect for a beacon
+ */
+@NullMarked
+public class PlayerChangeBeaconEffectEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final Block beacon;
+ private PotionEffectType primary;
+ private PotionEffectType secondary;
+ private @Nullable PotionEffectType primary;
+ private @Nullable PotionEffectType secondary;
+ private boolean consumeItem = true;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerChangeBeaconEffectEvent(@NotNull Player player, @Nullable PotionEffectType primary, @Nullable PotionEffectType secondary, @NotNull Block beacon) {
+ public PlayerChangeBeaconEffectEvent(final Player player, final @Nullable PotionEffectType primary, final @Nullable PotionEffectType secondary, final Block beacon) {
+ super(player);
+ this.primary = primary;
+ this.secondary = secondary;
@ -47,7 +48,7 @@ index 0000000000000000000000000000000000000000..1cc5dfb6d31f312f07acb1d5fb4719d6
+ /**
+ * @return the primary effect
+ */
+ @Nullable public PotionEffectType getPrimary() {
+ public @Nullable PotionEffectType getPrimary() {
+ return this.primary;
+ }
+
@ -58,14 +59,14 @@ index 0000000000000000000000000000000000000000..1cc5dfb6d31f312f07acb1d5fb4719d6
+ *
+ * @param primary the primary effect
+ */
+ public void setPrimary(@Nullable PotionEffectType primary) {
+ public void setPrimary(final @Nullable PotionEffectType primary) {
+ this.primary = primary;
+ }
+
+ /**
+ * @return the secondary effect
+ */
+ @Nullable public PotionEffectType getSecondary() {
+ public @Nullable PotionEffectType getSecondary() {
+ return this.secondary;
+ }
+
@ -77,14 +78,13 @@ index 0000000000000000000000000000000000000000..1cc5dfb6d31f312f07acb1d5fb4719d6
+ *
+ * @param secondary the secondary effect
+ */
+ public void setSecondary(@Nullable PotionEffectType secondary) {
+ public void setSecondary(final @Nullable PotionEffectType secondary) {
+ this.secondary = secondary;
+ }
+
+ /**
+ * @return the beacon block associated with this event
+ */
+ @NotNull
+ public Block getBeacon() {
+ return this.beacon;
+ }
@ -109,7 +109,7 @@ index 0000000000000000000000000000000000000000..1cc5dfb6d31f312f07acb1d5fb4719d6
+ *
+ * @param consumeItem {@code true} if item should be consumed
+ */
+ public void setConsumeItem(boolean consumeItem) {
+ public void setConsumeItem(final boolean consumeItem) {
+ this.consumeItem = consumeItem;
+ }
+
@ -133,16 +133,15 @@ index 0000000000000000000000000000000000000000..1cc5dfb6d31f312f07acb1d5fb4719d6
+ * or saved.
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Added PlayerStonecutterRecipeSelectEvent
diff --git a/src/main/java/io/papermc/paper/event/player/PlayerStonecutterRecipeSelectEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerStonecutterRecipeSelectEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a7e1cb49ace104af3f9571fbc36b80687141736
index 0000000000000000000000000000000000000000..7f603310bff54b1c58334f21a6975bfe20812d72
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/PlayerStonecutterRecipeSelectEvent.java
@@ -0,0 +1,60 @@
@@ -0,0 +1,57 @@
+package io.papermc.paper.event.player;
+
+import org.bukkit.entity.Player;
@ -18,8 +18,9 @@ index 0000000000000000000000000000000000000000..8a7e1cb49ace104af3f9571fbc36b806
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.StonecutterInventory;
+import org.bukkit.inventory.StonecuttingRecipe;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public class PlayerStonecutterRecipeSelectEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -29,23 +30,21 @@ index 0000000000000000000000000000000000000000..8a7e1cb49ace104af3f9571fbc36b806
+
+ private boolean cancelled;
+
+ public PlayerStonecutterRecipeSelectEvent(@NotNull Player player, @NotNull StonecutterInventory stonecutterInventory, @NotNull StonecuttingRecipe stonecuttingRecipe) {
+ public PlayerStonecutterRecipeSelectEvent(final Player player, final StonecutterInventory stonecutterInventory, final StonecuttingRecipe stonecuttingRecipe) {
+ super(player);
+ this.stonecutterInventory = stonecutterInventory;
+ this.stonecuttingRecipe = stonecuttingRecipe;
+ }
+
+ @NotNull
+ public StonecutterInventory getStonecutterInventory() {
+ return this.stonecutterInventory;
+ }
+
+ @NotNull
+ public StonecuttingRecipe getStonecuttingRecipe() {
+ return this.stonecuttingRecipe;
+ }
+
+ public void setStonecuttingRecipe(@NotNull StonecuttingRecipe stonecuttingRecipe) {
+ public void setStonecuttingRecipe(final StonecuttingRecipe stonecuttingRecipe) {
+ this.stonecuttingRecipe = stonecuttingRecipe;
+ }
+
@ -55,17 +54,15 @@ index 0000000000000000000000000000000000000000..8a7e1cb49ace104af3f9571fbc36b806
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] add DragonEggFormEvent
diff --git a/src/main/java/io/papermc/paper/event/block/DragonEggFormEvent.java b/src/main/java/io/papermc/paper/event/block/DragonEggFormEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..695c21a296c6d12e1204eba33b92c44e7c2d98b8
index 0000000000000000000000000000000000000000..d0549d95985ff08af1fc1e6291e0124b766bf99d
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/block/DragonEggFormEvent.java
@@ -0,0 +1,55 @@
@@ -0,0 +1,53 @@
+package io.papermc.paper.event.block;
+
+import org.bukkit.Material;
@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..695c21a296c6d12e1204eba33b92c44e
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.block.BlockFormEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when the {@link EnderDragon} is defeated (killed) in a {@link DragonBattle},
@ -30,6 +30,7 @@ index 0000000000000000000000000000000000000000..695c21a296c6d12e1204eba33b92c44e
+ * <b>This event might be cancelled by default depending on
+ * e.g. {@link DragonBattle#hasBeenPreviouslyKilled()} and server configuration.</b>
+ */
+@NullMarked
+public class DragonEggFormEvent extends BlockFormEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -37,7 +38,7 @@ index 0000000000000000000000000000000000000000..695c21a296c6d12e1204eba33b92c44e
+ private final DragonBattle dragonBattle;
+
+ @ApiStatus.Internal
+ public DragonEggFormEvent(@NotNull Block block, @NotNull BlockState newState, @NotNull DragonBattle dragonBattle) {
+ public DragonEggFormEvent(final Block block, final BlockState newState, final DragonBattle dragonBattle) {
+ super(block, newState);
+ this.dragonBattle = dragonBattle;
+ }
@ -49,18 +50,15 @@ index 0000000000000000000000000000000000000000..695c21a296c6d12e1204eba33b92c44e
+ *
+ * @return the dragon battle
+ */
+ @NotNull
+ public DragonBattle getDragonBattle() {
+ return this.dragonBattle;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] EntityMoveEvent
diff --git a/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd46c2ad77c
index 0000000000000000000000000000000000000000..49ace395393839b3652a537207b4cf5b24beeac0
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java
@@ -0,0 +1,150 @@
@@ -0,0 +1,146 @@
+package io.papermc.paper.event.entity;
+
+import com.google.common.base.Preconditions;
@ -20,13 +20,14 @@ index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd4
+import org.bukkit.event.entity.EntityEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Holds information for living entity movement events
+ * <p>
+ * Does not fire for players; use {@link PlayerMoveEvent} for player movement.
+ */
+@NullMarked
+public class EntityMoveEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -37,14 +38,13 @@ index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd4
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EntityMoveEvent(@NotNull LivingEntity entity, @NotNull Location from, @NotNull Location to) {
+ public EntityMoveEvent(final LivingEntity entity, final Location from, final Location to) {
+ super(entity);
+ this.from = from;
+ this.to = to;
+ }
+
+ @Override
+ @NotNull
+ public LivingEntity getEntity() {
+ return (LivingEntity) super.getEntity();
+ }
@ -54,7 +54,6 @@ index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd4
+ *
+ * @return Location the entity moved from
+ */
+ @NotNull
+ public Location getFrom() {
+ return this.from;
+ }
@ -64,8 +63,8 @@ index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd4
+ *
+ * @param from New location to mark as the entity's previous location
+ */
+ public void setFrom(@NotNull Location from) {
+ validateLocation(from);
+ public void setFrom(final Location from) {
+ this.validateLocation(from);
+ this.from = from;
+ }
+
@ -74,7 +73,6 @@ index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd4
+ *
+ * @return Location the entity moved to
+ */
+ @NotNull
+ public Location getTo() {
+ return this.to;
+ }
@ -84,8 +82,8 @@ index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd4
+ *
+ * @param to New Location this entity will move to
+ */
+ public void setTo(@NotNull Location to) {
+ validateLocation(to);
+ public void setTo(final Location to) {
+ this.validateLocation(to);
+ this.to = to;
+ }
+
@ -95,7 +93,7 @@ index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd4
+ * @return whether the entity has changed position or not
+ */
+ public boolean hasChangedPosition() {
+ return hasExplicitlyChangedPosition() || !this.from.getWorld().equals(this.to.getWorld());
+ return this.hasExplicitlyChangedPosition() || !this.from.getWorld().equals(this.to.getWorld());
+ }
+
+ /**
@ -113,7 +111,7 @@ index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd4
+ * @return whether the entity has moved to a new block or not
+ */
+ public boolean hasChangedBlock() {
+ return hasExplicitlyChangedBlock() || !from.getWorld().equals(to.getWorld());
+ return this.hasExplicitlyChangedBlock() || !this.from.getWorld().equals(this.to.getWorld());
+ }
+
+ /**
@ -134,7 +132,7 @@ index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd4
+ return this.from.getPitch() != this.to.getPitch() || this.from.getYaw() != this.to.getYaw();
+ }
+
+ private void validateLocation(@NotNull Location loc) {
+ private void validateLocation(final Location loc) {
+ Preconditions.checkArgument(loc != null, "Cannot use null location!");
+ Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!");
+ }
@ -145,17 +143,15 @@ index 0000000000000000000000000000000000000000..46990a220f70b04218b14aec1e9efbd4
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Add worldborder events
diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..02ac479840c137ca5afcec149ef884e5a5d62928
index 0000000000000000000000000000000000000000..3c168b3522c538c1576238738d48eaef6559450d
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java
@@ -0,0 +1,117 @@
@@ -0,0 +1,115 @@
+package io.papermc.paper.event.world.border;
+
+import org.bukkit.World;
@ -17,11 +17,12 @@ index 0000000000000000000000000000000000000000..02ac479840c137ca5afcec149ef884e5
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a world border changes its bounds, either over time, or instantly.
+ */
+@NullMarked
+public class WorldBorderBoundsChangeEvent extends WorldBorderEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -33,7 +34,7 @@ index 0000000000000000000000000000000000000000..02ac479840c137ca5afcec149ef884e5
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public WorldBorderBoundsChangeEvent(@NotNull World world, @NotNull WorldBorder worldBorder, @NotNull Type type, double oldSize, double newSize, long duration) {
+ public WorldBorderBoundsChangeEvent(final World world, final WorldBorder worldBorder, final Type type, final double oldSize, final double newSize, final long duration) {
+ super(world, worldBorder);
+ this.type = type;
+ this.oldSize = oldSize;
@ -46,7 +47,6 @@ index 0000000000000000000000000000000000000000..02ac479840c137ca5afcec149ef884e5
+ *
+ * @return the change type
+ */
+ @NotNull
+ public Type getType() {
+ return this.type;
+ }
@ -74,7 +74,7 @@ index 0000000000000000000000000000000000000000..02ac479840c137ca5afcec149ef884e5
+ *
+ * @param newSize the new size
+ */
+ public void setNewSize(double newSize) {
+ public void setNewSize(final double newSize) {
+ this.newSize = Math.min(this.worldBorder.getMaxSize(), Math.max(1.0D, newSize));
+ }
+
@ -93,7 +93,7 @@ index 0000000000000000000000000000000000000000..02ac479840c137ca5afcec149ef884e5
+ *
+ * @param duration the time in milliseconds for the change
+ */
+ public void setDuration(long duration) {
+ public void setDuration(final long duration) {
+ // PAIL: TODO: Magic Values
+ this.duration = Math.min(9223372036854775L, Math.max(0L, duration));
+ if (duration >= 0 && this.type == Type.INSTANT_MOVE) {
@ -107,17 +107,15 @@ index 0000000000000000000000000000000000000000..02ac479840c137ca5afcec149ef884e5
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
@ -129,21 +127,22 @@ index 0000000000000000000000000000000000000000..02ac479840c137ca5afcec149ef884e5
+}
diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeFinishEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeFinishEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..a44964593b7f78c5086dc4928e75ad892e624671
index 0000000000000000000000000000000000000000..6a264660897f0b621e3fb112e6056d98bb510f52
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeFinishEvent.java
@@ -0,0 +1,67 @@
@@ -0,0 +1,66 @@
+package io.papermc.paper.event.world.border;
+
+import org.bukkit.World;
+import org.bukkit.WorldBorder;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a moving world border has finished its move.
+ */
+@NullMarked
+public class WorldBorderBoundsChangeFinishEvent extends WorldBorderEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -153,7 +152,7 @@ index 0000000000000000000000000000000000000000..a44964593b7f78c5086dc4928e75ad89
+ private final double duration;
+
+ @ApiStatus.Internal
+ public WorldBorderBoundsChangeFinishEvent(@NotNull World world, @NotNull WorldBorder worldBorder, double oldSize, double newSize, double duration) {
+ public WorldBorderBoundsChangeFinishEvent(final World world, final WorldBorder worldBorder, final double oldSize, final double newSize, final double duration) {
+ super(world, worldBorder);
+ this.oldSize = oldSize;
+ this.newSize = newSize;
@ -189,23 +188,21 @@ index 0000000000000000000000000000000000000000..a44964593b7f78c5086dc4928e75ad89
+ return this.duration;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderCenterChangeEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderCenterChangeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd96dcc0dd68d71bf27c758ed496153d434fb386
index 0000000000000000000000000000000000000000..74fe5ad50517374631fa3009249833e2b99a55f0
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderCenterChangeEvent.java
@@ -0,0 +1,79 @@
@@ -0,0 +1,76 @@
+package io.papermc.paper.event.world.border;
+
+import org.bukkit.Location;
@ -214,11 +211,12 @@ index 0000000000000000000000000000000000000000..dd96dcc0dd68d71bf27c758ed496153d
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a world border's center is changed.
+ */
+@NullMarked
+public class WorldBorderCenterChangeEvent extends WorldBorderEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -229,7 +227,7 @@ index 0000000000000000000000000000000000000000..dd96dcc0dd68d71bf27c758ed496153d
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public WorldBorderCenterChangeEvent(@NotNull World world, @NotNull WorldBorder worldBorder, @NotNull Location oldCenter, @NotNull Location newCenter) {
+ public WorldBorderCenterChangeEvent(final World world, final WorldBorder worldBorder, final Location oldCenter, final Location newCenter) {
+ super(world, worldBorder);
+ this.oldCenter = oldCenter;
+ this.newCenter = newCenter;
@ -240,7 +238,6 @@ index 0000000000000000000000000000000000000000..dd96dcc0dd68d71bf27c758ed496153d
+ *
+ * @return the old center
+ */
+ @NotNull
+ public Location getOldCenter() {
+ return this.oldCenter.clone();
+ }
@ -250,7 +247,6 @@ index 0000000000000000000000000000000000000000..dd96dcc0dd68d71bf27c758ed496153d
+ *
+ * @return the new center
+ */
+ @NotNull
+ public Location getNewCenter() {
+ return this.newCenter;
+ }
@ -260,7 +256,7 @@ index 0000000000000000000000000000000000000000..dd96dcc0dd68d71bf27c758ed496153d
+ *
+ * @param newCenter the new center
+ */
+ public void setNewCenter(@NotNull Location newCenter) {
+ public void setNewCenter(final Location newCenter) {
+ this.newCenter = newCenter;
+ }
+
@ -270,24 +266,22 @@ index 0000000000000000000000000000000000000000..dd96dcc0dd68d71bf27c758ed496153d
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..adb244f9be35c43ff99dbc3a771e1fdfb21da68c
index 0000000000000000000000000000000000000000..1f260e4d693903361d54c0af42144faa66adf4ea
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderEvent.java
@@ -0,0 +1,23 @@
@ -297,19 +291,19 @@ index 0000000000000000000000000000000000000000..adb244f9be35c43ff99dbc3a771e1fdf
+import org.bukkit.WorldBorder;
+import org.bukkit.event.world.WorldEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public abstract class WorldBorderEvent extends WorldEvent {
+
+ protected final WorldBorder worldBorder;
+
+ @ApiStatus.Internal
+ protected WorldBorderEvent(@NotNull World world, @NotNull WorldBorder worldBorder) {
+ protected WorldBorderEvent(final World world, final WorldBorder worldBorder) {
+ super(world);
+ this.worldBorder = worldBorder;
+ }
+
+ @NotNull
+ public WorldBorder getWorldBorder() {
+ return this.worldBorder;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] added PlayerNameEntityEvent
diff --git a/src/main/java/io/papermc/paper/event/player/PlayerNameEntityEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerNameEntityEvent.java
new file mode 100755
index 0000000000000000000000000000000000000000..84736d4a438e9023fbdeac1aea4d8b741cc39b61
index 0000000000000000000000000000000000000000..fb990180d9958fe2bbe44e86aa360102f37be9ed
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/PlayerNameEntityEvent.java
@@ -0,0 +1,110 @@
@@ -0,0 +1,107 @@
+package io.papermc.paper.event.player;
+
+import net.kyori.adventure.text.Component;
@ -19,24 +19,25 @@ index 0000000000000000000000000000000000000000..84736d4a438e9023fbdeac1aea4d8b74
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Called when the player is attempting to rename a mob
+ */
+@NullMarked
+public class PlayerNameEntityEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private LivingEntity entity;
+ private Component name;
+ private @Nullable Component name;
+ private boolean persistent;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerNameEntityEvent(@NotNull Player player, @NotNull LivingEntity entity, @NotNull Component name, boolean persistent) {
+ public PlayerNameEntityEvent(final Player player, final LivingEntity entity, final Component name, final boolean persistent) {
+ super(player);
+ this.entity = entity;
+ this.name = name;
@ -48,8 +49,7 @@ index 0000000000000000000000000000000000000000..84736d4a438e9023fbdeac1aea4d8b74
+ *
+ * @return the name
+ */
+ @Nullable
+ public Component getName() {
+ public @Nullable Component getName() {
+ return this.name;
+ }
+
@ -58,7 +58,7 @@ index 0000000000000000000000000000000000000000..84736d4a438e9023fbdeac1aea4d8b74
+ *
+ * @param name the name
+ */
+ public void setName(@Nullable Component name) {
+ public void setName(final @Nullable Component name) {
+ this.name = name;
+ }
+
@ -67,7 +67,6 @@ index 0000000000000000000000000000000000000000..84736d4a438e9023fbdeac1aea4d8b74
+ *
+ * @return the entity
+ */
+ @NotNull
+ public LivingEntity getEntity() {
+ return this.entity;
+ }
@ -77,7 +76,7 @@ index 0000000000000000000000000000000000000000..84736d4a438e9023fbdeac1aea4d8b74
+ *
+ * @param entity the entity
+ */
+ public void setEntity(@NotNull LivingEntity entity) {
+ public void setEntity(final LivingEntity entity) {
+ this.entity = entity;
+ }
+
@ -95,7 +94,7 @@ index 0000000000000000000000000000000000000000..84736d4a438e9023fbdeac1aea4d8b74
+ *
+ * @param persistent persistent
+ */
+ public void setPersistent(boolean persistent) {
+ public void setPersistent(final boolean persistent) {
+ this.persistent = persistent;
+ }
+
@ -105,17 +104,15 @@ index 0000000000000000000000000000000000000000..84736d4a438e9023fbdeac1aea4d8b74
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,10 +6,10 @@ Subject: [PATCH] Added PlayerDeepSleepEvent
diff --git a/src/main/java/io/papermc/paper/event/player/PlayerDeepSleepEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerDeepSleepEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..54cf2ec5e025fac9a0c8f151ff4f8c83a62b8405
index 0000000000000000000000000000000000000000..2d4b15ded1e9aa00f21ca0b412e6b6ac333e5e02
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/PlayerDeepSleepEvent.java
@@ -0,0 +1,48 @@
@@ -0,0 +1,47 @@
+package io.papermc.paper.event.player;
+
+import org.bukkit.entity.Player;
@ -17,7 +17,7 @@ index 0000000000000000000000000000000000000000..54cf2ec5e025fac9a0c8f151ff4f8c83
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when a player has slept long enough
@ -26,6 +26,7 @@ index 0000000000000000000000000000000000000000..54cf2ec5e025fac9a0c8f151ff4f8c83
+ * Cancelling this event will prevent the player from being counted as deeply sleeping
+ * unless they exit and re-enter the bed.
+ */
+@NullMarked
+public class PlayerDeepSleepEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -33,7 +34,7 @@ index 0000000000000000000000000000000000000000..54cf2ec5e025fac9a0c8f151ff4f8c83
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerDeepSleepEvent(@NotNull Player player) {
+ public PlayerDeepSleepEvent(final Player player) {
+ super(player);
+ }
+
@ -43,17 +44,15 @@ index 0000000000000000000000000000000000000000..54cf2ec5e025fac9a0c8f151ff4f8c83
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

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