From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Mon, 25 Sep 2023 03:15:07 +0000 Subject: [PATCH] Purpur API Changes Original license: MIT Original project: https://github.com/PurpurMC/Purpur Commit: 4b1a082c94ebc090bbc74b9230e4f43075090a29 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 Fire-Immunity-API.patch diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java index 0c4dbb9ef63fa8575b5546239443cb2bd91ba847..b347224c223569297ee67ac630a710fdf28748ea 100644 --- a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +++ b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java @@ -198,6 +198,18 @@ public interface VanillaGoal extends Goal { GoalKey CLIMB_ON_TOP_OF_POWDER_SNOW = GoalKey.of(Mob.class, NamespacedKey.minecraft("climb_on_top_of_powder_snow")); GoalKey WOLF_PANIC = GoalKey.of(Wolf.class, NamespacedKey.minecraft("wolf_panic")); + // Purpur start + GoalKey MOB_HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider")); + GoalKey HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider")); + GoalKey LLAMA_HAS_RIDER = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_has_rider")); + GoalKey FIND_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal")); + GoalKey ORBIT_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal")); + GoalKey DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager")); + GoalKey ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager")); + GoalKey AVOID_RABID_WOLF = GoalKey.of(Wolf.class, NamespacedKey.minecraft("avoid_rabid_wolf")); + GoalKey RECEIVE_FLOWER = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("receive_flower")); + // Purpur end + /** * @deprecated removed in 1.20.2 */ 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 48808edcea2271d564390c637160881645f30489..8e6efa0dd4bc9ee4d20f6ef591f091e8e70faec0 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java @@ -2899,4 +2899,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 8c4ba0028f5c350a2906add58d9bf3d127a16f58..8ef4fa47e6721f5154316e81c2173cc4a42f4901 100644 --- a/src/main/java/org/bukkit/Material.java +++ b/src/main/java/org/bukkit/Material.java @@ -11054,4 +11054,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 bce07d84cafca677bb6fad78c21b82097f06430c..4ef0fa4f1ef72bb784674671473c6a322acadecc 100644 --- a/src/main/java/org/bukkit/OfflinePlayer.java +++ b/src/main/java/org/bukkit/OfflinePlayer.java @@ -522,4 +522,114 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio */ @Nullable public Location getLastDeathLocation(); + + // 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(); + + /** + * Gets the entity's current position + * + * @return a new copy of Location containing the position of this offline player + */ + @Nullable + public Location getLocation(); + + /** + * 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 74317f10d7f7b31eac50b4fcff5b3cc96c12bce1..6282d9fe1bdf0add7bbd2eaa8916d345fe923a8b 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -2243,6 +2243,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() @@ -2560,4 +2572,111 @@ 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 5eb3521f5f91b0684b4beebf4f7ba2c795b41c42..cf63054e1b597b2bb13164722dd9a829ba7069ba 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java @@ -4160,6 +4160,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..e43d0e0a2c5edfcc82a677b6c4db9314006c9bf4 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); 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 d340ddcf6924cc834455de3acbbac91ab9c66e39..ee3ca27a5406024ed71cce14b0891266b64e6fdf 100644 --- a/src/main/java/org/bukkit/entity/Entity.java +++ b/src/main/java/org/bukkit/entity/Entity.java @@ -1065,4 +1065,42 @@ 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(); + // 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 58017fce436cdbda255f7172fbdadb726d4b113c..05600fc8bf2a61aca8094029bc4c208a710da952 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 a599ed2795ba1baf2cbb465d1c7145580c27e1ea..298acbfb93663e40e627f6a47d51fd87a1551feb 100644 --- a/src/main/java/org/bukkit/entity/LivingEntity.java +++ b/src/main/java/org/bukkit/entity/LivingEntity.java @@ -1243,4 +1243,41 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource */ void setBodyYaw(float bodyYaw); // Paper end + + // Purpur start + /** + * Gets the distance (in blocks) this entity can safely fall without taking damage + * + * @return Safe fall distance + */ + float getSafeFallDistance(); + + /** + * Set the distance (in blocks) this entity can safely fall without taking damage + * + * @param safeFallDistance Safe fall distance + */ + void setSafeFallDistance(float safeFallDistance); + + /** + * 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 d7bbc3d4fbb049b8656b4f0970ced8b955cf56bd..69357a7e78ce8813eac0babdd869edf6804f5c50 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -3319,4 +3319,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 84db38388bf7a58e66d6cd29620b4fe64b0a897e..82ebd99549ce9f9e6427a50cef424e9007735708 100644 --- a/src/main/java/org/bukkit/entity/Wolf.java +++ b/src/main/java/org/bukkit/entity/Wolf.java @@ -69,4 +69,20 @@ public interface Wolf extends Tameable, Sittable, io.papermc.paper.entity.Collar * @param interested Whether the wolf is interested */ public void setInterested(boolean interested); + + // 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/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 cbce826add9dc2b3187c7bea00c27b785d7517df..3a98de6407d9a6307f89c207be1f09e639385ebe 100644 --- a/src/main/java/org/bukkit/event/inventory/InventoryType.java +++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java @@ -151,7 +151,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/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java index 0217f98a74140bbae454d467de27c12b6060ca75..444b021691ea90ee3c87f4e47d4e8c48ef404a8f 100644 --- a/src/main/java/org/bukkit/inventory/ItemFactory.java +++ b/src/main/java/org/bukkit/inventory/ItemFactory.java @@ -355,4 +355,15 @@ public interface ItemFactory { */ @NotNull ItemStack enchantWithLevels(@NotNull ItemStack itemStack, @org.jetbrains.annotations.Range(from = 1, to = 30) int levels, boolean allowTreasure, @NotNull java.util.Random random); // Paper end - enchantWithLevels API + + // Purpur start + /** + * Returns the lines of text shown when hovering over an item + * + * @param itemStack The ItemStack + * @param advanced Whether advanced tooltips are shown + * @return the list of Components + */ + @NotNull java.util.List getHoverLines(@NotNull ItemStack itemStack, boolean advanced); + // Purpur end } diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java index 0af73cc04edb93b9772136d4d808f657ea40e733..085d98b30afa51e7665cb01bdd80b21f82771b95 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java @@ -17,6 +17,18 @@ 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; +import com.destroystokyo.paper.Namespaced; +// Purpur end /** * Represents a stack of items. @@ -1005,4 +1017,636 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat return type.isAir() || amount <= 0; } // Paper end + + // 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); + } + + /** + * Gets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE} + * + * @return Set of {@link com.destroystokyo.paper.Namespaced} + */ + @NotNull + public java.util.Set getDestroyableKeys() { + return getItemMeta().getDestroyableKeys(); + } + + /** + * Sets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE} + * + * @param canDestroy Collection of {@link com.destroystokyo.paper.Namespaced} + */ + public void setDestroyableKeys(@NotNull Collection canDestroy) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setDestroyableKeys(canDestroy); + setItemMeta(itemMeta); + } + + /** + * Gets the collection of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} + * + * @return Set of {@link com.destroystokyo.paper.Namespaced} + */ + @NotNull + public java.util.Set getPlaceableKeys() { + return getItemMeta().getPlaceableKeys(); + } + + /** + * Sets the set of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} + * + * @param canPlaceOn Collection of {@link com.destroystokyo.paper.Namespaced} + */ + @NotNull + public void setPlaceableKeys(@NotNull Collection canPlaceOn) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setPlaceableKeys(canPlaceOn); + setItemMeta(itemMeta); + } + + /** + * Checks for the existence of any keys that the item can be placed on + * + * @return true if this item has placeable keys + */ + public boolean hasPlaceableKeys() { + return hasItemMeta() && getItemMeta().hasPlaceableKeys(); + } + + /** + * Checks for the existence of any keys that the item can destroy + * + * @return true if this item has destroyable keys + */ + public boolean hasDestroyableKeys() { + return hasItemMeta() && getItemMeta().hasDestroyableKeys(); + } + + /** + * 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.DURABILITY); + 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; + } + + /** + * Returns the lines of text shown when hovering over the item + * + * @param advanced Whether advanced tooltips are shown + * @return the list of Components + */ + public @NotNull List getHoverLines(boolean advanced) { + return Bukkit.getItemFactory().getHoverLines(this, advanced); + } + // Purpur end } diff --git a/src/main/java/org/bukkit/inventory/RecipeChoice.java b/src/main/java/org/bukkit/inventory/RecipeChoice.java index 523818cbb0d6c90481ec97123e7fe0e2ff4eea14..bfeb8171a723d84b94bfaacd8aaf7d4d48ecd051 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/potion/PotionEffect.java b/src/main/java/org/bukkit/potion/PotionEffect.java index 037af5fd6d71a526c0e6620f2db0cd6df9625261..939ed1931492854c5854cab06730cf235eba7e89 100644 --- a/src/main/java/org/bukkit/potion/PotionEffect.java +++ b/src/main/java/org/bukkit/potion/PotionEffect.java @@ -32,12 +32,14 @@ public class PotionEffect implements ConfigurationSerializable { private static final String AMBIENT = "ambient"; private static final String PARTICLES = "has-particles"; private static final String ICON = "has-icon"; + private static final String KEY = "namespacedKey"; // Purpur private final int amplifier; private final int duration; private final PotionEffectType type; private final boolean ambient; private final boolean particles; private final boolean icon; + @Nullable private final NamespacedKey key; // Purpur /** * Creates a potion effect. @@ -50,6 +52,36 @@ public class PotionEffect implements ConfigurationSerializable { * @param icon the icon status, see {@link PotionEffect#hasIcon()} */ public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon) { + // Purpur start + this(type, duration, amplifier, ambient, particles, icon, null); + } + + /** + * Create a potion effect. + * @param duration measured in ticks, see {@link + * PotionEffect#getDuration()} + * @param amplifier the amplifier, see {@link PotionEffect#getAmplifier()} + * @param ambient the ambient status, see {@link PotionEffect#isAmbient()} + * @param particles the particle status, see {@link PotionEffect#hasParticles()} + * @param key the namespacedKey, see {@link PotionEffect#getKey()} + */ + public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, @Nullable NamespacedKey key) { + this(type, duration, amplifier, ambient, particles, particles, key); + } + + /** + * Creates a potion effect. + * @param type effect type + * @param duration measured in ticks, see {@link + * PotionEffect#getDuration()} + * @param amplifier the amplifier, see {@link PotionEffect#getAmplifier()} + * @param ambient the ambient status, see {@link PotionEffect#isAmbient()} + * @param particles the particle status, see {@link PotionEffect#hasParticles()} + * @param icon the icon status, see {@link PotionEffect#hasIcon()} + * @param key the namespacedKey, see {@link PotionEffect#getKey()} + */ + public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon, @Nullable NamespacedKey key) { + // Purpur end Preconditions.checkArgument(type != null, "effect type cannot be null"); this.type = type; this.duration = duration; @@ -57,6 +89,7 @@ public class PotionEffect implements ConfigurationSerializable { this.ambient = ambient; this.particles = particles; this.icon = icon; + this.key = key; // Purpur - add key } /** @@ -104,36 +137,43 @@ public class PotionEffect implements ConfigurationSerializable { * @param map the map to deserialize from */ public PotionEffect(@NotNull Map map) { - this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT, false), getBool(map, PARTICLES, true), getBool(map, ICON, getBool(map, PARTICLES, true))); + this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT, false), getBool(map, PARTICLES, true), getBool(map, ICON, getBool(map, PARTICLES, true)), getKey(map)); // Purpur - getKey } // Paper start @NotNull public PotionEffect withType(@NotNull PotionEffectType type) { - return new PotionEffect(type, duration, amplifier, ambient, particles, icon); + return new PotionEffect(type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key } @NotNull public PotionEffect withDuration(int duration) { - return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); + return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key } @NotNull public PotionEffect withAmplifier(int amplifier) { - return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); + return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key } @NotNull public PotionEffect withAmbient(boolean ambient) { - return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); + return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key } @NotNull public PotionEffect withParticles(boolean particles) { - return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); + return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key } @NotNull public PotionEffect withIcon(boolean icon) { - return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); + return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key } // Paper end + // Purpur start + @NotNull + public PotionEffect withKey(@Nullable NamespacedKey key) { + return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); + } + // Purpur end + @NotNull private static PotionEffectType getEffectType(@NotNull Map map) { PotionEffectType effect; @@ -166,17 +206,33 @@ public class PotionEffect implements ConfigurationSerializable { return def; } + // Purpur start + @Nullable + private static NamespacedKey getKey(@NotNull Map map) { + Object key = map.get(KEY); + if (key instanceof String stringKey) { + return NamespacedKey.fromString(stringKey); + } + return null; + } + // Purpur end + @Override @NotNull public Map serialize() { - return ImmutableMap.builder() + // Purpur start - add key, don't serialize if null. + ImmutableMap.Builder builder = ImmutableMap.builder() .put(TYPE, type.getKey().toString()) .put(DURATION, duration) .put(AMPLIFIER, amplifier) .put(AMBIENT, ambient) .put(PARTICLES, particles) - .put(ICON, icon) - .build(); + .put(ICON, icon); + if(key != null) { + builder.put(KEY, key.toString()); + } + return builder.build(); + // Purpur end } /** @@ -200,7 +256,7 @@ public class PotionEffect implements ConfigurationSerializable { return false; } PotionEffect that = (PotionEffect) obj; - return this.type.equals(that.type) && this.ambient == that.ambient && this.amplifier == that.amplifier && this.duration == that.duration && this.particles == that.particles && this.icon == that.icon; + return this.type.equals(that.type) && this.ambient == that.ambient && this.amplifier == that.amplifier && this.duration == that.duration && this.particles == that.particles && this.icon == that.icon && this.key == that.key; // Purpur - add key } /** @@ -296,6 +352,24 @@ public class PotionEffect implements ConfigurationSerializable { return icon; } + + // Purpur start + /** + * @return if the key isn't the default namespacedKey + */ + public boolean hasKey() { + return key != null; + } + + /** + * @return the key attached to the potion + */ + @Nullable + public NamespacedKey getKey() { + return key; + } + // Purpur end + @Override public int hashCode() { int hash = 1; @@ -310,6 +384,6 @@ public class PotionEffect implements ConfigurationSerializable { @Override public String toString() { - return type.getName() + (ambient ? ":(" : ":") + duration + "t-x" + amplifier + (ambient ? ")" : ""); + return type.getName() + (ambient ? ":(" : ":") + duration + "t-x" + amplifier + (ambient ? ")" : "") + (hasKey() ? "(" + key + ")" : ""); // Purpur - add key if not null } } 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..32602b398ede24a35ed8a996faa2b23455615a7b --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java @@ -0,0 +1,54 @@ +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 org.jetbrains.annotations.Nullable; +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, @Nullable BlockState explodedBlockState) { + super(what, Collections.emptyList(), yield, explodedBlockState); + 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/packet/NetworkItemSerializeEvent.java b/src/main/java/org/purpurmc/purpur/event/packet/NetworkItemSerializeEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..c0da73d2ea83a6055e34894ba1c7506fc8667712 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/packet/NetworkItemSerializeEvent.java @@ -0,0 +1,48 @@ +package org.purpurmc.purpur.event.packet; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Called when an item is about to be written to a packet. + */ +public class NetworkItemSerializeEvent extends Event { + private ItemStack itemStack; + + public NetworkItemSerializeEvent(@NotNull ItemStack itemStack) { + super(!org.bukkit.Bukkit.isPrimaryThread()); + this.itemStack = itemStack; + } + + /** + * @return The item that is about to be serialized. Not mutable + */ + @NotNull + public ItemStack getItemStack() { + return itemStack; + } + + /** + * Sets the item that will be serialized. + * + * @param itemStack The item + */ + public void setItemStack(@Nullable ItemStack itemStack) { + this.itemStack = itemStack; + } + + private static final HandlerList handlers = new HandlerList(); + + @NotNull + 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()); + } +}