Merge branch 'ver/1.21.11' into feat/lightning-affects-blocks

This commit is contained in:
granny
2025-12-17 20:22:53 -08:00
796 changed files with 38036 additions and 49832 deletions

View File

@@ -0,0 +1,55 @@
--- a/paper-api/build.gradle.kts
+++ b/paper-api/build.gradle.kts
@@ -91,7 +_,7 @@
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
-val generatedDir: java.nio.file.Path = layout.projectDirectory.dir("src/generated/java").asFile.toPath()
+val generatedDir: java.nio.file.Path = rootProject.layout.projectDirectory.dir("paper-api/src/generated/java").asFile.toPath()
idea {
module {
generatedSourceDirs.add(generatedDir.toFile())
@@ -101,6 +_,18 @@
main {
java {
srcDir(generatedDir)
+ srcDir(file("../paper-api/src/main/java"))
+ }
+ resources {
+ srcDir(file("../paper-api/src/main/resources"))
+ }
+ }
+ test {
+ java {
+ srcDir(file("../paper-api/src/test/java"))
+ }
+ resources {
+ srcDir(file("../paper-api/src/test/resources"))
}
}
}
@@ -182,8 +_,9 @@
val services = objects.newInstance<Services>()
tasks.withType<Javadoc>().configureEach {
+ (options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet") // Purpur - silence Paper's bajillion javadoc warnings
val options = options as StandardJavadocDocletOptions
- options.overview = "src/main/javadoc/overview.html"
+ options.overview = "../paper-api/src/main/javadoc/overview.html"
options.use()
options.isDocFilesSubDirs = true
options.links(
@@ -216,11 +_,11 @@
}
// workaround for https://github.com/gradle/gradle/issues/4046
- inputs.dir("src/main/javadoc").withPropertyName("javadoc-sourceset")
+ inputs.dir("../paper-api/src/main/javadoc").withPropertyName("javadoc-sourceset")
val fsOps = services.fileSystemOperations
doLast {
fsOps.copy {
- from("src/main/javadoc") {
+ from("../paper-api/src/main/javadoc") {
include("**/doc-files/**")
}
into("build/docs/javadoc")

View File

@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: granny <granny@purpurmc.org>
Date: Thu, 16 May 2024 19:11:29 -0700
Subject: [PATCH] Rebrand
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfo.java b/src/main/java/io/papermc/paper/ServerBuildInfo.java
index 652ff54e7c50412503725d628bfe72ed03059790..fb1fe2651e53a9bf46b3632c638e13eea9dcda93 100644
--- a/src/main/java/io/papermc/paper/ServerBuildInfo.java
+++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java
@@ -19,6 +19,12 @@ public interface ServerBuildInfo {
*/
Key BRAND_PAPER_ID = Key.key("papermc", "paper");
+ // Purpur start
+ /**
+ * The brand id for Purpur.
+ */
+ Key BRAND_PURPUR_ID = Key.key("purpurmc", "purpur");
+ // Purpur end
/**
* Gets the {@code ServerBuildInfo}.
*

View File

@@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Tue, 18 Feb 2020 20:30:03 -0600
Subject: [PATCH] Purpur config files
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index bd8123503132b742d873c18486c3d19024fb9898..a17790d2da3008927b79814629e073b2091ce421 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2425,6 +2425,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
}
// Paper end
+ // Purpur start
+ @NotNull
+ public org.bukkit.configuration.file.YamlConfiguration getPurpurConfig() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @NotNull
+ public java.util.Properties getServerProperties() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ // Purpur end
+
/**
* Sends the component to the player
*

View File

@@ -0,0 +1,57 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: granny <contact@granny.dev>
Date: Wed, 17 Dec 2025 20:20:00 -0800
Subject: [PATCH] lightning transforms blocks
diff --git a/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java b/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java
index a16aadadae7b70a8f3140478feb8846b7fec13ff..e79db0f2e80fc2a5521f9ccc34009f31c4baa04f 100644
--- a/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java
+++ b/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java
@@ -16,6 +16,7 @@ public class LightningStrikeEvent extends WeatherEvent implements Cancellable {
private final LightningStrike bolt;
private final Cause cause;
+ private final java.util.List<org.bukkit.block.BlockState> blocks; // Purpur - lightning transforms blocks
private boolean cancelled;
@@ -27,9 +28,16 @@ public class LightningStrikeEvent extends WeatherEvent implements Cancellable {
@ApiStatus.Internal
public LightningStrikeEvent(@NotNull final World world, @NotNull final LightningStrike bolt, @NotNull final Cause cause) {
+ // Purpur start - lightning transforms blocks
+ this(world, bolt, cause, new java.util.ArrayList<>());
+ }
+ @ApiStatus.Internal
+ public LightningStrikeEvent(@NotNull final World world, @NotNull final LightningStrike bolt, @NotNull final Cause cause, @NotNull final java.util.List<org.bukkit.block.BlockState> blocks) {
+ // Purpur end - lightning transforms blocks
super(world);
this.bolt = bolt;
this.cause = cause;
+ this.blocks = blocks; // Purpur - lightning transforms blocks
}
/**
@@ -62,6 +70,21 @@ public class LightningStrikeEvent extends WeatherEvent implements Cancellable {
this.cancelled = cancel;
}
+ // Purpur start - lightning transforms blocks
+ /**
+ * Get a list of all blocks that will be modified by the lightning strike.
+ * <br>
+ * This list is mutable and contains the blocks in their changed state, i.e.
+ * having a type of {@link org.bukkit.Material#GLASS}.
+ *
+ * @return list of the modified blocks.
+ */
+ @NotNull
+ public java.util.List<org.bukkit.block.BlockState> getBlocks() {
+ return blocks;
+ }
+ // Purpur end - lightning transforms blocks
+
@NotNull
@Override
public HandlerList getHandlers() {

View File

@@ -0,0 +1,29 @@
--- a/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java
+++ b/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java
@@ -450,6 +_,26 @@
GoalKey<Zombie> ZOMBIE_ATTACK_TURTLE_EGG = create("zombie_attack_turtle_egg", Zombie.class);
+ // Purpur start - Ridables
+ GoalKey<Mob> MOB_HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider"));
+ GoalKey<AbstractHorse> HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider"));
+ GoalKey<Llama> LLAMA_HAS_RIDER = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_has_rider"));
+ // Purpur end - Ridables
+ // Purpur start - Phantoms attracted to crystals and crystals shoot phantoms
+ GoalKey<Phantom> FIND_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal"));
+ GoalKey<Phantom> ORBIT_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal"));
+ // Purpur end - Phantoms attracted to crystals and crystals shoot phantoms
+ // Purpur start - Add option to disable zombie aggressiveness towards villagers when lagging
+ GoalKey<Drowned> DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager"));
+ GoalKey<Zombie> ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager"));
+ // Purpur end - Add option to disable zombie aggressiveness towards villagers when lagging
+ // Purpur start - Configurable chance for wolves to spawn rabid
+ GoalKey<Wolf> AVOID_RABID_WOLF = GoalKey.of(Wolf.class, NamespacedKey.minecraft("avoid_rabid_wolf"));
+ // Purpur end - Configurable chance for wolves to spawn rabid
+ // Purpur start - Iron golem poppy calms anger
+ GoalKey<IronGolem> RECEIVE_FLOWER = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("receive_flower"));
+ // Purpur end - Iron golem poppy calms anger
+
private static <T extends Mob> GoalKey<T> create(final String key, final Class<T> type) {
return GoalKey.of(type, NamespacedKey.minecraft(key));
}

View File

@@ -0,0 +1,14 @@
--- a/src/main/java/co/aikar/timings/TimedEventExecutor.java
+++ b/src/main/java/co/aikar/timings/TimedEventExecutor.java
@@ -80,9 +_,9 @@
executor.execute(listener, event);
return;
}
- try (Timing ignored = timings.startTiming()){
+ //try (Timing ignored = timings.startTiming()){ // Purpur - Remove Timings
executor.execute(listener, event);
- }
+ //} // Purpur - Remove Timings
}
@Override

View File

@@ -0,0 +1,48 @@
--- a/src/main/java/co/aikar/timings/Timing.java
+++ b/src/main/java/co/aikar/timings/Timing.java
@@ -39,6 +_,7 @@
* @return Timing
*/
@NotNull
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
Timing startTiming();
/**
@@ -46,6 +_,7 @@
*
* Will automatically be called when this Timing is used with try-with-resources
*/
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
void stopTiming();
/**
@@ -56,6 +_,7 @@
* @return Timing
*/
@NotNull
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
Timing startTimingIfSync();
/**
@@ -65,12 +_,14 @@
*
* But only if we are on the primary thread.
*/
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
void stopTimingIfSync();
/**
* @deprecated Doesn't do anything - Removed
*/
@Deprecated
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
void abort();
/**
@@ -82,5 +_,6 @@
TimingHandler getTimingHandler();
@Override
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
void close();
}

View File

@@ -0,0 +1,25 @@
--- a/src/main/java/co/aikar/timings/Timings.java
+++ b/src/main/java/co/aikar/timings/Timings.java
@@ -124,7 +_,7 @@
@NotNull
public static Timing ofStart(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) {
Timing timing = of(plugin, name, groupHandler);
- timing.startTiming();
+ //timing.startTiming(); // Purpur - Remove Timings
return timing;
}
@@ -146,7 +_,7 @@
*/
public static void setTimingsEnabled(boolean enabled) {
if (enabled && !warnedAboutDeprecationOnEnable) {
- Bukkit.getLogger().severe(PlainTextComponentSerializer.plainText().serialize(deprecationMessage()));
+ //Bukkit.getLogger().severe(PlainTextComponentSerializer.plainText().serialize(deprecationMessage())); // Purpur - Remove Timings
warnedAboutDeprecationOnEnable = true;
}
}
@@ -322,4 +_,3 @@
return TimingsManager.getHandler(groupName, name, groupHandler);
}
}
-

View File

@@ -0,0 +1,34 @@
--- a/src/main/java/co/aikar/timings/TimingsCommand.java
+++ b/src/main/java/co/aikar/timings/TimingsCommand.java
@@ -47,7 +_,7 @@
public TimingsCommand(@NotNull String name) {
super(name);
this.description = "Manages Spigot Timings data to see performance of the server.";
- this.usageMessage = "/timings <reset|report|on|off|verbon|verboff>";
+ this.usageMessage = "/timings";// <reset|report|on|off|verbon|verboff>"; // Purpur - Remove Timings
this.setPermission("bukkit.command.timings");
}
@@ -57,7 +_,12 @@
return true;
}
if (true) {
- sender.sendMessage(Timings.deprecationMessage());
+ // Purpur start - Remove Timings
+ net.kyori.adventure.text.minimessage.MiniMessage mm = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage();
+ sender.sendMessage(mm.deserialize("<gold>Purpur has removed timings to save your performance. Please use <click:suggest_command:'/spark'><grey>/spark</grey></click> instead"));
+ sender.sendMessage(mm.deserialize("<gold>For more information, view its documentation at"));
+ sender.sendMessage(mm.deserialize("<gold><click:open_url:'https://spark.lucko.me/docs/Command-Usage'>https://spark.lucko.me/docs/Command-Usage</click>"));
+ // Purpur end - Remove Timings
return true;
}
if (args.length < 1) {
@@ -118,7 +_,7 @@
Preconditions.checkNotNull(args, "Arguments cannot be null");
Preconditions.checkNotNull(alias, "Alias cannot be null");
- if (args.length == 1) {
+ if (false && args.length == 1) { // Purpur - Remove Timings
return StringUtil.copyPartialMatches(args[0], TIMINGS_SUBCOMMANDS,
new ArrayList<String>(TIMINGS_SUBCOMMANDS.size()));
}

View File

@@ -0,0 +1,15 @@
--- a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java
+++ b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java
@@ -40,6 +_,12 @@
return getVersionMessage();
}
+ // Purpur start
+ default int distance() {
+ return 0;
+ }
+ // Purpur end
+
/**
* @hidden
*/

View File

@@ -0,0 +1,150 @@
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -3003,4 +_,147 @@
public static void restart() {
server.restart();
}
+
+ // Purpur start - Bring back server name
+ /**
+ * Get the name of this server
+ * @return the name of the server
+ */
+ @NotNull
+ public static String getServerName() {
+ return server.getServerName();
+ }
+ // Purpur end - Bring back server name
+
+ // Purpur start - Lagging threshold
+ /**
+ * Check if server is lagging according to laggy threshold setting
+ *
+ * @return True if lagging
+ */
+ public static boolean isLagging() {
+ return server.isLagging();
+ }
+ // Purpur end - Lagging threshold
+
+ // Purpur start - Added the ability to add combustible items
+ /**
+ * Add an Item as fuel for furnaces
+ *
+ * @param material The material that will be the fuel
+ * @param burnTime The time (in ticks) this item will burn for
+ */
+ public static void addFuel(@NotNull Material material, int burnTime) {
+ server.addFuel(material, burnTime);
+ }
+
+ /**
+ * Remove an item as fuel for furnaces
+ *
+ * @param material The material that will no longer be a fuel
+ */
+ public static void removeFuel(@NotNull Material material) {
+ server.removeFuel(material);
+ }
+ // Purpur end - Added the ability to add combustible items
+
+ // Purpur start - Debug Marker API
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration) {
+ server.sendBlockHighlight(location, duration);
+ }
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration, int argb) {
+ server.sendBlockHighlight(location, duration, argb);
+ }
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text) {
+ server.sendBlockHighlight(location, duration, text);
+ }
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb) {
+ server.sendBlockHighlight(location, duration, text, argb);
+ }
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency) {
+ server.sendBlockHighlight(location, duration, color, transparency);
+ }
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency) {
+ server.sendBlockHighlight(location, duration, text, color, transparency);
+ }
+
+ /**
+ * Clears all debug block highlights for all players on the server.
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ public static void clearBlockHighlights() {
+ server.clearBlockHighlights();
+ }
+ // Purpur end - Debug Marker API
}

View File

@@ -0,0 +1,80 @@
--- a/src/main/java/org/bukkit/ChatColor.java
+++ b/src/main/java/org/bukkit/ChatColor.java
@@ -456,4 +_,77 @@
BY_CHAR.put(color.code, color);
}
}
+
+ // Purpur start - ChatColor conveniences
+ /**
+ * Convert legacy string into a string ready to be parsed by MiniMessage
+ *
+ * @param str Legacy string
+ * @return MiniMessage ready string
+ */
+ @NotNull
+ public static String toMM(@NotNull String str) {
+ StringBuilder sb = new StringBuilder(str);
+ java.util.regex.Matcher m = STRIP_COLOR_PATTERN.matcher(sb);
+ while (m.find()) {
+ sb.replace(m.start(), m.end(), sb.substring(m.start(), m.end()).toLowerCase());
+ }
+ return sb.toString()
+ .replace("&0", "<black>")
+ .replace("&1", "<dark_blue>")
+ .replace("&2", "<dark_green>")
+ .replace("&3", "<dark_aqua>")
+ .replace("&4", "<dark_red>")
+ .replace("&5", "<dark_purple>")
+ .replace("&6", "<gold>")
+ .replace("&7", "<grey>")
+ .replace("&8", "<dark_grey>")
+ .replace("&9", "<blue>")
+ .replace("&a", "<green>")
+ .replace("&b", "<aqua>")
+ .replace("&c", "<red>")
+ .replace("&d", "<light_purple>")
+ .replace("&e", "<yellow>")
+ .replace("&f", "<white>")
+ .replace("&k", "<obf>")
+ .replace("&l", "<b>")
+ .replace("&m", "<st>")
+ .replace("&n", "<u>")
+ .replace("&o", "<i>")
+ .replace("&r", "<r>");
+ }
+
+ @NotNull
+ public static net.kyori.adventure.text.Component parseMM(@NotNull String string, @Nullable Object... args) {
+ return net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(String.format(string, args));
+ }
+
+ @Deprecated
+ public static final Pattern HEX_PATTERN = Pattern.compile("(#[A-Fa-f0-9]{6})");
+
+ @Deprecated
+ @Nullable
+ public static String replaceHex(@Nullable String str) {
+ if (str != null) {
+ java.util.regex.Matcher matcher = HEX_PATTERN.matcher(str);
+ while (matcher.find()) {
+ String group = matcher.group(1);
+ str = str.replace(group, net.md_5.bungee.api.ChatColor.of(group).toString());
+ }
+ }
+ return str;
+ }
+
+ @Deprecated
+ @Nullable
+ public static String color(@Nullable String str) {
+ return color(str, true);
+ }
+
+ @Deprecated
+ @Nullable
+ public static String color(@Nullable String str, boolean parseHex) {
+ return str != null ? net.md_5.bungee.api.ChatColor.translateAlternateColorCodes('&', parseHex ? replaceHex(str) : str) : str;
+ }
+ // Purpur end - ChatColor conveniences
}

