From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Sun, 6 Apr 2025 06:33:23 +0000 Subject: [PATCH] Purpur API Changes Original license: MIT Original project: https://github.com/PurpurMC/Purpur Commit: 61d7f5590e79909caba55e9f00cefdd51006d015 Patches listed below are removed in this patch, They exists in Gale or Leaf: * "co/aikar/timings/TimedEventExecutor.java.patch" * "co/aikar/timings/Timing.java.patch" * "co/aikar/timings/Timings.java.patch" * "co/aikar/timings/TimingsCommand.java.patch" * "com/destroystokyo/paper/util/VersionFetcher.java.patch" * "org/bukkit/command/defaults/VersionCommand.java.patch" * "org/bukkit/command/SimpleCommandMap.java.patch" (Timings changes) * "org/bukkit/plugin/java/JavaPluginLoader.java.patch" * "org/bukkit/plugin/java/LibraryLoader.java.patch" * "org/spigotmc/CustomTimingsHandler.java.patch" diff --git a/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java index 12207256ae0fa5f2f822116cd22f1a1250e6ee1c..07a9ccf572e514047a5af7071b9270d2ed9c1c72 100644 --- a/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +++ b/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java @@ -441,6 +441,26 @@ public interface VanillaGoal extends Goal { GoalKey ZOMBIE_ATTACK_TURTLE_EGG = create("zombie_attack_turtle_egg", Zombie.class); + // Purpur start - Ridables + GoalKey MOB_HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider")); + GoalKey HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider")); + GoalKey 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 FIND_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal")); + GoalKey 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_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager")); + GoalKey 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 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 RECEIVE_FLOWER = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("receive_flower")); + // Purpur end - Iron golem poppy calms anger + private static GoalKey create(final String key, final Class type) { return GoalKey.of(type, NamespacedKey.minecraft(key)); } diff --git a/src/main/java/io/papermc/paper/ServerBuildInfo.java b/src/main/java/io/papermc/paper/ServerBuildInfo.java index f738bbcefe288474c5f591dda03d713850633854..5c10ab3deb359bd0045ba5999bcbce19a7949eaa 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 // Leaf start - Rebrand /** * The brand id for Gale. diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java index 2e316238da9377c046105249273b260912ebfcab..98cfd68226494dbb1a2eaa6680e23a76c2129a62 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java @@ -3073,4 +3073,133 @@ public final class Bukkit { 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. + *

+ * Clients may be inconsistent in displaying it. + * @param location Location to highlight + * @param duration Duration for highlight to show in milliseconds + */ + 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. + *

+ * 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 + */ + 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. + *

+ * 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 + */ + 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. + *

+ * 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 + */ + 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. + *

+ * 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 + */ + 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. + *

