Compare commits

..

2 commits

Author SHA1 Message Date
Jason Penilla
a136173f15
adjust delay to 5s 2024-09-13 15:04:18 -07:00
Jason Penilla
fcf48a9c94
Add ticket on player join to avoid chunk load-unload-load cycle
Adding the entity will add and then immediately remove an entity load ticket, which would result in the chunk loading and then unloading before being loaded again once the player chunk loader reacts (delay can vary based on rate limit configs)

By adding a ticket with a short removal delay we attempt to keep the chunk loaded until the player chunk loader reacts, but this is not a guarantee due to the aforementioned rate limit configs. Plugins should still handle load/unload events as normal, however this will reduce redundant calls.

The delay is currently set to 2 seconds, however we may want to adjust this before merging
2024-09-13 14:38:01 -07:00
1150 changed files with 4716 additions and 16131 deletions

View file

@ -249,17 +249,6 @@ 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

@ -11,7 +11,7 @@ import kotlin.io.path.*
plugins {
java
`maven-publish`
id("io.papermc.paperweight.core") version "1.7.3"
id("io.papermc.paperweight.core") version "1.7.1"
}
allprojects {

View file

@ -1,343 +0,0 @@
package io.papermc.paper.registry.keys;
import static net.kyori.adventure.key.Key.key;
import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import net.kyori.adventure.key.Key;
import org.bukkit.block.banner.PatternType;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus;
/**
* Vanilla keys for {@link RegistryKey#BANNER_PATTERN}.
*
* @apiNote The fields provided here are a direct representation of
* what is available from the vanilla game source. They may be
* changed (including removals) on any Minecraft version
* bump, so cross-version compatibility is not provided on the
* same level as it is on most of the other API.
*/
@SuppressWarnings({
"unused",
"SpellCheckingInspection"
})
@GeneratedFrom("1.21.1")
@ApiStatus.Experimental
public final class BannerPatternKeys {
/**
* {@code minecraft:base}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> BASE = create(key("base"));
/**
* {@code minecraft:border}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> BORDER = create(key("border"));
/**
* {@code minecraft:bricks}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> BRICKS = create(key("bricks"));
/**
* {@code minecraft:circle}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> CIRCLE = create(key("circle"));
/**
* {@code minecraft:creeper}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> CREEPER = create(key("creeper"));
/**
* {@code minecraft:cross}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> CROSS = create(key("cross"));
/**
* {@code minecraft:curly_border}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> CURLY_BORDER = create(key("curly_border"));
/**
* {@code minecraft:diagonal_left}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> DIAGONAL_LEFT = create(key("diagonal_left"));
/**
* {@code minecraft:diagonal_right}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> DIAGONAL_RIGHT = create(key("diagonal_right"));
/**
* {@code minecraft:diagonal_up_left}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> DIAGONAL_UP_LEFT = create(key("diagonal_up_left"));
/**
* {@code minecraft:diagonal_up_right}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> DIAGONAL_UP_RIGHT = create(key("diagonal_up_right"));
/**
* {@code minecraft:flow}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> FLOW = create(key("flow"));
/**
* {@code minecraft:flower}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> FLOWER = create(key("flower"));
/**
* {@code minecraft:globe}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> GLOBE = create(key("globe"));
/**
* {@code minecraft:gradient}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> GRADIENT = create(key("gradient"));
/**
* {@code minecraft:gradient_up}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> GRADIENT_UP = create(key("gradient_up"));
/**
* {@code minecraft:guster}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> GUSTER = create(key("guster"));
/**
* {@code minecraft:half_horizontal}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> HALF_HORIZONTAL = create(key("half_horizontal"));
/**
* {@code minecraft:half_horizontal_bottom}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> HALF_HORIZONTAL_BOTTOM = create(key("half_horizontal_bottom"));
/**
* {@code minecraft:half_vertical}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> HALF_VERTICAL = create(key("half_vertical"));
/**
* {@code minecraft:half_vertical_right}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> HALF_VERTICAL_RIGHT = create(key("half_vertical_right"));
/**
* {@code minecraft:mojang}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> MOJANG = create(key("mojang"));
/**
* {@code minecraft:piglin}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> PIGLIN = create(key("piglin"));
/**
* {@code minecraft:rhombus}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> RHOMBUS = create(key("rhombus"));
/**
* {@code minecraft:skull}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> SKULL = create(key("skull"));
/**
* {@code minecraft:small_stripes}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> SMALL_STRIPES = create(key("small_stripes"));
/**
* {@code minecraft:square_bottom_left}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> SQUARE_BOTTOM_LEFT = create(key("square_bottom_left"));
/**
* {@code minecraft:square_bottom_right}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> SQUARE_BOTTOM_RIGHT = create(key("square_bottom_right"));
/**
* {@code minecraft:square_top_left}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> SQUARE_TOP_LEFT = create(key("square_top_left"));
/**
* {@code minecraft:square_top_right}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> SQUARE_TOP_RIGHT = create(key("square_top_right"));
/**
* {@code minecraft:straight_cross}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> STRAIGHT_CROSS = create(key("straight_cross"));
/**
* {@code minecraft:stripe_bottom}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> STRIPE_BOTTOM = create(key("stripe_bottom"));
/**
* {@code minecraft:stripe_center}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> STRIPE_CENTER = create(key("stripe_center"));
/**
* {@code minecraft:stripe_downleft}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> STRIPE_DOWNLEFT = create(key("stripe_downleft"));
/**
* {@code minecraft:stripe_downright}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> STRIPE_DOWNRIGHT = create(key("stripe_downright"));
/**
* {@code minecraft:stripe_left}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> STRIPE_LEFT = create(key("stripe_left"));
/**
* {@code minecraft:stripe_middle}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> STRIPE_MIDDLE = create(key("stripe_middle"));
/**
* {@code minecraft:stripe_right}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> STRIPE_RIGHT = create(key("stripe_right"));
/**
* {@code minecraft:stripe_top}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> STRIPE_TOP = create(key("stripe_top"));
/**
* {@code minecraft:triangle_bottom}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> TRIANGLE_BOTTOM = create(key("triangle_bottom"));
/**
* {@code minecraft:triangle_top}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> TRIANGLE_TOP = create(key("triangle_top"));
/**
* {@code minecraft:triangles_bottom}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> TRIANGLES_BOTTOM = create(key("triangles_bottom"));
/**
* {@code minecraft:triangles_top}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<PatternType> TRIANGLES_TOP = create(key("triangles_top"));
private BannerPatternKeys() {
}
/**
* Creates a key for {@link PatternType} in the registry {@code minecraft:banner_pattern}.
*
* @param key the value's key in the registry
* @return a new typed key
*/
@ApiStatus.Experimental
public static @NonNull TypedKey<PatternType> create(final @NonNull Key key) {
return TypedKey.create(RegistryKey.BANNER_PATTERN, key);
}
}

View file

@ -1,112 +0,0 @@
package io.papermc.paper.registry.keys;
import static net.kyori.adventure.key.Key.key;
import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import net.kyori.adventure.key.Key;
import org.bukkit.entity.Cat;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus;
/**
* Vanilla keys for {@link RegistryKey#CAT_VARIANT}.
*
* @apiNote The fields provided here are a direct representation of
* what is available from the vanilla game source. They may be
* changed (including removals) on any Minecraft version
* bump, so cross-version compatibility is not provided on the
* same level as it is on most of the other API.
*/
@SuppressWarnings({
"unused",
"SpellCheckingInspection"
})
@GeneratedFrom("1.21.1")
@ApiStatus.Experimental
public final class CatVariantKeys {
/**
* {@code minecraft:all_black}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> ALL_BLACK = create(key("all_black"));
/**
* {@code minecraft:black}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> BLACK = create(key("black"));
/**
* {@code minecraft:british_shorthair}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> BRITISH_SHORTHAIR = create(key("british_shorthair"));
/**
* {@code minecraft:calico}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> CALICO = create(key("calico"));
/**
* {@code minecraft:jellie}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> JELLIE = create(key("jellie"));
/**
* {@code minecraft:persian}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> PERSIAN = create(key("persian"));
/**
* {@code minecraft:ragdoll}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> RAGDOLL = create(key("ragdoll"));
/**
* {@code minecraft:red}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> RED = create(key("red"));
/**
* {@code minecraft:siamese}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> SIAMESE = create(key("siamese"));
/**
* {@code minecraft:tabby}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> TABBY = create(key("tabby"));
/**
* {@code minecraft:white}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Cat.Type> WHITE = create(key("white"));
private CatVariantKeys() {
}
private static @NonNull TypedKey<Cat.Type> create(final @NonNull Key key) {
return TypedKey.create(RegistryKey.CAT_VARIANT, key);
}
}

View file

@ -1,56 +0,0 @@
package io.papermc.paper.registry.keys;
import static net.kyori.adventure.key.Key.key;
import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import net.kyori.adventure.key.Key;
import org.bukkit.entity.Frog;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus;
/**
* Vanilla keys for {@link RegistryKey#FROG_VARIANT}.
*
* @apiNote The fields provided here are a direct representation of
* what is available from the vanilla game source. They may be
* changed (including removals) on any Minecraft version
* bump, so cross-version compatibility is not provided on the
* same level as it is on most of the other API.
*/
@SuppressWarnings({
"unused",
"SpellCheckingInspection"
})
@GeneratedFrom("1.21.1")
@ApiStatus.Experimental
public final class FrogVariantKeys {
/**
* {@code minecraft:cold}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Frog.Variant> COLD = create(key("cold"));
/**
* {@code minecraft:temperate}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Frog.Variant> TEMPERATE = create(key("temperate"));
/**
* {@code minecraft:warm}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Frog.Variant> WARM = create(key("warm"));
private FrogVariantKeys() {
}
private static @NonNull TypedKey<Frog.Variant> create(final @NonNull Key key) {
return TypedKey.create(RegistryKey.FROG_VARIANT, key);
}
}

View file

@ -1,175 +0,0 @@
package io.papermc.paper.registry.keys;
import static net.kyori.adventure.key.Key.key;
import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import net.kyori.adventure.key.Key;
import org.bukkit.JukeboxSong;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus;
/**
* Vanilla keys for {@link RegistryKey#JUKEBOX_SONG}.
*
* @apiNote The fields provided here are a direct representation of
* what is available from the vanilla game source. They may be
* changed (including removals) on any Minecraft version
* bump, so cross-version compatibility is not provided on the
* same level as it is on most of the other API.
*/
@SuppressWarnings({
"unused",
"SpellCheckingInspection"
})
@GeneratedFrom("1.21.1")
@ApiStatus.Experimental
public final class JukeboxSongKeys {
/**
* {@code minecraft:11}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> ELEVEN = create(key("11"));
/**
* {@code minecraft:13}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> THIRTEEN = create(key("13"));
/**
* {@code minecraft:5}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> FIVE = create(key("5"));
/**
* {@code minecraft:blocks}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> BLOCKS = create(key("blocks"));
/**
* {@code minecraft:cat}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> CAT = create(key("cat"));
/**
* {@code minecraft:chirp}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> CHIRP = create(key("chirp"));
/**
* {@code minecraft:creator}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> CREATOR = create(key("creator"));
/**
* {@code minecraft:creator_music_box}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> CREATOR_MUSIC_BOX = create(key("creator_music_box"));
/**
* {@code minecraft:far}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> FAR = create(key("far"));
/**
* {@code minecraft:mall}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> MALL = create(key("mall"));
/**
* {@code minecraft:mellohi}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> MELLOHI = create(key("mellohi"));
/**
* {@code minecraft:otherside}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> OTHERSIDE = create(key("otherside"));
/**
* {@code minecraft:pigstep}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> PIGSTEP = create(key("pigstep"));
/**
* {@code minecraft:precipice}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> PRECIPICE = create(key("precipice"));
/**
* {@code minecraft:relic}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> RELIC = create(key("relic"));
/**
* {@code minecraft:stal}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> STAL = create(key("stal"));
/**
* {@code minecraft:strad}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> STRAD = create(key("strad"));
/**
* {@code minecraft:wait}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> WAIT = create(key("wait"));
/**
* {@code minecraft:ward}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<JukeboxSong> WARD = create(key("ward"));
private JukeboxSongKeys() {
}
/**
* Creates a key for {@link JukeboxSong} in the registry {@code minecraft:jukebox_song}.
*
* @param key the value's key in the registry
* @return a new typed key
*/
@ApiStatus.Experimental
public static @NonNull TypedKey<JukeboxSong> create(final @NonNull Key key) {
return TypedKey.create(RegistryKey.JUKEBOX_SONG, key);
}
}

View file

@ -1,280 +0,0 @@
package io.papermc.paper.registry.keys;
import static net.kyori.adventure.key.Key.key;
import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import net.kyori.adventure.key.Key;
import org.bukkit.map.MapCursor;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus;
/**
* Vanilla keys for {@link RegistryKey#MAP_DECORATION_TYPE}.
*
* @apiNote The fields provided here are a direct representation of
* what is available from the vanilla game source. They may be
* changed (including removals) on any Minecraft version
* bump, so cross-version compatibility is not provided on the
* same level as it is on most of the other API.
*/
@SuppressWarnings({
"unused",
"SpellCheckingInspection"
})
@GeneratedFrom("1.21.1")
@ApiStatus.Experimental
public final class MapDecorationTypeKeys {
/**
* {@code minecraft:banner_black}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_BLACK = create(key("banner_black"));
/**
* {@code minecraft:banner_blue}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_BLUE = create(key("banner_blue"));
/**
* {@code minecraft:banner_brown}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_BROWN = create(key("banner_brown"));
/**
* {@code minecraft:banner_cyan}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_CYAN = create(key("banner_cyan"));
/**
* {@code minecraft:banner_gray}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_GRAY = create(key("banner_gray"));
/**
* {@code minecraft:banner_green}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_GREEN = create(key("banner_green"));
/**
* {@code minecraft:banner_light_blue}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_LIGHT_BLUE = create(key("banner_light_blue"));
/**
* {@code minecraft:banner_light_gray}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_LIGHT_GRAY = create(key("banner_light_gray"));
/**
* {@code minecraft:banner_lime}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_LIME = create(key("banner_lime"));
/**
* {@code minecraft:banner_magenta}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_MAGENTA = create(key("banner_magenta"));
/**
* {@code minecraft:banner_orange}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_ORANGE = create(key("banner_orange"));
/**
* {@code minecraft:banner_pink}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_PINK = create(key("banner_pink"));
/**
* {@code minecraft:banner_purple}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_PURPLE = create(key("banner_purple"));
/**
* {@code minecraft:banner_red}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_RED = create(key("banner_red"));
/**
* {@code minecraft:banner_white}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_WHITE = create(key("banner_white"));
/**
* {@code minecraft:banner_yellow}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BANNER_YELLOW = create(key("banner_yellow"));
/**
* {@code minecraft:blue_marker}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> BLUE_MARKER = create(key("blue_marker"));
/**
* {@code minecraft:frame}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> FRAME = create(key("frame"));
/**
* {@code minecraft:jungle_temple}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> JUNGLE_TEMPLE = create(key("jungle_temple"));
/**
* {@code minecraft:mansion}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> MANSION = create(key("mansion"));
/**
* {@code minecraft:monument}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> MONUMENT = create(key("monument"));
/**
* {@code minecraft:player}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> PLAYER = create(key("player"));
/**
* {@code minecraft:player_off_limits}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> PLAYER_OFF_LIMITS = create(key("player_off_limits"));
/**
* {@code minecraft:player_off_map}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> PLAYER_OFF_MAP = create(key("player_off_map"));
/**
* {@code minecraft:red_marker}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> RED_MARKER = create(key("red_marker"));
/**
* {@code minecraft:red_x}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> RED_X = create(key("red_x"));
/**
* {@code minecraft:swamp_hut}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> SWAMP_HUT = create(key("swamp_hut"));
/**
* {@code minecraft:target_point}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> TARGET_POINT = create(key("target_point"));
/**
* {@code minecraft:target_x}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> TARGET_X = create(key("target_x"));
/**
* {@code minecraft:trial_chambers}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> TRIAL_CHAMBERS = create(key("trial_chambers"));
/**
* {@code minecraft:village_desert}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> VILLAGE_DESERT = create(key("village_desert"));
/**
* {@code minecraft:village_plains}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> VILLAGE_PLAINS = create(key("village_plains"));
/**
* {@code minecraft:village_savanna}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> VILLAGE_SAVANNA = create(key("village_savanna"));
/**
* {@code minecraft:village_snowy}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> VILLAGE_SNOWY = create(key("village_snowy"));
/**
* {@code minecraft:village_taiga}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MapCursor.Type> VILLAGE_TAIGA = create(key("village_taiga"));
private MapDecorationTypeKeys() {
}
private static @NonNull TypedKey<MapCursor.Type> create(final @NonNull Key key) {
return TypedKey.create(RegistryKey.MAP_DECORATION_TYPE, key);
}
}

View file

@ -1,210 +0,0 @@
package io.papermc.paper.registry.keys;
import static net.kyori.adventure.key.Key.key;
import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import net.kyori.adventure.key.Key;
import org.bukkit.inventory.MenuType;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus;
/**
* Vanilla keys for {@link RegistryKey#MENU}.
*
* @apiNote The fields provided here are a direct representation of
* what is available from the vanilla game source. They may be
* changed (including removals) on any Minecraft version
* bump, so cross-version compatibility is not provided on the
* same level as it is on most of the other API.
*/
@SuppressWarnings({
"unused",
"SpellCheckingInspection"
})
@GeneratedFrom("1.21.1")
@ApiStatus.Experimental
public final class MenuTypeKeys {
/**
* {@code minecraft:anvil}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> ANVIL = create(key("anvil"));
/**
* {@code minecraft:beacon}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> BEACON = create(key("beacon"));
/**
* {@code minecraft:blast_furnace}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> BLAST_FURNACE = create(key("blast_furnace"));
/**
* {@code minecraft:brewing_stand}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> BREWING_STAND = create(key("brewing_stand"));
/**
* {@code minecraft:cartography_table}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> CARTOGRAPHY_TABLE = create(key("cartography_table"));
/**
* {@code minecraft:crafter_3x3}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> CRAFTER_3X3 = create(key("crafter_3x3"));
/**
* {@code minecraft:crafting}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> CRAFTING = create(key("crafting"));
/**
* {@code minecraft:enchantment}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> ENCHANTMENT = create(key("enchantment"));
/**
* {@code minecraft:furnace}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> FURNACE = create(key("furnace"));
/**
* {@code minecraft:generic_3x3}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> GENERIC_3X3 = create(key("generic_3x3"));
/**
* {@code minecraft:generic_9x1}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> GENERIC_9X1 = create(key("generic_9x1"));
/**
* {@code minecraft:generic_9x2}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> GENERIC_9X2 = create(key("generic_9x2"));
/**
* {@code minecraft:generic_9x3}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> GENERIC_9X3 = create(key("generic_9x3"));
/**
* {@code minecraft:generic_9x4}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> GENERIC_9X4 = create(key("generic_9x4"));
/**
* {@code minecraft:generic_9x5}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> GENERIC_9X5 = create(key("generic_9x5"));
/**
* {@code minecraft:generic_9x6}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> GENERIC_9X6 = create(key("generic_9x6"));
/**
* {@code minecraft:grindstone}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> GRINDSTONE = create(key("grindstone"));
/**
* {@code minecraft:hopper}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> HOPPER = create(key("hopper"));
/**
* {@code minecraft:lectern}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> LECTERN = create(key("lectern"));
/**
* {@code minecraft:loom}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> LOOM = create(key("loom"));
/**
* {@code minecraft:merchant}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> MERCHANT = create(key("merchant"));
/**
* {@code minecraft:shulker_box}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> SHULKER_BOX = create(key("shulker_box"));
/**
* {@code minecraft:smithing}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> SMITHING = create(key("smithing"));
/**
* {@code minecraft:smoker}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> SMOKER = create(key("smoker"));
/**
* {@code minecraft:stonecutter}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<MenuType> STONECUTTER = create(key("stonecutter"));
private MenuTypeKeys() {
}
private static @NonNull TypedKey<MenuType> create(final @NonNull Key key) {
return TypedKey.create(RegistryKey.MENU, key);
}
}

View file

@ -1,140 +0,0 @@
package io.papermc.paper.registry.keys;
import static net.kyori.adventure.key.Key.key;
import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import net.kyori.adventure.key.Key;
import org.bukkit.entity.Villager;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus;
/**
* Vanilla keys for {@link RegistryKey#VILLAGER_PROFESSION}.
*
* @apiNote The fields provided here are a direct representation of
* what is available from the vanilla game source. They may be
* changed (including removals) on any Minecraft version
* bump, so cross-version compatibility is not provided on the
* same level as it is on most of the other API.
*/
@SuppressWarnings({
"unused",
"SpellCheckingInspection"
})
@GeneratedFrom("1.21.1")
@ApiStatus.Experimental
public final class VillagerProfessionKeys {
/**
* {@code minecraft:armorer}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> ARMORER = create(key("armorer"));
/**
* {@code minecraft:butcher}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> BUTCHER = create(key("butcher"));
/**
* {@code minecraft:cartographer}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> CARTOGRAPHER = create(key("cartographer"));
/**
* {@code minecraft:cleric}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> CLERIC = create(key("cleric"));
/**
* {@code minecraft:farmer}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> FARMER = create(key("farmer"));
/**
* {@code minecraft:fisherman}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> FISHERMAN = create(key("fisherman"));
/**
* {@code minecraft:fletcher}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> FLETCHER = create(key("fletcher"));
/**
* {@code minecraft:leatherworker}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> LEATHERWORKER = create(key("leatherworker"));
/**
* {@code minecraft:librarian}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> LIBRARIAN = create(key("librarian"));
/**
* {@code minecraft:mason}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> MASON = create(key("mason"));
/**
* {@code minecraft:nitwit}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> NITWIT = create(key("nitwit"));
/**
* {@code minecraft:none}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> NONE = create(key("none"));
/**
* {@code minecraft:shepherd}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> SHEPHERD = create(key("shepherd"));
/**
* {@code minecraft:toolsmith}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> TOOLSMITH = create(key("toolsmith"));
/**
* {@code minecraft:weaponsmith}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Profession> WEAPONSMITH = create(key("weaponsmith"));
private VillagerProfessionKeys() {
}
private static @NonNull TypedKey<Villager.Profession> create(final @NonNull Key key) {
return TypedKey.create(RegistryKey.VILLAGER_PROFESSION, key);
}
}

View file

@ -1,84 +0,0 @@
package io.papermc.paper.registry.keys;
import static net.kyori.adventure.key.Key.key;
import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import net.kyori.adventure.key.Key;
import org.bukkit.entity.Villager;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus;
/**
* Vanilla keys for {@link RegistryKey#VILLAGER_TYPE}.
*
* @apiNote The fields provided here are a direct representation of
* what is available from the vanilla game source. They may be
* changed (including removals) on any Minecraft version
* bump, so cross-version compatibility is not provided on the
* same level as it is on most of the other API.
*/
@SuppressWarnings({
"unused",
"SpellCheckingInspection"
})
@GeneratedFrom("1.21.1")
@ApiStatus.Experimental
public final class VillagerTypeKeys {
/**
* {@code minecraft:desert}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Type> DESERT = create(key("desert"));
/**
* {@code minecraft:jungle}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Type> JUNGLE = create(key("jungle"));
/**
* {@code minecraft:plains}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Type> PLAINS = create(key("plains"));
/**
* {@code minecraft:savanna}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Type> SAVANNA = create(key("savanna"));
/**
* {@code minecraft:snow}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Type> SNOW = create(key("snow"));
/**
* {@code minecraft:swamp}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Type> SWAMP = create(key("swamp"));
/**
* {@code minecraft:taiga}
*
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
*/
public static final TypedKey<Villager.Type> TAIGA = create(key("taiga"));
private VillagerTypeKeys() {
}
private static @NonNull TypedKey<Villager.Type> create(final @NonNull Key key) {
return TypedKey.create(RegistryKey.VILLAGER_TYPE, key);
}
}

View file

@ -9,55 +9,34 @@ import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import org.bukkit.GameEvent;
import org.bukkit.JukeboxSong;
import org.bukkit.MusicInstrument;
import org.bukkit.block.Biome;
import org.bukkit.block.BlockType;
import org.bukkit.block.banner.PatternType;
import org.bukkit.damage.DamageType;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Cat;
import org.bukkit.entity.Frog;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Wolf;
import org.bukkit.generator.structure.Structure;
import org.bukkit.generator.structure.StructureType;
import org.bukkit.inventory.ItemType;
import org.bukkit.inventory.MenuType;
import org.bukkit.inventory.meta.trim.TrimMaterial;
import org.bukkit.inventory.meta.trim.TrimPattern;
import org.bukkit.map.MapCursor;
import org.bukkit.potion.PotionEffectType;
public interface Generators {
SourceGenerator[] API = {
// built-ins
simpleKey("GameEventKeys", GameEvent.class, Registries.GAME_EVENT, RegistryKey.GAME_EVENT, false),
simpleKey("StructureTypeKeys", StructureType.class, Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, false),
simpleKey("InstrumentKeys", MusicInstrument.class, Registries.INSTRUMENT, RegistryKey.INSTRUMENT, false),
simpleKey("MobEffectKeys", PotionEffectType.class, Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, false),
simpleKey("BlockTypeKeys", BlockType.class, Registries.BLOCK, RegistryKey.BLOCK, false),
simpleKey("ItemTypeKeys", ItemType.class, Registries.ITEM, RegistryKey.ITEM, false),
simpleKey("CatVariantKeys", Cat.Type.class, Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT, false),
simpleKey("FrogVariantKeys", Frog.Variant.class, Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT, false),
simpleKey("VillagerProfessionKeys", Villager.Profession.class, Registries.VILLAGER_PROFESSION, RegistryKey.VILLAGER_PROFESSION, false),
simpleKey("VillagerTypeKeys", Villager.Type.class, Registries.VILLAGER_TYPE, RegistryKey.VILLAGER_TYPE, false),
simpleKey("MapDecorationTypeKeys", MapCursor.Type.class, Registries.MAP_DECORATION_TYPE, RegistryKey.MAP_DECORATION_TYPE, false),
simpleKey("MenuTypeKeys", MenuType.class, Registries.MENU, RegistryKey.MENU, false),
// data-driven
simpleKey("BiomeKeys", Biome.class, Registries.BIOME, RegistryKey.BIOME, true),
simpleKey("StructureKeys", Structure.class, Registries.STRUCTURE, RegistryKey.STRUCTURE, true),
simpleKey("TrimMaterialKeys", TrimMaterial.class, Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL, true),
simpleKey("TrimPatternKeys", TrimPattern.class, Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN, true),
simpleKey("StructureKeys", Structure.class, Registries.STRUCTURE, RegistryKey.STRUCTURE, true),
simpleKey("StructureTypeKeys", StructureType.class, Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, false),
simpleKey("InstrumentKeys", MusicInstrument.class, Registries.INSTRUMENT, RegistryKey.INSTRUMENT, false),
simpleKey("EnchantmentKeys", Enchantment.class, Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, false),
simpleKey("MobEffectKeys", PotionEffectType.class, Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, false),
simpleKey("DamageTypeKeys", DamageType.class, Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE, true),
simpleKey("WolfVariantKeys", Wolf.Variant.class, Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT, true),
simpleKey("EnchantmentKeys", Enchantment.class, Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, false),
simpleKey("JukeboxSongKeys", JukeboxSong.class, Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG, true),
simpleKey("BannerPatternKeys", PatternType.class, Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN, true),
simpleKey("ItemTypeKeys", ItemType.class, Registries.ITEM, RegistryKey.ITEM, false),
// tags
simpleTagKey("EnchantmentTagKeys", Enchantment.class, Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT),
simpleTagKey("ItemTypeTagKeys", ItemType.class, Registries.ITEM, RegistryKey.ITEM),
new MobGoalGenerator("VanillaGoal", "com.destroystokyo.paper.entity.ai")

View file

@ -1,6 +1,5 @@
package io.papermc.generator.utils;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.math.NumberUtils;
import java.util.Comparator;
@ -13,13 +12,8 @@ public final class Formatting {
private static final Pattern ILLEGAL_FIELD_CHARACTERS = Pattern.compile("[.-/]");
private static final Map<String, String> MANUAL_OVERRIDES = Map.of(
"5", "five",
"11", "eleven",
"13", "thirteen"
);
public static String formatKeyAsField(String path) {
return ILLEGAL_FIELD_CHARACTERS.matcher(MANUAL_OVERRIDES.getOrDefault(path, path).toUpperCase(Locale.ROOT)).replaceAll("_");
return ILLEGAL_FIELD_CHARACTERS.matcher(path.toUpperCase(Locale.ROOT)).replaceAll("_");
}
public static Optional<String> formatTagKey(String tagDir, String resourcePath) {

View file

@ -5,10 +5,10 @@ Subject: [PATCH] Build system changes
diff --git a/build.gradle.kts b/build.gradle.kts
index 6271e2bad0ed937c2c46a8c8fdf186c46b0b620e..78aadebda145fe83327ceb430c4b38f9a8e45a2b 100644
index 6271e2bad0ed937c2c46a8c8fdf186c46b0b620e..a918fd14c95e714e935758d60bccd72755e00b11 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -18,15 +18,27 @@ dependencies {
@@ -18,15 +18,26 @@ dependencies {
api("net.md-5:bungeecord-chat:$bungeeCordChatVersion")
api("org.yaml:snakeyaml:2.2")
api("org.joml:joml:1.10.5")
@ -32,12 +32,11 @@ index 6271e2bad0ed937c2c46a8c8fdf186c46b0b620e..78aadebda145fe83327ceb430c4b38f9
+ 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 +81,13 @@ tasks.withType<Javadoc> {
@@ -69,8 +80,12 @@ tasks.withType<Javadoc> {
options.links(
"https://guava.dev/releases/32.1.2-jre/api/docs/",
"https://javadoc.io/doc/org.yaml/snakeyaml/2.2/",
@ -47,12 +46,11 @@ index 6271e2bad0ed937c2c46a8c8fdf186c46b0b620e..78aadebda145fe83327ceb430c4b38f9
+ // 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 +106,14 @@ tasks.withType<Javadoc> {
@@ -89,3 +104,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 78aadebda145fe83327ceb430c4b38f9a8e45a2b..8c7a5be5193ae397ec324d78566edce90608ed57 100644
index a918fd14c95e714e935758d60bccd72755e00b11..768024b2b4584fd7dd86f068c0e79c89ffc5faa1 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -107,6 +107,12 @@ tasks.test {
@@ -105,6 +105,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..7ff939ea41417bad3a436a87c89d5efa7ecefe86 100644
index 64e7aef6220097edefdff3b98a771b988365930d..d9091ba1e5a55e03adca98305233cce9d6888609 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,19 +103,7 @@ index 64e7aef6220097edefdff3b98a771b988365930d..7ff939ea41417bad3a436a87c89d5efa
};
@Test
@@ -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;
@@ -67,14 +83,48 @@ public class AnnotationTest {
}
if (mustBeAnnotated(Type.getReturnType(method.desc)) && !isWellAnnotated(method.invisibleAnnotations)) {
@ -164,7 +152,7 @@ index 64e7aef6220097edefdff3b98a771b988365930d..7ff939ea41417bad3a436a87c89d5efa
ParameterNode paramNode = parameters == null ? null : parameters.get(i);
String paramName = paramNode == null ? null : paramNode.name;
@@ -91,13 +147,18 @@ public class AnnotationTest {
@@ -91,13 +141,18 @@ public class AnnotationTest {
Collections.sort(errors);
@ -187,20 +175,7 @@ index 64e7aef6220097edefdff3b98a771b988365930d..7ff939ea41417bad3a436a87c89d5efa
}
private static void collectClasses(@NotNull File from, @NotNull Map<String, ClassNode> to) throws IOException {
@@ -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 {
@@ -140,6 +195,11 @@ public class AnnotationTest {
// Exceptions are excluded
return false;
}
@ -212,7 +187,7 @@ index 64e7aef6220097edefdff3b98a771b988365930d..7ff939ea41417bad3a436a87c89d5efa
for (String excludedClass : EXCLUDED_CLASSES) {
if (excludedClass.equals(clazz.name)) {
@@ -152,7 +224,7 @@ public class AnnotationTest {
@@ -152,7 +212,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
@ -221,7 +196,7 @@ index 64e7aef6220097edefdff3b98a771b988365930d..7ff939ea41417bad3a436a87c89d5efa
return false;
}
@@ -170,11 +242,30 @@ public class AnnotationTest {
@@ -170,11 +230,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 8c7a5be5193ae397ec324d78566edce90608ed57..877ea06c0ea8c8c0c73d23fbb996f6692c100d98 100644
index 768024b2b4584fd7dd86f068c0e79c89ffc5faa1..f11a22ab01e97e51619c96f2d8a78a99297efc59 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,6 +1,7 @@
@ -18,7 +18,7 @@ index 8c7a5be5193ae397ec324d78566edce90608ed57..877ea06c0ea8c8c0c73d23fbb996f669
}
java {
@@ -46,6 +47,22 @@ dependencies {
@@ -45,6 +46,22 @@ dependencies {
testImplementation("org.ow2.asm:asm-tree:9.7")
}
@ -41,7 +41,7 @@ index 8c7a5be5193ae397ec324d78566edce90608ed57..877ea06c0ea8c8c0c73d23fbb996f669
configure<PublishingExtension> {
publications.create<MavenPublication>("maven") {
from(components["java"])
@@ -123,3 +140,14 @@ tasks.check {
@@ -121,3 +138,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..8410d7213370f01cbedbf7fac29bac96f150c49a
index 0000000000000000000000000000000000000000..76daccf4ea502e1747a6f9176dc16fd20c561286
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java
@@ -0,0 +1,179 @@
@@ -0,0 +1,147 @@
+package io.papermc.paper.registry;
+
+import net.kyori.adventure.key.Keyed;
@ -114,14 +114,12 @@ index 0000000000000000000000000000000000000000..8410d7213370f01cbedbf7fac29bac96
+import org.bukkit.generator.structure.Structure;
+import org.bukkit.generator.structure.StructureType;
+import org.bukkit.inventory.ItemType;
+import org.bukkit.inventory.MenuType;
+import org.bukkit.inventory.meta.trim.TrimMaterial;
+import org.bukkit.inventory.meta.trim.TrimPattern;
+import org.bukkit.map.MapCursor;
+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;
+
@ -138,7 +136,6 @@ index 0000000000000000000000000000000000000000..8410d7213370f01cbedbf7fac29bac96
+ * @param <T> the value type
+ */
+@SuppressWarnings("unused")
+@NullMarked
+public sealed interface RegistryKey<T> extends Keyed permits RegistryKeyImpl {
+
+ /* ******************* *
@ -174,36 +171,6 @@ index 0000000000000000000000000000000000000000..8410d7213370f01cbedbf7fac29bac96
+ */
+ @ApiStatus.Internal
+ RegistryKey<ItemType> ITEM = create("item");
+ /**
+ * Built-in registry for cat variants.
+ * @see io.papermc.paper.registry.keys.CatVariantKeys
+ */
+ RegistryKey<Cat.Type> CAT_VARIANT = create("cat_variant");
+ /**
+ * Built-in registry for frog variants.
+ * @see io.papermc.paper.registry.keys.FrogVariantKeys
+ */
+ RegistryKey<Frog.Variant> FROG_VARIANT = create("frog_variant");
+ /**
+ * Built-in registry for villager professions.
+ * @see io.papermc.paper.registry.keys.VillagerProfessionKeys
+ */
+ RegistryKey<Villager.Profession> VILLAGER_PROFESSION = create("villager_profession");
+ /**
+ * Built-in registry for villager types.
+ * @see io.papermc.paper.registry.keys.VillagerTypeKeys
+ */
+ RegistryKey<Villager.Type> VILLAGER_TYPE = create("villager_type");
+ /**
+ * Built-in registry for map decoration types.
+ * @see io.papermc.paper.registry.keys.MapDecorationTypeKeys
+ */
+ RegistryKey<MapCursor.Type> MAP_DECORATION_TYPE = create("map_decoration_type");
+ /**
+ * Built-in registry for menu types.
+ * @see io.papermc.paper.registry.keys.MenuTypeKeys
+ */
+ RegistryKey<MenuType> MENU = create("menu");
+
+
+ /* ********************** *
@ -246,14 +213,9 @@ index 0000000000000000000000000000000000000000..8410d7213370f01cbedbf7fac29bac96
+ RegistryKey<Enchantment> ENCHANTMENT = create("enchantment");
+ /**
+ * Data-driven registry for jukebox songs.
+ * @see io.papermc.paper.registry.keys.JukeboxSongKeys
+ */
+ @ApiStatus.Experimental
+ RegistryKey<JukeboxSong> JUKEBOX_SONG = create("jukebox_song");
+ /**
+ * Data-driven registry for banner patterns.
+ * @see io.papermc.paper.registry.keys.BannerPatternKeys
+ */
+ RegistryKey<PatternType> BANNER_PATTERN = create("banner_pattern");
+
+
+ /* ******************* *
@ -261,30 +223,34 @@ index 0000000000000000000000000000000000000000..8410d7213370f01cbedbf7fac29bac96
+ * ******************* */
+ RegistryKey<Art> PAINTING_VARIANT = create("painting_variant");
+ RegistryKey<Attribute> ATTRIBUTE = create("attribute");
+ RegistryKey<PatternType> BANNER_PATTERN = create("banner_pattern");
+ RegistryKey<Cat.Type> CAT_VARIANT = create("cat_variant");
+ RegistryKey<EntityType> ENTITY_TYPE = create("entity_type");
+ RegistryKey<Particle> PARTICLE_TYPE = create("particle_type");
+ RegistryKey<PotionType> POTION = create("potion");
+ RegistryKey<Sound> SOUND_EVENT = create("sound_event");
+ RegistryKey<Villager.Profession> VILLAGER_PROFESSION = create("villager_profession");
+ RegistryKey<Villager.Type> VILLAGER_TYPE = create("villager_type");
+ RegistryKey<MemoryKey<?>> MEMORY_MODULE_TYPE = create("memory_module_type");
+ RegistryKey<Fluid> FLUID = create("fluid");
+ RegistryKey<Frog.Variant> FROG_VARIANT = create("frog_variant");
+ RegistryKey<MapCursor.Type> MAP_DECORATION_TYPE = create("map_decoration_type");
+}
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..80e3e64f47ac55a4978c9e5b430e2f2d1c871d1b
index 0000000000000000000000000000000000000000..791813220b2504214b1adecc69093cd600fb0f8c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
@@ -0,0 +1,26 @@
@@ -0,0 +1,24 @@
+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.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+
+@NullMarked
+record RegistryKeyImpl<T>(Key key) implements RegistryKey<T> {
+record RegistryKeyImpl<T>(@NotNull Key key) implements RegistryKey<T> {
+
+ static final Set<RegistryKey<?>> REGISTRY_KEYS = Sets.newIdentityHashSet();
+
@ -302,16 +268,16 @@ index 0000000000000000000000000000000000000000..80e3e64f47ac55a4978c9e5b430e2f2d
+}
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..cb2e1a4a6d583787573eeefab24e3188c43d148f
index 0000000000000000000000000000000000000000..6f5a062ba7ee7173468ecea3c1855a233bf3855e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/TypedKey.java
@@ -0,0 +1,45 @@
@@ -0,0 +1,44 @@
+package io.papermc.paper.registry;
+
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.key.Keyed;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Represents a key for a value in a specific registry.
@ -319,7 +285,6 @@ index 0000000000000000000000000000000000000000..cb2e1a4a6d583787573eeefab24e3188
+ * @param <T> the value type for the registry
+ */
+@ApiStatus.Experimental
+@NullMarked
+public sealed interface TypedKey<T> extends Keyed permits TypedKeyImpl {
+
+ /**
@ -328,7 +293,7 @@ index 0000000000000000000000000000000000000000..cb2e1a4a6d583787573eeefab24e3188
+ * @return the value's key
+ */
+ @Override
+ Key key();
+ @NotNull Key key();
+
+ /**
+ * Gets the registry key for the value this key
@ -336,7 +301,7 @@ index 0000000000000000000000000000000000000000..cb2e1a4a6d583787573eeefab24e3188
+ *
+ * @return the registry key
+ */
+ RegistryKey<T> registryKey();
+ @NotNull RegistryKey<T> registryKey();
+
+ /**
+ * Create a typed key from a key and a registry key.
@ -347,23 +312,23 @@ index 0000000000000000000000000000000000000000..cb2e1a4a6d583787573eeefab24e3188
+ * @return a new key for the value key and registry key
+ */
+ @ApiStatus.Experimental
+ static <T> TypedKey<T> create(final RegistryKey<T> registryKey, final Key key) {
+ static <T> @NotNull TypedKey<T> create(final @NotNull RegistryKey<T> registryKey, final @NotNull 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..99375deaa6b90b33cd6a77e0df651236d304874e
index 0000000000000000000000000000000000000000..1a97b3359c4ece5c29131da7c3f208aaa8fab66e
--- /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 org.jspecify.annotations.NullMarked;
+import net.kyori.adventure.key.Keyed;
+import org.jetbrains.annotations.NotNull;
+
+@NullMarked
+record TypedKeyImpl<T>(Key key, RegistryKey<T> registryKey) implements TypedKey<T> {
+record TypedKeyImpl<T>(@NotNull Key key, @NotNull 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 3383fb91249ea53740326b538abd905f84ff0e3c..74f0e2b812c1e2e922b136fefe505fc8cbe33e83 100644
index 2f266350a787a4cfdfda1b0e760bfb7604cac43c..af3514113abdf3f42c41f1e7ff0f930cc1a417f5 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -11,12 +11,28 @@ java {
@ -55,7 +55,7 @@ index 3383fb91249ea53740326b538abd905f84ff0e3c..74f0e2b812c1e2e922b136fefe505fc8
// Paper end
compileOnly("org.apache.maven:maven-resolver-provider:3.9.6")
@@ -100,15 +123,32 @@ tasks.withType<Javadoc> {
@@ -99,14 +122,31 @@ 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,7 +64,6 @@ index 3383fb91249ea53740326b538abd905f84ff0e3c..74f0e2b812c1e2e922b136fefe505fc8
// 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/",
@ -91,25 +90,23 @@ index 3383fb91249ea53740326b538abd905f84ff0e3c..74f0e2b812c1e2e922b136fefe505fc8
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..1288cdeafe587e9e78e7c5087742ea054ba8423d
index 0000000000000000000000000000000000000000..ffe0a921cc1ebbb95104f22b57e0e3af85e287a6
--- /dev/null
+++ b/src/main/java/io/papermc/paper/chat/ChatRenderer.java
@@ -0,0 +1,70 @@
@@ -0,0 +1,71 @@
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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}.
+ *
@ -120,13 +117,15 @@ index 0000000000000000000000000000000000000000..1288cdeafe587e9e78e7c5087742ea05
+ * @return a rendered chat message
+ */
+ @ApiStatus.OverrideOnly
+ Component render(Player source, Component sourceDisplayName, Component message, Audience viewer);
+ @NotNull
+ Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message, @NotNull 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));
+ }
@ -142,7 +141,8 @@ index 0000000000000000000000000000000000000000..1288cdeafe587e9e78e7c5087742ea05
+ * @param renderer the viewer unaware renderer
+ * @return a new {@link ChatRenderer}
+ */
+ static ChatRenderer viewerUnaware(final ViewerUnaware renderer) {
+ @NotNull
+ static ChatRenderer viewerUnaware(final @NotNull ViewerUnaware renderer) {
+ return new ViewerUnawareImpl(renderer);
+ }
+
@ -152,7 +152,6 @@ index 0000000000000000000000000000000000000000..1288cdeafe587e9e78e7c5087742ea05
+ * @see ChatRenderer#viewerUnaware(ViewerUnaware)
+ */
+ interface ViewerUnaware {
+
+ /**
+ * Renders a chat message.
+ *
@ -162,26 +161,24 @@ index 0000000000000000000000000000000000000000..1288cdeafe587e9e78e7c5087742ea05
+ * @return a rendered chat message
+ */
+ @ApiStatus.OverrideOnly
+ Component render(Player source, Component sourceDisplayName, Component message);
+ @NotNull
+ Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull 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..e1ef23b4bdf60a299d6d37099cef777b3de13ac7
index 0000000000000000000000000000000000000000..2ad76b1751ba707f7ae0d283aa1cbaf6c9619da9
--- /dev/null
+++ b/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java
@@ -0,0 +1,38 @@
@@ -0,0 +1,35 @@
+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.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@ApiStatus.Internal
+@NullMarked
+sealed class ViewerUnawareImpl implements ChatRenderer, ChatRenderer.ViewerUnaware permits ViewerUnawareImpl.Default {
+ private final ViewerUnaware unaware;
+ private @Nullable Component message;
@ -191,12 +188,12 @@ index 0000000000000000000000000000000000000000..e1ef23b4bdf60a299d6d37099cef777b
+ }
+
+ @Override
+ public Component render(final Player source, final Component sourceDisplayName, final Component message, final Audience viewer) {
+ public @NotNull Component render(final @NotNull Player source, final @NotNull Component sourceDisplayName, final @NotNull Component message, final @NotNull Audience viewer) {
+ return this.render(source, sourceDisplayName, message);
+ }
+
+ @Override
+ public Component render(final Player source, final Component sourceDisplayName, final Component message) {
+ public @NotNull Component render(final @NotNull Player source, final @NotNull Component sourceDisplayName, final @NotNull Component message) {
+ if (this.message == null) {
+ this.message = this.unaware.render(source, sourceDisplayName, message);
+ }
@ -211,14 +208,13 @@ index 0000000000000000000000000000000000000000..e1ef23b4bdf60a299d6d37099cef777b
+}
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..9a95d203151d2c91b0eec494e3674f0facfaa305
index 0000000000000000000000000000000000000000..a0fd845bc9b2540c398fe1dbbf821803a7017a28
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java
@@ -0,0 +1,122 @@
@@ -0,0 +1,127 @@
+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;
@ -226,7 +222,9 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+
+import static java.util.Objects.requireNonNull;
+
@ -234,7 +232,6 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+ * 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;
@ -245,7 +242,7 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+
+ private boolean cancelled;
+
+ AbstractChatEvent(final boolean async, final Player player, final Set<Audience> viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) {
+ 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) {
+ super(player, async);
+ this.viewers = viewers;
+ this.renderer = renderer;
@ -262,6 +259,7 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+ *
+ * @return a mutable set of {@link Audience audiences} who will receive the chat message
+ */
+ @NotNull
+ public final Set<Audience> viewers() {
+ return this.viewers;
+ }
@ -272,7 +270,7 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+ * @param renderer the chat renderer
+ * @throws NullPointerException if {@code renderer} is {@code null}
+ */
+ public final void renderer(final ChatRenderer renderer) {
+ public final void renderer(final @NotNull ChatRenderer renderer) {
+ this.renderer = requireNonNull(renderer, "renderer");
+ }
+
@ -281,6 +279,7 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+ *
+ * @return the chat renderer
+ */
+ @NotNull
+ public final ChatRenderer renderer() {
+ return this.renderer;
+ }
@ -291,6 +290,7 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+ *
+ * @return the user-supplied message
+ */
+ @NotNull
+ public final Component message() {
+ return this.message;
+ }
@ -301,7 +301,7 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+ * @param message the user-supplied message
+ * @throws NullPointerException if {@code message} is {@code null}
+ */
+ public final void message(final Component message) {
+ public final void message(final @NotNull Component message) {
+ this.message = requireNonNull(message, "message");
+ }
+
@ -312,6 +312,7 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+ *
+ * @return the original user-supplied message
+ */
+ @NotNull
+ public final Component originalMessage() {
+ return this.originalMessage;
+ }
@ -323,6 +324,7 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+ *
+ * @return the signed message
+ */
+ @NotNull
+ public final SignedMessage signedMessage() {
+ return this.signedMessage;
+ }
@ -339,42 +341,41 @@ index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0f
+}
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..ddd4c90f83b5cb8f069ff53760abb3c4adfd1168
index 0000000000000000000000000000000000000000..01cf89d3558132912c4d0eb48c98cd8c06e46a67
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java
@@ -0,0 +1,29 @@
@@ -0,0 +1,28 @@
+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.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@ApiStatus.Experimental
+@NullMarked
+public class AsyncChatCommandDecorateEvent extends AsyncChatDecorateEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ @ApiStatus.Internal
+ public AsyncChatCommandDecorateEvent(final @Nullable Player player, final Component originalMessage) {
+ public AsyncChatCommandDecorateEvent(@Nullable Player player, @NotNull Component originalMessage) {
+ super(player, originalMessage);
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ public @NotNull HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static HandlerList getHandlerList() {
+ public static @NotNull 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..9e5ea0cd006bd9744b84923620841f07fa40c2cb
index 0000000000000000000000000000000000000000..2e492f4cd179135bd40ad951ab23acb562be2f06
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java
@@ -0,0 +1,105 @@
@ -386,8 +387,9 @@ index 0000000000000000000000000000000000000000..9e5ea0cd006bd9744b84923620841f07
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.server.ServerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * This event is fired when the server decorates a component for chat purposes. This is called
@ -399,19 +401,18 @@ index 0000000000000000000000000000000000000000..9e5ea0cd006bd9744b84923620841f07
+ * 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 @Nullable Player player;
+ private final Player player;
+ private final Component originalMessage;
+ private Component result;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public AsyncChatDecorateEvent(final @Nullable Player player, final Component originalMessage) {
+ public AsyncChatDecorateEvent(final @Nullable Player player, final @NotNull Component originalMessage) {
+ super(true);
+ this.player = player;
+ this.originalMessage = originalMessage;
@ -435,7 +436,7 @@ index 0000000000000000000000000000000000000000..9e5ea0cd006bd9744b84923620841f07
+ *
+ * @return the input
+ */
+ public Component originalMessage() {
+ public @NotNull Component originalMessage() {
+ return this.originalMessage;
+ }
+
@ -446,7 +447,7 @@ index 0000000000000000000000000000000000000000..9e5ea0cd006bd9744b84923620841f07
+ *
+ * @return the result
+ */
+ public Component result() {
+ public @NotNull Component result() {
+ return this.result;
+ }
+
@ -455,7 +456,7 @@ index 0000000000000000000000000000000000000000..9e5ea0cd006bd9744b84923620841f07
+ *
+ * @param result the result
+ */
+ public void result(final Component result) {
+ public void result(@NotNull Component result) {
+ this.result = result;
+ }
+
@ -470,36 +471,36 @@ index 0000000000000000000000000000000000000000..9e5ea0cd006bd9744b84923620841f07
+ * component.
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ public @NotNull HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static HandlerList getHandlerList() {
+ public static @NotNull 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..50c3e117dec63811823b4e6395bf4f090692ee8c
index 0000000000000000000000000000000000000000..4adae8b8a8640ffbd6a86b0908ca21fded737b88
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java
@@ -0,0 +1,44 @@
@@ -0,0 +1,45 @@
+package io.papermc.paper.event.player;
+
+import io.papermc.paper.chat.ChatRenderer;
+import java.util.Set;
+import io.papermc.paper.chat.ChatRenderer;
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * An event fired when a {@link Player} sends a chat message to the server.
@ -514,35 +515,36 @@ index 0000000000000000000000000000000000000000..50c3e117dec63811823b4e6395bf4f09
+ * 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 Player player, final Set<Audience> viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) {
+ 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) {
+ 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..42a82ce2316a4aad2883d24c7e2ff95d95f5881a
index 0000000000000000000000000000000000000000..7411f58f9f36beaadcc47c2264a4af313956ee03
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/player/ChatEvent.java
@@ -0,0 +1,40 @@
@@ -0,0 +1,41 @@
+package io.papermc.paper.event.player;
+
+import io.papermc.paper.chat.ChatRenderer;
+import java.util.Set;
+import io.papermc.paper.chat.ChatRenderer;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.chat.SignedMessage;
+import net.kyori.adventure.text.Component;
@ -550,7 +552,7 @@ index 0000000000000000000000000000000000000000..42a82ce2316a4aad2883d24c7e2ff95d
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * An event fired when a {@link Player} sends a chat message to the server.
@ -560,34 +562,34 @@ index 0000000000000000000000000000000000000000..42a82ce2316a4aad2883d24c7e2ff95d
+ */
+@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 Player player, final Set<Audience> viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) {
+ 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) {
+ 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..934d1d3ca490a8e25c438bc8c57eb6bde50e0147
index 0000000000000000000000000000000000000000..1a11cfde07db55194cd26757863a268b9042d0bb
--- /dev/null
+++ b/src/main/java/io/papermc/paper/text/PaperComponents.java
@@ -0,0 +1,180 @@
@@ -0,0 +1,177 @@
+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;
@ -598,15 +600,15 @@ index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bd
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Entity;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+
+/**
+ * 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!");
+ }
@ -636,7 +638,7 @@ index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bd
+ * @return the resolved component
+ * @throws IOException if a syntax error tripped during resolving
+ */
+ public static Component resolveWithContext(final Component input, final @Nullable CommandSender context, final @Nullable Entity scoreboardSubject) throws IOException {
+ public static @NotNull Component resolveWithContext(@NotNull Component input, @Nullable CommandSender context, @Nullable Entity scoreboardSubject) throws IOException {
+ return resolveWithContext(input, context, scoreboardSubject, true);
+ }
+
@ -667,8 +669,7 @@ index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bd
+ * @return the resolved component
+ * @throws IOException if a syntax error tripped during resolving
+ */
+ @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 {
+ public static @NotNull Component resolveWithContext(@NotNull Component input, @Nullable CommandSender context, @Nullable Entity scoreboardSubject, boolean bypassPermissions) throws IOException {
+ return Bukkit.getUnsafe().resolveWithContext(input, context, scoreboardSubject, bypassPermissions);
+ }
+
@ -677,8 +678,7 @@ index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bd
+ *
+ * @return a component flattener
+ */
+ @SuppressWarnings("deprecation") // using unsafe as a bridge
+ public static ComponentFlattener flattener() {
+ public static @NotNull ComponentFlattener flattener() {
+ return Bukkit.getUnsafe().componentFlattener();
+ }
+
@ -693,7 +693,7 @@ index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bd
+ * @deprecated will be removed in adventure 5.0.0, use {@link PlainTextComponentSerializer#plainText()}
+ */
+ @Deprecated(forRemoval = true, since = "1.18.1")
+ public static PlainComponentSerializer plainSerializer() {
+ public static @NotNull PlainComponentSerializer plainSerializer() {
+ return Bukkit.getUnsafe().plainComponentSerializer();
+ }
+
@ -708,7 +708,7 @@ index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bd
+ * @deprecated use {@link PlainTextComponentSerializer#plainText()}
+ */
+ @Deprecated(forRemoval = true, since = "1.18.2")
+ public static PlainTextComponentSerializer plainTextSerializer() {
+ public static @NotNull PlainTextComponentSerializer plainTextSerializer() {
+ return Bukkit.getUnsafe().plainTextSerializer();
+ }
+
@ -724,7 +724,7 @@ index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bd
+ * @deprecated use {@link GsonComponentSerializer#gson()}
+ */
+ @Deprecated(forRemoval = true, since = "1.18.2")
+ public static GsonComponentSerializer gsonSerializer() {
+ public static @NotNull GsonComponentSerializer gsonSerializer() {
+ return Bukkit.getUnsafe().gsonComponentSerializer();
+ }
+
@ -741,7 +741,7 @@ index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bd
+ * @deprecated use {@link GsonComponentSerializer#colorDownsamplingGson()}
+ */
+ @Deprecated(forRemoval = true, since = "1.18.2")
+ public static GsonComponentSerializer colorDownsamplingGsonSerializer() {
+ public static @NotNull GsonComponentSerializer colorDownsamplingGsonSerializer() {
+ return Bukkit.getUnsafe().colorDownsamplingGsonComponentSerializer();
+ }
+
@ -761,7 +761,7 @@ index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bd
+ * @deprecated use {@link LegacyComponentSerializer#legacySection()}
+ */
+ @Deprecated(forRemoval = true, since = "1.18.2")
+ public static LegacyComponentSerializer legacySectionSerializer() {
+ public static @NotNull LegacyComponentSerializer legacySectionSerializer() {
+ return Bukkit.getUnsafe().legacyComponentSerializer();
+ }
+}
@ -3343,16 +3343,16 @@ index 133760be6c73436512ba684a3ac77a514b2d8765..9473303bd8ab1f6b63b6999a5f5ff3ec
* Gets how much EXP the Player should have at respawn.
* <p>
diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java
index 094963b16eccc303fb1a10b1e052feebe4a4d68b..3e6ac5beb137efd8ecd80e2e9b17015cb38e8a0a 100644
index c5734d66686e68080f55034754d43ae55030c3eb..32cd8ee2e849df602a7e10aa5d0a218007faa0ac 100644
--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java
+++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java
@@ -163,7 +163,18 @@ public enum InventoryType {
@@ -161,6 +161,18 @@ public enum InventoryType {
private final String title;
private final MenuType menuType;
private final boolean isCreatable;
+ // Paper start
+ private final net.kyori.adventure.text.Component defaultTitleComponent;
+
+ /**
+ * Gets the inventory's default title.
+ *
@ -3362,18 +3362,18 @@ index 094963b16eccc303fb1a10b1e052feebe4a4d68b..3e6ac5beb137efd8ecd80e2e9b17015c
+ return defaultTitleComponent;
+ }
+ // Paper end
private InventoryType(int defaultSize, /*@NotNull*/ String defaultTitle, @Nullable MenuType type) {
this(defaultSize, defaultTitle, type, true);
private InventoryType(int defaultSize, /*@NotNull*/ String defaultTitle) {
this(defaultSize, defaultTitle, true);
}
@@ -173,6 +184,7 @@ public enum InventoryType {
@@ -169,6 +181,7 @@ public enum InventoryType {
size = defaultSize;
title = defaultTitle;
this.menuType = type;
this.isCreatable = isCreatable;
+ this.defaultTitleComponent = net.kyori.adventure.text.Component.text(defaultTitle); // Paper - Adventure
}
public int getDefaultSize() {
@@ -180,6 +192,7 @@ public enum InventoryType {
@@ -176,6 +189,7 @@ public enum InventoryType {
}
@NotNull
@ -4421,56 +4421,6 @@ index eade62328895133c026e7e678e648e1fc846f5ee..730c42eddd38acec1cdbb19dfc8c6757
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/inventory/MenuType.java b/src/main/java/org/bukkit/inventory/MenuType.java
index ee39bf9019fa0377beb895a22db0b2a0934a4d84..29dfad691cbdd09d043f6171defc8a7fabbc2b75 100644
--- a/src/main/java/org/bukkit/inventory/MenuType.java
+++ b/src/main/java/org/bukkit/inventory/MenuType.java
@@ -146,11 +146,45 @@ public interface MenuType extends Keyed {
* @param player the player the view belongs to
* @param title the title of the view
* @return the created {@link InventoryView}
+ * @deprecated Use {@link #create(HumanEntity, net.kyori.adventure.text.Component)} instead.
*/
@NotNull
+ @Deprecated(since = "1.21") // Paper - adventure
V create(@NotNull HumanEntity player, @NotNull String title);
+
+ // Paper start - adventure
+ /**
+ * Creates a view of the specified menu type.
+ * <p>
+ * The player provided to create this view must be the player the view
+ * is opened for. See {@link HumanEntity#openInventory(InventoryView)}
+ * for more information.
+ *
+ * @param player the player the view belongs to
+ * @param title the title of the view
+ * @return the created {@link InventoryView}
+ */
+ @NotNull
+ V create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title);
+ // Paper end - adventure
}
+ // Paper start - adventure
+ /**
+ * Creates a view of the specified menu type.
+ * <p>
+ * The player provided to create this view must be the player the view
+ * is opened for. See {@link HumanEntity#openInventory(InventoryView)}
+ * for more information.
+ *
+ * @param player the player the view belongs to
+ * @param title the title of the view
+ * @return the created {@link InventoryView}
+ */
+ @NotNull
+ InventoryView create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title);
+ // Paper end - adventure
+
/**
* Yields this MenuType as a typed version of itself with a plain
* {@link InventoryView} representing it.
diff --git a/src/main/java/org/bukkit/inventory/meta/BookMeta.java b/src/main/java/org/bukkit/inventory/meta/BookMeta.java
index 9bab73c3c2ca759b8e1c7d07d98cc593c961666a..f0c6943da3f783101ca647b75b3230fae3a310da 100644
--- a/src/main/java/org/bukkit/inventory/meta/BookMeta.java

View file

@ -6,25 +6,22 @@ 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..fbcd82b513b4cb9839f9d2b38d9c6c73148e30a6
index 0000000000000000000000000000000000000000..9db0056ab94145819628b3ad8d8d26130d117fcf
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java
@@ -0,0 +1,19 @@
@@ -0,0 +1,16 @@
+package com.destroystokyo.paper.util;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+@ApiStatus.Internal
+@NullMarked
+public final class SneakyThrow {
+public class SneakyThrow {
+
+ public static void sneaky(final Throwable exception) {
+ SneakyThrow.throwSneaky(exception);
+ public static void sneaky(@NotNull Throwable exception) {
+ SneakyThrow.<RuntimeException>throwSneaky(exception);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T extends Throwable> void throwSneaky(final Throwable exception) throws T {
+ private static <T extends Throwable> void throwSneaky(@NotNull 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 74f0e2b812c1e2e922b136fefe505fc8cbe33e83..1f627e81622e77b81b1228a467fbb9e6fd979e7a 100644
index af3514113abdf3f42c41f1e7ff0f930cc1a417f5..ed0b67ac322aa22b191cd35502ae5b4f20af19f8 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -47,6 +47,9 @@ dependencies {
@ -21,138 +21,127 @@ index 74f0e2b812c1e2e922b136fefe505fc8cbe33e83..1f627e81622e77b81b1228a467fbb9e6
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..5a702481d28d90cb503faad0d9b9c3231bbff940
index 0000000000000000000000000000000000000000..5b28e9b1daba7834af67dbc193dd656bedd9a994
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java
@@ -0,0 +1,46 @@
@@ -0,0 +1,42 @@
+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.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+
+@ApiStatus.Internal
+@NullMarked
+public class MethodHandleEventExecutor implements EventExecutor {
+
+ private final Class<? extends Event> eventClass;
+ private final MethodHandle handle;
+
+ public MethodHandleEventExecutor(final Class<? extends Event> eventClass, final MethodHandle handle) {
+ public MethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull MethodHandle handle) {
+ this.eventClass = eventClass;
+ this.handle = handle;
+ }
+
+ public MethodHandleEventExecutor(final Class<? extends Event> eventClass, final Method m) {
+ public MethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull Method m) {
+ this.eventClass = eventClass;
+ try {
+ m.setAccessible(true);
+ this.handle = MethodHandles.lookup().unreflect(m);
+ } catch (final IllegalAccessException e) {
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("Unable to set accessible", e);
+ }
+ }
+
+ @Override
+ public void execute(final Listener listener, final Event event) throws EventException {
+ if (!this.eventClass.isInstance(event)) return;
+ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException {
+ if (!eventClass.isInstance(event)) return;
+ try {
+ this.handle.invoke(listener, event);
+ } catch (final Throwable t) {
+ handle.invoke(listener, event);
+ } catch (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..bbdb5b472df116b71c459bdc6cc4b74267ea0f5e
index 0000000000000000000000000000000000000000..827f2b27f70a7ec0bc11d039305c3e58c02a4ef4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java
@@ -0,0 +1,44 @@
@@ -0,0 +1,42 @@
+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.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+@ApiStatus.Internal
+@NullMarked
+public class StaticMethodHandleEventExecutor implements EventExecutor {
+
+ private final Class<? extends Event> eventClass;
+ private final MethodHandle handle;
+
+ public StaticMethodHandleEventExecutor(final Class<? extends Event> eventClass, final Method m) {
+ public StaticMethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull 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 (final IllegalAccessException e) {
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("Unable to set accessible", e);
+ }
+ }
+
+ @Override
+ public void execute(final Listener listener, final Event event) throws EventException {
+ if (!this.eventClass.isInstance(event)) return;
+ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException {
+ if (!eventClass.isInstance(event)) return;
+ try {
+ this.handle.invoke(event);
+ } catch (final Throwable throwable) {
+ handle.invoke(event);
+ } catch (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..abfcb6e8383ff311940d82afe4ff990649a082dc
index 0000000000000000000000000000000000000000..084c31af1a7ba32bb4c3dc8f16f67fd09ce0b6a4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java
@@ -0,0 +1,59 @@
@@ -0,0 +1,54 @@
+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.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.GeneratorAdapter;
+
+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;
+import static org.objectweb.asm.Opcodes.*;
+
+@ApiStatus.Internal
+@NullMarked
+public final class ASMEventExecutorGenerator {
+public class ASMEventExecutorGenerator {
+
+ private static final String EXECUTE_DESCRIPTOR = "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Event;)V";
+
+ 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)});
+ @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)});
+ // Generate constructor
+ GeneratorAdapter methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null), ACC_PUBLIC, "<init>", "()V");
+ methodGenerator.loadThis();
@ -180,25 +169,22 @@ index 0000000000000000000000000000000000000000..abfcb6e8383ff311940d82afe4ff9906
+ }
+
+ public static AtomicInteger NEXT_ID = new AtomicInteger(1);
+
+ @NotNull
+ public static String generateName() {
+ final int id = NEXT_ID.getAndIncrement();
+ 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..581561fbd32c81ab1774ba8f0b7f3cec9392d99a
index 0000000000000000000000000000000000000000..f79685b48bb581277a6891927988b6f7a4389dc4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java
@@ -0,0 +1,35 @@
@@ -0,0 +1,34 @@
+package com.destroystokyo.paper.event.executor.asm;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+@ApiStatus.Internal
+@NullMarked
+public interface ClassDefiner {
+
+ /**
@ -206,7 +192,7 @@ index 0000000000000000000000000000000000000000..581561fbd32c81ab1774ba8f0b7f3cec
+ *
+ * @return if classes bypass access checks
+ */
+ default boolean isBypassAccessChecks() {
+ public default boolean isBypassAccessChecks() {
+ return false;
+ }
+
@ -220,79 +206,79 @@ index 0000000000000000000000000000000000000000..581561fbd32c81ab1774ba8f0b7f3cec
+ * @throws ClassFormatError if the class data is invalid
+ * @throws NullPointerException if any of the arguments are null
+ */
+ Class<?> defineClass(ClassLoader parentLoader, String name, byte[] data);
+ @NotNull
+ public Class<?> defineClass(@NotNull ClassLoader parentLoader, @NotNull String name, @NotNull byte[] data);
+
+ static ClassDefiner getInstance() {
+ @NotNull
+ public 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..48bcc72293c2a31b6e2dd2dcd6a79d618c72a137
index 0000000000000000000000000000000000000000..abcc966d8ee01d73c1d1480237ab46fa0ab55fdc
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java
@@ -0,0 +1,66 @@
@@ -0,0 +1,64 @@
+package com.destroystokyo.paper.event.executor.asm;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.MapMaker;
+import java.util.concurrent.ConcurrentMap;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+@ApiStatus.Internal
+@NullMarked
+import com.google.common.base.Preconditions;
+
+import com.google.common.collect.MapMaker;
+import org.jetbrains.annotations.NotNull;
+
+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(final ClassLoader parentLoader, final String name, final byte[] data) {
+ final GeneratedClassLoader loader = this.loaders.computeIfAbsent(parentLoader, GeneratedClassLoader::new);
+ public Class<?> defineClass(@NotNull ClassLoader parentLoader, @NotNull String name, @NotNull byte[] data) {
+ GeneratedClassLoader loader = loaders.computeIfAbsent(parentLoader, GeneratedClassLoader::new);
+ synchronized (loader.getClassLoadingLock(name)) {
+ Preconditions.checkState(!loader.hasClass(name), "%s already defined", name);
+ final Class<?> c = loader.define(name, data);
+ Class<?> c = loader.define(name, data);
+ assert c.getName().equals(name);
+ return c;
+ }
+ }
+
+ private static class GeneratedClassLoader extends ClassLoader {
+
+ static {
+ ClassLoader.registerAsParallelCapable();
+ }
+
+ protected GeneratedClassLoader(final ClassLoader parent) {
+ protected GeneratedClassLoader(@NotNull ClassLoader parent) {
+ super(parent);
+ }
+
+ 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);
+ private Class<?> define(@NotNull String name, byte[] data) {
+ synchronized (getClassLoadingLock(name)) {
+ assert !hasClass(name);
+ Class<?> c = defineClass(name, data, 0, data.length);
+ resolveClass(c);
+ return c;
+ }
+ }
+
+ @Override
+ public Object getClassLoadingLock(final String name) {
+ @NotNull
+ public Object getClassLoadingLock(@NotNull String name) {
+ return super.getClassLoadingLock(name);
+ }
+
+ public boolean hasClass(final String name) {
+ synchronized (this.getClassLoadingLock(name)) {
+ public boolean hasClass(@NotNull String name) {
+ synchronized (getClassLoadingLock(name)) {
+ try {
+ Class.forName(name);
+ return true;
+ } catch (final ClassNotFoundException e) {
+ } catch (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 1f627e81622e77b81b1228a467fbb9e6fd979e7a..3c50362de25617d878ef58f14f67c240005ff624 100644
index ed0b67ac322aa22b191cd35502ae5b4f20af19f8..258d7010d24c529c9bbc76cc26adf226c641ee58 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -52,7 +52,7 @@ dependencies {
@ -17,7 +17,7 @@ index 1f627e81622e77b81b1228a467fbb9e6fd979e7a..3c50362de25617d878ef58f14f67c240
compileOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
compileOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18")
@@ -141,6 +141,7 @@ tasks.withType<Javadoc> {
@@ -139,6 +139,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 1f627e81622e77b81b1228a467fbb9e6fd979e7a..3c50362de25617d878ef58f14f67c240
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..c78ada48e27c5552529fe8d5bc23db1dac94e481
index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c27846933
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/PermissionManager.java
@@ -0,0 +1,166 @@
@@ -0,0 +1,171 @@
+package io.papermc.paper.plugin;
+
+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;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 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,7 +55,8 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ * @param name Name of the permission
+ * @return Permission, or null if none
+ */
+ @Nullable Permission getPermission(String name);
+ @Nullable
+ Permission getPermission(@NotNull String name);
+
+ /**
+ * Adds a {@link Permission} to this plugin manager.
@ -67,7 +68,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ * @throws IllegalArgumentException Thrown when a permission with the same
+ * name already exists
+ */
+ void addPermission(Permission perm);
+ void addPermission(@NotNull Permission perm);
+
+ /**
+ * Removes a {@link Permission} registration from this plugin manager.
@ -80,7 +81,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ *
+ * @param perm Permission to remove
+ */
+ void removePermission(Permission perm);
+ void removePermission(@NotNull Permission perm);
+
+ /**
+ * Removes a {@link Permission} registration from this plugin manager.
@ -93,7 +94,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ *
+ * @param name Permission to remove
+ */
+ void removePermission(String name);
+ void removePermission(@NotNull String name);
+
+ /**
+ * Gets the default permissions for the given op status
@ -101,6 +102,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ * @param op Which set of default permissions to get
+ * @return The default permissions
+ */
+ @NotNull
+ Set<Permission> getDefaultPermissions(boolean op);
+
+ /**
@ -111,7 +113,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ *
+ * @param perm Permission to recalculate
+ */
+ void recalculatePermissionDefaults(Permission perm);
+ void recalculatePermissionDefaults(@NotNull Permission perm);
+
+ /**
+ * Subscribes the given Permissible for information about the requested
@ -123,7 +125,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ * @param permission Permission to subscribe to
+ * @param permissible Permissible subscribing
+ */
+ void subscribeToPermission(String permission, Permissible permissible);
+ void subscribeToPermission(@NotNull String permission, @NotNull Permissible permissible);
+
+ /**
+ * Unsubscribes the given Permissible for information about the requested
@ -132,7 +134,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ * @param permission Permission to unsubscribe from
+ * @param permissible Permissible subscribing
+ */
+ void unsubscribeFromPermission(String permission, Permissible permissible);
+ void unsubscribeFromPermission(@NotNull String permission, @NotNull Permissible permissible);
+
+ /**
+ * Gets a set containing all subscribed {@link Permissible}s to the given
@ -141,7 +143,8 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ * @param permission Permission to query for
+ * @return Set containing all subscribed permissions
+ */
+ Set<Permissible> getPermissionSubscriptions(String permission);
+ @NotNull
+ Set<Permissible> getPermissionSubscriptions(@NotNull String permission);
+
+ /**
+ * Subscribes to the given Default permissions by operator status
@ -152,7 +155,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ * @param op Default list to subscribe to
+ * @param permissible Permissible subscribing
+ */
+ void subscribeToDefaultPerms(boolean op, Permissible permissible);
+ void subscribeToDefaultPerms(boolean op, @NotNull Permissible permissible);
+
+ /**
+ * Unsubscribes from the given Default permissions by operator status
@ -160,7 +163,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ * @param op Default list to unsubscribe from
+ * @param permissible Permissible subscribing
+ */
+ void unsubscribeFromDefaultPerms(boolean op, Permissible permissible);
+ void unsubscribeFromDefaultPerms(boolean op, @NotNull Permissible permissible);
+
+ /**
+ * Gets a set containing all subscribed {@link Permissible}s to the given
@ -169,6 +172,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ * @param op Default list to query for
+ * @return Set containing all subscribed permissions
+ */
+ @NotNull
+ Set<Permissible> getDefaultPermSubscriptions(boolean op);
+
+ /**
@ -178,6 +182,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ *
+ * @return Set containing all current registered permissions
+ */
+ @NotNull
+ Set<Permission> getPermissions();
+
+ /**
@ -187,7 +192,7 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+ *
+ * @param perm permission
+ */
+ void addPermissions(List<Permission> perm);
+ void addPermissions(@NotNull List<Permission> perm);
+
+ /**
+ * Clears the current registered permissinos.
@ -199,14 +204,13 @@ index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1d
+}
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..4c47414fc08e1183b1e59369bacc4d7f7042f262
index 0000000000000000000000000000000000000000..70d5f9802f90605a5120ff2a000a2e9395f0aecc
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java
@@ -0,0 +1,16 @@
@@ -0,0 +1,14 @@
+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
@ -215,13 +219,12 @@ index 0000000000000000000000000000000000000000..4c47414fc08e1183b1e59369bacc4d7f
+ * 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..e6696dcd8049e869bd1733f7c67ff802c54d7c37
index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8d287a11f
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrap.java
@@ -0,0 +1,41 @@
@ -230,7 +233,7 @@ index 0000000000000000000000000000000000000000..e6696dcd8049e869bd1733f7c67ff802
+import io.papermc.paper.plugin.provider.util.ProviderUtil;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A plugin bootstrap is meant for loading certain parts of the plugin before the server is loaded.
@ -242,9 +245,8 @@ index 0000000000000000000000000000000000000000..e6696dcd8049e869bd1733f7c67ff802
+ * <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.Experimental
+@NullMarked
+@ApiStatus.OverrideOnly
+@ApiStatus.Experimental
+public interface PluginBootstrap {
+
+ /**
@ -252,7 +254,7 @@ index 0000000000000000000000000000000000000000..e6696dcd8049e869bd1733f7c67ff802
+ *
+ * @param context the server provided context
+ */
+ void bootstrap(BootstrapContext context);
+ void bootstrap(@NotNull BootstrapContext context);
+
+ /**
+ * Called by the server to instantiate your main class.
@ -262,23 +264,25 @@ index 0000000000000000000000000000000000000000..e6696dcd8049e869bd1733f7c67ff802
+ * @param context the server created bootstrap object
+ * @return the server requested instance of the plugins main class.
+ */
+ default JavaPlugin createPlugin(final PluginProviderContext context) {
+ @NotNull
+ default JavaPlugin createPlugin(@NotNull 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..19bb302ab264b72306d9bd15e9c40ade6dde7ee7
index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba46282bea5d1a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginProviderContext.java
@@ -0,0 +1,48 @@
@@ -0,0 +1,52 @@
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+import java.nio.file.Path;
+
+/**
+ * Represents the context provided to a {@link PluginBootstrap} during both the bootstrapping and plugin
@ -286,9 +290,8 @@ index 0000000000000000000000000000000000000000..19bb302ab264b72306d9bd15e9c40ade
+ * 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.Experimental
+@NullMarked
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental
+public interface PluginProviderContext {
+
+ /**
@ -296,6 +299,7 @@ index 0000000000000000000000000000000000000000..19bb302ab264b72306d9bd15e9c40ade
+ *
+ * @return the plugin's configuration
+ */
+ @NotNull
+ PluginMeta getConfiguration();
+
+ /**
@ -303,6 +307,7 @@ index 0000000000000000000000000000000000000000..19bb302ab264b72306d9bd15e9c40ade
+ *
+ * @return the previously described path
+ */
+ @NotNull
+ Path getDataDirectory();
+
+ /**
@ -310,6 +315,7 @@ index 0000000000000000000000000000000000000000..19bb302ab264b72306d9bd15e9c40ade
+ *
+ * @return the logger instance
+ */
+ @NotNull
+ ComponentLogger getLogger();
+
+ /**
@ -317,32 +323,33 @@ index 0000000000000000000000000000000000000000..19bb302ab264b72306d9bd15e9c40ade
+ *
+ * @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..3c768d5ccf490e962d9638e92d4ea7c85670bad8
index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9ada2e585f
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/configuration/PluginMeta.java
@@ -0,0 +1,186 @@
@@ -0,0 +1,203 @@
+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.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * This class acts as an abstraction for a plugin configuration.
+ */
+@ApiStatus.Experimental // Subject to change!
+@NullMarked
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental // Subject to change!
+public interface PluginMeta {
+
+ /**
@ -362,6 +369,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @return the name of the plugin
+ */
+ @NotNull
+ String getName();
+
+ /**
@ -369,6 +377,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @return a descriptive name of the plugin and respective version
+ */
+ @NotNull
+ default String getDisplayName() {
+ return this.getName() + " v" + this.getVersion();
+ }
@ -379,6 +388,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @return the fully qualified class name of the plugin's main class.
+ */
+ @NotNull
+ String getMainClass();
+
+ /**
@ -387,6 +397,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ * @return the plugin load order
+ * @see PluginLoadOrder for further details regards the available load orders.
+ */
+ @NotNull
+ PluginLoadOrder getLoadOrder();
+
+ /**
@ -396,6 +407,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @return the string representation of the plugin's version
+ */
+ @NotNull
+ String getVersion();
+
+ /**
@ -406,7 +418,8 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ * @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.
@ -417,6 +430,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @return an immutable list of required dependency names
+ */
+ @NotNull
+ List<String> getPluginDependencies();
+
+ /**
@ -429,6 +443,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @return immutable list of soft dependencies
+ */
+ @NotNull
+ List<String> getPluginSoftDependencies();
+
+ /**
@ -441,6 +456,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @return immutable list of plugins to load before this plugin
+ */
+ @NotNull
+ List<String> getLoadBeforePlugins();
+
+ /**
@ -450,6 +466,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @return immutable list of provided plugins/dependencies
+ */
+ @NotNull
+ List<String> getProvidedPlugins();
+
+ /**
@ -458,6 +475,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @return an immutable list of the plugin's authors
+ */
+ @NotNull
+ List<String> getAuthors();
+
+ /**
@ -466,6 +484,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @return an immutable list of the plugin's contributors
+ */
+ @NotNull
+ List<String> getContributors();
+
+ /**
@ -474,7 +493,8 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @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.
@ -482,7 +502,8 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ *
+ * @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.
@ -490,6 +511,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ * @return an immutable list of permissions
+ */
+ // TODO: Do we even want this? Why not just use the bootstrapper
+ @NotNull
+ List<Permission> getPermissions();
+
+ /**
@ -499,6 +521,7 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ * @see #getPermissions()
+ */
+ // TODO: Do we even want this? Why not just use the bootstrapper
+ @NotNull
+ PermissionDefault getPermissionDefault();
+
+ /**
@ -509,7 +532,8 @@ index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c8
+ * @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
@ -528,10 +552,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..ddb768057cdfd9202e4386494fd5f643692c73a1
index 0000000000000000000000000000000000000000..28cbc09b7c1ded1f4515969cef4a669adac85703
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/PluginClasspathBuilder.java
@@ -0,0 +1,37 @@
@@ -0,0 +1,38 @@
+package io.papermc.paper.plugin.loader;
+
+import io.papermc.paper.plugin.bootstrap.PluginProviderContext;
@ -539,15 +563,14 @@ index 0000000000000000000000000000000000000000..ddb768057cdfd9202e4386494fd5f643
+import io.papermc.paper.plugin.loader.library.LibraryStore;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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.Experimental
+@NullMarked
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental
+public interface PluginClasspathBuilder {
+
+ /**
@ -564,21 +587,23 @@ index 0000000000000000000000000000000000000000..ddb768057cdfd9202e4386494fd5f643
+ * @see io.papermc.paper.plugin.loader.library.impl.JarLibrary
+ * @see io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver
+ */
+ @NotNull
+ @Contract("_ -> this")
+ PluginClasspathBuilder addLibrary(ClassPathLibrary classPathLibrary);
+ PluginClasspathBuilder addLibrary(@NotNull 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..c2d029e4474cc00c84e5b3f7fceec4c3f30b486b
index 0000000000000000000000000000000000000000..c9e31f78ff6ff969436c6d99755845786c4d383f
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/PluginLoader.java
@@ -0,0 +1,31 @@
@@ -0,0 +1,30 @@
+package io.papermc.paper.plugin.loader;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A plugin loader is responsible for creating certain aspects of a plugin before it is created.
@ -590,9 +615,8 @@ index 0000000000000000000000000000000000000000..c2d029e4474cc00c84e5b3f7fceec4c3
+ * 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.Experimental
+@NullMarked
+@ApiStatus.OverrideOnly
+@ApiStatus.Experimental
+public interface PluginLoader {
+
+ /**
@ -603,24 +627,23 @@ index 0000000000000000000000000000000000000000..c2d029e4474cc00c84e5b3f7fceec4c3
+ * @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(PluginClasspathBuilder classpathBuilder);
+ void classloader(@NotNull 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..8a07333a592056bab1d26d811316bb5ea5f30e18
index 0000000000000000000000000000000000000000..1347b535d90c2c281c184d0459e7ac59c0350c9f
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/ClassPathLibrary.java
@@ -0,0 +1,21 @@
@@ -0,0 +1,20 @@
+package io.papermc.paper.plugin.loader.library;
+
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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 {
+
+ /**
@ -631,7 +654,7 @@ index 0000000000000000000000000000000000000000..8a07333a592056bab1d26d811316bb5e
+ * @param store the library store instance to register this library into
+ * @throws LibraryLoadingException if library loading failed for this classpath library
+ */
+ void register(LibraryStore store) throws LibraryLoadingException;
+ void register(@NotNull 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
@ -656,15 +679,16 @@ 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..93ef8e369a158c25bc4fdd553faf13c1826ad872
index 0000000000000000000000000000000000000000..0546fa1e9dcd7155086a8650806a8c086b6fc458
--- /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 java.nio.file.Path;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+import java.nio.file.Path;
+
+/**
+ * Represents a storage that stores library jars.
@ -675,7 +699,6 @@ index 0000000000000000000000000000000000000000..93ef8e369a158c25bc4fdd553faf13c1
+ * @see io.papermc.paper.plugin.loader.PluginLoader
+ */
+@ApiStatus.Internal
+@NullMarked
+public interface LibraryStore {
+
+ /**
@ -683,12 +706,12 @@ index 0000000000000000000000000000000000000000..93ef8e369a158c25bc4fdd553faf13c1
+ *
+ * @param library path to the libraries jar file on the disk
+ */
+ void addLibrary(Path library);
+ void addLibrary(@NotNull 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..9efcd9a62d6439eb27fc4e08498b4b7fbbdecb3c
index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff25961ee79fb
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/JarLibrary.java
@@ -0,0 +1,45 @@
@ -697,9 +720,10 @@ index 0000000000000000000000000000000000000000..9efcd9a62d6439eb27fc4e08498b4b7f
+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
@ -714,7 +738,6 @@ index 0000000000000000000000000000000000000000..9efcd9a62d6439eb27fc4e08498b4b7f
+ * <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;
@ -724,12 +747,12 @@ index 0000000000000000000000000000000000000000..9efcd9a62d6439eb27fc4e08498b4b7f
+ *
+ * @param path the path, relative to the JVMs start directory.
+ */
+ public JarLibrary(final Path path) {
+ public JarLibrary(@NotNull Path path) {
+ this.path = path;
+ }
+
+ @Override
+ public void register(final LibraryStore store) throws LibraryLoadingException {
+ public void register(@NotNull LibraryStore store) throws LibraryLoadingException {
+ if (Files.notExists(this.path)) {
+ throw new LibraryLoadingException("Could not find library at " + this.path);
+ }
@ -739,7 +762,7 @@ index 0000000000000000000000000000000000000000..9efcd9a62d6439eb27fc4e08498b4b7f
+}
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..107705db2d82b7c191e5e625ec888e0bc3b03831
index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19a94791ab
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java
@@ -0,0 +1,133 @@
@ -748,9 +771,6 @@ index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0b
+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;
@ -771,10 +791,14 @@ index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0b
+import org.eclipse.aether.transfer.TransferCancelledException;
+import org.eclipse.aether.transfer.TransferEvent;
+import org.eclipse.aether.transport.http.HttpTransporterFactory;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+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.
@ -789,13 +813,12 @@ index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0b
+ * "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;
@ -811,7 +834,7 @@ index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0b
+ * submitting the {@link MavenLibraryResolver} to the {@link io.papermc.paper.plugin.loader.PluginClasspathBuilder}.
+ */
+ public MavenLibraryResolver() {
+ final DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
+ DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
+ locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
+ locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
+
@ -823,8 +846,8 @@ index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0b
+ this.session.setLocalRepositoryManager(this.repository.newLocalRepositoryManager(this.session, new LocalRepository("libraries")));
+ this.session.setTransferListener(new AbstractTransferListener() {
+ @Override
+ public void transferInitiated(final TransferEvent event) throws TransferCancelledException {
+ LOGGER.info("Downloading {}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
+ public void transferInitiated(@NotNull TransferEvent event) throws TransferCancelledException {
+ logger.info("Downloading {}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
+ }
+ });
+ this.session.setReadOnly();
@ -837,7 +860,7 @@ index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0b
+ * @param dependency the definition of the dependency the maven library resolver should resolve when running
+ * @see MavenLibraryResolver#addRepository(RemoteRepository)
+ */
+ public void addDependency(final Dependency dependency) {
+ public void addDependency(@NotNull Dependency dependency) {
+ this.dependencies.add(dependency);
+ }
+
@ -847,9 +870,9 @@ index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0b
+ * repository.
+ *
+ * @param remoteRepository the configuration that defines the maven repository this library resolver should fetch
+ * dependencies from
+ * dependencies from
+ */
+ public void addRepository(final RemoteRepository remoteRepository) {
+ public void addRepository(@NotNull RemoteRepository remoteRepository) {
+ this.repositories.add(remoteRepository);
+ }
+
@ -860,32 +883,32 @@ index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0b
+ * @throws LibraryLoadingException if resolving a dependency failed
+ */
+ @Override
+ public void register(final LibraryStore store) throws LibraryLoadingException {
+ final List<RemoteRepository> repos = this.repository.newResolutionRepositories(this.session, this.repositories);
+ public void register(@NotNull LibraryStore store) throws LibraryLoadingException {
+ List<RemoteRepository> repos = this.repository.newResolutionRepositories(this.session, this.repositories);
+
+ final DependencyResult result;
+ DependencyResult result;
+ try {
+ result = this.repository.resolveDependencies(this.session, new DependencyRequest(new CollectRequest((Dependency) null, this.dependencies, repos), null));
+ } catch (final DependencyResolutionException ex) {
+ } catch (DependencyResolutionException ex) {
+ throw new LibraryLoadingException("Error resolving libraries", ex);
+ }
+
+ for (final ArtifactResult artifact : result.getArtifactResults()) {
+ final File file = artifact.getArtifact().getFile();
+ for (ArtifactResult artifact : result.getArtifactResults()) {
+ 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..75fe408ec742319c3cba2461b33b2a6e8b22d231
index 0000000000000000000000000000000000000000..64e46fdfa4d404cb08c67a456e5990b729296b98
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/ClassLoaderAccess.java
@@ -0,0 +1,35 @@
@@ -0,0 +1,34 @@
+package io.papermc.paper.plugin.provider.classloader;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * The class loader access interface is an <b>internal</b> representation of a class accesses' ability to see types
@ -896,7 +919,6 @@ index 0000000000000000000000000000000000000000..75fe408ec742319c3cba2461b33b2a6e
+ * 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 {
+
@ -919,18 +941,19 @@ index 0000000000000000000000000000000000000000..75fe408ec742319c3cba2461b33b2a6e
+}
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..7c23e0a1a38f8b89484aee160647f751088903cd
index 0000000000000000000000000000000000000000..a21bdc57564aef7caf43dde3b2bcb2fc7f30461c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/ConfiguredPluginClassLoader.java
@@ -0,0 +1,70 @@
@@ -0,0 +1,71 @@
+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.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.Closeable;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * The configured plugin class loader represents an <b>internal</b> abstraction over the classloaders used by the server
@ -939,7 +962,6 @@ index 0000000000000000000000000000000000000000..7c23e0a1a38f8b89484aee160647f751
+ * 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 {
+
@ -965,7 +987,7 @@ index 0000000000000000000000000000000000000000..7c23e0a1a38f8b89484aee160647f751
+ * @see ClassLoader#loadClass(String)
+ * @see Class#forName(String, boolean, ClassLoader)
+ */
+ Class<?> loadClass(String name,
+ Class<?> loadClass(@NotNull String name,
+ boolean resolve,
+ boolean checkGlobal,
+ boolean checkLibraries) throws ClassNotFoundException;
@ -991,7 +1013,8 @@ index 0000000000000000000000000000000000000000..7c23e0a1a38f8b89484aee160647f751
+ * 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
@ -1116,16 +1139,15 @@ 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..dd3bfbf8a30c9ac6a82dcbdf879bbf120d920e20
index 0000000000000000000000000000000000000000..885151cb932d9b8c09a7887edc879e154225f416
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/PluginClassLoaderGroup.java
@@ -0,0 +1,66 @@
@@ -0,0 +1,65 @@
+package io.papermc.paper.plugin.provider.classloader;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * A plugin classloader group represents a group of classloaders that a plugins classloader may access.
@ -1133,7 +1155,6 @@ index 0000000000000000000000000000000000000000..dd3bfbf8a30c9ac6a82dcbdf879bbf12
+ * 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 {
+
@ -1151,7 +1172,8 @@ index 0000000000000000000000000000000000000000..dd3bfbf8a30c9ac6a82dcbdf879bbf12
+ * 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.
@ -1188,15 +1210,15 @@ index 0000000000000000000000000000000000000000..dd3bfbf8a30c9ac6a82dcbdf879bbf12
+}
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..338dc25d5161b7378dd17b17d6f603c92eb0a894
index 0000000000000000000000000000000000000000..44d630c3eb2670c36134b9907519dc986b3761b4
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/entrypoint/DependencyContext.java
@@ -0,0 +1,49 @@
@@ -0,0 +1,48 @@
+package io.papermc.paper.plugin.provider.entrypoint;
+
+import io.papermc.paper.plugin.configuration.PluginMeta;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A dependency context is a read-only abstraction of a type/concept that can resolve dependencies between plugins.
@ -1204,7 +1226,6 @@ index 0000000000000000000000000000000000000000..338dc25d5161b7378dd17b17d6f603c9
+ * 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 {
+
@ -1224,7 +1245,7 @@ index 0000000000000000000000000000000000000000..338dc25d5161b7378dd17b17d6f603c9
+ * @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(PluginMeta plugin, PluginMeta depend);
+ boolean isTransitiveDependency(@NotNull PluginMeta plugin, @NotNull PluginMeta depend);
+
+ /**
+ * Computes if this dependency context is aware of a dependency that provides/matches the passed identifier.
@ -1238,30 +1259,29 @@ index 0000000000000000000000000000000000000000..338dc25d5161b7378dd17b17d6f603c9
+ * @return a plain boolean flag indicating if this dependency context is aware of a potential dependency with the
+ * passed identifier.
+ */
+ boolean hasDependency(String pluginIdentifier);
+ boolean hasDependency(@NotNull 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..48a67c1b6070292dbf4ea3081f89b530207f9f6d
index 0000000000000000000000000000000000000000..6bf3d212a6156ad9ab0e82d1ca0a04f83f6e4b83
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java
@@ -0,0 +1,77 @@
@@ -0,0 +1,78 @@
+package io.papermc.paper.plugin.provider.util;
+
+import com.destroystokyo.paper.util.SneakyThrow;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.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 final class ProviderUtil {
+public class ProviderUtil {
+
+ /**
+ * Loads the class found at the provided fully qualified class name from the passed classloader, creates a new
@ -1274,7 +1294,8 @@ index 0000000000000000000000000000000000000000..48a67c1b6070292dbf4ea3081f89b530
+ * @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
+ */
+ public static <T> T loadClass(final String clazz, final Class<T> classType, final ClassLoader loader) {
+ @NotNull
+ public static <T> T loadClass(@NotNull String clazz, @NotNull Class<T> classType, @NotNull ClassLoader loader) {
+ return loadClass(clazz, classType, loader, null);
+ }
+
@ -1291,29 +1312,30 @@ index 0000000000000000000000000000000000000000..48a67c1b6070292dbf4ea3081f89b530
+ * @return the object instantiated from the class found at the provided fully qualified class name, cast to the
+ * parent type
+ */
+ public static <T> T loadClass(final String clazz, final Class<T> classType, final ClassLoader loader, final @Nullable Runnable onError) {
+ @NotNull
+ public static <T> T loadClass(@NotNull String clazz, @NotNull Class<T> classType, @NotNull ClassLoader loader, @Nullable Runnable onError) {
+ try {
+ final T clazzInstance;
+ T clazzInstance;
+
+ try {
+ final Class<?> jarClass = Class.forName(clazz, true, loader);
+ Class<?> jarClass = Class.forName(clazz, true, loader);
+
+ final Class<? extends T> pluginClass;
+ Class<? extends T> pluginClass;
+ try {
+ pluginClass = jarClass.asSubclass(classType);
+ } catch (final ClassCastException ex) {
+ } catch (ClassCastException ex) {
+ throw new ClassCastException("class '%s' does not extend '%s'".formatted(clazz, classType));
+ }
+
+ clazzInstance = pluginClass.getDeclaredConstructor().newInstance();
+ } catch (final IllegalAccessException exception) {
+ } catch (IllegalAccessException exception) {
+ throw new RuntimeException("No public constructor");
+ } catch (final InstantiationException exception) {
+ } catch (InstantiationException exception) {
+ throw new RuntimeException("Abnormal class instantiation", exception);
+ }
+
+ return clazzInstance;
+ } catch (final Throwable e) {
+ } catch (Throwable e) {
+ if (onError != null) {
+ onError.run();
+ }

View file

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

View file

@ -10,21 +10,18 @@ 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..023cc52a9e28e1238c7452c0f3f577f2850fd861
index 0000000000000000000000000000000000000000..a736d7bcdc5861a01b66ba36158db1c716339346
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java
@@ -0,0 +1,47 @@
@@ -0,0 +1,45 @@
+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.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+@NullMarked
+public interface VersionFetcher {
+
+ /**
+ * Amount of time to cache results for in milliseconds
+ * <p>
@ -42,9 +39,9 @@ index 0000000000000000000000000000000000000000..023cc52a9e28e1238c7452c0f3f577f2
+ * @param serverVersion the current version of the server (will match {@link Bukkit#getVersion()})
+ * @return the message to show when requesting a version
+ */
+ Component getVersionMessage(String serverVersion);
+ @NotNull
+ Component getVersionMessage(@NotNull String serverVersion);
+
+ @ApiStatus.Internal
+ class DummyVersionFetcher implements VersionFetcher {
+
+ @Override
@ -52,8 +49,9 @@ index 0000000000000000000000000000000000000000..023cc52a9e28e1238c7452c0f3f577f2
+ return -1;
+ }
+
+ @NotNull
+ @Override
+ public Component getVersionMessage(final String serverVersion) {
+ public Component getVersionMessage(@NotNull 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();
@ -63,10 +61,10 @@ index 0000000000000000000000000000000000000000..023cc52a9e28e1238c7452c0f3f577f2
+}
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..652ff54e7c50412503725d628bfe72ed03059790
index 0000000000000000000000000000000000000000..9df9d09aa477d4cd3c496ba0933c816df1ef0964
--- /dev/null
+++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java
@@ -0,0 +1,122 @@
@@ -0,0 +1,121 @@
+package io.papermc.paper;
+
+import java.time.Instant;
@ -75,12 +73,11 @@ index 0000000000000000000000000000000000000000..652ff54e7c50412503725d628bfe72ed
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.util.Services;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Information about the current server build.
+ */
+@NullMarked
+@ApiStatus.NonExtendable
+public interface ServerBuildInfo {
+ /**
@ -93,7 +90,7 @@ index 0000000000000000000000000000000000000000..652ff54e7c50412503725d628bfe72ed
+ *
+ * @return the {@code ServerBuildInfo}
+ */
+ static ServerBuildInfo buildInfo() {
+ static @NotNull ServerBuildInfo buildInfo() {
+ //<editor-fold defaultstate="collapsed" desc="Holder">
+ final class Holder {
+ static final Optional<ServerBuildInfo> INSTANCE = Services.service(ServerBuildInfo.class);
@ -107,7 +104,7 @@ index 0000000000000000000000000000000000000000..652ff54e7c50412503725d628bfe72ed
+ *
+ * @return the brand id of the server (e.g. "papermc:paper")
+ */
+ Key brandId();
+ @NotNull Key brandId();
+
+ /**
+ * Checks if the current server supports the specified brand.
@ -116,56 +113,56 @@ index 0000000000000000000000000000000000000000..652ff54e7c50412503725d628bfe72ed
+ * @return {@code true} if the server supports the specified brand
+ */
+ @ApiStatus.Experimental
+ boolean isBrandCompatible(final Key brandId);
+ boolean isBrandCompatible(final @NotNull Key brandId);
+
+ /**
+ * Gets the brand name of the server.
+ *
+ * @return the brand name of the server (e.g. "Paper")
+ */
+ String brandName();
+ @NotNull String brandName();
+
+ /**
+ * Gets the Minecraft version id.
+ *
+ * @return the Minecraft version id (e.g. "1.20.4", "1.20.2-pre2", "23w31a")
+ */
+ String minecraftVersionId();
+ @NotNull String minecraftVersionId();
+
+ /**
+ * Gets the Minecraft version name.
+ *
+ * @return the Minecraft version name (e.g. "1.20.4", "1.20.2 Pre-release 2", "23w31a")
+ */
+ String minecraftVersionName();
+ @NotNull String minecraftVersionName();
+
+ /**
+ * Gets the build number.
+ *
+ * @return the build number
+ */
+ OptionalInt buildNumber();
+ @NotNull OptionalInt buildNumber();
+
+ /**
+ * Gets the build time.
+ *
+ * @return the build time
+ */
+ Instant buildTime();
+ @NotNull Instant buildTime();
+
+ /**
+ * Gets the git commit branch.
+ *
+ * @return the git commit branch
+ */
+ Optional<String> gitBranch();
+ @NotNull Optional<String> gitBranch();
+
+ /**
+ * Gets the git commit hash.
+ *
+ * @return the git commit hash
+ */
+ Optional<String> gitCommit();
+ @NotNull Optional<String> gitCommit();
+
+ /**
+ * Creates a string representation of the server build information.
@ -173,7 +170,7 @@ index 0000000000000000000000000000000000000000..652ff54e7c50412503725d628bfe72ed
+ * @param representation the type of representation
+ * @return a string
+ */
+ String asString(final StringRepresentation representation);
+ @NotNull String asString(final @NotNull StringRepresentation representation);
+
+ /**
+ * String representation types.
@ -191,10 +188,10 @@ index 0000000000000000000000000000000000000000..652ff54e7c50412503725d628bfe72ed
+}
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..7915a70d676b1205dcae39259f670af258a1ab9b
index 0000000000000000000000000000000000000000..909617079db61b675cc7b60b44ef96b306076343
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/JarManifests.java
@@ -0,0 +1,38 @@
@@ -0,0 +1,37 @@
+package io.papermc.paper.util;
+
+import java.io.IOException;
@ -205,10 +202,9 @@ index 0000000000000000000000000000000000000000..7915a70d676b1205dcae39259f670af2
+import java.util.WeakHashMap;
+import java.util.jar.Manifest;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@NullMarked
+@ApiStatus.Internal
+public final class JarManifests {
+ private JarManifests() {
@ -216,7 +212,7 @@ index 0000000000000000000000000000000000000000..7915a70d676b1205dcae39259f670af2
+
+ private static final Map<ClassLoader, Manifest> MANIFESTS = Collections.synchronizedMap(new WeakHashMap<>());
+
+ public static @Nullable Manifest manifest(final Class<?> clazz) {
+ public static @Nullable Manifest manifest(final @NotNull 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..741d0e73bc635a545c94c4b1254cee8f41ba8925
index 0000000000000000000000000000000000000000..7270c1feece2dc15a4a0503c4bca93a1288f8f13
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java
@@ -0,0 +1,88 @@
@@ -0,0 +1,91 @@
+package com.destroystokyo.paper.event.block;
+
+import org.bukkit.block.Block;
@ -19,12 +19,11 @@ index 0000000000000000000000000000000000000000..741d0e73bc635a545c94c4b1254cee8f
+import org.bukkit.event.block.BlockEvent;
+import org.bukkit.potion.PotionEffect;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
@ -36,7 +35,7 @@ index 0000000000000000000000000000000000000000..741d0e73bc635a545c94c4b1254cee8f
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public BeaconEffectEvent(final Block block, final PotionEffect effect, final Player player, final boolean primary) {
+ public BeaconEffectEvent(@NotNull Block block, @NotNull PotionEffect effect, @NotNull Player player, boolean primary) {
+ super(block);
+ this.effect = effect;
+ this.player = player;
@ -48,6 +47,7 @@ index 0000000000000000000000000000000000000000..741d0e73bc635a545c94c4b1254cee8f
+ *
+ * @return Potion effect
+ */
+ @NotNull
+ public PotionEffect getEffect() {
+ return this.effect;
+ }
@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..741d0e73bc635a545c94c4b1254cee8f
+ *
+ * @param effect Potion effect
+ */
+ public void setEffect(final PotionEffect effect) {
+ public void setEffect(@NotNull PotionEffect effect) {
+ this.effect = effect;
+ }
+
@ -66,6 +66,7 @@ index 0000000000000000000000000000000000000000..741d0e73bc635a545c94c4b1254cee8f
+ *
+ * @return Affected player
+ */
+ @NotNull
+ public Player getPlayer() {
+ return this.player;
+ }
@ -85,15 +86,17 @@ index 0000000000000000000000000000000000000000..741d0e73bc635a545c94c4b1254cee8f
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,31 +6,30 @@ 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..95a5a59e6bd88345177fca0b12008ddd689cb448
index 0000000000000000000000000000000000000000..9377ee1c2368ce058397037952d17bc010f66957
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java
@@ -0,0 +1,43 @@
@@ -0,0 +1,45 @@
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final ServerException exception;
+ @NotNull private final ServerException exception;
+
+ @ApiStatus.Internal
+ public ServerExceptionEvent(final ServerException exception) {
+ public ServerExceptionEvent(@NotNull ServerException exception) {
+ super(!Bukkit.isPrimaryThread());
+ this.exception = exception;
+ }
@ -40,15 +39,18 @@ index 0000000000000000000000000000000000000000..95a5a59e6bd88345177fca0b12008ddd
+ *
+ * @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

@ -7,7 +7,7 @@ Upstream added methods for this so the original methods
are now deprecated
diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java
index b5a302ba913d2de97f1bcd7c60fd5cd4f245d275..cafa79f80eec5ec6d8d31d40cc2b46acc06831f9 100644
index 67115810d5e837f154c3accd92dbb5e4192d264f..32e89741ffd895e31af0104a0126c2f72742a1bb 100644
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -243,12 +243,44 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
@ -56,7 +56,7 @@ index b5a302ba913d2de97f1bcd7c60fd5cd4f245d275..cafa79f80eec5ec6d8d31d40cc2b46ac
/**
* Returns the living entity's current maximum no damage ticks.
@@ -787,4 +819,24 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
@@ -777,4 +809,24 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
* @return Whether the entity is invisible
*/
public boolean isInvisible();

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..11f8540a4752cf4d2112eff48bcca3b935c9f8b1
index 0000000000000000000000000000000000000000..1d8e3c93a139bba11affca74b742269f24300d2c
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityAddToWorldEvent.java
@@ -0,0 +1,44 @@
@@ -0,0 +1,45 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.World;
@ -18,22 +18,21 @@ index 0000000000000000000000000000000000000000..11f8540a4752cf4d2112eff48bcca3b9
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final World world;
+ @NotNull private final World world;
+
+ @ApiStatus.Internal
+ public EntityAddToWorldEvent(final Entity entity, final World world) {
+ public EntityAddToWorldEvent(@NotNull Entity entity, @NotNull World world) {
+ super(entity);
+ this.world = world;
+ }
@ -41,25 +40,27 @@ index 0000000000000000000000000000000000000000..11f8540a4752cf4d2112eff48bcca3b9
+ /**
+ * @return The world that the entity is being added to
+ */
+ @NotNull
+ public World getWorld() {
+ return this.world;
+ }
+
+ @Override
+ @NotNull
+ 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..5ad5632d4d47d8b42e4f2af19c0fe6cf94ac5643
index 0000000000000000000000000000000000000000..d75e6a8334c7408ea8c3f155414fc14dc427f190
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityRemoveFromWorldEvent.java
@@ -0,0 +1,42 @@
@@ -0,0 +1,43 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.World;
@ -67,21 +68,20 @@ index 0000000000000000000000000000000000000000..5ad5632d4d47d8b42e4f2af19c0fe6cf
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final World world;
+ @NotNull private final World world;
+
+ @ApiStatus.Internal
+ public EntityRemoveFromWorldEvent(final Entity entity, final World world) {
+ public EntityRemoveFromWorldEvent(@NotNull Entity entity, @NotNull World world) {
+ super(entity);
+ this.world = world;
+ }
@ -89,15 +89,17 @@ index 0000000000000000000000000000000000000000..5ad5632d4d47d8b42e4f2af19c0fe6cf
+ /**
+ * @return The world that the entity is being removed from
+ */
+ @NotNull
+ public World getWorld() {
+ return this.world;
+ }
+
+ @Override
+ @NotNull
+ 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..8624e0a528985c9b118f5e8a0f33d3286af2fc36
index 0000000000000000000000000000000000000000..8267e8f1f0ade29a284831069e1268ee4b29e109
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityPathfindEvent.java
@@ -0,0 +1,84 @@
@@ -0,0 +1,87 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.Location;
@ -19,8 +19,8 @@ index 0000000000000000000000000000000000000000..8624e0a528985c9b118f5e8a0f33d328
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Fired when an Entity decides to start moving towards a location.
@ -28,17 +28,16 @@ index 0000000000000000000000000000000000000000..8624e0a528985c9b118f5e8a0f33d328
+ * 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();
+
+ private final @Nullable Entity targetEntity;
+ private final Location location;
+ @Nullable private final Entity targetEntity;
+ @NotNull private final Location location;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EntityPathfindEvent(final Entity entity, final Location location, final @Nullable Entity targetEntity) {
+ public EntityPathfindEvent(@NotNull Entity entity, @NotNull Location location, @Nullable Entity targetEntity) {
+ super(entity);
+ this.targetEntity = targetEntity;
+ this.location = location;
@ -49,7 +48,7 @@ index 0000000000000000000000000000000000000000..8624e0a528985c9b118f5e8a0f33d328
+ *
+ * @return The Entity that is pathfinding.
+ */
+ @Override
+ @NotNull
+ public Entity getEntity() {
+ return this.entity;
+ }
@ -57,11 +56,12 @@ index 0000000000000000000000000000000000000000..8624e0a528985c9b118f5e8a0f33d328
+ /**
+ * 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}
+ */
+ public @Nullable Entity getTargetEntity() {
+ @Nullable
+ public Entity getTargetEntity() {
+ return this.targetEntity;
+ }
+
@ -72,6 +72,7 @@ index 0000000000000000000000000000000000000000..8624e0a528985c9b118f5e8a0f33d328
+ *
+ * @return Location of where the entity is trying to pathfind to.
+ */
+ @NotNull
+ public Location getLoc() {
+ return this.location.clone();
+ }
@ -82,15 +83,17 @@ index 0000000000000000000000000000000000000000..8624e0a528985c9b118f5e8a0f33d328
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..9ff2bbf7f99df45cc626cad60bec4d14a8a04e3e
index 0000000000000000000000000000000000000000..dbb635686e9108b9d3df5d373e6972cca07c0621
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java
@@ -0,0 +1,85 @@
@@ -0,0 +1,86 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.entity.Player;
@ -23,8 +23,8 @@ index 0000000000000000000000000000000000000000..9ff2bbf7f99df45cc626cad60bec4d14
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Represents an event that is called when a player right-clicks an unknown entity.
@ -33,18 +33,17 @@ index 0000000000000000000000000000000000000000..9ff2bbf7f99df45cc626cad60bec4d14
+ * 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 EquipmentSlot hand;
+ private final @NotNull EquipmentSlot hand;
+ private final @Nullable Vector clickedPosition;
+
+ @ApiStatus.Internal
+ public PlayerUseUnknownEntityEvent(final Player player, final int entityId, final boolean attack, final EquipmentSlot hand, final @Nullable Vector clickedPosition) {
+ public PlayerUseUnknownEntityEvent(@NotNull Player player, int entityId, boolean attack, @NotNull EquipmentSlot hand, @Nullable Vector clickedPosition) {
+ super(player);
+ this.entityId = entityId;
+ this.attack = attack;
@ -75,7 +74,7 @@ index 0000000000000000000000000000000000000000..9ff2bbf7f99df45cc626cad60bec4d14
+ *
+ * @return the hand used to interact
+ */
+ public EquipmentSlot getHand() {
+ public @NotNull EquipmentSlot getHand() {
+ return this.hand;
+ }
+
@ -90,11 +89,13 @@ index 0000000000000000000000000000000000000000..9ff2bbf7f99df45cc626cad60bec4d14
+ 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,14 +7,13 @@ 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..aea04fb357f5728195fd9c9bdcd6304a0b953c45
index 0000000000000000000000000000000000000000..7c049bad187b94331f42f96833d1cf4ce03ef477
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java
@@ -0,0 +1,257 @@
@@ -0,0 +1,267 @@
+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;
@ -22,8 +21,10 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.UUID;
+
+/**
+ * This event is fired during a player handshake.
@ -33,17 +34,16 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * <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();
+
+ private final String originalHandshake;
+ private final String originalSocketAddressHostname;
+ private @Nullable String serverHostname;
+ private @Nullable String socketAddressHostname;
+ private @Nullable UUID uniqueId;
+ private @Nullable String propertiesJson;
+ @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 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..aea04fb357f5728195fd9c9bdcd6304a
+
+ @Deprecated
+ @ApiStatus.Internal
+ public PlayerHandshakeEvent(final String originalHandshake, final boolean cancelled) {
+ public PlayerHandshakeEvent(@NotNull String originalHandshake, boolean cancelled) {
+ this(originalHandshake, "127.0.0.1", cancelled);
+ }
+
+ @ApiStatus.Internal
+ public PlayerHandshakeEvent(final String originalHandshake, final String originalSocketAddressHostname, final boolean cancelled) {
+ public PlayerHandshakeEvent(@NotNull String originalHandshake, @NotNull String originalSocketAddressHostname, boolean cancelled) {
+ super(true);
+ this.originalHandshake = originalHandshake;
+ this.originalSocketAddressHostname = originalSocketAddressHostname;
@ -85,7 +85,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ * @param cancel {@code true} if this event is cancelled, {@code false} otherwise
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
@ -94,6 +94,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @return the original handshake string
+ */
+ @NotNull
+ public String getOriginalHandshake() {
+ return this.originalHandshake;
+ }
@ -106,6 +107,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @return the original socket address hostname
+ */
+ @NotNull
+ public String getOriginalSocketAddressHostname() {
+ return this.originalSocketAddressHostname;
+ }
@ -117,7 +119,8 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @return the server hostname string
+ */
+ public @Nullable String getServerHostname() {
+ @Nullable
+ public String getServerHostname() {
+ return this.serverHostname;
+ }
+
@ -128,7 +131,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @param serverHostname the server hostname string
+ */
+ public void setServerHostname(final String serverHostname) {
+ public void setServerHostname(@NotNull String serverHostname) {
+ this.serverHostname = serverHostname;
+ }
+
@ -139,7 +142,8 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @return the socket address hostname string
+ */
+ public @Nullable String getSocketAddressHostname() {
+ @Nullable
+ public String getSocketAddressHostname() {
+ return this.socketAddressHostname;
+ }
+
@ -150,7 +154,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @param socketAddressHostname the socket address hostname string
+ */
+ public void setSocketAddressHostname(final String socketAddressHostname) {
+ public void setSocketAddressHostname(@NotNull String socketAddressHostname) {
+ this.socketAddressHostname = socketAddressHostname;
+ }
+
@ -159,7 +163,8 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @return the unique id
+ */
+ public @Nullable UUID getUniqueId() {
+ @Nullable
+ public UUID getUniqueId() {
+ return this.uniqueId;
+ }
+
@ -168,7 +173,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @param uniqueId the unique id
+ */
+ public void setUniqueId(final UUID uniqueId) {
+ public void setUniqueId(@NotNull UUID uniqueId) {
+ this.uniqueId = uniqueId;
+ }
+
@ -179,7 +184,8 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @return the profile properties, as JSON
+ */
+ public @Nullable String getPropertiesJson() {
+ @Nullable
+ public String getPropertiesJson() {
+ return this.propertiesJson;
+ }
+
@ -203,7 +209,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @param failed {@code true} if authentication failed, {@code false} otherwise
+ */
+ public void setFailed(final boolean failed) {
+ public void setFailed(boolean failed) {
+ this.failed = failed;
+ }
+
@ -214,7 +220,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @param propertiesJson the profile properties, as JSON
+ */
+ public void setPropertiesJson(final String propertiesJson) {
+ public void setPropertiesJson(@NotNull String propertiesJson) {
+ this.propertiesJson = propertiesJson;
+ }
+
@ -223,6 +229,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @return the message to display to the client
+ */
+ @NotNull
+ public Component failMessage() {
+ return this.failMessage;
+ }
@ -232,7 +239,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ *
+ * @param failMessage the message to display to the client
+ */
+ public void failMessage(final Component failMessage) {
+ public void failMessage(@NotNull Component failMessage) {
+ this.failMessage = failMessage;
+ }
+
@ -242,6 +249,7 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ * @return the message to display to the client
+ * @deprecated use {@link #failMessage()}
+ */
+ @NotNull
+ @Deprecated
+ public String getFailMessage() {
+ return LegacyComponentSerializer.legacySection().serialize(this.failMessage());
@ -254,16 +262,18 @@ index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a
+ * @deprecated use {@link #failMessage(Component)}
+ */
+ @Deprecated
+ public void setFailMessage(final String failMessage) {
+ public void setFailMessage(@NotNull 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,98 +12,96 @@ 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..6a03252d66a3e13c1960568ea23f6dcc673f34af
index 0000000000000000000000000000000000000000..92d7b853a2ccaae5afa8ac141bead840942944ef
--- /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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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..31ca54dea65dc0363a0ff7991ba5be3b06533876
index 0000000000000000000000000000000000000000..b387894fe8001edb41ad2ad2b70ebabe065b682e
--- /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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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..9fb621200fb3969e8e440341e906acc3547b4039
index 0000000000000000000000000000000000000000..b18a0b50c12fe8d8c954e5c070f2ecd1854a2583
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/LootableInventory.java
@@ -0,0 +1,128 @@
@@ -0,0 +1,124 @@
+package com.destroystokyo.paper.loottable;
+
+import java.util.UUID;
+import org.bukkit.entity.Player;
+import org.bukkit.loot.Lootable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+import java.util.UUID;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.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 an object in a world should refill
+ * Server owners have to enable whether or not an object in a world should refill
+ *
+ * @return If the world this inventory is currently in has Replenishable Lootables enabled
+ */
+ boolean isRefillEnabled();
+
+ /**
+ * Whether this object has ever been filled
+ *
+ * Whether or not 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 this player has looted this block
+ * @return Whether or not this player has looted this block
+ */
+ default boolean hasPlayerLooted(final Player player) {
+ default boolean hasPlayerLooted(final @NotNull Player player) {
+ return this.hasPlayerLooted(player.getUniqueId());
+ }
+
@ -111,17 +109,17 @@ index 0000000000000000000000000000000000000000..9fb621200fb3969e8e440341e906acc3
+ * 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(UUID player);
+ boolean canPlayerLoot(@NotNull UUID player);
+
+ /**
+ * Has this player ever looted this block
+ *
+ * @param player The player to check
+ * @return Whether this player has looted this block
+ * @return Whether or not this player has looted this block
+ */
+ boolean hasPlayerLooted(UUID player);
+ boolean hasPlayerLooted(@NotNull UUID player);
+
+ /**
+ * Gets the timestamp, in milliseconds, of when the player last looted this object
@ -129,7 +127,7 @@ index 0000000000000000000000000000000000000000..9fb621200fb3969e8e440341e906acc3
+ * @param player The player to check
+ * @return Timestamp last looted, or null if player has not looted this object
+ */
+ default @Nullable Long getLastLooted(final Player player) {
+ default @Nullable Long getLastLooted(final @NotNull Player player) {
+ return this.getLastLooted(player.getUniqueId());
+ }
+
@ -139,31 +137,29 @@ index 0000000000000000000000000000000000000000..9fb621200fb3969e8e440341e906acc3
+ * @param player The player to check
+ * @return Timestamp last looted, or null if player has not looted this object
+ */
+ @Nullable Long getLastLooted(UUID player);
+ @Nullable
+ Long getLastLooted(@NotNull UUID player);
+
+ /**
+ * Change the state of whether a player has looted this block
+ *
+ * Change the state of whether or not 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 Player player, final boolean looted) {
+ default boolean setHasPlayerLooted(final @NotNull Player player, final boolean looted) {
+ return this.setHasPlayerLooted(player.getUniqueId(), looted);
+ }
+
+ /**
+ * Change the state of whether a player has looted this block
+ *
+ * Change the state of whether or not 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(UUID player, boolean looted);
+ boolean setHasPlayerLooted(@NotNull UUID player, boolean looted);
+
+ /**
+ * Returns Whether this object has been filled and now has a pending refill
+ *
+ * Returns Whether or not this object has been filled and now has a pending refill
+ * @return Has pending refill
+ */
+ boolean hasPendingRefill();
@ -192,10 +188,10 @@ index 0000000000000000000000000000000000000000..9fb621200fb3969e8e440341e906acc3
+}
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..994c2183db89fc40d5991d5e1906e4bd04db6291
index 0000000000000000000000000000000000000000..5ee1a04aaaa4ef09559f2cf757811e463e2a1be6
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java
@@ -0,0 +1,46 @@
@@ -0,0 +1,47 @@
+package com.destroystokyo.paper.loottable;
+
+import org.bukkit.entity.Player;
@ -203,22 +199,22 @@ index 0000000000000000000000000000000000000000..994c2183db89fc40d5991d5e1906e4bd
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+@NullMarked
+public class LootableInventoryReplenishEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final LootableInventory inventory;
+ @NotNull private final LootableInventory inventory;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public LootableInventoryReplenishEvent(final Player player, final LootableInventory inventory) {
+ public LootableInventoryReplenishEvent(@NotNull Player player, @NotNull LootableInventory inventory) {
+ super(player);
+ this.inventory = inventory;
+ }
+
+ @NotNull
+ public LootableInventory getInventory() {
+ return this.inventory;
+ }
@ -229,15 +225,16 @@ index 0000000000000000000000000000000000000000..994c2183db89fc40d5991d5e1906e4bd
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ 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..af2b1629f845ffe1559e7d580b482636cc6441d9
index 0000000000000000000000000000000000000000..dc6d15975a47e68c5bd939e68ddd2773028a6ac8
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityZapEvent.java
@@ -0,0 +1,65 @@
@@ -0,0 +1,69 @@
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired when lightning strikes an entity
+ */
+@NullMarked
+public class EntityZapEvent extends EntityTransformEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final LightningStrike bolt;
+ @NotNull private final LightningStrike bolt;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EntityZapEvent(final Entity entity, final LightningStrike bolt, final Entity replacementEntity) {
+ public EntityZapEvent(@NotNull final Entity entity, @NotNull final LightningStrike bolt, @NotNull final Entity replacementEntity) {
+ super(entity, Collections.singletonList(replacementEntity), TransformReason.LIGHTNING);
+ this.bolt = bolt;
+ }
@ -43,6 +43,7 @@ index 0000000000000000000000000000000000000000..af2b1629f845ffe1559e7d580b482636
+ *
+ * @return The lightning bolt responsible for this event
+ */
+ @NotNull
+ public LightningStrike getBolt() {
+ return this.bolt;
+ }
@ -52,6 +53,7 @@ index 0000000000000000000000000000000000000000..af2b1629f845ffe1559e7d580b482636
+ *
+ * @return The entity that will replace the struck entity
+ */
+ @NotNull
+ public Entity getReplacementEntity() {
+ return super.getTransformedEntity();
+ }
@ -62,15 +64,17 @@ index 0000000000000000000000000000000000000000..af2b1629f845ffe1559e7d580b482636
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,44 +6,41 @@ 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..ebaa12ecacd169f00e184fed95720d047eda8b9d
index 0000000000000000000000000000000000000000..5bb677ce585b856b3d3e589e29786a29619c56a7
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java
@@ -0,0 +1,37 @@
@@ -0,0 +1,34 @@
+package com.destroystokyo.paper.utils;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@NullMarked
+@ApiStatus.Internal
+public class CachedSizeConcurrentLinkedQueue<E> extends ConcurrentLinkedQueue<E> {
+
+ private final LongAdder cachedSize = new LongAdder();
+
+ @Override
+ public boolean add(final E e) {
+ final boolean result = super.add(e);
+ public boolean add(@NotNull E e) {
+ boolean result = super.add(e);
+ if (result) {
+ this.cachedSize.increment();
+ cachedSize.increment();
+ }
+ return result;
+ }
+
+ @Nullable
+ @Override
+ public @Nullable E poll() {
+ final E result = super.poll();
+ public E poll() {
+ E result = super.poll();
+ if (result != null) {
+ this.cachedSize.decrement();
+ cachedSize.decrement();
+ }
+ return result;
+ }
+
+ @Override
+ public int size() {
+ return this.cachedSize.intValue();
+ return 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..4488154d3f99f4281b08eef8a44c13fd896e538f
index 0000000000000000000000000000000000000000..40bd79fbe30f19bc93e34da52d2b2bf0768be974
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerTeleportEndGatewayEvent.java
@@ -0,0 +1,32 @@
@ -18,18 +18,17 @@ index 0000000000000000000000000000000000000000..4488154d3f99f4281b08eef8a44c13fd
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired when a teleport is triggered for an End Gateway
+ */
+@NullMarked
+public class PlayerTeleportEndGatewayEvent extends PlayerTeleportEvent {
+
+ private final EndGateway gateway;
+ @NotNull private final EndGateway gateway;
+
+ @ApiStatus.Internal
+ public PlayerTeleportEndGatewayEvent(final Player player, final Location from, final Location to, final EndGateway gateway) {
+ public PlayerTeleportEndGatewayEvent(@NotNull Player player, @NotNull Location from, @NotNull Location to, @NotNull EndGateway gateway) {
+ super(player, from, to, PlayerTeleportEvent.TeleportCause.END_GATEWAY);
+ this.gateway = gateway;
+ }
@ -39,6 +38,7 @@ index 0000000000000000000000000000000000000000..4488154d3f99f4281b08eef8a44c13fd
+ *
+ * @return EndGateway used
+ */
+ @NotNull
+ public EndGateway getGateway() {
+ return this.gateway;
+ }

View file

@ -200,10 +200,10 @@ index 9885fd1adc1f93a80d650e6d42dfa3a0b084db9f..c4f2f03ec31998d486dad1d45ef83df3
* <p>
* The {@code radius} is not a rigid square radius. Each structure may alter
diff --git a/src/main/java/org/bukkit/attribute/AttributeModifier.java b/src/main/java/org/bukkit/attribute/AttributeModifier.java
index 6ffc895138088162cab827b3ca6c68961b7bcc64..8c53ac6b4381f3cf8b5e989c8b2a3ba77bd4e475 100644
index d66502c9df2592cd18694481e7e90a71a5c3a359..ee39c0b83e558681e8b006172d34c98e2c83cda2 100644
--- a/src/main/java/org/bukkit/attribute/AttributeModifier.java
+++ b/src/main/java/org/bukkit/attribute/AttributeModifier.java
@@ -129,8 +129,7 @@ public class AttributeModifier implements ConfigurationSerializable, Keyed {
@@ -117,8 +117,7 @@ public class AttributeModifier implements ConfigurationSerializable, Keyed {
}
/**
@ -430,7 +430,7 @@ index 4e1fb0974d061d5bb64899cac576318d2e6f8bf6..539b3527d0c66611e21712f29b90fba9
public int getEntityId();
diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java
index 40214a136894270695746ac83fb5f7bcc406f34a..2bb4d2da99d3f0f70e19381c13b43c147c34f944 100644
index 8fdfa1d79daf464f8e364fd9e19d1de3a2a6848c..195a7fa0ea8e056cbde7b9152cc014d2c94353ff 100644
--- a/src/main/java/org/bukkit/entity/HumanEntity.java
+++ b/src/main/java/org/bukkit/entity/HumanEntity.java
@@ -22,6 +22,11 @@ import org.jetbrains.annotations.Nullable;
@ -459,7 +459,7 @@ index b688b3856cb3068a539fcecfbfa113f8ab4160a9..c275b881cbd11307a6dcc7190d7a7d40
* @return whether the item frame is visible or not
*/
diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java
index cafa79f80eec5ec6d8d31d40cc2b46acc06831f9..b0fbad5de65c33710ec46734ad6c69ec9b2769d5 100644
index 32e89741ffd895e31af0104a0126c2f72742a1bb..bc17c86da49faf4b6e07d4fb4c53649da0384d69 100644
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -502,7 +502,7 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
@ -1050,34 +1050,6 @@ index 08a7c564fe5d3d232998d1789d4d4723a59c1430..8a5be3f0322ac19aeac3f00df54add0e
@NotNull
@Override
public AnvilView getView() {
diff --git a/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java b/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java
index 48a00fb50fe32c732a578d5179b3bb43ffd68b69..6d7ee2c6e053ea9af9116e7c2adb521f12b914df 100644
--- a/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java
+++ b/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java
@@ -106,7 +106,9 @@ public class PlayerCommandPreprocessEvent extends PlayerEvent implements Cancell
*
* @param player New player which this event will execute as
* @throws IllegalArgumentException if the player provided is null
+ * @deprecated Only works for sign commands; use {@link Player#performCommand(String)}, including those cases
*/
+ @Deprecated(forRemoval = true)
public void setPlayer(@NotNull final Player player) throws IllegalArgumentException {
Preconditions.checkArgument(player != null, "Player cannot be null");
this.player = player;
@@ -123,11 +125,10 @@ public class PlayerCommandPreprocessEvent extends PlayerEvent implements Cancell
* unmodifiable set.
*
* @return All Players who will see this chat message
- * @deprecated This method is provided for backward compatibility with no
- * guarantee to the effect of viewing or modifying the set.
+ * @deprecated This is simply the online players. Modifications have no effect
*/
@NotNull
- @Deprecated
+ @Deprecated(forRemoval = true)
public Set<Player> getRecipients() {
return recipients;
}
diff --git a/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java b/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java
index e4c32b21ab013703a6a1b07a1ad564d914ebe83f..e58fecf0fe54db06e0e944027923a352fd8005d8 100644
--- a/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java
@ -1747,32 +1719,6 @@ index b84b37fe27d84574dc5897285f1d9a1437bd322c..281ae60a6be7e39aab4f27b4c7de3d49
*
* @return Set containing all the channels that this client may accept.
*/
diff --git a/src/main/java/org/bukkit/projectiles/ProjectileSource.java b/src/main/java/org/bukkit/projectiles/ProjectileSource.java
index eabd8b926ec1c934cd7e77b7cc6adfae16771021..8557bfefaf02538dec95adb29734ae2cf50f3f8c 100644
--- a/src/main/java/org/bukkit/projectiles/ProjectileSource.java
+++ b/src/main/java/org/bukkit/projectiles/ProjectileSource.java
@@ -12,6 +12,10 @@ public interface ProjectileSource {
/**
* Launches a {@link Projectile} from the ProjectileSource.
+ * <p>
+ * The family of launchProjectile methods only promise the ability to launch projectile types
+ * that the {@link ProjectileSource} is capable of firing in vanilla.
+ * Any other types of projectiles *may* be implemented but are not part of the method contract.
*
* @param <T> a projectile subclass
* @param projectile class of the projectile to launch
@@ -23,6 +27,10 @@ public interface ProjectileSource {
/**
* Launches a {@link Projectile} from the ProjectileSource with an
* initial velocity.
+ * <p>
+ * The family of launchProjectile methods only promise the ability to launch projectile types
+ * that the {@link ProjectileSource} is capable of firing in vanilla.
+ * Any other types of projectiles *may* be implemented but are not part of the method contract.
*
* @param <T> a projectile subclass
* @param projectile class of the projectile to launch
diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java
index 22b1dc5fd4d453161a5ee520072f8e8f955b3a80..a625bcab8e77b05b3341a52c708fae1542b7e3d5 100644
--- a/src/main/java/org/bukkit/scoreboard/Objective.java

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..eff29875f6282d8bd04a33cb572c90090742d3b2
index 0000000000000000000000000000000000000000..13e4b1309ea9965a07fc8b276d5a7e606e205824
--- /dev/null
+++ b/src/main/java/org/bukkit/event/player/PlayerAttemptPickupItemEvent.java
@@ -0,0 +1,94 @@
@@ -0,0 +1,96 @@
+package org.bukkit.event.player;
+
+import org.bukkit.entity.Item;
@ -17,17 +17,16 @@ index 0000000000000000000000000000000000000000..eff29875f6282d8bd04a33cb572c9009
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final Item item;
+ @NotNull private final Item item;
+ private final int remaining;
+ private boolean flyAtPlayer = true;
+
@ -35,12 +34,12 @@ index 0000000000000000000000000000000000000000..eff29875f6282d8bd04a33cb572c9009
+
+ @Deprecated // Remove in 1.13 // Remove in 1.14?
+ @ApiStatus.Internal
+ public PlayerAttemptPickupItemEvent(final Player player, final Item item) {
+ public PlayerAttemptPickupItemEvent(@NotNull final Player player, @NotNull final Item item) {
+ this(player, item, 0);
+ }
+
+ @ApiStatus.Internal
+ public PlayerAttemptPickupItemEvent(final Player player, final Item item, final int remaining) {
+ public PlayerAttemptPickupItemEvent(@NotNull final Player player, @NotNull final Item item, final int remaining) {
+ super(player);
+ this.item = item;
+ this.remaining = remaining;
@ -51,6 +50,7 @@ index 0000000000000000000000000000000000000000..eff29875f6282d8bd04a33cb572c9009
+ *
+ * @return Item
+ */
+ @NotNull
+ public Item getItem() {
+ return this.item;
+ }
@ -95,11 +95,13 @@ index 0000000000000000000000000000000000000000..eff29875f6282d8bd04a33cb572c9009
+ 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..58fe8f60ad5e7ca0ffddebb7ba5748bbfb129ddd
index 0000000000000000000000000000000000000000..9bdeeecdb6021d61fd9141270011e56b06a58a76
--- /dev/null
+++ b/src/main/java/org/bukkit/event/command/UnknownCommandEvent.java
@@ -0,0 +1,105 @@
@@ -0,0 +1,110 @@
+package org.bukkit.event.command;
+
+import net.kyori.adventure.text.Component;
@ -19,23 +19,22 @@ index 0000000000000000000000000000000000000000..58fe8f60ad5e7ca0ffddebb7ba5748bb
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.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();
+
+ private final CommandSender sender;
+ private final String commandLine;
+ private @Nullable Component message;
+ @NotNull private final CommandSender sender;
+ @NotNull private final String commandLine;
+ @Nullable private Component message;
+
+ @ApiStatus.Internal
+ public UnknownCommandEvent(final CommandSender sender, final String commandLine, final @Nullable Component message) {
+ public UnknownCommandEvent(@NotNull final CommandSender sender, @NotNull final String commandLine, @Nullable final Component message) {
+ super(false);
+ this.sender = sender;
+ this.commandLine = commandLine;
@ -47,6 +46,7 @@ index 0000000000000000000000000000000000000000..58fe8f60ad5e7ca0ffddebb7ba5748bb
+ *
+ * @return Sender of the command
+ */
+ @NotNull
+ public CommandSender getSender() {
+ return this.sender;
+ }
@ -56,6 +56,7 @@ index 0000000000000000000000000000000000000000..58fe8f60ad5e7ca0ffddebb7ba5748bb
+ *
+ * @return Command sent
+ */
+ @NotNull
+ public String getCommandLine() {
+ return this.commandLine;
+ }
@ -66,8 +67,9 @@ index 0000000000000000000000000000000000000000..58fe8f60ad5e7ca0ffddebb7ba5748bb
+ * @return Unknown command message
+ * @deprecated use {@link #message()}
+ */
+ @Nullable
+ @Deprecated
+ public @Nullable String getMessage() {
+ public String getMessage() {
+ return this.message == null ? null : LegacyComponentSerializer.legacySection().serialize(this.message);
+ }
+
@ -89,8 +91,9 @@ index 0000000000000000000000000000000000000000..58fe8f60ad5e7ca0ffddebb7ba5748bb
+ *
+ * @return Unknown command message
+ */
+ @Nullable
+ @Contract(pure = true)
+ public @Nullable Component message() {
+ public Component message() {
+ return this.message;
+ }
+
@ -105,11 +108,13 @@ index 0000000000000000000000000000000000000000..58fe8f60ad5e7ca0ffddebb7ba5748bb
+ this.message = message;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -7,30 +7,29 @@ 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..324c1cba46c9eef95cc22ffa231b04f9298a5e00
index 0000000000000000000000000000000000000000..b4f9ffbebab8eef99dbd81c816c16c274a1ec4cd
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java
@@ -0,0 +1,246 @@
@@ -0,0 +1,234 @@
+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.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.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();
+
@ -40,14 +39,14 @@ index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9
+ * @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
@ -55,8 +54,8 @@ index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9
+ * @param uuid The new UUID
+ * @return The previous UUID
+ */
+ @Deprecated(forRemoval = true, since = "1.18.1")
+ @Nullable
+ @Deprecated(forRemoval = true, since = "1.18.1")
+ UUID setId(@Nullable UUID uuid);
+
+ /**
@ -66,7 +65,7 @@ index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9
+ *
+ * @return the textures, not <code>null</code>
+ */
+ @Override
+ @NotNull
+ PlayerTextures getTextures();
+
+ /**
@ -75,18 +74,16 @@ index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9
+ * @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.
+ */
+ Set<ProfileProperty> getProperties();
+ @NotNull Set<ProfileProperty> getProperties();
+
+ /**
+ * Check if the Profile has the specified property
+ *
+ * @param property Property name to check
+ * @return If the property is set
+ */
@ -98,19 +95,17 @@ index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9
+ * @param property Property to set.
+ * @throws IllegalArgumentException if setting the property results in more than 16 properties
+ */
+ void setProperty(ProfileProperty property);
+ void setProperty(@NotNull 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(Collection<ProfileProperty> properties);
+ void setProperties(@NotNull Collection<ProfileProperty> properties);
+
+ /**
+ * Removes a specific property from this profile
+ *
+ * @param property The property to remove
+ * @return If a property was removed
+ */
@ -118,24 +113,22 @@ index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9
+
+ /**
+ * Removes a specific property from this profile
+ *
+ * @param property The property to remove
+ * @return If a property was removed
+ */
+ default boolean removeProperty(final ProfileProperty property) {
+ return this.removeProperty(property.getName());
+ default boolean removeProperty(@NotNull ProfileProperty property) {
+ return removeProperty(property.getName());
+ }
+
+ /**
+ * Removes all properties in the collection
+ *
+ * @param properties The properties to remove
+ * @return If any property was removed
+ */
+ default boolean removeProperties(final Collection<ProfileProperty> properties) {
+ default boolean removeProperties(@NotNull Collection<ProfileProperty> properties) {
+ boolean removed = false;
+ for (final ProfileProperty property : properties) {
+ if (this.removeProperty(property)) {
+ for (ProfileProperty property : properties) {
+ if (removeProperty(property)) {
+ removed = true;
+ }
+ }
@ -150,7 +143,6 @@ index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9
+ /**
+ * @return If the profile is now complete (has UUID and Name)
+ */
+ @Override
+ boolean isComplete();
+
+ /**
@ -183,23 +175,21 @@ index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9
+ /**
+ * 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)}}
+ *
+ * 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 this.complete(true);
+ return 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
+ *
+ * Optionally will also fill textures.
+ *
+ * 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)
+ */
@ -208,9 +198,8 @@ index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9
+ /**
+ * 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.
+ *
+ * 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)
@ -246,45 +235,43 @@ index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9
+ * </pre>
+ */
+ @Override
+ CompletableFuture<PlayerProfile> update();
+ @NotNull CompletableFuture<PlayerProfile> update();
+
+ /**
+ * Whether this Profile has textures associated to it
+ *
+ * @return If it has a textures property
+ */
+ default boolean hasTextures() {
+ return this.hasProperty("textures");
+ return 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..35341d8f1ac2d80f339084ef80d099a545027554
index 0000000000000000000000000000000000000000..8f913a078dd692a9feafb98a6e6c9583f3253bd4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java
@@ -0,0 +1,73 @@
@@ -0,0 +1,75 @@
+package com.destroystokyo.paper.profile;
+
+import com.google.common.base.Preconditions;
+
+import java.util.Objects;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Represents a property on a {@link PlayerProfile}
+ */
+@NullMarked
+public final class ProfileProperty {
+
+public class ProfileProperty {
+ private final String name;
+ private final String value;
+ private final @Nullable String signature;
+ private final String signature;
+
+ public ProfileProperty(final String name, final String value) {
+ public ProfileProperty(@NotNull String name, @NotNull String value) {
+ this(name, value, null);
+ }
+
+ public ProfileProperty(final String name, final String value, final @Nullable String signature) {
+ public ProfileProperty(@NotNull String name, @NotNull String value, @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;
@ -296,22 +283,25 @@ index 0000000000000000000000000000000000000000..35341d8f1ac2d80f339084ef80d099a5
+ /**
+ * @return The property name, ie "textures"
+ */
+ @NotNull
+ public String getName() {
+ return this.name;
+ return name;
+ }
+
+ /**
+ * @return The property value, likely to be base64 encoded
+ */
+ @NotNull
+ public String getValue() {
+ return this.value;
+ return value;
+ }
+
+ /**
+ * @return A signature from Mojang for signed properties
+ */
+ public @Nullable String getSignature() {
+ return this.signature;
+ @Nullable
+ public String getSignature() {
+ return signature;
+ }
+
+ /**
@ -322,18 +312,18 @@ index 0000000000000000000000000000000000000000..35341d8f1ac2d80f339084ef80d099a5
+ }
+
+ @Override
+ public boolean equals(final @Nullable Object o) {
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ 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);
+ 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);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.name);
+ return Objects.hash(name);
+ }
+}
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java

View file

@ -5,10 +5,10 @@ Subject: [PATCH] Shoulder Entities Release API
diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java
index 2bb4d2da99d3f0f70e19381c13b43c147c34f944..b8431d9722ef9fce0ac9e18367abef22717997ca 100644
index 195a7fa0ea8e056cbde7b9152cc014d2c94353ff..85eec2e57b03c11f4737addb0fa88b7bf29dc9e5 100644
--- a/src/main/java/org/bukkit/entity/HumanEntity.java
+++ b/src/main/java/org/bukkit/entity/HumanEntity.java
@@ -346,6 +346,26 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
@@ -337,6 +337,26 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
*/
public int getExpToLevel();

View file

@ -8,18 +8,19 @@ 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..9e8ae0ab13cac9a260c9959eb6bf5b93a3c15018
index 0000000000000000000000000000000000000000..2ad2782aafe76f8b10565c0f0419d6b9c665b267
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/profile/LookupProfileEvent.java
@@ -0,0 +1,45 @@
@@ -0,0 +1,48 @@
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Allows a plugin to be notified anytime AFTER a Profile has been looked up from the Mojang API
@ -28,15 +29,14 @@ index 0000000000000000000000000000000000000000..9e8ae0ab13cac9a260c9959eb6bf5b93
+ * 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();
+
+ private final PlayerProfile profile;
+ @NotNull private final PlayerProfile profile;
+
+ @ApiStatus.Internal
+ public LookupProfileEvent(final PlayerProfile profile) {
+ public LookupProfileEvent(@NotNull PlayerProfile profile) {
+ super(!Bukkit.isPrimaryThread());
+ this.profile = profile;
+ }
@ -44,37 +44,41 @@ index 0000000000000000000000000000000000000000..9e8ae0ab13cac9a260c9959eb6bf5b93
+ /**
+ * @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..07416cc9e2b8156be2cc92d6d974b881b427fd99
index 0000000000000000000000000000000000000000..3f73ec52f9b581001bef3a19a5f1533dfa474356
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java
@@ -0,0 +1,107 @@
@@ -0,0 +1,112 @@
+package com.destroystokyo.paper.event.profile;
+
+import com.destroystokyo.paper.profile.ProfileProperty;
+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 java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Allows a plugin to intercept a Profile Lookup for a Profile by name
@ -86,18 +90,17 @@ index 0000000000000000000000000000000000000000..07416cc9e2b8156be2cc92d6d974b881
+ * 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();
+
+ private final String name;
+ @NotNull private final String name;
+
+ private @Nullable UUID uuid;
+ private Set<ProfileProperty> properties = new HashSet<>();
+ private UUID uuid;
+ @NotNull private Set<ProfileProperty> properties = new HashSet<>();
+
+ @ApiStatus.Internal
+ public PreLookupProfileEvent(final String name) {
+ public PreLookupProfileEvent(@NotNull String name) {
+ super(!Bukkit.isPrimaryThread());
+ this.name = name;
+ }
@ -105,6 +108,7 @@ index 0000000000000000000000000000000000000000..07416cc9e2b8156be2cc92d6d974b881
+ /**
+ * @return Name of the profile
+ */
+ @NotNull
+ public String getName() {
+ return this.name;
+ }
@ -116,7 +120,8 @@ index 0000000000000000000000000000000000000000..07416cc9e2b8156be2cc92d6d974b881
+ *
+ * @return The UUID of the profile if it has already been provided by a plugin
+ */
+ public @Nullable UUID getUUID() {
+ @Nullable
+ public UUID getUUID() {
+ return this.uuid;
+ }
+
@ -127,7 +132,7 @@ index 0000000000000000000000000000000000000000..07416cc9e2b8156be2cc92d6d974b881
+ *
+ * @param uuid the UUID to set for the profile or {@code null} to reset
+ */
+ public void setUUID(final @Nullable UUID uuid) {
+ public void setUUID(@Nullable UUID uuid) {
+ this.uuid = uuid;
+ }
+
@ -135,6 +140,7 @@ index 0000000000000000000000000000000000000000..07416cc9e2b8156be2cc92d6d974b881
+ * @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;
+ }
@ -145,7 +151,7 @@ index 0000000000000000000000000000000000000000..07416cc9e2b8156be2cc92d6d974b881
+ *
+ * @param properties The properties to add
+ */
+ public void setProfileProperties(final Set<ProfileProperty> properties) {
+ public void setProfileProperties(@NotNull Set<ProfileProperty> properties) {
+ this.properties = new HashSet<>();
+ this.properties.addAll(properties);
+ }
@ -156,15 +162,17 @@ index 0000000000000000000000000000000000000000..07416cc9e2b8156be2cc92d6d974b881
+ *
+ * @param properties The properties to add
+ */
+ public void addProfileProperties(final Set<ProfileProperty> properties) {
+ public void addProfileProperties(@NotNull 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,16 +8,14 @@ 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..994f34ac2062c092c2b4e5ff364067482d19588c
index 0000000000000000000000000000000000000000..163ffe8ff76ded6265d865901d5110fb6a56950d
--- /dev/null
+++ b/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java
@@ -0,0 +1,22 @@
@@ -0,0 +1,21 @@
+package org.bukkit.inventory;
+
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.Nullable;
+
+@NullMarked
+public interface ArmoredHorseInventory extends AbstractHorseInventory {
+
+ /**
@ -25,7 +23,8 @@ index 0000000000000000000000000000000000000000..994f34ac2062c092c2b4e5ff36406748
+ *
+ * @return the armor item
+ */
+ @Nullable ItemStack getArmor();
+ @Nullable
+ ItemStack getArmor();
+
+ /**
+ * Sets the item in the horse's armor slot.
@ -75,14 +74,10 @@ 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..0f508a8df87f1e23764152d00e02a3da5131f034
index 0000000000000000000000000000000000000000..7944f26a3e2a92601c3be0e55c00c39cc16cf177
--- /dev/null
+++ b/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java
@@ -0,0 +1,7 @@
@@ -0,0 +1,3 @@
+package org.bukkit.inventory;
+
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public interface SaddledHorseInventory extends AbstractHorseInventory {
+}
+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..901efb61fdc02b3228cc25649926d691c4617512
index 0000000000000000000000000000000000000000..52959c2d19c5b73ccd85afce6b2ab8133478f7c6
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/profile/ProfileWhitelistVerifyEvent.java
@@ -0,0 +1,146 @@
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2017 - Daniel Ennis (Aikar) - MIT License
+ *
@ -44,9 +44,8 @@ index 0000000000000000000000000000000000000000..901efb61fdc02b3228cc25649926d691
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Fires when the server needs to verify if a player is whitelisted.
@ -54,25 +53,24 @@ index 0000000000000000000000000000000000000000..901efb61fdc02b3228cc25649926d691
+ * 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();
+
+ private final PlayerProfile profile;
+ @NotNull private final PlayerProfile profile;
+ private final boolean whitelistEnabled;
+ private final boolean isOp;
+ private boolean whitelisted;
+ private @Nullable Component kickMessage;
+ @Nullable private Component kickMessage;
+
+ @Deprecated
+ @ApiStatus.Internal
+ public ProfileWhitelistVerifyEvent(final PlayerProfile profile, final boolean whitelistEnabled, final boolean whitelisted, final boolean isOp, final @Nullable String kickMessage) {
+ public ProfileWhitelistVerifyEvent(@NotNull final PlayerProfile profile, boolean whitelistEnabled, boolean whitelisted, boolean isOp, @Nullable String kickMessage) {
+ this(profile, whitelistEnabled, whitelisted, isOp, kickMessage == null ? null : LegacyComponentSerializer.legacySection().deserialize(kickMessage));
+ }
+
+ @ApiStatus.Internal
+ public ProfileWhitelistVerifyEvent(final PlayerProfile profile, final boolean whitelistEnabled, final boolean whitelisted, final boolean isOp, final @Nullable Component kickMessage) {
+ public ProfileWhitelistVerifyEvent(@NotNull final PlayerProfile profile, boolean whitelistEnabled, boolean whitelisted, boolean isOp, @Nullable Component kickMessage) {
+ this.profile = profile;
+ this.whitelistEnabled = whitelistEnabled;
+ this.whitelisted = whitelisted;
@ -85,7 +83,8 @@ index 0000000000000000000000000000000000000000..901efb61fdc02b3228cc25649926d691
+ * @deprecated use {@link #kickMessage()}
+ */
+ @Deprecated
+ public @Nullable String getKickMessage() {
+ @Nullable
+ public String getKickMessage() {
+ return this.kickMessage == null ? null : LegacyComponentSerializer.legacySection().serialize(this.kickMessage);
+ }
+
@ -94,34 +93,35 @@ index 0000000000000000000000000000000000000000..901efb61fdc02b3228cc25649926d691
+ * @deprecated Use {@link #kickMessage(Component)}
+ */
+ @Deprecated
+ public void setKickMessage(final @Nullable String kickMessage) {
+ public void setKickMessage(@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
+ */
+ @Contract(pure = true)
+ public @Nullable Component kickMessage() {
+ @Nullable
+ public 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(final @Nullable Component kickMessage) {
+ public void kickMessage(@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 it's true)
+ * @return Whether the player is whitelisted to play on this server (whitelist may be off is why its true)
+ */
+ public boolean isWhitelisted() {
+ return this.whitelisted;
@ -129,10 +129,9 @@ index 0000000000000000000000000000000000000000..901efb61fdc02b3228cc25649926d691
+
+ /**
+ * Changes the players whitelisted state. {@code false} will deny the login
+ *
+ * @param whitelisted The new whitelisted state
+ */
+ public void setWhitelisted(final boolean whitelisted) {
+ public void setWhitelisted(boolean whitelisted) {
+ this.whitelisted = whitelisted;
+ }
+
@ -150,11 +149,13 @@ index 0000000000000000000000000000000000000000..901efb61fdc02b3228cc25649926d691
+ 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 3c50362de25617d878ef58f14f67c240005ff624..76aa23da778b0fe8a093429c56cb29b044359b40 100644
index 258d7010d24c529c9bbc76cc26adf226c641ee58..4da053d427f3f9c5e7fc144408836ebef80026c6 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -12,6 +12,8 @@ java {
@ -35,7 +35,7 @@ index 3c50362de25617d878ef58f14f67c240005ff624..76aa23da778b0fe8a093429c56cb29b0
implementation("org.ow2.asm:asm:9.7")
implementation("org.ow2.asm:asm-commons:9.7")
@@ -140,6 +144,8 @@ tasks.withType<Javadoc> {
@@ -138,6 +142,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 3c50362de25617d878ef58f14f67c240005ff624..76aa23da778b0fe8a093429c56cb29b0
"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 68a0ed5f0ed25e98f4ab4d1e482ec2ccfda9cd3a..46fc37a36403c8fbc4c0c9f863d4d57eb3896bd4 100644
index 8c76716249e44ed8bf6be94c1f5c7b6d9bb35be2..4eb639fbb46a0848be207149ea433455550fae1c 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..1d07c3d6bf3b9283371ca45698178979113085fa
index 0000000000000000000000000000000000000000..8c2fd2c1120d634052f9bc345365272ad3a67b6f
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerJumpEvent.java
@@ -0,0 +1,105 @@
@@ -0,0 +1,106 @@
+package com.destroystokyo.paper.event.player;
+
+import com.google.common.base.Preconditions;
@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..1d07c3d6bf3b9283371ca45698178979
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Called when the server detects the player is jumping.
@ -29,18 +29,17 @@ index 0000000000000000000000000000000000000000..1d07c3d6bf3b9283371ca45698178979
+ * 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();
+
+ private final Location to;
+ private Location from;
+ @NotNull private final Location to;
+ @NotNull private Location from;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerJumpEvent(final Player player, final Location from, final Location to) {
+ public PlayerJumpEvent(@NotNull final Player player, @NotNull final Location from, @NotNull final Location to) {
+ super(player);
+ this.from = from;
+ this.to = to;
@ -55,7 +54,6 @@ index 0000000000000000000000000000000000000000..1d07c3d6bf3b9283371ca45698178979
+ *
+ * @return {@code true} if this event is cancelled
+ */
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
@ -69,8 +67,7 @@ index 0000000000000000000000000000000000000000..1d07c3d6bf3b9283371ca45698178979
+ *
+ * @param cancel {@code true} if you wish to cancel this event
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
@ -79,6 +76,7 @@ index 0000000000000000000000000000000000000000..1d07c3d6bf3b9283371ca45698178979
+ *
+ * @return Location the player jumped from
+ */
+ @NotNull
+ public Location getFrom() {
+ return this.from;
+ }
@ -88,7 +86,7 @@ index 0000000000000000000000000000000000000000..1d07c3d6bf3b9283371ca45698178979
+ *
+ * @param from New location to mark as the players previous location
+ */
+ public void setFrom(final Location from) {
+ public void setFrom(@NotNull 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;
@ -102,15 +100,18 @@ index 0000000000000000000000000000000000000000..1d07c3d6bf3b9283371ca45698178979
+ *
+ * @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,31 +14,33 @@ 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..c78a359566a11904d2dd41098ced556a91a7fa36
index 0000000000000000000000000000000000000000..087ee57fe5485bc760fadd45a176d4d90a18f9f8
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/utils/PaperPluginLogger.java
@@ -0,0 +1,46 @@
@@ -0,0 +1,48 @@
+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.bukkit.plugin.PluginDescriptionFile;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Prevents plugins (e.g. Essentials) from changing the parent of the plugin logger.
+ */
+@NullMarked
+public class PaperPluginLogger extends Logger {
+
+ @Deprecated(forRemoval = true)
+ public static Logger getLogger(final PluginDescriptionFile description) {
+ @NotNull
+ public static Logger getLogger(@NotNull PluginDescriptionFile description) {
+ return getLogger((PluginMeta) description);
+ }
+
+ public static Logger getLogger(final PluginMeta meta) {
+ @NotNull
+ public static Logger getLogger(@NotNull PluginMeta meta) {
+ Logger logger = new PaperPluginLogger(meta);
+ if (!LogManager.getLogManager().addLogger(logger)) {
+ // Disable this if it's going to happen across reloads anyways...
@ -49,14 +51,14 @@ index 0000000000000000000000000000000000000000..c78a359566a11904d2dd41098ced556a
+ return logger;
+ }
+
+ private PaperPluginLogger(final PluginMeta meta) {
+ private PaperPluginLogger(@NotNull PluginMeta meta) {
+ super(meta.getLoggerPrefix() != null ? meta.getLoggerPrefix() : meta.getName(), null);
+ }
+
+ @Override
+ public void setParent(final Logger parent) {
+ if (this.getParent() != null) {
+ this.warning("Ignoring attempt to change parent of plugin logger");
+ public void setParent(@NotNull Logger parent) {
+ if (getParent() != null) {
+ warning("Ignoring attempt to change parent of plugin logger");
+ } else {
+ this.log(Level.FINE, "Setting plugin logger parent to {0}", parent);
+ super.setParent(parent);
@ -65,7 +67,7 @@ index 0000000000000000000000000000000000000000..c78a359566a11904d2dd41098ced556a
+
+}
diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
index 801578de8599d6b546cde63b3f2655fab48eee03..2d64fc065d53dcd8c01d05215c3e63aaf4428177 100644
index f81e335a4e533221529355bec2f5d588aa79e60c..d359ea9b02952f981b9cf9d778c56eb995454c60 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,21 +6,22 @@ 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..c7cc612ec81b0c7da6ee6676167e047e69347966
index 0000000000000000000000000000000000000000..ab08219497f7e362f113321c4bcfd180b335bf20
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java
@@ -0,0 +1,120 @@
@@ -0,0 +1,127 @@
+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.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static org.bukkit.Material.*;
+
@ -29,17 +30,16 @@ index 0000000000000000000000000000000000000000..c7cc612ec81b0c7da6ee6676167e047e
+ * <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();
+
+ private final SlotType slotType;
+ private final ItemStack oldItem;
+ private final ItemStack newItem;
+ @NotNull private final SlotType slotType;
+ @NotNull private final ItemStack oldItem;
+ @NotNull private final ItemStack newItem;
+
+ @ApiStatus.Internal
+ public PlayerArmorChangeEvent(final Player player, final SlotType slotType, final ItemStack oldItem, final ItemStack newItem) {
+ public PlayerArmorChangeEvent(@NotNull Player player, @NotNull SlotType slotType, @NotNull ItemStack oldItem, @NotNull ItemStack newItem) {
+ super(player);
+ this.slotType = slotType;
+ this.oldItem = oldItem;
@ -51,6 +51,7 @@ index 0000000000000000000000000000000000000000..c7cc612ec81b0c7da6ee6676167e047e
+ *
+ * @return type of slot being altered
+ */
+ @NotNull
+ public SlotType getSlotType() {
+ return this.slotType;
+ }
@ -60,6 +61,7 @@ index 0000000000000000000000000000000000000000..c7cc612ec81b0c7da6ee6676167e047e
+ *
+ * @return old item
+ */
+ @NotNull
+ public ItemStack getOldItem() {
+ return this.oldItem;
+ }
@ -69,15 +71,18 @@ index 0000000000000000000000000000000000000000..c7cc612ec81b0c7da6ee6676167e047e
+ *
+ * @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;
+ }
@ -90,7 +95,7 @@ index 0000000000000000000000000000000000000000..c7cc612ec81b0c7da6ee6676167e047e
+
+ private final Set<Material> types;
+
+ SlotType(final Material... types) {
+ SlotType(Material... types) {
+ this.types = Set.of(types);
+ }
+
@ -100,6 +105,7 @@ index 0000000000000000000000000000000000000000..c7cc612ec81b0c7da6ee6676167e047e
+ *
+ * @return immutable set of material types
+ */
+ @NotNull
+ public Set<Material> getTypes() {
+ return this.types;
+ }
@ -110,8 +116,9 @@ index 0000000000000000000000000000000000000000..c7cc612ec81b0c7da6ee6676167e047e
+ * @param material material to get slot by
+ * @return slot type the material will go in, or {@code null} if it won't
+ */
+ public static @Nullable SlotType getByMaterial(final Material material) {
+ for (final SlotType slotType : values()) {
+ @Nullable
+ public static SlotType getByMaterial(@NotNull Material material) {
+ for (SlotType slotType : values()) {
+ if (slotType.getTypes().contains(material)) {
+ return slotType;
+ }
@ -125,7 +132,7 @@ index 0000000000000000000000000000000000000000..c7cc612ec81b0c7da6ee6676167e047e
+ * @param material material to check
+ * @return whether this material can be equipped
+ */
+ public static boolean isEquipable(final Material material) {
+ public static boolean isEquipable(@NotNull 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..0482ecf5b84ba8e0260679049f384f3449bbe7b5
index 0000000000000000000000000000000000000000..8965974988ad20fbe1d45885f20a3a98d2e9595f
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java
@@ -0,0 +1,333 @@
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License
+ *
@ -48,10 +48,6 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+
+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;
@ -62,9 +58,14 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+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.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Allows plugins to compute tab completion results asynchronously.
@ -75,15 +76,15 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ * <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();
+
+ private final CommandSender sender;
+ private final String buffer;
+ @NotNull private final CommandSender sender;
+ @NotNull private final String buffer;
+ private final boolean isCommand;
+ private final @Nullable Location location;
+ @Nullable
+ private final Location location;
+ private final List<Completion> completions = new ArrayList<>();
+ private final List<String> stringCompletions = new TransformingRandomAccessList<>(
+ this.completions,
@ -94,7 +95,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public AsyncTabCompleteEvent(final CommandSender sender, final String buffer, final boolean isCommand, final @Nullable Location loc) {
+ public AsyncTabCompleteEvent(@NotNull CommandSender sender, @NotNull String buffer, boolean isCommand, @Nullable Location loc) {
+ super(true);
+ this.sender = sender;
+ this.buffer = buffer;
@ -104,7 +105,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+
+ @Deprecated
+ @ApiStatus.Internal
+ public AsyncTabCompleteEvent(final CommandSender sender, final List<String> completions, final String buffer, final boolean isCommand, final @Nullable Location loc) {
+ public AsyncTabCompleteEvent(@NotNull CommandSender sender, @NotNull List<String> completions, @NotNull String buffer, boolean isCommand, @Nullable Location loc) {
+ super(true);
+ this.sender = sender;
+ this.completions.addAll(fromStrings(completions));
@ -118,6 +119,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ *
+ * @return the {@link CommandSender} instance
+ */
+ @NotNull
+ public CommandSender getSender() {
+ return this.sender;
+ }
@ -132,6 +134,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ *
+ * @return a list of offered completions
+ */
+ @NotNull
+ public List<String> getCompletions() {
+ return this.stringCompletions;
+ }
@ -146,7 +149,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ *
+ * @param completions the new completions
+ */
+ public void setCompletions(final List<String> completions) {
+ public void setCompletions(@NotNull List<String> completions) {
+ Preconditions.checkArgument(completions != null, "Completions list cannot be null");
+ if (completions == this.stringCompletions) {
+ return;
@ -165,7 +168,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ *
+ * @return a list of offered completions
+ */
+ public List<Completion> completions() {
+ public @NotNull List<Completion> completions() {
+ return this.completions;
+ }
+
@ -179,7 +182,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ *
+ * @param newCompletions the new completions
+ */
+ public void completions(final List<Completion> newCompletions) {
+ public void completions(final @NotNull List<Completion> newCompletions) {
+ Preconditions.checkArgument(newCompletions != null, "new completions cannot be null");
+ this.completions.clear();
+ this.completions.addAll(newCompletions);
@ -190,6 +193,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ *
+ * @return command buffer, as entered
+ */
+ @NotNull
+ public String getBuffer() {
+ return this.buffer;
+ }
@ -204,7 +208,8 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ /**
+ * @return The position looked at by the sender, or {@code null} if none
+ */
+ public @Nullable Location getLocation() {
+ @Nullable
+ public Location getLocation() {
+ return this.location != null ? this.location.clone() : null;
+ }
+
@ -225,7 +230,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ *
+ * @param handled if this completion should be marked as being handled
+ */
+ public void setHandled(final boolean handled) {
+ public void setHandled(boolean handled) {
+ this.handled = handled;
+ }
+
@ -240,20 +245,21 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ * Will provide no completions, and will not fire the synchronous process
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+
+ private static List<Completion> fromStrings(final List<String> suggestions) {
+ private static @NotNull List<Completion> fromStrings(final @NotNull List<String> suggestions) {
+ final List<Completion> list = new ArrayList<>(suggestions.size());
+ for (final String suggestion : suggestions) {
+ list.add(new CompletionImpl(suggestion, null));
@ -271,7 +277,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ *
+ * @return suggestion string
+ */
+ String suggestion();
+ @NotNull String suggestion();
+
+ /**
+ * Get the suggestion tooltip for this {@link Completion}.
@ -281,7 +287,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ @Nullable Component tooltip();
+
+ @Override
+ default Stream<? extends ExaminableProperty> examinableProperties() {
+ default @NotNull Stream<? extends ExaminableProperty> examinableProperties() {
+ return Stream.of(ExaminableProperty.of("suggestion", this.suggestion()), ExaminableProperty.of("tooltip", this.tooltip()));
+ }
+
@ -291,7 +297,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ * @param suggestion suggestion string
+ * @return new completion instance
+ */
+ static Completion completion(final String suggestion) {
+ static @NotNull Completion completion(final @NotNull String suggestion) {
+ return new CompletionImpl(suggestion, null);
+ }
+
@ -304,7 +310,7 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ * @param tooltip tooltip component, or {@code null}
+ * @return new completion instance
+ */
+ static Completion completion(final String suggestion, final @Nullable Component tooltip) {
+ static @NotNull Completion completion(final @NotNull String suggestion, final @Nullable Component tooltip) {
+ return new CompletionImpl(suggestion, tooltip);
+ }
+ }
@ -313,15 +319,15 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ static final class CompletionImpl implements Completion {
+
+ private final String suggestion;
+ private final @Nullable Component tooltip;
+ private final Component tooltip;
+
+ CompletionImpl(final String suggestion, final @Nullable Component tooltip) {
+ CompletionImpl(final @NotNull String suggestion, final @Nullable Component tooltip) {
+ this.suggestion = suggestion;
+ this.tooltip = tooltip;
+ }
+
+ @Override
+ public String suggestion() {
+ public @NotNull String suggestion() {
+ return this.suggestion;
+ }
+
@ -349,19 +355,22 @@ index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f34
+ }
+
+ @Override
+ public String toString() {
+ public @NotNull 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..488250fdcdc93ca1aba5042f63fb6286db518014
index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276118c1c7b
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java
@@ -0,0 +1,172 @@
@@ -0,0 +1,169 @@
+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;
@ -369,8 +378,6 @@ index 0000000000000000000000000000000000000000..488250fdcdc93ca1aba5042f63fb6286
+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;
+
@ -380,10 +387,7 @@ index 0000000000000000000000000000000000000000..488250fdcdc93ca1aba5042f63fb6286
+ * @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;
@ -391,14 +395,14 @@ index 0000000000000000000000000000000000000000..488250fdcdc93ca1aba5042f63fb6286
+ /**
+ * 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 List<F> fromList,
+ final Function<? super F, ? extends T> toFunction,
+ final Function<? super T, ? extends F> fromFunction
+ final @NonNull List<F> fromList,
+ final @NonNull Function<? super F, ? extends T> toFunction,
+ final @NonNull Function<? super T, ? extends F> fromFunction
+ ) {
+ this.fromList = checkNotNull(fromList);
+ this.toFunction = checkNotNull(toFunction);
@ -411,25 +415,25 @@ index 0000000000000000000000000000000000000000..488250fdcdc93ca1aba5042f63fb6286
+ }
+
+ @Override
+ public T get(final int index) {
+ public T get(int index) {
+ return this.toFunction.apply(this.fromList.get(index));
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ public @NotNull Iterator<T> iterator() {
+ return this.listIterator();
+ }
+
+ @Override
+ public ListIterator<T> listIterator(final int index) {
+ return new TransformedListIterator<>(this.fromList.listIterator(index)) {
+ public @NotNull ListIterator<T> listIterator(int index) {
+ return new TransformedListIterator<F, T>(this.fromList.listIterator(index)) {
+ @Override
+ T transform(final F from) {
+ T transform(F from) {
+ return TransformingRandomAccessList.this.toFunction.apply(from);
+ }
+
+ @Override
+ F transformBack(final T from) {
+ F transformBack(T from) {
+ return TransformingRandomAccessList.this.fromFunction.apply(from);
+ }
+ };
@ -441,13 +445,13 @@ index 0000000000000000000000000000000000000000..488250fdcdc93ca1aba5042f63fb6286
+ }
+
+ @Override
+ public boolean removeIf(final Predicate<? super T> filter) {
+ public boolean removeIf(Predicate<? super T> filter) {
+ checkNotNull(filter);
+ return this.fromList.removeIf(element -> filter.test(this.toFunction.apply(element)));
+ }
+
+ @Override
+ public T remove(final int index) {
+ public T remove(int index) {
+ return this.toFunction.apply(this.fromList.remove(index));
+ }
+
@ -457,20 +461,19 @@ index 0000000000000000000000000000000000000000..488250fdcdc93ca1aba5042f63fb6286
+ }
+
+ @Override
+ public T set(final int i, final T t) {
+ public T set(int i, T t) {
+ return this.toFunction.apply(this.fromList.set(i, this.fromFunction.apply(t)));
+ }
+
+ @Override
+ public void add(final int i, final T t) {
+ public void add(int i, T t) {
+ this.fromList.add(i, this.fromFunction.apply(t));
+ }
+
+ abstract static class TransformedListIterator<F, T> implements ListIterator<T>, Iterator<T> {
+
+ static abstract class TransformedListIterator<F, T> implements ListIterator<T>, Iterator<T> {
+ final Iterator<F> backingIterator;
+
+ TransformedListIterator(final ListIterator<F> backingIterator) {
+ TransformedListIterator(ListIterator<F> backingIterator) {
+ this.backingIterator = checkNotNull((Iterator<F>) backingIterator);
+ }
+
@ -478,7 +481,7 @@ index 0000000000000000000000000000000000000000..488250fdcdc93ca1aba5042f63fb6286
+ return cast(this.backingIterator);
+ }
+
+ static <A> ListIterator<A> cast(final Iterator<A> iterator) {
+ static <A> ListIterator<A> cast(Iterator<A> iterator) {
+ return (ListIterator<A>) iterator;
+ }
+
@ -503,12 +506,12 @@ index 0000000000000000000000000000000000000000..488250fdcdc93ca1aba5042f63fb6286
+ }
+
+ @Override
+ public void set(final T element) {
+ public void set(T element) {
+ this.backingIterator().set(this.transformBack(element));
+ }
+
+ @Override
+ public void add(final T element) {
+ public void add(T element) {
+ this.backingIterator().add(this.transformBack(element));
+ }
+
@ -596,7 +599,7 @@ index 270e6d8ad4358baa256cee5f16cff281f063ce3b..6465e290c090d82986352d5ab7ba5dc6
@Override
diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java
index 7ff939ea41417bad3a436a87c89d5efa7ecefe86..88d5db2995829cba919d78f988d5c735cf70cb1b 100644
index d9091ba1e5a55e03adca98305233cce9d6888609..b82f07a2879412f6b30643ca93a97439aa49a98a 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..c84ce3fc874eea3d8f0b1cf5273996d9b4af6225
index 0000000000000000000000000000000000000000..7b2af1bd72dfbcf4e962a982940fc49b851aa04f
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/network/NetworkClient.java
@@ -0,0 +1,39 @@
@@ -0,0 +1,41 @@
+package com.destroystokyo.paper.network;
+
+import java.net.InetSocketAddress;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Represents a client connected to the server.
+ */
+@NullMarked
+public interface NetworkClient {
+
+ /**
@ -32,6 +32,7 @@ index 0000000000000000000000000000000000000000..c84ce3fc874eea3d8f0b1cf5273996d9
+ *
+ * @return The client's socket address
+ */
+ @NotNull
+ InetSocketAddress getAddress();
+
+ /**
@ -51,7 +52,8 @@ index 0000000000000000000000000000000000000000..c84ce3fc874eea3d8f0b1cf5273996d9
+ *
+ * @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..0c6ddf0724780245ad01a3b5a5b0e477c25fc62e
index 0000000000000000000000000000000000000000..0ef10ac6bac990837e21520c800d89420a18e3d4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerPickupExperienceEvent.java
@@ -0,0 +1,81 @@
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License
+ *
@ -42,21 +42,20 @@ index 0000000000000000000000000000000000000000..0c6ddf0724780245ad01a3b5a5b0e477
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final ExperienceOrb experienceOrb;
+ @NotNull private final ExperienceOrb experienceOrb;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerPickupExperienceEvent(final Player player, final ExperienceOrb experienceOrb) {
+ public PlayerPickupExperienceEvent(@NotNull Player player, @NotNull ExperienceOrb experienceOrb) {
+ super(player);
+ this.experienceOrb = experienceOrb;
+ }
@ -64,6 +63,7 @@ index 0000000000000000000000000000000000000000..0c6ddf0724780245ad01a3b5a5b0e477
+ /**
+ * @return Returns the Orb that the player is picking up
+ */
+ @NotNull
+ public ExperienceOrb getExperienceOrb() {
+ return this.experienceOrb;
+ }
@ -79,15 +79,17 @@ index 0000000000000000000000000000000000000000..0c6ddf0724780245ad01a3b5a5b0e477
+ * If {@code true}, cancels picking up the experience orb, leaving it in the world
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..5902e6d6c0516a1249c72b405a49dfc5cc490e0e
index 0000000000000000000000000000000000000000..c520e5517861c4686806df233d1ef5e6bfb76ad3
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/ExperienceOrbMergeEvent.java
@@ -0,0 +1,88 @@
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License
+ *
@ -46,23 +46,22 @@ index 0000000000000000000000000000000000000000..5902e6d6c0516a1249c72b405a49dfc5
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final ExperienceOrb mergeTarget;
+ private final ExperienceOrb mergeSource;
+ @NotNull private final ExperienceOrb mergeTarget;
+ @NotNull private final ExperienceOrb mergeSource;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public ExperienceOrbMergeEvent(final ExperienceOrb mergeTarget, final ExperienceOrb mergeSource) {
+ public ExperienceOrbMergeEvent(@NotNull ExperienceOrb mergeTarget, @NotNull ExperienceOrb mergeSource) {
+ super(mergeTarget);
+ this.mergeTarget = mergeTarget;
+ this.mergeSource = mergeSource;
@ -71,6 +70,7 @@ index 0000000000000000000000000000000000000000..5902e6d6c0516a1249c72b405a49dfc5
+ /**
+ * @return The orb that will absorb the other experience orb
+ */
+ @NotNull
+ public ExperienceOrb getMergeTarget() {
+ return this.mergeTarget;
+ }
@ -78,6 +78,7 @@ index 0000000000000000000000000000000000000000..5902e6d6c0516a1249c72b405a49dfc5
+ /**
+ * @return The orb that is subject to being removed and merged into the target orb
+ */
+ @NotNull
+ public ExperienceOrb getMergeSource() {
+ return this.mergeSource;
+ }
@ -91,15 +92,17 @@ index 0000000000000000000000000000000000000000..5902e6d6c0516a1249c72b405a49dfc5
+ * @param cancel {@code true} if you wish to cancel this event, and prevent the orbs from merging
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..c1c96f93a4a5450381cb5bdb198b056a37ba0fbe
index 0000000000000000000000000000000000000000..633ef4dcc701916f2dbfefbbebd5994f93ffc2a4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/PreCreatureSpawnEvent.java
@@ -0,0 +1,105 @@
@@ -0,0 +1,109 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.Location;
@ -29,7 +29,7 @@ index 0000000000000000000000000000000000000000..c1c96f93a4a5450381cb5bdb198b056a
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * WARNING: This event only fires for a limited number of cases, and not for every case that {@link CreatureSpawnEvent} does.
@ -41,20 +41,19 @@ index 0000000000000000000000000000000000000000..c1c96f93a4a5450381cb5bdb198b056a
+ * 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();
+
+ private final Location location;
+ private final EntityType type;
+ private final CreatureSpawnEvent.SpawnReason reason;
+ @NotNull private final Location location;
+ @NotNull private final EntityType type;
+ @NotNull private final CreatureSpawnEvent.SpawnReason reason;
+ private boolean shouldAbortSpawn;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PreCreatureSpawnEvent(final Location location, final EntityType type, final CreatureSpawnEvent.SpawnReason reason) {
+ public PreCreatureSpawnEvent(@NotNull Location location, @NotNull EntityType type, @NotNull CreatureSpawnEvent.SpawnReason reason) {
+ this.location = location;
+ this.type = type;
+ this.reason = reason;
@ -63,6 +62,7 @@ index 0000000000000000000000000000000000000000..c1c96f93a4a5450381cb5bdb198b056a
+ /**
+ * @return The location this creature is being spawned at
+ */
+ @NotNull
+ public Location getSpawnLocation() {
+ return this.location.clone();
+ }
@ -70,6 +70,7 @@ index 0000000000000000000000000000000000000000..c1c96f93a4a5450381cb5bdb198b056a
+ /**
+ * @return The type of creature being spawned
+ */
+ @NotNull
+ public EntityType getType() {
+ return this.type;
+ }
@ -77,6 +78,7 @@ index 0000000000000000000000000000000000000000..c1c96f93a4a5450381cb5bdb198b056a
+ /**
+ * @return Reason this creature is spawning (ie, NATURAL vs SPAWNER)
+ */
+ @NotNull
+ public CreatureSpawnEvent.SpawnReason getReason() {
+ return this.reason;
+ }
@ -94,7 +96,7 @@ index 0000000000000000000000000000000000000000..c1c96f93a4a5450381cb5bdb198b056a
+ *
+ * @param shouldAbortSpawn Set if the spawn process should be aborted vs trying more attempts
+ */
+ public void setShouldAbortSpawn(final boolean shouldAbortSpawn) {
+ public void setShouldAbortSpawn(boolean shouldAbortSpawn) {
+ this.shouldAbortSpawn = shouldAbortSpawn;
+ }
+
@ -112,15 +114,17 @@ index 0000000000000000000000000000000000000000..c1c96f93a4a5450381cb5bdb198b056a
+ * @param cancel {@code true} if you wish to cancel this event, and abort the spawn of this creature
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..a3267a283b39e8db1e9b7e5338d2909320f1421c
index 0000000000000000000000000000000000000000..7fcee73d61347165cefef7b92f0e63e0bed8ad73
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/PlayerNaturallySpawnCreaturesEvent.java
@@ -0,0 +1,65 @@
@@ -0,0 +1,66 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Player;
@ -21,12 +21,11 @@ index 0000000000000000000000000000000000000000..a3267a283b39e8db1e9b7e5338d29093
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
@ -35,7 +34,7 @@ index 0000000000000000000000000000000000000000..a3267a283b39e8db1e9b7e5338d29093
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerNaturallySpawnCreaturesEvent(final Player player, final byte radius) {
+ public PlayerNaturallySpawnCreaturesEvent(@NotNull Player player, byte radius) {
+ super(player);
+ this.radius = radius;
+ }
@ -50,12 +49,12 @@ index 0000000000000000000000000000000000000000..a3267a283b39e8db1e9b7e5338d29093
+ /**
+ * @param radius The radius of chunks around this player to be included in natural spawn selection
+ */
+ public void setSpawnRadius(final byte radius) {
+ public void setSpawnRadius(byte radius) {
+ this.radius = radius;
+ }
+
+ /**
+ * @return If this player's chunks will be excluded from natural spawns
+ * @return If this players chunks will be excluded from natural spawns
+ */
+ @Override
+ public boolean isCancelled() {
@ -63,18 +62,20 @@ index 0000000000000000000000000000000000000000..a3267a283b39e8db1e9b7e5338d29093
+ }
+
+ /**
+ * @param cancel {@code true} if you wish to cancel this event, and not include this player's chunks for natural spawning
+ * @param cancel {@code true} if you wish to cancel this event, and not include this players chunks for natural spawning
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..0fb316e34ec9728610237a08f37fffb61fd5afa8
index 0000000000000000000000000000000000000000..9502f94b3567fc22c4b61fea5aa251d738dde7ae
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerAdvancementCriterionGrantEvent.java
@@ -0,0 +1,80 @@
@@ -0,0 +1,84 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.advancement.Advancement;
@ -20,25 +20,24 @@ index 0000000000000000000000000000000000000000..0fb316e34ec9728610237a08f37fffb6
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final Advancement advancement;
+ private final String criterion;
+ private final AdvancementProgress advancementProgress;
+ @NotNull private final Advancement advancement;
+ @NotNull private final String criterion;
+ @NotNull private final AdvancementProgress advancementProgress;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerAdvancementCriterionGrantEvent(final Player player, final Advancement advancement, final String criterion) {
+ public PlayerAdvancementCriterionGrantEvent(@NotNull Player player, @NotNull Advancement advancement, @NotNull String criterion) {
+ super(player);
+ this.advancement = advancement;
+ this.criterion = criterion;
@ -50,6 +49,7 @@ index 0000000000000000000000000000000000000000..0fb316e34ec9728610237a08f37fffb6
+ *
+ * @return affected advancement
+ */
+ @NotNull
+ public Advancement getAdvancement() {
+ return this.advancement;
+ }
@ -59,6 +59,7 @@ index 0000000000000000000000000000000000000000..0fb316e34ec9728610237a08f37fffb6
+ *
+ * @return granted criterion
+ */
+ @NotNull
+ public String getCriterion() {
+ return this.criterion;
+ }
@ -68,6 +69,7 @@ index 0000000000000000000000000000000000000000..0fb316e34ec9728610237a08f37fffb6
+ *
+ * @return advancement progress
+ */
+ @NotNull
+ public AdvancementProgress getAdvancementProgress() {
+ return this.advancementProgress;
+ }
@ -78,15 +80,17 @@ index 0000000000000000000000000000000000000000..0fb316e34ec9728610237a08f37fffb6
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..8625d60eb822f39140152f2f74ec5bfe5ecd0039
index 0000000000000000000000000000000000000000..c97ded9f9ef1c550cca7d0a3a3b09a85e5999cdf
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/profile/FillProfileEvent.java
@@ -0,0 +1,75 @@
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
+ *
@ -43,24 +43,24 @@ index 0000000000000000000000000000000000000000..8625d60eb822f39140152f2f74ec5bfe
+
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final PlayerProfile profile;
+ @NotNull private final PlayerProfile profile;
+
+ @ApiStatus.Internal
+ public FillProfileEvent(final PlayerProfile profile) {
+ public FillProfileEvent(@NotNull PlayerProfile profile) {
+ super(!org.bukkit.Bukkit.isPrimaryThread());
+ this.profile = profile;
+ }
@ -68,6 +68,7 @@ index 0000000000000000000000000000000000000000..8625d60eb822f39140152f2f74ec5bfe
+ /**
+ * @return The Profile that had properties filled
+ */
+ @NotNull
+ public PlayerProfile getPlayerProfile() {
+ return this.profile;
+ }
@ -75,28 +76,31 @@ index 0000000000000000000000000000000000000000..8625d60eb822f39140152f2f74ec5bfe
+ /**
+ * Same as .getPlayerProfile().getProperties()
+ *
+ * @return The new properties on the profile.
+ * @see PlayerProfile#getProperties()
+ * @return The new properties on the profile.
+ */
+ @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..177c23274d6dad709b05706117303b70ae8b4c7b
index 0000000000000000000000000000000000000000..e2a47c4af2c368a361e4a370a01111abe8e48062
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/profile/PreFillProfileEvent.java
@@ -0,0 +1,78 @@
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
+ *
@ -124,26 +128,26 @@ index 0000000000000000000000000000000000000000..177c23274d6dad709b05706117303b70
+
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final PlayerProfile profile;
+ @NotNull private final PlayerProfile profile;
+
+ @ApiStatus.Internal
+ public PreFillProfileEvent(final PlayerProfile profile) {
+ public PreFillProfileEvent(@NotNull PlayerProfile profile) {
+ super(!org.bukkit.Bukkit.isPrimaryThread());
+ this.profile = profile;
+ }
@ -151,6 +155,7 @@ index 0000000000000000000000000000000000000000..177c23274d6dad709b05706117303b70
+ /**
+ * @return The profile that needs its properties filled
+ */
+ @NotNull
+ public PlayerProfile getPlayerProfile() {
+ return this.profile;
+ }
@ -158,19 +163,21 @@ index 0000000000000000000000000000000000000000..177c23274d6dad709b05706117303b70
+ /**
+ * Sets the properties on the profile, avoiding the call to the Mojang API
+ * Same as .getPlayerProfile().setProperties(properties);
+ *
+ * @param properties The properties to set/append
+ *
+ * @see PlayerProfile#setProperties(Collection)
+ * @param properties The properties to set/append
+ */
+ public void setProperties(final Collection<ProfileProperty> properties) {
+ public void setProperties(@NotNull 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..a8437bbd80b3a20772352a3b1797990ea13806ad 100644
index 517d15238ed117f38bbd39f570874014cecf7bb5..ffda9f6a8b094942009aa78b331d22d9dcca2802 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..a8437bbd80b3a20772352a3b1797990e
+ /**
+ * Returns whether the client is using an older version that doesn't
+ * support all the features in {@link PaperServerListPingEvent}.
+ * support all of the features in {@link PaperServerListPingEvent}.
+ *
+ * <p>For Vanilla, this returns {@code true} for all clients older than 1.7.</p>
+ *

View file

@ -5,10 +5,10 @@ Subject: [PATCH] Add openSign method to HumanEntity
diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java
index b8431d9722ef9fce0ac9e18367abef22717997ca..0d01fe9c96a1b9076dbd6d031fa8cd41954ea8db 100644
index 85eec2e57b03c11f4737addb0fa88b7bf29dc9e5..58dbe34ab1b603c2cd53af1625c1f82f8890da01 100644
--- a/src/main/java/org/bukkit/entity/HumanEntity.java
+++ b/src/main/java/org/bukkit/entity/HumanEntity.java
@@ -507,6 +507,26 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
@@ -498,6 +498,26 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
*/
@Deprecated
public void setShoulderEntityRight(@Nullable Entity entity);

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

View file

@ -10,45 +10,46 @@ 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..6c405755f4507d6fbc6c3877c611a7191206f3ff
index 0000000000000000000000000000000000000000..52f639b838e8b49952c560f20bacbad0337f279c
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/ParticleBuilder.java
@@ -0,0 +1,582 @@
@@ -0,0 +1,583 @@
+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 org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.List;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.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 @Nullable List<Player> receivers;
+ private @Nullable Player source;
+ private @Nullable Location location;
+ private List<Player> receivers;
+ private Player source;
+ private Location location;
+ private int count = 1;
+ private double offsetX = 0, offsetY = 0, offsetZ = 0;
+ private double extra = 1;
+ private @Nullable Object data;
+ private Object data;
+ private boolean force = true;
+
+ public ParticleBuilder(final Particle particle) {
+ public ParticleBuilder(@NotNull Particle particle) {
+ this.particle = particle;
+ }
+
@ -58,14 +59,14 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ *
+ * @return a reference to this object.
+ */
+ @NotNull
+ public ParticleBuilder spawn() {
+ if (this.location == null) {
+ throw new IllegalStateException("Please specify location for this particle");
+ }
+ 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
+ location.getWorld().spawnParticle(particle, receivers, source,
+ location.getX(), location.getY(), location.getZ(),
+ count, offsetX, offsetY, offsetZ, extra, data, force
+ );
+ return this;
+ }
@ -73,8 +74,9 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ /**
+ * @return The particle going to be sent
+ */
+ @NotNull
+ public Particle particle() {
+ return this.particle;
+ return particle;
+ }
+
+ /**
@ -83,7 +85,8 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @param particle The particle
+ * @return a reference to this object.
+ */
+ public ParticleBuilder particle(final Particle particle) {
+ @NotNull
+ public ParticleBuilder particle(@NotNull Particle particle) {
+ this.particle = particle;
+ return this;
+ }
@ -91,30 +94,32 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ /**
+ * @return List of players who will receive the particle, or null for all in world
+ */
+ public @Nullable List<Player> receivers() {
+ return this.receivers;
+ @Nullable
+ public List<Player> receivers() {
+ return 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 (this.receivers == null && this.location != null && !this.location.getWorld().getPlayers().isEmpty()) || (
+ this.receivers != null && !this.receivers.isEmpty());
+ return (receivers == null && !location.getWorld().getPlayers().isEmpty()) || (
+ receivers != null && !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;
@ -122,10 +127,11 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+
+ /**
+ * @param receivers List of players to receive this particle, or null for all players in the
+ * world
+ * world
+ * @return a reference to this object.
+ */
+ public ParticleBuilder receivers(final @Nullable List<Player> receivers) {
+ @NotNull
+ public ParticleBuilder receivers(@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;
@ -134,20 +140,22 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+
+ /**
+ * @param receivers List of players to receive this particle, or null for all players in the
+ * world
+ * world
+ * @return a reference to this object.
+ */
+ public ParticleBuilder receivers(final @Nullable Collection<Player> receivers) {
+ @NotNull
+ public ParticleBuilder receivers(@Nullable Collection<Player> receivers) {
+ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null;
+ return this;
+ }
+
+ /**
+ * @param receivers List of players to receive this particle, or null for all players in the
+ * world
+ * @param receivers List of players to be receive this particle, or null for all players in the
+ * world
+ * @return a reference to this object.
+ */
+ public ParticleBuilder receivers(final Player @Nullable... receivers) {
+ @NotNull
+ public ParticleBuilder receivers(@Nullable Player... receivers) {
+ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null;
+ return this;
+ }
@ -160,8 +168,9 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @param radius amount to add on all axis
+ * @return a reference to this object.
+ */
+ public ParticleBuilder receivers(final int radius) {
+ return this.receivers(radius, radius);
+ @NotNull
+ public ParticleBuilder receivers(int radius) {
+ return receivers(radius, radius);
+ }
+
+ /**
@ -169,24 +178,22 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * 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.
+ */
+ public ParticleBuilder receivers(final int radius, final boolean byDistance) {
+ @NotNull
+ public ParticleBuilder receivers(int radius, boolean byDistance) {
+ if (!byDistance) {
+ return this.receivers(radius, radius, radius);
+ return receivers(radius, radius, radius);
+ } else {
+ if (this.location == null) {
+ throw new IllegalStateException("Please set location first");
+ }
+ this.receivers = Lists.newArrayList();
+ 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());
+ 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());
+ if (Math.sqrt(x + y + z) > radius) {
+ continue;
+ }
@ -203,11 +210,12 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * 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.
+ */
+ public ParticleBuilder receivers(final int xzRadius, final int yRadius) {
+ return this.receivers(xzRadius, yRadius, xzRadius);
+ @NotNull
+ public ParticleBuilder receivers(int xzRadius, int yRadius) {
+ return receivers(xzRadius, yRadius, xzRadius);
+ }
+
+ /**
@ -215,28 +223,25 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * 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
+ */
+ public ParticleBuilder receivers(final int xzRadius, final int yRadius, final boolean byDistance) {
+ @NotNull
+ public ParticleBuilder receivers(int xzRadius, int yRadius, boolean byDistance) {
+ if (!byDistance) {
+ return this.receivers(xzRadius, yRadius, xzRadius);
+ return receivers(xzRadius, yRadius, xzRadius);
+ } else {
+ if (this.location == null) {
+ throw new IllegalStateException("Please set location first");
+ }
+ this.receivers = Lists.newArrayList();
+ for (final Player nearbyPlayer : this.location.getWorld()
+ .getNearbyPlayers(this.location, xzRadius, yRadius, xzRadius)) {
+ final Location loc = nearbyPlayer.getLocation();
+ for (Player nearbyPlayer : location.getWorld()
+ .getNearbyPlayers(location, xzRadius, yRadius, xzRadius)) {
+ Location loc = nearbyPlayer.getLocation();
+ if (Math.abs(loc.getY() - this.location.getY()) > yRadius) {
+ continue;
+ }
+ final double x = NumberConversions.square(this.location.getX() - loc.getX());
+ final double z = NumberConversions.square(this.location.getZ() - loc.getZ());
+ double x = NumberConversions.square(location.getX() - loc.getX());
+ double z = NumberConversions.square(location.getZ() - loc.getZ());
+ if (x + z > NumberConversions.square(xzRadius)) {
+ continue;
+ }
@ -256,18 +261,20 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @param zRadius amount to add on the z axis
+ * @return a reference to this object.
+ */
+ public ParticleBuilder receivers(final int xRadius, final int yRadius, final int zRadius) {
+ if (this.location == null) {
+ @NotNull
+ public ParticleBuilder receivers(int xRadius, int yRadius, int zRadius) {
+ if (location == null) {
+ throw new IllegalStateException("Please set location first");
+ }
+ return this.receivers(this.location.getWorld().getNearbyPlayers(this.location, xRadius, yRadius, zRadius));
+ return receivers(location.getWorld().getNearbyPlayers(location, xRadius, yRadius, zRadius));
+ }
+
+ /**
+ * @return The player considered the source of this particle (for Visibility concerns), or null
+ */
+ public @Nullable Player source() {
+ return this.source;
+ @Nullable
+ public Player source() {
+ return source;
+ }
+
+ /**
@ -276,7 +283,8 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @param source The player who is considered the source
+ * @return a reference to this object.
+ */
+ public ParticleBuilder source(final @Nullable Player source) {
+ @NotNull
+ public ParticleBuilder source(@Nullable Player source) {
+ this.source = source;
+ return this;
+ }
@ -284,8 +292,9 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ /**
+ * @return Location of where the particle will spawn
+ */
+ public @Nullable Location location() {
+ return this.location;
+ @Nullable
+ public Location location() {
+ return location;
+ }
+
+ /**
@ -294,7 +303,8 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @param location The location of the particle
+ * @return a reference to this object.
+ */
+ public ParticleBuilder location(final Location location) {
+ @NotNull
+ public ParticleBuilder location(@NotNull Location location) {
+ this.location = location.clone();
+ return this;
+ }
@ -303,12 +313,13 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * 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.
+ */
+ public ParticleBuilder location(final World world, final double x, final double y, final double z) {
+ @NotNull
+ public ParticleBuilder location(@NotNull World world, double x, double y, double z) {
+ this.location = new Location(world, x, y, z);
+ return this;
+ }
@ -317,7 +328,7 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @return Number of particles to spawn
+ */
+ public int count() {
+ return this.count;
+ return count;
+ }
+
+ /**
@ -326,7 +337,8 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @param count Number of particles
+ * @return a reference to this object.
+ */
+ public ParticleBuilder count(final int count) {
+ @NotNull
+ public ParticleBuilder count(int count) {
+ this.count = count;
+ return this;
+ }
@ -337,7 +349,7 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @return Particle offset X.
+ */
+ public double offsetX() {
+ return this.offsetX;
+ return offsetX;
+ }
+
+ /**
@ -346,7 +358,7 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @return Particle offset Y.
+ */
+ public double offsetY() {
+ return this.offsetY;
+ return offsetY;
+ }
+
+ /**
@ -355,7 +367,7 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @return Particle offset Z.
+ */
+ public double offsetZ() {
+ return this.offsetZ;
+ return offsetZ;
+ }
+
+ /**
@ -366,7 +378,8 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @param offsetZ Particle offset Z
+ * @return a reference to this object.
+ */
+ public ParticleBuilder offset(final double offsetX, final double offsetY, final double offsetZ) {
+ @NotNull
+ public ParticleBuilder offset(double offsetX, double offsetY, double offsetZ) {
+ this.offsetX = offsetX;
+ this.offsetY = offsetY;
+ this.offsetZ = offsetZ;
@ -379,7 +392,7 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @return the extra particle data
+ */
+ public double extra() {
+ return this.extra;
+ return extra;
+ }
+
+ /**
@ -388,7 +401,8 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @param extra the extra particle data
+ * @return a reference to this object.
+ */
+ public ParticleBuilder extra(final double extra) {
+ @NotNull
+ public ParticleBuilder extra(double extra) {
+ this.extra = extra;
+ return this;
+ }
@ -399,19 +413,21 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @param <T> The Particle data type
+ * @return the ParticleData for this particle
+ */
+ public @Nullable <T> T data() {
+ @Nullable
+ public <T> T data() {
+ //noinspection unchecked
+ return (T) this.data;
+ return (T) 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.
+ */
+ public <T> ParticleBuilder data(final @Nullable T data) {
+ @NotNull
+ public <T> ParticleBuilder data(@Nullable T data) {
+ this.data = data;
+ return this;
+ }
@ -420,7 +436,7 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @return whether the particle is forcefully shown to players.
+ */
+ public boolean force() {
+ return this.force;
+ return force;
+ }
+
+ /**
@ -431,94 +447,74 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * @param force true to force, false for normal
+ * @return a reference to this object.
+ */
+ public ParticleBuilder force(final boolean force) {
+ @NotNull
+ public ParticleBuilder force(boolean force) {
+ this.force = force;
+ return this;
+ }
+
+ /**
+ * Sets the particle Color.
+ * Only valid for particles with a data type of {@link Color} or {@link Particle.DustOptions}.
+ * Only valid for {@link Particle#DUST}.
+ *
+ * @param color the new particle color
+ * @return a reference to this object.
+ */
+ public ParticleBuilder color(final @Nullable Color color) {
+ if (this.particle.getDataType() == Color.class) {
+ return this.data(color);
+ }
+ return this.color(color, 1);
+ @NotNull
+ public ParticleBuilder color(@Nullable Color color) {
+ return color(color, 1);
+ }
+
+ /**
+ * Sets the particle Color and size.
+ * Only valid for particles with a data type of {@link Particle.DustOptions}.
+ * Only valid for {@link Particle#DUST}.
+ *
+ * @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.
+ */
+ 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.");
+ @NotNull
+ public ParticleBuilder color(@Nullable Color color, float size) {
+ if (particle != Particle.DUST && color != null) {
+ throw new IllegalStateException("Color may only be set on particle DUST.");
+ }
+
+ // We don't officially support reusing these objects, but here we go
+ if (color == null) {
+ if (this.data instanceof Particle.DustOptions) {
+ return this.data(null);
+ if (data instanceof Particle.DustOptions) {
+ return data(null);
+ } else {
+ return this;
+ }
+ }
+
+ return this.data(new Particle.DustOptions(color, size));
+ return data(new Particle.DustOptions(color, size));
+ }
+
+ /**
+ * Sets the particle Color.
+ * Only valid for particles with a data type of {@link Color} or {@link Particle.DustOptions}.
+ * Only valid for {@link Particle#DUST}.
+ *
+ * @param r red color component
+ * @param g green color component
+ * @param b blue color component
+ * @return a reference to this object.
+ */
+ public ParticleBuilder color(final int r, final int g, final int b) {
+ return this.color(Color.fromRGB(r, g, b));
+ @NotNull
+ public ParticleBuilder color(int r, int g, int b) {
+ return color(Color.fromRGB(r, g, b));
+ }
+
+ /**
+ * Sets the particle Color.
+ * Only valid for particles with a data type of {@link Color} or {@link Particle.DustOptions}.
+ * <p>
+ * This method detects if the provided color integer is in RGB or ARGB format.
+ * If the alpha channel is zero, it treats the color as RGB. Otherwise, it treats it as ARGB.
+ * Only valid for {@link Particle#DUST}.
+ *
+ * @param color an integer representing the color components. If the highest byte (alpha channel) is zero,
+ * the color is treated as RGB. Otherwise, it is treated as ARGB.
+ * @param rgb an integer representing the red, green, and blue color components
+ * @return a reference to this object.
+ */
+ public ParticleBuilder color(final int color) {
+ final int alpha = (color >> 24) & 0xFF;
+ if (alpha == 0) {
+ return this.color(Color.fromRGB(color));
+ }
+ return this.color(Color.fromARGB(color));
+ }
+
+ /**
+ * Sets the particle Color.
+ * Only valid for particles with a data type of {@link Color} or {@link Particle.DustOptions}.
+ *
+ * @param a alpha color component
+ * @param r red color component
+ * @param g green color component
+ * @param b blue color component
+ * @return a reference to this object.
+ */
+ public ParticleBuilder color(final int a, final int r, final int g, final int b) {
+ return this.color(Color.fromARGB(a, r, g, b));
+ @NotNull
+ public ParticleBuilder color(final int rgb) {
+ return color(Color.fromRGB(rgb));
+ }
+
+ /**
@ -526,64 +522,69 @@ index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a719
+ * 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}.
+ */
+ public ParticleBuilder colorTransition(final Color fromColor, final Color toColor) {
+ return this.colorTransition(fromColor, toColor, 1);
+ @NotNull
+ public ParticleBuilder colorTransition(@NotNull final Color fromColor, @NotNull final Color toColor) {
+ return 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}.
+ */
+ 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));
+ @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));
+ }
+
+ /**
+ * 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 this.colorTransition(Color.fromRGB(fromRgb), Color.fromRGB(toRgb));
+ return 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}.
+ */
+ public ParticleBuilder colorTransition(final Color fromColor, final Color toColor, final float size) {
+ @NotNull
+ public ParticleBuilder colorTransition(@NotNull final Color fromColor,
+ @NotNull 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 this.data(new Particle.DustTransition(fromColor, toColor, size));
+ return 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..34adc77de2d1f06b2b10cc26b60240c6a3ef259c
index 0000000000000000000000000000000000000000..ae34e679723a2ef436da04c116038272743a8f35
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java
@@ -0,0 +1,99 @@
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
+ *
@ -44,7 +44,7 @@ index 0000000000000000000000000000000000000000..34adc77de2d1f06b2b10cc26b60240c6
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired when an Enderman determines if it should attack a player or not.
@ -52,16 +52,15 @@ index 0000000000000000000000000000000000000000..34adc77de2d1f06b2b10cc26b60240c6
+ * 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();
+
+ private final Player player;
+ @NotNull private final Player player;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EndermanAttackPlayerEvent(final Enderman entity, final Player player) {
+ public EndermanAttackPlayerEvent(@NotNull Enderman entity, @NotNull Player player) {
+ super(entity);
+ this.player = player;
+ }
@ -71,6 +70,7 @@ index 0000000000000000000000000000000000000000..34adc77de2d1f06b2b10cc26b60240c6
+ *
+ * @return The enderman considering attacking
+ */
+ @NotNull
+ @Override
+ public Enderman getEntity() {
+ return (Enderman) super.getEntity();
@ -81,6 +81,7 @@ index 0000000000000000000000000000000000000000..34adc77de2d1f06b2b10cc26b60240c6
+ *
+ * @return The player the Enderman is considering attacking
+ */
+ @NotNull
+ public Player getPlayer() {
+ return this.player;
+ }
@ -99,15 +100,16 @@ index 0000000000000000000000000000000000000000..34adc77de2d1f06b2b10cc26b60240c6
+ * Cancels if the Enderman will attack this player
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ 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..43ee765dedf5001fadf1af317b6ab323fde34851
index 0000000000000000000000000000000000000000..773079aa92280bb97e9b4c0e62d9ead08135610a
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchConsumePotionEvent.java
@@ -0,0 +1,71 @@
@@ -0,0 +1,73 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Witch;
@ -19,26 +19,26 @@ index 0000000000000000000000000000000000000000..43ee765dedf5001fadf1af317b6ab323
+import org.bukkit.event.entity.EntityEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.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();
+
+ private @Nullable ItemStack potion;
+ @Nullable private ItemStack potion;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public WitchConsumePotionEvent(final Witch witch, final @Nullable ItemStack potion) {
+ public WitchConsumePotionEvent(@NotNull Witch witch, @Nullable ItemStack potion) {
+ super(witch);
+ this.potion = potion;
+ }
+
+ @NotNull
+ @Override
+ public Witch getEntity() {
+ return (Witch) super.getEntity();
@ -47,7 +47,8 @@ index 0000000000000000000000000000000000000000..43ee765dedf5001fadf1af317b6ab323
+ /**
+ * @return the potion the witch will consume and have the effects applied.
+ */
+ public @Nullable ItemStack getPotion() {
+ @Nullable
+ public ItemStack getPotion() {
+ return this.potion;
+ }
+
@ -56,7 +57,7 @@ index 0000000000000000000000000000000000000000..43ee765dedf5001fadf1af317b6ab323
+ *
+ * @param potion The potion
+ */
+ public void setPotion(final @Nullable ItemStack potion) {
+ public void setPotion(@Nullable ItemStack potion) {
+ this.potion = potion != null ? potion.clone() : null;
+ }
+
@ -69,15 +70,16 @@ index 0000000000000000000000000000000000000000..43ee765dedf5001fadf1af317b6ab323
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ 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..02395582b680f4baa3dc2251a8a79f41241b96ec
index 0000000000000000000000000000000000000000..f1d546a3576a170ecb3608e07befa0f621ea043a
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java
@@ -0,0 +1,81 @@
@@ -0,0 +1,85 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.LivingEntity;
@ -20,28 +20,28 @@ index 0000000000000000000000000000000000000000..02395582b680f4baa3dc2251a8a79f41
+import org.bukkit.event.entity.EntityEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.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();
+
+ private final LivingEntity target;
+ private @Nullable ItemStack potion;
+ @NotNull private final LivingEntity target;
+ @Nullable private ItemStack potion;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public WitchThrowPotionEvent(final Witch witch, final LivingEntity target, final @Nullable ItemStack potion) {
+ public WitchThrowPotionEvent(@NotNull Witch witch, @NotNull LivingEntity target, @Nullable ItemStack potion) {
+ super(witch);
+ this.target = target;
+ this.potion = potion;
+ }
+
+ @NotNull
+ @Override
+ public Witch getEntity() {
+ return (Witch) super.getEntity();
@ -50,6 +50,7 @@ index 0000000000000000000000000000000000000000..02395582b680f4baa3dc2251a8a79f41
+ /**
+ * @return The target of the potion
+ */
+ @NotNull
+ public LivingEntity getTarget() {
+ return this.target;
+ }
@ -57,7 +58,8 @@ index 0000000000000000000000000000000000000000..02395582b680f4baa3dc2251a8a79f41
+ /**
+ * @return The potion the witch will throw at a player
+ */
+ public @Nullable ItemStack getPotion() {
+ @Nullable
+ public ItemStack getPotion() {
+ return this.potion;
+ }
+
@ -66,7 +68,7 @@ index 0000000000000000000000000000000000000000..02395582b680f4baa3dc2251a8a79f41
+ *
+ * @param potion The potion
+ */
+ public void setPotion(final @Nullable ItemStack potion) {
+ public void setPotion(@Nullable ItemStack potion) {
+ this.potion = potion != null ? potion.clone() : null;
+ }
+
@ -79,15 +81,17 @@ index 0000000000000000000000000000000000000000..02395582b680f4baa3dc2251a8a79f41
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..bda48563cc9e00bd9a537ddec0c730b5e784c9a4
index 0000000000000000000000000000000000000000..7feca06e72bd585bbfa219df38a2161b77e8d4c4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java
@@ -0,0 +1,65 @@
@@ -0,0 +1,68 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Witch;
@ -19,23 +19,23 @@ index 0000000000000000000000000000000000000000..bda48563cc9e00bd9a537ddec0c730b5
+import org.bukkit.event.entity.EntityEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@NullMarked
+public class WitchReadyPotionEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private @Nullable ItemStack potion;
+ private ItemStack potion;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public WitchReadyPotionEvent(final Witch witch, final @Nullable ItemStack potion) {
+ public WitchReadyPotionEvent(@NotNull Witch witch, @Nullable ItemStack potion) {
+ super(witch);
+ this.potion = potion;
+ }
+
+ @NotNull
+ @Override
+ public Witch getEntity() {
+ return (Witch) super.getEntity();
@ -44,7 +44,8 @@ index 0000000000000000000000000000000000000000..bda48563cc9e00bd9a537ddec0c730b5
+ /**
+ * @return the potion the witch is readying to use
+ */
+ public @Nullable ItemStack getPotion() {
+ @Nullable
+ public ItemStack getPotion() {
+ return this.potion;
+ }
+
@ -53,7 +54,7 @@ index 0000000000000000000000000000000000000000..bda48563cc9e00bd9a537ddec0c730b5
+ *
+ * @param potion The potion
+ */
+ public void setPotion(final @Nullable ItemStack potion) {
+ public void setPotion(@Nullable ItemStack potion) {
+ this.potion = potion != null ? potion.clone() : null;
+ }
+
@ -63,15 +64,17 @@ index 0000000000000000000000000000000000000000..bda48563cc9e00bd9a537ddec0c730b5
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..cea029bfbd526d21509dee69bbfad44323107cf2
index 0000000000000000000000000000000000000000..88b9c059f9d66877260c66496443ad0aefaf8f47
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityTeleportEndGatewayEvent.java
@@ -0,0 +1,33 @@
@ -17,18 +17,17 @@ index 0000000000000000000000000000000000000000..cea029bfbd526d21509dee69bbfad443
+import org.bukkit.entity.Entity;
+import org.bukkit.event.entity.EntityTeleportEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired any time an entity attempts to teleport in an end gateway
+ */
+@NullMarked
+public class EntityTeleportEndGatewayEvent extends EntityTeleportEvent {
+
+ private final EndGateway gateway;
+ @NotNull private final EndGateway gateway;
+
+ @ApiStatus.Internal
+ public EntityTeleportEndGatewayEvent(final Entity entity, final Location from, final Location to, final EndGateway gateway) {
+ public EntityTeleportEndGatewayEvent(@NotNull Entity entity, @NotNull Location from, @NotNull Location to, @NotNull EndGateway gateway) {
+ super(entity, from, to);
+ this.gateway = gateway;
+ }
@ -38,6 +37,7 @@ index 0000000000000000000000000000000000000000..cea029bfbd526d21509dee69bbfad443
+ *
+ * @return EndGateway used
+ */
+ @NotNull
+ public EndGateway getGateway() {
+ return this.gateway;
+ }

View file

@ -5,10 +5,10 @@ Subject: [PATCH] Make shield blocking delay configurable
diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java
index e6bdfd14bffa394cd717de7118de951a997f50b3..2d4d93a4fc3f712a21bd61e203407f3a84e16310 100644
index f154c5607b1dc3585052d9f02cf8b28cf8a3c886..7b53064364e206bc1a0f4b7af4931f6c658b7c55 100644
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -847,5 +847,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
@@ -837,5 +837,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
*/
@Deprecated
void setArrowsStuck(int arrows);

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..3eadfae8860a4f6cde107cc3c7048368ade29d28
index 0000000000000000000000000000000000000000..f30c4c372c92a79fb6c3fe80c4b51b5c8c0d4d3b
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerReadyArrowEvent.java
@@ -0,0 +1,92 @@
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
+ *
@ -42,22 +42,21 @@ index 0000000000000000000000000000000000000000..3eadfae8860a4f6cde107cc3c7048368
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final ItemStack bow;
+ private final ItemStack arrow;
+ @NotNull private final ItemStack bow;
+ @NotNull private final ItemStack arrow;
+
+ private boolean cancelled;
+
+ public PlayerReadyArrowEvent(final Player player, final ItemStack bow, final ItemStack arrow) {
+ public PlayerReadyArrowEvent(@NotNull Player player, @NotNull ItemStack bow, @NotNull ItemStack arrow) {
+ super(player);
+ this.bow = bow;
+ this.arrow = arrow;
@ -66,6 +65,7 @@ index 0000000000000000000000000000000000000000..3eadfae8860a4f6cde107cc3c7048368
+ /**
+ * @return the player is using to fire the arrow
+ */
+ @NotNull
+ public ItemStack getBow() {
+ return this.bow;
+ }
@ -73,6 +73,7 @@ index 0000000000000000000000000000000000000000..3eadfae8860a4f6cde107cc3c7048368
+ /**
+ * @return the arrow that is attempting to be used
+ */
+ @NotNull
+ public ItemStack getArrow() {
+ return this.arrow;
+ }
@ -91,15 +92,16 @@ index 0000000000000000000000000000000000000000..3eadfae8860a4f6cde107cc3c7048368
+ * Cancel use of this arrow. On cancel, the server will try the next arrow available and fire another event.
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ this.cancelled = cancel;
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ 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..6f376e1ac0f2f44255993b3d5b144f5559d13cc3
index 0000000000000000000000000000000000000000..beb1715e30ec476e3031c247285d0d3219e8a8ea
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java
@@ -0,0 +1,52 @@
@@ -0,0 +1,51 @@
+package com.destroystokyo.paper.event.entity;
+
+import io.papermc.paper.event.entity.EntityKnockbackEvent;
@ -23,20 +23,19 @@ index 0000000000000000000000000000000000000000..6f376e1ac0f2f44255993b3d5b144f55
+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 LivingEntity entity, final Entity hitBy, final EntityKnockbackEvent.Cause cause, final float knockbackStrength, final Vector knockback) {
+ public EntityKnockbackByEntityEvent(final @NonNull LivingEntity entity, final @NonNull Entity hitBy, final EntityKnockbackEvent.@NonNull Cause cause, final float knockbackStrength, final @NonNull Vector knockback) {
+ super(entity, cause, hitBy, knockback);
+ this.knockbackStrength = knockbackStrength;
+ }
@ -45,7 +44,7 @@ index 0000000000000000000000000000000000000000..6f376e1ac0f2f44255993b3d5b144f55
+ * @return the entity which was knocked back
+ */
+ @Override
+ public LivingEntity getEntity() {
+ public @NonNull LivingEntity getEntity() {
+ return (LivingEntity) super.getEntity();
+ }
+
@ -63,17 +62,17 @@ index 0000000000000000000000000000000000000000..6f376e1ac0f2f44255993b3d5b144f55
+ *
+ * @return the Entity which hit
+ */
+ public Entity getHitBy() {
+ public @NonNull 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..bc120d4928dc41ea827e2a06f7d30d0e3d484ce0
index 0000000000000000000000000000000000000000..8aaafa4ea837f54b32497010d121f02b103e03a6
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java
@@ -0,0 +1,117 @@
@@ -0,0 +1,116 @@
+package io.papermc.paper.event.entity;
+
+import com.google.common.base.Preconditions;
@ -82,15 +81,14 @@ index 0000000000000000000000000000000000000000..bc120d4928dc41ea827e2a06f7d30d0e
+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();
@ -100,7 +98,7 @@ index 0000000000000000000000000000000000000000..bc120d4928dc41ea827e2a06f7d30d0e
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EntityKnockbackEvent(final Entity entity, final EntityKnockbackEvent.Cause cause, final Vector knockback) {
+ public EntityKnockbackEvent(final @NonNull Entity entity, final EntityKnockbackEvent.@NonNull Cause cause, final @NonNull Vector knockback) {
+ super(entity);
+ this.cause = cause;
+ this.knockback = knockback;
@ -111,7 +109,7 @@ index 0000000000000000000000000000000000000000..bc120d4928dc41ea827e2a06f7d30d0e
+ *
+ * @return the cause of the knockback
+ */
+ public EntityKnockbackEvent.Cause getCause() {
+ public EntityKnockbackEvent.@NonNull Cause getCause() {
+ return this.cause;
+ }
+
@ -123,7 +121,7 @@ index 0000000000000000000000000000000000000000..bc120d4928dc41ea827e2a06f7d30d0e
+ *
+ * @return the knockback
+ */
+ public Vector getKnockback() {
+ public @NonNull Vector getKnockback() {
+ return this.knockback.clone();
+ }
+
@ -132,7 +130,7 @@ index 0000000000000000000000000000000000000000..bc120d4928dc41ea827e2a06f7d30d0e
+ *
+ * @param knockback the knockback
+ */
+ public void setKnockback(final Vector knockback) {
+ public void setKnockback(final @NonNull Vector knockback) {
+ Preconditions.checkArgument(knockback != null, "knockback");
+ this.knockback = knockback.clone();
+ }
@ -148,11 +146,11 @@ index 0000000000000000000000000000000000000000..bc120d4928dc41ea827e2a06f7d30d0e
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ public @NonNull HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static HandlerList getHandlerList() {
+ public static @NonNull HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+
@ -193,17 +191,17 @@ index 0000000000000000000000000000000000000000..bc120d4928dc41ea827e2a06f7d30d0e
+}
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..7655c3694b9d6b37206fc46bf892004686e0a7dd
index 0000000000000000000000000000000000000000..b9d2a7a5bc4e67d8c36047da616046cbedce1d4a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java
@@ -0,0 +1,67 @@
@@ -0,0 +1,66 @@
+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
@ -212,13 +210,12 @@ index 0000000000000000000000000000000000000000..7655c3694b9d6b37206fc46bf8920046
+ * 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 Entity entity, final EntityKnockbackEvent.Cause cause, final Entity pushedBy, final Vector knockback) {
+ public EntityPushedByEntityAttackEvent(final @NonNull Entity entity, final EntityKnockbackEvent.@NonNull Cause cause, final @NonNull Entity pushedBy, final @NonNull Vector knockback) {
+ super(entity, cause, knockback);
+ this.pushedBy = pushedBy;
+ }
@ -228,7 +225,7 @@ index 0000000000000000000000000000000000000000..7655c3694b9d6b37206fc46bf8920046
+ *
+ * @return the pushing entity
+ */
+ public Entity getPushedBy() {
+ public @NonNull Entity getPushedBy() {
+ return this.pushedBy;
+ }
+
@ -239,7 +236,7 @@ index 0000000000000000000000000000000000000000..7655c3694b9d6b37206fc46bf8920046
+ * @deprecated use {@link #getKnockback()}
+ */
+ @Deprecated(since = "1.20.6", forRemoval = true)
+ public Vector getAcceleration() {
+ public @NonNull Vector getAcceleration() {
+ return this.knockback; // TODO Clone in 1.21 to not instantly break what was technically already modifiable (call super.getKnockback())
+ }
+
@ -250,7 +247,7 @@ index 0000000000000000000000000000000000000000..7655c3694b9d6b37206fc46bf8920046
+ * @deprecated use {@link #setKnockback(Vector)}
+ */
+ @Deprecated(since = "1.20.6", forRemoval = true)
+ public void setAcceleration(final Vector acceleration) {
+ public void setAcceleration(final @NonNull Vector acceleration) {
+ super.setKnockback(acceleration);
+ }
+

View file

@ -5,9 +5,6 @@ Subject: [PATCH] Expand Explosions API
Add Entity as a Source capability, and add more API choices, and on Location.
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
index 3161eae2fa5f03b7d3a5e9945ab659c15cf568c6..af737017ee397f80c44ee02c6cc60cefa07f59c1 100644
--- a/src/main/java/org/bukkit/Location.java
@ -111,10 +108,10 @@ index 3161eae2fa5f03b7d3a5e9945ab659c15cf568c6..af737017ee397f80c44ee02c6cc60cef
/**
* Returns a list of entities within a bounding box centered around a Location.
diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java
index 44a74f15bea60ecd8380520e8faaea41a6c261c5..c2b5fdaace13c8bd46c073ac6d427fe411d96367 100644
index 44a74f15bea60ecd8380520e8faaea41a6c261c5..50c1e4957f66826feb0a2eb04293dbd6b5595700 100644
--- a/src/main/java/org/bukkit/World.java
+++ b/src/main/java/org/bukkit/World.java
@@ -1424,6 +1424,104 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
@@ -1424,6 +1424,88 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
*/
public boolean createExplosion(@NotNull Location loc, float power, boolean setFire);
@ -128,25 +125,9 @@ index 44a74f15bea60ecd8380520e8faaea41a6c261c5..c2b5fdaace13c8bd46c073ac6d427fe4
+ * @param power The power of explosion, where 4F is TNT
+ * @param setFire Whether or not to set blocks on fire
+ * @param breakBlocks Whether or not to have blocks be destroyed
+ * @param excludeSourceFromDamage whether the explosion should exclude the passed source from taking damage like vanilla explosions do.
+ * @return false if explosion was canceled, otherwise true
+ */
+ public boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire, boolean breakBlocks, boolean excludeSourceFromDamage);
+
+ /**
+ * Creates explosion at given location with given power and optionally
+ * setting blocks on fire, with the specified entity as the source.
+ *
+ * @param source The source entity of the explosion
+ * @param loc Location to blow up
+ * @param power The power of explosion, where 4F is TNT
+ * @param setFire Whether or not to set blocks on fire
+ * @param breakBlocks Whether or not to have blocks be destroyed
+ * @return false if explosion was canceled, otherwise true
+ */
+ default boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire, boolean breakBlocks) {
+ return createExplosion(source, loc, power, setFire, breakBlocks, true);
+ }
+ public boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire, boolean breakBlocks);
+
+ /**
+ * Creates explosion at given location with given power and optionally

View file

@ -9,10 +9,10 @@ such as a bow or eating food.
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java
index 0d01fe9c96a1b9076dbd6d031fa8cd41954ea8db..b0cb4377e14da5ef1e155513046c2340ab6e525e 100644
index 58dbe34ab1b603c2cd53af1625c1f82f8890da01..9cbb9093e7d8cd21eef6a23c265d68d7d0ee97b8 100644
--- a/src/main/java/org/bukkit/entity/HumanEntity.java
+++ b/src/main/java/org/bukkit/entity/HumanEntity.java
@@ -336,7 +336,9 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
@@ -327,7 +327,9 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
* blocking).
*
* @return Whether their hand is raised
@ -23,7 +23,7 @@ index 0d01fe9c96a1b9076dbd6d031fa8cd41954ea8db..b0cb4377e14da5ef1e155513046c2340
/**
diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java
index 2d4d93a4fc3f712a21bd61e203407f3a84e16310..434ad8b07b6ee0b0919de8044d14fe3c789e203f 100644
index 7b53064364e206bc1a0f4b7af4931f6c658b7c55..0ed64618b3f62ee984fe4f99dc6a52d5fad7b3cc 100644
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -202,15 +202,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
@ -56,7 +56,7 @@ index 2d4d93a4fc3f712a21bd61e203407f3a84e16310..434ad8b07b6ee0b0919de8044d14fe3c
public void setItemInUseTicks(int ticks);
/**
@@ -862,4 +868,130 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
@@ -852,4 +858,130 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
*/
void setShieldBlockingDelay(int delay);
// Paper end

View file

@ -8,17 +8,16 @@ 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..09c82908f63233febfe1e07fe756f1c39d23d44f
index 0000000000000000000000000000000000000000..46e0e62d620def237dab44ad24708f1b93a8a1a7
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java
@@ -0,0 +1,36 @@
@@ -0,0 +1,35 @@
+package com.destroystokyo.paper.entity;
+
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Mob;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+@NullMarked
+public interface RangedEntity extends Mob {
+ /**
+ * Attack the specified entity using a ranged attack.
@ -27,7 +26,7 @@ index 0000000000000000000000000000000000000000..09c82908f63233febfe1e07fe756f1c3
+ * @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(LivingEntity target, float charge);
+ void rangedAttack(@NotNull LivingEntity target, float charge);
+
+ /**
+ * Sets that the Entity is "charging" up an attack, by raising its hands
@ -45,7 +44,7 @@ index 0000000000000000000000000000000000000000..09c82908f63233febfe1e07fe756f1c3
+ */
+ @Deprecated(since = "1.19.2")
+ default boolean isChargingAttack() {
+ return this.isHandRaised();
+ return 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..242eb9c07866365568c036819be2b4f882319aa1
index 0000000000000000000000000000000000000000..bf5f82c8ba36bd245e1536fd4f654487aa8f6e21
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFireballHitEvent.java
@@ -0,0 +1,74 @@
@@ -0,0 +1,79 @@
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final Collection<LivingEntity> targets;
+ private final AreaEffectCloud areaEffectCloud;
+ @NotNull private final Collection<LivingEntity> targets;
+ @NotNull private final AreaEffectCloud areaEffectCloud;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EnderDragonFireballHitEvent(final DragonFireball fireball, final Collection<LivingEntity> targets, final AreaEffectCloud areaEffectCloud) {
+ public EnderDragonFireballHitEvent(@NotNull DragonFireball fireball, @NotNull Collection<LivingEntity> targets, @NotNull AreaEffectCloud areaEffectCloud) {
+ super(fireball);
+ this.targets = targets;
+ this.areaEffectCloud = areaEffectCloud;
@ -44,6 +44,7 @@ index 0000000000000000000000000000000000000000..242eb9c07866365568c036819be2b4f8
+ /**
+ * The fireball involved in this event
+ */
+ @NotNull
+ @Override
+ public DragonFireball getEntity() {
+ return (DragonFireball) super.getEntity();
@ -54,6 +55,7 @@ index 0000000000000000000000000000000000000000..242eb9c07866365568c036819be2b4f8
+ *
+ * @return the targets
+ */
+ @NotNull
+ public Collection<LivingEntity> getTargets() {
+ return this.targets;
+ }
@ -61,6 +63,7 @@ index 0000000000000000000000000000000000000000..242eb9c07866365568c036819be2b4f8
+ /**
+ * @return The area effect cloud spawned in this collision
+ */
+ @NotNull
+ public AreaEffectCloud getAreaEffectCloud() {
+ return this.areaEffectCloud;
+ }
@ -71,25 +74,27 @@ index 0000000000000000000000000000000000000000..242eb9c07866365568c036819be2b4f8
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..47cf33ef97ce1b92bc13c4d3a6c49d050e344eb1
index 0000000000000000000000000000000000000000..4a61878152c95a07160f4216e78b042ca45d24b3
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFlameEvent.java
@@ -0,0 +1,61 @@
@@ -0,0 +1,63 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.AreaEffectCloud;
@ -98,21 +103,20 @@ index 0000000000000000000000000000000000000000..47cf33ef97ce1b92bc13c4d3a6c49d05
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final AreaEffectCloud areaEffectCloud;
+ @NotNull private final AreaEffectCloud areaEffectCloud;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EnderDragonFlameEvent(final EnderDragon enderDragon, final AreaEffectCloud areaEffectCloud) {
+ public EnderDragonFlameEvent(@NotNull EnderDragon enderDragon, @NotNull AreaEffectCloud areaEffectCloud) {
+ super(enderDragon);
+ this.areaEffectCloud = areaEffectCloud;
+ }
@ -120,6 +124,7 @@ index 0000000000000000000000000000000000000000..47cf33ef97ce1b92bc13c4d3a6c49d05
+ /**
+ * The enderdragon involved in this event
+ */
+ @NotNull
+ @Override
+ public EnderDragon getEntity() {
+ return (EnderDragon) super.getEntity();
@ -128,6 +133,7 @@ index 0000000000000000000000000000000000000000..47cf33ef97ce1b92bc13c4d3a6c49d05
+ /**
+ * @return The area effect cloud spawned in this collision
+ */
+ @NotNull
+ public AreaEffectCloud getAreaEffectCloud() {
+ return this.areaEffectCloud;
+ }
@ -138,25 +144,26 @@ index 0000000000000000000000000000000000000000..47cf33ef97ce1b92bc13c4d3a6c49d05
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ 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..7dd6e17b648868cf5d549f1e779e5d92439751dd
index 0000000000000000000000000000000000000000..3c6c3db37d91aad3638aef107a3bf8ca1d4f7085
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonShootFireballEvent.java
@@ -0,0 +1,61 @@
@@ -0,0 +1,64 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.DragonFireball;
@ -165,21 +172,20 @@ index 0000000000000000000000000000000000000000..7dd6e17b648868cf5d549f1e779e5d92
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired when an EnderDragon shoots a fireball
+ */
+@NullMarked
+public class EnderDragonShootFireballEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final DragonFireball fireball;
+ @NotNull private final DragonFireball fireball;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EnderDragonShootFireballEvent(final EnderDragon entity, final DragonFireball fireball) {
+ public EnderDragonShootFireballEvent(@NotNull EnderDragon entity, @NotNull DragonFireball fireball) {
+ super(entity);
+ this.fireball = fireball;
+ }
@ -187,6 +193,7 @@ index 0000000000000000000000000000000000000000..7dd6e17b648868cf5d549f1e779e5d92
+ /**
+ * The enderdragon shooting the fireball
+ */
+ @NotNull
+ @Override
+ public EnderDragon getEntity() {
+ return (EnderDragon) super.getEntity();
@ -195,6 +202,7 @@ index 0000000000000000000000000000000000000000..7dd6e17b648868cf5d549f1e779e5d92
+ /**
+ * @return The fireball being shot
+ */
+ @NotNull
+ public DragonFireball getFireball() {
+ return this.fireball;
+ }
@ -205,15 +213,17 @@ index 0000000000000000000000000000000000000000..7dd6e17b648868cf5d549f1e779e5d92
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..7d41a5c2dc6ca659bfad41e70cbeac2349c2b0f3
index 0000000000000000000000000000000000000000..9ebac41c22b8866df616020d409e5e1a49cddca5
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerElytraBoostEvent.java
@@ -0,0 +1,99 @@
@@ -0,0 +1,104 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.entity.Firework;
@ -20,25 +20,25 @@ index 0000000000000000000000000000000000000000..7d41a5c2dc6ca659bfad41e70cbeac23
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final ItemStack itemStack;
+ private final Firework firework;
+ @NotNull private final ItemStack itemStack;
+ @NotNull private final Firework firework;
+ private boolean consume = true;
+ @NotNull
+ private final EquipmentSlot hand;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerElytraBoostEvent(final Player player, final ItemStack itemStack, final Firework firework, final EquipmentSlot hand) {
+ public PlayerElytraBoostEvent(@NotNull Player player, @NotNull ItemStack itemStack, @NotNull Firework firework, @NotNull EquipmentSlot hand) {
+ super(player);
+ this.itemStack = itemStack;
+ this.firework = firework;
@ -50,6 +50,7 @@ index 0000000000000000000000000000000000000000..7d41a5c2dc6ca659bfad41e70cbeac23
+ *
+ * @return ItemStack of firework
+ */
+ @NotNull
+ public ItemStack getItemStack() {
+ return this.itemStack;
+ }
@ -59,6 +60,7 @@ index 0000000000000000000000000000000000000000..7d41a5c2dc6ca659bfad41e70cbeac23
+ *
+ * @return Firework entity
+ */
+ @NotNull
+ public Firework getFirework() {
+ return this.firework;
+ }
@ -77,7 +79,7 @@ index 0000000000000000000000000000000000000000..7d41a5c2dc6ca659bfad41e70cbeac23
+ *
+ * @param consume {@code true} to consume
+ */
+ public void setShouldConsume(final boolean consume) {
+ public void setShouldConsume(boolean consume) {
+ this.consume = consume;
+ }
+
@ -86,6 +88,7 @@ index 0000000000000000000000000000000000000000..7d41a5c2dc6ca659bfad41e70cbeac23
+ *
+ * @return interaction hand
+ */
+ @NotNull
+ public EquipmentSlot getHand() {
+ return this.hand;
+ }
@ -96,15 +99,17 @@ index 0000000000000000000000000000000000000000..7d41a5c2dc6ca659bfad41e70cbeac23
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..a6d483e6be8b8527d7cfd676f6056179e8e9bf33
index 0000000000000000000000000000000000000000..efd947eb0aa0633891d9c6a8bde66d33e29020d7
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java
@@ -0,0 +1,92 @@
@@ -0,0 +1,95 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.entity.Player;
@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..a6d483e6be8b8527d7cfd676f6056179
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Called when a player shoots a projectile.
@ -29,19 +29,18 @@ index 0000000000000000000000000000000000000000..a6d483e6be8b8527d7cfd676f6056179
+ * 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();
+
+ private final Projectile projectile;
+ private final ItemStack itemStack;
+ @NotNull private final Projectile projectile;
+ @NotNull private final ItemStack itemStack;
+ private boolean consumeItem = true;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerLaunchProjectileEvent(final Player shooter, final ItemStack itemStack, final Projectile projectile) {
+ public PlayerLaunchProjectileEvent(@NotNull Player shooter, @NotNull ItemStack itemStack, @NotNull Projectile projectile) {
+ super(shooter);
+ this.itemStack = itemStack;
+ this.projectile = projectile;
@ -52,6 +51,7 @@ index 0000000000000000000000000000000000000000..a6d483e6be8b8527d7cfd676f6056179
+ *
+ * @return the launched projectile
+ */
+ @NotNull
+ public Projectile getProjectile() {
+ return this.projectile;
+ }
@ -61,6 +61,7 @@ index 0000000000000000000000000000000000000000..a6d483e6be8b8527d7cfd676f6056179
+ *
+ * @return The ItemStack used
+ */
+ @NotNull
+ public ItemStack getItemStack() {
+ return this.itemStack;
+ }
@ -79,7 +80,7 @@ index 0000000000000000000000000000000000000000..a6d483e6be8b8527d7cfd676f6056179
+ *
+ * @param consumeItem {@code true} to consume
+ */
+ public void setShouldConsume(final boolean consumeItem) {
+ public void setShouldConsume(boolean consumeItem) {
+ this.consumeItem = consumeItem;
+ }
+
@ -89,15 +90,17 @@ index 0000000000000000000000000000000000000000..a6d483e6be8b8527d7cfd676f6056179
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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..a70f4972a012f955b45a91fe20ca5df7e2123528
index 0000000000000000000000000000000000000000..f6724e6e5754996ac10888aaa92baf2dcc6134d3
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SkeletonHorseTrapEvent.java
@@ -0,0 +1,64 @@
@@ -0,0 +1,68 @@
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+/**
+ * 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,21 +35,23 @@ index 0000000000000000000000000000000000000000..a70f4972a012f955b45a91fe20ca5df7
+
+ @Deprecated
+ @ApiStatus.Internal
+ public SkeletonHorseTrapEvent(final SkeletonHorse horse) {
+ public SkeletonHorseTrapEvent(@NotNull SkeletonHorse horse) {
+ this(horse, ImmutableList.of());
+ }
+
+ @ApiStatus.Internal
+ public SkeletonHorseTrapEvent(final SkeletonHorse horse, final List<HumanEntity> eligibleHumans) {
+ public SkeletonHorseTrapEvent(@NotNull SkeletonHorse horse, @NotNull 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;
+ }
@ -60,15 +62,17 @@ index 0000000000000000000000000000000000000000..a70f4972a012f955b45a91fe20ca5df7
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -12,19 +12,18 @@ 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..2a8e1aa29ab87c69a02f72615fbf1374714f54cf
index 0000000000000000000000000000000000000000..0ac1618113699ac50b9c35294bf23fb9fb7cfbad
--- /dev/null
+++ b/src/main/java/io/papermc/paper/math/Rotations.java
@@ -0,0 +1,101 @@
@@ -0,0 +1,100 @@
+package io.papermc.paper.math;
+
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Rotations is an immutable object that stores rotations
+ * in degrees on each axis (X, Y, Z).
+ */
+@NullMarked
+public interface Rotations {
+
+ /**
@ -40,7 +39,7 @@ index 0000000000000000000000000000000000000000..2a8e1aa29ab87c69a02f72615fbf1374
+ * @param z the angle for the Z axis in degrees
+ * @return Rotations instance holding the provided rotations
+ */
+ static Rotations ofDegrees(final double x, final double y, final double z) {
+ static @NotNull Rotations ofDegrees(double x, double y, double z) {
+ return new RotationsImpl(x, y, z);
+ }
+
@ -72,7 +71,7 @@ index 0000000000000000000000000000000000000000..2a8e1aa29ab87c69a02f72615fbf1374
+ * @param x the angle in degrees
+ * @return the resultant Rotations
+ */
+ Rotations withX(double x);
+ @NotNull Rotations withX(double x);
+
+ /**
+ * Returns a new Rotations instance which is the result
@ -81,7 +80,7 @@ index 0000000000000000000000000000000000000000..2a8e1aa29ab87c69a02f72615fbf1374
+ * @param y the angle in degrees
+ * @return the resultant Rotations
+ */
+ Rotations withY(double y);
+ @NotNull Rotations withY(double y);
+
+ /**
+ * Returns a new Rotations instance which is the result
@ -90,7 +89,7 @@ index 0000000000000000000000000000000000000000..2a8e1aa29ab87c69a02f72615fbf1374
+ * @param z the angle in degrees
+ * @return the resultant Rotations
+ */
+ Rotations withZ(double z);
+ @NotNull Rotations withZ(double z);
+
+ /**
+ * Returns a new Rotations instance which is the result of adding
@ -101,7 +100,7 @@ index 0000000000000000000000000000000000000000..2a8e1aa29ab87c69a02f72615fbf1374
+ * @param z the angle to add to the Z axis in degrees
+ * @return the resultant Rotations
+ */
+ Rotations add(double x, double y, double z);
+ @NotNull Rotations add(double x, double y, double z);
+
+ /**
+ * Returns a new Rotations instance which is the result of subtracting
@ -112,41 +111,40 @@ index 0000000000000000000000000000000000000000..2a8e1aa29ab87c69a02f72615fbf1374
+ * @param z the angle to subtract from the Z axis in degrees
+ * @return the resultant Rotations
+ */
+ default Rotations subtract(final double x, final double y, final double z) {
+ return this.add(-x, -y, -z);
+ default @NotNull Rotations subtract(double x, double y, double z) {
+ return 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..35b493b870240f2cb142ea0c3bc2a5b2a89af25b
index 0000000000000000000000000000000000000000..53359ab4a6659bce895deef6a21cde848d3cadcd
--- /dev/null
+++ b/src/main/java/io/papermc/paper/math/RotationsImpl.java
@@ -0,0 +1,28 @@
@@ -0,0 +1,27 @@
+package io.papermc.paper.math;
+
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+@NullMarked
+record RotationsImpl(double x, double y, double z) implements Rotations {
+
+ @Override
+ public RotationsImpl withX(final double x) {
+ return new RotationsImpl(x, this.y, this.z);
+ public @NotNull RotationsImpl withX(double x) {
+ return new RotationsImpl(x, y, z);
+ }
+
+ @Override
+ public RotationsImpl withY(final double y) {
+ return new RotationsImpl(this.x, y, this.z);
+ public @NotNull RotationsImpl withY(double y) {
+ return new RotationsImpl(x, y, z);
+ }
+
+ @Override
+ public RotationsImpl withZ(final double z) {
+ return new RotationsImpl(this.x, this.y, z);
+ public @NotNull RotationsImpl withZ(double z) {
+ return new RotationsImpl(x, y, z);
+ }
+
+ @Override
+ public RotationsImpl add(final double x, final double y, final double z) {
+ public @NotNull RotationsImpl add(double x, double y, 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..1472ecef11627d82f72911d86d579ad3bb365dca
index 0000000000000000000000000000000000000000..4f88c101d81e5c3a8a065260304d5816337666d7
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/block/AnvilDamagedEvent.java
@@ -0,0 +1,149 @@
@@ -0,0 +1,154 @@
+package com.destroystokyo.paper.event.block;
+
+import org.bukkit.Material;
@ -20,13 +20,12 @@ index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3
+import org.bukkit.inventory.AnvilInventory;
+import org.bukkit.inventory.InventoryView;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.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();
@ -35,11 +34,12 @@ index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public AnvilDamagedEvent(final InventoryView inventory, final @Nullable BlockData blockData) {
+ public AnvilDamagedEvent(@NotNull InventoryView inventory, @Nullable BlockData blockData) {
+ super(inventory);
+ this.damageState = DamageState.getState(blockData);
+ }
+
+ @NotNull
+ @Override
+ public AnvilInventory getInventory() {
+ return (AnvilInventory) super.getInventory();
@ -50,6 +50,7 @@ index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3
+ *
+ * @return Damage state
+ */
+ @NotNull
+ public DamageState getDamageState() {
+ return this.damageState;
+ }
@ -59,7 +60,7 @@ index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3
+ *
+ * @param damageState Damage state
+ */
+ public void setDamageState(final DamageState damageState) {
+ public void setDamageState(@NotNull DamageState damageState) {
+ this.damageState = damageState;
+ }
+
@ -77,7 +78,7 @@ index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3
+ *
+ * @param breaking {@code true} if breaking
+ */
+ public void setBreaking(final boolean breaking) {
+ public void setBreaking(boolean breaking) {
+ if (breaking) {
+ this.damageState = DamageState.BROKEN;
+ } else if (this.damageState == DamageState.BROKEN) {
@ -91,15 +92,16 @@ index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
@ -115,7 +117,7 @@ index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3
+
+ private final Material material;
+
+ DamageState(final Material material) {
+ DamageState(@NotNull Material material) {
+ this.material = material;
+ }
+
@ -124,6 +126,7 @@ index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3
+ *
+ * @return Material
+ */
+ @NotNull
+ public Material getMaterial() {
+ return this.material;
+ }
@ -135,7 +138,8 @@ index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3
+ * @return DamageState
+ * @throws IllegalArgumentException If non anvil block data is given
+ */
+ public static DamageState getState(final @Nullable BlockData blockData) {
+ @NotNull
+ public static DamageState getState(@Nullable BlockData blockData) {
+ return blockData == null ? BROKEN : getState(blockData.getMaterial());
+ }
+
@ -146,11 +150,12 @@ index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3
+ * @return DamageState
+ * @throws IllegalArgumentException If non anvil material is given
+ */
+ public static DamageState getState(final @Nullable Material material) {
+ @NotNull
+ public static DamageState getState(@Nullable Material material) {
+ if (material == null) {
+ return BROKEN;
+ }
+ for (final DamageState state : values()) {
+ for (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..a5d4442b53c4bd70165c3240c7dbd3d56b6bf0ae
index 0000000000000000000000000000000000000000..30864539574e23bbe9e4c5dc73ad6614de782ac2
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeChangeDirectionEvent.java
@@ -0,0 +1,41 @@
@@ -0,0 +1,40 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Slime;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired when a Slime decides to change its facing direction.
@ -22,13 +22,12 @@ index 0000000000000000000000000000000000000000..a5d4442b53c4bd70165c3240c7dbd3d5
+ * 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(final Slime slime, final float yaw) {
+ public SlimeChangeDirectionEvent(@NotNull Slime slime, float yaw) {
+ super(slime);
+ this.yaw = yaw;
+ }
@ -47,13 +46,13 @@ index 0000000000000000000000000000000000000000..a5d4442b53c4bd70165c3240c7dbd3d5
+ *
+ * @param yaw Chosen yaw
+ */
+ public void setNewYaw(final float yaw) {
+ public void setNewYaw(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..d481d116452fb5a702bc88a08da3c28cd0401a70
index 0000000000000000000000000000000000000000..706ed85a5415d688aaa5f138cbf583b9e2bab27d
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimePathfindEvent.java
@@ -0,0 +1,56 @@
@ -64,7 +63,7 @@ index 0000000000000000000000000000000000000000..d481d116452fb5a702bc88a08da3c28c
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired when a Slime decides to start pathfinding.
@ -72,7 +71,6 @@ index 0000000000000000000000000000000000000000..d481d116452fb5a702bc88a08da3c28c
+ * 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();
@ -80,7 +78,7 @@ index 0000000000000000000000000000000000000000..d481d116452fb5a702bc88a08da3c28c
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public SlimePathfindEvent(final Slime slime) {
+ public SlimePathfindEvent(@NotNull Slime slime) {
+ super(slime);
+ }
+
@ -89,7 +87,7 @@ index 0000000000000000000000000000000000000000..d481d116452fb5a702bc88a08da3c28c
+ *
+ * @return The Slime that is pathfinding.
+ */
+ @Override
+ @NotNull
+ public Slime getEntity() {
+ return (Slime) super.getEntity();
+ }
@ -100,30 +98,31 @@ index 0000000000000000000000000000000000000000..d481d116452fb5a702bc88a08da3c28c
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ 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..4233ea3012c03660c42e3ec93832a6e019440eba
index 0000000000000000000000000000000000000000..65e8a29751e338b0f0acda7bef9e014852a73e6e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeSwimEvent.java
@@ -0,0 +1,20 @@
@@ -0,0 +1,19 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Slime;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired when a Slime decides to start jumping while swimming in water/lava.
@ -131,17 +130,16 @@ index 0000000000000000000000000000000000000000..4233ea3012c03660c42e3ec93832a6e0
+ * 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(final Slime slime) {
+ public SlimeSwimEvent(@NotNull 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..ba7369aab0c257acafda7d3a43a41e409240bf1d
index 0000000000000000000000000000000000000000..87c64b04dfec232e98361c3ec29da7664498c65b
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeTargetLivingEntityEvent.java
@@ -0,0 +1,33 @@
@ -150,7 +148,7 @@ index 0000000000000000000000000000000000000000..ba7369aab0c257acafda7d3a43a41e40
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Slime;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired when a Slime decides to change direction to target a LivingEntity.
@ -158,13 +156,12 @@ index 0000000000000000000000000000000000000000..ba7369aab0c257acafda7d3a43a41e40
+ * 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 {
+
+ private final LivingEntity target;
+ @NotNull private final LivingEntity target;
+
+ @ApiStatus.Internal
+ public SlimeTargetLivingEntityEvent(final Slime slime, final LivingEntity target) {
+ public SlimeTargetLivingEntityEvent(@NotNull Slime slime, @NotNull LivingEntity target) {
+ super(slime);
+ this.target = target;
+ }
@ -174,21 +171,22 @@ index 0000000000000000000000000000000000000000..ba7369aab0c257acafda7d3a43a41e40
+ *
+ * @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..0ea085c4a1cf663e2333444cebda876db321164d
index 0000000000000000000000000000000000000000..2ad9cc1673ffbb8b48349e461d1154d1d4ec2874
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeWanderEvent.java
@@ -0,0 +1,20 @@
@@ -0,0 +1,19 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.entity.Slime;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired when a Slime decides to start wandering.
@ -196,11 +194,10 @@ index 0000000000000000000000000000000000000000..0ea085c4a1cf663e2333444cebda876d
+ * 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(final Slime slime) {
+ public SlimeWanderEvent(@NotNull 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..e465222aa8218a7fef85f2e1df1a919a88499eab
index 0000000000000000000000000000000000000000..ff7d9ff618ab821eeece6923a694a9a4eea8585d
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/PhantomPreSpawnEvent.java
@@ -0,0 +1,32 @@
@ -17,18 +17,17 @@ index 0000000000000000000000000000000000000000..e465222aa8218a7fef85f2e1df1a919a
+import org.bukkit.entity.EntityType;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Called when a phantom is spawned for an exhausted player
+ */
+@NullMarked
+public class PhantomPreSpawnEvent extends PreCreatureSpawnEvent {
+
+ private final Entity entity;
+ @NotNull private final Entity entity;
+
+ @ApiStatus.Internal
+ public PhantomPreSpawnEvent(final Location location, final Entity entity, final CreatureSpawnEvent.SpawnReason reason) {
+ public PhantomPreSpawnEvent(@NotNull Location location, @NotNull Entity entity, @NotNull CreatureSpawnEvent.SpawnReason reason) {
+ super(location, EntityType.PHANTOM, reason);
+ this.entity = entity;
+ }
@ -38,6 +37,7 @@ index 0000000000000000000000000000000000000000..e465222aa8218a7fef85f2e1df1a919a
+ *
+ * @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..8b97cc830aa8bdb09dec3c4b8ebe4fb22d279f46
index 0000000000000000000000000000000000000000..e86500337f26fcb6bb04545c68c67df32021ce25
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/CreeperIgniteEvent.java
@@ -0,0 +1,60 @@
@ -17,14 +17,13 @@ index 0000000000000000000000000000000000000000..8b97cc830aa8bdb09dec3c4b8ebe4fb2
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
@ -33,11 +32,12 @@ index 0000000000000000000000000000000000000000..8b97cc830aa8bdb09dec3c4b8ebe4fb2
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public CreeperIgniteEvent(final Creeper creeper, final boolean ignited) {
+ public CreeperIgniteEvent(@NotNull Creeper creeper, boolean ignited) {
+ super(creeper);
+ this.ignited = ignited;
+ }
+
+ @NotNull
+ @Override
+ public Creeper getEntity() {
+ return (Creeper) super.getEntity();
@ -47,25 +47,25 @@ index 0000000000000000000000000000000000000000..8b97cc830aa8bdb09dec3c4b8ebe4fb2
+ return this.ignited;
+ }
+
+ public void setIgnited(final boolean ignited) {
+ public void setIgnited(boolean ignited) {
+ this.ignited = ignited;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -13,28 +13,30 @@ 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..5f6d6e222f9f1ac1648a11b6d4a240371c4f07e9
index 0000000000000000000000000000000000000000..3c1e2c93d923a683cc0455af77c43784ef12270e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java
@@ -0,0 +1,221 @@
@@ -0,0 +1,220 @@
+package com.destroystokyo.paper.entity;
+
+import java.util.List;
+import org.bukkit.Location;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Mob;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Handles pathfinding operations for an Entity
+ */
+@NullMarked
+public interface Pathfinder {
+
+ /**
+ *
+ * @return The entity that is controlled by this pathfinder
+ */
+ @NotNull
+ Mob getEntity();
+
+ /**
@ -44,7 +46,6 @@ index 0000000000000000000000000000000000000000..5f6d6e222f9f1ac1648a11b6d4a24037
+
+ /**
+ * 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();
@ -52,88 +53,86 @@ index 0000000000000000000000000000000000000000..5f6d6e222f9f1ac1648a11b6d4a24037
+ /**
+ * @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(Location loc);
+ @Nullable PathResult findPath(@NotNull 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(LivingEntity target);
+ @Nullable PathResult findPath(@NotNull 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(Location loc) {
+ return this.moveTo(loc, 1);
+ default boolean moveTo(@NotNull Location loc) {
+ return 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(Location loc, double speed) {
+ PathResult path = this.findPath(loc);
+ return path != null && this.moveTo(path, speed);
+ default boolean moveTo(@NotNull Location loc, double speed) {
+ PathResult path = findPath(loc);
+ return path != null && 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(LivingEntity target) {
+ return this.moveTo(target, 1);
+ default boolean moveTo(@NotNull LivingEntity target) {
+ return 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(LivingEntity target, double speed) {
+ PathResult path = this.findPath(target);
+ return path != null && this.moveTo(path, speed);
+ default boolean moveTo(@NotNull LivingEntity target, double speed) {
+ PathResult path = findPath(target);
+ return path != null && moveTo(path, speed);
+ }
+
+ /**
@ -143,19 +142,19 @@ index 0000000000000000000000000000000000000000..5f6d6e222f9f1ac1648a11b6d4a24037
+ * @param path The Path to start following
+ * @return If the pathfinding was successfully started
+ */
+ default boolean moveTo(PathResult path) {
+ return this.moveTo(path, 1);
+ default boolean moveTo(@NotNull PathResult path) {
+ return 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(PathResult path, double speed);
+ boolean moveTo(@NotNull PathResult path, double speed);
+
+ /**
+ * Checks if this pathfinder allows passing through closed doors.
@ -206,11 +205,11 @@ index 0000000000000000000000000000000000000000..5f6d6e222f9f1ac1648a11b6d4a24037
+
+ /**
+ * 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()}
+ *
+ * Will return points the entity has already moved past, see {@link #getNextPointIndex()}
+ * @return List of points
+ */
+ @NotNull
+ List<Location> getPoints();
+
+ /**

View file

@ -5,10 +5,10 @@ Subject: [PATCH] Material API additions
diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java
index 111c9a6be1f3d095cf8e82b118371986b6cc0fc7..c407bc264ab6c2e5aa7122d4caec63f9b482d76d 100644
index 019cc6baf8c767d973feba55ddc99a8d222e00d8..6ffed5ef4331498ff318ffc5850f8b9a0b85eba7 100644
--- a/src/main/java/org/bukkit/Material.java
+++ b/src/main/java/org/bukkit/Material.java
@@ -129,6 +129,7 @@ import org.jetbrains.annotations.Nullable;
@@ -127,6 +127,7 @@ import org.jetbrains.annotations.Nullable;
/**
* An enum of all material IDs accepted by the official server and client
*/
@ -16,7 +16,7 @@ index 111c9a6be1f3d095cf8e82b118371986b6cc0fc7..c407bc264ab6c2e5aa7122d4caec63f9
public enum Material implements Keyed, Translatable {
//<editor-fold desc="Materials" defaultstate="collapsed">
AIR(9648, 0),
@@ -4662,6 +4663,22 @@ public enum Material implements Keyed, Translatable {
@@ -4660,6 +4661,22 @@ public enum Material implements Keyed, Translatable {
}
}

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..679b37056be9515c69922285affbf0301f5335e3
index 0000000000000000000000000000000000000000..2910f0bf929d918c86510f29d9361bbc19411256
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/PreSpawnerSpawnEvent.java
@@ -0,0 +1,29 @@
@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..679b37056be9515c69922285affbf030
+import org.bukkit.entity.EntityType;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Called before an entity is spawned into a world by a spawner.
@ -30,17 +30,17 @@ index 0000000000000000000000000000000000000000..679b37056be9515c69922285affbf030
+ * 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 {
+
+ private final Location spawnerLocation;
+ @NotNull private final Location spawnerLocation;
+
+ @ApiStatus.Internal
+ public PreSpawnerSpawnEvent(final Location location, final EntityType type, final Location spawnerLocation) {
+ public PreSpawnerSpawnEvent(@NotNull Location location, @NotNull EntityType type, @NotNull 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..91cede0e53cf6f1089e549053ebc2e2b190a1aab
index 0000000000000000000000000000000000000000..cfbc8aaf862ac90e794ee38bf8a6cb9ea414b13e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleGoHomeEvent.java
@@ -0,0 +1,53 @@
@ -17,12 +17,11 @@ index 0000000000000000000000000000000000000000..91cede0e53cf6f1089e549053ebc2e2b
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired when a Turtle decides to go home
+ */
+@NullMarked
+public class TurtleGoHomeEvent extends EntityEvent implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -30,7 +29,7 @@ index 0000000000000000000000000000000000000000..91cede0e53cf6f1089e549053ebc2e2b
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public TurtleGoHomeEvent(final Turtle turtle) {
+ public TurtleGoHomeEvent(@NotNull Turtle turtle) {
+ super(turtle);
+ }
+
@ -39,7 +38,7 @@ index 0000000000000000000000000000000000000000..91cede0e53cf6f1089e549053ebc2e2b
+ *
+ * @return The turtle
+ */
+ @Override
+ @NotNull
+ public Turtle getEntity() {
+ return (Turtle) super.getEntity();
+ }
@ -50,25 +49,26 @@ index 0000000000000000000000000000000000000000..91cede0e53cf6f1089e549053ebc2e2b
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ 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..1492d168aa1dc538b732b0ff262074cc7c9900e6
index 0000000000000000000000000000000000000000..3029e406cd684efb5645e38711dff9c0bb7b01e4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java
@@ -0,0 +1,90 @@
@@ -0,0 +1,92 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.Location;
@ -77,23 +77,23 @@ index 0000000000000000000000000000000000000000..1492d168aa1dc538b732b0ff262074cc
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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(final Turtle turtle, final Location location, final int eggCount) {
+ public TurtleLayEggEvent(@NotNull Turtle turtle, @NotNull Location location, int eggCount) {
+ super(turtle);
+ this.location = location;
+ this.eggCount = eggCount;
@ -104,7 +104,7 @@ index 0000000000000000000000000000000000000000..1492d168aa1dc538b732b0ff262074cc
+ *
+ * @return The turtle
+ */
+ @Override
+ @NotNull
+ public Turtle getEntity() {
+ return (Turtle) super.getEntity();
+ }
@ -114,6 +114,7 @@ index 0000000000000000000000000000000000000000..1492d168aa1dc538b732b0ff262074cc
+ *
+ * @return Location of eggs
+ */
+ @NotNull
+ public Location getLocation() {
+ return this.location.clone();
+ }
@ -132,7 +133,7 @@ index 0000000000000000000000000000000000000000..1492d168aa1dc538b732b0ff262074cc
+ *
+ * @param eggCount Number of eggs
+ */
+ public void setEggCount(final int eggCount) {
+ public void setEggCount(int eggCount) {
+ if (eggCount < 1) {
+ this.cancelled = true;
+ return;
@ -146,25 +147,26 @@ index 0000000000000000000000000000000000000000..1492d168aa1dc538b732b0ff262074cc
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ 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..a84101fb1b478f3018f283bc47d3e73a7ae5bbc8
index 0000000000000000000000000000000000000000..7a2fa4a11b47e4982d1644830d7e28f12b4378ec
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java
@@ -0,0 +1,65 @@
@@ -0,0 +1,66 @@
+package com.destroystokyo.paper.event.entity;
+
+import org.bukkit.Location;
@ -173,21 +175,20 @@ index 0000000000000000000000000000000000000000..a84101fb1b478f3018f283bc47d3e73a
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final Location location;
+ @NotNull private final Location location;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public TurtleStartDiggingEvent(final Turtle turtle, final Location location) {
+ public TurtleStartDiggingEvent(@NotNull Turtle turtle, @NotNull Location location) {
+ super(turtle);
+ this.location = location;
+ }
@ -197,7 +198,7 @@ index 0000000000000000000000000000000000000000..a84101fb1b478f3018f283bc47d3e73a
+ *
+ * @return The turtle
+ */
+ @Override
+ @NotNull
+ public Turtle getEntity() {
+ return (Turtle) super.getEntity();
+ }
@ -207,6 +208,7 @@ index 0000000000000000000000000000000000000000..a84101fb1b478f3018f283bc47d3e73a
+ *
+ * @return Location where digging
+ */
+ @NotNull
+ public Location getLocation() {
+ return this.location.clone();
+ }
@ -217,15 +219,16 @@ index 0000000000000000000000000000000000000000..a84101fb1b478f3018f283bc47d3e73a
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ @NotNull
+ 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..5ce2f30c094608cc547d2f2517f0ac2546bab85a
index 0000000000000000000000000000000000000000..a70a64d2273414d95d77e601a41a208cce78e345
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerStartSpectatingEntityEvent.java
@@ -0,0 +1,68 @@
@@ -0,0 +1,71 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.entity.Entity;
@ -20,23 +20,22 @@ index 0000000000000000000000000000000000000000..5ce2f30c094608cc547d2f2517f0ac25
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final Entity currentSpectatorTarget;
+ private final Entity newSpectatorTarget;
+ @NotNull private final Entity currentSpectatorTarget;
+ @NotNull private final Entity newSpectatorTarget;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerStartSpectatingEntityEvent(final Player player, final Entity currentSpectatorTarget, final Entity newSpectatorTarget) {
+ public PlayerStartSpectatingEntityEvent(@NotNull Player player, @NotNull Entity currentSpectatorTarget, @NotNull Entity newSpectatorTarget) {
+ super(player);
+ this.currentSpectatorTarget = currentSpectatorTarget;
+ this.newSpectatorTarget = newSpectatorTarget;
@ -47,6 +46,7 @@ index 0000000000000000000000000000000000000000..5ce2f30c094608cc547d2f2517f0ac25
+ *
+ * @return The entity the player is currently spectating (before they start spectating the new target).
+ */
+ @NotNull
+ public Entity getCurrentSpectatorTarget() {
+ return this.currentSpectatorTarget;
+ }
@ -56,6 +56,7 @@ index 0000000000000000000000000000000000000000..5ce2f30c094608cc547d2f2517f0ac25
+ *
+ * @return The entity the player is now going to be spectating.
+ */
+ @NotNull
+ public Entity getNewSpectatorTarget() {
+ return this.newSpectatorTarget;
+ }
@ -66,15 +67,17 @@ index 0000000000000000000000000000000000000000..5ce2f30c094608cc547d2f2517f0ac25
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
@ -82,10 +85,10 @@ index 0000000000000000000000000000000000000000..5ce2f30c094608cc547d2f2517f0ac25
+
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..ebda87b7914995a28abce844654ee4f5089c416e
index 0000000000000000000000000000000000000000..a6a5ebc534cc380740ba42790149c8b85f52aabb
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerStopSpectatingEntityEvent.java
@@ -0,0 +1,55 @@
@@ -0,0 +1,57 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.entity.Entity;
@ -94,21 +97,20 @@ index 0000000000000000000000000000000000000000..ebda87b7914995a28abce844654ee4f5
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final Entity spectatorTarget;
+ @NotNull private final Entity spectatorTarget;
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerStopSpectatingEntityEvent(final Player player, final Entity spectatorTarget) {
+ public PlayerStopSpectatingEntityEvent(@NotNull Player player, @NotNull Entity spectatorTarget) {
+ super(player);
+ this.spectatorTarget = spectatorTarget;
+ }
@ -118,6 +120,7 @@ index 0000000000000000000000000000000000000000..ebda87b7914995a28abce844654ee4f5
+ *
+ * @return The entity the player is currently spectating (before they will stop).
+ */
+ @NotNull
+ public Entity getSpectatorTarget() {
+ return this.spectatorTarget;
+ }
@ -128,15 +131,17 @@ index 0000000000000000000000000000000000000000..ebda87b7914995a28abce844654ee4f5
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -35,20 +35,21 @@ 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..5f5afcdb3c9e669ed0e730c720ad91d16b95602c
index 0000000000000000000000000000000000000000..d0fb13adc140f1ca74d0c3448f92baa60684f3e2
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java
@@ -0,0 +1,83 @@
@@ -0,0 +1,88 @@
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * <p>
@ -75,17 +76,16 @@ index 0000000000000000000000000000000000000000..5f5afcdb3c9e669ed0e730c720ad91d1
+ * 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();
+
+ private final UUID playerUniqueId;
+ private final String playerName;
+ private final InetAddress ipAddress;
+ @NotNull private final UUID playerUniqueId;
+ @NotNull private final String playerName;
+ @NotNull private final InetAddress ipAddress;
+
+ @ApiStatus.Internal
+ public PlayerConnectionCloseEvent(final UUID playerUniqueId, final String playerName, final InetAddress ipAddress, final boolean async) {
+ public PlayerConnectionCloseEvent(@NotNull final UUID playerUniqueId, @NotNull final String playerName, @NotNull final InetAddress ipAddress, final boolean async) {
+ super(async);
+ this.playerUniqueId = playerUniqueId;
+ this.playerName = playerName;
@ -95,6 +95,7 @@ index 0000000000000000000000000000000000000000..5f5afcdb3c9e669ed0e730c720ad91d1
+ /**
+ * Returns the {@code UUID} of the player disconnecting.
+ */
+ @NotNull
+ public UUID getPlayerUniqueId() {
+ return this.playerUniqueId;
+ }
@ -102,6 +103,7 @@ index 0000000000000000000000000000000000000000..5f5afcdb3c9e669ed0e730c720ad91d1
+ /**
+ * Returns the name of the player disconnecting.
+ */
+ @NotNull
+ public String getPlayerName() {
+ return this.playerName;
+ }
@ -109,15 +111,18 @@ index 0000000000000000000000000000000000000000..5f5afcdb3c9e669ed0e730c720ad91d1
+ /**
+ * 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..122ccdef02c292c5705a6ac0a96e6095d28bd7bf
index 0000000000000000000000000000000000000000..c0742b58ca2c098c27394915b624889ece1a9168
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java
@@ -0,0 +1,120 @@
@@ -0,0 +1,122 @@
+package com.destroystokyo.paper.event.block;
+
+import org.bukkit.block.Block;
@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..122ccdef02c292c5705a6ac0a96e6095
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.block.BlockExpEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired anytime the server intends to 'destroy' a block through some triggering reason.
@ -36,12 +36,11 @@ index 0000000000000000000000000000000000000000..122ccdef02c292c5705a6ac0a96e6095
+ * <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();
+
+ private final BlockData newState;
+ @NotNull private final BlockData newState;
+ private boolean willDrop;
+ private boolean playEffect = true;
+ private BlockData effectBlock;
@ -49,7 +48,7 @@ index 0000000000000000000000000000000000000000..122ccdef02c292c5705a6ac0a96e6095
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public BlockDestroyEvent(final Block block, final BlockData newState, final BlockData effectBlock, final int xp, final boolean willDrop) {
+ public BlockDestroyEvent(@NotNull Block block, @NotNull BlockData newState, @NotNull BlockData effectBlock, int xp, boolean willDrop) {
+ super(block, xp);
+ this.newState = newState;
+ this.effectBlock = effectBlock;
@ -61,6 +60,7 @@ index 0000000000000000000000000000000000000000..122ccdef02c292c5705a6ac0a96e6095
+ *
+ * @return block break effect
+ */
+ @NotNull
+ public BlockData getEffectBlock() {
+ return this.effectBlock;
+ }
@ -72,14 +72,14 @@ index 0000000000000000000000000000000000000000..122ccdef02c292c5705a6ac0a96e6095
+ *
+ * @param effectBlock block effect
+ */
+ public void setEffectBlock(final BlockData effectBlock) {
+ public void setEffectBlock(@NotNull BlockData effectBlock) {
+ this.effectBlock = effectBlock;
+ }
+
+ /**
+ * @return The new state of this block (Air, or a Fluid type)
+ */
+ public BlockData getNewState() {
+ public @NotNull BlockData getNewState() {
+ return this.newState.clone();
+ }
+
@ -93,7 +93,7 @@ index 0000000000000000000000000000000000000000..122ccdef02c292c5705a6ac0a96e6095
+ /**
+ * @param willDrop If the server is going to drop the block in question with this destroy event
+ */
+ public void setWillDrop(final boolean willDrop) {
+ public void setWillDrop(boolean willDrop) {
+ this.willDrop = willDrop;
+ }
+
@ -107,7 +107,7 @@ index 0000000000000000000000000000000000000000..122ccdef02c292c5705a6ac0a96e6095
+ /**
+ * @param playEffect If the server should play the sound effect for this destruction
+ */
+ public void setPlayEffect(final boolean playEffect) {
+ public void setPlayEffect(boolean playEffect) {
+ this.playEffect = playEffect;
+ }
+
@ -123,15 +123,17 @@ index 0000000000000000000000000000000000000000..122ccdef02c292c5705a6ac0a96e6095
+ * If the event is cancelled, the block will remain in its previous state.
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -6,23 +6,22 @@ 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..b9a59a28c1dec6c174885892ff40d3caaaf409a4
index 0000000000000000000000000000000000000000..22fa169c278639f31aec2695259963038de0af8a
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/WhitelistToggleEvent.java
@@ -0,0 +1,42 @@
@@ -0,0 +1,43 @@
+package com.destroystokyo.paper.event.server;
+
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
@ -30,7 +29,7 @@ index 0000000000000000000000000000000000000000..b9a59a28c1dec6c174885892ff40d3ca
+ private final boolean enabled;
+
+ @ApiStatus.Internal
+ public WhitelistToggleEvent(final boolean enabled) {
+ public WhitelistToggleEvent(boolean enabled) {
+ this.enabled = enabled;
+ }
+
@ -43,11 +42,13 @@ index 0000000000000000000000000000000000000000..b9a59a28c1dec6c174885892ff40d3ca
+ 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..5a8813c80e56d17ccaa35a7eef2f6bd70c7a3d96
index 0000000000000000000000000000000000000000..8edc33bde29e967cec488d0f5e2f1097291978a6
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java
@@ -0,0 +1,395 @@
@@ -0,0 +1,424 @@
+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,7 +33,6 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @author Mark Vainomaa
+ */
+@NullMarked
+public final class GS4QueryEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -43,7 +42,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ private QueryResponse response;
+
+ @ApiStatus.Internal
+ public GS4QueryEvent(final QueryType queryType, final InetAddress querierAddress, final QueryResponse response) {
+ public GS4QueryEvent(@NotNull QueryType queryType, @NotNull InetAddress querierAddress, @NotNull QueryResponse response) {
+ super(true); // should always be called async
+ this.queryType = queryType;
+ this.querierAddress = querierAddress;
@ -55,6 +54,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return query type
+ */
+ @NotNull
+ public QueryType getQueryType() {
+ return this.queryType;
+ }
@ -64,6 +64,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return querier address
+ */
+ @NotNull
+ public InetAddress getQuerierAddress() {
+ return this.querierAddress;
+ }
@ -73,6 +74,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return query response
+ */
+ @NotNull
+ public QueryResponse getResponse() {
+ return this.response;
+ }
@ -82,15 +84,17 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @param response query response
+ */
+ public void setResponse(final QueryResponse response) {
+ public void setResponse(@NotNull QueryResponse response) {
+ this.response = Preconditions.checkNotNull(response, "response");
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
@ -111,7 +115,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ FULL
+ }
+
+ public static final class QueryResponse {
+ public final static class QueryResponse {
+
+ private final String motd;
+ private final String gameVersion;
@ -124,7 +128,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ private final String serverVersion;
+ private final 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) {
+ private QueryResponse(String motd, String gameVersion, String map, int currentPlayers, int maxPlayers, String hostname, int port, Collection<String> players, String serverVersion, Collection<PluginInformation> plugins) {
+ this.motd = motd;
+ this.gameVersion = gameVersion;
+ this.map = map;
@ -138,19 +142,21 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ }
+
+ /**
+ * 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;
+ }
@ -160,6 +166,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return map name
+ */
+ @NotNull
+ public String getMap() {
+ return this.map;
+ }
@ -187,6 +194,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return server hostname
+ */
+ @NotNull
+ public String getHostname() {
+ return this.hostname;
+ }
@ -205,6 +213,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return collection of players
+ */
+ @NotNull
+ public Collection<String> getPlayers() {
+ return this.players;
+ }
@ -214,6 +223,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return server software
+ */
+ @NotNull
+ public String getServerVersion() {
+ return this.serverVersion;
+ }
@ -223,6 +233,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return collection of plugins
+ */
+ @NotNull
+ public Collection<PluginInformation> getPlugins() {
+ return this.plugins;
+ }
@ -232,18 +243,19 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return {@link QueryResponse} builder
+ */
+ @NotNull
+ public Builder toBuilder() {
+ return QueryResponse.builder()
+ .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());
+ .motd(getMotd())
+ .gameVersion(getGameVersion())
+ .map(getMap())
+ .currentPlayers(getCurrentPlayers())
+ .maxPlayers(getMaxPlayers())
+ .hostname(getHostname())
+ .port(getPort())
+ .players(getPlayers())
+ .serverVersion(getServerVersion())
+ .plugins(getPlugins());
+ }
+
+ /**
@ -251,6 +263,7 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return {@link QueryResponse} builder
+ */
+ @NotNull
+ public static Builder builder() {
+ return new Builder();
+ }
@ -259,12 +272,11 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ * A builder for {@link QueryResponse} objects.
+ */
+ public static final class Builder {
+
+ private @MonotonicNonNull String motd;
+ private @MonotonicNonNull String gameVersion;
+ private @MonotonicNonNull String map;
+ private @MonotonicNonNull String hostname;
+ private @MonotonicNonNull String serverVersion;
+ private String motd;
+ private String gameVersion;
+ private String map;
+ private String hostname;
+ private String serverVersion;
+
+ private int currentPlayers;
+ private int maxPlayers;
@ -273,77 +285,90 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ private final List<String> players = new ArrayList<>();
+ private final List<PluginInformation> plugins = new ArrayList<>();
+
+ private Builder() {
+ }
+ private Builder() {}
+
+ public Builder motd(final String motd) {
+ @NotNull
+ public Builder motd(@NotNull String motd) {
+ this.motd = Preconditions.checkNotNull(motd, "motd");
+ return this;
+ }
+
+ public Builder gameVersion(final String gameVersion) {
+ @NotNull
+ public Builder gameVersion(@NotNull String gameVersion) {
+ this.gameVersion = Preconditions.checkNotNull(gameVersion, "gameVersion");
+ return this;
+ }
+
+ public Builder map(final String map) {
+ @NotNull
+ public Builder map(@NotNull String map) {
+ this.map = Preconditions.checkNotNull(map, "map");
+ return this;
+ }
+
+ public Builder currentPlayers(final int currentPlayers) {
+ @NotNull
+ public Builder currentPlayers(int currentPlayers) {
+ Preconditions.checkArgument(currentPlayers >= 0, "currentPlayers cannot be negative");
+ this.currentPlayers = currentPlayers;
+ return this;
+ }
+
+ public Builder maxPlayers(final int maxPlayers) {
+ @NotNull
+ public Builder maxPlayers(int maxPlayers) {
+ Preconditions.checkArgument(maxPlayers >= 0, "maxPlayers cannot be negative");
+ this.maxPlayers = maxPlayers;
+ return this;
+ }
+
+ public Builder hostname(final String hostname) {
+ @NotNull
+ public Builder hostname(@NotNull String hostname) {
+ this.hostname = Preconditions.checkNotNull(hostname, "hostname");
+ return this;
+ }
+
+ public Builder port(final int port) {
+ @NotNull
+ public Builder port(int port) {
+ Preconditions.checkArgument(port >= 1 && port <= 65535, "port must be between 1-65535");
+ this.port = port;
+ return this;
+ }
+
+ public Builder players(final Collection<String> players) {
+ @NotNull
+ public Builder players(@NotNull Collection<String> players) {
+ this.players.addAll(Preconditions.checkNotNull(players, "players"));
+ return this;
+ }
+
+ public Builder players(final String... players) {
+ @NotNull
+ public Builder players(@NotNull String... players) {
+ this.players.addAll(Arrays.asList(Preconditions.checkNotNull(players, "players")));
+ return this;
+ }
+
+ @NotNull
+ public Builder clearPlayers() {
+ this.players.clear();
+ return this;
+ }
+
+ public Builder serverVersion(final String serverVersion) {
+ @NotNull
+ public Builder serverVersion(@NotNull String serverVersion) {
+ this.serverVersion = Preconditions.checkNotNull(serverVersion, "serverVersion");
+ return this;
+ }
+
+ public Builder plugins(final Collection<PluginInformation> plugins) {
+ @NotNull
+ public Builder plugins(@NotNull Collection<PluginInformation> plugins) {
+ this.plugins.addAll(Preconditions.checkNotNull(plugins, "plugins"));
+ return this;
+ }
+
+ public Builder plugins(final PluginInformation... plugins) {
+ @NotNull
+ public Builder plugins(@NotNull PluginInformation... plugins) {
+ this.plugins.addAll(Arrays.asList(Preconditions.checkNotNull(plugins, "plugins")));
+ return this;
+ }
+
+ @NotNull
+ public Builder clearPlugins() {
+ this.plugins.clear();
+ return this;
@ -354,18 +379,19 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ *
+ * @return response
+ */
+ @NotNull
+ public QueryResponse build() {
+ return new QueryResponse(
+ 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)
+ 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)
+ );
+ }
+ }
@ -378,28 +404,31 @@ index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd7
+ private String name;
+ private String version;
+
+ public PluginInformation(final String name, final String version) {
+ public PluginInformation(@NotNull String name, @NotNull String version) {
+ this.name = Preconditions.checkNotNull(name, "name");
+ this.version = Preconditions.checkNotNull(version, "version");
+ }
+
+ @NotNull
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(final String name) {
+ public void setName(@NotNull String name) {
+ this.name = name;
+ }
+
+ public void setVersion(final String version) {
+ public void setVersion(@NotNull String version) {
+ this.version = version;
+ }
+
+ @NotNull
+ public String getVersion() {
+ return this.version;
+ }
+
+ public static PluginInformation of(final String name, final String version) {
+ @NotNull
+ public static PluginInformation of(@NotNull String name, @NotNull 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..e82446ec3d706c47ac9a544f70d0c19b658665d5
index 0000000000000000000000000000000000000000..16961aac061e78fb84029f8435ab5f7c493b1362
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerPostRespawnEvent.java
@@ -0,0 +1,54 @@
@@ -0,0 +1,56 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.Location;
@ -17,21 +17,20 @@ index 0000000000000000000000000000000000000000..e82446ec3d706c47ac9a544f70d0c19b
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Fired after a player has respawned
+ */
+@NullMarked
+public class PlayerPostRespawnEvent extends PlayerEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+ private final static HandlerList HANDLER_LIST = new HandlerList();
+
+ private final Location respawnedLocation;
+ private final boolean isBedSpawn;
+
+ @ApiStatus.Internal
+ public PlayerPostRespawnEvent(final Player respawnPlayer, final Location respawnedLocation, final boolean isBedSpawn) {
+ public PlayerPostRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnedLocation, final boolean isBedSpawn) {
+ super(respawnPlayer);
+ this.respawnedLocation = respawnedLocation;
+ this.isBedSpawn = isBedSpawn;
@ -42,6 +41,7 @@ index 0000000000000000000000000000000000000000..e82446ec3d706c47ac9a544f70d0c19b
+ *
+ * @return location of the respawned player
+ */
+ @NotNull
+ public Location getRespawnedLocation() {
+ return this.respawnedLocation.clone();
+ }
@ -56,10 +56,12 @@ index 0000000000000000000000000000000000000000..e82446ec3d706c47ac9a544f70d0c19b
+ }
+
+ @Override
+ @NotNull
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -300,10 +300,10 @@ index c30600666e7b32b8b4ba1e20ede04fd5ebd5a692..eec6c9cd7da6938351905129bb5a66f4
if (this.world == null) {
return null;
diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java
index c407bc264ab6c2e5aa7122d4caec63f9b482d76d..a432e1c776cd5bda7ba9da8a1b608cb30495e647 100644
index 6ffed5ef4331498ff318ffc5850f8b9a0b85eba7..444406eb7f0c3cd13039bf809254e480ee6fa24f 100644
--- a/src/main/java/org/bukkit/Material.java
+++ b/src/main/java/org/bukkit/Material.java
@@ -4683,20 +4683,20 @@ public enum Material implements Keyed, Translatable {
@@ -4681,20 +4681,20 @@ public enum Material implements Keyed, Translatable {
* Do not use for any reason.
*
* @return ID of this material
@ -328,7 +328,7 @@ index c407bc264ab6c2e5aa7122d4caec63f9b482d76d..a432e1c776cd5bda7ba9da8a1b608cb3
public boolean isLegacy() {
return legacy;
}
@@ -4772,8 +4772,10 @@ public enum Material implements Keyed, Translatable {
@@ -4770,8 +4770,10 @@ public enum Material implements Keyed, Translatable {
* Gets the MaterialData class associated with this Material
*
* @return MaterialData associated with this Material
@ -339,7 +339,7 @@ index c407bc264ab6c2e5aa7122d4caec63f9b482d76d..a432e1c776cd5bda7ba9da8a1b608cb3
public Class<? extends MaterialData> getData() {
Preconditions.checkArgument(legacy, "Cannot get data class of Modern Material");
return ctor.getDeclaringClass();
@@ -5229,7 +5231,11 @@ public enum Material implements Keyed, Translatable {
@@ -5227,7 +5229,11 @@ public enum Material implements Keyed, Translatable {
* material.
*
* @return true if this material can be interacted with.
@ -453,10 +453,10 @@ index 48aecc9421c500137bbef1dfe3bec8de277c3ff9..aff858346776386f1288b648b221404f
return note;
}
diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java
index 883338632b81f6eebc03c95d5883536a5d87fc59..fbede496b05c4b9b1ecd12e711a100586776d469 100644
index d1906d150a7d4c4852e085d6fd480aec317c22e4..e9edc8c17cbd29cfdad31df13acb15bab2304735 100644
--- a/src/main/java/org/bukkit/Registry.java
+++ b/src/main/java/org/bukkit/Registry.java
@@ -228,14 +228,12 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
@@ -220,14 +220,12 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
*
* @see TrimMaterial
*/
@ -471,7 +471,7 @@ index 883338632b81f6eebc03c95d5883536a5d87fc59..fbede496b05c4b9b1ecd12e711a10058
Registry<TrimPattern> TRIM_PATTERN = Bukkit.getRegistry(TrimPattern.class);
/**
* Damage types.
@@ -343,8 +341,11 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
@@ -335,8 +333,11 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
*
* @param input non-null input
* @return registered object or null if does not exist
@ -618,7 +618,7 @@ index e455eb21abf121dc6ff10ff8a13dd06f67096a8f..bbc01e7c192ae6689c301670047ff114
return origin;
}
diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java
index 7dbc2e4883feb5b0b1a20cf36cda01ef3795a262..e4471e86e1b0993425087d8331e7c3d9896b3908 100644
index fcdc5d83621acff5f9210585455be1ea50abb77c..216995288f6b8b407ef8240411b5ed4713379a7a 100644
--- a/src/main/java/org/bukkit/World.java
+++ b/src/main/java/org/bukkit/World.java
@@ -418,9 +418,8 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
@ -632,7 +632,7 @@ index 7dbc2e4883feb5b0b1a20cf36cda01ef3795a262..e4471e86e1b0993425087d8331e7c3d9
public boolean refreshChunk(int x, int z);
/**
@@ -3813,6 +3812,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
@@ -3797,6 +3796,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
StructureSearchResult locateNearestStructure(@NotNull Location origin, @NotNull Structure structure, int radius, boolean findUnexplored);
// Spigot start
@ -640,7 +640,7 @@ index 7dbc2e4883feb5b0b1a20cf36cda01ef3795a262..e4471e86e1b0993425087d8331e7c3d9
public class Spigot {
/**
@@ -3846,7 +3846,11 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
@@ -3830,7 +3830,11 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
}
}
@ -652,7 +652,7 @@ index 7dbc2e4883feb5b0b1a20cf36cda01ef3795a262..e4471e86e1b0993425087d8331e7c3d9
Spigot spigot();
// Spigot end
@@ -4064,9 +4068,9 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
@@ -4048,9 +4052,9 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
* Gets the dimension ID of this environment
*
* @return dimension ID
@ -664,7 +664,7 @@ index 7dbc2e4883feb5b0b1a20cf36cda01ef3795a262..e4471e86e1b0993425087d8331e7c3d9
public int getId() {
return id;
}
@@ -4076,9 +4080,9 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
@@ -4060,9 +4064,9 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
*
* @param id The ID of the environment
* @return The environment
@ -713,25 +713,6 @@ index 3e07fc1bc0e08d0cfd998711c7fd547b2b7b6b73..f4a739d8022d19a7ae0ee9bf93eb5c48
+ @Deprecated(forRemoval = true, since = "1.13")
void setData(@NotNull MaterialData data);
/**
diff --git a/src/main/java/org/bukkit/block/BlockType.java b/src/main/java/org/bukkit/block/BlockType.java
index dfd8187ef941e8afe9cb28a26bf0d2cf2e4c4bc5..d285a1df492d2155f179e8abc17d0bf7527e6d38 100644
--- a/src/main/java/org/bukkit/block/BlockType.java
+++ b/src/main/java/org/bukkit/block/BlockType.java
@@ -3433,9 +3433,14 @@ public interface BlockType extends Keyed, Translatable {
* state as well. This method will return true if there is at least one
* state in which additional interact handling is performed for the
* block type.
+ *
+ * @deprecated This method is not comprehensive and does not accurately reflect what block types are
+ * interactable. Many "interactions" are defined on the item not block, and many are conditional on some other world state
+ * checks being true.
*
* @return true if this block type can be interacted with.
*/
+ @Deprecated // Paper
boolean isInteractable();
/**
diff --git a/src/main/java/org/bukkit/block/BrushableBlock.java b/src/main/java/org/bukkit/block/BrushableBlock.java
index 4bd127b3646307398e0c937c3e36ab671235b72b..f2557a87f468ee20c2d276dbfc0e9a976656c75c 100644
@ -909,7 +890,7 @@ index bafef53c1d449135f1300c8c8fbb06f482ba67e1..f50aaddf8582be55fd4860ad374d8f22
+@Deprecated(forRemoval = true) // Paper
public interface LingeringPotion extends ThrownPotion { }
diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java
index 9e0137ea412ec8c65b2903a76499ba8222446ea3..db7dafba43b50146a32d749ec043c5d548b0d6e3 100644
index 3f1b74af137868e502792c65ccd7ca74f3c3cb8c..c89ffb0f98dccd015e80e299142252fed3ece4a8 100644
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -716,7 +716,9 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
@ -922,7 +903,7 @@ index 9e0137ea412ec8c65b2903a76499ba8222446ea3..db7dafba43b50146a32d749ec043c5d5
public void setSwimming(boolean swimming);
/**
@@ -981,7 +983,7 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
@@ -971,7 +973,7 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
* @deprecated entity groupings are now managed by tags, not categories
*/
@NotNull
@ -1286,16 +1267,16 @@ index f2a2a2ad9930499c5bf624e73571a3294a90db14..c8540a42ab44647fdd112ce4f731f3dc
return getView().getCursor();
}
diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java
index 3e6ac5beb137efd8ecd80e2e9b17015cb38e8a0a..ae4ae1fa6d407665ef03edcdef683d741668acf1 100644
index 32cd8ee2e849df602a7e10aa5d0a218007faa0ac..fbdbd2f4da5e09d4b111ddcf72e2d7dd59046bd7 100644
--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java
+++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java
@@ -155,7 +155,7 @@ public enum InventoryType {
@@ -153,7 +153,7 @@ public enum InventoryType {
*
* @deprecated use {@link #SMITHING}
*/
- @Deprecated
+ @Deprecated(forRemoval = true) // Paper
SMITHING_NEW(4, "Upgrade Gear", MenuType.SMITHING),
SMITHING_NEW(4, "Upgrade Gear"),
;
diff --git a/src/main/java/org/bukkit/event/player/PlayerBedLeaveEvent.java b/src/main/java/org/bukkit/event/player/PlayerBedLeaveEvent.java

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..c879588693c930226049e60393f2f23aad1588b9
index 0000000000000000000000000000000000000000..17e9f39ce1cc7489e936c96f95b8b0579528b222
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/ServerTickEndEvent.java
@@ -0,0 +1,62 @@
@ -16,12 +16,11 @@ index 0000000000000000000000000000000000000000..c879588693c930226049e60393f2f23a
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Called when the server has finished ticking the main loop
+ */
+@NullMarked
+public class ServerTickEndEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -31,7 +30,7 @@ index 0000000000000000000000000000000000000000..c879588693c930226049e60393f2f23a
+ private final long timeEnd;
+
+ @ApiStatus.Internal
+ public ServerTickEndEvent(final int tickNumber, final double tickDuration, final long timeRemaining) {
+ public ServerTickEndEvent(int tickNumber, double tickDuration, long timeRemaining) {
+ this.tickNumber = tickNumber;
+ this.tickDuration = tickDuration;
+ this.timeEnd = System.nanoTime() + timeRemaining;
@ -64,18 +63,19 @@ index 0000000000000000000000000000000000000000..c879588693c930226049e60393f2f23a
+ return this.timeEnd - System.nanoTime();
+ }
+
+ @Override
+ @NotNull
+ 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..890153657ea5b756a8a3a038d6b53857e0d17fea
index 0000000000000000000000000000000000000000..fb5bbfffea8b883e4c8769484a2b64dd895cb617
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java
@@ -0,0 +1,35 @@
@ -84,9 +84,8 @@ index 0000000000000000000000000000000000000000..890153657ea5b756a8a3a038d6b53857
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+@NullMarked
+public class ServerTickStartEvent extends Event {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -94,7 +93,7 @@ index 0000000000000000000000000000000000000000..890153657ea5b756a8a3a038d6b53857
+ private final int tickNumber;
+
+ @ApiStatus.Internal
+ public ServerTickStartEvent(final int tickNumber) {
+ public ServerTickStartEvent(int tickNumber) {
+ this.tickNumber = tickNumber;
+ }
+
@ -105,11 +104,12 @@ index 0000000000000000000000000000000000000000..890153657ea5b756a8a3a038d6b53857
+ return this.tickNumber;
+ }
+
+ @Override
+ @NotNull
+ 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..26526049a4c7f7ebe6bea27a9c5a638df3ef8854
index 0000000000000000000000000000000000000000..092bab9be36acc0f04c7ea5b3510879169a0a125
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/ThrownEggHatchEvent.java
@@ -0,0 +1,117 @@
@@ -0,0 +1,120 @@
+package com.destroystokyo.paper.event.entity;
+
+import com.google.common.base.Preconditions;
@ -20,14 +20,13 @@ index 0000000000000000000000000000000000000000..26526049a4c7f7ebe6bea27a9c5a638d
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
@ -38,7 +37,7 @@ index 0000000000000000000000000000000000000000..26526049a4c7f7ebe6bea27a9c5a638d
+ private EntityType hatchType;
+
+ @ApiStatus.Internal
+ public ThrownEggHatchEvent(final Egg egg, final boolean hatching, final byte numHatches, final EntityType hatchingType) {
+ public ThrownEggHatchEvent(@NotNull final Egg egg, final boolean hatching, final byte numHatches, @NotNull final EntityType hatchingType) {
+ this.egg = egg;
+ this.hatching = hatching;
+ this.numHatches = numHatches;
@ -50,6 +49,7 @@ index 0000000000000000000000000000000000000000..26526049a4c7f7ebe6bea27a9c5a638d
+ *
+ * @return the egg involved in this event
+ */
+ @NotNull
+ public Egg getEgg() {
+ return this.egg;
+ }
@ -68,9 +68,9 @@ index 0000000000000000000000000000000000000000..26526049a4c7f7ebe6bea27a9c5a638d
+ * 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(final boolean hatching) {
+ public void setHatching(boolean hatching) {
+ this.hatching = hatching;
+ }
+
@ -79,6 +79,7 @@ index 0000000000000000000000000000000000000000..26526049a4c7f7ebe6bea27a9c5a638d
+ *
+ * @return The type of the mob being hatched by the egg
+ */
+ @NotNull
+ public EntityType getHatchingType() {
+ return this.hatchType;
+ }
@ -88,13 +89,13 @@ index 0000000000000000000000000000000000000000..26526049a4c7f7ebe6bea27a9c5a638d
+ *
+ * @param hatchType The type of the mob being hatched by the egg
+ */
+ public void setHatchingType(final EntityType hatchType) {
+ public void setHatchingType(@NotNull 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
@ -116,15 +117,17 @@ index 0000000000000000000000000000000000000000..26526049a4c7f7ebe6bea27a9c5a638d
+ *
+ * @param numHatches The number of mobs coming out of the egg
+ */
+ public void setNumHatches(final byte numHatches) {
+ public void setNumHatches(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..b49b72608573ad5b98fc6e0070f6ef105bf177e4
index 0000000000000000000000000000000000000000..a6306c957fcacdcbcc8037b4ee33a167d21ff29e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityJumpEvent.java
@@ -0,0 +1,50 @@
@ -17,14 +17,13 @@ index 0000000000000000000000000000000000000000..b49b72608573ad5b98fc6e0070f6ef10
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.entity.EntityEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
@ -32,39 +31,40 @@ index 0000000000000000000000000000000000000000..b49b72608573ad5b98fc6e0070f6ef10
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public EntityJumpEvent(final LivingEntity entity) {
+ public EntityJumpEvent(@NotNull LivingEntity entity) {
+ super(entity);
+ }
+
+ @NotNull
+ @Override
+ public LivingEntity getEntity() {
+ return (LivingEntity) super.getEntity();
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(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/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java
index db7dafba43b50146a32d749ec043c5d548b0d6e3..c2352d75e02f7be27fcf9ea69df1bd104a2449bd 100644
index ec35111df4b38fd55cc34f4baedebcf39c7fc92b..fdb985763d0a7b0a31ad938616e11ef244f63062 100644
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -1159,4 +1159,26 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
@@ -1149,4 +1149,26 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
return this.getActiveItemHand();
}
// Paper end - active item API

View file

@ -5,8 +5,6 @@ Subject: [PATCH] Add Raw Byte ItemStack Serialization
Serializes using NBT which is safer for server data migrations than bukkits format.
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
index 6e67fdb091a006d2d13bc2d93db4d55348af4c8f..e41d5d9b810c8816cd0d1eba5fd1ea56252fb0df 100644
--- a/src/main/java/org/bukkit/UnsafeValues.java
@ -22,10 +20,10 @@ index 6e67fdb091a006d2d13bc2d93db4d55348af4c8f..e41d5d9b810c8816cd0d1eba5fd1ea56
// Paper end
}
diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java
index e9c29fc1db686b80bc2477d78ec2b361b8600b9e..af09398e0864d338da530495bfd577db8adbe65a 100644
index e9c29fc1db686b80bc2477d78ec2b361b8600b9e..4b4c364dad70126dee17aabca2c3da9f148dd6d0 100644
--- a/src/main/java/org/bukkit/inventory/ItemStack.java
+++ b/src/main/java/org/bukkit/inventory/ItemStack.java
@@ -661,6 +661,117 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
@@ -661,6 +661,30 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
return Bukkit.getServer().getItemFactory().ensureServerConversions(this);
}
@ -52,126 +50,7 @@ index e9c29fc1db686b80bc2477d78ec2b361b8600b9e..af09398e0864d338da530495bfd577db
+ public byte[] serializeAsBytes() {
+ return org.bukkit.Bukkit.getUnsafe().serializeItem(this);
+ }
+
+ /**
+ * The current version byte of the item array format used in {@link #serializeItemsAsBytes(java.util.Collection)}
+ * and {@link #deserializeItemsFromBytes(byte[])} respectively.
+ */
+ private static final byte ARRAY_SERIALIZATION_VERSION = 1;
+
+ /**
+ * Serializes a collection of items to raw bytes in NBT. Serializes null items as {@link #empty()}.
+ * <p>
+ * If you need a string representation to put into a file, you can for example use {@link java.util.Base64} encoding.
+ *
+ * @param items items to serialize
+ * @return bytes representing the items in NBT
+ * @see #serializeAsBytes()
+ */
+ public static byte @NotNull [] serializeItemsAsBytes(java.util.@NotNull Collection<ItemStack> items) {
+ try (final java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream()) {
+ final java.io.DataOutput output = new java.io.DataOutputStream(outputStream);
+ output.writeByte(ARRAY_SERIALIZATION_VERSION);
+ output.writeInt(items.size());
+ for (final ItemStack item : items) {
+ if (item == null || item.isEmpty()) {
+ // Ensure the correct order by including empty/null items
+ output.writeInt(0);
+ continue;
+ }
+
+ final byte[] itemBytes = item.serializeAsBytes();
+ output.writeInt(itemBytes.length);
+ output.write(itemBytes);
+ }
+ return outputStream.toByteArray();
+ } catch (final java.io.IOException e) {
+ throw new RuntimeException("Error while writing itemstack", e);
+ }
+ }
+
+ /**
+ * Serializes a collection of items to raw bytes in NBT. Serializes null items as {@link #empty()}.
+ * <p>
+ * If you need a string representation to put into a file, you can for example use {@link java.util.Base64} encoding.
+ *
+ * @param items items to serialize
+ * @return bytes representing the items in NBT
+ * @see #serializeAsBytes()
+ */
+ public static byte @NotNull [] serializeItemsAsBytes(@Nullable ItemStack @NotNull [] items) {
+ return serializeItemsAsBytes(java.util.Arrays.asList(items));
+ }
+
+ /**
+ * Deserializes this itemstack from raw NBT bytes.
+ * <p>
+ * If you need a string representation to put into a file, you can for example use {@link java.util.Base64} encoding.
+ *
+ * @param bytes bytes representing an item in NBT
+ * @return ItemStack array migrated to this version of Minecraft if needed
+ * @see #deserializeBytes(byte[])
+ */
+ public static @NotNull ItemStack @NotNull [] deserializeItemsFromBytes(final byte @NotNull [] bytes) {
+ try (final java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(bytes)) {
+ final java.io.DataInputStream input = new java.io.DataInputStream(inputStream);
+ final byte version = input.readByte();
+ if (version != ARRAY_SERIALIZATION_VERSION) {
+ throw new IllegalArgumentException("Unsupported version or bad data: " + version);
+ }
+
+ final int count = input.readInt();
+ final ItemStack[] items = new ItemStack[count];
+ for (int i = 0; i < count; i++) {
+ final int length = input.readInt();
+ if (length == 0) {
+ // Empty item, keep entry as empty
+ items[i] = ItemStack.empty();
+ continue;
+ }
+
+ final byte[] itemBytes = new byte[length];
+ input.read(itemBytes);
+ items[i] = ItemStack.deserializeBytes(itemBytes);
+ }
+ return items;
+ } catch (final java.io.IOException e) {
+ throw new RuntimeException("Error while reading itemstack", e);
+ }
+ }
+
/**
* Gets the Display name as seen in the Client.
* Currently the server only supports the English language. To override this,
diff --git a/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java b/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java
index 0f8eb97bd5e2f8b0f0cc03f7c4342aae06c4520c..6c074ff2dcfc279657037013b9b54890d7c8a533 100644
--- a/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java
+++ b/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java
@@ -14,7 +14,11 @@ import org.bukkit.configuration.serialization.ConfigurationSerialization;
* <p>
* Behavior of implementations extending this class is not guaranteed across
* future versions.
+ * @deprecated Object streams on their own are not safe. For safer and more consistent serialization of items,
+ * use {@link org.bukkit.inventory.ItemStack#serializeAsBytes()} or
+ * {@link org.bukkit.inventory.ItemStack#serializeItemsAsBytes(java.util.Collection)}.
*/
+@Deprecated(since = "1.21") // Paper
public class BukkitObjectInputStream extends ObjectInputStream {
/**
diff --git a/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java b/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java
index dd1b9ee5f57773f07924aa311823fd8d63195cb2..4e24e7c73271a579db2c4309951693dfb2fecceb 100644
--- a/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java
+++ b/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java
@@ -14,7 +14,11 @@ import org.bukkit.configuration.serialization.ConfigurationSerializable;
* <p>
* Behavior of implementations extending this class is not guaranteed across
* future versions.
+ * @deprecated Object streams on their own are not safe. For safer and more consistent serialization of items,
+ * use {@link org.bukkit.inventory.ItemStack#serializeAsBytes()} or
+ * {@link org.bukkit.inventory.ItemStack#serializeItemsAsBytes(java.util.Collection)}.
*/
+@Deprecated(since = "1.21") // Paper
public class BukkitObjectOutputStream extends ObjectOutputStream {
/**

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..ed08f823e0620289392f7fc2ff0ac721cff60478
index 0000000000000000000000000000000000000000..f89bfeba29e6988db849957a508ca97ff5322242
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/ClientOption.java
@@ -0,0 +1,51 @@
@@ -0,0 +1,52 @@
+package com.destroystokyo.paper;
+
+import net.kyori.adventure.translation.Translatable;
+import net.kyori.adventure.util.Index;
+import org.bukkit.inventory.MainHand;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+import org.bukkit.inventory.MainHand;
+
+@NullMarked
+public final class ClientOption<T> {
+
+ public static final ClientOption<SkinParts> SKIN_PARTS = new ClientOption<>(SkinParts.class);
@ -31,12 +31,13 @@ index 0000000000000000000000000000000000000000..ed08f823e0620289392f7fc2ff0ac721
+
+ private final Class<T> type;
+
+ private ClientOption(final Class<T> type) {
+ private ClientOption(@NotNull Class<T> type) {
+ this.type = type;
+ }
+
+ @NotNull
+ public Class<T> getType() {
+ return this.type;
+ return type;
+ }
+
+ public enum ChatVisibility implements Translatable {
@ -45,15 +46,15 @@ index 0000000000000000000000000000000000000000..ed08f823e0620289392f7fc2ff0ac721
+ HIDDEN("hidden"),
+ UNKNOWN("unknown");
+
+ public static final Index<String, ChatVisibility> NAMES = Index.create(ChatVisibility.class, chatVisibility -> chatVisibility.name);
+ public static Index<String, ChatVisibility> NAMES = Index.create(ChatVisibility.class, chatVisibility -> chatVisibility.name);
+ private final String name;
+
+ ChatVisibility(final String name) {
+ ChatVisibility(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String translationKey() {
+ public @NotNull String translationKey() {
+ if (this == UNKNOWN) {
+ throw new UnsupportedOperationException(this.name + " doesn't have a translation key");
+ }
@ -89,27 +90,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..6cf6aa876278d0d3e75148608951fc5865ad5aee
index 0000000000000000000000000000000000000000..1757055d821d9ec7c728aa6c1b52fa6aea591ae5
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerClientOptionsChangeEvent.java
@@ -0,0 +1,130 @@
@@ -0,0 +1,136 @@
+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.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+/**
+ * Called when the player changes their client settings
+ */
+@NullMarked
+public class PlayerClientOptionsChangeEvent extends PlayerEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
@ -124,7 +125,7 @@ index 0000000000000000000000000000000000000000..6cf6aa876278d0d3e75148608951fc58
+ private final boolean textFilteringEnabled;
+
+ @Deprecated
+ public PlayerClientOptionsChangeEvent(final Player player, final String locale, final int viewDistance, final ChatVisibility chatVisibility, final boolean chatColors, final SkinParts skinParts, final MainHand mainHand) {
+ public PlayerClientOptionsChangeEvent(@NotNull Player player, @NotNull String locale, int viewDistance, @NotNull ChatVisibility chatVisibility, boolean chatColors, @NotNull SkinParts skinParts, @NotNull MainHand mainHand) {
+ super(player);
+ this.locale = locale;
+ this.viewDistance = viewDistance;
@ -137,7 +138,7 @@ index 0000000000000000000000000000000000000000..6cf6aa876278d0d3e75148608951fc58
+ }
+
+ @ApiStatus.Internal
+ public PlayerClientOptionsChangeEvent(final Player player, final Map<ClientOption<?>, ?> options) {
+ public PlayerClientOptionsChangeEvent(@NotNull Player player, @NotNull Map<ClientOption<?>, ?> options) {
+ super(player);
+
+ this.locale = (String) options.get(ClientOption.LOCALE);
@ -150,6 +151,7 @@ index 0000000000000000000000000000000000000000..6cf6aa876278d0d3e75148608951fc58
+ this.textFilteringEnabled = (boolean) options.get(ClientOption.TEXT_FILTERING_ENABLED);
+ }
+
+ @NotNull
+ public String getLocale() {
+ return this.locale;
+ }
@ -166,6 +168,7 @@ index 0000000000000000000000000000000000000000..6cf6aa876278d0d3e75148608951fc58
+ return this.viewDistance != this.player.getClientOption(ClientOption.VIEW_DISTANCE);
+ }
+
+ @NotNull
+ public ChatVisibility getChatVisibility() {
+ return this.chatVisibility;
+ }
@ -182,6 +185,7 @@ index 0000000000000000000000000000000000000000..6cf6aa876278d0d3e75148608951fc58
+ return this.chatColors != this.player.getClientOption(ClientOption.CHAT_COLORS_ENABLED);
+ }
+
+ @NotNull
+ public SkinParts getSkinParts() {
+ return this.skinparts;
+ }
@ -190,6 +194,7 @@ index 0000000000000000000000000000000000000000..6cf6aa876278d0d3e75148608951fc58
+ return this.skinparts.getRaw() != this.player.getClientOption(ClientOption.SKIN_PARTS).getRaw();
+ }
+
+ @NotNull
+ public MainHand getMainHand() {
+ return this.mainHand;
+ }
@ -215,10 +220,12 @@ index 0000000000000000000000000000000000000000..6cf6aa876278d0d3e75148608951fc58
+ }
+
+ @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..2cd5c9c344cacbabe64dae8ec87babb506b5fb09
index 0000000000000000000000000000000000000000..5ceaff1a499d08575ddcdcbead8e2cef6cfbea47
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerAttackEntityCooldownResetEvent.java
@@ -0,0 +1,77 @@
@ -18,23 +18,22 @@ index 0000000000000000000000000000000000000000..2cd5c9c344cacbabe64dae8ec87babb5
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private final Entity attackedEntity;
+ @NotNull private final Entity attackedEntity;
+ private final float cooledAttackStrength;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerAttackEntityCooldownResetEvent(final Player player, final Entity attackedEntity, final float cooledAttackStrength) {
+ public PlayerAttackEntityCooldownResetEvent(@NotNull Player player, @NotNull Entity attackedEntity, float cooledAttackStrength) {
+ super(player);
+ this.attackedEntity = attackedEntity;
+ this.cooledAttackStrength = cooledAttackStrength;
@ -54,6 +53,7 @@ index 0000000000000000000000000000000000000000..2cd5c9c344cacbabe64dae8ec87babb5
+ *
+ * @return the entity attacked by the player
+ */
+ @NotNull
+ public Entity getAttackedEntity() {
+ return this.attackedEntity;
+ }
@ -74,16 +74,16 @@ index 0000000000000000000000000000000000000000..2cd5c9c344cacbabe64dae8ec87babb5
+ * Cancelling this event will prevent the target player from having their cooldown reset from attacking this entity
+ */
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ public @NotNull HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static HandlerList getHandlerList() {
+ public static @NotNull HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}

View file

@ -6,20 +6,21 @@ 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..88f64a84c6b81246a4936e37c9f0410eefc847fd
index 0000000000000000000000000000000000000000..c57c5416c88e2070a082403ab0dda9d7f08d2a57
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java
@@ -0,0 +1,63 @@
@@ -0,0 +1,66 @@
+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> {
+
+ /**
@ -35,7 +36,7 @@ index 0000000000000000000000000000000000000000..88f64a84c6b81246a4936e37c9f0410e
+ * @return if this goal should stay active
+ */
+ default boolean shouldStayActive() {
+ return this.shouldActivate();
+ return shouldActivate();
+ }
+
+ /**
@ -62,79 +63,86 @@ index 0000000000000000000000000000000000000000..88f64a84c6b81246a4936e37c9f0410e
+ *
+ * @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..fb626065c642a3f43075f2ae751419e23431763c
index 0000000000000000000000000000000000000000..9cd98c6fcfa3eb439d9013ef76ef4661175a0e5a
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java
@@ -0,0 +1,59 @@
@@ -0,0 +1,64 @@
+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
+ */
+@NullMarked
+public final class GoalKey<T extends Mob> {
+public class GoalKey<T extends Mob> {
+
+ private final Class<T> entityClass;
+ private final NamespacedKey namespacedKey;
+
+ private GoalKey(Class<T> entityClass, NamespacedKey namespacedKey) {
+ private GoalKey(@NotNull Class<T> entityClass, @NotNull NamespacedKey namespacedKey) {
+ this.entityClass = entityClass;
+ this.namespacedKey = namespacedKey;
+ }
+
+ @NotNull
+ public Class<T> getEntityClass() {
+ return this.entityClass;
+ return entityClass;
+ }
+
+ @NotNull
+ public NamespacedKey getNamespacedKey() {
+ return this.namespacedKey;
+ return namespacedKey;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || this.getClass() != o.getClass()) return false;
+ if (o == null || getClass() != o.getClass()) return false;
+ GoalKey<?> goalKey = (GoalKey<?>) o;
+ return Objects.equal(this.entityClass, goalKey.entityClass) &&
+ Objects.equal(this.namespacedKey, goalKey.namespacedKey);
+ return Objects.equal(entityClass, goalKey.entityClass) &&
+ Objects.equal(namespacedKey, goalKey.namespacedKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.entityClass, this.namespacedKey);
+ return Objects.hashCode(entityClass, namespacedKey);
+ }
+
+ @Override
+ public String toString() {
+ return new StringJoiner(", ", GoalKey.class.getSimpleName() + "[", "]")
+ .add("entityClass=" + this.entityClass)
+ .add("namespacedKey=" + this.namespacedKey)
+ .add("entityClass=" + entityClass)
+ .add("namespacedKey=" + namespacedKey)
+ .toString();
+ }
+
+ public static <A extends Mob> GoalKey<A> of(Class<A> entityClass, NamespacedKey namespacedKey) {
+ @NotNull
+ public static <A extends Mob> GoalKey<A> of(@NotNull Class<A> entityClass, @NotNull NamespacedKey namespacedKey) {
+ return new GoalKey<>(entityClass, namespacedKey);
+ }
+}
@ -163,51 +171,59 @@ 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..0203e7efbb8c729ed378c53c2630a523b697314f
index 0000000000000000000000000000000000000000..e21f7574763dd4f13794f91bbef192ef66a8f5e9
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java
@@ -0,0 +1,42 @@
@@ -0,0 +1,50 @@
+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(T mob, int priority, Goal<T> goal);
+ <T extends Mob> void addGoal(@NotNull T mob, int priority, @NotNull Goal<T> goal);
+
+ <T extends Mob> void removeGoal(T mob, Goal<T> goal);
+ <T extends Mob> void removeGoal(@NotNull T mob, @NotNull Goal<T> goal);
+
+ <T extends Mob> void removeAllGoals(T mob);
+ <T extends Mob> void removeAllGoals(@NotNull T mob);
+
+ <T extends Mob> void removeAllGoals(T mob, GoalType type);
+ <T extends Mob> void removeAllGoals(@NotNull T mob, @NotNull GoalType type);
+
+ <T extends Mob> void removeGoal(T mob, GoalKey<T> key);
+ <T extends Mob> void removeGoal(@NotNull T mob, @NotNull GoalKey<T> key);
+
+ <T extends Mob> boolean hasGoal(T mob, GoalKey<T> key);
+ <T extends Mob> boolean hasGoal(@NotNull T mob, @NotNull GoalKey<T> key);
+
+ <T extends Mob> @Nullable Goal<T> getGoal(T mob, GoalKey<T> key);
+ @Nullable
+ <T extends Mob> Goal<T> getGoal(@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>> getGoals(@NotNull T mob, @NotNull GoalKey<T> key);
+
+ <T extends Mob> Collection<Goal<T>> getAllGoals(T mob);
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getAllGoals(@NotNull T mob);
+
+ <T extends Mob> Collection<Goal<T>> getAllGoals(T mob, GoalType type);
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getAllGoals(@NotNull T mob, @NotNull GoalType type);
+
+ <T extends Mob> Collection<Goal<T>> getAllGoalsWithout(T mob, GoalType type);
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getAllGoalsWithout(@NotNull T mob, @NotNull GoalType type);
+
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob);
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(@NotNull T mob);
+
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob, GoalType type);
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(@NotNull T mob, @NotNull GoalType type);
+
+ <T extends Mob> Collection<Goal<T>> getRunningGoalsWithout(T mob, GoalType type);
+ @NotNull
+ <T extends Mob> Collection<Goal<T>> getRunningGoalsWithout(@NotNull T mob, @NotNull 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,30 +6,31 @@ 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..cbbf70507c2df922e75b686c36500f6f85f92db6
index 0000000000000000000000000000000000000000..0a69e21b0b3001c9cc50951b4b8bd593f6fa74be
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/villager/Reputation.java
@@ -0,0 +1,56 @@
@@ -0,0 +1,57 @@
+package com.destroystokyo.paper.entity.villager;
+
+import com.google.common.base.Preconditions;
+
+import java.util.EnumMap;
+import java.util.Map;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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(final Map<ReputationType, Integer> reputation) {
+ public Reputation(@NotNull Map<ReputationType, Integer> reputation) {
+ Preconditions.checkNotNull(reputation, "reputation cannot be null");
+ this.reputation = reputation;
+ }
@ -40,7 +41,7 @@ index 0000000000000000000000000000000000000000..cbbf70507c2df922e75b686c36500f6f
+ * @param type The {@link ReputationType type} of reputation to get.
+ * @return The value of the {@link ReputationType type}.
+ */
+ public int getReputation(final ReputationType type) {
+ public int getReputation(@NotNull ReputationType type) {
+ Preconditions.checkNotNull(type, "the reputation type cannot be null");
+ return this.reputation.getOrDefault(type, 0);
+ }
@ -51,7 +52,7 @@ index 0000000000000000000000000000000000000000..cbbf70507c2df922e75b686c36500f6f
+ * @param type The {@link ReputationType type} of reputation to set.
+ * @param value The value of the {@link ReputationType type}.
+ */
+ public void setReputation(final ReputationType type, final int value) {
+ public void setReputation(@NotNull ReputationType type, int value) {
+ Preconditions.checkNotNull(type, "the reputation type cannot be null");
+ this.reputation.put(type, value);
+ }
@ -62,7 +63,7 @@ index 0000000000000000000000000000000000000000..cbbf70507c2df922e75b686c36500f6f
+ * @param type The {@link ReputationType type} to check
+ * @return If there is a value for this {@link ReputationType type} set.
+ */
+ public boolean hasReputationSet(final ReputationType type) {
+ public boolean hasReputationSet(@NotNull 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..a7becccb2cf3b72744fcac4efa52d7c61e607765
index 0000000000000000000000000000000000000000..c38ac6d0e0ac4ecbdc73d2bedd7731ff34c9d192
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerRecipeBookClickEvent.java
@@ -0,0 +1,87 @@
@@ -0,0 +1,89 @@
+package com.destroystokyo.paper.event.player;
+
+import org.bukkit.NamespacedKey;
@ -18,23 +18,22 @@ index 0000000000000000000000000000000000000000..a7becccb2cf3b72744fcac4efa52d7c6
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * 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();
+
+ private NamespacedKey recipe;
+ @NotNull private NamespacedKey recipe;
+ private boolean makeAll;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public PlayerRecipeBookClickEvent(final Player player, final NamespacedKey recipe, final boolean makeAll) {
+ public PlayerRecipeBookClickEvent(@NotNull Player player, @NotNull NamespacedKey recipe, boolean makeAll) {
+ super(player);
+ this.recipe = recipe;
+ this.makeAll = makeAll;
@ -45,6 +44,7 @@ index 0000000000000000000000000000000000000000..a7becccb2cf3b72744fcac4efa52d7c6
+ *
+ * @return The namespaced key of the recipe
+ */
+ @NotNull
+ public NamespacedKey getRecipe() {
+ return this.recipe;
+ }
@ -54,7 +54,7 @@ index 0000000000000000000000000000000000000000..a7becccb2cf3b72744fcac4efa52d7c6
+ *
+ * @param recipe The key of the recipe that should be requested
+ */
+ public void setRecipe(final NamespacedKey recipe) {
+ public void setRecipe(@NotNull NamespacedKey recipe) {
+ this.recipe = recipe;
+ }
+
@ -74,7 +74,7 @@ index 0000000000000000000000000000000000000000..a7becccb2cf3b72744fcac4efa52d7c6
+ *
+ * @param makeAll {@code true} if the request should attempt to make the maximum amount of results
+ */
+ public void setMakeAll(final boolean makeAll) {
+ public void setMakeAll(boolean makeAll) {
+ this.makeAll = makeAll;
+ }
+
@ -84,15 +84,17 @@ index 0000000000000000000000000000000000000000..a7becccb2cf3b72744fcac4efa52d7c6
+ }
+
+ @Override
+ public void setCancelled(final boolean cancel) {
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }

View file

@ -48,29 +48,28 @@ 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..8ca7858613bb78ee1f9453b55fc38e00414fefb5
index 0000000000000000000000000000000000000000..c305c606bef93866993095cec5f50e191c5a382a
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareResultEvent.java
@@ -0,0 +1,42 @@
@@ -0,0 +1,40 @@
+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.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.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(final InventoryView inventory, final @Nullable ItemStack result) {
+ public PrepareResultEvent(@NotNull InventoryView inventory, @Nullable ItemStack result) {
+ super(inventory, result);
+ }
+
@ -79,8 +78,8 @@ index 0000000000000000000000000000000000000000..8ca7858613bb78ee1f9453b55fc38e00
+ *
+ * @return result item
+ */
+ @Override
+ public @Nullable ItemStack getResult() {
+ @Nullable
+ public ItemStack getResult() {
+ return super.getResult();
+ }
+
@ -89,8 +88,7 @@ index 0000000000000000000000000000000000000000..8ca7858613bb78ee1f9453b55fc38e00
+ *
+ * @param result result item
+ */
+ @Override
+ public void setResult(final @Nullable ItemStack result) {
+ public void setResult(@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..0b24e1a92bba4fed0ca2d4336a3b8351a800f93a
index 0000000000000000000000000000000000000000..df05153397b42930cd53d37b30824c7e5f008f7e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/world/MoonPhase.java
@@ -0,0 +1,35 @@
@@ -0,0 +1,36 @@
+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,19 +29,20 @@ index 0000000000000000000000000000000000000000..0b24e1a92bba4fed0ca2d4336a3b8351
+
+ private final long day;
+
+ MoonPhase(final long day) {
+ MoonPhase(long day) {
+ this.day = day;
+ }
+
+ private static final Map<Long, MoonPhase> BY_DAY = new HashMap<>();
+
+ static {
+ for (final MoonPhase phase : values()) {
+ for (MoonPhase phase : values()) {
+ BY_DAY.put(phase.day, phase);
+ }
+ }
+
+ public static MoonPhase getPhase(final long day) {
+ @NotNull
+ public static MoonPhase getPhase(long day) {
+ return BY_DAY.get(day % 8L);
+ }
+}

View file

@ -5,10 +5,10 @@ Subject: [PATCH] Add playPickupItemAnimation to LivingEntity
diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java
index c2352d75e02f7be27fcf9ea69df1bd104a2449bd..88d6a5aaf2a686186fab4916480a04f6503d887c 100644
index fdb985763d0a7b0a31ad938616e11ef244f63062..d87c49550e697ad545742baed40068623e83bf0b 100644
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -1181,4 +1181,29 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
@@ -1171,4 +1171,29 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource
*/
void setJumping(boolean jumping);
// Paper end - entity jump API

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