View File

@@ -0,0 +1,43 @@
--- a/src/main/java/org/bukkit/Material.java
+++ b/src/main/java/org/bukkit/Material.java
@@ -3708,4 +_,40 @@
return this.asItemType().getDefaultDataTypes();
}
// Paper end - data component API
+
+ // Purpur start - ItemStack convenience methods
+ public boolean isArmor() {
+ switch (this) {
+ // <editor-fold defaultstate="collapsed" desc="isarmor">
+ case LEATHER_BOOTS:
+ case LEATHER_CHESTPLATE:
+ case LEATHER_HELMET:
+ case LEATHER_LEGGINGS:
+ case CHAINMAIL_BOOTS:
+ case CHAINMAIL_CHESTPLATE:
+ case CHAINMAIL_HELMET:
+ case CHAINMAIL_LEGGINGS:
+ case IRON_BOOTS:
+ case IRON_CHESTPLATE:
+ case IRON_HELMET:
+ case IRON_LEGGINGS:
+ case GOLDEN_BOOTS:
+ case GOLDEN_CHESTPLATE:
+ case GOLDEN_HELMET:
+ case GOLDEN_LEGGINGS:
+ case DIAMOND_BOOTS:
+ case DIAMOND_CHESTPLATE:
+ case DIAMOND_HELMET:
+ case DIAMOND_LEGGINGS:
+ case NETHERITE_BOOTS:
+ case NETHERITE_CHESTPLATE:
+ case NETHERITE_HELMET:
+ case NETHERITE_LEGGINGS:
+ case TURTLE_HELMET:
+ return true;
+ default:
+ return false;
+ }
+ }
+ // Purpur end - ItemStack convenience methods
}

View File

@@ -0,0 +1,107 @@
--- a/src/main/java/org/bukkit/OfflinePlayer.java
+++ b/src/main/java/org/bukkit/OfflinePlayer.java
@@ -592,4 +_,104 @@
default void applySkinToPlayerHeadContents(final PlayerHeadObjectContents.@NonNull Builder builder) {
builder.id(this.getUniqueId());
}
+
+ // Purpur start - OfflinePlayer API
+ /**
+ * Determines if the OfflinePlayer is allowed to fly via jump key double-tap like
+ * in creative mode.
+ *
+ * @return True if the player is allowed to fly.
+ */
+ boolean getAllowFlight();
+
+ /**
+ * Sets if the OfflinePlayer is allowed to fly via jump key double-tap like in
+ * creative mode.
+ *
+ * @param flight If flight should be allowed.
+ */
+ void setAllowFlight(boolean flight);
+
+ /**
+ * Checks to see if this player is currently flying or not.
+ *
+ * @return True if the player is flying, else false.
+ */
+ boolean isFlying();
+
+ /**
+ * Makes this player start or stop flying.
+ *
+ * @param value True to fly.
+ */
+ void setFlying(boolean value);
+
+ /**
+ * Sets the speed at which a client will fly. Negative values indicate
+ * reverse directions.
+ *
+ * @param value The new speed, from -1 to 1.
+ * @throws IllegalArgumentException If new speed is less than -1 or
+ * greater than 1
+ */
+ void setFlySpeed(float value) throws IllegalArgumentException;
+
+ /**
+ * Sets the speed at which a client will walk. Negative values indicate
+ * reverse directions.
+ *
+ * @param value The new speed, from -1 to 1.
+ * @throws IllegalArgumentException If new speed is less than -1 or
+ * greater than 1
+ */
+ void setWalkSpeed(float value) throws IllegalArgumentException;
+
+ /**
+ * Gets the current allowed speed that a client can fly.
+ *
+ * @return The current allowed speed, from -1 to 1
+ */
+ float getFlySpeed();
+
+ /**
+ * Gets the current allowed speed that a client can walk.
+ *
+ * @return The current allowed speed, from -1 to 1
+ */
+ float getWalkSpeed();
+
+ /**
+ * Sets OfflinePlayer's location. If player is online, it falls back to the Player#teleport implementation.
+ *
+ * @param destination
+ * @return true if teleportation was successful
+ */
+ boolean teleportOffline(org.bukkit.Location destination);
+
+ /**
+ * Sets OfflinePlayer's location. If player is online, it falls back to the Player#teleport implementation.
+ *
+ * @param destination
+ * @param cause Teleport cause used if player is online
+ * @return true if teleportation was successful
+ */
+ boolean teleportOffline(org.bukkit.Location destination, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause);
+
+ /**
+ * Sets OfflinePlayer's location. If player is online, it falls back to the Player#teleportAsync implementation.
+ *
+ * @param destination
+ * @return <code>true</code> if teleportation successful
+ */
+ java.util.concurrent.CompletableFuture<Boolean> teleportOfflineAsync(Location destination);
+
+ /**
+ * Sets OfflinePlayer's location. If player is online, it falls back to the Player#teleportAsync implementation.
+ *
+ * @param destination
+ * @param cause Teleport cause used if player is online
+ * @return <code>true</code> if teleportation successful
+ */
+ java.util.concurrent.CompletableFuture<Boolean> teleportOfflineAsync(Location destination, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause);
+ // Purpur end - OfflinePlayer API
}

View File