+ * 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 + */ + 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. + */ + public static void clearBlockHighlights() { + server.clearBlockHighlights(); + } + // Purpur end - Debug Marker API } diff --git a/src/main/java/org/bukkit/ChatColor.java b/src/main/java/org/bukkit/ChatColor.java index 918a045165cdcde264bc24082b7afebb407271de..f283bcabff7fe6eede6cf4344537e43048c35166 100644 --- a/src/main/java/org/bukkit/ChatColor.java +++ b/src/main/java/org/bukkit/ChatColor.java @@ -456,4 +456,77 @@ public enum ChatColor { 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", "") + .replace("&1", "") + .replace("&2", "") + .replace("&3", "") + .replace("&4", "") + .replace("&5", "") + .replace("&6", "") + .replace("&7", "") + .replace("&8", "") + .replace("&9", "") + .replace("&a", "") + .replace("&b", "") + .replace("&c", "") + .replace("&d", "") + .replace("&e", "") + .replace("&f", "") + .replace("&k", "") + .replace("&l", "") + .replace("&m", "") + .replace("&n", "") + .replace("&o", "") + .replace("&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 } diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java index 5a1b9f81830dee052bafd743f4a1bf0c39288c7a..cf8fd9a981c7fbaa304988df17233ccf40d6829e 100644 --- a/src/main/java/org/bukkit/Material.java +++ b/src/main/java/org/bukkit/Material.java @@ -3616,4 +3616,40 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla return this.asItemType().getDefaultDataTypes(); } // Paper end - data component API + + // Purpur start - ItemStack convenience methods + public boolean isArmor() { + switch (this) { + // + 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 } diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java index 6f83097b1097d0ffa81a95e6f0300cb410dfee2b..c1f19d5c1b819873fce1185b4fbf4c72eda26309 100644 --- a/src/main/java/org/bukkit/OfflinePlayer.java +++ b/src/main/java/org/bukkit/OfflinePlayer.java @@ -585,4 +585,104 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio @Override io.papermc.paper.persistence.PersistentDataContainerView getPersistentDataContainer(); // Paper end - add pdc to offline player + + // 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 true if teleportation successful + */ + java.util.concurrent.CompletableFuture 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 true if teleportation successful + */ + java.util.concurrent.CompletableFuture teleportOfflineAsync(Location destination, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause); + // Purpur end - OfflinePlayer API } diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java index e8f192bad2ffa3cb1c5217293420a863d57b5377..002c998368dea33872d65beb79eb4931ce1158d2 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -2432,6 +2432,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 + // Leaf start - Leaf config - API @NotNull public org.bukkit.configuration.file.YamlConfiguration getLeafConfig() @@ -2801,4 +2813,121 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi */ long getLastTickOversleepTime(); // Gale end - YAPFA - last tick time - API + + // 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. + *

+ * Clients may be inconsistent in displaying it. + * + * @param location Location to highlight + * @param duration Duration for highlight to show in milliseconds + */ + void sendBlockHighlight(@NotNull Location location, int duration); + + /** + * Creates debug block highlight on specified block location and show it to all players on the server. + *

+ * 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(@NotNull Location location, int duration, int argb); + + /** + * Creates debug block highlight on specified block location and show it to all players on the server. + *

+ * 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(@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. + *

+ * 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(@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. + *

+ * 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(@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. + *

+ * 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(@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. + */ + void clearBlockHighlights(); + // Purpur end - Debug Marker API } diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java index a8b64f78bf3c453094074b4b4d3c8fd07b9eb273..d0c2ff65893c1fd3903633ebc24aae879dc91f10 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java @@ -4290,6 +4290,86 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient @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. + *

