diff --git a/.gitignore b/.gitignore index 74c3ad3..a67b6d1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,10 @@ build /run -/fork-server/build.gradle.kts -/fork-server/src/minecraft +/parchment-server/build.gradle.kts +/parchment-server/src/minecraft /paper-server -/fork-api/build.gradle.kts +/parchment-api/build.gradle.kts /paper-api /paper-api-generator diff --git a/README.md b/README.md new file mode 100644 index 0000000..f94f633 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +Things I've found while just trying to get this to work: + +- If you've made an update to either of the build.gradle.kts files in api or server, run `./gradlew rebuildPaperSingleFilePatches` after adding to git (no commit) +- To create a file patch: + - Make the changes you need and have no other staged changes + - cd paper-api or paper-server + - git add . + - git commit --ammend + - This ammends it to the specific 'File Patch Commit' + - ./gradlew rebuildPaperFilePatches \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index d97bcdf..71efa04 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,23 +12,23 @@ paperweight { patchFile { path = "paper-server/build.gradle.kts" - outputFile = file("fork-server/build.gradle.kts") - patchFile = file("fork-server/build.gradle.kts.patch") + outputFile = file("parchment-server/build.gradle.kts") + patchFile = file("parchment-server/build.gradle.kts.patch") } patchFile { path = "paper-api/build.gradle.kts" - outputFile = file("fork-api/build.gradle.kts") - patchFile = file("fork-api/build.gradle.kts.patch") + outputFile = file("parchment-api/build.gradle.kts") + patchFile = file("parchment-api/build.gradle.kts.patch") } patchDir("paperApi") { upstreamPath = "paper-api" excludes = setOf("build.gradle.kts") - patchesDir = file("fork-api/paper-patches") + patchesDir = file("parchment-api/paper-patches") outputDir = file("paper-api") } patchDir("paperApiGenerator") { upstreamPath = "paper-api-generator" - patchesDir = file("fork-api-generator/paper-patches") + patchesDir = file("parchment-api-generator/paper-patches") outputDir = file("paper-api-generator") } } @@ -49,6 +49,7 @@ subprojects { repositories { mavenCentral() maven(paperMavenPublicUrl) + maven("https://sonatype.projecteden.gg/repository/maven-public/") } dependencies { @@ -80,12 +81,11 @@ subprojects { extensions.configure { repositories { - /* - maven("https://repo.papermc.io/repository/maven-snapshots/") { - name = "paperSnapshots" + maven { + name = "edenSnapshots" + url = uri("https://sonatype.projecteden.gg/repository/maven-snapshots/") credentials(PasswordCredentials::class) } - */ } } } diff --git a/gradle.properties b/gradle.properties index 85e11f0..a836af1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -group=fork.test +group=gg.projecteden.parchment version=1.21.4-R0.1-SNAPSHOT mcVersion=1.21.4 paperRef=b03d39b5ce6b5046ce6854ddba74e8ae3641c230 @@ -7,3 +7,5 @@ org.gradle.configuration-cache=true org.gradle.caching=true org.gradle.parallel=true org.gradle.vfs.watch=false + +edenVersion = 2.3.0-SNAPSHOT \ No newline at end of file diff --git a/parchment-api/build.gradle.kts.patch b/parchment-api/build.gradle.kts.patch index 4fe51fc..5812932 100644 --- a/parchment-api/build.gradle.kts.patch +++ b/parchment-api/build.gradle.kts.patch @@ -1,5 +1,22 @@ --- a/paper-api/build.gradle.kts +++ b/paper-api/build.gradle.kts +@@ -15,6 +_,8 @@ + val slf4jVersion = "2.0.9" + val log4jVersion = "2.17.1" + ++val edenVersion: String by project // Parchment ++ + val apiAndDocs: Configuration by configurations.creating { + attributes { + attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION)) +@@ -39,6 +_,7 @@ + } + + dependencies { ++ api("gg.projecteden:eden-interfaces:$edenVersion") // Parchment + + // api dependencies are listed transitively to API consumers + api("com.google.guava:guava:33.3.1-jre") @@ -103,6 +_,18 @@ main { java { diff --git a/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java.patch new file mode 100644 index 0000000..fd117da --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java +@@ -13,7 +_,7 @@ + * Called when a beacon effect is being applied to a player. + */ + @NullMarked +-public class BeaconEffectEvent extends BlockEvent implements Cancellable { ++public class BeaconEffectEvent extends BlockEvent implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + + private static final HandlerList HANDLER_LIST = new HandlerList(); + diff --git a/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java.patch new file mode 100644 index 0000000..04c653f --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java +@@ -38,7 +_,7 @@ + * at the Enderman, according to Vanilla rules. + */ + @NullMarked +-public class EndermanAttackPlayerEvent extends EntityEvent implements Cancellable { ++public class EndermanAttackPlayerEvent extends EntityEvent implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + + private static final HandlerList HANDLER_LIST = new HandlerList(); + diff --git a/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java.patch new file mode 100644 index 0000000..826c04d --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java +@@ -12,7 +_,7 @@ + * Fired when a Turtle lays eggs + */ + @NullMarked +-public class TurtleLayEggEvent extends EntityEvent implements Cancellable { ++public class TurtleLayEggEvent extends EntityEvent implements Cancellable, gg.projecteden.parchment.HasLocation { // Parchment + + private static final HandlerList HANDLER_LIST = new HandlerList(); + diff --git a/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java.patch new file mode 100644 index 0000000..e7df86c --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java +@@ -12,7 +_,7 @@ + * Fired when a Turtle starts digging to lay eggs + */ + @NullMarked +-public class TurtleStartDiggingEvent extends EntityEvent implements Cancellable { ++public class TurtleStartDiggingEvent extends EntityEvent implements Cancellable, gg.projecteden.parchment.HasLocation { // Parchment + + private static final HandlerList HANDLER_LIST = new HandlerList(); + diff --git a/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java.patch new file mode 100644 index 0000000..1cc4104 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java +@@ -21,7 +_,7 @@ + *

WARNING: TAMPERING WITH THIS EVENT CAN BE DANGEROUS

+ */ + @NullMarked +-public class PlayerHandshakeEvent extends Event implements Cancellable { ++public class PlayerHandshakeEvent extends Event implements Cancellable, gg.projecteden.api.interfaces.OptionalUniqueId { // Parchment + + private static final HandlerList HANDLER_LIST = new HandlerList(); + diff --git a/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java.patch new file mode 100644 index 0000000..72dc747 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java.patch @@ -0,0 +1,22 @@ +--- a/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java +@@ -22,7 +_,7 @@ + * {@link Event#isAsynchronous()} + */ + @NullMarked +-public class PreLookupProfileEvent extends Event { ++public class PreLookupProfileEvent extends Event implements gg.projecteden.api.interfaces.OptionalUniqueId { // Parchment + + private static final HandlerList HANDLER_LIST = new HandlerList(); + +@@ -52,6 +_,10 @@ + * @return The UUID of the profile if it has already been provided by a plugin + */ + public @Nullable UUID getUUID() { ++ return this.uuid; ++ } ++ ++ public UUID getUniqueId() { + return this.uuid; + } + diff --git a/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java.patch new file mode 100644 index 0000000..92c9f97 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java +@@ -53,7 +_,7 @@ + * Only 1 process will be allowed to provide completions, the Async Event, or the standard process. + */ + @NullMarked +-public class AsyncTabCompleteEvent extends Event implements Cancellable { ++public class AsyncTabCompleteEvent extends Event implements Cancellable, gg.projecteden.parchment.OptionalLocation { // Parchment + + private static final HandlerList HANDLER_LIST = new HandlerList(); + diff --git a/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java.patch b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java.patch new file mode 100644 index 0000000..61269fc --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java +@@ -8,7 +_,7 @@ + /** + * Thrown when an incoming plugin message channel throws an exception + */ +-public class ServerPluginMessageException extends ServerPluginException { ++public class ServerPluginMessageException extends ServerPluginException implements gg.projecteden.parchment.HasPlayer { // Parchment + + private final Player player; + private final String channel; diff --git a/parchment-api/paper-patches/files/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java.patch new file mode 100644 index 0000000..6f8b281 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java ++++ b/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java +@@ -16,7 +_,7 @@ + * Not intended for modifying server side state. + */ + @NullMarked +-public class PlayerChunkLoadEvent extends ChunkEvent { ++public class PlayerChunkLoadEvent extends ChunkEvent implements gg.projecteden.parchment.HasPlayer { // Parchment + + private static final HandlerList HANDLER_LIST = new HandlerList(); + diff --git a/parchment-api/paper-patches/files/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java.patch new file mode 100644 index 0000000..919e881 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java ++++ b/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java +@@ -14,7 +_,7 @@ + * Not intended for modifying server side. + */ + @NullMarked +-public class PlayerChunkUnloadEvent extends ChunkEvent { ++public class PlayerChunkUnloadEvent extends ChunkEvent implements gg.projecteden.parchment.HasPlayer { // Parchment + + private static final HandlerList HANDLER_LIST = new HandlerList(); + diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/ChatColor.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/ChatColor.java.patch new file mode 100644 index 0000000..3da0a5c --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/ChatColor.java.patch @@ -0,0 +1,73 @@ +--- a/src/main/java/org/bukkit/ChatColor.java ++++ b/src/main/java/org/bukkit/ChatColor.java +@@ -13,7 +_,7 @@ + * @deprecated ChatColor has been deprecated in favor of Adventure API. See {@link net.kyori.adventure.text.format.NamedTextColor} for the adventure equivalent of pre-defined text colors + */ + @Deprecated // Paper +-public enum ChatColor { ++public enum ChatColor implements net.kyori.adventure.text.format.StyleBuilderApplicable, net.kyori.adventure.text.format.TextFormat { // Parchment + /** + * Represents black + */ +@@ -183,6 +_,13 @@ + public net.md_5.bungee.api.ChatColor asBungee() { + return net.md_5.bungee.api.ChatColor.MAGIC; + } ++ ++ // Parchment start ++ @Override ++ public void styleApply(net.kyori.adventure.text.format.Style.@NotNull Builder style) { ++ style.apply(net.kyori.adventure.text.format.TextDecoration.OBFUSCATED); ++ } ++ // Parchment end + }, + /** + * Makes the text bold. +@@ -213,6 +_,13 @@ + public net.md_5.bungee.api.ChatColor asBungee() { + return net.md_5.bungee.api.ChatColor.UNDERLINE; + } ++ ++ // Parchment start ++ @Override ++ public void styleApply(net.kyori.adventure.text.format.Style.@NotNull Builder style) { ++ style.apply(net.kyori.adventure.text.format.TextDecoration.UNDERLINED); ++ } ++ // Parchment end + }, + /** + * Makes the text italic. +@@ -233,6 +_,16 @@ + public net.md_5.bungee.api.ChatColor asBungee() { + return net.md_5.bungee.api.ChatColor.RESET; + } ++ ++ // Parchment start ++ @Override ++ public void styleApply(net.kyori.adventure.text.format.Style.@NotNull Builder style) { ++ style.color(null); ++ for (net.kyori.adventure.text.format.TextDecoration decoration : net.kyori.adventure.text.format.TextDecoration.values()) { ++ style.decoration(decoration, net.kyori.adventure.text.format.TextDecoration.State.NOT_SET); ++ } ++ } ++ // Parchment end + }; + + /** +@@ -264,6 +_,16 @@ + public net.md_5.bungee.api.ChatColor asBungee() { + return net.md_5.bungee.api.ChatColor.RESET; + }; ++ ++ // Parchment start ++ @Override ++ public void styleApply(net.kyori.adventure.text.format.Style.@NotNull Builder style) { ++ if (isColor()) ++ style.color(net.kyori.adventure.text.format.TextColor.color(asBungee().getColor().getRGB())); ++ else ++ style.decorate(net.kyori.adventure.text.format.TextDecoration.valueOf(name())); ++ } ++ // Parchment end + + /** + * Gets the char value associated with this color diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/Color.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/Color.java.patch new file mode 100644 index 0000000..364b160 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/Color.java.patch @@ -0,0 +1,25 @@ +--- a/src/main/java/org/bukkit/Color.java ++++ b/src/main/java/org/bukkit/Color.java +@@ -17,7 +_,7 @@ + * but subject to change. + */ + @SerializableAs("Color") +-public final class Color implements ConfigurationSerializable { ++public final class Color implements ConfigurationSerializable, net.kyori.adventure.text.format.TextColor { // Parchment + private static final int BIT_MASK = 0xff; + private static final int DEFAULT_ALPHA = 255; + +@@ -309,6 +_,13 @@ + public int asARGB() { + return getAlpha() << 24 | getRed() << 16 | getGreen() << 8 | getBlue(); + } ++ ++ // Parchment start ++ @Override ++ public int value() { ++ return asRGB(); ++ } ++ // Parchment end + + /** + * Gets the color as an BGR integer. diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/DyeColor.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/DyeColor.java.patch new file mode 100644 index 0000000..7f04e5e --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/DyeColor.java.patch @@ -0,0 +1,40 @@ +--- a/src/main/java/org/bukkit/DyeColor.java ++++ b/src/main/java/org/bukkit/DyeColor.java +@@ -8,7 +_,7 @@ + /** + * All supported color values for dyes and cloth + */ +-public enum DyeColor { ++public enum DyeColor implements net.kyori.adventure.util.RGBLike, net.kyori.adventure.text.format.StyleBuilderApplicable { // Parchment + + /** + * Represents white dye. +@@ -134,6 +_,28 @@ + public Color getFireworkColor() { + return firework; + } ++ ++ // Parchment start ++ @Override ++ public @org.jetbrains.annotations.Range(from = 0L, to = 255L) int red() { ++ return color.getRed(); ++ } ++ ++ @Override ++ public @org.jetbrains.annotations.Range(from = 0L, to = 255L) int green() { ++ return color.getGreen(); ++ } ++ ++ @Override ++ public @org.jetbrains.annotations.Range(from = 0L, to = 255L) int blue() { ++ return color.getBlue(); ++ } ++ ++ @Override ++ public void styleApply(net.kyori.adventure.text.format.Style.@org.jetbrains.annotations.NotNull Builder style) { ++ style.color(net.kyori.adventure.text.format.TextColor.color(color)); ++ } ++ // Parchment end + + /** + * Gets the DyeColor with the given wool data value. diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/Location.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/Location.java.patch new file mode 100644 index 0000000..72daf26 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/Location.java.patch @@ -0,0 +1,24 @@ +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -27,13 +_,20 @@ + * magnitude than 360 are valid, but may be normalized to any other equivalent + * representation by the implementation. + */ +-public class Location implements Cloneable, ConfigurationSerializable, io.papermc.paper.math.FinePosition { ++public class Location implements Cloneable, ConfigurationSerializable, io.papermc.paper.math.FinePosition, gg.projecteden.parchment.HasLocation { // Paper // Parchment + private Reference world; + private double x; + private double y; + private double z; + private float pitch; + private float yaw; ++ ++ // Parchment start ++ @Override ++ public @NotNull Location getLocation() { ++ return this; ++ } ++ // Parchment end + + /** + * Constructs a new Location with the given coordinates diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/OfflinePlayer.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/OfflinePlayer.java.patch new file mode 100644 index 0000000..26fd9e1 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/OfflinePlayer.java.patch @@ -0,0 +1,18 @@ +--- a/src/main/java/org/bukkit/OfflinePlayer.java ++++ b/src/main/java/org/bukkit/OfflinePlayer.java +@@ -19,7 +_,14 @@ + * player that is stored on the disk and can, thus, be retrieved without the + * player needing to be online. + */ +-public interface OfflinePlayer extends ServerOperator, AnimalTamer, ConfigurationSerializable, io.papermc.paper.persistence.PersistentDataViewHolder { // Paper - Add Offline PDC API ++public interface OfflinePlayer extends ServerOperator, AnimalTamer, ConfigurationSerializable, io.papermc.paper.persistence.PersistentDataViewHolder, gg.projecteden.parchment.HasOfflinePlayer, gg.projecteden.parchment.OptionalPlayer { // Parchment ++ ++ // Parchment start ++ @Override ++ default @org.jetbrains.annotations.NotNull OfflinePlayer getOfflinePlayer() { ++ return this; ++ } ++ // Parchment end + + /** + * Checks if this player is currently online diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/Raid.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/Raid.java.patch new file mode 100644 index 0000000..5da6d9f --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/Raid.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/Raid.java ++++ b/src/main/java/org/bukkit/Raid.java +@@ -9,7 +_,7 @@ + /** + * Represents a raid event. + */ +-public interface Raid extends org.bukkit.persistence.PersistentDataHolder { // Paper ++public interface Raid extends org.bukkit.persistence.PersistentDataHolder, gg.projecteden.parchment.HasLocation { // Paper // Parchment + + /** + * Get whether this raid started. diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/Vibration.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/Vibration.java.patch new file mode 100644 index 0000000..cb106c4 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/Vibration.java.patch @@ -0,0 +1,12 @@ +--- a/src/main/java/org/bukkit/Vibration.java ++++ b/src/main/java/org/bukkit/Vibration.java +@@ -74,7 +_,8 @@ + } + } + +- public static class BlockDestination implements Destination { ++ public static class BlockDestination implements Destination, gg.projecteden.parchment.HasLocation { // Parchment ++ + + private final Location block; + diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/World.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/World.java.patch new file mode 100644 index 0000000..b982c26 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/World.java.patch @@ -0,0 +1,39 @@ +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -52,6 +_,36 @@ + */ + public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, Keyed, net.kyori.adventure.audience.ForwardingAudience { // Paper + ++ // Parchment start ++ /** ++ * Returns the item that will result from smelting the input item, if applicable. ++ * ++ * @param toSmelt the item to simulate smelting ++ * @return the resulting item, or null ++ */ ++ @Nullable ++ default ItemStack smeltItem(@NotNull ItemStack toSmelt) { ++ return smeltItem(toSmelt, gg.projecteden.parchment.inventory.RecipeType.SMELTING); ++ } ++ ++ /** ++ * Returns the item that will result from smelting the input item, if applicable. ++ *

++ * Applicable values for {@code recipeType} are ++ * {@link gg.projecteden.parchment.inventory.RecipeType#SMELTING SMELTING}, ++ * {@link gg.projecteden.parchment.inventory.RecipeType#BLASTING BLASTING}, ++ * {@link gg.projecteden.parchment.inventory.RecipeType#SMOKING SMOKING}, ++ * and {@link gg.projecteden.parchment.inventory.RecipeType#CAMPFIRE_COOKING CAMPFIRE_COOKING}. ++ * An {@link IllegalArgumentException} will be thrown if another value is supplied. ++ * ++ * @param toSmelt the item to simulate smelting ++ * @param recipeType type of furnace to simulate smelting ++ * @return the resulting item, or null ++ */ ++ @Nullable ++ ItemStack smeltItem(@NotNull ItemStack toSmelt, gg.projecteden.parchment.inventory.@NotNull RecipeType recipeType); ++ // Parchment end ++ + // Paper start - void damage configuration + /** + * Checks if void damage is enabled on this world. diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/attribute/AttributeModifier.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/attribute/AttributeModifier.java.patch new file mode 100644 index 0000000..4a5141e --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/attribute/AttributeModifier.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/attribute/AttributeModifier.java ++++ b/src/main/java/org/bukkit/attribute/AttributeModifier.java +@@ -20,7 +_,7 @@ + /** + * Concrete implementation of an attribute modifier. + */ +-public class AttributeModifier implements ConfigurationSerializable, Keyed { ++public class AttributeModifier implements ConfigurationSerializable, Keyed, gg.projecteden.api.interfaces.HasUniqueId { // Parchment + + private static final Pattern UUID_PATTERN = Pattern.compile("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"); + private final NamespacedKey key; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/block/Block.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/block/Block.java.patch new file mode 100644 index 0000000..9b5ac65 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/block/Block.java.patch @@ -0,0 +1,32 @@ +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -32,7 +_,7 @@ + * (i.e. lighting and power) may not be able to be safely accessed during world + * generation when used in cases like BlockPhysicsEvent!!!! + */ +-public interface Block extends Metadatable, Translatable, net.kyori.adventure.translation.Translatable { // Paper - translatable ++public interface Block extends Metadatable, Translatable, net.kyori.adventure.translation.Translatable, gg.projecteden.parchment.HasLocation { // Paper - translatable // Parchment + + /** + * Gets the metadata for this block +@@ -593,6 +_,20 @@ + * @return true if the block was destroyed + */ + boolean breakNaturally(@NotNull ItemStack tool, boolean triggerEffect, boolean dropExperience); ++ ++ // Parchment Start ++ /** ++ * Breaks the block and spawns item drops as if a player had broken it ++ * with a specific tool ++ * ++ * @param player The player to break the block as ++ * @param tool The tool or item in hand used for digging ++ * @param triggerEffect Play the block break particle effect and sound ++ * @param dropExperience drop exp if the block normally does so ++ * @return true if the block was destroyed ++ */ ++ boolean breakNaturally(Player player, @NotNull ItemStack tool, boolean triggerEffect, boolean dropExperience); ++ // Parchment end + + /** + * Causes the block to be ticked, this is different from {@link Block#randomTick()}, diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/block/BlockState.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/block/BlockState.java.patch new file mode 100644 index 0000000..074e2a0 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/block/BlockState.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/block/BlockState.java ++++ b/src/main/java/org/bukkit/block/BlockState.java +@@ -21,7 +_,7 @@ + * change the state of the block and you will not know, or they may change the + * block to another type entirely, causing your BlockState to become invalid. + */ +-public interface BlockState extends Metadatable { ++public interface BlockState extends Metadatable, gg.projecteden.parchment.HasLocation { // Parchment + + /** + * Gets the block represented by this block state. diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/block/DoubleChest.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/block/DoubleChest.java.patch new file mode 100644 index 0000000..cfba356 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/block/DoubleChest.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/block/DoubleChest.java ++++ b/src/main/java/org/bukkit/block/DoubleChest.java +@@ -11,7 +_,7 @@ + /** + * Represents a double chest. + */ +-public class DoubleChest implements InventoryHolder { ++public class DoubleChest implements InventoryHolder, gg.projecteden.parchment.HasLocation { // Parchment + private DoubleChestInventory inventory; + + public DoubleChest(@NotNull DoubleChestInventory chest) { diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/AnimalTamer.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/AnimalTamer.java.patch new file mode 100644 index 0000000..72aa084 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/AnimalTamer.java.patch @@ -0,0 +1,12 @@ +--- a/src/main/java/org/bukkit/entity/AnimalTamer.java ++++ b/src/main/java/org/bukkit/entity/AnimalTamer.java +@@ -4,7 +_,8 @@ + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + +-public interface AnimalTamer { ++public interface AnimalTamer extends gg.projecteden.api.interfaces.HasUniqueId { // Parchment ++ + + /** + * This is the name of the specified AnimalTamer. diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch new file mode 100644 index 0000000..13039e7 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch @@ -0,0 +1,19 @@ +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -33,7 +_,7 @@ + * Not all methods are guaranteed to work/may have side effects when + * {@link #isInWorld()} is false. + */ +-public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder, net.kyori.adventure.text.event.HoverEventSource, net.kyori.adventure.sound.Sound.Emitter { // Paper ++public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder, net.kyori.adventure.text.event.HoverEventSource, net.kyori.adventure.sound.Sound.Emitter, gg.projecteden.api.interfaces.HasUniqueId, gg.projecteden.parchment.HasLocation { // Paper // Parchment + + /** + * Gets the entity's current position +@@ -1196,4 +_,7 @@ + */ + void broadcastHurtAnimation(@NotNull java.util.Collection players); + // Paper end - broadcast hurt animation ++ ++ gg.projecteden.parchment.entity.EntityData getStoredEntityData(); ++ + } diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/EntityType.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/EntityType.java.patch new file mode 100644 index 0000000..2129a74 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/EntityType.java.patch @@ -0,0 +1,10 @@ +--- a/src/main/java/org/bukkit/entity/EntityType.java ++++ b/src/main/java/org/bukkit/entity/EntityType.java +@@ -341,6 +_,7 @@ + /** + * An unknown entity without an Entity Class + */ ++ NPC("npc", NPC.class, -1, true), + UNKNOWN(null, null, -1, false); + + private final String name; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/Hanging.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/Hanging.java.patch new file mode 100644 index 0000000..ff01045 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/Hanging.java.patch @@ -0,0 +1,25 @@ +--- a/src/main/java/org/bukkit/entity/Hanging.java ++++ b/src/main/java/org/bukkit/entity/Hanging.java +@@ -20,4 +_,22 @@ + * attach to in order to face the given direction. + */ + public boolean setFacingDirection(@NotNull BlockFace face, boolean force); ++ ++ // Parchment start ++ /** ++ * Determines whether the hanging entity is allowed to tick. ++ * Ticking is used to validate the hanging entity's placement. ++ * ++ * @return True if the entity is allowed to tick. ++ */ ++ default boolean canTick() { return true; } ++ ++ /** ++ * Sets whether the hanging entity is allowed to tick. ++ * Ticking is used to validate the hanging entity's placement. ++ * ++ * @param tick True if the entity is allowed to tick. ++ */ ++ default void setCanTick(boolean tick) { throw new UnsupportedOperationException(); } ++ // Parchment end + } diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/HumanEntity.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/HumanEntity.java.patch new file mode 100644 index 0000000..904e98e --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/HumanEntity.java.patch @@ -0,0 +1,18 @@ +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -23,7 +_,14 @@ + /** + * Represents a human entity, such as an NPC or a player + */ +-public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder { ++public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder, gg.projecteden.parchment.HasHumanEntity { // Parchment ++ ++ // Parchment start ++ @Override ++ default @NotNull HumanEntity getPlayer() { ++ return this; ++ } ++ // Parchment end + + // Paper start + @Override diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch new file mode 100644 index 0000000..84c7f6b --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch @@ -0,0 +1,85 @@ +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -59,7 +_,17 @@ + /** + * Represents a player, connected or not + */ +-public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified, net.kyori.adventure.bossbar.BossBarViewer, com.destroystokyo.paper.network.NetworkClient { // Paper ++public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified, net.kyori.adventure.bossbar.BossBarViewer, com.destroystokyo.paper.network.NetworkClient , gg.projecteden.parchment.HasPlayer { // Paper // Parchment ++ ++ // Parchment start ++ /** ++ * Returns this player object. ++ * ++ * @return this player ++ */ ++ @Override ++ @NotNull Player getPlayer(); ++ // Parchment end + + // Paper start + @Override +@@ -2128,6 +_,17 @@ + */ + public boolean canSee(@NotNull Entity entity); + ++ // Parchment start ++ /** ++ * Gets a view of the hidden entity UUIDs. ++ * ++ * @param plugin Plugin that has hidden entities ++ * @return a view of hidden entity UUIDs ++ */ ++ public java.util.@NotNull Set getHiddenEntities(@NotNull Plugin plugin); ++ // Parchment end ++ ++ + // Paper start + /** + * Returns whether the {@code other} player is listed for {@code this}. +@@ -3892,4 +_,45 @@ + */ + void sendEntityEffect(org.bukkit.@NotNull EntityEffect effect, @NotNull Entity target); + // Paper end - entity effect API ++ ++ /** ++ * Checks if the player will spawn phantoms at night ++ * Uses time since last rest statistic ++ * ++ * {@link #getTimeSinceLastRest()} ++ * ++ * @return if the player will spawn phantoms at night ++ */ ++ boolean isInsomniac(); ++ ++ /** ++ * Sets if the player bypasses phantom spawning if insomniac ++ * ++ * @param val ++ */ ++ void setBypassInsomnia(boolean val); ++ ++ /** ++ * Does the player bypass phantom spawning if insomniac ++ * ++ * @return if the player bypasses phantom spawning ++ */ ++ boolean doesBypassInsomnia(); ++ ++ /** ++ * Set the time since last rest stat for the player ++ * This modifies the phantom spawning timer ++ * ++ * @param ticks how long since last rest, greater than or equal to 1 ++ */ ++ void setTimeSinceLastRest(int ticks); ++ ++ /** ++ * Gets the time since the player last slept ++ * ++ * @return ticks since the player last slept ++ */ ++ int getTimeSinceLastRest(); ++// Parchment end ++ + } diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockBreakEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockBreakEvent.java.patch new file mode 100644 index 0000000..f32d2e9 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockBreakEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/block/BlockBreakEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockBreakEvent.java +@@ -26,7 +_,7 @@ + * If a Block Break event is cancelled, the block will not break and + * experience will not drop. + */ +-public class BlockBreakEvent extends BlockExpEvent implements Cancellable { ++public class BlockBreakEvent extends BlockExpEvent implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + private final Player player; + private boolean dropItems; + private boolean cancel; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java.patch new file mode 100644 index 0000000..ce83214 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java +@@ -19,7 +_,7 @@ + * #getMaterial()} instead. + * + */ +-public class BlockCanBuildEvent extends BlockEvent { ++public class BlockCanBuildEvent extends BlockEvent implements gg.projecteden.parchment.OptionalPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + protected boolean buildable; + diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockDamageEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockDamageEvent.java.patch new file mode 100644 index 0000000..1647f7a --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockDamageEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/block/BlockDamageEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockDamageEvent.java +@@ -13,7 +_,7 @@ + * If a Block Damage event is cancelled, the block will not be damaged. + * @see BlockDamageAbortEvent + */ +-public class BlockDamageEvent extends BlockEvent implements Cancellable { ++public class BlockDamageEvent extends BlockEvent implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + private final Player player; + private boolean instaBreak; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java.patch new file mode 100644 index 0000000..eb2516b --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java +@@ -28,7 +_,7 @@ + * AIR in most cases. Use #getBlockState() for more Information about the broken + * block. + */ +-public class BlockDropItemEvent extends BlockEvent implements Cancellable { ++public class BlockDropItemEvent extends BlockEvent implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + + private static final HandlerList handlers = new HandlerList(); + private final Player player; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockFertilizeEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockFertilizeEvent.java.patch new file mode 100644 index 0000000..11ecde5 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockFertilizeEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/block/BlockFertilizeEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockFertilizeEvent.java +@@ -15,7 +_,7 @@ + * block with bonemeal. Will be called after the applicable + * {@link StructureGrowEvent}. + */ +-public class BlockFertilizeEvent extends BlockEvent implements Cancellable { ++public class BlockFertilizeEvent extends BlockEvent implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java.patch new file mode 100644 index 0000000..27b8ae4 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java +@@ -14,7 +_,7 @@ + *

+ * If a Block Ignite event is cancelled, the block will not be ignited. + */ +-public class BlockIgniteEvent extends BlockEvent implements Cancellable { ++public class BlockIgniteEvent extends BlockEvent implements Cancellable, gg.projecteden.parchment.OptionalPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + private final IgniteCause cause; + private final Entity ignitingEntity; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java.patch new file mode 100644 index 0000000..80c4af9 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java +@@ -14,7 +_,7 @@ + *

+ * If a Block Place event is cancelled, the block will not be placed. + */ +-public class BlockPlaceEvent extends BlockEvent implements Cancellable { ++public class BlockPlaceEvent extends BlockEvent implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + protected boolean cancel; + protected boolean canBuild; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/SignChangeEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/SignChangeEvent.java.patch new file mode 100644 index 0000000..0c29565 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/block/SignChangeEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/block/SignChangeEvent.java ++++ b/src/main/java/org/bukkit/event/block/SignChangeEvent.java +@@ -13,7 +_,7 @@ + *

+ * If a Sign Change event is cancelled, the sign will not be changed. + */ +-public class SignChangeEvent extends BlockEvent implements Cancellable { ++public class SignChangeEvent extends BlockEvent implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + private boolean cancel = false; + private final Player player; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java.patch new file mode 100644 index 0000000..4450856 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java.patch @@ -0,0 +1,53 @@ +--- a/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java +@@ -20,6 +_,7 @@ + public class EntityDamageByBlockEvent extends EntityDamageEvent { + private final Block damager; + private final BlockState damagerState; ++ private final org.bukkit.Location location; // Parchment + + @Deprecated(since = "1.20.4", forRemoval = true) + public EntityDamageByBlockEvent(@Nullable final Block damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, final double damage) { +@@ -30,18 +_,39 @@ + super(damagee, cause, damageSource, damage); + this.damager = damager; + this.damagerState = damagerState; ++ this.location = damager != null ? damager.getLocation() : null; // Parchment + } + + @Deprecated(since = "1.20.4", forRemoval = true) + public EntityDamageByBlockEvent(@Nullable final Block damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { +- this(damager, (damager != null) ? damager.getState() : null, damagee, cause, (damager != null) ? DamageSource.builder(DamageType.GENERIC).withDamageLocation(damager.getLocation()).build() : DamageSource.builder(DamageType.GENERIC).build(), modifiers, modifierFunctions); ++ this(damager, (damager != null) ? damager.getState() : null, damagee, cause, (damager != null) ? DamageSource.builder(DamageType.GENERIC).withDamageLocation(damager.getLocation()).build() : DamageSource.builder(DamageType.GENERIC).build(), modifiers, modifierFunctions, null); + } + +- public EntityDamageByBlockEvent(@Nullable final Block damager, @Nullable final BlockState damagerState, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { ++ public EntityDamageByBlockEvent(@Nullable final Block damager, @Nullable final BlockState damagerState, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions, @Nullable final org.bukkit.Location damageLocation) { // Parchment + super(damagee, cause, damageSource, modifiers, modifierFunctions); + this.damager = damager; + this.damagerState = damagerState; +- } ++ // Parchment start ++ if (damageLocation != null) ++ this.location = damageLocation; ++ else if (damager != null) ++ this.location = damager.getLocation(); ++ else ++ this.location = null; ++ // Parchment end ++ } ++ ++ // Parchment - add Location ++ /** ++ * Gets the location of the damage source. ++ * ++ * @return Originating location of the damage source ++ */ ++ @Nullable ++ public org.bukkit.Location getLocation() { ++ return location; ++ } ++ // Parchment end + + /** + * Returns the block that damaged the player. diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityEnterLoveModeEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityEnterLoveModeEvent.java.patch new file mode 100644 index 0000000..d13a3b8 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityEnterLoveModeEvent.java.patch @@ -0,0 +1,37 @@ +--- a/src/main/java/org/bukkit/event/entity/EntityEnterLoveModeEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityEnterLoveModeEvent.java +@@ -13,7 +_,7 @@ + * This can be cancelled but the item will still be consumed that was used to + * make the entity enter into love mode. + */ +-public class EntityEnterLoveModeEvent extends EntityEvent implements Cancellable { ++public class EntityEnterLoveModeEvent extends EntityEvent implements Cancellable, gg.projecteden.parchment.OptionalHumanEntity { // Parchment + + private static final HandlerList handlers = new HandlerList(); + private boolean cancel; +@@ -44,9 +_,24 @@ + * null if there wasn't one. + */ + @Nullable +- public HumanEntity getHumanEntity() { ++ // Parchment start ++ @Deprecated ++ public final HumanEntity getHumanEntity() { ++ return getPlayer(); ++ } ++ ++ /** ++ * Gets the Human Entity that caused the animal to enter love mode. ++ * ++ * @return The Human entity that caused the animal to enter love mode, or ++ * null if there wasn't one. ++ */ ++ @Override ++ @Nullable ++ public HumanEntity getPlayer() { + return humanEntity; + } ++ // Parchment end + + /** + * Gets the amount of ticks that the animal will fall in love for. diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java.patch new file mode 100644 index 0000000..fb8b4a5 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java +@@ -14,7 +_,7 @@ + * event isn't called if the {@link org.bukkit.GameRule#MOB_GRIEFING} + * is disabled as no block interaction will occur. + */ +-public class EntityExplodeEvent extends EntityEvent implements Cancellable { ++public class EntityExplodeEvent extends EntityEvent implements Cancellable, gg.projecteden.parchment.HasLocation { // Parchment + private static final HandlerList handlers = new HandlerList(); + private boolean cancel; + private final Location location; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java.patch new file mode 100644 index 0000000..c39950e --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java +@@ -17,7 +_,7 @@ + * Note that this event is currently only fired for four specific placements: + * armor stands, boats, minecarts, and end crystals. + */ +-public class EntityPlaceEvent extends EntityEvent implements Cancellable { ++public class EntityPlaceEvent extends EntityEvent implements Cancellable, gg.projecteden.parchment.OptionalPlayer { // Parchment + + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java.patch new file mode 100644 index 0000000..dc7fc8c --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java +@@ -11,7 +_,7 @@ + * Cancelling this event prevents any further processing of the portal for that tick. + * @see io.papermc.paper.event.entity.EntityInsideBlockEvent + */ +-public class EntityPortalEnterEvent extends EntityEvent implements org.bukkit.event.Cancellable { // Paper ++public class EntityPortalEnterEvent extends EntityEvent implements org.bukkit.event.Cancellable, gg.projecteden.parchment.HasLocation { // Parchment + private static final HandlerList handlers = new HandlerList(); + private final Location location; + diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntitySpawnEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntitySpawnEvent.java.patch new file mode 100644 index 0000000..1b5e56f --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntitySpawnEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/entity/EntitySpawnEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntitySpawnEvent.java +@@ -11,7 +_,7 @@ + *

+ * If an Entity Spawn event is cancelled, the entity will not spawn. + */ +-public class EntitySpawnEvent extends EntityEvent implements Cancellable { ++public class EntitySpawnEvent extends EntityEvent implements Cancellable, gg.projecteden.parchment.HasLocation { // Parchment + + private static final HandlerList handlers = new HandlerList(); + private boolean canceled; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java.patch new file mode 100644 index 0000000..acf7f6d --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java ++++ b/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java +@@ -13,7 +_,7 @@ + * Cancelling the event results in the item being allowed to exist for 5 more + * minutes. This behavior is not guaranteed and may change in future versions. + */ +-public class ItemDespawnEvent extends EntityEvent implements Cancellable { ++public class ItemDespawnEvent extends EntityEvent implements Cancellable, gg.projecteden.parchment.HasLocation { // Parchment + private static final HandlerList handlers = new HandlerList(); + private boolean canceled; + private final Location location; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/PlayerLeashEntityEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/PlayerLeashEntityEvent.java.patch new file mode 100644 index 0000000..5a8975d --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/entity/PlayerLeashEntityEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/entity/PlayerLeashEntityEvent.java ++++ b/src/main/java/org/bukkit/event/entity/PlayerLeashEntityEvent.java +@@ -11,7 +_,7 @@ + /** + * Called immediately prior to a creature being leashed by a player. + */ +-public class PlayerLeashEntityEvent extends Event implements Cancellable { ++public class PlayerLeashEntityEvent extends Event implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + private final Entity leashHolder; + private final Entity entity; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/hanging/HangingPlaceEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/hanging/HangingPlaceEvent.java.patch new file mode 100644 index 0000000..522541d --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/hanging/HangingPlaceEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/hanging/HangingPlaceEvent.java ++++ b/src/main/java/org/bukkit/event/hanging/HangingPlaceEvent.java +@@ -14,7 +_,7 @@ + /** + * Triggered when a hanging entity is created in the world + */ +-public class HangingPlaceEvent extends HangingEvent implements Cancellable { ++public class HangingPlaceEvent extends HangingEvent implements Cancellable, gg.projecteden.parchment.OptionalPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final Player player; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java.patch new file mode 100644 index 0000000..2f16885 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java +@@ -13,7 +_,7 @@ + * {@link org.bukkit.block.Furnace}, {@link org.bukkit.block.Smoker}, or + * {@link org.bukkit.block.BlastFurnace}. + */ +-public class FurnaceExtractEvent extends BlockExpEvent { ++public class FurnaceExtractEvent extends BlockExpEvent implements gg.projecteden.parchment.HasPlayer { // Parchment + private final Player player; + private final Material itemType; + private final int itemAmount; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java.patch new file mode 100644 index 0000000..e9c6235 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java +@@ -28,7 +_,7 @@ + * on the next tick. Also be aware that this is not an exhaustive list, and + * other methods could potentially create issues as well. + */ +-public class InventoryCloseEvent extends InventoryEvent { ++public class InventoryCloseEvent extends InventoryEvent implements gg.projecteden.parchment.HasHumanEntity { // Parchment + private static final HandlerList handlers = new HandlerList(); + // Paper start + private final Reason reason; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java.patch new file mode 100644 index 0000000..455ce6a --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java +@@ -9,7 +_,7 @@ + /** + * Called when a player opens an inventory + */ +-public class InventoryOpenEvent extends InventoryEvent implements Cancellable { ++public class InventoryOpenEvent extends InventoryEvent implements Cancellable, gg.projecteden.parchment.HasHumanEntity { // Parchment + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private net.kyori.adventure.text.Component titleOverride; // Paper diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java.patch new file mode 100644 index 0000000..68be471 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +@@ -18,7 +_,7 @@ + * Consider rendering any translatable yourself with {@link net.kyori.adventure.translation.GlobalTranslator#render} + * if the client's language is known. + */ +-public class AsyncPlayerPreLoginEvent extends Event { ++public class AsyncPlayerPreLoginEvent extends Event implements gg.projecteden.api.interfaces.HasUniqueId { // Parchment + private static final HandlerList handlers = new HandlerList(); + private Result result; + private net.kyori.adventure.text.Component message; // Paper diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/PlayerEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/PlayerEvent.java.patch new file mode 100644 index 0000000..74c09d1 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/PlayerEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/player/PlayerEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerEvent.java +@@ -7,7 +_,7 @@ + /** + * Represents a player related event + */ +-public abstract class PlayerEvent extends Event { ++public abstract class PlayerEvent extends Event implements gg.projecteden.parchment.HasPlayer { // Parchment + protected Player player; + + public PlayerEvent(@NotNull final Player who) { diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java.patch new file mode 100644 index 0000000..a9dc9c3 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java +@@ -23,7 +_,7 @@ + */ + @Deprecated(since = "1.3.2") + @Warning(reason = "This event causes a login thread to synchronize with the main thread") +-public class PlayerPreLoginEvent extends Event { ++public class PlayerPreLoginEvent extends Event implements gg.projecteden.api.interfaces.HasUniqueId { // Parchment + private static final HandlerList handlers = new HandlerList(); + private Result result; + private net.kyori.adventure.text.Component message; // Paper diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java.patch new file mode 100644 index 0000000..a422492 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java +@@ -10,7 +_,7 @@ + /** + * Called prior to an entity being unleashed due to a player's action. + */ +-public class PlayerUnleashEntityEvent extends EntityUnleashEvent implements Cancellable { ++public class PlayerUnleashEntityEvent extends EntityUnleashEvent implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + + private boolean cancelled = false; + diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/raid/RaidTriggerEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/raid/RaidTriggerEvent.java.patch new file mode 100644 index 0000000..addd192 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/raid/RaidTriggerEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/raid/RaidTriggerEvent.java ++++ b/src/main/java/org/bukkit/event/raid/RaidTriggerEvent.java +@@ -11,7 +_,7 @@ + * Called when a {@link Raid} is triggered (e.g: a player with Bad Omen effect + * enters a village). + */ +-public class RaidTriggerEvent extends RaidEvent implements Cancellable { ++public class RaidTriggerEvent extends RaidEvent implements Cancellable, gg.projecteden.parchment.HasPlayer { // Parchment + + private static final HandlerList handlers = new HandlerList(); + // diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/server/TabCompleteEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/server/TabCompleteEvent.java.patch new file mode 100644 index 0000000..681dd4e --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/server/TabCompleteEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/server/TabCompleteEvent.java ++++ b/src/main/java/org/bukkit/event/server/TabCompleteEvent.java +@@ -21,7 +_,7 @@ + * @apiNote Only called for bukkit API commands {@link org.bukkit.command.Command} and + * {@link org.bukkit.command.CommandExecutor} and not for brigadier commands ({@link io.papermc.paper.command.brigadier.Commands}). + */ +-public class TabCompleteEvent extends Event implements Cancellable { ++public class TabCompleteEvent extends Event implements Cancellable, gg.projecteden.parchment.OptionalLocation { // Parchment + + private static final HandlerList handlers = new HandlerList(); + // diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/world/GenericGameEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/world/GenericGameEvent.java.patch new file mode 100644 index 0000000..48f3f8d --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/world/GenericGameEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/world/GenericGameEvent.java ++++ b/src/main/java/org/bukkit/event/world/GenericGameEvent.java +@@ -15,7 +_,7 @@ + * Specific Bukkit events should be used where possible, this event is mainly + * used internally by Sculk sensors. + */ +-public class GenericGameEvent extends WorldEvent implements Cancellable { ++public class GenericGameEvent extends WorldEvent implements Cancellable, gg.projecteden.parchment.HasLocation { // Parchment + + private static final HandlerList handlers = new HandlerList(); + private final GameEvent event; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/world/StructureGrowEvent.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/world/StructureGrowEvent.java.patch new file mode 100644 index 0000000..65d19d4 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/event/world/StructureGrowEvent.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/world/StructureGrowEvent.java ++++ b/src/main/java/org/bukkit/event/world/StructureGrowEvent.java +@@ -14,7 +_,7 @@ + * Event that is called when an organic structure attempts to grow (Sapling {@literal ->} + * Tree), (Mushroom {@literal ->} Huge Mushroom), naturally or using bonemeal. + */ +-public class StructureGrowEvent extends WorldEvent implements Cancellable { ++public class StructureGrowEvent extends WorldEvent implements Cancellable, gg.projecteden.parchment.OptionalPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled = false; + private final Location location; diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/inventory/Inventory.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/inventory/Inventory.java.patch new file mode 100644 index 0000000..fa8ad7d --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/inventory/Inventory.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/inventory/Inventory.java ++++ b/src/main/java/org/bukkit/inventory/Inventory.java +@@ -25,7 +_,7 @@ + * @see #getContents() + * @see #getStorageContents() + */ +-public interface Inventory extends Iterable { ++public interface Inventory extends Iterable, gg.projecteden.parchment.OptionalLocation { // Parchment + + /** + * Returns the size of the inventory diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/inventory/InventoryView.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/inventory/InventoryView.java.patch new file mode 100644 index 0000000..2f91351 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/inventory/InventoryView.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/inventory/InventoryView.java ++++ b/src/main/java/org/bukkit/inventory/InventoryView.java +@@ -9,7 +_,7 @@ + * Represents a view linking two inventories and a single player (whose + * inventory may or may not be one of the two). + */ +-public interface InventoryView { ++public interface InventoryView extends gg.projecteden.parchment.HasHumanEntity { // Parchment + public static final int OUTSIDE = -999; + /** + * Represents various extra properties of certain inventory windows. diff --git a/parchment-api/paper-patches/files/src/main/java/org/bukkit/loot/LootContext.java.patch b/parchment-api/paper-patches/files/src/main/java/org/bukkit/loot/LootContext.java.patch new file mode 100644 index 0000000..c0cf7f5 --- /dev/null +++ b/parchment-api/paper-patches/files/src/main/java/org/bukkit/loot/LootContext.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/loot/LootContext.java ++++ b/src/main/java/org/bukkit/loot/LootContext.java +@@ -11,7 +_,7 @@ + * Represents additional information a {@link LootTable} can use to modify it's + * generated loot. + */ +-public final class LootContext { ++public final class LootContext implements gg.projecteden.parchment.HasLocation { // Parchment + + public static final int DEFAULT_LOOT_MODIFIER = -1; + diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/HasHumanEntity.java b/parchment-api/src/main/java/gg/projecteden/parchment/HasHumanEntity.java new file mode 100644 index 0000000..b920db2 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/HasHumanEntity.java @@ -0,0 +1,19 @@ +package gg.projecteden.parchment; + +import org.bukkit.entity.HumanEntity; +import org.jetbrains.annotations.NotNull; + +/** + * Represents an object that has a {@link HumanEntity} + * @see gg.projecteden.parchment.OptionalHumanEntity + */ +@FunctionalInterface +public interface HasHumanEntity extends OptionalHumanEntity { + /** + * Gets a {@link HumanEntity} object that this represents + * + * @return human entity + */ + @Override + @NotNull HumanEntity getPlayer(); +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/HasLocation.java b/parchment-api/src/main/java/gg/projecteden/parchment/HasLocation.java new file mode 100644 index 0000000..10b03e5 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/HasLocation.java @@ -0,0 +1,18 @@ +package gg.projecteden.parchment; + +import org.bukkit.Location; +import org.jetbrains.annotations.NotNull; + +/** + * Represents an object that has a {@link Location} + * @see OptionalLocation + */ +public interface HasLocation extends OptionalLocation { + /** + * Gets a {@link Location} attached to this object + * + * @return attached location + */ + @Override + @NotNull Location getLocation(); +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/HasOfflinePlayer.java b/parchment-api/src/main/java/gg/projecteden/parchment/HasOfflinePlayer.java new file mode 100644 index 0000000..a6e5cc1 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/HasOfflinePlayer.java @@ -0,0 +1,17 @@ +package gg.projecteden.parchment; + +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; + +/** + * Represents an object that has a {@link OfflinePlayer} + */ +@FunctionalInterface +public interface HasOfflinePlayer { + /** + * Gets an {@link OfflinePlayer} object that this represents + * + * @return offline player + */ + @NotNull OfflinePlayer getOfflinePlayer(); +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/HasPlayer.java b/parchment-api/src/main/java/gg/projecteden/parchment/HasPlayer.java new file mode 100644 index 0000000..00e6a0f --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/HasPlayer.java @@ -0,0 +1,19 @@ +package gg.projecteden.parchment; + +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +/** + * Represents an object that has a {@link Player} + * @see gg.projecteden.parchment.OptionalPlayer + */ +@FunctionalInterface +public interface HasPlayer extends OptionalPlayer, HasHumanEntity { + /** + * Gets a {@link Player} object that this represents + * + * @return player + */ + @Override + @NotNull Player getPlayer(); +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/OptionalHumanEntity.java b/parchment-api/src/main/java/gg/projecteden/parchment/OptionalHumanEntity.java new file mode 100644 index 0000000..21da026 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/OptionalHumanEntity.java @@ -0,0 +1,18 @@ +package gg.projecteden.parchment; + +import org.bukkit.entity.HumanEntity; +import org.jetbrains.annotations.Nullable; + +/** + * Represents an object that may have a {@link HumanEntity} + * @see HasHumanEntity + */ +@FunctionalInterface +public interface OptionalHumanEntity { + /** + * Gets a {@link HumanEntity} object that this represents, if there is one + * + * @return human entity or null + */ + @Nullable HumanEntity getPlayer(); +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/OptionalLocation.java b/parchment-api/src/main/java/gg/projecteden/parchment/OptionalLocation.java new file mode 100644 index 0000000..d4b47b1 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/OptionalLocation.java @@ -0,0 +1,17 @@ +package gg.projecteden.parchment; + +import org.bukkit.Location; +import org.jetbrains.annotations.Nullable; + +/** + * Represents an object that may have a {@link Location} + * @see HasLocation + */ +@FunctionalInterface +public interface OptionalLocation { + /** + * Gets a {@link Location} attached to this object if present * + * @return attached location + */ + @Nullable Location getLocation(); +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/OptionalPlayer.java b/parchment-api/src/main/java/gg/projecteden/parchment/OptionalPlayer.java new file mode 100644 index 0000000..6dd5fbf --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/OptionalPlayer.java @@ -0,0 +1,19 @@ +package gg.projecteden.parchment; + +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Nullable; + +/** + * Represents an object that may have a {@link Player} + * @see HasPlayer + */ +@FunctionalInterface +public interface OptionalPlayer extends OptionalHumanEntity { + /** + * Gets a {@link Player} object that this represents, if there is one. This may be null if the + * player is online or the player object being optional. + * + * @return player or null + */ + @Nullable Player getPlayer(); +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/OptionalPlayerLike.java b/parchment-api/src/main/java/gg/projecteden/parchment/OptionalPlayerLike.java new file mode 100644 index 0000000..cc61001 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/OptionalPlayerLike.java @@ -0,0 +1,48 @@ +package gg.projecteden.parchment; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.audience.ForwardingAudience; +import net.kyori.adventure.identity.Identified; +import net.kyori.adventure.identity.Identity; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +/** + * Class that may be like a {@link org.bukkit.entity.Player} in that it has a {@link java.util.UUID}, {@link org.bukkit.OfflinePlayer}, {@link Identity}, and a nullable Player. + * @see gg.projecteden.parchment.PlayerLike + */ +public interface OptionalPlayerLike extends OptionalPlayer, gg.projecteden.api.interfaces.HasUniqueId, HasOfflinePlayer, OptionalLocation, Identified, ForwardingAudience.Single { + /** + * Gets the identity associated with this object + * + * @return associated identity + */ + @Override + default @NotNull Identity identity() { + return Identity.identity(getUniqueId()); + } + + /** + * Returns if the {@link Player} associated with this object is online. + * + * @return if the player is online + */ + default boolean isOnline() { + return getPlayer() != null; + } + + @Override + default @NotNull Audience audience() { + return Objects.requireNonNullElse(getPlayer(), Audience.empty()); + } + + @Override + default @Nullable Location getLocation() { + final Player player = getPlayer(); + return player == null ? null : player.getLocation(); + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/PlayerLike.java b/parchment-api/src/main/java/gg/projecteden/parchment/PlayerLike.java new file mode 100644 index 0000000..29f28f9 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/PlayerLike.java @@ -0,0 +1,30 @@ +package gg.projecteden.parchment; + +import net.kyori.adventure.audience.Audience; +import org.bukkit.Location; +import org.jetbrains.annotations.NotNull; + +/** + * Class that is like a {@link org.bukkit.entity.Player} in that it has a Player, {@link java.util.UUID}, {@link org.bukkit.OfflinePlayer}, and an {@link net.kyori.adventure.identity.Identity}. + * @see gg.projecteden.parchment.OptionalPlayerLike + */ +public interface PlayerLike extends HasPlayer, HasLocation, OptionalPlayerLike { + + // reduce nullability checks by re-implementing the methods from OptionalPlayerLike + // (but without the null checks) + + @Override + default @NotNull Audience audience() { + return getPlayer(); + } + + @Override + default boolean isOnline() { + return true; + } + + @Override + default @NotNull Location getLocation() { + return getPlayer().getLocation(); + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityData.java b/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityData.java new file mode 100644 index 0000000..d1da168 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityData.java @@ -0,0 +1,140 @@ +package gg.projecteden.parchment.entity; + +import org.bukkit.entity.Entity; + +import java.util.*; +import java.util.function.Supplier; + +public final class EntityData { + private static final Map> PARKED = new HashMap<>(); + private static int DATA_IDX; + + private final List> data = new ArrayList<>(); + private final Class ownerType; + private Entity owner; + + EntityData(Class ownerType) { + this.ownerType = ownerType; + } + + public static , E extends Entity> EntityDataKey createKey( + Supplier generator, + Class ownerType + ) { + return new EntityDataKey<>(ownerType, generator, EntityData.DATA_IDX); + } + + public static EntityData create(Entity entity) { + EntityData data = new EntityData(entity.getClass()); + + List slots = EntityData.PARKED.get(entity.getUniqueId()); + if (slots != null) { + for (DataSlot slot : slots) { + data.set(slot.idx, slot.data); + } + } + + data.setOwner(entity); + + return data; + } + + public , E extends Entity> T get(EntityDataKey key) { + while (this.data.size() <= key.getIdx()) { + this.data.add(null); + } + + T out = cast(this.data.get(key.getIdx())); + if (out == null) { + this.checkEntityType(key.ownerType); + + out = key.getGenerator().get(); + out.setOwner(cast(this.owner)); + + this.data.set(key.getIdx(), out); + } + + return out; + } + + public , E extends Entity> boolean clear(EntityDataKey key) { + if (this.data.size() <= key.getIdx()) { + return false; + } + + this.checkEntityType(key.ownerType); + return this.data.set(key.getIdx(), null) != null; + } + + public void orphan() { + for (EntityDataFragment frag : this.data) { + if (frag != null) { + frag.onOrphan(); + } + } + + List persist = new ArrayList<>(); + + for (int i = this.data.size() - 1; i >= 0; i--) { + EntityDataFragment frag = this.data.get(i); + if (frag != null && frag.isPersistent()) { + persist.add(new DataSlot(frag, i)); + } + } + + if (!persist.isEmpty()) { + EntityData.PARKED.put(this.owner.getUniqueId(), persist); + } + } + + void set(int slot, EntityDataFragment data) { + while (this.data.size() <= slot) { + this.data.add(null); + } + + this.data.set(slot, data); + } + + void setOwner(Entity entity) { + Class ownerType = entity.getClass(); + if (!ownerType.equals(this.ownerType)) { + throw new IllegalArgumentException(String.format( + "Wrong entity type. (entity=%s@%s, expect=%s@%s)", + ownerType, ownerType.getClassLoader(), + this.ownerType, this.ownerType.getClassLoader() + )); + } + + this.owner = entity; + + for (EntityDataFragment frag : this.data) { + if (frag != null) { + frag.setOwner(cast(entity)); + } + } + } + + private void checkEntityType(Class ownerType) { + if (!ownerType.isAssignableFrom(this.ownerType)) { + throw new IllegalArgumentException(String.format( + "Incompatible entity types. (key=%s@%s, expect=%s@%s)", + ownerType, ownerType.getClassLoader(), + this.ownerType, this.ownerType.getClassLoader() + )); + } + } + + private T cast(S src) { + return (T) src; + } + + private static final class DataSlot { + private final EntityDataFragment data; + private final int idx; + + private DataSlot(EntityDataFragment data, int idx) { + this.data = data; + this.idx = idx; + } + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityDataFragment.java b/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityDataFragment.java new file mode 100644 index 0000000..7bb0736 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityDataFragment.java @@ -0,0 +1,34 @@ +package gg.projecteden.parchment.entity; + +import org.bukkit.entity.Entity; + +public abstract class EntityDataFragment { + private E owner; + private boolean persistent = true; + + protected EntityDataFragment() { + } + + protected void onOwnerChange() { + } + + protected void onOrphan() { + } + + protected final E getOwner() { + return this.owner; + } + + protected final void setPersistent(boolean persistent) { + this.persistent = persistent; + } + + final boolean isPersistent() { + return this.persistent; + } + + final void setOwner(E entity) { + this.owner = entity; + this.onOwnerChange(); + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityDataKey.java b/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityDataKey.java new file mode 100644 index 0000000..4329fc3 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityDataKey.java @@ -0,0 +1,27 @@ +package gg.projecteden.parchment.entity; + +import org.bukkit.entity.Entity; + +import java.util.function.Supplier; + +public final class EntityDataKey, E extends Entity> { + private final Supplier generator; + private final int idx; + + final Class ownerType; + + EntityDataKey(Class ownerType, Supplier generator, int idx) { + this.generator = generator; + this.idx = idx; + + this.ownerType = ownerType; + } + + Supplier getGenerator() { + return this.generator; + } + + int getIdx() { + return this.idx; + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityDataServiceKey.java b/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityDataServiceKey.java new file mode 100644 index 0000000..dc8a28a --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/entity/EntityDataServiceKey.java @@ -0,0 +1,30 @@ +package gg.projecteden.parchment.entity; + +public final class EntityDataServiceKey { + private final Class serviceType; + private S service; + + public EntityDataServiceKey(Class serviceType) { + this.serviceType = serviceType; + } + + public S get() { + if (this.service == null) { + throw new IllegalStateException("Service is not initialized."); + } + + return this.service; + } + + public void set(S service) { + if (this.service != null) { + throw new IllegalStateException("Service is already initialized."); + } + + if (!this.serviceType.isInstance(service)) { + throw new IllegalArgumentException("Value does not implement service contract."); + } + + this.service = service; + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/event/block/BlockDropResourcesEvent.java b/parchment-api/src/main/java/gg/projecteden/parchment/event/block/BlockDropResourcesEvent.java new file mode 100644 index 0000000..be237b7 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/event/block/BlockDropResourcesEvent.java @@ -0,0 +1,45 @@ +package gg.projecteden.parchment.event.block; + +import org.bukkit.block.Block; +import org.bukkit.event.HandlerList; +import org.bukkit.event.block.BlockEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Called when a block drops resources in the world. The block will exist in the world at the time. + *

+ * This event fires in between {@link org.bukkit.event.block.BlockBreakEvent BlockBreakEvent} + * and {@link org.bukkit.event.block.BlockDropItemEvent BlockDropItemEvent}. + */ +public class BlockDropResourcesEvent extends BlockEvent { + private static final HandlerList handlers = new HandlerList(); + private final @NotNull List resources; + + public BlockDropResourcesEvent(@NotNull Block block, @NotNull List resources) { + super(block); + this.resources = resources; + } + + /** + * Gets the resources being dropped by the block. This list is guaranteed to be mutable + * and may be safely altered. + * @return mutable list of items + */ + public @NotNull List getResources() { + return resources; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + public static HandlerList getHandlerList() { + return handlers; + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/event/block/CustomBlockUpdateEvent.java b/parchment-api/src/main/java/gg/projecteden/parchment/event/block/CustomBlockUpdateEvent.java new file mode 100644 index 0000000..c65c044 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/event/block/CustomBlockUpdateEvent.java @@ -0,0 +1,70 @@ +package gg.projecteden.parchment.event.block; + +import org.bukkit.block.data.BlockData; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.Location; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class CustomBlockUpdateEvent extends Event implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + + private BlockData block; + private UpdateType updateType; + private Location location; + + public CustomBlockUpdateEvent(BlockData block, UpdateType updateType, Location location) { + this.block = block; + this.updateType = updateType; + this.location = location; + } + + public CustomBlockUpdateEvent(BlockData block, UpdateType updateType) { + this.block = block; + this.updateType = updateType; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + public BlockData getBlock() { + return block; + } + + public UpdateType getUpdateType() { + return updateType; + } + + public Location getLocation() { + return location; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + public static HandlerList getHandlerList() { + return handlers; + } + + public enum UpdateType { + POWERED, + SHAPE, + INSTRUMENT, + PITCH + } + +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/event/entity/PreEntityShootBowEvent.java b/parchment-api/src/main/java/gg/projecteden/parchment/event/entity/PreEntityShootBowEvent.java new file mode 100644 index 0000000..88becbf --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/event/entity/PreEntityShootBowEvent.java @@ -0,0 +1,60 @@ +package gg.projecteden.parchment.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +public class PreEntityShootBowEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + + private final @NotNull ItemStack bow; + private final @NotNull ItemStack arrow; + boolean relative = true; + boolean cancelled = false; + + public PreEntityShootBowEvent(@NotNull Entity entity, @NotNull ItemStack bow, @NotNull ItemStack arrow) { + super(entity); + this.bow = bow; + this.arrow = arrow; + } + + public @NotNull ItemStack getBow() { + return this.bow; + } + + public @NotNull ItemStack getArrow() { + return this.arrow; + } + + public boolean isRelative() { + return this.relative; + } + + public void setRelative(boolean relative) { + this.relative = relative; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } + + @NotNull + public static HandlerList getHandlerList() { + return handlers; + } + +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/event/player/PlayerUseRespawnAnchorEvent.java b/parchment-api/src/main/java/gg/projecteden/parchment/event/player/PlayerUseRespawnAnchorEvent.java new file mode 100644 index 0000000..c2dfb2e --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/event/player/PlayerUseRespawnAnchorEvent.java @@ -0,0 +1,117 @@ +package gg.projecteden.parchment.event.player; + +import com.google.common.base.Preconditions; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.NotNull; + +/** + * This event is fired after determining what action should result from a player interacting with + * a respawn anchor. + */ +public class PlayerUseRespawnAnchorEvent extends PlayerEvent implements Cancellable { + + /** + * Represents the default possible outcomes of this event. + */ + public enum RespawnAnchorResult { + /** + * The player's spawn point will be set + */ + SET_SPAWN, + /** + * The respawn anchor will explode due to being used outside the nether + */ + EXPLODE, + /** + * The player will charge the respawn anchor + */ + CHARGE, + /** + * The respawn anchor will do nothing + */ + NOTHING + } + + private static final HandlerList handlers = new HandlerList(); + private final Block respawnAnchor; + private RespawnAnchorResult respawnAnchorResult; + private boolean cancelled = false; + + public PlayerUseRespawnAnchorEvent(@NotNull Player who, @NotNull Block respawnAnchor, @NotNull RespawnAnchorResult respawnAnchorResult) { + super(who); + this.respawnAnchor = respawnAnchor; + this.respawnAnchorResult = respawnAnchorResult; + } + + /** + * Returns the respawn anchor block involved in this event. + * + * @return the respawn anchor block involved in this event + */ + @NotNull + public Block getRespawnAnchor() { + return this.respawnAnchor; + } + + /** + * Describes the outcome of the event. + * + * @return the respawn anchor result for the outcome of the event + */ + @NotNull + public RespawnAnchorResult getResult() { + return this.respawnAnchorResult; + } + + /** + * Sets the outcome of the event. + * + * @param result event to set + */ + public void setResult(@NotNull RespawnAnchorResult result) { + this.respawnAnchorResult = Preconditions.checkNotNull(result, "result"); + } + + /** + * Gets the cancellation state of this event. A cancelled event will not + * be executed in the server, but will still pass to other plugins. + *

+ * A positive value means the respawn anchor will not take any action, as + * if it had not been clicked at all. + * + * @return true if this event is cancelled + */ + @Override + public boolean isCancelled() { + return cancelled; + } + + /** + * Sets the cancellation state of this event. A canceled event will not be + * executed in the server, but will still pass to other plugins. + *

+ * Canceling this event will prevent use of the respawn anchor, leaving it + * as thought it hadn't been clicked at all. + * + * @param cancel true if you wish to cancel this event + */ + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } + + @NotNull + public static HandlerList getHandlerList() { + return handlers; + } + +} diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/event/sound/SoundEvent.java b/parchment-api/src/main/java/gg/projecteden/parchment/event/sound/SoundEvent.java new file mode 100644 index 0000000..eb7112b --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/event/sound/SoundEvent.java @@ -0,0 +1,359 @@ +package gg.projecteden.parchment.event.sound; + +import gg.projecteden.parchment.HasLocation; +import gg.projecteden.parchment.OptionalHumanEntity; +import net.kyori.adventure.sound.Sound; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Called when a sound is sent to a player. + * Cancelling this event will prevent the packet from sending. + */ +public final class SoundEvent extends Event implements Cancellable { + private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(SoundEvent.class); + + private static final org.bukkit.event.HandlerList handlers = new org.bukkit.event.HandlerList(); + public static final @NotNull Function DEFAULT_DISTANCE_FUNCTION = event -> event.volume() > 1.0F ? (double) (16.0F * event.volume()) : 16.0D; + public static final @NotNull Function> DEFAULT_RECIPIENTS_FUNCTION = new WrappedRecipientsFunction(event -> { + final double distance = event.calculateDistance(); + final Location loc = event.getEmitter().location(); + return loc.getWorld().getPlayers().stream() + .filter(player -> { + Location pl = player.getLocation(); + double x = loc.getX() - pl.getX(); + double y = loc.getY() - pl.getY(); + double z = loc.getZ() - pl.getZ(); + return x * x + y * y + z * z < distance * distance; + }) + .toList(); + }); + + private @Nullable HumanEntity except; + private @NotNull Function<@NotNull Sound, @NotNull Double> distanceFunction; + private @NotNull Function<@NotNull SoundEvent, @NotNull List<@NotNull Player>> recipientsFunction; + private @NotNull Sound sound; + private @NotNull Emitter emitter; + private boolean cancelled; + private @Nullable BiFunction<@NotNull SoundEvent, @NotNull Player, @Nullable Sound> soundOverrideFunction; + private @Nullable BiFunction<@NotNull SoundEvent, @NotNull Player, @Nullable Emitter> emitterOverrideFunction; + + public SoundEvent(@Nullable HumanEntity except, @NotNull Sound sound, @NotNull Emitter emitter, @Nullable Function distanceFunction, @Nullable Function> recipientsFunction) { + super(true); + this.except = except; + this.sound = Objects.requireNonNull(sound, "sound cannot be null"); + this.emitter = Objects.requireNonNull(emitter, "emitter cannot be null"); + this.distanceFunction = Objects.requireNonNullElse(distanceFunction, DEFAULT_DISTANCE_FUNCTION); + this.recipientsFunction = wrapRecipientsFunction(Objects.requireNonNullElse(recipientsFunction, DEFAULT_RECIPIENTS_FUNCTION)); + } + + /** + * Gets the player that won't be receiving this sound. + * + * @return player excluded from receiving this sound + */ + public @Nullable HumanEntity getException() { + return except; + } + + /** + * Sets the player that won't be receiving this sound. + * + * @param except player excluded from receiving this sound + */ + public void setException(@Nullable HumanEntity except) { + this.except = except; + } + + /** + * Gets the sound that will be sent. + * + * @return sound that will be sent + */ + public @NotNull Sound getSound() { + return sound; + } + + /** + * Sets the sound that will be sent. + * + * @param sound sound that will be sent + */ + public void setSound(@NotNull Sound sound) { + this.sound = Objects.requireNonNull(sound, "sound cannot be null"); + } + + /** + * Gets the emitter which determines how and where the sound will be played from. + * + * @return emitter which determines how and where the sound will be played from + */ + public @NotNull Emitter getEmitter() { + return emitter; + } + + /** + * Sets the emitter which determines how and where the sound will be played from. + * + * @param emitter emitter which determines how and where the sound will be played from + */ + public void setEmitter(@NotNull Emitter emitter) { + this.emitter = Objects.requireNonNull(emitter, "emitter cannot be null"); + } + + /** + * Calculates the distance of the sound. + *

+ * The distance value is dynamically calculated using a + * {@link Function Function<SoundEvent, Double>}. + * In vanilla Minecraft, the default function is {@link #DEFAULT_DISTANCE_FUNCTION} + * ({@code event -> event.getVolume() > 1.0F ? (double) (16.0F * event.getVolume()) : 16.0D}). + *

+ * This is used by the vanilla implementation of {@link #calculateRecipients()}, though custom + * implementations won't always use this method. + * + * @return calculated distance + * @see #getDistanceFunction() + * @see #setDistanceFunction(Function) + */ + public double calculateDistance() { + return distanceFunction.apply(sound); + } + + /** + * Gets the function that calculates the distance of the sound. + * + * @return distance function + * @see #calculateDistance() + * @see #setDistanceFunction(Function) + */ + public @NotNull Function<@NotNull Sound, @NotNull Double> getDistanceFunction() { + return distanceFunction; + } + + /** + * Sets the function that calculates the distance of the sound. + * + * @param distanceFunction distance function + * @see #calculateDistance() + * @see #getDistanceFunction() + */ + public void setDistanceFunction(@NotNull Function<@NotNull Sound, @NotNull Double> distanceFunction) { + this.distanceFunction = Objects.requireNonNull(distanceFunction, "distanceFunction cannot be null"); + } + + /** + * Determines which players will receive this sound packet. + * + * @return immutable list of players + * @see #getRecipientsFunction() + * @see #setRecipientsFunction(Function) + */ + public @NotNull List calculateRecipients() { + return recipientsFunction.apply(this); + } + + /** + * Gets the function that determines which players will receive the sound packet. + * + * @return recipients function + * @see #calculateRecipients() + * @see #setRecipientsFunction(Function) + */ + public @NotNull Function<@NotNull SoundEvent, @NotNull List<@NotNull Player>> getRecipientsFunction() { + return recipientsFunction; + } + + /** + * Sets the function that determines which players will receive the sound packet. + *

+ * This function does not need to query {@link #getException()} as this is done automatically. + * + * @param recipientsFunction recipients function + * @see #calculateRecipients() + * @see #getRecipientsFunction() + */ + public void setRecipientsFunction(@NotNull Function<@NotNull SoundEvent, @NotNull List<@NotNull Player>> recipientsFunction) { + this.recipientsFunction = wrapRecipientsFunction(Objects.requireNonNull(recipientsFunction, "recipientsFunction cannot be null")); + } + + /** + * Gets the function that overrides what {@link Sound} is sent to a {@link Player}. + * + * @return sound override function (or {@code null} if not overridden) + */ + public @Nullable BiFunction<@NotNull SoundEvent, @NotNull Player, @Nullable Sound> getSoundOverrideFunction() { + return soundOverrideFunction; + } + + /** + * Sets the function that overrides what {@link Sound} is sent to a {@link Player}. + * + * @param soundOverrideFunction function which accepts a sound event and a player and returns + * a sound (or {@code null} if the default sound should be used) + */ + public void setSoundOverrideFunction(@Nullable BiFunction<@NotNull SoundEvent, @NotNull Player, @Nullable Sound> soundOverrideFunction) { + this.soundOverrideFunction = soundOverrideFunction; + } + + /** + * Calculates the sound that will be sent to a {@link Player}. + * + * @param player player to calculate the sound for + * @return sound that will be sent to the player + */ + public @NotNull Sound calculateSound(@NotNull Player player) { + if (soundOverrideFunction != null) { + try { + Sound override = soundOverrideFunction.apply(this, player); + if (override != null) { + return override; + } + } catch (Throwable e) { + LOGGER.error("Error while overriding sound for player " + player.getName(), e); + } + } + return sound; + } + + /** + * Gets the function that overrides what {@link Emitter} is used when playing this sound to a + * {@link Player}. + * + * @return emitter override function (or {@code null} if not overridden) + */ + public @Nullable BiFunction<@NotNull SoundEvent, @NotNull Player, @Nullable Emitter> getEmitterOverrideFunction() { + return emitterOverrideFunction; + } + + /** + * Sets the function that overrides what {@link Emitter} is used when playing this sound to a + * {@link Player}. + * + * @param emitterOverrideFunction function which accepts a sound event and a player and returns + * an emitter + * (or {@code null} if the default emitter should be used) + */ + public void setEmitterOverrideFunction(@Nullable BiFunction<@NotNull SoundEvent, @NotNull Player, @Nullable Emitter> emitterOverrideFunction) { + this.emitterOverrideFunction = emitterOverrideFunction; + } + + /** + * Calculates the emitter that will be used when playing this sound to a {@link Player}. + * + * @param player player to calculate the emitter for + * @return emitter that will be used when playing the sound to the player + */ + public @NotNull Emitter calculateEmitter(@NotNull Player player) { + if (emitterOverrideFunction != null) { + try { + Emitter override = emitterOverrideFunction.apply(this, player); + if (override != null) { + return override; + } + } catch (Throwable e) { + LOGGER.error("Error while overriding emitter for player " + player.getName(), e); + } + } + return emitter; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @NotNull + public static org.bukkit.event.HandlerList getHandlerList() { + return handlers; + } + + @Override + public @NotNull org.bukkit.event.HandlerList getHandlers() { + return handlers; + } + + private record WrappedRecipientsFunction(@NotNull Function> wrapped) implements Function> { + @Override + public @NotNull List apply(@NotNull SoundEvent event) { + List recipients = wrapped.apply(event); + HumanEntity except = event.getException(); + if (except != null) { + List filteredRecipients = new ArrayList<>(recipients.size()); + for (Player player : recipients) { + if (!player.getUniqueId().equals(except.getUniqueId())) + filteredRecipients.add(player); + } + return filteredRecipients; + } + return recipients; + } + } + + @NotNull + private static Function> wrapRecipientsFunction(@NotNull Function> recipientsFunction) { + if (recipientsFunction instanceof WrappedRecipientsFunction) + return recipientsFunction; + else + return new WrappedRecipientsFunction(recipientsFunction); + } + + /** + * The class which determines where a sound will emit from. + */ + public sealed interface Emitter extends HasLocation permits EntityEmitter, LocationEmitter { + /** + * Gets the location at which the sound will be played. + * + * @return sound's location + * @deprecated use {@link #getLocation()} instead + */ + @NotNull + @Deprecated + default Location location() { + return getLocation(); + } + } + + /** + * An emitter which plays a sound from an entity. + * + * @param entity the entity from which the sound will be played + */ + public record EntityEmitter(@NotNull Entity entity) implements Emitter { + @Override + public @NotNull Location getLocation() { + return entity.getLocation(); + } + } + + /** + * An emitter which plays a sound from a location. + * + * @param location the location from which the sound will be played + */ + public record LocationEmitter(@NotNull Location location) implements Emitter { + @Override + public @NotNull Location getLocation() { + return location; + } + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/inventory/RecipeType.java b/parchment-api/src/main/java/gg/projecteden/parchment/inventory/RecipeType.java new file mode 100644 index 0000000..88088d5 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/inventory/RecipeType.java @@ -0,0 +1,50 @@ +package gg.projecteden.parchment.inventory; + +/** + * A type of crafting recipe. + */ +public enum RecipeType { + /** + * Recipes crafted in the standard crafting table. + */ + CRAFTING(false), + /** + * Recipes for smelting an item inside a furnace. + */ + SMELTING(true), + /** + * Recipes for smelting an item inside a blasting furnace. + */ + BLASTING(true), + /** + * Recipes for smelting an item inside a smoker. + */ + SMOKING(true), + /** + * Recipes for cooking an item on a campfire. + */ + CAMPFIRE_COOKING(true), + /** + * Recipes for carving stones in a stonecutter. + */ + STONECUTTING(true), + /** + * Recipes for smithing an item in a smithing table. + */ + SMITHING(false), + ; + + private final boolean singleInput; + + RecipeType(boolean singleInput) { + this.singleInput = singleInput; + } + + /** + * Determines if the recipe only accepts a single item for input. + * @return true if the recipe only accepts a single item for input + */ + public boolean isSingleInput() { + return singleInput; + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/Sidebar.java b/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/Sidebar.java new file mode 100644 index 0000000..92d9389 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/Sidebar.java @@ -0,0 +1,123 @@ +package gg.projecteden.parchment.sidebar; + +import gg.projecteden.parchment.entity.EntityData; +import gg.projecteden.parchment.entity.EntityDataFragment; +import gg.projecteden.parchment.entity.EntityDataKey; +import org.bukkit.entity.Player; + +import java.util.Objects; + +public final class Sidebar extends EntityDataFragment { + private static final EntityDataKey DATA_KEY = EntityData.createKey(Sidebar::new, Player.class); + + private final SidebarBuffer[] buffer = new SidebarBuffer[2]; + + private final StageImpl stage = new StageImpl(); + private final Runnable layoutListener; + + private SidebarLayout layout; + + private boolean visible; + private int back; + + public static Sidebar get(Player player) { + Objects.requireNonNull(player); + + return player.getStoredEntityData().get(Sidebar.DATA_KEY); + } + + private Sidebar() { + this.buffer[0] = SidebarBufferUtilSpec.IMPL_KEY.get().create("_sidebar_l"); + this.buffer[1] = SidebarBufferUtilSpec.IMPL_KEY.get().create("_sidebar_r"); + + this.layoutListener = () -> { + this.layout.update(this.stage); + this.flush(); + }; + + this.setPersistent(false); + } + + public void applyLayout(SidebarLayout layout) { + if (this.layout != null) { + this.layout.unsubscribe(this.layoutListener); + this.buffer[this.back].clear(); + } + + this.layout = layout; + + if (layout == null) { + this.hide(); + } else { + layout.setup(this.stage); + this.flush(); + + layout.subscribe(this.layoutListener); + } + } + + private void setTitle(String title) { + this.buffer[this.back].setTitle(title); + } + + private void setLine(int idx, String value, String display) { + if (value == null) { + this.buffer[this.back].clearLine(idx); + } else { + this.buffer[this.back].setLine(idx, value, display); + } + } + + private void flush() { + SidebarBuffer front = this.buffer[this.back]; + SidebarBuffer back = this.buffer[this.back ^ 1]; + boolean shouldShow = !this.visible; + + if (front.hasDiverged(back)) { + front.pushChanges(); + + back.sync(front); + this.back ^= 1; + + shouldShow = true; + } + + if (shouldShow) { + front.setActive(); + this.visible = true; + } + } + + private void hide() { + SidebarBufferUtilSpec.IMPL_KEY.get().hideSidebar(this.getOwner()); + this.visible = false; + } + + @Override + protected void onOwnerChange() { + this.buffer[0].setOwner(this.getOwner()); + this.buffer[1].setOwner(this.getOwner()); + + if (this.visible) { + this.buffer[this.back ^ 1].setActive(); + } + } + + private final class StageImpl implements SidebarStage { + @Override + public void setTitle(String title) { + Sidebar.this.setTitle(title); + } + + @Override + public void setLine(int line, String value) { + this.setLine(line, value, null); + } + + @Override + public void setLine(int line, String value, String display) { + Sidebar.this.setLine(line, value, display); + } + + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarBuffer.java b/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarBuffer.java new file mode 100644 index 0000000..fa4967a --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarBuffer.java @@ -0,0 +1,100 @@ +package gg.projecteden.parchment.sidebar; + +import org.bukkit.entity.Player; + +import java.util.Arrays; +import java.util.Objects; + +public abstract class SidebarBuffer { + + @SuppressWarnings("StringOperationCanBeSimplified") + private static final String AUTO_SPACE = new String(); + protected final String name; + protected final int size; + protected final String[] liveLines; + protected final String[] stagedLines; + protected final String[] liveDisplays; + protected final String[] stagedDisplays; + + protected String liveTitle = ""; + protected String stagedTitle = ""; + + protected SidebarBuffer(String name, int size) { + this.name = name; + this.size = size; + this.liveLines = new String[size]; + this.stagedLines = new String[size]; + this.liveDisplays = new String[size]; + this.stagedDisplays = new String[size]; + } + + protected abstract void setActive(); + + protected abstract void pushChanges(); + + protected abstract void setOwner(Player player); + + protected abstract boolean checkTitle(String title); + + protected abstract boolean checkLine(String line); + + void setTitle(String title) { + this.stagedTitle = Objects.requireNonNullElse(title, ""); + } + + void setLine(int line, String value, String display) { + Objects.requireNonNull(value); + if (line < 0 || line > this.size - 1) { + throw new IndexOutOfBoundsException(); + } + + this.stagedLines[line] = value; + this.stagedDisplays[line] = display; + + for (int i = line - 1; i >= 0; i--) { + if (this.stagedLines[i] == null) { + this.stagedLines[i] = SidebarBuffer.AUTO_SPACE; + } else { + break; + } + } + } + + void clearLine(int line) { + if (line < 0 || line > this.size - 1) { + throw new IndexOutOfBoundsException(); + } + + this.stagedLines[line] = SidebarBuffer.AUTO_SPACE; + + if (line + 1 == this.size || this.stagedLines[line + 1] == null) { + for (int i = line; i >= 0; i--) { + if (this.stagedLines[i] == SidebarBuffer.AUTO_SPACE) { + this.stagedLines[i] = null; + } else { + break; + } + } + } + } + + void sync(SidebarBuffer live) { + this.stagedTitle = live.liveTitle; + System.arraycopy(live.liveLines, 0, this.stagedLines, 0, this.size); + System.arraycopy(live.liveDisplays, 0, this.stagedDisplays, 0, this.size); + } + + void clear() { + this.stagedTitle = ""; + Arrays.fill(this.stagedLines, null); + Arrays.fill(this.stagedDisplays, null); + } + + boolean hasDiverged(SidebarBuffer live) { + boolean out = !Objects.equals(this.stagedTitle, live.liveTitle); + out = out || !Arrays.equals(this.stagedLines, live.liveLines); + out = out || !Arrays.equals(this.stagedDisplays, live.liveDisplays); + + return out; + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarBufferUtilSpec.java b/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarBufferUtilSpec.java new file mode 100644 index 0000000..ebe5df1 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarBufferUtilSpec.java @@ -0,0 +1,12 @@ +package gg.projecteden.parchment.sidebar; + +import gg.projecteden.parchment.entity.EntityDataServiceKey; +import org.bukkit.entity.Player; + +public interface SidebarBufferUtilSpec { + EntityDataServiceKey IMPL_KEY = new EntityDataServiceKey<>(SidebarBufferUtilSpec.class); + + SidebarBuffer create(String bufferName); + + void hideSidebar(Player player); +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarLayout.java b/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarLayout.java new file mode 100644 index 0000000..603de56 --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarLayout.java @@ -0,0 +1,58 @@ +package gg.projecteden.parchment.sidebar; + +import java.util.HashSet; +import java.util.Set; + +/** + * A sidebar layout. Subclasses can describe custom layouts by using the + * {@link #setup(SidebarStage)} and {@link #update(SidebarStage)} hooks. + */ +public abstract class SidebarLayout { + private final Set subscribers = new HashSet<>(); + + /** + * Pushes an update to all subscribers. + */ + public final void refresh() { + synchronized (this.subscribers) { + for (Runnable s : this.subscribers) { + s.run(); + } + } + } + + /** + * Runs when the layout is first applied. + * + *

The provided sidebar stage may be used to create the first + * frame of sidebar data, which will be pushed to the client upon + * exit of this method. + * + * @param stage The sidebar stage. Using it outside this method will + * result in undefined behavior. + */ + protected void setup(SidebarStage stage) { + } + + /** + * Runs when a refresh is requested. + * + *

The provided sidebar stage may be used to update the existing + * sidebar data, which will be pushed to the client upon exit of + * this method. Sidebar data from previous hook calls will stay the + * same unless explicitly changed here. + * + * @param stage The sidebar stage. Using it outside this method will + * result in undefined behavior. + */ + protected void update(SidebarStage stage) { + } + + final void subscribe(Runnable listener) { + this.subscribers.add(listener); + } + + final void unsubscribe(Runnable listener) { + this.subscribers.remove(listener); + } +} \ No newline at end of file diff --git a/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarStage.java b/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarStage.java new file mode 100644 index 0000000..e50616b --- /dev/null +++ b/parchment-api/src/main/java/gg/projecteden/parchment/sidebar/SidebarStage.java @@ -0,0 +1,32 @@ +package gg.projecteden.parchment.sidebar; + +/** + * An abstracted sidebar stage. + */ +public interface SidebarStage { + /** + * Stages a new title. + * + * @param title The new title. + */ + void setTitle(String title); + + /** + * Stages a new line at the provided index. + * + * @param line The line index. + * @param value The new line. + */ + void setLine(int line, String value); + + /** + * Stages a new line at the provided index + * Uses the display as the right aligned text + * + * @param line The line index + * @param value The new line + * @param display The right aligned text + */ + void setLine(int line, String value, String display); + +} \ No newline at end of file diff --git a/parchment-server/build.gradle.kts.patch b/parchment-server/build.gradle.kts.patch index 65387dc..dd04dc7 100644 --- a/parchment-server/build.gradle.kts.patch +++ b/parchment-server/build.gradle.kts.patch @@ -4,7 +4,7 @@ // macheOldPath = file("F:\\Projects\\PaperTooling\\mache\\versions\\1.21.4\\src\\main\\java") // gitFilePatches = true -+ val fork = forks.register("fork") { ++ val fork = forks.register("parchment") { + upstream.patchDir("paperServer") { + upstreamPath = "paper-server" + excludes = setOf("src/minecraft", "patches", "build.gradle.kts") @@ -52,3 +52,23 @@ implementation("ca.spottedleaf:concurrentutil:0.0.2") implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+ implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21 +@@ -192,14 +_,14 @@ + val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim() + attributes( + "Main-Class" to "org.bukkit.craftbukkit.Main", +- "Implementation-Title" to "Paper", ++ "Implementation-Title" to "Parchment", + "Implementation-Version" to implementationVersion, + "Implementation-Vendor" to date, +- "Specification-Title" to "Paper", ++ "Specification-Title" to "Parchment", + "Specification-Version" to project.version, +- "Specification-Vendor" to "Paper Team", +- "Brand-Id" to "papermc:paper", +- "Brand-Name" to "Paper", ++ "Specification-Vendor" to "Project Eden", ++ "Brand-Id" to "projectedengg:parchment", ++ "Brand-Name" to "Parchment", + "Build-Number" to (build ?: ""), + "Build-Time" to buildTime.toString(), + "Git-Branch" to gitBranch, diff --git a/parchment-server/src/main/java/gg/projecteden/parchment/entity/EntityDataServices.java b/parchment-server/src/main/java/gg/projecteden/parchment/entity/EntityDataServices.java new file mode 100644 index 0000000..855a077 --- /dev/null +++ b/parchment-server/src/main/java/gg/projecteden/parchment/entity/EntityDataServices.java @@ -0,0 +1,20 @@ +package gg.projecteden.parchment.entity; + +import gg.projecteden.parchment.sidebar.SidebarBufferUtil; +import gg.projecteden.parchment.sidebar.SidebarBufferUtilSpec; + +public class EntityDataServices { + + private static boolean initialized; + + public static void init() { + if (initialized) { + throw new RuntimeException("EntityData Services already initialized"); + } + initialized = true; + + // Initialize Services Here + SidebarBufferUtilSpec.IMPL_KEY.set(new SidebarBufferUtil()); + } + +} \ No newline at end of file diff --git a/parchment-server/src/main/java/gg/projecteden/parchment/event/sound/ParchmentSoundEvent.java b/parchment-server/src/main/java/gg/projecteden/parchment/event/sound/ParchmentSoundEvent.java new file mode 100644 index 0000000..d389920 --- /dev/null +++ b/parchment-server/src/main/java/gg/projecteden/parchment/event/sound/ParchmentSoundEvent.java @@ -0,0 +1,28 @@ +package gg.projecteden.parchment.event.sound; + +import io.papermc.paper.adventure.PaperAdventure; +import net.kyori.adventure.sound.Sound; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import org.bukkit.Location; + +import java.util.Optional; +import java.util.function.Function; + +public class ParchmentSoundEvent { + public static final Function DISTANCE_FUNCTION = sound -> { + Optional soundEvent = PaperAdventure.asVanillaSound(sound.name()); + if (soundEvent.isPresent()) + return Double.valueOf(soundEvent.get().getRange(sound.volume())); + return gg.projecteden.parchment.event.sound.SoundEvent.DEFAULT_DISTANCE_FUNCTION.apply(sound); + }; + + public static gg.projecteden.parchment.event.sound.SoundEvent.Emitter createEmitter(Level level, double x, double y, double z) { + return new gg.projecteden.parchment.event.sound.SoundEvent.LocationEmitter(new Location(level.getWorld(), x, y, z)); + } + + public static gg.projecteden.parchment.event.sound.SoundEvent.Emitter createEmitter(Entity entity) { + return new gg.projecteden.parchment.event.sound.SoundEvent.EntityEmitter(entity.getBukkitEntity()); + } +} \ No newline at end of file diff --git a/parchment-server/src/main/java/gg/projecteden/parchment/inventory/CraftRecipeType.java b/parchment-server/src/main/java/gg/projecteden/parchment/inventory/CraftRecipeType.java new file mode 100644 index 0000000..41834f5 --- /dev/null +++ b/parchment-server/src/main/java/gg/projecteden/parchment/inventory/CraftRecipeType.java @@ -0,0 +1,44 @@ +package gg.projecteden.parchment.inventory; + +import net.minecraft.world.item.crafting.AbstractCookingRecipe; + +public class CraftRecipeType { + public static net.minecraft.world.item.crafting.RecipeType asNMS(RecipeType recipeType) { + return switch (recipeType) { + case CRAFTING -> net.minecraft.world.item.crafting.RecipeType.CRAFTING; + case SMELTING -> net.minecraft.world.item.crafting.RecipeType.SMELTING; + case BLASTING -> net.minecraft.world.item.crafting.RecipeType.BLASTING; + case SMOKING -> net.minecraft.world.item.crafting.RecipeType.SMOKING; + case CAMPFIRE_COOKING -> net.minecraft.world.item.crafting.RecipeType.CAMPFIRE_COOKING; + case STONECUTTING -> net.minecraft.world.item.crafting.RecipeType.STONECUTTING; + case SMITHING -> net.minecraft.world.item.crafting.RecipeType.SMITHING; + }; + } + + public static RecipeType asBukkit(net.minecraft.world.item.crafting.RecipeType recipeType) { + if (recipeType == net.minecraft.world.item.crafting.RecipeType.CRAFTING) { + return RecipeType.CRAFTING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.SMELTING) { + return RecipeType.SMELTING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.BLASTING) { + return RecipeType.BLASTING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.SMOKING) { + return RecipeType.SMOKING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.CAMPFIRE_COOKING) { + return RecipeType.CAMPFIRE_COOKING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.STONECUTTING) { + return RecipeType.STONECUTTING; + } else if (recipeType == net.minecraft.world.item.crafting.RecipeType.SMITHING) { + return RecipeType.SMITHING; + } + throw new IllegalArgumentException("Unknown recipe type"); + } + + public static net.minecraft.world.item.crafting.RecipeType asCookingRecipe(RecipeType recipeType) { + try { + return (net.minecraft.world.item.crafting.RecipeType) asNMS(recipeType); + } catch (ClassCastException exc) { + throw new IllegalArgumentException("Recipe type must be a cooking recipe"); + } + } +} \ No newline at end of file diff --git a/parchment-server/src/main/java/gg/projecteden/parchment/inventory/SingletonContainer.java b/parchment-server/src/main/java/gg/projecteden/parchment/inventory/SingletonContainer.java new file mode 100644 index 0000000..eb3af46 --- /dev/null +++ b/parchment-server/src/main/java/gg/projecteden/parchment/inventory/SingletonContainer.java @@ -0,0 +1,151 @@ +package gg.projecteden.parchment.inventory; + +import com.google.common.base.Preconditions; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * A container which holds only one item and returns similar values to that of + * {@link net.minecraft.world.SimpleContainer SimpleContainer}, meaning it will raise + * {@link IndexOutOfBoundsException IndexOutOfBoundsExceptions} and return empty item stacks + * where applicable to mirror that class. + */ +public class SingletonContainer implements net.minecraft.world.Container { + + private @NotNull ItemStack item; + private int maxStackSize = Container.MAX_STACK; + + public SingletonContainer() { + this.item = ItemStack.EMPTY; + } + + public SingletonContainer(@NotNull ItemStack item) { + this.item = Preconditions.checkNotNull(item, "item"); + } + + public SingletonContainer(org.bukkit.inventory.@NotNull ItemStack item) { + this.item = CraftItemStack.asNMSCopy(Preconditions.checkNotNull(item, "item")); + } + + public SingletonContainer(@NotNull Material material) { + this(new org.bukkit.inventory.ItemStack(Preconditions.checkNotNull(material, "material"))); + } + + private static void throwIndexException(int index) { + throw new IndexOutOfBoundsException("Received slot " + index + ", expected 0"); + } + + @Override + public int getContainerSize() { + return 1; + } + + @Override + public boolean isEmpty() { + return item.isEmpty(); + } + + @Override + public ItemStack getItem(int slot) { + if (slot < 0) { + throwIndexException(slot); + } + return slot == 0 ? item : ItemStack.EMPTY; + } + + @Override + public ItemStack removeItem(int slot, int amount) { + if (slot < 0) { + throwIndexException(slot); + } + ItemStack itemStack = slot == 0 && !item.isEmpty() ? item.split(amount) : ItemStack.EMPTY; + if (!itemStack.isEmpty()) { + setChanged(); + } + return itemStack; + } + + @Override + public ItemStack removeItemNoUpdate(int slot) { + if (slot != 0) { + throwIndexException(slot); + } + ItemStack oldItem = item; + item = ItemStack.EMPTY; + return oldItem.isEmpty() ? ItemStack.EMPTY : oldItem; + } + + @Override + public void setItem(int slot, ItemStack stack) { + if (slot != 0) { + throwIndexException(slot); + } + item = stack; + } + + @Override + public int getMaxStackSize() { + return maxStackSize; + } + + @Override + public void setMaxStackSize(int size) { + maxStackSize = size; + } + + @Override + public void setChanged() { + + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public List getContents() { + return Collections.singletonList(item); + } + + @Override + public void onOpen(CraftHumanEntity who) { + + } + + @Override + public void onClose(CraftHumanEntity who) { + + } + + @Override + public List getViewers() { + return Collections.emptyList(); + } + + @Override + public InventoryHolder getOwner() { + return null; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public void clearContent() { + item = ItemStack.EMPTY; + } +} \ No newline at end of file diff --git a/parchment-server/src/main/java/gg/projecteden/parchment/sidebar/SidebarBufferImpl.java b/parchment-server/src/main/java/gg/projecteden/parchment/sidebar/SidebarBufferImpl.java new file mode 100644 index 0000000..d3035dd --- /dev/null +++ b/parchment-server/src/main/java/gg/projecteden/parchment/sidebar/SidebarBufferImpl.java @@ -0,0 +1,182 @@ +package gg.projecteden.parchment.sidebar; + +import gg.projecteden.parchment.util.StringUtils; +import net.minecraft.network.Connection; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.numbers.BlankFormat; +import net.minecraft.network.chat.numbers.FixedFormat; +import net.minecraft.network.chat.numbers.NumberFormat; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.world.scores.DisplaySlot; +import net.minecraft.world.scores.Objective; +import net.minecraft.world.scores.PlayerTeam; +import net.minecraft.world.scores.Team; +import net.minecraft.world.scores.criteria.ObjectiveCriteria; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Objects; +import java.util.Optional; + +public class SidebarBufferImpl extends SidebarBuffer { + + private static final int NAME_LIMIT = 38; + private static final int AFFIX_LIMIT = 16; + private static final int SIZE = 15; + + static final int SIDEBAR_SLOT = 1; + private final Objective objective = new Objective(DedicatedServer.getServer().getScoreboard(), this.name, + ObjectiveCriteria.DUMMY, Component.literal(this.stagedTitle), ObjectiveCriteria.RenderType.INTEGER, + false, null); + + private Connection connection; + + SidebarBufferImpl(String name) { + super(name, SidebarBufferImpl.SIZE); + } + + protected void setActive() { + objective.setDisplayName(Component.literal(StringUtils.colorize(this.stagedTitle))); + ClientboundSetObjectivePacket packet = new ClientboundSetObjectivePacket(this.objective, ClientboundSetObjectivePacket.METHOD_CHANGE); + ClientboundSetDisplayObjectivePacket packet2 = new ClientboundSetDisplayObjectivePacket(DisplaySlot.SIDEBAR, this.objective); + + this.connection.send(packet); + this.connection.send(packet2); + } + + protected void pushChanges() { + if (!Objects.equals(this.liveTitle, this.stagedTitle)) { + this.liveTitle = this.stagedTitle; + + ClientboundSetObjectivePacket packet = new ClientboundSetObjectivePacket(this.objective, ClientboundSetObjectivePacket.METHOD_CHANGE); + + this.connection.send(packet); + } + + int liveEnd = this.size; + for (int i = 0; i < this.size; i++) { + if (this.liveLines[i] == null) { + liveEnd = i; + break; + } + } + + int stagedEnd = this.size; + for (int i = 0; i < this.size; i++) { + if (this.stagedLines[i] == null) { + stagedEnd = i; + break; + } + } + + int maxEnd = Math.max(liveEnd, stagedEnd); + int liveIdx = liveEnd - maxEnd; + int stagedIdx = stagedEnd - maxEnd; + + for (int i = 0; i < this.size; i++) { + String live = liveIdx >= 0 ? this.liveLines[liveIdx] : null; + String staged = stagedIdx >= 0 ? this.stagedLines[stagedIdx] : null; + + String liveDisplay = liveIdx >= 0 ? this.liveDisplays[liveIdx] : null; + String stagedDisplay = stagedIdx >= 0 ? this.stagedDisplays[stagedIdx] : null; + + if (!Objects.equals(live, staged) || !Objects.equals(liveDisplay, stagedDisplay)) { + if (live != null) { + this.sendDelete(live, liveEnd - liveIdx); + } + + if (staged != null) { + this.sendCreate(staged, stagedEnd - stagedIdx, this.stagedDisplays[stagedIdx]); + } + } + + liveIdx++; + stagedIdx++; + } + + System.arraycopy(this.stagedLines, 0, this.liveLines, 0, this.size); + System.arraycopy(this.stagedDisplays, 0, this.liveDisplays, 0, this.size); + } + + @Override + protected void setOwner(Player player) { + this.connection = ((CraftPlayer) player).getHandle().connection.connection; + + ClientboundSetObjectivePacket packet = new ClientboundSetObjectivePacket(this.objective, ClientboundSetObjectivePacket.METHOD_ADD); + this.connection.send(packet); + + for (int i = 0; i < this.size; i++) { + String live = this.liveLines[i]; + + if (live != null) { + this.sendCreate(live, i, stagedDisplays[i]); + } + } + } + + @Override + protected boolean checkTitle(String line) { + return line.length() <= 32; + } + + @Override + protected boolean checkLine(String line) { + return line.length() <= SidebarBufferImpl.NAME_LIMIT + SidebarBufferImpl.AFFIX_LIMIT * 2; + } + + private void sendCreate(String value, int line, String display) { + String id = "\u00a7" + (char) ('\u0080' + line); + value = StringUtils.colorize(value); + + if (value.length() > SidebarBufferImpl.NAME_LIMIT) { + String prefix = value.substring(0, SidebarBufferImpl.AFFIX_LIMIT); + String suffix = ""; + + value = value.substring(SidebarBufferImpl.AFFIX_LIMIT); + + if (value.length() > SidebarBufferImpl.NAME_LIMIT) { + suffix = value.substring(SidebarBufferImpl.NAME_LIMIT); + value = value.substring(0, SidebarBufferImpl.NAME_LIMIT); + } + + PlayerTeam team = new PlayerTeam(DedicatedServer.getServer().getScoreboard(), this.getTeamName(line)); + team.setPlayerPrefix(Component.literal(prefix)); + team.setPlayerSuffix(Component.literal(suffix)); + team.setNameTagVisibility(Team.Visibility.NEVER); + team.setCollisionRule(Team.CollisionRule.NEVER); + team.getPlayers().add(id + value); + ClientboundSetPlayerTeamPacket packet = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true); + + this.connection.send(packet); + } + + java.util.Optional numberFormat = java.util.Optional.of((display == null || display.isEmpty() || display.isBlank()) ? BlankFormat.INSTANCE : new FixedFormat(Component.literal(StringUtils.colorize(display)))); + ClientboundSetScorePacket packet = new ClientboundSetScorePacket(id + value, this.name, line, Optional.empty(), numberFormat); + + this.connection.send(packet); + } + + private void sendDelete(String value, int line) { + String id = "\u00a7" + (char) ('\u0080' + line); + + value = StringUtils.colorize(value); + + if (value.length() > SidebarBufferImpl.NAME_LIMIT) { + value = value.substring( + SidebarBufferImpl.AFFIX_LIMIT, + Math.min(value.length(), SidebarBufferImpl.AFFIX_LIMIT + SidebarBufferImpl.NAME_LIMIT) + ); + + ClientboundSetPlayerTeamPacket packet = ClientboundSetPlayerTeamPacket.createRemovePacket(DedicatedServer.getServer().getScoreboard().getPlayerTeam(this.getTeamName(line))); + this.connection.send(packet); + } + + ClientboundResetScorePacket packet = new ClientboundResetScorePacket(id + value, this.name); + this.connection.send(packet); + } + + private String getTeamName(int line) { + return this.name + "/" + Integer.toUnsignedString(line, 32); + } +} \ No newline at end of file diff --git a/parchment-server/src/main/java/gg/projecteden/parchment/sidebar/SidebarBufferUtil.java b/parchment-server/src/main/java/gg/projecteden/parchment/sidebar/SidebarBufferUtil.java new file mode 100644 index 0000000..c802513 --- /dev/null +++ b/parchment-server/src/main/java/gg/projecteden/parchment/sidebar/SidebarBufferUtil.java @@ -0,0 +1,19 @@ +package gg.projecteden.parchment.sidebar; + +import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket; +import net.minecraft.world.scores.DisplaySlot; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class SidebarBufferUtil implements SidebarBufferUtilSpec { + @Override + public SidebarBuffer create(String name) { + return new SidebarBufferImpl(name); + } + + @Override + public void hideSidebar(Player player) { + ClientboundSetDisplayObjectivePacket packet = new ClientboundSetDisplayObjectivePacket(DisplaySlot.SIDEBAR, null); + ((CraftPlayer) player).getHandle().connection.send(packet); + } +} \ No newline at end of file diff --git a/parchment-server/src/main/java/gg/projecteden/parchment/util/StringUtils.java b/parchment-server/src/main/java/gg/projecteden/parchment/util/StringUtils.java new file mode 100644 index 0000000..e61e907 --- /dev/null +++ b/parchment-server/src/main/java/gg/projecteden/parchment/util/StringUtils.java @@ -0,0 +1,30 @@ +package gg.projecteden.parchment.util; + +import net.md_5.bungee.api.ChatColor; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class StringUtils { + + private static final String colorChar = "ยง"; + private static final String altColorChar = "&"; + private static final String colorCharsRegex = "[" + colorChar + altColorChar + "]"; + private static final Pattern hexPattern = Pattern.compile(colorCharsRegex + "#[a-fA-F\\d]{6}"); + + public static String colorize(String input) { + if (input == null) + return null; + + while (true) { + Matcher matcher = hexPattern.matcher(input); + if (!matcher.find()) break; + + String color = matcher.group(); + input = input.replace(color, ChatColor.of(color.replaceFirst(colorCharsRegex, "")).toString()); + } + + return ChatColor.translateAlternateColorCodes(altColorChar.charAt(0), input); + } + +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index fb5080d..25aa807 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,7 +10,7 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0" } -rootProject.name = "fork" +rootProject.name = "Parchment" -include("fork-api") -include("fork-server") +include("parchment-api") +include("parchment-server")