@@ -0,0 +1,128 @@
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2761,4 +_,125 @@
*/
void allowPausing(@NotNull org.bukkit.plugin.Plugin plugin, boolean value);
// Paper end - API to check if the server is sleeping
+
+ // Purpur start - Bring back server name
+ /**
+ * Get the name of this server
+ * @return the name of the server
+ */
+ @NotNull
+ String getServerName();
+ // Purpur end - Bring back server name
+
+ // Purpur start - Lagging threshold
+ /**
+ * Check if server is lagging according to laggy threshold setting
+ *
+ * @return True if lagging
+ */
+ boolean isLagging();
+ // Purpur end - Lagging threshold
+
+ // Purpur start - Added the ability to add combustible items
+ /**
+ * Add an Item as fuel for furnaces
+ *
+ * @param material The material that will be the fuel
+ * @param burnTime The time (in ticks) this item will burn for
+ */
+ public void addFuel(@NotNull Material material, int burnTime);
+
+ /**
+ * Remove an item as fuel for furnaces
+ *
+ * @param material The material that will no longer be a fuel
+ */
+ public void removeFuel(@NotNull Material material);
+ // Purpur end - Added the ability to add combustible items
+
+ // Purpur start - Debug Marker API
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, int argb);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency);
+
+ /**
+ * Clears all debug block highlights for all players on the server.
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void clearBlockHighlights();
+ // Purpur end - Debug Marker API
}

View File

@@ -0,0 +1,103 @@
--- a/src/main/java/org/bukkit/World.java
+++ b/src/main/java/org/bukkit/World.java
@@ -4497,6 +_,100 @@
@Nullable
public DragonBattle getEnderDragonBattle();
+ // Purpur start
+ /**
+ * Gets the local difficulty (based on inhabited time) at a location
+ *
+ * @param location Location to check
+ * @return The local difficulty
+ */
+ public float getLocalDifficultyAt(@NotNull Location location);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on this world.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on this world.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, int argb);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on this world.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on this world.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on this world.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on this world.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency);
+
+ /**
+ * Clears all debug block highlights for all players on this world.
+ * @deprecated until further notice. NOOP since 1.21.10
+ */
+ @Deprecated
+ void clearBlockHighlights();
+ // Purpur end
+
/**
* Get all {@link FeatureFlag} enabled in this world.
*

View File

@@ -0,0 +1,28 @@
--- a/src/main/java/org/bukkit/block/EntityBlockStorage.java
+++ b/src/main/java/org/bukkit/block/EntityBlockStorage.java
@@ -47,6 +_,25 @@
@NotNull
List<T> releaseEntities();
+ // Purpur start - Stored Bee API
+ /**
+ * Releases a stored entity, and returns the entity in the world.
+ *
+ * @param entity Entity to release
+ * @return The entity which was released, or null if the stored entity is not in the hive
+ */
+ @org.jetbrains.annotations.Nullable
+ T releaseEntity(@NotNull org.purpurmc.purpur.entity.StoredEntity<T> entity);
+
+ /**
+ * Gets all the entities currently stored in the block.
+ *
+ * @return List of all entities which are stored in the block
+ */
+ @NotNull
+ List<org.purpurmc.purpur.entity.StoredEntity<T>> getEntities();
+ // Purpur end - Stored Bee API
+
/**
* Add an entity to the block.
*

View File

@@ -0,0 +1,36 @@
--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java
+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java
@@ -148,6 +_,19 @@
return false;
}
+ // Purpur start - ExecuteCommandEvent
+ String[] parsedArgs = Arrays.copyOfRange(args, 1, args.length);
+ org.purpurmc.purpur.event.ExecuteCommandEvent event = new org.purpurmc.purpur.event.ExecuteCommandEvent(sender, target, sentCommandLabel, parsedArgs);
+ if (!event.callEvent()) {
+ return true; // cancelled
+ }
+
+ sender = event.getSender();
+ target = event.getCommand();
+ sentCommandLabel = event.getLabel();
+ parsedArgs = event.getArgs();
+ // Purpur end - ExecuteCommandEvent
+
// Paper start - Plugins do weird things to workaround normal registration
if (target.timings == null) {
target.timings = co.aikar.timings.TimingsManager.getCommandTiming(null, target);
@@ -155,10 +_,10 @@
// Paper end
try {
- try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources
+ //try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources // Purpur - Remove Timings
// Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false)
- target.execute(sender, sentCommandLabel, Arrays.copyOfRange(args, 1, args.length));
- } // target.timings.stopTiming(); // Spigot // Paper
+ target.execute(sender, sentCommandLabel, parsedArgs); // Purpur - ExecuteCommandEvent
+ //} // target.timings.stopTiming(); // Spigot // Paper // Purpur - Remove Timings
} catch (CommandException ex) {
server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper
//target.timings.stopTiming(); // Spigot // Paper

View File

@@ -0,0 +1,26 @@
--- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java
@@ -214,7 +_,7 @@
String version = Bukkit.getVersion();
// Paper start
if (version.startsWith("null")) { // running from ide?
- setVersionMessage(Component.text("Unknown version, custom build?", NamedTextColor.YELLOW));
+ setVersionMessage(Component.text("* Unknown version, custom build?", NamedTextColor.RED)); // Purpur
return;
}
setVersionMessage(getVersionFetcher().getVersionMessage(version));
@@ -255,9 +_,11 @@
// Paper start
private void setVersionMessage(final @NotNull Component msg) {
lastCheck = System.currentTimeMillis();
- final Component message = Component.textOfChildren(
- Component.text(Bukkit.getVersionMessage(), NamedTextColor.WHITE),
- Component.newline(),
+ // Purpur start
+ int distance = getVersionFetcher().distance();
+ final Component message = Component.join(net.kyori.adventure.text.JoinConfiguration.separator(Component.newline()),
+ ChatColor.parseMM("<grey>Current Purpur Version: %s%s*", distance == 0 ? "<green>" : distance > 0 ? "<yellow>" : "<red>", Bukkit.getVersion()),
+ // Purpur end
msg
);
this.versionMessage = Component.text()

View File

@@ -0,0 +1,33 @@
--- a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java
+++ b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java
@@ -169,6 +_,30 @@
public boolean includes(@NotNull Material item) {
return Tag.ITEMS_ENCHANTABLE_VANISHING.isTagged(item);
}
+ // Purpur start - Add enchantment target for bows and crossbows
+ },
+
+ /**
+ * Allow the Enchantment to be placed on bows and crossbows.
+ */
+ BOW_AND_CROSSBOW {
+ @Override
+ public boolean includes(@NotNull Material item) {
+ return item.equals(Material.BOW) || item.equals(Material.CROSSBOW);
+ }
+ // Purpur end - Add enchantment target for bows and crossbows
+ // Purpur start - Shears can have looting enchantment
+ },
+
+ /**
+ * Allow the Enchantment to be placed on shears.
+ */
+ WEAPON_AND_SHEARS {
+ @Override
+ public boolean includes(@NotNull Material item) {
+ return WEAPON.includes(item) || item.equals(Material.SHEARS);
+ }
+ // Purpur end - Shears can have looting enchantment
};
/**

View File

@@ -0,0 +1,25 @@
--- a/src/main/java/org/bukkit/entity/CopperGolem.java
+++ b/src/main/java/org/bukkit/entity/CopperGolem.java
@@ -39,6 +_,22 @@
*/
void setOxidizing(Oxidizing oxidizing);
+ // Purpur start
+ /**
+ * Get the player that summoned this iron golem
+ *
+ * @return UUID of summoner
+ */
+ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner();
+
+ /**
+ * Set the player that summoned this iron golem
+ *
+ * @param summoner UUID of summoner
+ */
+ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner);
+ // Purpur end
+
/**
* Represents the oxidizing state of a copper golem.
*

View File

@@ -0,0 +1,32 @@
--- a/src/main/java/org/bukkit/entity/Endermite.java
+++ b/src/main/java/org/bukkit/entity/Endermite.java
@@ -3,25 +_,21 @@
public interface Endermite extends Monster {
/**
- * Gets whether this Endermite was spawned by a player.
+ * Gets whether this Endermite was spawned by a player from throwing an ender pearl
*
- * An Endermite spawned by a player will be attacked by nearby Enderman.
+ * An Endermite spawned by a player might be attacked by nearby Enderman depending on purpur.yml settings
*
* @return player spawned status
- * @deprecated this functionality no longer exists
*/
- @Deprecated(since = "1.17", forRemoval = true)
boolean isPlayerSpawned();
/**
- * Sets whether this Endermite was spawned by a player.
+ * Sets whether this Endermite was spawned by a player from throwing an ender pearl
*
- * An Endermite spawned by a player will be attacked by nearby Enderman.
+ * An Endermite spawned by a player might be attacked by nearby Enderman depending on purpur.yml settings
*
* @param playerSpawned player spawned status
- * @deprecated this functionality no longer exists
*/
- @Deprecated(since = "1.17", forRemoval = true)
void setPlayerSpawned(boolean playerSpawned);
// Paper start
/**

View File

@@ -0,0 +1,62 @@
--- a/src/main/java/org/bukkit/entity/Entity.java
+++ b/src/main/java/org/bukkit/entity/Entity.java
@@ -1322,4 +_,59 @@
*/
void broadcastHurtAnimation(@NotNull java.util.Collection<Player> players);
// Paper end - broadcast hurt animation
+
+ // Purpur start - Ridables
+ /**
+ * Get the riding player
+ *
+ * @return Riding player
+ */
+ @Nullable
+ Player getRider();
+
+ /**
+ * Check if entity is being ridden
+ *
+ * @return True if being ridden
+ */
+ boolean hasRider();
+
+ /**
+ * Check if entity is ridable
+ *
+ * @return True if ridable
+ */
+ boolean isRidable();
+
+ /**
+ * Check if entity is ridable in water
+ *
+ * @return True if ridable in water
+ */
+ boolean isRidableInWater();
+ // Purpur end - Ridables
+
+ // Purpur start - API for any mob to burn daylight
+ /**
+ * Checks if the entity is in daylight
+ *
+ * @return True if in daylight
+ */
+ boolean isInDaylight();
+ // Purpur end - API for any mob to burn daylight
+
+ // Purpur start - Fire Immunity API
+ /**
+ * Checks if the entity is fire immune
+ *
+ * @return True if fire immune
+ */
+ boolean isImmuneToFire();
+
+ /**
+ * Sets if the entity is fire immune
+ * Set this to null to restore the entity type default
+ */
+ void setImmuneToFire(@Nullable Boolean fireImmune);
+ // Purpur end - Fire Immunity API
}

View File

@@ -0,0 +1,23 @@
--- a/src/main/java/org/bukkit/entity/IronGolem.java
+++ b/src/main/java/org/bukkit/entity/IronGolem.java
@@ -19,4 +_,20 @@
* player created, false if you want it to be a natural village golem.
*/
public void setPlayerCreated(boolean playerCreated);
+
+ // Purpur start
+ /**
+ * Get the player that summoned this iron golem
+ *
+ * @return UUID of summoner
+ */
+ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner();
+
+ /**
+ * Set the player that summoned this iron golem
+ *
+ * @param summoner UUID of summoner
+ */
+ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner);
+ // Purpur end
}

View File

@@ -0,0 +1,65 @@
--- a/src/main/java/org/bukkit/entity/Item.java
+++ b/src/main/java/org/bukkit/entity/Item.java
@@ -153,4 +_,62 @@
*/
public void setHealth(int health);
// Paper end
+
+ // Purpur start
+ /**
+ * Set whether or not this item is immune to cactus
+ *
+ * @param immuneToCactus True to make immune to cactus
+ */
+ void setImmuneToCactus(boolean immuneToCactus);
+
+ /**
+ * Check if item is immune to cactus
+ *
+ * @return True if immune to cactus
+ */
+ boolean isImmuneToCactus();
+
+ /**
+ * Set whether or not this item is immune to explosions
+ *
+ * @param immuneToExplosion True to make immune to explosions
+ */
+ void setImmuneToExplosion(boolean immuneToExplosion);
+
+ /**
+ * Check if item is immune to explosions
+ *
+ * @return True if immune to explosions
+ */
+ boolean isImmuneToExplosion();
+
+ /**
+ * Set whether or not this item is immune to fire
+ *
+ * @param immuneToFire True to make immune to fire
+ */
+ void setImmuneToFire(boolean immuneToFire);
+
+ /**
+ * Check if item is immune to fire
+ *
+ * @return True if immune to fire
+ */
+ boolean isImmuneToFire();
+
+ /**
+ * Set whether or not this item is immune to lightning
+ *
+ * @param immuneToLightning True to make immune to lightning
+ */
+ void setImmuneToLightning(boolean immuneToLightning);
+
+ /**
+ * Check if item is immune to lightning
+ *
+ * @return True if immune to lightning
+ */
+ boolean isImmuneToLightning();
+ // Purpur end
}