+ * Clients may be inconsistent in displaying it. + * @param location Location to highlight + * @param duration Duration for highlight to show in milliseconds + */ + void sendBlockHighlight(@NotNull Location location, int duration); + + /** + * Creates debug block highlight on specified block location and show it to all players on this world. + *

+ * 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(@NotNull Location location, int duration, int argb); + + /** + * Creates debug block highlight on specified block location and show it to all players on this world. + *

+ * 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(@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. + *

+ * 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(@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. + *

+ * 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(@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. + *

+ * 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(@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. + */ + void clearBlockHighlights(); + // Purpur end + /** * Get all {@link FeatureFlag} enabled in this world. * diff --git a/src/main/java/org/bukkit/block/EntityBlockStorage.java b/src/main/java/org/bukkit/block/EntityBlockStorage.java index 739911cda33b373f99df627a3a378b37d7d461aa..58e16c12b06fa11d30b67f5038844ff9990790ae 100644 --- a/src/main/java/org/bukkit/block/EntityBlockStorage.java +++ b/src/main/java/org/bukkit/block/EntityBlockStorage.java @@ -47,6 +47,25 @@ public interface EntityBlockStorage extends TileState { @NotNull List 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 entity); + + /** + * Gets all the entities currently stored in the block. + * + * @return List of all entities which are stored in the block + */ + @NotNull + List> getEntities(); + // Purpur end - Stored Bee API + /** * Add an entity to the block. * diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java index 4acda947b7d69ab4133b4cc94e76d945e4d148d5..613a0bad5c07cf14098218652eba1f4deaf77c6d 100644 --- a/src/main/java/org/bukkit/command/SimpleCommandMap.java +++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java @@ -146,6 +146,19 @@ public class SimpleCommandMap implements CommandMap { 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,7 +168,7 @@ public class SimpleCommandMap implements CommandMap { try { try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources // 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.execute(sender, sentCommandLabel, parsedArgs); // Purpur - ExecuteCommandEvent } // target.timings.stopTiming(); // Spigot // Paper } catch (CommandException ex) { server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java index 4b66de5614afed3feb2838771f8a2c3c539b0a9e..0c9680732fb92030ac0dd3099509cd6e46c67578 100644 --- a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java +++ b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java @@ -230,6 +230,30 @@ public enum EnchantmentTarget { public boolean includes(@NotNull Material item) { return BREAKABLE.includes(item) || (WEARABLE.includes(item) && !item.equals(Material.ELYTRA)) || item.equals(Material.COMPASS); } + // 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 }; /** diff --git a/src/main/java/org/bukkit/entity/Endermite.java b/src/main/java/org/bukkit/entity/Endermite.java index 332c55fd6b4b3a8c0cad920a6e765ecc40e684e4..10a8d64ad2da0be2c14f34c3e7d1957c6f2883d1 100644 --- a/src/main/java/org/bukkit/entity/Endermite.java +++ b/src/main/java/org/bukkit/entity/Endermite.java @@ -3,25 +3,21 @@ package org.bukkit.entity; 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 /** diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java index 66a31c5d83b78dddb43e70cfd5ce7c7fb8a551b6..b6ee04873c1ee57f7e8804f6d247806f2c0e448f 100644 --- a/src/main/java/org/bukkit/entity/Entity.java +++ b/src/main/java/org/bukkit/entity/Entity.java @@ -1261,4 +1261,59 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent */ void broadcastHurtAnimation(@NotNull java.util.Collection 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 } diff --git a/src/main/java/org/bukkit/entity/IronGolem.java b/src/main/java/org/bukkit/entity/IronGolem.java index 655e37cb3a09610a3f3df805d6dcad17d722da62..09fd716c8fc9ea34a1cbf87bcbe22df035422a51 100644 --- a/src/main/java/org/bukkit/entity/IronGolem.java +++ b/src/main/java/org/bukkit/entity/IronGolem.java @@ -19,4 +19,20 @@ public interface IronGolem extends Golem { * 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 } diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java index bcc6ba95bd21c7972865838c636a03f50b6c1f1a..c3fcd8dd7dbb1e1a18e17c014c1e641149ea5960 100644 --- a/src/main/java/org/bukkit/entity/Item.java +++ b/src/main/java/org/bukkit/entity/Item.java @@ -153,4 +153,62 @@ public interface Item extends Entity, io.papermc.paper.entity.Frictional { // Pa */ 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 } diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java index 7f2892dd93a17136e1aaea14db401710bc1becfb..8c0659efa5c84191f3faa1ada52e57eb2a4f9f90 100644 --- a/src/main/java/org/bukkit/entity/LivingEntity.java +++ b/src/main/java/org/bukkit/entity/LivingEntity.java @@ -1463,4 +1463,20 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource */ @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 } diff --git a/src/main/java/org/bukkit/entity/Llama.java b/src/main/java/org/bukkit/entity/Llama.java index bc84b892cae5fe7019a3ad481e9da79956efa1fe..48eb5b00c460cccde29d327cef1d63fc04d6a829 100644 --- a/src/main/java/org/bukkit/entity/Llama.java +++ b/src/main/java/org/bukkit/entity/Llama.java @@ -119,4 +119,20 @@ public interface Llama extends ChestedHorse, RangedEntity { // Paper @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 } diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java index c44453789834c544b0e78b52bb9b09ffbd5958fb..d4082cd6dae07958ace3b9e9769ccb7da4c2a828 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -3935,4 +3935,123 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @param score New death screen score of player */ void setDeathScreenScore(int score); + + // 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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 } diff --git a/src/main/java/org/bukkit/entity/Snowman.java b/src/main/java/org/bukkit/entity/Snowman.java index 7fbfdb07585c7b28acea1f0c1f58ada0cc744441..21fcca092e2e31baa5ece0de9e44e3fade8c7123 100644 --- a/src/main/java/org/bukkit/entity/Snowman.java +++ b/src/main/java/org/bukkit/entity/Snowman.java @@ -23,4 +23,20 @@ public interface Snowman extends Golem, RangedEntity, io.papermc.paper.entity.Sh * @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 } diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java index 4d88bb2eaa43709fb6103a6f77d8c01e83bfe743..bb3773e002ebcfd8eced792bf0236c4cfbae8663 100644 --- a/src/main/java/org/bukkit/entity/Villager.java +++ b/src/main/java/org/bukkit/entity/Villager.java @@ -408,4 +408,13 @@ public interface Villager extends AbstractVillager { * 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 } diff --git a/src/main/java/org/bukkit/entity/Wither.java b/src/main/java/org/bukkit/entity/Wither.java index 11ae1b3ad8c215f9245945d223c52f4a62ac47d9..7f23eb5a60ff08fb31e8ba3731a43bd75690214a 100644 --- a/src/main/java/org/bukkit/entity/Wither.java +++ b/src/main/java/org/bukkit/entity/Wither.java @@ -105,4 +105,20 @@ public interface Wither extends Monster, Boss, com.destroystokyo.paper.entity.Ra * 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 } diff --git a/src/main/java/org/bukkit/entity/Wolf.java b/src/main/java/org/bukkit/entity/Wolf.java index a6414ffc4a6d8ebef3486abc877688507e34e5c8..ade8b061f0a3d94f990e997659d5ad32aa1631c4 100644 --- a/src/main/java/org/bukkit/entity/Wolf.java +++ b/src/main/java/org/bukkit/entity/Wolf.java @@ -163,4 +163,20 @@ public interface Wolf extends Tameable, Sittable, io.papermc.paper.entity.Collar 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 } diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java index 6d5ae34b39d6001effc2faadd6c30e3a8ab109fa..e8c7aebcab1649e55ab9e947036c9fab839cd675 100644 --- a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java @@ -310,7 +310,8 @@ public class EntityDamageEvent extends EntityEvent implements Cancellable { 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) *

