From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Mon, 29 Apr 2024 09:05:40 +0000 Subject: [PATCH] Purpur API Changes Original license: MIT Original project: https://github.com/PurpurMC/Purpur Commit: 8aa793450315a361548f5e1dce4edf18e606bf51 Patches below are removed in this patch: Pufferfish-API-Changes.patch Fix-pufferfish-issues.patch Build-System-Changes.patch Remove-Timings.patch Add-log-suppression-for-LibraryLoader.patch diff --git a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java index a736d7bcdc5861a01b66ba36158db1c716339346..22fc165fd9c95f0f3ae1be7a0857e48cc50fad5b 100644 --- a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java +++ b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java @@ -26,6 +26,12 @@ public interface VersionFetcher { @NotNull Component getVersionMessage(@NotNull String serverVersion); + // Purpur start + default int distance() { + return 0; + } + // Purpur end + class DummyVersionFetcher implements VersionFetcher { @Override diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java index 8dfb22c3cf06c8037ca709ebd486a37c71a5a352..76dbc19ab0b87a3b081dbc38e8185268a50f4e3e 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java @@ -2977,4 +2977,127 @@ public final class Bukkit { public static Server.Spigot spigot() { return server.spigot(); } + + // Purpur start + /** + * Get the name of this server + * @return the name of the server + */ + @NotNull + public static String getServerName() { + return server.getServerName(); + } + + /** + * Check if server is lagging according to laggy threshold setting + * + * @return True if lagging + */ + public static boolean isLagging() { + return server.isLagging(); + } + + /** + * 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); + } + + /** + * 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 } diff --git a/src/main/java/org/bukkit/ChatColor.java b/src/main/java/org/bukkit/ChatColor.java index 918a045165cdcde264bc24082b7afebb407271de..687d11619379aead7f665d4a5f8f8bcc857cb8e9 100644 --- a/src/main/java/org/bukkit/ChatColor.java +++ b/src/main/java/org/bukkit/ChatColor.java @@ -3,6 +3,7 @@ package org.bukkit; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import java.util.Map; +import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -456,4 +457,77 @@ public enum ChatColor { BY_CHAR.put(color.code, color); } } + + // Purpur start + /** + * 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); + 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 } diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java index 7a337fe908915f8ea487a0b9236c511cb07d5e66..1dd02e2782364bf25521088cf8858d3443643447 100644 --- a/src/main/java/org/bukkit/Material.java +++ b/src/main/java/org/bukkit/Material.java @@ -11657,4 +11657,40 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla public boolean isEnabledByFeature(@NotNull World world) { return Bukkit.getDataPackManager().isEnabledByFeature(this, world); } + + // Purpur start + 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 } diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java index 30298a629b39bd43ce14b414fc697b2dfcbea89c..ce00af9121de7a910aaea4e0685a06d4cf31b4e3 100644 --- a/src/main/java/org/bukkit/OfflinePlayer.java +++ b/src/main/java/org/bukkit/OfflinePlayer.java @@ -557,4 +557,106 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio */ @Nullable public Location getLocation(); + + // 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. + */ + public 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. + */ + public void setAllowFlight(boolean flight); + + /** + * Checks to see if this player is currently flying or not. + * + * @return True if the player is flying, else false. + */ + public boolean isFlying(); + + /** + * Makes this player start or stop flying. + * + * @param value True to fly. + */ + public 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 + */ + public 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 + */ + public 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 + */ + public float getFlySpeed(); + + /** + * Gets the current allowed speed that a client can walk. + * + * @return The current allowed speed, from -1 to 1 + */ + public 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 + */ + public boolean teleportOffline(@NotNull 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 + */ + public boolean teleportOffline(@NotNull org.bukkit.Location destination, @NotNull 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 + */ + @NotNull + public java.util.concurrent.CompletableFuture teleportOfflineAsync(@NotNull 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 + */ + @NotNull + public java.util.concurrent.CompletableFuture teleportOfflineAsync(@NotNull Location destination, @NotNull 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 4fefbde12a189a481efd0fd0fec06ff0bd02a57b..5f306e9cf3ca332338a82414a420f3c7a58c31fe 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -2310,6 +2310,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 @NotNull public org.bukkit.configuration.file.YamlConfiguration getLeafConfig() @@ -2627,4 +2639,104 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi long getLastTickOversleepTime(); // Gale end - YAPFA - last tick time - API + // Purpur start + /** + * Get the name of this server + * @return the name of the server + */ + @NotNull + String getServerName(); + + /** + * Check if server is lagging according to laggy threshold setting + * + * @return True if lagging + */ + boolean isLagging(); + + /** + * 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); + + /** + * 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 } diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java index 97f97ea5c6aa513c439f86a9c82821e0f7d9cd1e..83a5b68c785a88594e6e3824ed282844086f7f1a 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java @@ -4249,6 +4249,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..51e78c22cd021722b963fe31d1d9175d141add1a 100644 --- a/src/main/java/org/bukkit/block/EntityBlockStorage.java +++ b/src/main/java/org/bukkit/block/EntityBlockStorage.java @@ -47,6 +47,24 @@ public interface EntityBlockStorage extends TileState { @NotNull List releaseEntities(); + // Purpur start + /** + * 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 /** * 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 ac9a28922f8a556944a4c3649d74c32c622f0cb0..e842d13febca67ffa1c89fb2c1324d2609fb81fd 100644 --- a/src/main/java/org/bukkit/command/SimpleCommandMap.java +++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java @@ -143,6 +143,19 @@ public class SimpleCommandMap implements CommandMap { return false; } + // Purpur start + 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 + // Paper start - Plugins do weird things to workaround normal registration if (target.timings == null) { target.timings = co.aikar.timings.TimingsManager.getCommandTiming(null, target); @@ -152,7 +165,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 } // 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/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java index fd5d9881abfd930bb883120f018f76dc78b62b14..d3dadad49df09e85c724c93e8cc88da2c985e9b4 100644 --- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java +++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java @@ -214,7 +214,7 @@ public class VersionCommand extends BukkitCommand { String version = Bukkit.getVersion(); // Paper start if (version.startsWith("null")) { // running from ide? - setVersionMessage(Component.text("Unknown version, custom build?", NamedTextColor.YELLOW)); + setVersionMessage(Component.text("* Unknown version, custom build?", NamedTextColor.RED)); // Purpur return; } setVersionMessage(getVersionFetcher().getVersionMessage(version)); @@ -255,9 +255,11 @@ public class VersionCommand extends BukkitCommand { // Paper start private void setVersionMessage(final @NotNull Component msg) { lastCheck = System.currentTimeMillis(); - final Component message = Component.textOfChildren( - Component.text(Bukkit.getVersionMessage(), NamedTextColor.WHITE), - Component.newline(), + // Purpur start + int distance = getVersionFetcher().distance(); + final Component message = Component.join(net.kyori.adventure.text.JoinConfiguration.separator(Component.newline()), + ChatColor.parseMM("Current: %s%s*", distance == 0 ? "" : distance > 0 ? "" : "", Bukkit.getVersion()), + // Purpur end msg ); this.versionMessage = Component.text() diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java index 455ff52d90565838fe7640c3f045b27082a6c2f1..45f5493eebfecf56b7c0ef4659c078dfc62c0612 100644 --- a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java +++ b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java @@ -227,6 +227,28 @@ 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 + }, + + /** + * 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); + } + }, + + /** + * 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 }; /** diff --git a/src/main/java/org/bukkit/entity/Endermite.java b/src/main/java/org/bukkit/entity/Endermite.java index 138d2530de2410f4a9424dabd3e5ce0cd1c1dcd2..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 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 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 62e3793903905b94eb1a120345015149abb33713..07b8c0dd049ff783fd2e408be634642479bf8b1e 100644 --- a/src/main/java/org/bukkit/entity/Entity.java +++ b/src/main/java/org/bukkit/entity/Entity.java @@ -1155,4 +1155,55 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent */ @NotNull String getScoreboardEntryName(); // Paper end - entity scoreboard name + + // Purpur start + /** + * 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(); + + /** + * Checks if the entity is in daylight + * + * @return True if in daylight + */ + boolean isInDaylight(); + + /** + * 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 } 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 b777e530122549455dcce6fac8d4a151c1c0af42..61a046584acf48693489ff551a0dd4c4b16af9ff 100644 --- a/src/main/java/org/bukkit/entity/LivingEntity.java +++ b/src/main/java/org/bukkit/entity/LivingEntity.java @@ -1447,4 +1447,27 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource */ void setBodyYaw(float bodyYaw); // Paper end - body yaw API + + // Purpur start + /** + * Play item break animation for the item in specified equipment slot + * + * @param slot Equipment slot to play break animation for + */ + void broadcastItemBreak(@NotNull org.bukkit.inventory.EquipmentSlot slot); + + /** + * 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 } 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 ba3edf4cb1a2fc0529465d6973ec086291bae41c..04392bebe3a0ca1cff8932610393cb3dbec1c722 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -3816,4 +3816,123 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM @Override Spigot spigot(); // Spigot end + + // Purpur start + /** + * Allows you to get if player uses Purpur Client + * + * @return True if Player uses Purpur Client + */ + public 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(@NotNull 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(@NotNull 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(@NotNull Location location, int duration, @NotNull 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(@NotNull Location location, int duration, @NotNull 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(@NotNull Location location, int duration, @NotNull 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(@NotNull Location location, int duration, @NotNull String text, @NotNull 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(@NotNull 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(@NotNull 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 3bc24457d143449e6a338d79becf7c39b9f81054..4a5edf4e72e81b22c1abb2ade244f7f4292e993c 100644 --- a/src/main/java/org/bukkit/entity/Villager.java +++ b/src/main/java/org/bukkit/entity/Villager.java @@ -328,4 +328,14 @@ public interface Villager extends AbstractVillager { */ public void clearReputations(); // Paper end + + // 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 14543c2238b45c526dd9aebea2aa5c22f5df54dc..5312daf33405704c74e2c9e109754285ea6cf734 100644 --- a/src/main/java/org/bukkit/entity/Wither.java +++ b/src/main/java/org/bukkit/entity/Wither.java @@ -107,4 +107,20 @@ public interface Wither extends Monster, Boss, com.destroystokyo.paper.entity.Ra */ void enterInvulnerabilityPhase(); // Paper end + + // 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 4b84c04675775e2a606630b00de8afe51665cebc..ccbaf40a3131f477b4be2264401ad893725c1162 100644 --- a/src/main/java/org/bukkit/entity/Wolf.java +++ b/src/main/java/org/bukkit/entity/Wolf.java @@ -112,4 +112,20 @@ public interface Wolf extends Tameable, Sittable, io.papermc.paper.entity.Collar return variant; } } + + // Purpur start + /** + * Checks if this wolf is rabid + * + * @return whether the wolf is rabid + */ + public boolean isRabid(); + + /** + * Sets this wolf to be rabid or not + * + * @param rabid whether the wolf should be rabid + */ + public 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 446b3ffd5caca5344be1c250475679834cd0d4a2..3da8d3d8925cd7a111c0c357bceecfd3a801c8eb 100644 --- a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java @@ -303,7 +303,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 c9f395064656dd0126410eb3c6e197baa450c063..13156a12e5df50cdc1e465dc0bd9d94108275629 100644 --- a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java @@ -217,6 +217,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 59b375569a75cb1e1f7c610f96078e102ec0d3ed..a3f74891abbdc51dbbddaeb511f2754e0603c904 100644 --- a/src/main/java/org/bukkit/event/inventory/InventoryType.java +++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java @@ -166,7 +166,7 @@ public enum InventoryType { SMITHING_NEW(4, "Upgrade Gear"), ; - private final int size; + private int size; public void setDefaultSize(int size) { this.size = size; } // Purpur - remove final and add setter private final String title; 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 c60be4fd24c7fdf65251dd6169e5e1ac3b588d95..569deccd2f1cf21da9b5906433ac493c1f2081be 100644 --- a/src/main/java/org/bukkit/inventory/AnvilInventory.java +++ b/src/main/java/org/bukkit/inventory/AnvilInventory.java @@ -123,4 +123,14 @@ public interface AnvilInventory extends Inventory { setItem(2, result); } // Paper end + + // Purpur start + boolean canBypassCost(); + + void setBypassCost(boolean bypassCost); + + boolean canDoUnsafeEnchants(); + + 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 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db534286d267b05 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java @@ -17,6 +17,17 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.material.MaterialData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +// Purpur start +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; +import org.bukkit.inventory.meta.BlockDataMeta; +import org.bukkit.inventory.meta.Repairable; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataHolder; +// Purpur end /** * Represents a stack of items. @@ -1073,4 +1084,565 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat return Bukkit.getUnsafe().computeTooltipLines(this, tooltipContext, player); } // Paper end - expose itemstack tooltip lines + + // Purpur start + /** + * 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 getItemMeta().getDisplayName(); + } + + /** + * Sets the display name. + * + * @param name the name to set + */ + public void setDisplayName(@Nullable String name) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setDisplayName(name); + setItemMeta(itemMeta); + } + + /** + * Checks for existence of a display name. + * + * @return true if this has a display name + */ + public boolean hasDisplayName() { + return hasItemMeta() && getItemMeta().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 getItemMeta().getLocalizedName(); + } + + /** + * Sets the localized name. + * + * @param name the name to set + */ + public void setLocalizedName(@Nullable String name) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setLocalizedName(name); + setItemMeta(itemMeta); + } + + /** + * Checks for existence of a localized name. + * + * @return true if this has a localized name + */ + public boolean hasLocalizedName() { + return hasItemMeta() && getItemMeta().hasLocalizedName(); + } + + /** + * Checks for existence of lore. + * + * @return true if this has lore + */ + public boolean hasLore() { + return hasItemMeta() && getItemMeta().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 hasItemMeta() && getItemMeta().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 getItemMeta().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 getItemMeta().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) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.addEnchant(ench, level, ignoreLevelRestriction); + setItemMeta(itemMeta); + return result; + } + + /** + * 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) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.removeEnchant(ench); + setItemMeta(itemMeta); + return result; + } + + /** + * Checks for the existence of any enchantments. + * + * @return true if an enchantment exists on this meta + */ + public boolean hasEnchants() { + return hasItemMeta() && getItemMeta().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 hasItemMeta() && getItemMeta().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) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setCustomModelData(data); + setItemMeta(itemMeta); + } + + /** + * 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 getItemMeta().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 hasItemMeta() && getItemMeta().hasCustomModelData(); + } + + /** + * Returns whether the item has block data currently attached to it. + * + * @return whether block data is already attached + */ + public boolean hasBlockData() { + return hasItemMeta() && ((BlockDataMeta) getItemMeta()).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 ((BlockDataMeta) getItemMeta()).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) { + ItemMeta itemMeta = getItemMeta(); + ((BlockDataMeta) itemMeta).setBlockData(blockData); + setItemMeta(itemMeta); + } + + /** + * Gets the repair penalty + * + * @return the repair penalty + */ + public int getRepairCost() { + return ((Repairable) getItemMeta()).getRepairCost(); + } + + /** + * Sets the repair penalty + * + * @param cost repair penalty + */ + public void setRepairCost(int cost) { + ItemMeta itemMeta = getItemMeta(); + ((Repairable) itemMeta).setRepairCost(cost); + setItemMeta(itemMeta); + } + + /** + * Checks to see if this has a repair penalty + * + * @return true if this has a repair penalty + */ + public boolean hasRepairCost() { + return hasItemMeta() && ((Repairable) getItemMeta()).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 hasItemMeta() && getItemMeta().isUnbreakable(); + } + + /** + * Sets the unbreakable tag. An unbreakable item will not lose durability. + * + * @param unbreakable true if set unbreakable + */ + public void setUnbreakable(boolean unbreakable) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setUnbreakable(unbreakable); + setItemMeta(itemMeta); + } + + /** + * Checks for the existence of any AttributeModifiers. + * + * @return true if any AttributeModifiers exist + */ + public boolean hasAttributeModifiers() { + return hasItemMeta() && getItemMeta().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 getItemMeta().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 getItemMeta().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 getItemMeta().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) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.addAttributeModifier(attribute, modifier); + setItemMeta(itemMeta); + return result; + } + + /** + * 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) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setAttributeModifiers(attributeModifiers); + setItemMeta(itemMeta); + } + + /** + * 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) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.removeAttributeModifier(attribute); + setItemMeta(itemMeta); + return result; + } + + /** + * 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) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.removeAttributeModifier(slot); + setItemMeta(itemMeta); + return result; + } + + /** + * 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) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.removeAttributeModifier(attribute, modifier); + setItemMeta(itemMeta); + return result; + } + + /** + * Returns a custom tag container capable of storing tags on the object. + * + * Note that the tags stored on this container are all stored under their + * own custom namespace therefore modifying default tags using this + * {@link PersistentDataHolder} is impossible. + * + * @return the persistent metadata container + */ + @NotNull + public PersistentDataContainer getPersistentDataContainer() { + return getItemMeta().getPersistentDataContainer(); + } + + /** + * Checks to see if this item has damage + * + * @return true if this has damage + */ + public boolean hasDamage() { + return hasItemMeta() && ((Damageable) getItemMeta()).hasDamage(); + } + + /** + * Gets the damage + * + * @return the damage + */ + public int getDamage() { + return ((Damageable) getItemMeta()).getDamage(); + } + + /** + * Sets the damage + * + * @param damage item damage + */ + public void setDamage(int damage) { + ItemMeta itemMeta = getItemMeta(); + ((Damageable) itemMeta).setDamage(damage); + setItemMeta(itemMeta); + } + + /** + * 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) { + Damageable damageable = (Damageable) getItemMeta(); + if (amount > 0) { + int unbreaking = getEnchantLevel(Enchantment.UNBREAKING); + int reduce = 0; + for (int i = 0; unbreaking > 0 && i < amount; ++i) { + if (reduceDamage(java.util.concurrent.ThreadLocalRandom.current(), unbreaking)) { + ++reduce; + } + } + amount -= reduce; + if (amount <= 0) { + return isBroke(damageable.getDamage()); + } + } + int damage = damageable.getDamage() + amount; + damageable.setDamage(damage); + setItemMeta((ItemMeta) damageable); + return isBroke(damage); + } + + public boolean isBroke(int damage) { + if (damage > getType().getMaxDurability()) { + if (getAmount() > 0) { + // ensure it "breaks" + setAmount(0); + } + return true; + } + return false; + } + + private boolean reduceDamage(java.util.Random random, int unbreaking) { + if (getType().isArmor()) { + return random.nextFloat() < 0.6F; + } + return random.nextInt(unbreaking + 1) > 0; + } + // Purpur end } diff --git a/src/main/java/org/bukkit/inventory/RecipeChoice.java b/src/main/java/org/bukkit/inventory/RecipeChoice.java index db8bcc66bdc4bedfffb4705db6338eda4c0ad29a..feda3ddfaaf37b6ee218a0e0b1fbc199899bd364 100644 --- a/src/main/java/org/bukkit/inventory/RecipeChoice.java +++ b/src/main/java/org/bukkit/inventory/RecipeChoice.java @@ -10,6 +10,7 @@ import java.util.function.Predicate; import org.bukkit.Material; import org.bukkit.Tag; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; // Purpur /** * Represents a potential item match within a recipe. All choices within a @@ -150,6 +151,7 @@ public interface RecipeChoice extends Predicate, Cloneable { public static class ExactChoice implements RecipeChoice { private List choices; + private Predicate predicate; // Purpur public ExactChoice(@NotNull ItemStack stack) { this(Arrays.asList(stack)); @@ -194,6 +196,7 @@ public interface RecipeChoice extends Predicate, Cloneable { @Override public boolean test(@NotNull ItemStack t) { + if (predicate != null) return predicate.test(t); // Purpur for (ItemStack match : choices) { if (t.isSimilar(match)) { return true; @@ -203,6 +206,17 @@ public interface RecipeChoice extends Predicate, Cloneable { return false; } + // Purpur start + @Nullable + public Predicate getPredicate() { + return predicate; + } + + public void setPredicate(@Nullable Predicate predicate) { + this.predicate = predicate; + } + // Purpur end + @Override public int hashCode() { int hash = 7; diff --git a/src/main/java/org/bukkit/map/MapRenderer.java b/src/main/java/org/bukkit/map/MapRenderer.java index cb7040876a99a5a7e49b81684ef0f3b79584c376..22d8f31b1b8a5dbb5ab3275068642937c097abfe 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 + /** + * Check if this is an explorer (aka treasure) map. + * + * @return True if explorer map + */ + public abstract boolean isExplorerMap(); + // Purpur - end } diff --git a/src/main/java/org/bukkit/permissions/PermissibleBase.java b/src/main/java/org/bukkit/permissions/PermissibleBase.java index cd3296fea01648592d2af89b3d80135acb6d0958..45797a6fbae1d8edc4211cb30def24ad4f59bd49 100644 --- a/src/main/java/org/bukkit/permissions/PermissibleBase.java +++ b/src/main/java/org/bukkit/permissions/PermissibleBase.java @@ -168,7 +168,7 @@ public class PermissibleBase implements Permissible { for (Permission perm : defaults) { String name = perm.getName().toLowerCase(java.util.Locale.ENGLISH); - permissions.put(name, new PermissionAttachmentInfo(parent, name, null, true)); + permissions.put(name, new PermissionAttachmentInfo(parent, name, null, perm.getDefault().getValue(isOp()))); // Purpur Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent); calculateChildPermissions(perm.getChildren(), false, null); } @@ -196,7 +196,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 String lname = name.toLowerCase(java.util.Locale.ENGLISH); 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..d5a42707d365ffd72532bbb1a59a1ca7145f9918 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 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..10627d2a11251a8cb01bbc3f6242d66f3505a16e 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 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 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 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 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 return perm; } @@ -89,6 +89,8 @@ public final class DefaultPermissions { CommandPermissions.registerPermissions(parent); BroadcastPermissions.registerPermissions(parent); + PurpurPermissions.registerPermissions(); // Purpur + parent.recalculatePermissibles(); } } diff --git a/src/main/java/org/bukkit/util/permissions/PurpurPermissions.java b/src/main/java/org/bukkit/util/permissions/PurpurPermissions.java new file mode 100644 index 0000000000000000000000000000000000000000..baec4c87d7ea4d54934ca22fd1eb7b46dd69061b --- /dev/null +++ b/src/main/java/org/bukkit/util/permissions/PurpurPermissions.java @@ -0,0 +1,87 @@ +package org.bukkit.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.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 + "drop.spawners", "Allows the user to drop spawner cage when broken with diamond pickaxe with silk touch", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission(PREFIX + "place.spawners", "Allows the user to place spawner cage in the world", PermissionDefault.FALSE, purpur); + + DefaultPermissions.registerPermission(PREFIX + "mending_shift_click", "Allows the user to use shift-right-click to mend items", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission(PREFIX + "inventory_totem", "Uses a totem from anywhere in the user's inventory on death", 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.FALSE, 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; + } +} 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..bc590c4d49d32f4365a50ceb5785e798702a8179 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/ExecuteCommandEvent.java @@ -0,0 +1,130 @@ +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.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * This event is called whenever someone runs a command + */ +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 String[] args; + + public ExecuteCommandEvent(@NotNull CommandSender sender, @NotNull Command command, @NotNull 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 + */ + @NotNull + 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(@NotNull 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 + */ + @NotNull + 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(@NotNull 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 + */ + @NotNull + public String getLabel() { + return label; + } + + /** + * Set the label used to execute this command + * + * @param label Label used + */ + public void setLabel(@NotNull String label) { + this.label = label; + } + + /** + * Get the args passed to the command + * + * @return Args passed to the command + */ + @NotNull + public String[] getArgs() { + return args; + } + + /** + * Set the args passed to the command + * + * @param args Args passed to the command + */ + public void setArgs(@NotNull String[] args) { + this.args = args; + } + + @Override + public boolean isCancelled() { + return cancel; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..25e92af7710316ed2afedf846a59dbd672869b51 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/PlayerAFKEvent.java @@ -0,0 +1,70 @@ +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.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PlayerAFKEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private final boolean setAfk; + private boolean shouldKick; + private String broadcast; + private boolean cancel; + + public PlayerAFKEvent(@NotNull 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 + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..519809eab5d926dc7b0a7bad5d446d0defc099dc --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java @@ -0,0 +1,85 @@ +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.NotNull; + +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; + + public PlayerSetSpawnerTypeWithEggEvent(@NotNull Player player, @NotNull Block block, @NotNull CreatureSpawner spawner, @NotNull EntityType type) { + super(player); + this.block = block; + this.spawner = spawner; + this.type = type; + } + + /** + * Get the spawner Block in the world + * + * @return Spawner Block + */ + @NotNull + public Block getBlock() { + return block; + } + + /** + * Get the spawner state + * + * @return Spawner state + */ + @NotNull + public CreatureSpawner getSpawner() { + return spawner; + } + + /** + * Gets the EntityType being set on the spawner + * + * @return EntityType being set + */ + @NotNull + public EntityType getEntityType() { + return type; + } + + /** + * Sets the EntityType being set on the spawner + * + * @param type EntityType to set + */ + public void setEntityType(@NotNull EntityType type) { + this.type = type; + } + + @Override + public boolean isCancelled() { + return cancel; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + @Override + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..8ea97ddceedb7c719e8a50a0dd8f3f0919ca1647 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java @@ -0,0 +1,53 @@ +package org.purpurmc.purpur.event; + +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.NotNull; +import java.util.Collections; + +/** + * Called before a block's explosion is processed + */ +public class PreBlockExplodeEvent extends BlockExplodeEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final float yield; + + public PreBlockExplodeEvent(@NotNull final Block what, final float yield, @NotNull BlockState explodedBlockState) { + super(what, explodedBlockState, Collections.emptyList(), yield); + 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 @NotNull HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..833f46d1941f377765132fc528c45567ee0290d2 --- /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.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Called when a bee targets a flower + */ +public class BeeFoundFlowerEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + private final Location location; + + public BeeFoundFlowerEvent(@NotNull Bee bee, @Nullable Location location) { + super(bee); + this.location = location; + } + + @Override + @NotNull + 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 + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..ae0bb654745724889c67fae9072ae90ea3778ba4 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/BeeStartedPollinatingEvent.java @@ -0,0 +1,47 @@ +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.NotNull; + +/** + * Called when a bee starts pollinating + */ +public class BeeStartedPollinatingEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + private final Location location; + + public BeeStartedPollinatingEvent(@NotNull Bee bee, @NotNull Location location) { + super(bee); + this.location = location; + } + + @Override + @NotNull + public Bee getEntity() { + return (Bee) super.getEntity(); + } + + /** + * Returns the location of the flower that the bee pollinates + * + * @return The location of the flower + */ + @NotNull + public Location getLocation() { + return this.location; + } + + @Override + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..ff3c9f075be2f624af8b0ce5fffc5ea69a41f32e --- /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.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Called when a bee stops pollinating + */ +public class BeeStopPollinatingEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + private final Location location; + private final boolean success; + + public BeeStopPollinatingEvent(@NotNull Bee bee, @Nullable Location location, boolean success) { + super(bee); + this.location = location; + this.success = success; + } + + @Override + @NotNull + 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 + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..c66eb163877e872f234d86dc244cab7efeb818cd --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java @@ -0,0 +1,117 @@ +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.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Fired when an entity is hindered from teleporting. + */ +public class EntityTeleportHinderedEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + + @NotNull + private final Reason reason; + + @Nullable + private final TeleportCause teleportCause; + + private boolean retry = false; + + public EntityTeleportHinderedEvent(@NotNull Entity what, @NotNull Reason reason, + @Nullable TeleportCause teleportCause) { + super(what); + this.reason = reason; + this.teleportCause = teleportCause; + } + + /** + * @return why the teleport was hindered. + */ + @NotNull + 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 + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..f62c14f3d4999e9112c1c73642aa337d97b94b5a --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/GoatRamEntityEvent.java @@ -0,0 +1,59 @@ +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.NotNull; + +/** + * Called when a goat rams an entity + */ +public class GoatRamEntityEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private final LivingEntity rammedEntity; + private boolean cancelled; + + public GoatRamEntityEvent(@NotNull Goat goat, @NotNull LivingEntity rammedEntity) { + super(goat); + this.rammedEntity = rammedEntity; + } + + /** + * Returns the entity that was rammed by the goat + * + * @return The rammed entity + */ + @NotNull + public LivingEntity getRammedEntity() { + return this.rammedEntity; + } + + @Override + @NotNull + public Goat getEntity() { + return (Goat) super.getEntity(); + } + + @Override + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..8849bb0becb16db907fa648cca2e98ab9d957c75 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/LlamaJoinCaravanEvent.java @@ -0,0 +1,61 @@ +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.NotNull; + +/** + * 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)}. + */ +public class LlamaJoinCaravanEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean canceled; + private final Llama head; + + public LlamaJoinCaravanEvent(@NotNull Llama llama, @NotNull Llama head) { + super(llama); + this.head = head; + } + + @Override + @NotNull + public Llama getEntity() { + return (Llama) entity; + } + + /** + * Get the Llama that this Llama is about to follow + * + * @return Llama about to be followed + */ + @NotNull + public Llama getHead() { + return head; + } + + @Override + public boolean isCancelled() { + return canceled; + } + + @Override + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + @Override + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..c268c35b541a222d50875c29770c846a8ffcc4f8 --- /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.NotNull; + +/** + * Called when a Llama leaves a caravan + */ +public class LlamaLeaveCaravanEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + + public LlamaLeaveCaravanEvent(@NotNull Llama llama) { + super(llama); + } + + @Override + @NotNull + public Llama getEntity() { + return (Llama) entity; + } + + @Override + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..2d4f68228861492baaea0bcc604dfef623b337ba --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/PreEntityExplodeEvent.java @@ -0,0 +1,64 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.Location; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.jetbrains.annotations.NotNull; +import java.util.Collections; + +/** + * Called before an entity's explosion is processed + */ +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; + + public PreEntityExplodeEvent(@NotNull org.bukkit.entity.Entity what, @NotNull final Location location, final float yield) { + super(what, location, Collections.emptyList(), yield); + 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 + */ + @NotNull + public Location getLocation() { + return location; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } + + @NotNull + public static HandlerList getHandlerList() { + return handlers; + } +} 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..a037df01b07af9ffb98b67aca412c1d34fade03b --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/RidableMoveEvent.java @@ -0,0 +1,103 @@ +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.NotNull; + +/** + * Triggered when a ridable mob moves with a rider + */ +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; + + public RidableMoveEvent(@NotNull Mob entity, @NotNull Player rider, @NotNull Location from, @NotNull Location to) { + super(entity); + this.rider = rider; + this.from = from; + this.to = to; + } + + @Override + @NotNull + public Mob getEntity() { + return (Mob) entity; + } + + @NotNull + 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 + */ + @NotNull + 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(@NotNull Location from) { + validateLocation(from); + this.from = from; + } + + /** + * Gets the location this entity moved to + * + * @return Location the entity moved to + */ + @NotNull + 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(@NotNull Location to) { + validateLocation(to); + this.to = to; + } + + private void validateLocation(@NotNull Location loc) { + Preconditions.checkArgument(loc != null, "Cannot use null location!"); + Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!"); + } + + @Override + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..3d3a7d898e3278ce998d713dafbb4b354dad7fc7 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/entity/RidableSpacebarEvent.java @@ -0,0 +1,37 @@ +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.NotNull; + +public class RidableSpacebarEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + + public RidableSpacebarEvent(@NotNull Entity entity) { + super(entity); + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + cancelled = cancel; + } + + @Override + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..b363c91a29f826910db22f2643decf996a067ab5 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java @@ -0,0 +1,52 @@ +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.NotNull; + +/** + * Called when a player takes the result item out of an anvil + */ +public class AnvilTakeResultEvent extends InventoryEvent { + private static final HandlerList handlers = new HandlerList(); + private final Player player; + private final ItemStack result; + + public AnvilTakeResultEvent(@NotNull HumanEntity player, @NotNull InventoryView view, @NotNull ItemStack result) { + super(view); + this.player = (Player) player; + this.result = result; + } + + @NotNull + public Player getPlayer() { + return player; + } + + @NotNull + public ItemStack getResult() { + return result; + } + + @NotNull + @Override + public AnvilInventory getInventory() { + return (AnvilInventory) super.getInventory(); + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..fd6a5a3589d436c2aaf988fd305899695799d3bb --- /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.NotNull; + +/** + * Called when anvil slots change, triggering the result slot to be updated + */ +public class AnvilUpdateResultEvent extends InventoryEvent { + private static final HandlerList handlers = new HandlerList(); + + public AnvilUpdateResultEvent(@NotNull InventoryView view) { + super(view); + } + + @NotNull + @Override + public AnvilInventory getInventory() { + return (AnvilInventory) super.getInventory(); + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..eebb5d124456b8209d1b8e8cc4cb772dd3714f04 --- /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.NotNull; + +/** + * Called when a player takes the result item out of a Grindstone + */ +public class GrindstoneTakeResultEvent extends InventoryEvent { + private static final HandlerList handlers = new HandlerList(); + private final Player player; + private final ItemStack result; + private int experienceAmount; + + public GrindstoneTakeResultEvent(@NotNull HumanEntity player, @NotNull InventoryView view, @NotNull ItemStack result, int experienceAmount) { + super(view); + this.player = (Player) player; + this.result = result; + this.experienceAmount = experienceAmount; + } + + @NotNull + public Player getPlayer() { + return player; + } + + @NotNull + public ItemStack getResult() { + return result; + } + + @NotNull + @Override + public GrindstoneInventory getInventory() { + return (GrindstoneInventory) super.getInventory(); + } + + /** + * Get the amount of experience this transaction will give + * + * @return Amount of experience to give + */ + public int getExperienceAmount() { + return this.experienceAmount; + } + + /** + * Set the amount of experience this transaction will give + * + * @param experienceAmount Amount of experience to give + */ + public void setExperienceAmount(int experienceAmount) { + this.experienceAmount = experienceAmount; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..c88394336bc9ab0f66a2af24d393f4a176a234d5 --- /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.NotNull; + +/** + * Called when a player tries to bypass book limitations + */ +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 + */ + public PlayerBookTooLargeEvent(@NotNull Player player, @NotNull ItemStack book) { + super(player, !Bukkit.isPrimaryThread()); + this.book = book; + } + + /** + * Get the book containing the wanted edits + * + * @return The book + */ + @NotNull + 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 + @NotNull + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + 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..38483d908ed830e97883733bee2370f87060f4c7 --- /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.jetbrains.annotations.NotNull; + +/** + * Represents a language that can translate translation keys + */ +public abstract class Language { + private static Language language; + + /** + * Returns the default language of the server + */ + @NotNull + public static Language getLanguage() { + return language; + } + + public static void setLanguage(@NotNull 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(@NotNull 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(@NotNull 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 + */ + @NotNull + abstract public String getOrDefault(@NotNull 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 + */ + @NotNull + public String getOrDefault(@NotNull Translatable key) { + return getOrDefault(key.translationKey()); + } +}