View File

@@ -0,0 +1,23 @@
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -1494,4 +_,20 @@
*/
@ApiStatus.Experimental
@NotNull CombatTracker getCombatTracker();
+
+ // Purpur start - API for any mob to burn daylight
+ /**
+ * If this mob will burn in the sunlight
+ *
+ * @return True if mob will burn in sunlight
+ */
+ boolean shouldBurnInDay();
+
+ /**
+ * Set if this mob should burn in the sunlight
+ *
+ * @param shouldBurnInDay True to burn in sunlight
+ */
+ void setShouldBurnInDay(boolean shouldBurnInDay);
+ // Purpur end - API for any mob to burn daylight
}

View File

@@ -0,0 +1,23 @@
--- a/src/main/java/org/bukkit/entity/Llama.java
+++ b/src/main/java/org/bukkit/entity/Llama.java
@@ -119,4 +_,20 @@
@org.jetbrains.annotations.Nullable
Llama getCaravanTail();
// Paper end
+
+ // Purpur start
+ /**
+ * Check if this Llama should attempt to join a caravan
+ *
+ * @return True if Llama is allowed to join a caravan
+ */
+ boolean shouldJoinCaravan();
+
+ /**
+ * Set if this Llama should attempt to join a caravan
+ *
+ * @param shouldJoinCaravan True to allow joining a caravan
+ */
+ void setShouldJoinCaravan(boolean shouldJoinCaravan);
+ // Purpur end
}

View File

@@ -0,0 +1,126 @@
--- a/src/main/java/org/bukkit/entity/Player.java
+++ b/src/main/java/org/bukkit/entity/Player.java
@@ -4004,4 +_,123 @@
*/
@ApiStatus.Experimental
PlayerGameConnection getConnection();
+
+ // Purpur start
+ /**
+ * Allows you to get if player uses PurpurClient
+ *
+ * @return true if player uses PurpurClient
+ */
+ boolean usesPurpurClient();
+
+ /**
+ * Check if player is AFK
+ *
+ * @return True if AFK
+ */
+ boolean isAfk();
+
+ /**
+ * Set player as AFK
+ *
+ * @param setAfk Whether to set AFK or not
+ */
+ void setAfk(boolean setAfk);
+
+ /**
+ * Reset the idle timer back to 0
+ * @deprecated Use {@link #resetIdleDuration()} instead
+ */
+ void resetIdleTimer();
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ */
+ void sendBlockHighlight(Location location, int duration);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
+ */
+ void sendBlockHighlight(Location location, int duration, int argb);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ */
+ void sendBlockHighlight(Location location, int duration, String text);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
+ */
+ void sendBlockHighlight(Location location, int duration, String text, int argb);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
+ */
+ void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
+ * <p>
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
+ */
+ void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency);
+
+ /**
+ * Clears all debug block highlights
+ */
+ void clearBlockHighlights();
+
+ /**
+ * Sends a player the death screen with a specified death message.
+ *
+ * @param message The death message to show the player
+ */
+ void sendDeathScreen(net.kyori.adventure.text.Component message);
+
+ /**
+ * Sends a player the death screen with a specified death message,
+ * along with the entity that caused the death.
+ *
+ * @param message The death message to show the player
+ * @param killer The entity that killed the player
+ * @deprecated Use {@link #sendDeathScreen(net.kyori.adventure.text.Component)} instead, as 1.20 removed the killer ID from the packet.
+ */
+ @Deprecated(since = "1.20")
+ default void sendDeathScreen(net.kyori.adventure.text.Component message, @Nullable Entity killer) {
+ sendDeathScreen(message);
+ }
+ // Purpur end
}

View File

@@ -0,0 +1,23 @@
--- a/src/main/java/org/bukkit/entity/Snowman.java
+++ b/src/main/java/org/bukkit/entity/Snowman.java
@@ -23,4 +_,20 @@
* @param derpMode True to remove the pumpkin, false to add a pumpkin
*/
void setDerp(boolean derpMode);
+
+ // Purpur start
+ /**
+ * Get the player that summoned this snowman
+ *
+ * @return UUID of summoner
+ */
+ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner();
+
+ /**
+ * Set the player that summoned this snowman
+ *
+ * @param summoner UUID of summoner
+ */
+ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner);
+ // Purpur end
}

View File

@@ -0,0 +1,16 @@
--- a/src/main/java/org/bukkit/entity/Villager.java
+++ b/src/main/java/org/bukkit/entity/Villager.java
@@ -406,4 +_,13 @@
* Demand is still updated even if all events are canceled.
*/
public void restock();
+
+ // Purpur start
+ /**
+ * Check if villager is currently lobotomized
+ *
+ * @return True if lobotomized
+ */
+ boolean isLobotomized();
+ // Purpur end
}

View File

@@ -0,0 +1,23 @@
--- a/src/main/java/org/bukkit/entity/Wither.java
+++ b/src/main/java/org/bukkit/entity/Wither.java
@@ -105,4 +_,20 @@
* This is called in vanilla directly after spawning the wither.
*/
void enterInvulnerabilityPhase();
+
+ // Purpur start
+ /**
+ * Get the player that summoned this wither
+ *
+ * @return UUID of summoner
+ */
+ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner();
+
+ /**
+ * Set the player that summoned this wither
+ *
+ * @param summoner UUID of summoner
+ */
+ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner);
+ // Purpur end
}

View File

@@ -0,0 +1,23 @@
--- a/src/main/java/org/bukkit/entity/Wolf.java
+++ b/src/main/java/org/bukkit/entity/Wolf.java
@@ -162,4 +_,20 @@
return RegistryAccess.registryAccess().getRegistry(RegistryKey.WOLF_SOUND_VARIANT).getOrThrow(NamespacedKey.minecraft(key));
}
}
+
+ // Purpur start
+ /**
+ * Checks if this wolf is rabid
+ *
+ * @return whether the wolf is rabid
+ */
+ boolean isRabid();
+
+ /**
+ * Sets this wolf to be rabid or not
+ *
+ * @param rabid whether the wolf should be rabid
+ */
+ void setRabid(boolean rabid);
+ // Purpur end
}

View File

@@ -0,0 +1,12 @@
--- a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java
+++ b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java
@@ -310,7 +_,8 @@
WORLD_BORDER,
/**
* Damage caused when an entity contacts a block such as a Cactus,
- * Dripstone (Stalagmite) or Berry Bush.
+ * Dripstone (Stalagmite) or Berry Bush. (Stonecutters too if you
+ * have the Stonecutter damage Purpur feature enabled)
* <p>
* Damage: variable
*/

View File

@@ -0,0 +1,15 @@
--- a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java
+++ b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java
@@ -218,6 +_,12 @@
* When all effects are removed due to a bucket of milk.
*/
MILK,
+ // Purpur start
+ /**
+ * When a player wears full netherite armor
+ */
+ NETHERITE_ARMOR,
+ // Purpur end
/**
* When the entity gets the effect from a nautilus.
*/

View File

@@ -0,0 +1,11 @@
--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java
+++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java
@@ -170,7 +_,7 @@
SMITHING_NEW(4, "Upgrade Gear", MenuType.SMITHING),
;
- private final int size;
+ private int size; @ApiStatus.Internal public void setDefaultSize(int size) { this.size = size; } // Purpur - remove final and add setter
private final String title;
private final MenuType menuType;
private final boolean isCreatable;

View File

@@ -0,0 +1,45 @@
--- a/src/main/java/org/bukkit/inventory/AnvilInventory.java
+++ b/src/main/java/org/bukkit/inventory/AnvilInventory.java
@@ -138,4 +_,42 @@
setItem(2, result);
}
// Paper end
+
+ // Purpur start
+ /**
+ * Gets if the player viewing the anvil inventory can bypass experience cost
+ *
+ * @return whether the player viewing the anvil inventory can bypass the experience cost
+ * @deprecated use {@link AnvilView#canBypassCost()}.
+ */
+ @Deprecated(forRemoval = true, since = "1.21")
+ boolean canBypassCost();
+
+ /**
+ * Set if the player viewing the anvil inventory can bypass the experience cost
+ *
+ * @param bypassCost whether the player viewing the anvil inventory can bypass the experience cost
+ * @deprecated use {@link AnvilView#setBypassCost(boolean)}.
+ */
+ @Deprecated(forRemoval = true, since = "1.21")
+ void setBypassCost(boolean bypassCost);
+
+ /**
+ * Gets if the player viewing the anvil inventory can do unsafe enchants
+ *
+ * @return whether the player viewing the anvil inventory can do unsafe enchants
+ * @deprecated use {@link AnvilView#canDoUnsafeEnchants()}.
+ */
+ @Deprecated(forRemoval = true, since = "1.21")
+ boolean canDoUnsafeEnchants();
+
+ /**
+ * Set if the player viewing the anvil inventory can do unsafe enchants
+ *
+ * @param canDoUnsafeEnchants whether the player viewing the anvil inventory can do unsafe enchants
+ * @deprecated use {@link AnvilView#setDoUnsafeEnchants(boolean)}.
+ */
+ @Deprecated(forRemoval = true, since = "1.21")
+ void setDoUnsafeEnchants(boolean canDoUnsafeEnchants);
+ // Purpur end
}

View File