* Damage: variable */ diff --git a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java index 22e14ba522510d659c191d72536cde895458d9ed..d45d781975a6026022712a217c154e316ff48f9f 100644 --- a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java @@ -218,6 +218,12 @@ public class EntityPotionEffectEvent extends EntityEvent implements Cancellable * 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 a player gets bad omen after killing a patrol captain. * diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java index 81118a91c2e22e02a1f774d1cc4d3e97064087ce..6640df827e354cc32cea5fc71b9e464443202708 100644 --- a/src/main/java/org/bukkit/event/inventory/InventoryType.java +++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java @@ -164,7 +164,7 @@ public enum InventoryType { 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; diff --git a/src/main/java/org/bukkit/inventory/AnvilInventory.java b/src/main/java/org/bukkit/inventory/AnvilInventory.java index f1f97a85ec713c05c882d7588f4a3e4a017f4795..813f6cd253322538bdf96eb323dd23a7809a1c1e 100644 --- a/src/main/java/org/bukkit/inventory/AnvilInventory.java +++ b/src/main/java/org/bukkit/inventory/AnvilInventory.java @@ -138,4 +138,42 @@ public interface AnvilInventory extends Inventory { 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 } diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java index 8a5a58408490110dfeb1a720aad6676883880db5..5ee730161c7f11ab7744c80563716e30921a6b5b 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java @@ -24,6 +24,13 @@ import org.bukkit.material.MaterialData; 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 +1380,482 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat return this.craftDelegate.matchesWithoutData(item, excludeTypes, ignoreCount); } // Paper end - data component API + + // Purpur start - ItemStack convenience methods + /** + * Gets the display name that is set. + *

