diff --git a/build.gradle.kts b/build.gradle.kts index 9ae340c..4681dc1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,12 +1,12 @@ plugins { `java-library` - id("com.github.johnrengelman.shadow") version "8.1.1" - id("io.papermc.paperweight.userdev") version "1.5.11" - id("xyz.jpenilla.run-paper") version "2.2.2" + alias(libs.plugins.shadow) + alias(libs.plugins.paperweight.userdev) + alias(libs.plugins.runpaper) } group = "com.danikvitek" -version = "2.0" +version = "2.1" repositories { mavenCentral() @@ -30,10 +30,10 @@ repositories { dependencies { paperweight.paperDevBundle("1.18.2-R0.1-SNAPSHOT") - compileOnly("org.jetbrains:annotations:24.1.0") - implementation("org.bstats:bstats-bukkit:3.0.2") - implementation("de.tr7zw:item-nbt-api:2.12.2") - implementation("io.vavr:vavr:0.10.4") + compileOnly(libs.jetbrains.annotations) + implementation(libs.bstats.bukkit) + implementation(libs.itemnbt.api) + implementation(libs.vavr) } java { diff --git a/src/main/java/com/danikvitek/slimeinabukkit/SlimeListener.java b/src/main/java/com/danikvitek/slimeinabukkit/SlimeListener.java index 5aca5a1..0f4f5b4 100644 --- a/src/main/java/com/danikvitek/slimeinabukkit/SlimeListener.java +++ b/src/main/java/com/danikvitek/slimeinabukkit/SlimeListener.java @@ -1,7 +1,11 @@ package com.danikvitek.slimeinabukkit; import com.danikvitek.slimeinabukkit.config.PluginConfig; -import de.tr7zw.changeme.nbtapi.NBTItem; +import com.danikvitek.slimeinabukkit.util.ISUtil; +import de.tr7zw.changeme.nbtapi.NBT; +import io.vavr.collection.Iterator; +import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.Chunk; import org.bukkit.Location; @@ -18,15 +22,11 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.inventory.CraftItemEvent; -import org.bukkit.event.player.PlayerDropItemEvent; -import org.bukkit.event.player.PlayerInteractEntityEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.*; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,7 +41,7 @@ public class SlimeListener implements Listener { public static final String SLIME_INTERACT_PERMISSION = "slimeinabukkit.interact"; public static final Random RANDOM = new Random(); - private static final Set interactingPlayers = new LinkedHashSet<>(); + private static final Set interactingPlayers = new HashSet<>(); private static final Map lastItemChunks = new ConcurrentHashMap<>(); private final @NotNull PluginConfig config; @@ -167,9 +167,9 @@ private void pickupSlime(final @NotNull Slime slime, private void assignUUID(final @NotNull ItemStack slimeBucketStack, final @NotNull UUID uuid) { - final var nbtItem = new NBTItem(slimeBucketStack); - nbtItem.setUUID(SLIME_BUCKET_UUID_KEY, uuid); - nbtItem.applyNBT(slimeBucketStack); + NBT.modify(slimeBucketStack, nbt -> { + nbt.setUUID(SLIME_BUCKET_UUID_KEY, uuid); + }); } @EventHandler @@ -193,9 +193,9 @@ public void onClickAtBlock(final @NotNull PlayerInteractEvent event) { assert itemMeta != null; if (!itemMeta.hasCustomModelData() || (itemMeta.getCustomModelData() != config.getCalmSlimeCmd() && - itemMeta.getCustomModelData() != config.getActiveSlimeCmd())) return; + itemMeta.getCustomModelData() != config.getActiveSlimeCmd())) return; - placeSlime(event, player, itemStack, itemMeta); + placeSlime(event, player, itemStack); } private boolean checkCannotPickupSlime(@NotNull Player player) { @@ -213,30 +213,33 @@ private boolean checkCannotPickupSlime(@NotNull Player player) { private void placeSlime(final @NotNull PlayerInteractEvent event, final @NotNull Player player, - final @NotNull ItemStack itemStack, - final @NotNull ItemMeta itemMeta) { + final @NotNull ItemStack itemStack) { + if (!itemStack.hasItemMeta()) throw new AssertionError("ItemStack has no ItemMeta"); + final ItemMeta itemMeta = itemStack.getItemMeta(); + if (interactingPlayers.contains(player.getUniqueId())) return; interactingPlayers.add(player.getUniqueId()); event.setUseInteractedBlock(Event.Result.DENY); final Block block = event.getClickedBlock(); - assert block != null; + assert block != null; // because the event.action is RIGHT_CLICK_BLOCK final BlockFace blockFace = event.getBlockFace(); - final Location slimeReleaseLocation = block.getLocation().clone() - .add(new Vector(0.5, 0d, 0.5)) + final Location slimeReleaseLocation = block.getLocation() + .add(0.5, 0d, 0.5) .add(blockFace.getDirection()); slimeReleaseLocation.setYaw(RANDOM.nextFloat() * 360f); player.getWorld().spawn(slimeReleaseLocation, Slime.class, slime -> { slime.setSize(1); final var serializer = PlainTextComponentSerializer.plainText(); - if (itemMeta.hasDisplayName() && - !serializer.serialize(itemMeta.displayName()) - .equals(serializer.serialize(config.getSlimeBucketTitle()))) { - slime.customName(itemMeta.displayName()); - } + ISUtil.useDisplayName(itemMeta, displayName -> { + if (!serializer.serialize(displayName) + .equals(serializer.serialize(config.getSlimeBucketTitle()))) { + slime.customName(itemMeta.displayName()); + } + }); }); itemMeta.setCustomModelData(null); @@ -252,27 +255,35 @@ private void placeSlime(final @NotNull PlayerInteractEvent event, } private void removeUUID(final @NotNull ItemStack itemStack) { - final var nbtItem = new NBTItem(itemStack); - nbtItem.removeKey(SLIME_BUCKET_UUID_KEY); - nbtItem.applyNBT(itemStack); + NBT.modify(itemStack, nbt -> { + nbt.removeKey(SLIME_BUCKET_UUID_KEY); + }); } @EventHandler(priority = EventPriority.MONITOR) public void onCraftWithSlimeBucket(final @NotNull CraftItemEvent e) { final int matrixSize = e.getInventory().getMatrix().length; - final Map slotsAndStacksToReplaceWithSlimeBucket = new LinkedHashMap<>(matrixSize); - io.vavr.collection.Iterator - .of(e.getInventory().getMatrix()) - .zipWithIndex() - .filter(pair -> pair._1 != null && pair._1.getType() == SLIME_BUCKET_MATERIAL && pair._1.hasItemMeta()) - .filter(pair -> { - final ItemMeta itemMeta = pair._1.getItemMeta(); - assert itemMeta != null; - return itemMeta.hasCustomModelData() && - (itemMeta.getCustomModelData() == config.getCalmSlimeCmd() || - itemMeta.getCustomModelData() == config.getActiveSlimeCmd()); - }) - .forEach(pair -> slotsAndStacksToReplaceWithSlimeBucket.put(pair._2, pair._1.clone())); + final Int2ObjectMap<@NotNull ItemStack> slotsAndStacksToReplaceWithSlimeBucket = + new Int2ObjectLinkedOpenHashMap<>(matrixSize); + Iterator.of(e.getInventory().getMatrix()) + .zipWithIndex() + .filter(pair -> { + final ItemStack itemStack = pair._1; + if (itemStack == null || itemStack.getType() != SLIME_BUCKET_MATERIAL || !itemStack.hasItemMeta()) { + return false; + } + final ItemMeta itemMeta = itemStack.getItemMeta(); + assert itemMeta != null; + return itemMeta.hasCustomModelData() && + (itemMeta.getCustomModelData() == config.getCalmSlimeCmd() || + itemMeta.getCustomModelData() == config.getActiveSlimeCmd()); + }) + .forEach(pair -> { + final ItemStack itemStack = pair._1; + assert itemStack != null; + final int slot = pair._2; + slotsAndStacksToReplaceWithSlimeBucket.put(slot, itemStack.clone()); + }); scheduler.runTaskLater(() -> { final ItemStack[] newMatrix = new ItemStack[matrixSize]; @@ -287,11 +298,10 @@ public void onCraftWithSlimeBucket(final @NotNull CraftItemEvent e) { newMatrix[slot] = clonedBucket; }); - io.vavr.collection.Iterator - .of(e.getInventory().getMatrix()) - .zipWithIndex() - .filter(pair -> newMatrix[pair._2] == null) - .forEach(pair -> newMatrix[pair._2] = pair._1); + Iterator.of(e.getInventory().getMatrix()) + .zipWithIndex() + .filter(pair -> newMatrix[pair._2] == null) + .forEach(pair -> newMatrix[pair._2] = pair._1); e.getInventory().setMatrix(newMatrix); }, 0L); } @@ -326,4 +336,9 @@ public void onSlimeBucketDrop(final @NotNull PlayerDropItemEvent event) { } }, 0L, 1L); } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerQuit(final @NotNull PlayerQuitEvent event) { + interactingPlayers.remove(event.getPlayer().getUniqueId()); + } } diff --git a/src/main/java/com/danikvitek/slimeinabukkit/command/GetSlimeCommand.java b/src/main/java/com/danikvitek/slimeinabukkit/command/GetSlimeCommand.java index 958084a..abc238a 100644 --- a/src/main/java/com/danikvitek/slimeinabukkit/command/GetSlimeCommand.java +++ b/src/main/java/com/danikvitek/slimeinabukkit/command/GetSlimeCommand.java @@ -1,7 +1,7 @@ package com.danikvitek.slimeinabukkit.command; import com.danikvitek.slimeinabukkit.config.PluginConfig; -import de.tr7zw.changeme.nbtapi.NBTItem; +import de.tr7zw.changeme.nbtapi.NBT; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Location; @@ -54,13 +54,14 @@ private void getSlimeImpl(@NotNull CommandSender sender) { slimeBucketMeta.displayName(config.getSlimeBucketTitle()); slimeBucket.setItemMeta(slimeBucketMeta); - final NBTItem nbtItem = new NBTItem(slimeBucket); - nbtItem.setUUID(SLIME_BUCKET_UUID_KEY, UUID.randomUUID()); // for it to be not stackable - nbtItem.applyNBT(slimeBucket); + NBT.modify(slimeBucket, nbt -> { + nbt.setUUID(SLIME_BUCKET_UUID_KEY, UUID.randomUUID()); // for it to be not stackable + }); final World world = player.getWorld(); world.playSound(location, Sound.ENTITY_ITEM_PICKUP, 1f, 1f); - if (!player.getInventory().addItem(slimeBucket).isEmpty()) + if (!player.getInventory().addItem(slimeBucket).isEmpty()) { world.dropItem(player.getEyeLocation(), slimeBucket); + } } } diff --git a/src/main/java/com/danikvitek/slimeinabukkit/util/ISUtil.java b/src/main/java/com/danikvitek/slimeinabukkit/util/ISUtil.java new file mode 100644 index 0000000..54d4501 --- /dev/null +++ b/src/main/java/com/danikvitek/slimeinabukkit/util/ISUtil.java @@ -0,0 +1,31 @@ +package com.danikvitek.slimeinabukkit.util; + +import net.kyori.adventure.text.Component; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; + +/** + * Utility class for {@link org.bukkit.inventory.ItemStack}. + */ +public final class ISUtil { + private ISUtil() { + } + + public static void useDisplayName(final @NotNull ItemStack itemStack, final @NotNull Consumer<@NotNull Component> consumer) { + if (!itemStack.hasItemMeta()) { + final ItemMeta itemMeta = itemStack.getItemMeta(); + useDisplayName(itemMeta, consumer); + } + } + + public static void useDisplayName(final @NotNull ItemMeta itemMeta, final @NotNull Consumer<@NotNull Component> consumer) { + if (itemMeta.hasDisplayName()) { + final Component displayName = itemMeta.displayName(); + assert displayName != null; + consumer.accept(displayName); + } + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index da2636c..3b839bb 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -24,9 +24,9 @@ permissions: commands: get_slime: permission: "slimeinabukkit.command.get_slime" - usage: "/get_slime | /gs" + usage: "/get_slime" description: "Gives a bucket of slime to the player" slime_chunk: permission: "slimeinabukkit.command.slime_chunk" - usage: "/slime_chunk | /sc" + usage: "/slime_chunk" description: "Tells you, if the chunk you are in is a slime chunk" \ No newline at end of file