@@ -0,0 +1,499 @@
--- a/src/main/java/org/bukkit/inventory/ItemStack.java
+++ b/src/main/java/org/bukkit/inventory/ItemStack.java
@@ -24,6 +_,13 @@
import org.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+// Purpur start - ItemStack convenience methods
+import com.google.common.collect.Multimap;
+import java.util.Collection;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.attribute.AttributeModifier;
+import org.bukkit.block.data.BlockData;
+// Purpur end - ItemStack convenience methods
/**
* Represents a stack of items.
@@ -1373,4 +_,482 @@
return this.craftDelegate.matchesWithoutData(item, excludeTypes, ignoreCount);
}
// Paper end - data component API
+
+ // Purpur start - ItemStack convenience methods
+ /**
+ * Gets the display name that is set.
+ * <p>
+ * Plugins should check that hasDisplayName() returns <code>true</code>
+ * before calling this method.
+ *
+ * @return the display name that is set
+ */
+ @NotNull
+ public String getDisplayName() {
+ return this.craftDelegate.getDisplayName();
+ }
+
+ /**
+ * Sets the display name.
+ *
+ * @param name the name to set
+ */
+ public void setDisplayName(@Nullable String name) {
+ this.craftDelegate.setDisplayName(name);
+ }
+
+ /**
+ * Checks for existence of a display name.
+ *
+ * @return true if this has a display name
+ */
+ public boolean hasDisplayName() {
+ return this.craftDelegate.hasDisplayName();
+ }
+
+ /**
+ * Gets the localized display name that is set.
+ * <p>
+ * Plugins should check that hasLocalizedName() returns <code>true</code>
+ * before calling this method.
+ *
+ * @return the localized name that is set
+ */
+ @NotNull
+ public String getLocalizedName() {
+ return this.craftDelegate.getLocalizedName();
+ }
+
+ /**
+ * Sets the localized name.
+ *
+ * @param name the name to set
+ */
+ public void setLocalizedName(@Nullable String name) {
+ this.craftDelegate.setLocalizedName(name);
+ }
+
+ /**
+ * Checks for existence of a localized name.
+ *
+ * @return true if this has a localized name
+ */
+ public boolean hasLocalizedName() {
+ return this.craftDelegate.hasLocalizedName();
+ }
+
+ /**
+ * Checks for existence of lore.
+ *
+ * @return true if this has lore
+ */
+ public boolean hasLore() {
+ return this.craftDelegate.hasLore();
+ }
+
+ /**
+ * Checks for existence of the specified enchantment.
+ *
+ * @param ench enchantment to check
+ * @return true if this enchantment exists for this meta
+ */
+ public boolean hasEnchant(@NotNull Enchantment ench) {
+ return this.craftDelegate.hasEnchant(ench);
+ }
+
+ /**
+ * Checks for the level of the specified enchantment.
+ *
+ * @param ench enchantment to check
+ * @return The level that the specified enchantment has, or 0 if none
+ */
+ public int getEnchantLevel(@NotNull Enchantment ench) {
+ return this.craftDelegate.getEnchantLevel(ench);
+ }
+
+ /**
+ * Returns a copy the enchantments in this ItemMeta. <br>
+ * Returns an empty map if none.
+ *
+ * @return An immutable copy of the enchantments
+ */
+ @NotNull
+ public Map<Enchantment, Integer> getEnchants() {
+ return this.craftDelegate.getEnchants();
+ }
+
+ /**
+ * Adds the specified enchantment to this item meta.
+ *
+ * @param ench Enchantment to add
+ * @param level Level for the enchantment
+ * @param ignoreLevelRestriction this indicates the enchantment should be
+ * applied, ignoring the level limit
+ * @return true if the item meta changed as a result of this call, false
+ * otherwise
+ */
+ public boolean addEnchant(@NotNull Enchantment ench, int level, boolean ignoreLevelRestriction) {
+ return this.craftDelegate.addEnchant(ench, level, ignoreLevelRestriction);
+ }
+
+ /**
+ * Removes the specified enchantment from this item meta.
+ *
+ * @param ench Enchantment to remove
+ * @return true if the item meta changed as a result of this call, false
+ * otherwise
+ */
+ public boolean removeEnchant(@NotNull Enchantment ench) {
+ return this.craftDelegate.removeEnchant(ench);
+ }
+
+ /**
+ * Checks for the existence of any enchantments.
+ *
+ * @return true if an enchantment exists on this meta
+ */
+ public boolean hasEnchants() {
+ return this.craftDelegate.hasEnchants();
+ }
+
+ /**
+ * Checks if the specified enchantment conflicts with any enchantments in
+ * this ItemMeta.
+ *
+ * @param ench enchantment to test
+ * @return true if the enchantment conflicts, false otherwise
+ */
+ public boolean hasConflictingEnchant(@NotNull Enchantment ench) {
+ return this.craftDelegate.hasConflictingEnchant(ench);
+ }
+
+ /**
+ * Sets the custom model data.
+ * <p>
+ * CustomModelData is an integer that may be associated client side with a
+ * custom item model.
+ *
+ * @param data the data to set, or null to clear
+ */
+ public void setCustomModelData(@Nullable Integer data) {
+ this.craftDelegate.setCustomModelData(data);
+ }
+
+ /**
+ * Gets the custom model data that is set.
+ * <p>
+ * CustomModelData is an integer that may be associated client side with a
+ * custom item model.
+ * <p>
+ * Plugins should check that hasCustomModelData() returns <code>true</code>
+ * before calling this method.
+ *
+ * @return the localized name that is set
+ */
+ public int getCustomModelData() {
+ return this.craftDelegate.getCustomModelData();
+ }
+
+ /**
+ * Checks for existence of custom model data.
+ * <p>
+ * CustomModelData is an integer that may be associated client side with a
+ * custom item model.
+ *
+ * @return true if this has custom model data
+ */
+ public boolean hasCustomModelData() {
+ return this.craftDelegate.hasCustomModelData();
+ }
+
+ /**
+ * Returns whether the item has block data currently attached to it.
+ *
+ * @return whether block data is already attached
+ */
+ public boolean hasBlockData() {
+ return this.craftDelegate.hasBlockData();
+ }
+
+ /**
+ * Returns the currently attached block data for this item or creates a new
+ * one if one doesn't exist.
+ *
+ * The state is a copy, it must be set back (or to another item) with
+ * {@link #setBlockData(BlockData)}
+ *
+ * @param material the material we wish to get this data in the context of
+ * @return the attached data or new data
+ */
+ @NotNull
+ public BlockData getBlockData(@NotNull Material material) {
+ return this.craftDelegate.getBlockData(material);
+ }
+
+ /**
+ * Attaches a copy of the passed block data to the item.
+ *
+ * @param blockData the block data to attach to the block.
+ * @throws IllegalArgumentException if the blockData is null or invalid for
+ * this item.
+ */
+ public void setBlockData(@NotNull BlockData blockData) {
+ this.craftDelegate.setBlockData(blockData);
+ }
+
+ /**
+ * Gets the repair penalty
+ *
+ * @return the repair penalty
+ */
+ public int getRepairCost() {
+ return this.craftDelegate.getRepairCost();
+ }
+
+ /**
+ * Sets the repair penalty
+ *
+ * @param cost repair penalty
+ */
+ public void setRepairCost(int cost) {
+ this.craftDelegate.setRepairCost(cost);
+ }
+
+ /**
+ * Checks to see if this has a repair penalty
+ *
+ * @return true if this has a repair penalty
+ */
+ public boolean hasRepairCost() {
+ return this.craftDelegate.hasRepairCost();
+ }
+
+ /**
+ * Return if the unbreakable tag is true. An unbreakable item will not lose
+ * durability.
+ *
+ * @return true if the unbreakable tag is true
+ */
+ public boolean isUnbreakable() {
+ return this.craftDelegate.isUnbreakable();
+ }
+
+ /**
+ * Sets the unbreakable tag. An unbreakable item will not lose durability.
+ *
+ * @param unbreakable true if set unbreakable
+ */
+ public void setUnbreakable(boolean unbreakable) {
+ this.craftDelegate.setUnbreakable(unbreakable);
+ }
+
+ /**
+ * Checks for the existence of any AttributeModifiers.
+ *
+ * @return true if any AttributeModifiers exist
+ */
+ public boolean hasAttributeModifiers() {
+ return this.craftDelegate.hasAttributeModifiers();
+ }
+
+ /**
+ * Return an immutable copy of all Attributes and
+ * their modifiers in this ItemMeta.<br>
+ * Returns null if none exist.
+ *
+ * @return an immutable {@link Multimap} of Attributes
+ * and their AttributeModifiers, or null if none exist
+ */
+ @Nullable
+ public Multimap<Attribute, AttributeModifier> getAttributeModifiers() {
+ return this.craftDelegate.getAttributeModifiers();
+ }
+
+ /**
+ * Return an immutable copy of all {@link Attribute}s and their
+ * {@link AttributeModifier}s for a given {@link EquipmentSlot}.<br>
+ * Any {@link AttributeModifier} that does have have a given
+ * {@link EquipmentSlot} will be returned. This is because
+ * AttributeModifiers without a slot are active in any slot.<br>
+ * If there are no attributes set for the given slot, an empty map
+ * will be returned.
+ *
+ * @param slot the {@link EquipmentSlot} to check
+ * @return the immutable {@link Multimap} with the
+ * respective Attributes and modifiers, or an empty map
+ * if no attributes are set.
+ */
+ @NotNull
+ public Multimap<Attribute, AttributeModifier> getAttributeModifiers(@Nullable EquipmentSlot slot) {
+ return this.craftDelegate.getAttributeModifiers(slot);
+ }
+
+ /**
+ * Return an immutable copy of all {@link AttributeModifier}s
+ * for a given {@link Attribute}
+ *
+ * @param attribute the {@link Attribute}
+ * @return an immutable collection of {@link AttributeModifier}s
+ * or null if no AttributeModifiers exist for the Attribute.
+ * @throws NullPointerException if Attribute is null
+ */
+ @Nullable
+ public Collection<AttributeModifier> getAttributeModifiers(@NotNull Attribute attribute) {
+ return this.craftDelegate.getAttributeModifiers(attribute);
+ }
+
+ /**
+ * Add an Attribute and it's Modifier.
+ * AttributeModifiers can now support {@link EquipmentSlot}s.
+ * If not set, the {@link AttributeModifier} will be active in ALL slots.
+ * <br>
+ * Two {@link AttributeModifier}s that have the same {@link java.util.UUID}
+ * cannot exist on the same Attribute.
+ *
+ * @param attribute the {@link Attribute} to modify
+ * @param modifier the {@link AttributeModifier} specifying the modification
+ * @return true if the Attribute and AttributeModifier were
+ * successfully added
+ * @throws NullPointerException if Attribute is null
+ * @throws NullPointerException if AttributeModifier is null
+ * @throws IllegalArgumentException if AttributeModifier already exists
+ */
+ public boolean addAttributeModifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier) {
+ return this.craftDelegate.addAttributeModifier(attribute, modifier);
+ }
+
+ /**
+ * Set all {@link Attribute}s and their {@link AttributeModifier}s.
+ * To clear all currently set Attributes and AttributeModifiers use
+ * null or an empty Multimap.
+ * If not null nor empty, this will filter all entries that are not-null
+ * and add them to the ItemStack.
+ *
+ * @param attributeModifiers the new Multimap containing the Attributes
+ * and their AttributeModifiers
+ */
+ public void setAttributeModifiers(@Nullable Multimap<Attribute, AttributeModifier> attributeModifiers) {
+ this.craftDelegate.setAttributeModifiers(attributeModifiers);
+ }
+
+ /**
+ * Remove all {@link AttributeModifier}s associated with the given
+ * {@link Attribute}.
+ * This will return false if nothing was removed.
+ *
+ * @param attribute attribute to remove
+ * @return true if all modifiers were removed from a given
+ * Attribute. Returns false if no attributes were
+ * removed.
+ * @throws NullPointerException if Attribute is null
+ */
+ public boolean removeAttributeModifier(@NotNull Attribute attribute) {
+ return this.craftDelegate.removeAttributeModifier(attribute);
+ }
+
+ /**
+ * Remove all {@link Attribute}s and {@link AttributeModifier}s for a
+ * given {@link EquipmentSlot}.<br>
+ * If the given {@link EquipmentSlot} is null, this will remove all
+ * {@link AttributeModifier}s that do not have an EquipmentSlot set.
+ *
+ * @param slot the {@link EquipmentSlot} to clear all Attributes and
+ * their modifiers for
+ * @return true if all modifiers were removed that match the given
+ * EquipmentSlot.
+ */
+ public boolean removeAttributeModifier(@Nullable EquipmentSlot slot) {
+ return this.craftDelegate.removeAttributeModifier(slot);
+ }
+
+ /**
+ * Remove a specific {@link Attribute} and {@link AttributeModifier}.
+ * AttributeModifiers are matched according to their {@link java.util.UUID}.
+ *
+ * @param attribute the {@link Attribute} to remove
+ * @param modifier the {@link AttributeModifier} to remove
+ * @return if any attribute modifiers were remove
+ *
+ * @throws NullPointerException if the Attribute is null
+ * @throws NullPointerException if the AttributeModifier is null
+ *
+ * @see AttributeModifier#getUniqueId()
+ */
+ public boolean removeAttributeModifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier) {
+ return this.craftDelegate.removeAttributeModifier(attribute, modifier);
+ }
+
+ /**
+ * Checks to see if this item has damage
+ *
+ * @return true if this has damage
+ */
+ public boolean hasDamage() {
+ return this.craftDelegate.hasDamage();
+ }
+
+ /**
+ * Gets the damage
+ *
+ * @return the damage
+ */
+ public int getDamage() {
+ return this.craftDelegate.getDamage();
+ }
+
+ /**
+ * Sets the damage
+ *
+ * @param damage item damage
+ */
+ public void setDamage(int damage) {
+ this.craftDelegate.setDamage(damage);
+ }
+
+ /**
+ * Repairs this item by 1 durability
+ */
+ public void repair() {
+ repair(1);
+ }
+
+ /**
+ * Damages this item by 1 durability
+ *
+ * @return True if damage broke the item
+ */
+ public boolean damage() {
+ return damage(1);
+ }
+
+ /**
+ * Repairs this item's durability by amount
+ *
+ * @param amount Amount of durability to repair
+ */
+ public void repair(int amount) {
+ damage(-amount);
+ }
+
+ /**
+ * Damages this item's durability by amount
+ *
+ * @param amount Amount of durability to damage
+ * @return True if damage broke the item
+ */
+ public boolean damage(int amount) {
+ return damage(amount, false);
+ }
+
+ /**
+ * Damages this item's durability by amount
+ *
+ * @param amount Amount of durability to damage
+ * @param ignoreUnbreaking Ignores unbreaking enchantment
+ * @return True if damage broke the item
+ */
+ public boolean damage(int amount, boolean ignoreUnbreaking) {
+ return this.craftDelegate.damage(amount, ignoreUnbreaking);
+ }
+ // Purpur end - ItemStack convenience methods
}