+ * Plugins should check that hasDisplayName() returns true + * 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. + *

+ * Plugins should check that hasLocalizedName() returns true + * 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.
+ * Returns an empty map if none. + * + * @return An immutable copy of the enchantments + */ + @NotNull + public Map 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. + *

+ * 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. + *

+ * CustomModelData is an integer that may be associated client side with a + * custom item model. + *

+ * Plugins should check that hasCustomModelData() returns true + * 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. + *

+ * 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.
+ * Returns null if none exist. + * + * @return an immutable {@link Multimap} of Attributes + * and their AttributeModifiers, or null if none exist + */ + @Nullable + public Multimap getAttributeModifiers() { + return this.craftDelegate.getAttributeModifiers(); + } + + /** + * Return an immutable copy of all {@link Attribute}s and their + * {@link AttributeModifier}s for a given {@link EquipmentSlot}.
+ * 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.
+ * 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 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 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. + *
+ * 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 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}.
+ * 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 } diff --git a/src/main/java/org/bukkit/inventory/RecipeChoice.java b/src/main/java/org/bukkit/inventory/RecipeChoice.java index 922bb69b5f218e489a6dd5e0f207743c1f1d3d35..3606c6457a98e0e39d6a4b171bc11b61aac73e5c 100644 --- a/src/main/java/org/bukkit/inventory/RecipeChoice.java +++ b/src/main/java/org/bukkit/inventory/RecipeChoice.java @@ -191,6 +191,7 @@ public interface RecipeChoice extends Predicate, Cloneable { public static class ExactChoice implements RecipeChoice { private List choices; + private Predicate predicate; // Purpur - Add predicate to recipe's ExactChoice ingredient public ExactChoice(@NotNull ItemStack stack) { this(Arrays.asList(stack)); @@ -241,6 +242,7 @@ public interface RecipeChoice extends Predicate, Cloneable { @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; @@ -250,6 +252,17 @@ public interface RecipeChoice extends Predicate, Cloneable { return false; } + // Purpur start - Add predicate to recipe's ExactChoice ingredient + @org.jetbrains.annotations.Nullable + public Predicate getPredicate() { + return predicate; + } + + public void setPredicate(@org.jetbrains.annotations.Nullable Predicate predicate) { + this.predicate = predicate; + } + // Purpur end - Add predicate to recipe's ExactChoice ingredient + @Override public int hashCode() { int hash = 7; diff --git a/src/main/java/org/bukkit/inventory/view/AnvilView.java b/src/main/java/org/bukkit/inventory/view/AnvilView.java index 3c1aa1e036bee08304c1cdca59f6a5bc0ba306c0..b273e168c976fb6e185da3ba83d9d69e0b2e7920 100644 --- a/src/main/java/org/bukkit/inventory/view/AnvilView.java +++ b/src/main/java/org/bukkit/inventory/view/AnvilView.java @@ -89,4 +89,34 @@ public interface AnvilView extends InventoryView { */ 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 } diff --git a/src/main/java/org/bukkit/map/MapRenderer.java b/src/main/java/org/bukkit/map/MapRenderer.java index cb7040876a99a5a7e49b81684ef0f3b79584c376..63351a0fb4263e2e7ccb6896768a5b10378de297 100644 --- a/src/main/java/org/bukkit/map/MapRenderer.java +++ b/src/main/java/org/bukkit/map/MapRenderer.java @@ -54,4 +54,12 @@ public abstract class MapRenderer { */ 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 } diff --git a/src/main/java/org/bukkit/permissions/PermissibleBase.java b/src/main/java/org/bukkit/permissions/PermissibleBase.java index 75b77cc4fe189b4b6baa1af3663dc492e992a266..1aa3c6dbf2f2a62fbec990f931d5c5d5c8e5a0bd 100644 --- a/src/main/java/org/bukkit/permissions/PermissibleBase.java +++ b/src/main/java/org/bukkit/permissions/PermissibleBase.java @@ -169,7 +169,7 @@ public class PermissibleBase implements Permissible { 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 +197,7 @@ public class PermissibleBase implements Permissible { 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)); diff --git a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java index 7763d6101ac61900db1e2310966b99584539fd0e..48c67cb3a7073db85d7cf2308e5b1aae89b7a1d2 100644 --- a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java +++ b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java @@ -18,6 +18,7 @@ public final class CommandPermissions { 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; diff --git a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java index e1a4ddf2c07cdd242fa8054a0152522fe4039e85..5329de48a739cafac98514e24edaf5f1b9d41fff 100644 --- a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java +++ b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java @@ -31,7 +31,7 @@ public final class DefaultPermissions { 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 +40,7 @@ public final class DefaultPermissions { @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 +53,7 @@ public final class DefaultPermissions { @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 +66,7 @@ public final class DefaultPermissions { @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 +79,7 @@ public final class DefaultPermissions { @NotNull public static Permission registerPermission(@NotNull String name, @Nullable String desc, @Nullable PermissionDefault def, @Nullable Map 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; } @@ -89,6 +89,8 @@ public final class DefaultPermissions { CommandPermissions.registerPermissions(parent); BroadcastPermissions.registerPermissions(parent); + org.purpurmc.purpur.util.permissions.PurpurPermissions.registerPermissions(); // Purpur - Default permissions + parent.recalculatePermissibles(); } } diff --git a/src/main/java/org/purpurmc/purpur/entity/StoredEntity.java b/src/main/java/org/purpurmc/purpur/entity/StoredEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..29540d55532197d2381a52ea9222b5785d224ef8 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/entity/StoredEntity.java @@ -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 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 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(); +} diff --git a/src/main/java/org/purpurmc/purpur/event/ExecuteCommandEvent.java b/src/main/java/org/purpurmc/purpur/event/ExecuteCommandEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..55feef2321c7d966c72a33a58cf10136a9cacfa6 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/ExecuteCommandEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/PlayerAFKEvent.java b/src/main/java/org/purpurmc/purpur/event/PlayerAFKEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..e9637b82014fe3f4f4671b24d18f77f3d5e4b8ad --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/PlayerAFKEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java b/src/main/java/org/purpurmc/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..795c558b481f4e2a550925bd88b8e7d41711456f --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/PlayerSetTrialSpawnerTypeWithEggEvent.java b/src/main/java/org/purpurmc/purpur/event/PlayerSetTrialSpawnerTypeWithEggEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..1d4dbf60a182a2a5f93c449e387b82743d20616c --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/PlayerSetTrialSpawnerTypeWithEggEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java b/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..4b4d32c58224e1208f14024ca214078a37550bb5 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/entity/BeeFoundFlowerEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/BeeFoundFlowerEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..7f631a41abee4640a37339a7896ce96e61747735 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/BeeFoundFlowerEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/entity/BeeStartedPollinatingEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/BeeStartedPollinatingEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..e260145d6dc556bbe9e3654296b965c4e393084d --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/BeeStartedPollinatingEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/entity/BeeStopPollinatingEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/BeeStopPollinatingEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..8b2b351d620c749cdf58d7e824b55cf55578fde6 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/BeeStopPollinatingEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..daf3bbf83ee76322828a38814b483fa2b337bd60 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java @@ -0,0 +1,114 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * Fired when an entity is hindered from teleporting. + */ +@NullMarked +public class EntityTeleportHinderedEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + + private final Reason reason; + + private final @Nullable TeleportCause teleportCause; + + private boolean retry = false; + + @ApiStatus.Internal + public EntityTeleportHinderedEvent(Entity what, Reason reason, @Nullable TeleportCause teleportCause) { + super(what); + this.reason = reason; + this.teleportCause = teleportCause; + } + + /** + * @return why the teleport was hindered. + */ + public Reason getReason() { + return reason; + } + + /** + * @return why the teleport occurred if cause was given, otherwise {@code null}. + */ + @Nullable + public TeleportCause getTeleportCause() { + return teleportCause; + } + + /** + * Whether the teleport should be retried. + *

+ * Note that this can put the server in a never-ending loop of trying to teleport someone resulting in a stack + * overflow. Do not retry more than necessary. + *

+ * + * @return whether the teleport should be retried. + */ + public boolean shouldRetry() { + return retry; + } + + /** + * Sets whether the teleport should be retried. + *

+ * Note that this can put the server in a never-ending loop of trying to teleport someone resulting in a stack + * overflow. Do not retry more than necessary. + *

+ * + * @param retry whether the teleport should be retried. + */ + public void setShouldRetry(boolean retry) { + this.retry = retry; + } + + /** + * Calls the event and tests if should retry. + * + * @return whether the teleport should be retried. + */ + @Override + public boolean callEvent() { + super.callEvent(); + return shouldRetry(); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + /** + * Reason for hindrance in teleports. + */ + public enum Reason { + /** + * The teleported entity is a passenger of another entity. + */ + IS_PASSENGER, + + /** + * The teleported entity has passengers. + */ + IS_VEHICLE, + + /** + * The teleport event was cancelled. + *

+ * This is only caused by players teleporting. + *

+ */ + EVENT_CANCELLED, + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/entity/GoatRamEntityEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/GoatRamEntityEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..f0a7fe694db145294ff93d320382d1baecc68702 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/GoatRamEntityEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/entity/LlamaJoinCaravanEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/LlamaJoinCaravanEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..e34c37579dc8a5a108c03b9eff6bb916a910d867 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/LlamaJoinCaravanEvent.java @@ -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. + *

+ * 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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/entity/LlamaLeaveCaravanEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/LlamaLeaveCaravanEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..23ea41ff5dc43a915a263aeb1a246705de8bf9e1 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/LlamaLeaveCaravanEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/entity/PreEntityExplodeEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/PreEntityExplodeEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..d56fb066455007cc710f7ba34ba722af6e89bc1d --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/PreEntityExplodeEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/entity/RidableMoveEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/RidableMoveEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..c31a656daa3df1ab87302d8f14110a828c920102 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/RidableMoveEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/entity/RidableSpacebarEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/RidableSpacebarEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..02de629f066ef7d4898b3053efa957edeea16a3f --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/RidableSpacebarEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..b2199854b5c7e74a673cbadbe584e5aaebbe3883 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..4293c4a57c1c054e8248b7712e8664bd4cb1a972 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java b/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..d6db2d355553c9c54b83328d237b9c75e7a8e375 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java b/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..31cce9f4e398135016114b96254376325a22ba7c --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java @@ -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; + } +} diff --git a/src/main/java/org/purpurmc/purpur/language/Language.java b/src/main/java/org/purpurmc/purpur/language/Language.java new file mode 100644 index 0000000000000000000000000000000000000000..cbdad4cf09c170064a45644efdf7aa0b28608301 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/language/Language.java @@ -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()); + } +} diff --git a/src/main/java/org/purpurmc/purpur/util/permissions/PurpurPermissions.java b/src/main/java/org/purpurmc/purpur/util/permissions/PurpurPermissions.java new file mode 100644 index 0000000000000000000000000000000000000000..50647252ed654fbcf71db72a283fb8080ecee6d3 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/util/permissions/PurpurPermissions.java @@ -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 mobs = new HashSet<>(); + + static { + for (EntityType mob : EntityType.values()) { + Class 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; + } +}