View File

@@ -0,0 +1,36 @@
--- a/src/main/java/org/bukkit/inventory/RecipeChoice.java
+++ b/src/main/java/org/bukkit/inventory/RecipeChoice.java
@@ -191,6 +_,7 @@
public static class ExactChoice implements RecipeChoice {
private List<ItemStack> choices;
+ private Predicate<ItemStack> predicate; // Purpur - Add predicate to recipe's ExactChoice ingredient
public ExactChoice(@NotNull ItemStack stack) {
this(Arrays.asList(stack));
@@ -241,6 +_,7 @@
@Override
public boolean test(@NotNull ItemStack t) {
+ if (predicate != null) return predicate.test(t); // Purpur - Add predicate to recipe's ExactChoice ingredient
for (ItemStack match : choices) {
if (t.isSimilar(match)) {
return true;
@@ -249,6 +_,17 @@
return false;
}
+
+ // Purpur start - Add predicate to recipe's ExactChoice ingredient
+ @org.jetbrains.annotations.Nullable
+ public Predicate<ItemStack> getPredicate() {
+ return predicate;
+ }
+
+ public void setPredicate(@org.jetbrains.annotations.Nullable Predicate<ItemStack> predicate) {
+ this.predicate = predicate;
+ }
+ // Purpur end - Add predicate to recipe's ExactChoice ingredient
@Override
public int hashCode() {

View File

@@ -0,0 +1,37 @@
--- a/src/main/java/org/bukkit/inventory/view/AnvilView.java
+++ b/src/main/java/org/bukkit/inventory/view/AnvilView.java
@@ -89,4 +_,34 @@
*/
void bypassEnchantmentLevelRestriction(boolean bypassEnchantmentLevelRestriction);
// Paper end - bypass anvil level restrictions
+
+ // Purpur start - Anvil API
+ /**
+ * Gets if the player viewing the anvil inventory can bypass experience cost
+ *
+ * @return whether the player viewing the anvil inventory can bypass the experience cost
+ */
+ boolean canBypassCost();
+
+ /**
+ * Set if the player viewing the anvil inventory can bypass the experience cost
+ *
+ * @param bypassCost whether the player viewing the anvil inventory can bypass the experience cost
+ */
+ void setBypassCost(boolean bypassCost);
+
+ /**
+ * Gets if the player viewing the anvil inventory can do unsafe enchants
+ *
+ * @return whether the player viewing the anvil inventory can do unsafe enchants
+ */
+ boolean canDoUnsafeEnchants();
+
+ /**
+ * Set if the player viewing the anvil inventory can do unsafe enchants
+ *
+ * @param canDoUnsafeEnchants whether the player viewing the anvil inventory can do unsafe enchants
+ */
+ void setDoUnsafeEnchants(boolean canDoUnsafeEnchants);
+ // Purpur end - Anvil API
}

View File

@@ -0,0 +1,15 @@
--- a/src/main/java/org/bukkit/map/MapRenderer.java
+++ b/src/main/java/org/bukkit/map/MapRenderer.java
@@ -54,4 +_,12 @@
*/
public abstract void render(@NotNull MapView map, @NotNull MapCanvas canvas, @NotNull Player player);
+ // Purpur - start - Explorer Map API
+ /**
+ * Check if this is an explorer (aka treasure) map.
+ *
+ * @return True if explorer map
+ */
+ public abstract boolean isExplorerMap();
+ // Purpur - end - Explorer Map API
}

View File

@@ -0,0 +1,20 @@
--- a/src/main/java/org/bukkit/permissions/PermissibleBase.java
+++ b/src/main/java/org/bukkit/permissions/PermissibleBase.java
@@ -169,7 +_,7 @@
for (Permission perm : defaults) {
String name = perm.getName().toLowerCase(Locale.ROOT);
- permissions.put(name, new PermissionAttachmentInfo(parent, name, null, true));
+ permissions.put(name, new PermissionAttachmentInfo(parent, name, null, perm.getDefault().getValue(isOp()))); // Purpur - Fix default permission system
Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent);
calculateChildPermissions(perm.getChildren(), false, null);
}
@@ -197,7 +_,7 @@
String name = entry.getKey();
Permission perm = Bukkit.getServer().getPluginManager().getPermission(name);
- boolean value = entry.getValue() ^ invert;
+ boolean value = (entry.getValue() == null && perm != null ? perm.getDefault().getValue(isOp()) : entry.getValue()) ^ invert; // Purpur - Fix default permission system
String lname = name.toLowerCase(Locale.ROOT);
permissions.put(lname, new PermissionAttachmentInfo(parent, lname, attachment, value));

View File

@@ -0,0 +1,10 @@
--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
@@ -53,6 +_,7 @@
private final Pattern[] fileFilters = new Pattern[]{Pattern.compile("\\.jar$")};
private final List<PluginClassLoader> loaders = new CopyOnWriteArrayList<PluginClassLoader>();
private final LibraryLoader libraryLoader;
+ public static boolean SuppressLibraryLoaderLogger = false; // Purpur - Add log suppression for LibraryLoader
/**
* This class was not meant to be constructed explicitly

View File

@@ -0,0 +1,26 @@
--- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java
+++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java
@@ -69,6 +_,7 @@
session.setTransferListener(new AbstractTransferListener() {
@Override
public void transferStarted(@NotNull TransferEvent event) {
+ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - Add log suppression for LibraryLoader
logger.log(Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
}
});
@@ -94,6 +_,7 @@
// Paper end - plugin loader api
return null;
}
+ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - Add log suppression for LibraryLoader
logger.log(Level.INFO, "[{0}] Loading {1} libraries... please wait", new Object[]
{
java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), desc.getLibraries().size() // Paper - use configured log prefix
@@ -146,6 +_,7 @@
}
jarFiles.add(url);
+ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - Add log suppression for LibraryLoader
logger.log(Level.INFO, "[{0}] Loaded library {1}", new Object[]
{
java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), file // Paper - use configured log prefix

View File

@@ -0,0 +1,10 @@
--- a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java
+++ b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java
@@ -18,6 +_,7 @@
DefaultPermissions.registerPermission(PREFIX + "plugins", "Allows the user to view the list of plugins running on this server", PermissionDefault.TRUE, commands);
DefaultPermissions.registerPermission(PREFIX + "reload", "Allows the user to reload the server settings", PermissionDefault.OP, commands);
DefaultPermissions.registerPermission(PREFIX + "version", "Allows the user to view the version of the server", PermissionDefault.TRUE, commands);
+ DefaultPermissions.registerPermission(PREFIX + "purpur", "Allows the user to use the purpur command", PermissionDefault.OP, commands); // Purpur - Default permissions
commands.recalculatePermissibles();
return commands;

View File

@@ -0,0 +1,56 @@
--- a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java
+++ b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java
@@ -31,7 +_,7 @@
if (withLegacy) {
Permission legacy = new Permission(LEGACY_PREFIX + result.getName(), result.getDescription(), PermissionDefault.FALSE);
- legacy.getChildren().put(result.getName(), true);
+ legacy.getChildren().put(result.getName(), null); // Purpur - Fix default permission system
registerPermission(perm, false);
}
@@ -40,7 +_,7 @@
@NotNull
public static Permission registerPermission(@NotNull Permission perm, @NotNull Permission parent) {
- parent.getChildren().put(perm.getName(), true);
+ parent.getChildren().put(perm.getName(), null); // Purpur - Fix default permission system
return registerPermission(perm);
}
@@ -53,7 +_,7 @@
@NotNull
public static Permission registerPermission(@NotNull String name, @Nullable String desc, @NotNull Permission parent) {
Permission perm = registerPermission(name, desc);
- parent.getChildren().put(perm.getName(), true);
+ parent.getChildren().put(perm.getName(), null); // Purpur - Fix default permission system
return perm;
}
@@ -66,7 +_,7 @@
@NotNull
public static Permission registerPermission(@NotNull String name, @Nullable String desc, @Nullable PermissionDefault def, @NotNull Permission parent) {
Permission perm = registerPermission(name, desc, def);
- parent.getChildren().put(perm.getName(), true);
+ parent.getChildren().put(perm.getName(), null); // Purpur - Fix default permission system
return perm;
}
@@ -79,7 +_,7 @@
@NotNull
public static Permission registerPermission(@NotNull String name, @Nullable String desc, @Nullable PermissionDefault def, @Nullable Map<String, Boolean> children, @NotNull Permission parent) {
Permission perm = registerPermission(name, desc, def, children);
- parent.getChildren().put(perm.getName(), true);
+ parent.getChildren().put(perm.getName(), null); // Purpur - Fix default permission system
return perm;
}
@@ -88,6 +_,8 @@
CommandPermissions.registerPermissions(parent);
BroadcastPermissions.registerPermissions(parent);
+
+ org.purpurmc.purpur.util.permissions.PurpurPermissions.registerPermissions(); // Purpur - Default permissions
parent.recalculatePermissibles();
}

View File

@@ -0,0 +1,12 @@
--- a/src/main/java/org/spigotmc/CustomTimingsHandler.java
+++ b/src/main/java/org/spigotmc/CustomTimingsHandler.java
@@ -61,7 +_,7 @@
handler = timing;
}
- public void startTiming() { handler.startTiming(); }
- public void stopTiming() { handler.stopTiming(); }
+ public void startTiming() { /*handler.startTiming();*/ } // Purpur - Remove Timings
+ public void stopTiming() { /*handler.stopTiming();*/ } // Purpur - Remove Timings
}

View File

@@ -0,0 +1,52 @@
package org.purpurmc.purpur.entity;
import org.bukkit.Nameable;
import org.bukkit.block.EntityBlockStorage;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.persistence.PersistentDataHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents an entity stored in a block
*
* @see org.bukkit.block.EntityBlockStorage
*/
public interface StoredEntity<T extends Entity> extends PersistentDataHolder, Nameable {
/**
* Checks if this entity has been released yet
*
* @return if this entity has been released
*/
boolean hasBeenReleased();
/**
* Releases the entity from its stored block
*
* @return the released entity, or null if unsuccessful (including if this entity has already been released)
*/
@Nullable
T release();
/**
* Returns the block in which this entity is stored
*
* @return the EntityBlockStorage in which this entity is stored, or null if it has been released
*/
@Nullable
EntityBlockStorage<T> getBlockStorage();
/**
* Gets the entity type of this stored entity
*
* @return the type of entity this stored entity represents
*/
@NotNull
EntityType getType();
/**
* Writes data to the block entity snapshot. {@link EntityBlockStorage#update()} must be run in order to update the block in game.
*/
void update();
}

View File

@@ -0,0 +1,127 @@
package org.purpurmc.purpur.event;
import com.google.common.base.Preconditions;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
/**
* This event is called whenever someone runs a command
*/
@NullMarked
public class ExecuteCommandEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancel = false;
private CommandSender sender;
private Command command;
private String label;
private @Nullable String[] args;
@ApiStatus.Internal
public ExecuteCommandEvent(CommandSender sender, Command command, String label, @Nullable String[] args) {
this.sender = sender;
this.command = command;
this.label = label;
this.args = args;
}
/**
* Gets the command that the player is attempting to execute.
*
* @return Command the player is attempting to execute
*/
public Command getCommand() {
return command;
}
/**
* Sets the command that the player will execute.
*
* @param command New command that the player will execute
* @throws IllegalArgumentException if command is null or empty
*/
public void setCommand(Command command) throws IllegalArgumentException {
Preconditions.checkArgument(command != null, "Command cannot be null");
this.command = command;
}
/**
* Gets the sender that this command will be executed as.
*
* @return Sender this command will be executed as
*/
public CommandSender getSender() {
return sender;
}
/**
* Sets the sender that this command will be executed as.
*
* @param sender New sender which this event will execute as
* @throws IllegalArgumentException if the sender provided is null
*/
public void setSender(final CommandSender sender) throws IllegalArgumentException {
Preconditions.checkArgument(sender != null, "Sender cannot be null");
this.sender = sender;
}
/**
* Get the label used to execute this command
*
* @return Label used to execute this command
*/
public String getLabel() {
return label;
}
/**
* Set the label used to execute this command
*
* @param label Label used
*/
public void setLabel(String label) {
this.label = label;
}
/**
* Get the args passed to the command
*
* @return Args passed to the command
*/
public String[] getArgs() {
return args;
}
/**
* Set the args passed to the command
*
* @param args Args passed to the command
*/
public void setArgs(String[] args) {
this.args = args;
}
@Override
public boolean isCancelled() {
return cancel;
}
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,71 @@
package org.purpurmc.purpur.event;
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.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public class PlayerAFKEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final boolean setAfk;
private boolean shouldKick;
private @Nullable String broadcast;
private boolean cancel;
@ApiStatus.Internal
public PlayerAFKEvent(Player player, boolean setAfk, boolean shouldKick, @Nullable String broadcast, boolean async) {
super(player, async);
this.setAfk = setAfk;
this.shouldKick = shouldKick;
this.broadcast = broadcast;
}
/**
* Whether player is going afk or coming back
*
* @return True if going afk. False is coming back
*/
public boolean isGoingAfk() {
return setAfk;
}
public boolean shouldKick() {
return shouldKick;
}
public void setShouldKick(boolean shouldKick) {
this.shouldKick = shouldKick;
}
@Nullable
public String getBroadcastMsg() {
return broadcast;
}
public void setBroadcastMsg(@Nullable String broadcast) {
this.broadcast = broadcast;
}
@Override
public boolean isCancelled() {
return cancel;
}
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,83 @@
package org.purpurmc.purpur.event;
import org.bukkit.block.Block;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.entity.EntityType;
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.ApiStatus;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PlayerSetSpawnerTypeWithEggEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final Block block;
private final CreatureSpawner spawner;
private EntityType type;
private boolean cancel;
@ApiStatus.Internal
public PlayerSetSpawnerTypeWithEggEvent(Player player, Block block, CreatureSpawner spawner, EntityType type) {
super(player);
this.block = block;
this.spawner = spawner;
this.type = type;
}
/**
* Get the spawner Block in the world
*
* @return Spawner Block
*/
public Block getBlock() {
return block;
}
/**
* Get the spawner state
*
* @return Spawner state
*/
public CreatureSpawner getSpawner() {
return spawner;
}
/**
* Gets the EntityType being set on the spawner
*
* @return EntityType being set
*/
public EntityType getEntityType() {
return type;
}
/**
* Sets the EntityType being set on the spawner
*
* @param type EntityType to set
*/
public void setEntityType(EntityType type) {
this.type = type;
}
@Override
public boolean isCancelled() {
return cancel;
}
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,83 @@
package org.purpurmc.purpur.event;
import org.bukkit.block.Block;
import org.bukkit.block.TrialSpawner;
import org.bukkit.entity.EntityType;
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.ApiStatus;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PlayerSetTrialSpawnerTypeWithEggEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final Block block;
private final TrialSpawner spawner;
private EntityType type;
private boolean cancel;
@ApiStatus.Internal
public PlayerSetTrialSpawnerTypeWithEggEvent(Player player, Block block, TrialSpawner spawner, EntityType type) {
super(player);
this.block = block;
this.spawner = spawner;
this.type = type;
}
/**
* Get the spawner Block in the world
*
* @return Spawner Block
*/
public Block getBlock() {
return block;
}
/**
* Get the spawner state
*
* @return Spawner state
*/
public TrialSpawner getSpawner() {
return spawner;
}
/**
* Gets the EntityType being set on the spawner
*
* @return EntityType being set
*/
public EntityType getEntityType() {
return type;
}
/**
* Sets the EntityType being set on the spawner
*
* @param type EntityType to set
*/
public void setEntityType(EntityType type) {
this.type = type;
}
@Override
public boolean isCancelled() {
return cancel;
}
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,56 @@
package org.purpurmc.purpur.event;
import org.bukkit.ExplosionResult;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.BlockExplodeEvent;
import org.jetbrains.annotations.ApiStatus;
import java.util.Collections;
import org.jspecify.annotations.NullMarked;
/**
* Called before a block's explosion is processed
*/
@NullMarked
public class PreBlockExplodeEvent extends BlockExplodeEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private final float yield;
@ApiStatus.Internal
public PreBlockExplodeEvent(final Block what, final float yield, BlockState explodedBlockState, ExplosionResult result) {
super(what, explodedBlockState, Collections.emptyList(), yield, result);
this.yield = yield;
this.cancelled = false;
}
/**
* Returns the percentage of blocks to drop from this explosion
*
* @return The yield.
*/
public float getYield() {
return yield;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,48 @@
package org.purpurmc.purpur.event.entity;
import org.bukkit.Location;
import org.bukkit.entity.Bee;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
/**
* Called when a bee targets a flower
*/
@NullMarked
public class BeeFoundFlowerEvent extends EntityEvent {
private static final HandlerList handlers = new HandlerList();
private final Location location;
@ApiStatus.Internal
public BeeFoundFlowerEvent(Bee bee, @Nullable Location location) {
super(bee);
this.location = location;
}
@Override
public Bee getEntity() {
return (Bee) super.getEntity();
}
/**
* Returns the location of the flower that the bee targets
*
* @return The location of the flower
*/
@Nullable
public Location getLocation() {
return location;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,46 @@
package org.purpurmc.purpur.event.entity;
import org.bukkit.Location;
import org.bukkit.entity.Bee;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Called when a bee starts pollinating
*/
@NullMarked
public class BeeStartedPollinatingEvent extends EntityEvent {
private static final HandlerList handlers = new HandlerList();
private final Location location;
@ApiStatus.Internal
public BeeStartedPollinatingEvent(Bee bee, Location location) {
super(bee);
this.location = location;
}
@Override
public Bee getEntity() {
return (Bee) super.getEntity();
}
/**
* Returns the location of the flower that the bee pollinates
*
* @return The location of the flower
*/
public Location getLocation() {
return this.location;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,60 @@
package org.purpurmc.purpur.event.entity;
import org.bukkit.Location;
import org.bukkit.entity.Bee;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
/**
* Called when a bee stops pollinating
*/
@NullMarked
public class BeeStopPollinatingEvent extends EntityEvent {
private static final HandlerList handlers = new HandlerList();
private final Location location;
private final boolean success;
@ApiStatus.Internal
public BeeStopPollinatingEvent(Bee bee, @Nullable Location location, boolean success) {
super(bee);
this.location = location;
this.success = success;
}
@Override
public Bee getEntity() {
return (Bee) super.getEntity();
}
/**
* Returns the location of the flower that the bee stopped pollinating
*
* @return The location of the flower
*/
@Nullable
public Location getLocation() {
return location;
}
/**
* Returns whether the bee successfully pollinated the flower
*
* @return True if the pollination was successful
*/
public boolean wasSuccessful() {
return success;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,58 @@
package org.purpurmc.purpur.event.entity;
import org.bukkit.entity.Goat;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Called when a goat rams an entity
*/
@NullMarked
public class GoatRamEntityEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final LivingEntity rammedEntity;
private boolean cancelled;
@ApiStatus.Internal
public GoatRamEntityEvent(Goat goat, LivingEntity rammedEntity) {
super(goat);
this.rammedEntity = rammedEntity;
}
/**
* Returns the entity that was rammed by the goat
*
* @return The rammed entity
*/
public LivingEntity getRammedEntity() {
return this.rammedEntity;
}
@Override
public Goat getEntity() {
return (Goat) super.getEntity();
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
}

View File

@@ -0,0 +1,60 @@
package org.purpurmc.purpur.event.entity;
import org.bukkit.entity.Llama;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Called when a Llama tries to join a caravan.
* <p>
* Cancelling the event will not let the Llama join. To prevent future attempts
* at joining a caravan use {@link Llama#setShouldJoinCaravan(boolean)}.
*/
@NullMarked
public class LlamaJoinCaravanEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean canceled;
private final Llama head;
@ApiStatus.Internal
public LlamaJoinCaravanEvent(Llama llama, Llama head) {
super(llama);
this.head = head;
}
@Override
public Llama getEntity() {
return (Llama) entity;
}
/**
* Get the Llama that this Llama is about to follow
*
* @return Llama about to be followed
*/
public Llama getHead() {
return head;
}
@Override
public boolean isCancelled() {
return canceled;
}
@Override
public void setCancelled(boolean cancel) {
canceled = cancel;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,34 @@
package org.purpurmc.purpur.event.entity;
import org.bukkit.entity.Llama;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Called when a Llama leaves a caravan
*/
@NullMarked
public class LlamaLeaveCaravanEvent extends EntityEvent {
private static final HandlerList handlers = new HandlerList();
@ApiStatus.Internal
public LlamaLeaveCaravanEvent(Llama llama) {
super(llama);
}
@Override
public Llama getEntity() {
return (Llama) entity;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,66 @@
package org.purpurmc.purpur.event.entity;
import org.bukkit.ExplosionResult;
import org.bukkit.Location;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.jetbrains.annotations.ApiStatus;
import java.util.Collections;
import org.jspecify.annotations.NullMarked;
/**
* Called before an entity's explosion is processed
*/
@NullMarked
public class PreEntityExplodeEvent extends EntityExplodeEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private final float yield;
private final Location location;
@ApiStatus.Internal
public PreEntityExplodeEvent(org.bukkit.entity.Entity what, final Location location, final float yield, ExplosionResult result) {
super(what, location, Collections.emptyList(), yield, result);
this.cancelled = false;
this.yield = yield;
this.location = location;
}
/**
* Returns the percentage of blocks to drop from this explosion
*
* @return The yield.
*/
public float getYield() {
return yield;
}
/**
* Returns the location where the explosion happened.
*
* @return The location of the explosion
*/
public Location getLocation() {
return location;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,100 @@
package org.purpurmc.purpur.event.entity;
import com.google.common.base.Preconditions;
import org.bukkit.Location;
import org.bukkit.entity.Mob;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Triggered when a ridable mob moves with a rider
*/
@NullMarked
public class RidableMoveEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean canceled;
private final Player rider;
private Location from;
private Location to;
@ApiStatus.Internal
public RidableMoveEvent(Mob entity, Player rider, Location from, Location to) {
super(entity);
this.rider = rider;
this.from = from;
this.to = to;
}
@Override
public Mob getEntity() {
return (Mob) entity;
}
public Player getRider() {
return rider;
}
public boolean isCancelled() {
return canceled;
}
public void setCancelled(boolean cancel) {
canceled = cancel;
}
/**
* Gets the location this entity moved from
*
* @return Location the entity moved from
*/
public Location getFrom() {
return from;
}
/**
* Sets the location to mark as where the entity moved from
*
* @param from New location to mark as the entity's previous location
*/
public void setFrom(Location from) {
validateLocation(from);
this.from = from;
}
/**
* Gets the location this entity moved to
*
* @return Location the entity moved to
*/
public Location getTo() {
return to;
}
/**
* Sets the location that this entity will move to
*
* @param to New Location this entity will move to
*/
public void setTo(Location to) {
validateLocation(to);
this.to = to;
}
private void validateLocation(Location loc) {
Preconditions.checkArgument(loc != null, "Cannot use null location!");
Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!");
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,38 @@
package org.purpurmc.purpur.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.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class RidableSpacebarEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
@ApiStatus.Internal
public RidableSpacebarEvent(Entity entity) {
super(entity);
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,50 @@
package org.purpurmc.purpur.event.inventory;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.inventory.AnvilInventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Called when a player takes the result item out of an anvil
*/
@NullMarked
public class AnvilTakeResultEvent extends InventoryEvent {
private static final HandlerList handlers = new HandlerList();
private final Player player;
private final ItemStack result;
@ApiStatus.Internal
public AnvilTakeResultEvent(HumanEntity player, InventoryView view, ItemStack result) {
super(view);
this.player = (Player) player;
this.result = result;
}
public Player getPlayer() {
return player;
}
public ItemStack getResult() {
return result;
}
@Override
public AnvilInventory getInventory() {
return (AnvilInventory) super.getInventory();
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,35 @@
package org.purpurmc.purpur.event.inventory;
import org.bukkit.event.HandlerList;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.inventory.AnvilInventory;
import org.bukkit.inventory.InventoryView;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Called when anvil slots change, triggering the result slot to be updated
*/
@NullMarked
public class AnvilUpdateResultEvent extends InventoryEvent {
private static final HandlerList handlers = new HandlerList();
@ApiStatus.Internal
public AnvilUpdateResultEvent(InventoryView view) {
super(view);
}
@Override
public AnvilInventory getInventory() {
return (AnvilInventory) super.getInventory();
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,72 @@
package org.purpurmc.purpur.event.inventory;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.inventory.GrindstoneInventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Called when a player takes the result item out of a Grindstone
*/
@NullMarked
public class GrindstoneTakeResultEvent extends InventoryEvent {
private static final HandlerList handlers = new HandlerList();
private final Player player;
private final ItemStack result;
private int experienceAmount;
@ApiStatus.Internal
public GrindstoneTakeResultEvent(HumanEntity player, InventoryView view, ItemStack result, int experienceAmount) {
super(view);
this.player = (Player) player;
this.result = result;
this.experienceAmount = experienceAmount;
}
public Player getPlayer() {
return player;
}
public ItemStack getResult() {
return result;
}
@Override
public GrindstoneInventory getInventory() {
return (GrindstoneInventory) super.getInventory();
}
/**
* Get the amount of experience this transaction will give
* (takes priority over and uses result from {@link org.bukkit.event.block.BlockExpEvent})
*
* @return Amount of experience to give
*/
public int getExperienceAmount() {
return this.experienceAmount;
}
/**
* Set the amount of experience this transaction will give
* (takes priority over {@link org.bukkit.event.block.BlockExpEvent})
*
* @param experienceAmount Amount of experience to give
*/
public void setExperienceAmount(int experienceAmount) {
this.experienceAmount = experienceAmount;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,65 @@
package org.purpurmc.purpur.event.player;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Called when a player tries to bypass book limitations
*/
@NullMarked
public class PlayerBookTooLargeEvent extends PlayerEvent {
private static final HandlerList handlers = new HandlerList();
private final ItemStack book;
private boolean kickPlayer = true;
/**
* @param player The player
* @param book The book
*/
@ApiStatus.Internal
public PlayerBookTooLargeEvent(Player player, ItemStack book) {
super(player, !Bukkit.isPrimaryThread());
this.book = book;
}
/**
* Get the book containing the wanted edits
*
* @return The book
*/
public ItemStack getBook() {
return book;
}
/**
* Whether server should kick the player or not
*
* @return True to kick player
*/
public boolean shouldKickPlayer() {
return kickPlayer;
}
/**
* Whether server should kick the player or not
*
* @param kickPlayer True to kick player
*/
public void setShouldKickPlayer(boolean kickPlayer) {
this.kickPlayer = kickPlayer;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,60 @@
package org.purpurmc.purpur.language;
import net.kyori.adventure.translation.Translatable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
/**
* Represents a language that can translate translation keys
*/
@NullMarked
public abstract class Language {
private static @Nullable Language language;
/**
* Returns the default language of the server
*/
@Nullable
public static Language getLanguage() {
return language;
}
public static void setLanguage(Language language) {
if (Language.language != null) {
throw new UnsupportedOperationException("Cannot redefine singleton Language");
}
Language.language = language;
}
/**
* Checks if a certain translation key is translatable with this language
* @param key The translation key
* @return Whether this language can translate the key
*/
abstract public boolean has(String key);
/**
* Checks if a certain translation key is translatable with this language
* @param key The translation key
* @return Whether this language can translate the key
*/
public boolean has(Translatable key) {
return has(key.translationKey());
}
/**
* Translates a translation key to this language
* @param key The translation key
* @return The translated key, or the translation key if it couldn't be translated
*/
abstract public String getOrDefault(String key);
/**
* Translates a translation key to this language
* @param key The translation key
* @return The translated key, or the translation key if it couldn't be translated
*/
public String getOrDefault(Translatable key) {
return getOrDefault(key.translationKey());
}
}

View File

@@ -0,0 +1,87 @@
package org.purpurmc.purpur.util.permissions;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Mob;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.util.permissions.DefaultPermissions;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
public final class PurpurPermissions {
private static final String ROOT = "purpur";
private static final String PREFIX = ROOT + ".";
private static final Set<String> mobs = new HashSet<>();
static {
for (EntityType mob : EntityType.values()) {
Class<? extends Entity> clazz = mob.getEntityClass();
if (clazz != null && Mob.class.isAssignableFrom(clazz)) {
mobs.add(mob.getName());
}
}
}
@NotNull
public static Permission registerPermissions() {
Permission purpur = DefaultPermissions.registerPermission(ROOT, "Gives the user the ability to use all Purpur utilities and commands", PermissionDefault.FALSE);
DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.six", "Gives the user six rows of enderchest space", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.five", "Gives the user five rows of enderchest space", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.four", "Gives the user four rows of enderchest space", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.three", "Gives the user three rows of enderchest space", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.two", "Gives the user two rows of enderchest space", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.one", "Gives the user one row of enderchest space", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "debug.f3n", "Allows the user to use F3+N keybind to swap gamemodes", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "joinfullserver", "Allows the user to join a full server", PermissionDefault.OP, purpur);
DefaultPermissions.registerPermission(PREFIX + "bypassIdleKick", "Allows the user to bypass being kicked while idle", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "inventory_totem", "Allows the user to use totem of undying anywhere in their inventory", PermissionDefault.FALSE, purpur);
Permission anvil = DefaultPermissions.registerPermission(PREFIX + "anvil", "Allows the user to use all anvil color and format abilities", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "anvil.color", "Allows the user to use color codes in an anvil", PermissionDefault.FALSE, anvil);
DefaultPermissions.registerPermission(PREFIX + "anvil.minimessage", "Allows the user to use minimessage tags in an anvil", PermissionDefault.FALSE, anvil);
DefaultPermissions.registerPermission(PREFIX + "anvil.remove_italics", "Allows the user to remove italics in an anvil", PermissionDefault.FALSE, anvil);
DefaultPermissions.registerPermission(PREFIX + "anvil.format", "Allows the user to use format codes in an anvil", PermissionDefault.FALSE, anvil);
anvil.recalculatePermissibles();
Permission book = DefaultPermissions.registerPermission(PREFIX + "book", "Allows the user to use color codes on books", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "book.color.edit", "Allows the user to use color codes on books when editing", PermissionDefault.FALSE, book);
DefaultPermissions.registerPermission(PREFIX + "book.color.sign", "Allows the user to use color codes on books when signing", PermissionDefault.FALSE, book);
book.recalculatePermissibles();
Permission sign = DefaultPermissions.registerPermission(PREFIX + "sign", "Allows the user to use all sign abilities", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission(PREFIX + "sign.edit", "Allows the user to click signs to open sign editor", PermissionDefault.TRUE, sign);
DefaultPermissions.registerPermission(PREFIX + "sign.color", "Allows the user to use color codes on signs", PermissionDefault.FALSE, sign);
DefaultPermissions.registerPermission(PREFIX + "sign.style", "Allows the user to use style codes on signs", PermissionDefault.FALSE, sign);
DefaultPermissions.registerPermission(PREFIX + "sign.magic", "Allows the user to use magic/obfuscate code on signs", PermissionDefault.FALSE, sign);
sign.recalculatePermissibles();
Permission ride = DefaultPermissions.registerPermission("allow.ride", "Allows the user to ride all mobs", PermissionDefault.FALSE, purpur);
for (String mob : mobs) {
DefaultPermissions.registerPermission("allow.ride." + mob, "Allows the user to ride " + mob, PermissionDefault.FALSE, ride);
}
ride.recalculatePermissibles();
Permission special = DefaultPermissions.registerPermission("allow.special", "Allows the user to use all mobs special abilities", PermissionDefault.FALSE, purpur);
for (String mob : mobs) {
DefaultPermissions.registerPermission("allow.special." + mob, "Allows the user to use " + mob + " special ability", PermissionDefault.FALSE, special);
}
special.recalculatePermissibles();
Permission powered = DefaultPermissions.registerPermission("allow.powered", "Allows the user to toggle all mobs powered state", PermissionDefault.FALSE, purpur);
DefaultPermissions.registerPermission("allow.powered.creeper", "Allows the user to toggle creeper powered state", PermissionDefault.FALSE, powered);
powered.recalculatePermissibles();
DefaultPermissions.registerPermission(PREFIX + "portal.instant", "Allows the user to bypass portal wait time", PermissionDefault.FALSE, purpur);
purpur.recalculatePermissibles();
return purpur;
}
}