diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 5ca327a..47da056 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -1,8 +1,8 @@ plugins { java `maven-publish` - kotlin("jvm") version "1.8.22" - id("org.jetbrains.dokka") version ("1.8.20") + kotlin("jvm") version "1.9.10" + id("org.jetbrains.dokka") version ("1.9.0") } group = "de.skyslycer.hmcwraps" @@ -21,7 +21,7 @@ repositories { } dependencies { - dokkaHtmlPlugin("org.jetbrains.dokka:kotlin-as-java-plugin:1.8.20") + dokkaHtmlPlugin("org.jetbrains.dokka:kotlin-as-java-plugin:1.9.0") compileOnly(depends.spigot) compileOnly(depends.annotations) compileOnly(depends.placeholderapi) diff --git a/api/src/main/java/de/skyslycer/hmcwraps/HMCWraps.java b/api/src/main/java/de/skyslycer/hmcwraps/HMCWraps.java index be7ac82..fe753e8 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/HMCWraps.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/HMCWraps.java @@ -11,13 +11,12 @@ import de.skyslycer.hmcwraps.wrap.CollectionHelper; import de.skyslycer.hmcwraps.wrap.Wrapper; import de.skyslycer.hmcwraps.wrap.WrapsLoader; -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - import java.nio.file.Path; import java.util.List; import java.util.UUID; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; public interface HMCWraps extends Plugin { @@ -26,6 +25,7 @@ public interface HMCWraps extends Plugin { Path WRAP_FILES_PATH = PLUGIN_PATH.resolve("wraps"); Path MESSAGES_PATH = PLUGIN_PATH.resolve("messages.properties"); Path CONVERT_PATH = PLUGIN_PATH.resolve("convert"); + Path COMMAND_PATH = WRAP_FILES_PATH.resolve("command"); Path COLLECTION_FILES_PATH = PLUGIN_PATH.resolve("collections"); /** diff --git a/api/src/main/java/de/skyslycer/hmcwraps/actions/information/GuiActionInformation.java b/api/src/main/java/de/skyslycer/hmcwraps/actions/information/GuiActionInformation.java index c8d4b6d..1ec2fac 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/actions/information/GuiActionInformation.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/actions/information/GuiActionInformation.java @@ -8,11 +8,13 @@ public class GuiActionInformation implements ActionInformation { private PaginatedGui gui; private Player player; private String arguments; + private int slot; - public GuiActionInformation(Player player, String arguments, PaginatedGui gui) { + public GuiActionInformation(Player player, String arguments, PaginatedGui gui, int slot) { this.player = player; this.arguments = arguments; this.gui = gui; + this.slot = slot; } @Override @@ -29,6 +31,14 @@ public PaginatedGui getGui() { return gui; } + public int getSlot() { + return slot; + } + + public void setSlot(int slot) { + this.slot = slot; + } + @Override public void setPlayer(Player player) { this.player = player; diff --git a/api/src/main/java/de/skyslycer/hmcwraps/actions/information/WrapGuiActionInformation.java b/api/src/main/java/de/skyslycer/hmcwraps/actions/information/WrapGuiActionInformation.java index 4024aa5..ef9f9c1 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/actions/information/WrapGuiActionInformation.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/actions/information/WrapGuiActionInformation.java @@ -10,12 +10,14 @@ public class WrapGuiActionInformation implements ActionInformation { private Wrap wrap; private Player player; private String arguments; + private int slot; - public WrapGuiActionInformation(PaginatedGui gui, Wrap wrap, Player player, String arguments) { + public WrapGuiActionInformation(PaginatedGui gui, Wrap wrap, Player player, int slot, String arguments) { this.gui = gui; this.wrap = wrap; this.player = player; this.arguments = arguments; + this.slot = slot; } public PaginatedGui getGui() { @@ -34,6 +36,14 @@ public void setWrap(Wrap wrap) { this.wrap = wrap; } + public int getSlot() { + return slot; + } + + public void setSlot(int slot) { + this.slot = slot; + } + @Override public Player getPlayer() { return player; diff --git a/api/src/main/java/de/skyslycer/hmcwraps/messages/Messages.java b/api/src/main/java/de/skyslycer/hmcwraps/messages/Messages.java index e6c5ee6..a293532 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/messages/Messages.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/messages/Messages.java @@ -10,10 +10,14 @@ public enum Messages { REMOVE_WRAP("remove-wrap"), NO_ITEM("no-item"), NO_WRAPS("no-wraps"), + NO_REWRAP("no-rewrap"), + ARMOR_IMITATION_FORBIDDEN_INVENTORY("armor-imitation.forbidden-inventory"), INVENTORY_FILTER_ACTIVE("inventory.filter.active"), INVENTORY_FILTER_INACTIVE("inventory.filter.inactive"), PREVIEW_DISABLED("preview.disabled"), PREVIEW_BAR("preview.bar"), + FAVORITES_SET("favorites.set"), + FAVORITES_CLEAR("favorites.clear"), COMMAND_MISSING_ARGUMENT("command.missing-argument"), COMMAND_PLAYER_ONLY("command.player-only"), COMMAND_INVALID_WRAP("command.invalid-wrap"), @@ -40,7 +44,9 @@ public enum Messages { COMMAND_CONVERT_SUCCESS("command.convert.success"), COMMAND_CONVERT_CONFIRM("command.convert.confirm"), COMMAND_CONVERT_NO_CONFIRM("command.convert.no-confirm"), - COMMAND_CONVERT_FAILED("command.convert.failed"); + COMMAND_CONVERT_FAILED("command.convert.failed"), + COMMAND_CREATE_FAILED("command.create.failed"), + COMMAND_CREATE_SUCCESS("command.create.success"); private final String key; diff --git a/api/src/main/java/de/skyslycer/hmcwraps/preview/Preview.java b/api/src/main/java/de/skyslycer/hmcwraps/preview/Preview.java index 64c64eb..3fdb1ee 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/preview/Preview.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/preview/Preview.java @@ -1,135 +1,17 @@ -package de.skyslycer.hmcwraps.preview; - -import com.github.retrooper.packetevents.PacketEvents; -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; -import com.github.retrooper.packetevents.protocol.player.Equipment; -import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; -import com.github.retrooper.packetevents.util.Vector3f; -import com.github.retrooper.packetevents.wrapper.play.server.*; -import de.skyslycer.hmcwraps.HMCWraps; -import de.skyslycer.hmcwraps.util.PlayerUtil; -import de.skyslycer.hmcwraps.util.VectorUtil; -import io.github.retrooper.packetevents.util.SpigotConversionUtil; -import io.github.retrooper.packetevents.util.SpigotReflectionUtil; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitTask; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; -import java.util.function.Consumer; - -public class Preview { - - private final int entityId = SpigotReflectionUtil.generateEntityId(); - private final Player player; - private final ItemStack item; - private final Consumer onClose; - private final HMCWraps plugin; - private BukkitTask task; - private BukkitTask cancelTask; - - Preview(Player player, ItemStack item, Consumer onClose, HMCWraps plugin) { - this.player = player; - this.item = item; - this.onClose = onClose; - this.plugin = plugin; - } - - /** - * Start the preview. - */ - public void preview() { - player.closeInventory(); - - sendSpawnPacket(); - sendMetadataPacket(); - sendTeleportPacket(); - sendEquipPacket(); - - task = Bukkit.getScheduler() - .runTaskTimerAsynchronously(plugin, new RotateRunnable(player, entityId, plugin), 3, 1); - - cancelTask = Bukkit.getScheduler() - .runTaskLater(plugin, () -> plugin.getPreviewManager().remove(player.getUniqueId(), true), - plugin.getConfiguration().getPreview().getDuration() * 20L); - } - - /** - * Cancel the preview. - * - * @param open If the inventory should open again - */ - public void cancel(boolean open) { - task.cancel(); - cancelTask.cancel(); - if (open && onClose != null) { - onClose.accept(player); - } - Bukkit.getScheduler().runTaskLater(plugin, () -> { - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerDestroyEntities(entityId)); - if (plugin.getConfiguration().getPreview().getSneakCancel().isActionBar()) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(" ")); - } - }, 1L); - } - - private void sendSpawnPacket() { - if (SpigotReflectionUtil.V_1_19_OR_HIGHER) { - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerSpawnEntity(entityId, - Optional.of(UUID.randomUUID()), - EntityTypes.ARMOR_STAND, - VectorUtil.fromLocation(PlayerUtil.getOpposite(player)), - 0f, - 0f, - 0f, - 0, - Optional.empty())); - PacketEvents.getAPI().getPlayerManager() - .sendPacket(player, new WrapperPlayServerEntityMetadata(entityId, - List.of(new EntityData(0, EntityDataTypes.BYTE, (byte) 0x20), - new EntityData(16, EntityDataTypes.ROTATION, new Vector3f(180, 0, 0)), - new EntityData(5, EntityDataTypes.BOOLEAN, true)))); - } else { - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerSpawnLivingEntity( - entityId, - UUID.randomUUID(), - EntityTypes.ARMOR_STAND, - VectorUtil.fromLocation(PlayerUtil.getOpposite(player)), - 0f, - 0f, - 0f, - VectorUtil.zeroVector(), - List.of(new EntityData(0, EntityDataTypes.BYTE, (byte) 0x20), - new EntityData(16, EntityDataTypes.ROTATION, new Vector3f(180, 0, 0)), - new EntityData(5, EntityDataTypes.BOOLEAN, true)))); - } - } - - private void sendMetadataPacket() { - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityMetadata( - entityId, - List.of(new EntityData(0, EntityDataTypes.BYTE, (byte) 0x20), - new EntityData(16, EntityDataTypes.ROTATION, new Vector3f(180, 0, 0)), - new EntityData(5, EntityDataTypes.BOOLEAN, true))) - ); - } - - private void sendTeleportPacket() { - PacketEvents.getAPI().getPlayerManager().sendPacket(player, - new WrapperPlayServerEntityTeleport(entityId, VectorUtil.fromLocation(PlayerUtil.getLookBlock(player)), - 0f, 0f, false)); - } - - private void sendEquipPacket() { - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityEquipment( - entityId, List.of(new Equipment(EquipmentSlot.HELMET, SpigotConversionUtil.fromBukkitItemStack(item))))); - } - -} +package de.skyslycer.hmcwraps.preview; + +public interface Preview { + + /** + * Start the preview. + */ + void preview(); + + /** + * Cancel the preview. + * + * @param open If the inventory should open again + */ + void cancel(boolean open); + +} diff --git a/api/src/main/java/de/skyslycer/hmcwraps/preview/PreviewManager.java b/api/src/main/java/de/skyslycer/hmcwraps/preview/PreviewManager.java index 0dfe6be..f9be1d8 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/preview/PreviewManager.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/preview/PreviewManager.java @@ -2,7 +2,11 @@ import de.skyslycer.hmcwraps.HMCWraps; import de.skyslycer.hmcwraps.events.ItemPreviewEvent; +import de.skyslycer.hmcwraps.preview.floating.FloatingPreview; +import de.skyslycer.hmcwraps.preview.hand.HandPreview; +import de.skyslycer.hmcwraps.serialization.preview.PreviewType; import de.skyslycer.hmcwraps.serialization.wrap.Wrap; +import de.skyslycer.hmcwraps.util.MaterialUtil; import dev.triumphteam.gui.builder.item.ItemBuilder; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -44,7 +48,9 @@ public void remove(UUID uuid, boolean open) { * @param wrap The wrap to preview */ public void create(Player player, Consumer onClose, Wrap wrap) { - var item = ItemBuilder.from(plugin.getCollectionHelper().getMaterial(wrap)).model(wrap.getModelId()); + var wrapType = plugin.getCollectionHelper().getMaterial(wrap); + var type = wrap.isArmorImitationEnabled() ? MaterialUtil.getLeatherAlternative(wrapType) : wrapType; + var item = ItemBuilder.from(type).model(wrap.getModelId()); if (wrap.getColor() != null) { item.color(wrap.getColor()); } @@ -58,7 +64,13 @@ public void create(Player player, Consumer onClose, Wrap wrap) { private void createPrivate(Player player, ItemStack item, Consumer onClose) { - var preview = new Preview(player, item, onClose, plugin); + this.remove(player.getUniqueId(), false); + Preview preview; + if (plugin.getConfiguration().getPreview().getType() == PreviewType.HAND) { + preview = new HandPreview(player, item, onClose, plugin); + } else { + preview = new FloatingPreview(player, item, onClose, plugin); + } previews.put(player.getUniqueId(), preview); preview.preview(); } @@ -72,4 +84,14 @@ public void removeAll(boolean open) { previews.keySet().forEach(uuid -> this.remove(uuid, open)); } + /** + * Check if a player is previewing. + * + * @param player The player + * @return If the player is previewing + */ + public boolean isPreviewing(Player player) { + return previews.containsKey(player.getUniqueId()); + } + } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/preview/floating/FloatingPreview.java b/api/src/main/java/de/skyslycer/hmcwraps/preview/floating/FloatingPreview.java new file mode 100644 index 0000000..f04febd --- /dev/null +++ b/api/src/main/java/de/skyslycer/hmcwraps/preview/floating/FloatingPreview.java @@ -0,0 +1,128 @@ +package de.skyslycer.hmcwraps.preview.floating; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; +import com.github.retrooper.packetevents.protocol.player.Equipment; +import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; +import com.github.retrooper.packetevents.util.Vector3f; +import com.github.retrooper.packetevents.wrapper.play.server.*; +import de.skyslycer.hmcwraps.HMCWraps; +import de.skyslycer.hmcwraps.preview.Preview; +import de.skyslycer.hmcwraps.util.PlayerUtil; +import de.skyslycer.hmcwraps.util.VectorUtil; +import io.github.retrooper.packetevents.util.SpigotConversionUtil; +import io.github.retrooper.packetevents.util.SpigotReflectionUtil; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitTask; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Consumer; + +public class FloatingPreview implements Preview { + + private final int entityId = SpigotReflectionUtil.generateEntityId(); + private final Player player; + private final ItemStack item; + private final Consumer onClose; + private final HMCWraps plugin; + private BukkitTask task; + private BukkitTask cancelTask; + + public FloatingPreview(Player player, ItemStack item, Consumer onClose, HMCWraps plugin) { + this.player = player; + this.item = item; + this.onClose = onClose; + this.plugin = plugin; + } + + public void preview() { + player.closeInventory(); + + sendSpawnPacket(); + sendMetadataPacket(); + sendTeleportPacket(); + sendEquipPacket(); + + task = Bukkit.getScheduler() + .runTaskTimerAsynchronously(plugin, new RotateRunnable(player, entityId, plugin), 3, 1); + + cancelTask = Bukkit.getScheduler() + .runTaskLater(plugin, () -> plugin.getPreviewManager().remove(player.getUniqueId(), true), + plugin.getConfiguration().getPreview().getDuration() * 20L); + } + + public void cancel(boolean open) { + task.cancel(); + cancelTask.cancel(); + if (open && onClose != null) { + onClose.accept(player); + } + Bukkit.getScheduler().runTaskLater(plugin, () -> { + PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerDestroyEntities(entityId)); + if (plugin.getConfiguration().getPreview().getSneakCancel().isActionBar()) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(" ")); + } + }, 1L); + } + + private void sendSpawnPacket() { + if (SpigotReflectionUtil.V_1_19_OR_HIGHER) { + PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerSpawnEntity(entityId, + Optional.of(UUID.randomUUID()), + EntityTypes.ARMOR_STAND, + VectorUtil.fromLocation(PlayerUtil.getOpposite(player)), + 0f, + 0f, + 0f, + 0, + Optional.empty())); + PacketEvents.getAPI().getPlayerManager() + .sendPacket(player, new WrapperPlayServerEntityMetadata(entityId, + List.of(new EntityData(0, EntityDataTypes.BYTE, (byte) 0x20), + new EntityData(16, EntityDataTypes.ROTATION, new Vector3f(180, 0, 0)), + new EntityData(5, EntityDataTypes.BOOLEAN, true)))); + } else { + PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerSpawnLivingEntity( + entityId, + UUID.randomUUID(), + EntityTypes.ARMOR_STAND, + VectorUtil.fromLocation(PlayerUtil.getOpposite(player)), + 0f, + 0f, + 0f, + VectorUtil.zeroVector(), + List.of(new EntityData(0, EntityDataTypes.BYTE, (byte) 0x20), + new EntityData(16, EntityDataTypes.ROTATION, new Vector3f(180, 0, 0)), + new EntityData(5, EntityDataTypes.BOOLEAN, true)))); + } + } + + private void sendMetadataPacket() { + PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityMetadata( + entityId, + List.of(new EntityData(0, EntityDataTypes.BYTE, (byte) 0x20), + new EntityData(16, EntityDataTypes.ROTATION, new Vector3f(180, 0, 0)), + new EntityData(5, EntityDataTypes.BOOLEAN, true))) + ); + } + + private void sendTeleportPacket() { + PacketEvents.getAPI().getPlayerManager().sendPacket(player, + new WrapperPlayServerEntityTeleport(entityId, VectorUtil.fromLocation(PlayerUtil.getLookBlock(player)), + 0f, 0f, false)); + } + + private void sendEquipPacket() { + PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityEquipment( + entityId, List.of(new Equipment(EquipmentSlot.HELMET, SpigotConversionUtil.fromBukkitItemStack(item))))); + } + +} diff --git a/api/src/main/java/de/skyslycer/hmcwraps/preview/RotateRunnable.java b/api/src/main/java/de/skyslycer/hmcwraps/preview/floating/RotateRunnable.java similarity index 96% rename from api/src/main/java/de/skyslycer/hmcwraps/preview/RotateRunnable.java rename to api/src/main/java/de/skyslycer/hmcwraps/preview/floating/RotateRunnable.java index 28e9681..fe195c4 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/preview/RotateRunnable.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/preview/floating/RotateRunnable.java @@ -1,53 +1,53 @@ -package de.skyslycer.hmcwraps.preview; - -import com.github.retrooper.packetevents.PacketEvents; -import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRelativeMoveAndRotation; -import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation; -import de.skyslycer.hmcwraps.HMCWraps; -import de.skyslycer.hmcwraps.messages.Messages; -import de.skyslycer.hmcwraps.util.MathUtil; -import de.skyslycer.hmcwraps.util.StringUtil; -import net.md_5.bungee.api.ChatMessageType; -import org.bukkit.entity.Player; - -public class RotateRunnable implements Runnable { - - private final Player player; - private final int entityId; - private final HMCWraps plugin; - - private int currentSinAngle = 0; - private float currentAngle = 0; - private double oldHeight = 0; - - public RotateRunnable(Player player, int entityId, HMCWraps plugin) { - this.player = player; - this.entityId = entityId; - this.plugin = plugin; - } - - @Override - public void run() { - if (plugin.getConfiguration().getPreview().getSneakCancel().isActionBar() && plugin.getConfiguration().getPreview().getSneakCancel().isEnabled()) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, StringUtil.parse(player, plugin.getMessageHandler().get(Messages.PREVIEW_BAR))); - } - if (plugin.getConfiguration().getPreview().getBobbing().isEnabled()) { - var newHeight = MathUtil.sin(currentSinAngle) * plugin.getConfiguration().getPreview().getBobbing() - .getIntensity(); - var difference = newHeight - oldHeight; - oldHeight = newHeight; - PacketEvents.getAPI().getPlayerManager().sendPacket(player, - new WrapperPlayServerEntityRelativeMoveAndRotation( - entityId, 0, difference, 0, currentAngle, 90f, false) - ); - currentSinAngle += plugin.getConfiguration().getPreview().getBobbing().getSpeed(); - if (currentSinAngle > 360) { - currentSinAngle = 0; - } - } else { - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityRotation(entityId, currentAngle, 90f, false)); - } - currentAngle += plugin.getConfiguration().getPreview().getRotation(); - } - -} +package de.skyslycer.hmcwraps.preview.floating; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRelativeMoveAndRotation; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation; +import de.skyslycer.hmcwraps.HMCWraps; +import de.skyslycer.hmcwraps.messages.Messages; +import de.skyslycer.hmcwraps.util.MathUtil; +import de.skyslycer.hmcwraps.util.StringUtil; +import net.md_5.bungee.api.ChatMessageType; +import org.bukkit.entity.Player; + +public class RotateRunnable implements Runnable { + + private final Player player; + private final int entityId; + private final HMCWraps plugin; + + private int currentSinAngle = 0; + private float currentAngle = 0; + private double oldHeight = 0; + + public RotateRunnable(Player player, int entityId, HMCWraps plugin) { + this.player = player; + this.entityId = entityId; + this.plugin = plugin; + } + + @Override + public void run() { + if (plugin.getConfiguration().getPreview().getSneakCancel().isActionBar() && plugin.getConfiguration().getPreview().getSneakCancel().isEnabled()) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, StringUtil.parse(player, plugin.getMessageHandler().get(Messages.PREVIEW_BAR))); + } + if (plugin.getConfiguration().getPreview().getBobbing().isEnabled()) { + var newHeight = MathUtil.sin(currentSinAngle) * plugin.getConfiguration().getPreview().getBobbing() + .getIntensity(); + var difference = newHeight - oldHeight; + oldHeight = newHeight; + PacketEvents.getAPI().getPlayerManager().sendPacket(player, + new WrapperPlayServerEntityRelativeMoveAndRotation( + entityId, 0, difference, 0, currentAngle, 90f, false) + ); + currentSinAngle += plugin.getConfiguration().getPreview().getBobbing().getSpeed(); + if (currentSinAngle > 360) { + currentSinAngle = 0; + } + } else { + PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityRotation(entityId, currentAngle, 90f, false)); + } + currentAngle += plugin.getConfiguration().getPreview().getRotation(); + } + +} diff --git a/api/src/main/java/de/skyslycer/hmcwraps/preview/hand/HandPreview.java b/api/src/main/java/de/skyslycer/hmcwraps/preview/hand/HandPreview.java new file mode 100644 index 0000000..75db8b0 --- /dev/null +++ b/api/src/main/java/de/skyslycer/hmcwraps/preview/hand/HandPreview.java @@ -0,0 +1,73 @@ +package de.skyslycer.hmcwraps.preview.hand; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetSlot; +import de.skyslycer.hmcwraps.HMCWraps; +import de.skyslycer.hmcwraps.messages.Messages; +import de.skyslycer.hmcwraps.preview.Preview; +import de.skyslycer.hmcwraps.util.StringUtil; +import io.github.retrooper.packetevents.util.SpigotReflectionUtil; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitTask; + +import java.util.function.Consumer; + +public class HandPreview implements Preview { + + private final Player player; + private final ItemStack item; + private final Consumer onClose; + private final HMCWraps plugin; + private BukkitTask task; + private BukkitTask cancelTask; + private ItemStack oldItem; + private int slot = 0; + + public HandPreview(Player player, ItemStack item, Consumer onClose, HMCWraps plugin) { + this.player = player; + this.item = item; + this.onClose = onClose; + this.plugin = plugin; + } + + public void preview() { + player.closeInventory(); + + oldItem = player.getInventory().getItemInMainHand(); + slot = 36 + player.getInventory().getHeldItemSlot(); + sendFakeItem(item); + + task = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, () -> { + if (plugin.getConfiguration().getPreview().getSneakCancel().isActionBar() && plugin.getConfiguration().getPreview().getSneakCancel().isEnabled()) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, StringUtil.parse(player, plugin.getMessageHandler().get(Messages.PREVIEW_BAR))); + } + }, 3, 1); + cancelTask = Bukkit.getScheduler() + .runTaskLater(plugin, () -> plugin.getPreviewManager().remove(player.getUniqueId(), true), + plugin.getConfiguration().getPreview().getDuration() * 20L); + } + + public void cancel(boolean open) { + task.cancel(); + cancelTask.cancel(); + if (open && onClose != null) { + onClose.accept(player); + } + Bukkit.getScheduler().runTaskLater(plugin, () -> { + sendFakeItem(oldItem); + if (plugin.getConfiguration().getPreview().getSneakCancel().isActionBar()) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(" ")); + } + }, 1L); + } + + private void sendFakeItem(ItemStack item) { + PacketEvents.getAPI().getPlayerManager().sendPacket(player, + new WrapperPlayServerSetSlot(0, -1, slot, SpigotReflectionUtil.decodeBukkitItemStack(item))); + } + +} diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/Config.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/Config.java index 9e705fb..99b5ebe 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/Config.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/Config.java @@ -1,6 +1,7 @@ package de.skyslycer.hmcwraps.serialization; import de.skyslycer.hmcwraps.serialization.filter.FilterSettings; +import de.skyslycer.hmcwraps.serialization.globaldisable.GlobalDisable; import de.skyslycer.hmcwraps.serialization.inventory.Inventory; import de.skyslycer.hmcwraps.serialization.item.SerializableItem; import de.skyslycer.hmcwraps.serialization.permission.PermissionSettings; @@ -8,8 +9,8 @@ import de.skyslycer.hmcwraps.serialization.preview.PreviewSettings; import de.skyslycer.hmcwraps.serialization.updater.UpdaterSettings; import de.skyslycer.hmcwraps.serialization.wrap.WrappableItem; +import de.skyslycer.hmcwraps.serialization.wrapping.WrappingSettings; import org.spongepowered.configurate.objectmapping.ConfigSerializable; -import org.spongepowered.configurate.objectmapping.meta.Setting; import java.util.HashMap; import java.util.List; @@ -19,7 +20,7 @@ public class Config { private UpdaterSettings updater; - @Setting("permission-settings") + private WrappingSettings wrapping; private PermissionSettings permissions; private PreviewSettings preview; private Toggleable favorites; @@ -27,12 +28,14 @@ public class Config { private Inventory inventory; private SerializableItem unwrapper; private PreservationSettings preservation; + private GlobalDisable globalDisable; private Map items = new HashMap<>(); private Map> collections = new HashMap<>(); + private Integer config = 1; public Config(UpdaterSettings updater, PermissionSettings permissions, PreviewSettings preview, Toggleable favorites, Inventory inventory, SerializableItem unwrapper, PreservationSettings preservation, Map items, - Map> collections, FilterSettings filter) { + Map> collections, FilterSettings filter, WrappingSettings wrapping) { this.updater = updater; this.permissions = permissions; this.preview = preview; @@ -43,6 +46,7 @@ public Config(UpdaterSettings updater, PermissionSettings permissions, PreviewSe this.items = items; this.collections = collections; this.filter = filter; + this.wrapping = wrapping; } public Config() { @@ -52,6 +56,10 @@ public Inventory getInventory() { return inventory; } + public WrappingSettings getWrapping() { + return wrapping; + } + public SerializableItem getUnwrapper() { return unwrapper; } @@ -88,4 +96,8 @@ public FilterSettings getFilter() { return filter; } + public GlobalDisable getGlobalDisable() { + return globalDisable; + } + } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/files/WrapFile.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/files/WrapFile.java index 0ce58c4..c36d568 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/files/WrapFile.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/files/WrapFile.java @@ -12,6 +12,8 @@ public class WrapFile extends Toggleable { private Map items = new HashMap<>(); + private int config = 1; + public WrapFile(Map items, boolean enabled) { super(enabled); this.items = items; diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/globaldisable/GlobalDisable.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/globaldisable/GlobalDisable.java new file mode 100644 index 0000000..46811ff --- /dev/null +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/globaldisable/GlobalDisable.java @@ -0,0 +1,36 @@ +package de.skyslycer.hmcwraps.serialization.globaldisable; + +import org.spongepowered.configurate.objectmapping.ConfigSerializable; + +import java.util.List; + +@ConfigSerializable +public class GlobalDisable { + + private List modelId; + private List color; + private List oraxen; + private List itemsadder; + private List mythic; + + public List getModelId() { + return modelId; + } + + public List getColor() { + return color; + } + + public List getOraxenId() { + return oraxen; + } + + public List getItemsAdderId() { + return itemsadder; + } + + public List getMythicId() { + return mythic; + } + +} diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/inventory/Inventory.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/inventory/Inventory.java index 72eb7bd..0007497 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/inventory/Inventory.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/inventory/Inventory.java @@ -11,6 +11,7 @@ public class Inventory { private ShortcutSettings shortcut; + private boolean itemChangeEnabled; private String title; private Type type; private int rows; @@ -47,6 +48,10 @@ public HashMap>> getActions() { return actions; } + public boolean isItemChangeEnabled() { + return itemChangeEnabled; + } + public enum Type { PAGINATED, diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/item/SerializableItem.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/item/SerializableItem.java index 8bd1cf0..83ca068 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/item/SerializableItem.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/item/SerializableItem.java @@ -2,6 +2,10 @@ import de.skyslycer.hmcwraps.HMCWraps; import de.skyslycer.hmcwraps.util.StringUtil; +import de.tr7zw.changeme.nbtapi.NBT; +import de.tr7zw.changeme.nbtapi.NBTContainer; +import de.tr7zw.changeme.nbtapi.NBTItem; +import de.tr7zw.changeme.nbtapi.NbtApiException; import dev.triumphteam.gui.builder.item.ItemBuilder; import org.bukkit.Bukkit; import org.bukkit.Color; @@ -11,6 +15,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.spongepowered.configurate.objectmapping.ConfigSerializable; @@ -31,9 +36,12 @@ public class SerializableItem { private @Nullable Map enchantments; private @Nullable Integer amount; private @Nullable String color; + private @Nullable String nbt; + private @Nullable Integer durability; public SerializableItem(String id, String name, @Nullable Boolean glow, @Nullable List lore, @Nullable List flags, - @Nullable Integer modelId, @Nullable Map enchantments, @Nullable Integer amount, @Nullable String color) { + @Nullable Integer modelId, @Nullable Map enchantments, @Nullable Integer amount, + @Nullable String color, @Nullable String nbt, @Nullable Integer durability) { this.id = id; this.name = name; this.glow = glow; @@ -43,6 +51,8 @@ public SerializableItem(String id, String name, @Nullable Boolean glow, @Nullabl this.enchantments = enchantments; this.amount = amount; this.color = color; + this.nbt = nbt; + this.durability = durability; } public SerializableItem() { @@ -85,7 +95,24 @@ public ItemStack toItem(HMCWraps plugin, Player player) { if (Boolean.TRUE.equals(isGlow())) { builder.glow(); } - return builder.build(); + var item = builder.build(); + if (getDurability() != null && item.getItemMeta() instanceof Damageable itemMeta) { + var damage = item.getType().getMaxDurability() - getDurability(); + itemMeta.setDamage(damage); + item.setItemMeta(itemMeta); + } + if (getNbt() != null) { + try { + new NBTContainer(getNbt()); + } catch (NbtApiException e) { + Bukkit.getLogger().warning("A provided NBT data is invalid in an item!"); + } + var itemNbt = new NBTItem(item); + var newNbt = NBT.parseNBT(getNbt()); + itemNbt.mergeCompound(newNbt); + item = itemNbt.getItem(); + } + return item; } public String getId() { @@ -128,6 +155,11 @@ public Boolean isGlow() { return glow; } + @Nullable + public Integer getDurability() { + return durability; + } + @Nullable public Color getColor() { if (color == null) { @@ -136,4 +168,9 @@ public Color getColor() { return StringUtil.colorFromString(color); } + @Nullable + public String getNbt() { + return nbt; + } + } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/permission/PermissionSettings.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/permission/PermissionSettings.java index 52825d9..2cde18d 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/permission/PermissionSettings.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/permission/PermissionSettings.java @@ -11,6 +11,7 @@ public class PermissionSettings { private boolean permissionVirtual; private boolean inventoryPermission; private boolean previewPermission; + private int inventoryCheckInterval; public boolean isCheckPermissionPhysical() { return checkPermissionPhysical; @@ -36,4 +37,8 @@ public boolean isPreviewPermission() { return previewPermission; } + public int getInventoryCheckInterval() { + return inventoryCheckInterval; + } + } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/preview/PreviewSettings.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/preview/PreviewSettings.java index e0026b4..2d2d3ea 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/preview/PreviewSettings.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/preview/PreviewSettings.java @@ -5,11 +5,16 @@ @ConfigSerializable public class PreviewSettings { + private PreviewType type; private int duration; private int rotation; private SneakCancel sneakCancel; private Bobbing bobbing; + public PreviewType getType() { + return type; + } + public int getDuration() { return duration; } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/preview/PreviewType.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/preview/PreviewType.java new file mode 100644 index 0000000..8936e6a --- /dev/null +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/preview/PreviewType.java @@ -0,0 +1,8 @@ +package de.skyslycer.hmcwraps.serialization.preview; + +public enum PreviewType { + + FLOATING, + HAND + +} diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/updater/UpdaterSettings.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/updater/UpdaterSettings.java index d823738..4056f8b 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/updater/UpdaterSettings.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/updater/UpdaterSettings.java @@ -6,6 +6,7 @@ @ConfigSerializable public class UpdaterSettings extends Toggleable { + private String frequency; private PluginPlatform platform; diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/PhysicalWrap.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/PhysicalWrap.java index fa45556..d34a2ba 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/PhysicalWrap.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/PhysicalWrap.java @@ -15,8 +15,8 @@ public class PhysicalWrap extends SerializableItem { public PhysicalWrap(String id, String name, @Nullable Boolean glow, @Nullable List lore, @Nullable List flags, @Nullable Integer modelId, @Nullable Map enchantments, - @Nullable Integer amount, @Nullable String color, boolean keepAfterUnwrap) { - super(id, name, glow, lore, flags, modelId, enchantments, amount, color); + @Nullable Integer amount, @Nullable String color, boolean keepAfterUnwrap, @Nullable String nbt) { + super(id, name, glow, lore, flags, modelId, enchantments, amount, color, nbt, null); this.keepAfterUnwrap = keepAfterUnwrap; } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/Wrap.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/Wrap.java index 949e11f..5b2fb30 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/Wrap.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/Wrap.java @@ -6,6 +6,7 @@ import de.skyslycer.hmcwraps.util.StringUtil; import dev.triumphteam.gui.builder.item.ItemBuilder; import org.bukkit.Color; +import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemFlag; @@ -15,11 +16,12 @@ import java.util.HashMap; import java.util.List; +import java.util.Map; @ConfigSerializable public class Wrap extends SerializableItem { - private Boolean preview = true; + private @Nullable Boolean preview; private String uuid; private @Nullable PhysicalWrap physical; private @Nullable String permission; @@ -30,12 +32,15 @@ public class Wrap extends SerializableItem { private @Nullable String wrapName; private @Nullable List wrapLore; private @Nullable RangeSettings range; - private @Nullable String nbt; + private @Nullable String wrapNbt; + private @Nullable List wrapFlags; + private @Nullable Boolean armorImitation; + private @Nullable Integer wrapDurability; public Wrap(String id, String name, @Nullable Boolean glow, @Nullable List lore, @Nullable Integer modelId, String uuid, @Nullable PhysicalWrap physical, @Nullable String permission, @Nullable SerializableItem lockedItem) { - super(id, name, glow, lore, null, modelId, null, null, null); + super(id, name, glow, lore, null, modelId, null, null, null, null, null); this.preview = true; this.uuid = uuid; this.physical = physical; @@ -43,6 +48,13 @@ public Wrap(String id, String name, @Nullable Boolean glow, @Nullable List lore, + @Nullable Integer modelId, String uuid, @Nullable String color, Integer amount, @Nullable List flags, + @Nullable Map enchantments) { + super(id, name, null, lore, flags, modelId, enchantments, amount, color, null, null); + this.uuid = uuid; + } + public Wrap() { } @@ -61,7 +73,7 @@ public PhysicalWrap getPhysical() { } public Boolean isPreview() { - return preview; + return preview == null || preview; } @Nullable @@ -107,15 +119,32 @@ public RangeSettings getRange() { } @Nullable - public String getNbt() { - return nbt; + public String getWrapNbt() { + return wrapNbt; + } + + @Nullable + public List getWrapFlags() { + return wrapFlags; } - public ItemStack toPermissionItem(HMCWraps plugin, Player player) { + public Boolean isArmorImitationEnabled() { + return armorImitation != null && armorImitation; + } + + @Nullable + public Integer getWrapDurability() { + return wrapDurability; + } + + public ItemStack toPermissionItem(HMCWraps plugin, Material type, Player player) { if (!plugin.getConfiguration().getPermissions().isPermissionVirtual() || hasPermission(player)) { - return super.toItem(plugin, player); + var item = super.toItem(plugin, player); + item.setType(type); + return item; } else if (getLockedItem() == null) { var item = super.toItem(plugin, player); + item.setType(type); var builder = ItemBuilder.from(item); if (getLockedName() != null) { builder.name(player != null ? StringUtil.parseComponent(player, getLockedName()) : StringUtil.parseComponent(getLockedName())); @@ -130,7 +159,7 @@ public ItemStack toPermissionItem(HMCWraps plugin, Player player) { } } - public record WrapValues(int modelId, Color color, String name, List lore, List flags) { + public record WrapValues(int modelId, Color color, String name, List lore, List flags, String itemsAdder, String oraxen, String mythic, String material) { } } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/range/RangeSettings.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/range/RangeSettings.java index 7c46e1b..f1d02d4 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/range/RangeSettings.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/range/RangeSettings.java @@ -7,12 +7,20 @@ public class RangeSettings { private ValueRangeSettings modelId; private ValueRangeSettings color; + private ValueRangeSettings itemsAdder; + private ValueRangeSettings oraxen; + private ValueRangeSettings mythic; - public RangeSettings(ValueRangeSettings modelId, ValueRangeSettings color) { + public RangeSettings(ValueRangeSettings modelId, ValueRangeSettings color, ValueRangeSettings itemsAdder, ValueRangeSettings oraxen, ValueRangeSettings mythic) { this.modelId = modelId; this.color = color; + this.itemsAdder = itemsAdder; + this.oraxen = oraxen; + this.mythic = mythic; } + public RangeSettings() {} + public ValueRangeSettings getModelId() { return modelId; } @@ -21,4 +29,21 @@ public ValueRangeSettings getColor() { return color; } + public ValueRangeSettings getItemsAdder() { + return itemsAdder; + } + + public ValueRangeSettings getOraxen() { + return oraxen; + } + + public ValueRangeSettings getMythic() { + return mythic; + } + + public static RangeSettings empty() { + return new RangeSettings(new ValueRangeSettings<>(), new ValueRangeSettings<>(), new ValueRangeSettings<>(), + new ValueRangeSettings<>(), new ValueRangeSettings<>()); + } + } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/range/ValueRangeSettings.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/range/ValueRangeSettings.java index b7c5ad4..74f9310 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/range/ValueRangeSettings.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrap/range/ValueRangeSettings.java @@ -11,13 +11,7 @@ public class ValueRangeSettings { private @Nullable List include; private @Nullable List exclude; - public ValueRangeSettings(@Nullable List include, @Nullable List exclude) { - this.include = include; - this.exclude = exclude; - } - - public ValueRangeSettings() { - } + public ValueRangeSettings() { } @Nullable public List getInclude() { diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrapping/RewrapSettings.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrapping/RewrapSettings.java new file mode 100644 index 0000000..dfbfa76 --- /dev/null +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrapping/RewrapSettings.java @@ -0,0 +1,19 @@ +package de.skyslycer.hmcwraps.serialization.wrapping; + +import org.spongepowered.configurate.objectmapping.ConfigSerializable; + +@ConfigSerializable +public class RewrapSettings { + + private boolean virtualEnabled = true; + private boolean physicalEnabled = true; + + public boolean isVirtualEnabled() { + return virtualEnabled; + } + + public boolean isPhysicalEnabled() { + return physicalEnabled; + } + +} diff --git a/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrapping/WrappingSettings.java b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrapping/WrappingSettings.java new file mode 100644 index 0000000..aa1b9f5 --- /dev/null +++ b/api/src/main/java/de/skyslycer/hmcwraps/serialization/wrapping/WrappingSettings.java @@ -0,0 +1,14 @@ +package de.skyslycer.hmcwraps.serialization.wrapping; + +import org.spongepowered.configurate.objectmapping.ConfigSerializable; + +@ConfigSerializable +public class WrappingSettings { + + private RewrapSettings rewrap; + + public RewrapSettings getRewrap() { + return rewrap; + } + +} diff --git a/api/src/main/java/de/skyslycer/hmcwraps/util/MaterialUtil.java b/api/src/main/java/de/skyslycer/hmcwraps/util/MaterialUtil.java new file mode 100644 index 0000000..fbbe6e5 --- /dev/null +++ b/api/src/main/java/de/skyslycer/hmcwraps/util/MaterialUtil.java @@ -0,0 +1,27 @@ +package de.skyslycer.hmcwraps.util; + +import org.bukkit.Material; + +public class MaterialUtil { + + /** + * Get the leather alternative of an armor piece. + * + * @param material The armor piece + * @return The leather alternative + */ + public static Material getLeatherAlternative(Material material) { + if (material.toString().contains("_HELMET")) { + return Material.LEATHER_HELMET; + } else if (material.toString().contains("_CHESTPLATE")) { + return Material.LEATHER_CHESTPLATE; + } else if (material.toString().contains("_LEGGINGS")) { + return Material.LEATHER_LEGGINGS; + } else if (material.toString().contains("_BOOTS")) { + return Material.LEATHER_BOOTS; + } else { + return material; + } + } + +} diff --git a/api/src/main/java/de/skyslycer/hmcwraps/util/PermissionUtil.java b/api/src/main/java/de/skyslycer/hmcwraps/util/PermissionUtil.java index 38f63a9..cf6b3e0 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/util/PermissionUtil.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/util/PermissionUtil.java @@ -4,6 +4,7 @@ import de.skyslycer.hmcwraps.serialization.wrap.Wrap; import de.skyslycer.hmcwraps.serialization.wrap.WrappableItem; import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; @@ -18,7 +19,7 @@ public class PermissionUtil { * @param player The player * @return If the player has permission to use the wrap on the item */ - static boolean hasPermission(HMCWraps plugin, Wrap wrap, ItemStack item, Player player) { + public static boolean hasPermission(HMCWraps plugin, Wrap wrap, ItemStack item, Player player) { var wrapper = plugin.getWrapper(); if (wrapper.isPhysical(item) && plugin.getConfiguration().getPermissions().isCheckPermissionPhysical() && !wrap.hasPermission(player) && !wrapper.isOwningPlayer(item, player)) { @@ -39,7 +40,7 @@ static boolean hasPermission(HMCWraps plugin, Wrap wrap, ItemStack item, Player */ @Nullable public static ItemStack hasPermission(HMCWraps plugin, ItemStack item, Player player) { - if (item.getType().isAir()) { + if (item == null || item.getType().isAir()) { return null; } var wrap = plugin.getWrapper().getWrap(item); @@ -47,24 +48,30 @@ public static ItemStack hasPermission(HMCWraps plugin, ItemStack item, Player pl return null; } if (!hasPermission(plugin, wrap, item, player)) { - return plugin.getWrapper().removeWrap(item, player, plugin.getConfiguration().getPermissions().isPermissionPhysical()); + return plugin.getWrapper().removeWrap(item, player, plugin.getConfiguration().getPermissions().isPermissionPhysical() + && (wrap.getPhysical() != null && wrap.getPhysical().isKeepAfterUnwrap())); } return null; } /** - * Loops through a players inventory and unwraps items the player doesn't have access to and apply favorites if possible. + * Loops through an inventory and unwraps items the player doesn't have access to and apply favorites if possible. * * @param plugin The plugin * @param player The player + * @param inventory The inventory */ - public static void loopThroughInventory(HMCWraps plugin, Player player) { - for (int i = 0; i < player.getInventory().getContents().length - 1; i++) { + public static void loopThroughInventory(HMCWraps plugin, Player player, Inventory inventory) { + for (int i = 0; i < inventory.getContents().length - 1; i++) { var item = player.getInventory().getItem(i); if (item == null || item.getType().isAir()) { continue; } - player.getInventory().setItem(i, check(plugin, player, item)); + var updatedItem = check(plugin, player, item); + if (updatedItem.equals(item)) { + continue; + } + inventory.setItem(i, updatedItem); } } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/util/StringUtil.java b/api/src/main/java/de/skyslycer/hmcwraps/util/StringUtil.java index 9c45704..0d103a3 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/util/StringUtil.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/util/StringUtil.java @@ -189,4 +189,32 @@ private static TagResolver papiTag(CommandSender sender) { }); } + /** + * Converts a string from UPPER_CASE_WITH_UNDERSCORES to Title Case. + * + * @param input the string to convert + * @return the converted string + */ + public static String convertToTitleCase(String input) { + if (input == null || input.isEmpty()) { + return input; + } + var words = input.split("_"); + var output = new StringBuilder(); + for (String word : words) { + if (!output.isEmpty()) { + output.append(" "); + } + output.append(toTitleCase(word)); + } + return output.toString(); + } + + private static String toTitleCase(String word) { + if (word == null || word.isEmpty()) { + return word; + } + return Character.toUpperCase(word.charAt(0)) + word.substring(1).toLowerCase(); + } + } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/util/WrapNBTUtil.java b/api/src/main/java/de/skyslycer/hmcwraps/util/WrapNBTUtil.java index 6eccb4f..555ed89 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/util/WrapNBTUtil.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/util/WrapNBTUtil.java @@ -99,6 +99,20 @@ private static void set(ReadableNBT source, String key, NBTCompound target) { case NBTTagByteArray -> target.setByteArray(key, source.getByteArray(key)); case NBTTagIntArray -> target.setIntArray(key, source.getIntArray(key)); case NBTTagString -> target.setString(key, source.getString(key)); + case NBTTagList -> setList(source, key, target); + } + } + + private static void setList(ReadableNBT source, String key, NBTCompound target) { + var type = source.getListType(key); + switch (type) { + case NBTTagInt -> target.getIntegerList(key).addAll(source.getIntegerList(key).toListCopy()); + case NBTTagFloat -> target.getFloatList(key).addAll(source.getFloatList(key).toListCopy()); + case NBTTagDouble -> target.getDoubleList(key).addAll(source.getDoubleList(key).toListCopy()); + case NBTTagIntArray -> target.getIntArrayList(key).addAll(source.getIntArrayList(key).toListCopy()); + case NBTTagString -> target.getStringList(key).addAll(source.getStringList(key).toListCopy()); + case NBTTagCompound -> target.getCompoundList(key).addAll(source.getCompoundList(key).toListCopy()); + case NBTTagLong -> target.getLongList(key).addAll(source.getLongList(key).toListCopy()); } } diff --git a/api/src/main/java/de/skyslycer/hmcwraps/wrap/Wrapper.java b/api/src/main/java/de/skyslycer/hmcwraps/wrap/Wrapper.java index 1f7e432..f2801f5 100644 --- a/api/src/main/java/de/skyslycer/hmcwraps/wrap/Wrapper.java +++ b/api/src/main/java/de/skyslycer/hmcwraps/wrap/Wrapper.java @@ -69,6 +69,40 @@ public interface Wrapper { */ ItemStack removeWrap(ItemStack itemStack, Player player, boolean giveBack); + /** + * Get the fake durability of the item. + * If the item isn't changing durability, it will return -1. + * + * @param item The item + * @return The fake durability + */ + int getFakeDurability(ItemStack item); + + /** + * Set the fake durability of the item. + * + * @param item The item + * @param durability The durability to set + */ + void setFakeDurability(ItemStack item, int durability); + + /** + * Get the fake max durability of the item. + * If the item isn't changing durability, it will return -1. + * + * @param item The item + * @return The fake durability + */ + int getFakeMaxDurability(ItemStack item); + + /** + * Set the fake max durability of the item. + * + * @param item The item + * @param durability The durability to set + */ + void setFakeMaxDurability(ItemStack item, int durability); + /** * Check if the item is an unwrapper. * @@ -145,4 +179,12 @@ public interface Wrapper { */ boolean isValid(ItemStack item, Wrap wrap); + /** + * Check if the item is globally disabled to not be able to be wrapped. + * + * @param item The item to check + * @return If the item is globally disabled + */ + boolean isGloballyDisabled(ItemStack item); + } diff --git a/build.gradle.kts b/build.gradle.kts index 54619f6..40de3ac 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,13 +2,13 @@ import net.minecrell.pluginyml.bukkit.BukkitPluginDescription.Permission.Default plugins { java - id("net.minecrell.plugin-yml.bukkit") version "0.5.3" + id("net.minecrell.plugin-yml.bukkit") version "0.6.0" id("com.github.johnrengelman.shadow") version "8.1.1" id("xyz.jpenilla.run-paper") version "2.1.0" } group = "de.skyslycer" -version = "1.3.3" +version = "1.4.0" val shadePattern = "$group.hmcwraps.shade" @@ -162,5 +162,9 @@ bukkit { description = "Gives access to debug commands." children = listOf("hmcwraps.admin") } + register("hmcwraps.commands.create") { + description = "Gives access to the create command." + children = listOf("hmcwraps.admin") + } } } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index ade908c..97e6fdb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,7 +4,7 @@ include("api") dependencyResolutionManagement { versionCatalogs { create("depends") { - library("spigot", "org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT") + library("spigot", "org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT") library("placeholderapi", "me.clip:placeholderapi:2.11.2") library("oraxen", "com.github.oraxen:oraxen:-SNAPSHOT") library("itemsadder", "com.github.LoneDev6:API-ItemsAdder:3.2.5") @@ -12,14 +12,14 @@ dependencyResolutionManagement { library("annotations", "org.jetbrains:annotations:24.0.1") } create("libs") { - library("packets", "com.github.retrooper.packetevents:spigot:2.0.0-SNAPSHOT") + library("packets", "com.github.retrooper.packetevents:spigot:2.2.0") library("particles", "com.owen1212055:particlehelper:1.1.0-SNAPSHOT") library("configupdater", "com.github.BG-Software-LLC:CommentedConfiguration:-SNAPSHOT") library("bstats", "org.bstats:bstats-bukkit:3.0.2") library("gui", "dev.triumphteam:triumph-gui:3.1.5") library("configurate", "org.spongepowered:configurate-yaml:4.1.2") library("mclogs", "com.github.aternosorg:mclogs-java:v2.2.0") - library("nbtapi", "de.tr7zw:item-nbt-api:2.11.3") + library("nbtapi", "de.tr7zw:item-nbt-api:2.12.0") library("adventure-api", "net.kyori", "adventure-api").versionRef("adventure") library("minimessage", "net.kyori", "adventure-text-minimessage").versionRef("adventure") diff --git a/src/main/java/de/skyslycer/hmcwraps/HMCWrapsPlugin.java b/src/main/java/de/skyslycer/hmcwraps/HMCWrapsPlugin.java index 1928d53..76c9bb8 100644 --- a/src/main/java/de/skyslycer/hmcwraps/HMCWrapsPlugin.java +++ b/src/main/java/de/skyslycer/hmcwraps/HMCWrapsPlugin.java @@ -21,7 +21,9 @@ import de.skyslycer.hmcwraps.storage.FavoriteWrapStorage; import de.skyslycer.hmcwraps.storage.PlayerFilterStorage; import de.skyslycer.hmcwraps.storage.Storage; +import de.skyslycer.hmcwraps.transformation.ConfigFileTransformations; import de.skyslycer.hmcwraps.updater.ContinuousUpdateChecker; +import de.skyslycer.hmcwraps.util.PermissionUtil; import de.skyslycer.hmcwraps.wrap.*; import de.tr7zw.changeme.nbtapi.NBTContainer; import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion; @@ -31,6 +33,7 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; import org.spongepowered.configurate.ConfigurationOptions; import org.spongepowered.configurate.yaml.YamlConfigurationLoader; @@ -64,6 +67,7 @@ public class HMCWrapsPlugin extends JavaPlugin implements HMCWraps { private HookAccessor hookAccessor; private Config config; private MessageHandler messageHandler; + private BukkitTask checkTask; @Override public void onLoad() { @@ -99,6 +103,11 @@ public void onEnable() { Bukkit.getPluginManager().registerEvents(new PlayerShiftListener(this), this); Bukkit.getPluginManager().registerEvents(new PlayerPickupListener(this), this); Bukkit.getPluginManager().registerEvents(new PlayerJoinListener(this), this); + Bukkit.getPluginManager().registerEvents(new PlayerDropListener(this), this); + Bukkit.getPluginManager().registerEvents(new PlayerHitEntityListener(this), this); + Bukkit.getPluginManager().registerEvents(new DurabilityChangeListener(this), this); + Bukkit.getPluginManager().registerEvents(new ItemBurnListener(this), this); + Bukkit.getPluginManager().registerEvents(new PlayerOffHandSwitchListener(this), this); PacketEvents.getAPI().init(); @@ -137,12 +146,16 @@ public boolean load() { } getPreviewManager().removeAll(true); getUpdateChecker().check(); + startCheckTask(); return true; } @Override public void unload() { getWrapsLoader().unload(); + if (checkTask != null) { + checkTask.cancel(); + } } private boolean loadMessages() { @@ -166,6 +179,10 @@ private boolean loadConfig() { Files.createDirectory(WRAP_FILES_PATH); Files.copy(getResource("silver_wraps.yml"), WRAP_FILES_PATH.resolve("silver_wraps.yml")); } + if (Files.notExists(WRAP_FILES_PATH)) { + Files.createDirectory(WRAP_FILES_PATH); + Files.copy(getResource("emerald_wraps.yml"), WRAP_FILES_PATH.resolve("emerald_wraps.yml")); + } if (Files.notExists(COLLECTION_FILES_PATH)) { Files.createDirectory(COLLECTION_FILES_PATH); Files.copy(getResource("some_collections.yml"), COLLECTION_FILES_PATH.resolve("some_collections.yml")); @@ -176,8 +193,9 @@ private boolean loadConfig() { if (Files.notExists(CONFIG_PATH)) { Files.copy(getResource("config.yml"), CONFIG_PATH); } + new ConfigFileTransformations().updateToLatest(CONFIG_PATH); CommentedConfiguration.loadConfiguration(CONFIG_PATH.toFile()).syncWithConfig(CONFIG_PATH.toFile(), getResource("config.yml"), - "items", "inventory.items", "collections", "unwrapper", "inventory.actions"); + "items", "inventory.items", "collections", "unwrapper", "inventory.actions"); config = LOADER.load().get(Config.class); getWrapsLoader().load(); } catch (IOException exception) { @@ -204,6 +222,32 @@ private boolean checkDependency(String name, boolean needed) { return true; } + private void startCheckTask() { + if (config.getPermissions().getInventoryCheckInterval() == -1) { + return; + } + checkTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> Bukkit.getOnlinePlayers().forEach(player -> { + for (int i = 0; i < player.getInventory().getContents().length - 1; i++) { + var item = player.getInventory().getItem(i); + if (item == null || item.getType().isAir()) { + continue; + } + var wrap = getWrapper().getWrap(item); + if (wrap == null) { + continue; + } + if (!PermissionUtil.hasPermission(this, wrap, item, player)) { + int finalI = i; // ;( + Bukkit.getScheduler().runTask(this, () -> { + var newItem = getWrapper().removeWrap(item, player, getConfiguration().getPermissions().isPermissionPhysical() + && (wrap.getPhysical() != null && wrap.getPhysical().isKeepAfterUnwrap())); + player.getInventory().setItem(finalI, newItem); + }); + } + } + }), 0L, config.getPermissions().getInventoryCheckInterval() < 1 ? 10L * 20 * 60 : config.getPermissions().getInventoryCheckInterval() * 20L * 60L); + } + @Override public void logSevere(String message, Throwable thrown) { if (thrown != null) { diff --git a/src/main/java/de/skyslycer/hmcwraps/actions/register/DefaultActionRegister.java b/src/main/java/de/skyslycer/hmcwraps/actions/register/DefaultActionRegister.java index 4b47902..94b305e 100644 --- a/src/main/java/de/skyslycer/hmcwraps/actions/register/DefaultActionRegister.java +++ b/src/main/java/de/skyslycer/hmcwraps/actions/register/DefaultActionRegister.java @@ -32,7 +32,6 @@ import org.bukkit.NamespacedKey; import org.bukkit.Sound; import org.bukkit.entity.Player; -import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import java.math.BigInteger; @@ -93,14 +92,19 @@ private void registerScrollBack() { private void registerUnwrap() { plugin.getActionHandler().subscribe(Action.UNWRAP, (actionInformation) -> { var player = actionInformation.getPlayer(); - var wrap = plugin.getWrapper().getWrap(player.getInventory().getItemInMainHand()); - player.getInventory().setItemInMainHand(plugin.getWrapper().removeWrap(player.getInventory().getItemInMainHand(), player, true)); - player.getOpenInventory().close(); + var slot = getSlot(actionInformation); + var wrap = plugin.getWrapper().getWrap(player.getInventory().getItem(slot)); + player.getInventory().setItem(slot, plugin.getWrapper().removeWrap(player.getInventory().getItem(slot), player, true)); plugin.getMessageHandler().send(player, Messages.REMOVE_WRAP); if (wrap != null) { plugin.getActionHandler().pushUnwrap(wrap, player); plugin.getActionHandler().pushVirtualUnwrap(wrap, player); } + if (plugin.getConfiguration().getInventory().isItemChangeEnabled()) { + openIfPossible(plugin, actionInformation, player); + } else { + player.closeInventory(); + } }); } @@ -278,7 +282,7 @@ private void registerCommand() { private void registerConsoleCommand() { plugin.getActionHandler().subscribe(Action.CONSOLE_COMMAND, (information) -> { if (checkSplit(information.getArguments().split(" "), 1, "console command", "kill ")) return; - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parseCommand(information)); + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parseCommand(information).substring(1)); }); } @@ -304,9 +308,11 @@ private void registerFavorite() { if (!ListUtil.containsAny(collections.getMaterials(collections.getCollection(currentWrap)), collections.getMaterials(collections.getCollection(wrap)))) { return; } - var range = wrap.getRange() == null ? new RangeSettings(new ValueRangeSettings<>(), new ValueRangeSettings<>()) : wrap.getRange(); - var currentRange = currentWrap.getRange() == null ? new RangeSettings(new ValueRangeSettings<>(null, null), new ValueRangeSettings<>(null, null)) : currentWrap.getRange(); - if (!isSameRange(range.getModelId(), currentRange.getModelId()) || !isSameRange(range.getColor(), currentRange.getColor())) { + var range = wrap.getRange() == null ? RangeSettings.empty() : wrap.getRange(); + var currentRange = currentWrap.getRange() == null ? RangeSettings.empty() : currentWrap.getRange(); + if (!isSameRange(range.getModelId(), currentRange.getModelId()) || !isSameRange(range.getColor(), currentRange.getColor()) + || !isSameRange(range.getOraxen(), currentRange.getOraxen()) || !isSameRange(range.getItemsAdder(), currentRange.getItemsAdder()) + || !isSameRange(range.getMythic(), currentRange.getMythic())) { return; } current.remove(currentWrap); @@ -314,6 +320,7 @@ private void registerFavorite() { current.removeIf(it -> it.getUuid().equals(wrap.getUuid())); current.add(wrap); plugin.getFavoriteWrapStorage().set(player, current); + plugin.getMessageHandler().send(player, Messages.FAVORITES_SET); })); } @@ -335,7 +342,10 @@ private boolean isSameRange(ValueRangeSettings first, ValueRangeSettings< } private void registerClearFavorites() { - plugin.getActionHandler().subscribe(Action.CLEAR_FAVORITES, (information -> plugin.getFavoriteWrapStorage().set(information.getPlayer(), new ArrayList<>()))); + plugin.getActionHandler().subscribe(Action.CLEAR_FAVORITES, (information -> { + plugin.getFavoriteWrapStorage().set(information.getPlayer(), new ArrayList<>()); + plugin.getMessageHandler().send(information.getPlayer(), Messages.FAVORITES_CLEAR); + })); } private void registerPreview() { @@ -357,9 +367,19 @@ private void registerPreview() { } private void openIfPossible(HMCWrapsPlugin plugin, ActionInformation information, Player player) { - if (!plugin.getCollectionHelper().getItems(player.getInventory().getItemInMainHand().getType()).isEmpty() + var slot = getSlot(information); + var item = player.getInventory().getItem(slot); + if (item == null) { + player.closeInventory(); + return; + } + var type = item.getType(); + if (plugin.getWrapper().getWrap(item) != null && !plugin.getWrapper().getOriginalData(item).material().isEmpty()) { + type = Material.valueOf(plugin.getWrapper().getOriginalData(item).material()); + } + if (!plugin.getCollectionHelper().getItems(type).isEmpty() && (information instanceof GuiActionInformation || information instanceof WrapGuiActionInformation)) { - GuiBuilder.open(plugin, player, player.getInventory().getItemInMainHand()); + GuiBuilder.open(plugin, player, player.getInventory().getItem(slot), slot); } } @@ -367,17 +387,26 @@ private void registerWrap() { plugin.getActionHandler().subscribe(Action.WRAP, (information -> { var player = information.getPlayer(); var wrap = getWrap(information); + var slot = getSlot(information); if (wrap == null) return; if (!wrap.hasPermission(player) && plugin.getConfiguration().getPermissions().isPermissionVirtual()) { plugin.getMessageHandler().send(player, Messages.NO_PERMISSION_FOR_WRAP); return; } - var item = player.getInventory().getItemInMainHand(); - player.getInventory().setItem(EquipmentSlot.HAND, plugin.getWrapper().setWrap(wrap, item, false, player, true)); + var item = player.getInventory().getItem(slot); + if (!plugin.getConfiguration().getWrapping().getRewrap().isVirtualEnabled() && plugin.getWrapper().getWrap(item) != null) { + plugin.getMessageHandler().send(player, Messages.NO_REWRAP); + return; + } + player.getInventory().setItem(slot, plugin.getWrapper().setWrap(wrap, item, false, player, true)); plugin.getMessageHandler().send(player, Messages.APPLY_WRAP); plugin.getActionHandler().pushWrap(wrap, player); plugin.getActionHandler().pushVirtualWrap(wrap, player); - player.getOpenInventory().close(); + if (plugin.getConfiguration().getInventory().isItemChangeEnabled()) { + openIfPossible(plugin, information, player); + } else { + player.closeInventory(); + } })); } @@ -419,6 +448,18 @@ private Wrap getWrap(ActionInformation information) { return wrap; } + private int getSlot(ActionInformation information) { + int slot; + if (information instanceof GuiActionInformation guiInformation) { + slot = guiInformation.getSlot(); + } else if (information instanceof WrapGuiActionInformation wrapInformation) { + slot = wrapInformation.getSlot(); + } else { + slot = information.getPlayer().getInventory().getHeldItemSlot(); + } + return slot; + } + private String parseMessage(ActionInformation information) { return parseMessage(information, information.getArguments()); } diff --git a/src/main/java/de/skyslycer/hmcwraps/commands/CommandRegister.java b/src/main/java/de/skyslycer/hmcwraps/commands/CommandRegister.java index 16996f6..8f590d7 100644 --- a/src/main/java/de/skyslycer/hmcwraps/commands/CommandRegister.java +++ b/src/main/java/de/skyslycer/hmcwraps/commands/CommandRegister.java @@ -27,11 +27,11 @@ public static void registerCommands(HMCWrapsPlugin plugin) { BukkitCommandHandler commandHandler = BukkitCommandHandler.create(plugin); commandHandler.registerValueResolver(Wrap.class, context -> { - var wrap = plugin.getWrapsLoader().getWraps().get(context.pop()); + var uuid = context.pop(); + var wrap = plugin.getWrapsLoader().getWraps().get(uuid); if (wrap == null) { plugin.getMessageHandler().send(context.actor().as(BukkitActor.class).getAsPlayer(), Messages.COMMAND_INVALID_WRAP, - Placeholder.parsed("uuid", context.pop())); - throw new IllegalArgumentException(); + Placeholder.parsed("uuid", uuid)); } return wrap; }); diff --git a/src/main/java/de/skyslycer/hmcwraps/commands/WrapCommand.java b/src/main/java/de/skyslycer/hmcwraps/commands/WrapCommand.java index 28d01a0..3808694 100644 --- a/src/main/java/de/skyslycer/hmcwraps/commands/WrapCommand.java +++ b/src/main/java/de/skyslycer/hmcwraps/commands/WrapCommand.java @@ -1,28 +1,43 @@ package de.skyslycer.hmcwraps.commands; +import de.skyslycer.hmcwraps.HMCWraps; import de.skyslycer.hmcwraps.HMCWrapsPlugin; import de.skyslycer.hmcwraps.gui.GuiBuilder; import de.skyslycer.hmcwraps.messages.Messages; +import de.skyslycer.hmcwraps.serialization.files.WrapFile; import de.skyslycer.hmcwraps.serialization.wrap.Wrap; import de.skyslycer.hmcwraps.serialization.wrap.WrappableItem; +import de.skyslycer.hmcwraps.util.ColorUtil; import de.skyslycer.hmcwraps.util.PlayerUtil; import de.skyslycer.hmcwraps.util.StringUtil; +import dev.lone.itemsadder.api.CustomStack; import dev.triumphteam.gui.guis.BaseGui; +import io.lumine.mythic.bukkit.MythicBukkit; +import io.th0rgal.oraxen.api.OraxenItems; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver.Single; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.spongepowered.configurate.BasicConfigurationNode; +import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.ConfigurationOptions; +import org.spongepowered.configurate.yaml.NodeStyle; +import org.spongepowered.configurate.yaml.YamlConfigurationLoader; +import revxrsal.commands.annotation.Optional; import revxrsal.commands.annotation.*; import revxrsal.commands.bukkit.annotation.CommandPermission; import revxrsal.commands.help.CommandHelp; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; import java.util.function.Supplier; import java.util.stream.Stream; @@ -37,6 +52,7 @@ public class WrapCommand { public static final String GIVE_UNWRAPPER_PERMISSION = "hmcwraps.commands.give.unwrapper"; public static final String PREVIEW_PERMISSION = "hmcwraps.commands.preview"; public static final String LIST_PERMISSION = "hmcwraps.commands.list"; + public static final String CREATE_PERMISSION = "hmcwraps.commands.create"; public static final String WRAPS_PERMISSION = "hmcwraps.wraps"; private final Set confirmingPlayers = new HashSet<>(); @@ -59,11 +75,16 @@ public void onWraps(Player player) { plugin.getMessageHandler().send(player, Messages.NO_ITEM); return; } - if (plugin.getCollectionHelper().getItems(item.getType()).isEmpty()) { + var type = item.getType(); + if (plugin.getWrapper().getWrap(item) != null && !plugin.getWrapper().getOriginalData(item).material().isEmpty()) { + type = Material.valueOf(plugin.getWrapper().getOriginalData(item).material()); + } + if (plugin.getCollectionHelper().getItems(type).isEmpty() || plugin.getWrapper().isGloballyDisabled(item)) { plugin.getMessageHandler().send(player, Messages.NO_WRAPS); return; } - GuiBuilder.open(plugin, player, player.getInventory().getItemInMainHand()); + var slot = player.getInventory().getHeldItemSlot(); + GuiBuilder.open(plugin, player, player.getInventory().getItem(slot), slot); } @Subcommand("reload") @@ -119,6 +140,9 @@ public void onConvert(CommandSender sender, @Optional String confirm) { @CommandPermission(WRAP_PERMISSION) @AutoComplete("@wraps @players @actions") public void onWrap(CommandSender sender, Wrap wrap, @Default("self") Player player, @Optional String actions) { + if (wrap == null) { + return; + } var item = player.getInventory().getItemInMainHand().clone(); if (item.getType().isAir()) { plugin.getMessageHandler().send(sender, Messages.COMMAND_NEED_ITEM); @@ -169,6 +193,9 @@ public void onUnwrap(CommandSender sender, @Default("self") Player player, @Opti @CommandPermission(PREVIEW_PERMISSION) @AutoComplete("@wraps @players @actions") public void onPreview(CommandSender sender, Wrap wrap, @Default("self") Player player, @Optional String actions) { + if (wrap == null) { + return; + } var material = plugin.getCollectionHelper().getMaterial(wrap); if (material == null) { plugin.getMessageHandler().send(sender, Messages.COMMAND_NO_MATCHING_ITEM); @@ -186,6 +213,9 @@ public void onPreview(CommandSender sender, Wrap wrap, @Default("self") Player p @CommandPermission(GIVE_WRAPPER_PERMISSION) @AutoComplete("@physicalWraps @players *") public void onGiveWrap(CommandSender sender, Wrap wrap, @Default("self") Player player, @Range(min = 1, max = 64) @Optional Integer amount) { + if (wrap == null) { + return; + } if (wrap.getPhysical() == null) { plugin.getMessageHandler().send(sender, Messages.COMMAND_INVALID_PHYSICAL, Placeholder.parsed("uuid", wrap.getUuid())); return; @@ -241,11 +271,143 @@ public void onList(CommandSender sender) { sender.spigot().sendMessage(BungeeComponentSerializer.get().serialize(component)); } + @Subcommand("create") + @Description("Create a wrap from an item in hand!") + @CommandPermission(CREATE_PERMISSION) + public void onCreate(Player player, String file, String uuid, @Optional String collection) { + var path = HMCWraps.COMMAND_PATH.resolve(file + (file.endsWith(".yml") ? "" : ".yml")); + var item = player.getInventory().getItemInMainHand(); + if (item == null || item.getType().isAir()) { + plugin.getMessageHandler().send(player, Messages.COMMAND_NEED_ITEM); + return; + } + var checkedCollection = collection == null ? item.getType().toString() : collection; + var newWrap = createWrapFromItem(item, uuid); + + WrapFile wrapFile; + if (Files.exists(path)) { + wrapFile = updateExistingWrapFile(player, path, item, newWrap, checkedCollection); + } else { + wrapFile = createNewWrapFile(item, newWrap, checkedCollection); + } + + saveWrapFile(path, wrapFile, player); + } + + private Wrap createWrapFromItem(ItemStack item, String uuid) { + var meta = item.getItemMeta(); + String color = null; + if (meta instanceof LeatherArmorMeta leatherArmorMeta) { + color = ColorUtil.colorToHex(leatherArmorMeta.getColor()); + } + String id = getHookId(item); + String name = StringUtil.legacyToMiniMessage(meta.hasDisplayName() ? meta.getDisplayName().replace("§", "&") : StringUtil.convertToTitleCase(item.getType().name())); + List lore = extractLore(meta); + int amount = item.getAmount(); + List flags = meta.getItemFlags().stream().map(Enum::name).toList(); + Map enchantments = extractEnchantments(item); + + return new Wrap(id, name, lore, null, uuid, color, amount == 1 ? null : amount, flags.isEmpty() ? null : flags, enchantments); + } + + private List extractLore(ItemMeta meta) { + List lore = new ArrayList<>(); + if (meta.hasLore()) { + meta.getLore().forEach(line -> lore.add(StringUtil.legacyToMiniMessage(line.replace("§", "&")))); + } else { + return null; + } + return lore; + } + + private Map extractEnchantments(ItemStack item) { + Map enchantments = new HashMap<>(); + item.getEnchantments().forEach((enchantment, integer) -> enchantments.put(enchantment.getKey().getKey().toUpperCase(), integer)); + if (enchantments.isEmpty()) { + return null; + } + return enchantments; + } + + private WrapFile updateExistingWrapFile(Player player, Path path, ItemStack item, Wrap newWrap, String collection) { + try { + var existingFile = YamlConfigurationLoader.builder() + .defaultOptions(ConfigurationOptions.defaults().implicitInitialization(false)) + .path(path) + .build().load().get(WrapFile.class); + var items = existingFile.getItems(); + if (items.containsKey(collection)) { + var wrappableItem = items.get(collection); + wrappableItem.putWrap(String.valueOf(getUnusedId(wrappableItem.getWraps())), newWrap); + items.put(collection, wrappableItem); + } else { + var wraps = new HashMap(); + wraps.put("1", newWrap); + var wrappableItem = new WrappableItem(wraps); + items.put(collection, wrappableItem); + } + return new WrapFile(items, true); + } catch (ConfigurateException exception) { + handleException(player, exception, "loading the existing wrap file"); + return null; + } + } + + private WrapFile createNewWrapFile(ItemStack item, Wrap newWrap, String collection) { + var wraps = new HashMap(); + wraps.put("1", newWrap); + var wrappableItem = new WrappableItem(wraps); + var items = new HashMap(); + items.put(collection, wrappableItem); + return new WrapFile(items, true); + } + + private void saveWrapFile(Path path, WrapFile wrapFile, Player player) { + try { + YamlConfigurationLoader.builder() + .defaultOptions(ConfigurationOptions.defaults().implicitInitialization(false)) + .path(path).indent(2) + .nodeStyle(NodeStyle.BLOCK) + .build().save(BasicConfigurationNode.factory().createNode().set(wrapFile)); + plugin.getMessageHandler().send(player, Messages.COMMAND_CREATE_SUCCESS, Placeholder.parsed("path", "plugins/HMCWraps/wraps/command/" + path.getFileName().toString())); + } catch (ConfigurateException exception) { + handleException(player, exception, "saving the wrap file"); + } + } + + private void handleException(Player player, ConfigurateException exception, String action) { + plugin.getMessageHandler().send(player, Messages.COMMAND_CREATE_FAILED); + plugin.getLogger().severe("An error occurred while " + action + "! Please report this to the developers."); + exception.printStackTrace(); + } + + private int getUnusedId(Map wraps) { + int id = wraps.size(); + while (wraps.containsKey(String.valueOf(id))) { + id++; + } + return id; + } + + private String getHookId(ItemStack item) { + if (Bukkit.getPluginManager().isPluginEnabled("ItemsAdder") && CustomStack.byItemStack(item) != null) { + return "itemsadder:" + CustomStack.byItemStack(item).getNamespacedID(); + } + if (Bukkit.getPluginManager().isPluginEnabled("Oraxen") && OraxenItems.getIdByItem(item) != null) { + return "oraxen:" + OraxenItems.getIdByItem(item); + } + if (Bukkit.getPluginManager().isPluginEnabled("MythicMobs") && MythicBukkit.inst().getItemManager().getMythicTypeFromItem(item) != null) { + return "mythic:" + MythicBukkit.inst().getItemManager().getMythicTypeFromItem(item); + } + var meta = item.getItemMeta(); + return String.valueOf(meta.hasCustomModelData() ? meta.getCustomModelData() : -1); + } + @Subcommand("help") @Description("Shows the help page.") public void onHelp(CommandSender sender, CommandHelp helpEntries) { plugin.getMessageHandler().send(sender, Messages.COMMAND_HELP_HEADER); - Supplier> filteredEntries = () -> helpEntries.paginate(1, 100).stream().filter(string -> !string.equals("")); + Supplier> filteredEntries = () -> helpEntries.paginate(1, 100).stream().filter(string -> !string.isEmpty()); if (filteredEntries.get().findAny().isEmpty()) { plugin.getMessageHandler().send(sender, Messages.COMMAND_HELP_NO_PERMISSION); } else { diff --git a/src/main/java/de/skyslycer/hmcwraps/converter/FileConverter.java b/src/main/java/de/skyslycer/hmcwraps/converter/FileConverter.java index 46eca87..8f9c23b 100644 --- a/src/main/java/de/skyslycer/hmcwraps/converter/FileConverter.java +++ b/src/main/java/de/skyslycer/hmcwraps/converter/FileConverter.java @@ -11,6 +11,7 @@ import org.spongepowered.configurate.BasicConfigurationNode; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationOptions; +import org.spongepowered.configurate.yaml.NodeStyle; import org.spongepowered.configurate.yaml.YamlConfigurationLoader; import java.nio.file.Files; @@ -61,6 +62,7 @@ public boolean convertAll() { YamlConfigurationLoader.builder() .defaultOptions(ConfigurationOptions.defaults().implicitInitialization(false)) .path(filePath).indent(2) + .nodeStyle(NodeStyle.BLOCK) .build().save(BasicConfigurationNode.factory().createNode().set(entry.getValue())); } catch (Exception exception) { plugin.getLogger().warning("Could not save generated wrap file! Please report this.\n" @@ -78,6 +80,7 @@ public boolean convertAll() { YamlConfigurationLoader.builder() .defaultOptions(ConfigurationOptions.defaults().implicitInitialization(false)) .path(filePath).indent(2) + .nodeStyle(NodeStyle.BLOCK) .build().save(BasicConfigurationNode.factory().createNode().set(new CollectionFile(collections, true))); } catch (Exception exception) { plugin.getLogger().warning("Could not save generated collection file! Please report this.\n" @@ -89,7 +92,7 @@ public boolean convertAll() { return success; } - public FolderConstruct loadFolder(Path path, Map> collections) throws Exception { + FolderConstruct loadFolder(Path path, Map> collections) throws Exception { var file = path.toFile(); if (!file.exists() || !file.isDirectory()) { return null; @@ -110,9 +113,9 @@ public FolderConstruct loadFolder(Path path, Map> collectio .filter(entry -> new HashSet<>(entry.getValue()).containsAll(construct.materials)).toList(); var matchingGeneratedCollections = newCollections.entrySet().stream() .filter(entry -> new HashSet<>(entry.getValue()).containsAll(construct.materials)).toList(); - if (matchingCollections.size() >= 1) { + if (!matchingCollections.isEmpty()) { material = matchingCollections.stream().findFirst().get().getKey(); - } else if (matchingGeneratedCollections.size() >= 1) { + } else if (!matchingGeneratedCollections.isEmpty()) { material = matchingGeneratedCollections.stream().findFirst().get().getKey(); } else { var i = 1; @@ -139,7 +142,7 @@ public FolderConstruct loadFolder(Path path, Map> collectio } } - public ConvertConstruct convert(Path path) throws ConfigurateException { + ConvertConstruct convert(Path path) throws ConfigurateException { var file = path.toFile(); if (!file.exists() || file.isDirectory()) { return null; @@ -158,7 +161,7 @@ public ConvertConstruct convert(Path path) throws ConfigurateException { physical = new PhysicalWrap( itemSkinsPhysical.getMaterial(), StringUtil.legacyToMiniMessage(itemSkinsPhysical.getDisplayName()), itemSkinsPhysical.getGlowing(), itemSkinsPhysical.getLore() != null ? itemSkinsPhysical.getLore().stream().map(StringUtil::legacyToMiniMessage).toList() : null, - null, itemSkinsPhysical.getCustomModelData(), null, null, null, true); + null, itemSkinsPhysical.getCustomModelData(), null, null, null, true, null); } SerializableItem lockedItem = null; if (itemSkinsFile.getUnavailableItem() != null) { @@ -166,9 +169,9 @@ public ConvertConstruct convert(Path path) throws ConfigurateException { lockedItem = unavailableItem.toItem(); } var wrap = new Wrap( - itemSkinsItem.getMaterial(), StringUtil.legacyToMiniMessage(itemSkinsItem.getDisplayName()), itemSkinsItem.getGlowing(), + String.valueOf(itemSkinsFile.getCustomModelData()), StringUtil.legacyToMiniMessage(itemSkinsItem.getDisplayName()), itemSkinsItem.getGlowing(), itemSkinsItem.getLore() != null ? itemSkinsItem.getLore().stream().map(StringUtil::legacyToMiniMessage).toList() : null, - itemSkinsFile.getCustomModelData(), file.getName().replace(".yml", ""), physical, itemSkinsFile.getPermission(), lockedItem); + null, file.getName().replace(".yml", ""), physical, itemSkinsFile.getPermission(), lockedItem); return new ConvertConstruct(wrap, itemSkinsFile.getMaterial().stream().map(String::toUpperCase).toList()); } diff --git a/src/main/java/de/skyslycer/hmcwraps/converter/ItemSkinsFile.java b/src/main/java/de/skyslycer/hmcwraps/converter/ItemSkinsFile.java index a3bda4e..3eae457 100644 --- a/src/main/java/de/skyslycer/hmcwraps/converter/ItemSkinsFile.java +++ b/src/main/java/de/skyslycer/hmcwraps/converter/ItemSkinsFile.java @@ -76,7 +76,7 @@ public List getLore() { } public SerializableItem toItem() { - return new SerializableItem(material, displayName, glowing, lore, null, customModelData, null, 1, null); + return new SerializableItem(material, displayName, glowing, lore, null, customModelData, null, 1, null, null, null); } } diff --git a/src/main/java/de/skyslycer/hmcwraps/debug/DebugCreator.java b/src/main/java/de/skyslycer/hmcwraps/debug/DebugCreator.java index f911203..b966ca9 100644 --- a/src/main/java/de/skyslycer/hmcwraps/debug/DebugCreator.java +++ b/src/main/java/de/skyslycer/hmcwraps/debug/DebugCreator.java @@ -4,7 +4,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; import de.skyslycer.hmcwraps.HMCWrapsPlugin; -import de.skyslycer.hmcwraps.serialization.Config; import de.skyslycer.hmcwraps.serialization.debug.*; import de.skyslycer.hmcwraps.serialization.wrap.Wrap; import gs.mclo.java.MclogsAPI; @@ -26,7 +25,7 @@ public class DebugCreator { private static final String DEBUG_URL = "https://paste.skyslycer.de/%s"; public static DebugConfig createDebugConfig(HMCWrapsPlugin plugin) { - return new DebugConfig((Config) plugin.getConfiguration()); + return new DebugConfig(plugin.getConfiguration()); } public static DebugInformation createDebugInformation(HMCWrapsPlugin plugin) { @@ -67,7 +66,9 @@ public static DebugItemData createDebugItemData(HMCWrapsPlugin plugin, Player pl wrapper.getOwningPlayer(item), wrapper.isPhysicalUnwrapper(item), wrapper.getPhysicalWrapper(item), - wrapper.getOriginalData(item) + wrapper.getOriginalData(item), + wrapper.getFakeDurability(item), + wrapper.getFakeMaxDurability(item) ); } diff --git a/src/main/java/de/skyslycer/hmcwraps/gui/GuiBuilder.java b/src/main/java/de/skyslycer/hmcwraps/gui/GuiBuilder.java index 89713b8..a8b8eba 100644 --- a/src/main/java/de/skyslycer/hmcwraps/gui/GuiBuilder.java +++ b/src/main/java/de/skyslycer/hmcwraps/gui/GuiBuilder.java @@ -4,7 +4,9 @@ import de.skyslycer.hmcwraps.actions.information.ActionInformation; import de.skyslycer.hmcwraps.actions.information.GuiActionInformation; import de.skyslycer.hmcwraps.actions.information.WrapGuiActionInformation; +import de.skyslycer.hmcwraps.messages.Messages; import de.skyslycer.hmcwraps.serialization.inventory.Inventory; +import de.skyslycer.hmcwraps.util.MaterialUtil; import de.skyslycer.hmcwraps.util.StringUtil; import dev.triumphteam.gui.components.ScrollType; import dev.triumphteam.gui.guis.Gui; @@ -22,7 +24,7 @@ public class GuiBuilder { - public static void open(HMCWrapsPlugin plugin, Player player, ItemStack item) { + public static void open(HMCWrapsPlugin plugin, Player player, ItemStack item, int slot) { plugin.getPreviewManager().remove(player.getUniqueId(), false); var inventory = plugin.getConfiguration().getInventory(); @@ -39,14 +41,31 @@ public static void open(HMCWrapsPlugin plugin, Player player, ItemStack item) { .create(); } - populate(plugin, item, player, gui); - populateStatic(plugin, player, inventory, gui); + populate(plugin, item, player, gui, slot); + populateStatic(plugin, player, inventory, gui, slot); setItemToSlot(gui, plugin, item); - gui.setDefaultClickAction(click -> click.setCancelled(true)); + gui.setDefaultClickAction(click -> { + click.setCancelled(true); + if (click.getClickedInventory() == player.getInventory()) { + var clicked = click.getCurrentItem(); + if (clicked == null || clicked.getType().isAir()) { + return; + } + var type = clicked.getType(); + if (plugin.getWrapper().getWrap(clicked) != null && !plugin.getWrapper().getOriginalData(clicked).material().isEmpty()) { + type = Material.valueOf(plugin.getWrapper().getOriginalData(clicked).material()); + } + if (plugin.getCollectionHelper().getItems(type).isEmpty()) { + plugin.getMessageHandler().send(player, Messages.NO_WRAPS); + return; + } + GuiBuilder.open(plugin, player, click.getCurrentItem(), click.getSlot()); + } + }); gui.open(player); } - private static void populateStatic(HMCWrapsPlugin plugin, Player player, Inventory inventory, PaginatedGui gui) { + private static void populateStatic(HMCWrapsPlugin plugin, Player player, Inventory inventory, PaginatedGui gui, int slot) { inventory.getItems().forEach((inventorySlot, serializableItem) -> { var fills = new ArrayList(); fills.add(inventorySlot); @@ -60,7 +79,7 @@ private static void populateStatic(HMCWrapsPlugin plugin, Player player, Invento ItemStack stack = serializableItem.toItem(plugin, player); GuiItem guiItem = new GuiItem(stack); if (serializableItem.getActions() != null) { - guiItem.setAction(event -> actions(plugin, new GuiActionInformation(player, "", gui), serializableItem.getActions(), event)); + guiItem.setAction(event -> actions(plugin, new GuiActionInformation(player, "", gui, slot), serializableItem.getActions(), event)); } gui.setItem(fills, guiItem); }); @@ -74,14 +93,12 @@ private static void actions(HMCWrapsPlugin plugin, ActionInformation information } else if (event.getClick() == ClickType.MIDDLE && actions.containsKey("middle")) { plugin.getActionHandler().pushFromConfig(actions.get("middle"), information); } - if (event.getClick() == ClickType.LEFT && actions.containsKey("left-shift") && information.getPlayer().isSneaking()) { + if (event.getClick() == ClickType.SHIFT_LEFT && actions.containsKey("left-shift")) { plugin.getActionHandler().pushFromConfig(actions.get("left-shift"), information); - } else if (event.getClick() == ClickType.RIGHT && actions.containsKey("right-shift") && information.getPlayer().isSneaking()) { + } else if (event.getClick() == ClickType.SHIFT_RIGHT && actions.containsKey("right-shift")) { plugin.getActionHandler().pushFromConfig(actions.get("right-shift"), information); - } else if (event.getClick() == ClickType.MIDDLE && actions.containsKey("middle-shift") && information.getPlayer().isSneaking()) { - plugin.getActionHandler().pushFromConfig(actions.get("middle-shift"), information); } - if (actions.containsKey("any-shift") && information.getPlayer().isSneaking()) { + if (actions.containsKey("any-shift") && event.getClick().toString().contains("SHIFT")) { plugin.getActionHandler().pushFromConfig(actions.get("any-shift"), information); } if (actions.containsKey("any")) { @@ -89,19 +106,20 @@ private static void actions(HMCWrapsPlugin plugin, ActionInformation information } } - private static void populate(HMCWrapsPlugin plugin, ItemStack item, Player player, PaginatedGui gui) { - plugin.getCollectionHelper().getItems(item.getType()).forEach(it -> it.getWraps() + private static void populate(HMCWrapsPlugin plugin, ItemStack item, Player player, PaginatedGui gui, int slot) { + var type = item.getType(); + if (plugin.getWrapper().getWrap(item) != null && !plugin.getWrapper().getOriginalData(item).material().isEmpty()) { + type = Material.valueOf(plugin.getWrapper().getOriginalData(item).material()); + } + var finalType = type; // Why :( + plugin.getCollectionHelper().getItems(type).forEach(it -> it.getWraps() .values().stream().filter(wrap -> plugin.getWrapper().isValid(item, wrap)) .filter(wrap -> !plugin.getFilterStorage().get(player) || wrap.hasPermission(player)).forEach(wrap -> { - var wrapItem = wrap.toPermissionItem(plugin, player); - if (!plugin.getConfiguration().getPermissions().isPermissionVirtual() || wrap.hasPermission(player) || wrap.getLockedItem() == null) { - wrapItem.setType(item.getType()); - } - + var wrapItem = wrap.toPermissionItem(plugin, wrap.isArmorImitationEnabled() ? MaterialUtil.getLeatherAlternative(item.getType()) : finalType, player); var guiItem = new GuiItem(wrapItem); guiItem.setAction(click -> { if (plugin.getConfiguration().getInventory().getActions() != null) { - actions(plugin, new WrapGuiActionInformation(gui, wrap, player, ""), plugin.getConfiguration().getInventory().getActions(), click); + actions(plugin, new WrapGuiActionInformation(gui, wrap, player, slot, ""), plugin.getConfiguration().getInventory().getActions(), click); } }); gui.addItem(guiItem); diff --git a/src/main/java/de/skyslycer/hmcwraps/listener/DurabilityChangeListener.java b/src/main/java/de/skyslycer/hmcwraps/listener/DurabilityChangeListener.java new file mode 100644 index 0000000..725132e --- /dev/null +++ b/src/main/java/de/skyslycer/hmcwraps/listener/DurabilityChangeListener.java @@ -0,0 +1,52 @@ +package de.skyslycer.hmcwraps.listener; + +import de.skyslycer.hmcwraps.HMCWrapsPlugin; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerItemDamageEvent; +import org.bukkit.event.player.PlayerItemMendEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; + +public class DurabilityChangeListener implements Listener { + + private final HMCWrapsPlugin plugin; + + public DurabilityChangeListener(HMCWrapsPlugin plugin) { + this.plugin = plugin; + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onItemDamage(PlayerItemDamageEvent event) { + var item = event.getItem(); + updateDurability(item, -event.getDamage()); + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onItemMend(PlayerItemMendEvent event) { + var item = event.getItem(); + updateDurability(item, event.getRepairAmount()); + } + + private void updateDurability(ItemStack item, int changed) { + var durability = plugin.getWrapper().getFakeDurability(item); + var maxDurability = plugin.getWrapper().getFakeMaxDurability(item); + if (plugin.getWrapper().getWrap(item) == null || plugin.getWrapper().getFakeDurability(item) == -1 || durability == -1) { + return; + } + var newDurability = Math.min(durability + changed, maxDurability); + var modelDurability = ((double) newDurability / maxDurability) * item.getType().getMaxDurability(); + if (modelDurability == 0 && newDurability > 0) { + modelDurability = 1; + } + plugin.getWrapper().setFakeDurability(item, newDurability); + var meta = (Damageable) item.getItemMeta(); + meta.setDamage(item.getType().getMaxDurability() - (int) modelDurability); + item.setItemMeta(meta); + if (newDurability <= 0) { + item.setAmount(0); + } + } + +} diff --git a/src/main/java/de/skyslycer/hmcwraps/listener/InventoryClickListener.java b/src/main/java/de/skyslycer/hmcwraps/listener/InventoryClickListener.java index f4bb0d6..0133df6 100644 --- a/src/main/java/de/skyslycer/hmcwraps/listener/InventoryClickListener.java +++ b/src/main/java/de/skyslycer/hmcwraps/listener/InventoryClickListener.java @@ -1,16 +1,32 @@ package de.skyslycer.hmcwraps.listener; import de.skyslycer.hmcwraps.HMCWrapsPlugin; +import de.skyslycer.hmcwraps.messages.Messages; +import de.skyslycer.hmcwraps.serialization.preview.PreviewType; import de.skyslycer.hmcwraps.serialization.wrap.WrappableItem; import de.skyslycer.hmcwraps.util.PermissionUtil; import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.ItemStack; + +import java.util.List; public class InventoryClickListener implements Listener { + private static final List FORBIDDEN_INVENTORIES = List.of( + InventoryType.ANVIL, + InventoryType.WORKBENCH, + InventoryType.ENCHANTING, + InventoryType.GRINDSTONE, + InventoryType.SMITHING + ); + private final HMCWrapsPlugin plugin; public InventoryClickListener(HMCWrapsPlugin plugin) { @@ -21,15 +37,48 @@ public InventoryClickListener(HMCWrapsPlugin plugin) { public void onInventoryClick(InventoryClickEvent event) { var player = (Player) event.getWhoClicked(); - if (event.getClickedInventory() != player.getInventory()) { + if (isForbiddenInventory(event) && (isImitatedArmor(event.getCursor()) || isImitatedArmor(event.getCurrentItem()) + || isFakeDurability(event.getCursor()) || isFakeDurability(event.getCurrentItem()))) { + event.setCancelled(true); + plugin.getMessageHandler().send(player, Messages.ARMOR_IMITATION_FORBIDDEN_INVENTORY); return; } + // Avoid possible issues such as client server inventory desync when moving a desynced inventory + if (plugin.getPreviewManager().isPreviewing(player) && plugin.getConfiguration().getPreview().getType() == PreviewType.HAND) { + plugin.getPreviewManager().remove(player.getUniqueId(), false); + event.setCancelled(true); + return; + } switch (event.getAction()) { - case PLACE_ALL, PLACE_SOME, PLACE_ONE -> { + case PLACE_ALL, PLACE_SOME, PLACE_ONE, SWAP_WITH_CURSOR -> { var slot = event.getRawSlot(); - Bukkit.getScheduler().runTaskLater(plugin, () -> player.getInventory().setItem(slot, PermissionUtil.check(plugin, player, player.getInventory().getItem(slot))), 1); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + var updatedItem = PermissionUtil.check(plugin, player, event.getView().getItem(slot)); + if (updatedItem == null || updatedItem.equals(event.getView().getItem(slot))) return; + event.getView().setItem(slot, updatedItem); + }, 1); } + case MOVE_TO_OTHER_INVENTORY -> Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (event.getClickedInventory() == player.getInventory()) { + PermissionUtil.loopThroughInventory(plugin, player, player.getOpenInventory().getTopInventory()); + } else { + PermissionUtil.loopThroughInventory(plugin, player, player.getOpenInventory().getBottomInventory()); + } + }, 1); + } + + if (event.getClick() == ClickType.NUMBER_KEY) { + var slot = event.getHotbarButton(); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + var updatedItem = PermissionUtil.check(plugin, player, player.getInventory().getItem(slot)); + if (updatedItem == null || updatedItem.equals(event.getView().getItem(slot))) return; + player.getInventory().setItem(slot, updatedItem); + }, 1); + } + + if (event.getClickedInventory() != player.getInventory()) { + return; } if (event.getCursor() == null || event.getCurrentItem() == null || event.getCurrentItem().getItemMeta() == null) { @@ -55,6 +104,10 @@ public void onInventoryClick(InventoryClickEvent event) { return; } + if (plugin.getWrapper().isGloballyDisabled(target)) { + return; + } + var wrapId = plugin.getWrapper().getPhysicalWrapper(physical); if (wrapId == null) { return; @@ -64,13 +117,21 @@ public void onInventoryClick(InventoryClickEvent event) { if (wrap == null) { return; } + var finalCursor = cursor; + var type = target.getType(); + if (plugin.getWrapper().getWrap(target) != null && !plugin.getWrapper().getOriginalData(target).material().isEmpty()) { + type = Material.valueOf(plugin.getWrapper().getOriginalData(target).material()); + } if (wrap.getPhysical() != null && (wrap.hasPermission(player) || !plugin.getConfiguration().getPermissions() .isPermissionPhysical())) { - for (WrappableItem wrappableItem : plugin.getCollectionHelper().getItems(target.getType())) { + for (WrappableItem wrappableItem : plugin.getCollectionHelper().getItems(type)) { if (wrappableItem.getWraps().containsValue(wrap)) { - event.setCurrentItem(plugin.getWrapper().setWrap(wrap, target, true, - player, true)); + if (!plugin.getConfiguration().getWrapping().getRewrap().isPhysicalEnabled() && plugin.getWrapper().getWrap(target) != null) { + plugin.getMessageHandler().send(player, Messages.NO_REWRAP); + return; + } + event.setCurrentItem(plugin.getWrapper().setWrap(wrap, target, true, player, true)); plugin.getActionHandler().pushWrap(wrap, player); plugin.getActionHandler().pushPhysicalWrap(wrap, player); event.getWhoClicked().setItemOnCursor(finalCursor); @@ -81,4 +142,16 @@ public void onInventoryClick(InventoryClickEvent event) { } } + private boolean isImitatedArmor(ItemStack item) { + return item != null && !item.getType().isAir() && !plugin.getWrapper().getOriginalData(item).material().isBlank(); + } + + private boolean isFakeDurability(ItemStack item) { + return item != null && !item.getType().isAir() && plugin.getWrapper().getFakeDurability(item) != -1; + } + + private boolean isForbiddenInventory(InventoryClickEvent event) { + return FORBIDDEN_INVENTORIES.contains(event.getWhoClicked().getOpenInventory().getType()) || (event.getClickedInventory() != null && event.getClickedInventory().getType() == InventoryType.CRAFTING); + } + } diff --git a/src/main/java/de/skyslycer/hmcwraps/listener/ItemBurnListener.java b/src/main/java/de/skyslycer/hmcwraps/listener/ItemBurnListener.java new file mode 100644 index 0000000..c6616a6 --- /dev/null +++ b/src/main/java/de/skyslycer/hmcwraps/listener/ItemBurnListener.java @@ -0,0 +1,44 @@ +package de.skyslycer.hmcwraps.listener; + +import de.skyslycer.hmcwraps.HMCWrapsPlugin; +import org.bukkit.entity.Item; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDamageEvent; + +public class ItemBurnListener implements Listener { + + private final HMCWrapsPlugin plugin; + + public ItemBurnListener(HMCWrapsPlugin plugin) { + this.plugin = plugin; + } + + @EventHandler(priority = EventPriority.HIGH) + public void onItemBurn(EntityCombustEvent event) { + if (!(event.getEntity() instanceof Item item)) { + return; + } + var originalData = plugin.getWrapper().getOriginalData(item.getItemStack()); + if (plugin.getWrapper().getWrap(item.getItemStack()) != null && originalData != null && !originalData.material().isBlank() && originalData.material().contains("NETHERITE")) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void onEntityBurn(EntityDamageEvent event) { + if (!(event.getEntity() instanceof Item item)) { + return; + } + if (event.getCause() != EntityDamageEvent.DamageCause.FIRE && event.getCause() != EntityDamageEvent.DamageCause.LAVA) { + return; + } + var originalData = plugin.getWrapper().getOriginalData(item.getItemStack()); + if (plugin.getWrapper().getWrap(item.getItemStack()) != null && originalData != null && !originalData.material().isBlank() && originalData.material().contains("NETHERITE")) { + event.setCancelled(true); + } + } + +} diff --git a/src/main/java/de/skyslycer/hmcwraps/listener/PlayerDropListener.java b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerDropListener.java index 89c99b0..b2ee2db 100644 --- a/src/main/java/de/skyslycer/hmcwraps/listener/PlayerDropListener.java +++ b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerDropListener.java @@ -2,10 +2,9 @@ import de.skyslycer.hmcwraps.HMCWrapsPlugin; import de.skyslycer.hmcwraps.util.PermissionUtil; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDropItemEvent; +import org.bukkit.event.player.PlayerDropItemEvent; public class PlayerDropListener implements Listener { @@ -16,11 +15,11 @@ public PlayerDropListener(HMCWrapsPlugin plugin) { } @EventHandler - public void onItemDrop(EntityDropItemEvent event) { - if (!(event.getEntity() instanceof Player)) { - return; + public void onItemDrop(PlayerDropItemEvent event) { + if (plugin.getPreviewManager().isPreviewing(event.getPlayer())) { + plugin.getPreviewManager().remove(event.getPlayer().getUniqueId(), false); } - var result = PermissionUtil.hasPermission(plugin, event.getItemDrop().getItemStack(), ((Player) event.getEntity()).getPlayer()); + var result = PermissionUtil.hasPermission(plugin, event.getItemDrop().getItemStack(), event.getPlayer()); if (result != null) { event.getItemDrop().setItemStack(result); } diff --git a/src/main/java/de/skyslycer/hmcwraps/listener/PlayerHitEntityListener.java b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerHitEntityListener.java new file mode 100644 index 0000000..29149e6 --- /dev/null +++ b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerHitEntityListener.java @@ -0,0 +1,44 @@ +package de.skyslycer.hmcwraps.listener; + +import de.skyslycer.hmcwraps.HMCWrapsPlugin; +import de.skyslycer.hmcwraps.actions.information.WrapActionInformation; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; + +public class PlayerHitEntityListener implements Listener { + + private final HMCWrapsPlugin plugin; + + public PlayerHitEntityListener(HMCWrapsPlugin plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onHit(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player player)) { + return; + } + if (plugin.getPreviewManager().isPreviewing(player)) { + plugin.getPreviewManager().remove(player.getUniqueId(), false); + } + var weapon = player.getInventory().getItemInMainHand(); + if (weapon == null || weapon.getType().isAir()) { + return; + } + var wrap = plugin.getWrapper().getWrap(weapon); + if (wrap == null || wrap.getActions() == null) { + return; + } + if (wrap.getActions().get("hit-any") != null) { + plugin.getActionHandler().pushFromConfig(wrap.getActions().get("hit-any"), new WrapActionInformation(wrap, player, "")); + } + if (event.getEntity() instanceof Player && wrap.getActions().get("hit-player") != null) { + plugin.getActionHandler().pushFromConfig(wrap.getActions().get("hit-player"), new WrapActionInformation(wrap, player, "")); + } else if (wrap.getActions().get("hit-entity") != null) { + plugin.getActionHandler().pushFromConfig(wrap.getActions().get("hit-entity"), new WrapActionInformation(wrap, player, "")); + } + } + +} diff --git a/src/main/java/de/skyslycer/hmcwraps/listener/PlayerInteractListener.java b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerInteractListener.java index cf373e5..cf02c14 100644 --- a/src/main/java/de/skyslycer/hmcwraps/listener/PlayerInteractListener.java +++ b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerInteractListener.java @@ -24,6 +24,9 @@ public PlayerInteractListener(HMCWrapsPlugin plugin) { @EventHandler public void onInteract(PlayerInteractEvent event) { var player = event.getPlayer(); + if (event.getAction() == Action.LEFT_CLICK_BLOCK && plugin.getPreviewManager().isPreviewing(player)) { + plugin.getPreviewManager().remove(player.getUniqueId(), false); + } if (player.getInventory().getItemInMainHand().getType().isAir()) { return; } @@ -37,18 +40,26 @@ public void onInteract(PlayerInteractEvent event) { } } + if (plugin.getWrapper().isGloballyDisabled(newItem)) { + return; + } + var excludes = plugin.getConfiguration().getInventory().getShortcut().getExclude(); + var type = newItem.getType(); + if (plugin.getWrapper().getWrap(newItem) != null && !plugin.getWrapper().getOriginalData(newItem).material().isEmpty()) { + type = Material.valueOf(plugin.getWrapper().getOriginalData(newItem).material()); + } if (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK - || plugin.getCollectionHelper().getItems(newItem.getType()).isEmpty() || !player.isSneaking() + || plugin.getCollectionHelper().getItems(type).isEmpty() || !player.isSneaking() || !plugin.getConfiguration().getInventory().getShortcut().isEnabled() - || ListUtil.containsAny(List.of(newItem.getType().toString(), + || ListUtil.containsAny(List.of(type.toString(), player.getInventory().getItemInOffHand().getType().toString()), excludes) || (plugin.getConfiguration().getPermissions().isInventoryPermission() && !player.hasPermission(WrapCommand.WRAPS_PERMISSION))) { return; } event.setCancelled(true); - GuiBuilder.open(plugin, player, newItem); + GuiBuilder.open(plugin, player, newItem, player.getInventory().getHeldItemSlot()); } } diff --git a/src/main/java/de/skyslycer/hmcwraps/listener/PlayerJoinListener.java b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerJoinListener.java index 75d3f51..d33ae31 100644 --- a/src/main/java/de/skyslycer/hmcwraps/listener/PlayerJoinListener.java +++ b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerJoinListener.java @@ -17,7 +17,7 @@ public PlayerJoinListener(HMCWrapsPlugin plugin) { @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { - Bukkit.getScheduler().runTaskLater(plugin, () -> PermissionUtil.loopThroughInventory(plugin, event.getPlayer()), 1); + Bukkit.getScheduler().runTaskLater(plugin, () -> PermissionUtil.loopThroughInventory(plugin, event.getPlayer(), event.getPlayer().getInventory()), 1); Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> plugin.getUpdateChecker().checkPlayer(event.getPlayer()), 5); } diff --git a/src/main/java/de/skyslycer/hmcwraps/listener/PlayerOffHandSwitchListener.java b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerOffHandSwitchListener.java new file mode 100644 index 0000000..6fd2bde --- /dev/null +++ b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerOffHandSwitchListener.java @@ -0,0 +1,29 @@ +package de.skyslycer.hmcwraps.listener; + +import de.skyslycer.hmcwraps.HMCWraps; +import de.skyslycer.hmcwraps.util.PermissionUtil; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerSwapHandItemsEvent; + +public class PlayerOffHandSwitchListener implements Listener { + + private final HMCWraps plugin; + + public PlayerOffHandSwitchListener(HMCWraps plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onSwitch(PlayerSwapHandItemsEvent event) { + var offHand = PermissionUtil.hasPermission(plugin, event.getOffHandItem(), event.getPlayer()); + var mainHand = PermissionUtil.hasPermission(plugin, event.getMainHandItem(), event.getPlayer()); + if (offHand != null) { + event.setOffHandItem(offHand); + } + if (mainHand != null) { + event.setMainHandItem(mainHand); + } + } + +} diff --git a/src/main/java/de/skyslycer/hmcwraps/listener/PlayerPickupListener.java b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerPickupListener.java index 6e6298f..50b2303 100644 --- a/src/main/java/de/skyslycer/hmcwraps/listener/PlayerPickupListener.java +++ b/src/main/java/de/skyslycer/hmcwraps/listener/PlayerPickupListener.java @@ -21,7 +21,7 @@ public void onItemPickup(EntityPickupItemEvent event) { if (!(event.getEntity() instanceof Player player)) { return; } - Bukkit.getScheduler().runTaskLater(plugin, () -> PermissionUtil.loopThroughInventory(plugin, player), 1L); + Bukkit.getScheduler().runTaskLater(plugin, () -> PermissionUtil.loopThroughInventory(plugin, player, player.getInventory()), 1L); } } diff --git a/src/main/java/de/skyslycer/hmcwraps/serialization/debug/DebugConfig.java b/src/main/java/de/skyslycer/hmcwraps/serialization/debug/DebugConfig.java index def31e0..d38c0fa 100644 --- a/src/main/java/de/skyslycer/hmcwraps/serialization/debug/DebugConfig.java +++ b/src/main/java/de/skyslycer/hmcwraps/serialization/debug/DebugConfig.java @@ -6,7 +6,7 @@ public class DebugConfig extends Config implements Debuggable { public DebugConfig(Config config) { super(config.getUpdater(), config.getPermissions(), config.getPreview(), config.getFavorites(), config.getInventory(), config.getUnwrapper(), - config.getPreservation(), null, null, config.getFilter()); + config.getPreservation(), null, null, config.getFilter(), config.getWrapping()); } } diff --git a/src/main/java/de/skyslycer/hmcwraps/serialization/debug/DebugItemData.java b/src/main/java/de/skyslycer/hmcwraps/serialization/debug/DebugItemData.java index 6d9530b..841bc3e 100644 --- a/src/main/java/de/skyslycer/hmcwraps/serialization/debug/DebugItemData.java +++ b/src/main/java/de/skyslycer/hmcwraps/serialization/debug/DebugItemData.java @@ -12,14 +12,18 @@ public class DebugItemData implements Debuggable { private boolean physicalUnwrapper; private String physicalWrapper; private Wrap.WrapValues wrapValues; + private int fakeDurability; + private int fakeMaxDurability; - public DebugItemData(boolean physical, String wrap, UUID owningPlayer, boolean physicalUnwrapper, String physicalWrapper, Wrap.WrapValues wrapValues) { + public DebugItemData(boolean physical, String wrap, UUID owningPlayer, boolean physicalUnwrapper, String physicalWrapper, Wrap.WrapValues wrapValues, int fakeDurability, int fakeMaxDurability) { this.physical = physical; this.wrap = wrap; this.owningPlayer = owningPlayer; this.physicalUnwrapper = physicalUnwrapper; this.physicalWrapper = physicalWrapper; this.wrapValues = (Wrap.WrapValues) wrapValues; + this.fakeDurability = fakeDurability; + this.fakeMaxDurability = fakeMaxDurability; } } diff --git a/src/main/java/de/skyslycer/hmcwraps/storage/PlayerFilterStorage.java b/src/main/java/de/skyslycer/hmcwraps/storage/PlayerFilterStorage.java index eb37bc2..39b9a19 100644 --- a/src/main/java/de/skyslycer/hmcwraps/storage/PlayerFilterStorage.java +++ b/src/main/java/de/skyslycer/hmcwraps/storage/PlayerFilterStorage.java @@ -18,10 +18,10 @@ public PlayerFilterStorage(HMCWrapsPlugin plugin) { @Override public Boolean get(Player source) { - var pdc = source.getPersistentDataContainer().get(key, PersistentDataType.BYTE); if (!plugin.getConfiguration().getFilter().isEnabled()) { return false; } + var pdc = source.getPersistentDataContainer().get(key, PersistentDataType.BYTE); if (pdc == null) { return plugin.getConfiguration().getFilter().getDefault(); } diff --git a/src/main/java/de/skyslycer/hmcwraps/transformation/ConfigFileTransformations.java b/src/main/java/de/skyslycer/hmcwraps/transformation/ConfigFileTransformations.java new file mode 100644 index 0000000..270f68c --- /dev/null +++ b/src/main/java/de/skyslycer/hmcwraps/transformation/ConfigFileTransformations.java @@ -0,0 +1,22 @@ +package de.skyslycer.hmcwraps.transformation; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class ConfigFileTransformations extends FileTransformations { + + public ConfigFileTransformations() { + setLatest(1); + addUpdateMethod(0, this::zeroToOne); + } + + private void zeroToOne(Path path) throws IOException { + var config = Files.readString(path); + config = config.replace(" nbt: ", " wrap-nbt: "); + config = config.replace("permission-settings:", "permissions:"); + config = config + "\nconfig: 1"; + Files.writeString(path, config); + } + +} diff --git a/src/main/java/de/skyslycer/hmcwraps/transformation/FileTransformations.java b/src/main/java/de/skyslycer/hmcwraps/transformation/FileTransformations.java new file mode 100644 index 0000000..5bf07bd --- /dev/null +++ b/src/main/java/de/skyslycer/hmcwraps/transformation/FileTransformations.java @@ -0,0 +1,55 @@ +package de.skyslycer.hmcwraps.transformation; + +import org.bukkit.Bukkit; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +public class FileTransformations { + + private static final Pattern VERSION_PATTERN = Pattern.compile("config: (?\\d)"); + + private int latest = -1; + private final Map updateMethods = new HashMap<>(); + + @FunctionalInterface + protected interface UpdateMethod { + void update(Path path) throws IOException; + } + + private int getConfigVersion(Path path) throws IOException { + var config = Files.readString(path); + var matcher = VERSION_PATTERN.matcher(config); + if (matcher.find()) { + return Integer.parseInt(matcher.group("ver")); + } else { + return 0; + } + } + + public void updateToLatest(Path path) throws IOException { + var currentVersion = getConfigVersion(path); + while (currentVersion < latest) { + var method = updateMethods.get(currentVersion); + if (method != null) { + method.update(path); + currentVersion = getConfigVersion(path); + } else { + Bukkit.getLogger().severe("Could not find update method for config version " + currentVersion + "! Please report this to the developers!"); + } + } + } + + protected void addUpdateMethod(int version, UpdateMethod method) { + updateMethods.put(version, method); + } + + protected void setLatest(int latest) { + this.latest = latest; + } + +} diff --git a/src/main/java/de/skyslycer/hmcwraps/transformation/WrapFileTransformations.java b/src/main/java/de/skyslycer/hmcwraps/transformation/WrapFileTransformations.java new file mode 100644 index 0000000..987c165 --- /dev/null +++ b/src/main/java/de/skyslycer/hmcwraps/transformation/WrapFileTransformations.java @@ -0,0 +1,21 @@ +package de.skyslycer.hmcwraps.transformation; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class WrapFileTransformations extends FileTransformations { + + public WrapFileTransformations() { + setLatest(1); + addUpdateMethod(0, this::zeroToOne); + } + + private void zeroToOne(Path path) throws IOException { + var config = Files.readString(path); + config = config.replace(" nbt: ", " wrap-nbt: "); + config = config + "\nconfig: 1"; + Files.writeString(path, config); + } + +} diff --git a/src/main/java/de/skyslycer/hmcwraps/wrap/ArmorModifiers.java b/src/main/java/de/skyslycer/hmcwraps/wrap/ArmorModifiers.java new file mode 100644 index 0000000..caaaf8b --- /dev/null +++ b/src/main/java/de/skyslycer/hmcwraps/wrap/ArmorModifiers.java @@ -0,0 +1,104 @@ +package de.skyslycer.hmcwraps.wrap; + +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.UUID; + +public enum ArmorModifiers { + + CHAINMAIL(0, 0, new ArmorValues(1, 2, 3, 1), new ArmorValues(15, 40, 30, 15)), + IRON(0, 0, new ArmorValues(2, 5, 6, 2), new ArmorValues(45, 120, 90, 45)), + GOLD(0, 0, new ArmorValues(2, 5, 3, 1), new ArmorValues(21, 56, 42, 21)), + DIAMOND(2, 0, new ArmorValues(3, 8, 6, 3), new ArmorValues(99, 264, 198, 99)), + TURTLE(0, 0, new ArmorValues(2, 6, 5, 2), new ArmorValues(75, 200, 150, 75)), + NETHERITE(3, 1, new ArmorValues(3, 8, 6, 3), new ArmorValues(111, 296, 222, 111)); + + private final int toughness; + private final int knockback; + private final ArmorValues defense; + private final ArmorValues durability; + + ArmorModifiers(int toughness, int knockback, ArmorValues defense, ArmorValues durability) { + this.toughness = toughness; + this.knockback = knockback; + this.defense = defense; + this.durability = durability; + } + + public record ArmorValues(int helmet, int chestplate, int leggings, int boots) { } + + public static ArmorModifiers getFromMaterial(String material) { + if (material.contains("CHAINMAIL")) return CHAINMAIL; + if (material.contains("IRON")) return IRON; + if (material.contains("GOLD")) return GOLD; + if (material.contains("DIAMOND")) return DIAMOND; + if (material.contains("TURTLE")) return TURTLE; + if (material.contains("NETHERITE")) return NETHERITE; + return null; + } + + public static void applyAttributes(ItemStack item, EquipmentSlot slot, int toughness, int knockback, int defense) { + var meta = item.getItemMeta(); + if (meta.getAttributeModifiers(Attribute.GENERIC_ARMOR_TOUGHNESS) == null) { + addModifier(meta, slot, Attribute.GENERIC_ARMOR_TOUGHNESS, toughness); + } else { + meta.getAttributeModifiers(Attribute.GENERIC_ARMOR_TOUGHNESS).stream().findFirst().ifPresent(modifier -> { + meta.removeAttributeModifier(Attribute.GENERIC_ARMOR_TOUGHNESS, modifier); + addModifier(meta, slot, Attribute.GENERIC_ARMOR_TOUGHNESS, toughness); + }); + } + if (knockback != 0) { + if (meta.getAttributeModifiers(Attribute.GENERIC_KNOCKBACK_RESISTANCE) == null) { + addModifier(meta, slot, Attribute.GENERIC_KNOCKBACK_RESISTANCE, knockback / 10d); + } else { + meta.getAttributeModifiers(Attribute.GENERIC_KNOCKBACK_RESISTANCE).stream().findFirst().ifPresent(modifier -> { + meta.removeAttributeModifier(Attribute.GENERIC_KNOCKBACK_RESISTANCE, modifier); + addModifier(meta, slot, Attribute.GENERIC_KNOCKBACK_RESISTANCE, knockback / 10d); // divided by 10 because Minecraft decided so + }); + } + } + if (meta.getAttributeModifiers(Attribute.GENERIC_ARMOR) == null) { + addModifier(meta, slot, Attribute.GENERIC_ARMOR, defense); + } else { + meta.getAttributeModifiers(Attribute.GENERIC_ARMOR).stream().findFirst().ifPresent(modifier -> { + meta.removeAttributeModifier(Attribute.GENERIC_ARMOR, modifier); + addModifier(meta, slot, Attribute.GENERIC_ARMOR, defense); + }); + } + item.setItemMeta(meta); + } + + public static ItemStack removeAttributes(ItemStack item) { + var meta = item.getItemMeta(); + meta.removeAttributeModifier(Attribute.GENERIC_ARMOR_TOUGHNESS); + meta.removeAttributeModifier(Attribute.GENERIC_KNOCKBACK_RESISTANCE); + meta.removeAttributeModifier(Attribute.GENERIC_ARMOR); + item.setItemMeta(meta); + return item; + } + + private static void addModifier(ItemMeta meta, EquipmentSlot slot, Attribute attribute, double amount) { + meta.addAttributeModifier(attribute, new AttributeModifier(UUID.randomUUID(), attribute.getKey().getKey(), amount, AttributeModifier.Operation.ADD_NUMBER, slot)); + } + + public int getToughness() { + return toughness; + } + + public int getKnockback() { + return knockback; + } + + public ArmorValues getDefense() { + return defense; + } + + public ArmorValues getDurability() { + return durability; + } + +} diff --git a/src/main/java/de/skyslycer/hmcwraps/wrap/WrapperImpl.java b/src/main/java/de/skyslycer/hmcwraps/wrap/WrapperImpl.java index b69c29c..45fa5a1 100644 --- a/src/main/java/de/skyslycer/hmcwraps/wrap/WrapperImpl.java +++ b/src/main/java/de/skyslycer/hmcwraps/wrap/WrapperImpl.java @@ -9,13 +9,15 @@ import de.skyslycer.hmcwraps.util.PlayerUtil; import de.skyslycer.hmcwraps.util.StringUtil; import de.skyslycer.hmcwraps.util.WrapNBTUtil; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Color; -import org.bukkit.NamespacedKey; +import dev.lone.itemsadder.api.CustomStack; +import io.lumine.mythic.bukkit.MythicBukkit; +import io.th0rgal.oraxen.api.OraxenItems; +import org.bukkit.*; import org.bukkit.entity.Player; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.LeatherArmorMeta; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -43,6 +45,12 @@ public class WrapperImpl implements Wrapper { private final NamespacedKey originalNameKey; private final NamespacedKey originalLoreKey; private final NamespacedKey originalFlagsKey; + private final NamespacedKey originalItemsAdderKey; + private final NamespacedKey originalOraxenKey; + private final NamespacedKey originalMythicKey; + private final NamespacedKey originalMaterialKey; + private final NamespacedKey fakeDurabilityKey; + private final NamespacedKey fakeMaxDurabilityKey; public WrapperImpl(HMCWrapsPlugin plugin) { this.plugin = plugin; @@ -56,6 +64,12 @@ public WrapperImpl(HMCWrapsPlugin plugin) { originalNameKey = new NamespacedKey(plugin, "original-name"); originalLoreKey = new NamespacedKey(plugin, "original-lore"); originalFlagsKey = new NamespacedKey(plugin, "original-flags"); + originalItemsAdderKey = new NamespacedKey(plugin, "original-itemsadder-id"); + originalOraxenKey = new NamespacedKey(plugin, "original-oraxen-id"); + originalMythicKey = new NamespacedKey(plugin, "original-mythic-id"); + originalMaterialKey = new NamespacedKey(plugin, "original-material"); + fakeDurabilityKey = new NamespacedKey(plugin, "fake-durability"); + fakeMaxDurabilityKey = new NamespacedKey(plugin, "fake-max-durability"); } @Override @@ -97,13 +111,23 @@ private ItemStack setWrapPrivate(@Nullable Wrap wrap, ItemStack item, boolean ph var originalModelId = -1; var originalLore = meta.getLore(); var originalFlags = meta.getItemFlags().stream().toList(); + var originalMaterial = ""; Color originalColor = null; if (meta.hasCustomModelData()) { originalModelId = meta.getCustomModelData(); } meta.getPersistentDataContainer().set(wrapIdKey, PersistentDataType.STRING, wrap == null ? "-" : wrap.getUuid()); + meta.getPersistentDataContainer().remove(playerKey); meta.setCustomModelData(wrap == null ? originalData.modelId() : wrap.getModelId()); if (wrap != null) { + if (currentWrap != null && originalData.material() != null && !originalData.material().isBlank()) { + switchFromLeather(editing, originalData.material()); + } + resetFakeDurability(item, editing); + meta.setDisplayName(originalData.name()); + meta.setLore(originalData.lore()); + meta.removeItemFlags(meta.getItemFlags().toArray(ItemFlag[]::new)); + meta.addItemFlags(originalData.flags().toArray(ItemFlag[]::new)); if (wrap.getWrapName() != null) { meta.setDisplayName(StringUtil.LEGACY_SERIALIZER.serialize(StringUtil.parseComponent(player, wrap.getWrapName()))); } @@ -111,26 +135,59 @@ private ItemStack setWrapPrivate(@Nullable Wrap wrap, ItemStack item, boolean ph var lore = wrap.getWrapLore().stream().map(entry -> StringUtil.LEGACY_SERIALIZER.serialize(StringUtil.parseComponent(player, entry))).toList(); meta.setLore(lore); } - if (wrap.getFlags() != null) { - for (String flag : wrap.getFlags()) { + if (wrap.getWrapFlags() != null) { + for (String flag : wrap.getWrapFlags()) { try { meta.addItemFlags(ItemFlag.valueOf(flag)); } catch (IllegalArgumentException ignored) { } } } - if (wrap.getColor() != null && meta instanceof LeatherArmorMeta leatherMeta) { + editing.setItemMeta(meta); + var changedDurability = false; + if (wrap.isArmorImitationEnabled() && !editing.getType().toString().contains("LEATHER")) { + var maxDurability = editing.getType().getMaxDurability(); + var currentDurability = maxDurability - ((Damageable) meta).getDamage(); + var temp = editing.getType().toString(); + if (switchToLeather(editing)) { + int newDurability = editing.getType().getMaxDurability(); + var modelDurability = ((double) currentDurability / maxDurability) * newDurability; + var newMeta = ((Damageable) editing.getItemMeta()); + newMeta.setDamage(newDurability - (int) modelDurability); + newMeta.getPersistentDataContainer().set(fakeDurabilityKey, PersistentDataType.INTEGER, currentDurability); + newMeta.getPersistentDataContainer().set(fakeMaxDurabilityKey, PersistentDataType.INTEGER, (int) maxDurability); + editing.setItemMeta(newMeta); + originalMaterial = temp; + changedDurability = true; + } + } + if (wrap.getWrapDurability() != null && wrap.getWrapDurability() > 0) { + var maxDurability = editing.getType().getMaxDurability(); + var currentDurability = maxDurability - ((Damageable) meta).getDamage(); + var modelDurability = ((double) currentDurability / maxDurability) * wrap.getWrapDurability(); + var newMeta = ((Damageable) editing.getItemMeta()); + newMeta.setDamage(maxDurability - currentDurability); + newMeta.getPersistentDataContainer().set(fakeDurabilityKey, PersistentDataType.INTEGER, (int) modelDurability); + newMeta.getPersistentDataContainer().set(fakeMaxDurabilityKey, PersistentDataType.INTEGER, wrap.getWrapDurability()); + editing.setItemMeta(newMeta); + changedDurability = true; + } + if (!changedDurability) { + var newMeta = editing.getItemMeta(); + newMeta.getPersistentDataContainer().remove(fakeDurabilityKey); + newMeta.getPersistentDataContainer().remove(fakeMaxDurabilityKey); + editing.setItemMeta(newMeta); + } + if (wrap.getColor() != null && editing.getItemMeta() instanceof LeatherArmorMeta leatherMeta) { originalColor = leatherMeta.getColor(); leatherMeta.setColor(wrap.getColor()); editing.setItemMeta(leatherMeta); - } else { - editing.setItemMeta(meta); } - if (wrap.getNbt() != null) { - editing = WrapNBTUtil.wrap(editing, wrap.getNbt()); + if (wrap.getWrapNbt() != null) { + editing = WrapNBTUtil.wrap(editing, wrap.getWrapNbt()); } } else { + meta.setCustomModelData(0); meta.setDisplayName(originalData.name()); - meta.setCustomModelData(originalData.modelId()); meta.setLore(originalData.lore()); meta.removeItemFlags(meta.getItemFlags().toArray(ItemFlag[]::new)); meta.addItemFlags(originalData.flags().toArray(ItemFlag[]::new)); @@ -140,13 +197,135 @@ private ItemStack setWrapPrivate(@Nullable Wrap wrap, ItemStack item, boolean ph } else { editing.setItemMeta(meta); } + if (originalData.material() != null && !originalData.material().isBlank()) { + switchFromLeather(editing, originalData.material()); + } + resetFakeDurability(item, editing); editing = WrapNBTUtil.unwrap(editing); } editing = setPhysical(editing.clone(), physical); if (wrap == null || currentWrap != null) { return editing; } - return setOriginalData(editing, new WrapValues(originalModelId, originalColor, originalName, originalLore, originalFlags)); + String itemsAdderId = null; + if (getWrap(item) == null && Bukkit.getPluginManager().getPlugin("ItemsAdder") != null) { + var id = CustomStack.byItemStack(item); + if (id != null) { + itemsAdderId = id.getNamespacedID(); + } + } else { + itemsAdderId = getOriginalItemsAdderId(item); + } + String oraxenId = null; + if (getWrap(item) == null && Bukkit.getPluginManager().getPlugin("Oraxen") != null) { + var id = OraxenItems.getIdByItem(item); + if (id != null) { + oraxenId = id; + } + } else { + oraxenId = getOriginalOraxenId(item); + } + String mythicId = null; + if (getWrap(item) == null && Bukkit.getPluginManager().getPlugin("MythicMobs") != null) { + var id = MythicBukkit.inst().getItemManager().getMythicTypeFromItem(item); + if (id != null) { + itemsAdderId = id; + } + } else { + mythicId = getOriginalMythicId(item); + } + return setOriginalData(editing, new WrapValues(originalModelId, originalColor, originalName, originalLore, + originalFlags, itemsAdderId, oraxenId, mythicId, originalMaterial)); + } + + private void resetFakeDurability(ItemStack item, ItemStack editing) { + if (getFakeDurability(item) != -1) { + var newMeta = (Damageable) editing.getItemMeta(); + if (newMeta.getPersistentDataContainer().has(fakeDurabilityKey, PersistentDataType.INTEGER)) { + var currentDurability = getFakeDurability(item); + var oldMaxDurability = getFakeMaxDurability(item); + var newMaxDurability = editing.getType().getMaxDurability(); + var newDurability = ((double) currentDurability / oldMaxDurability) * newMaxDurability; + newMeta.setDamage(editing.getType().getMaxDurability() - (int) newDurability); + newMeta.getPersistentDataContainer().remove(fakeDurabilityKey); + newMeta.getPersistentDataContainer().remove(fakeMaxDurabilityKey); + editing.setItemMeta(newMeta); + } + } + } + + private boolean switchToLeather(ItemStack editing) { + if (editing.getType().toString().contains("_HELMET")) { + var armorModifiers = ArmorModifiers.getFromMaterial(editing.getType().toString()); + editing.setType(Material.LEATHER_HELMET); + ArmorModifiers.applyAttributes(editing, EquipmentSlot.HEAD, armorModifiers.getToughness(), armorModifiers.getKnockback(), armorModifiers.getDefense().helmet()); + } else if (editing.getType().toString().contains("_CHESTPLATE")) { + var armorModifiers = ArmorModifiers.getFromMaterial(editing.getType().toString()); + editing.setType(Material.LEATHER_CHESTPLATE); + ArmorModifiers.applyAttributes(editing, EquipmentSlot.CHEST, armorModifiers.getToughness(), armorModifiers.getKnockback(), armorModifiers.getDefense().chestplate()); + } else if (editing.getType().toString().contains("_LEGGINGS")) { + var armorModifiers = ArmorModifiers.getFromMaterial(editing.getType().toString()); + editing.setType(Material.LEATHER_LEGGINGS); + ArmorModifiers.applyAttributes(editing, EquipmentSlot.LEGS, armorModifiers.getToughness(), armorModifiers.getKnockback(), armorModifiers.getDefense().leggings()); + } else if (editing.getType().toString().contains("_BOOTS")) { + var armorModifiers = ArmorModifiers.getFromMaterial(editing.getType().toString()); + editing.setType(Material.LEATHER_BOOTS); + ArmorModifiers.applyAttributes(editing, EquipmentSlot.FEET, armorModifiers.getToughness(), armorModifiers.getKnockback(), armorModifiers.getDefense().boots()); + } else { + return false; + } + return true; + } + + private void switchFromLeather(ItemStack editing, String material) { + editing.setType(Material.valueOf(material)); + ArmorModifiers.removeAttributes(editing); + } + + @Override + public int getFakeDurability(ItemStack item) { + var meta = item.getItemMeta(); + if (meta == null) { + return -1; + } + var data = meta.getPersistentDataContainer().get(fakeDurabilityKey, PersistentDataType.INTEGER); + if (data == null) { + return -1; + } + return data; + } + + @Override + public void setFakeDurability(ItemStack item, int durability) { + var meta = item.getItemMeta(); + if (meta == null) { + return; + } + meta.getPersistentDataContainer().set(fakeDurabilityKey, PersistentDataType.INTEGER, durability); + item.setItemMeta(meta); + } + + @Override + public int getFakeMaxDurability(ItemStack item) { + var meta = item.getItemMeta(); + if (meta == null) { + return -1; + } + var data = meta.getPersistentDataContainer().get(fakeMaxDurabilityKey, PersistentDataType.INTEGER); + if (data == null) { + return -1; + } + return data; + } + + @Override + public void setFakeMaxDurability(ItemStack item, int durability) { + var meta = item.getItemMeta(); + if (meta == null) { + return; + } + meta.getPersistentDataContainer().set(fakeDurabilityKey, PersistentDataType.INTEGER, durability); + item.setItemMeta(meta); } @Override @@ -205,7 +384,9 @@ public String getPhysicalWrapper(ItemStack item) { @Override public WrapValues getOriginalData(ItemStack item) { - return new WrapValues(getOriginalModelId(item), getOriginalColor(item), getOriginalName(item), getOriginalLore(item), getOriginalFlags(item)); + return new WrapValues(getOriginalModelId(item), getOriginalColor(item), getOriginalName(item), + getOriginalLore(item), getOriginalFlags(item), getOriginalItemsAdderId(item), getOriginalOraxenId(item), + getOriginalMythicId(item), getOriginalMaterial(item)); } private int getOriginalModelId(ItemStack item) { @@ -240,6 +421,7 @@ private String getOriginalName(ItemStack item) { if (data != null) { name = ChatColor.translateAlternateColorCodes('&', data); } + return name; } else if (nameSettings.isDefaultEnabled()) { var map = nameSettings.getDefaults(); if (map.containsKey(item.getType().toString())) { @@ -250,8 +432,9 @@ private String getOriginalName(ItemStack item) { name = StringUtil.LEGACY_SERIALIZER_AMPERSAND.serialize(StringUtil.parseComponent(map.get(key))); } } + return name; } - return name; + return item.getItemMeta().getDisplayName(); } private List getOriginalLore(ItemStack item) { @@ -263,6 +446,7 @@ private List getOriginalLore(ItemStack item) { if (data != null) { Arrays.stream(data.split(SEPARATOR)).map(entry -> ChatColor.translateAlternateColorCodes('&', entry)).forEach(lore::add); } + return lore; } else if (loreSettings.isDefaultEnabled()) { var map = loreSettings.getDefaults(); if (map.containsKey(item.getType().toString())) { @@ -273,8 +457,9 @@ private List getOriginalLore(ItemStack item) { map.get(key).stream().map(entry -> ChatColor.translateAlternateColorCodes('&', entry)).forEach(lore::add); } } + return lore; } - return lore; + return item.getItemMeta().getLore(); } private Color getOriginalColor(ItemStack item) { @@ -314,6 +499,7 @@ private List getOriginalFlags(ItemStack item) { } catch (IllegalArgumentException ignored) { } } } + return list; } else if (settings.isDefaultEnabled()) { var map = settings.getDefaults(); if (map.containsKey(item.getType().toString())) { @@ -332,10 +518,31 @@ private List getOriginalFlags(ItemStack item) { } } } + return list; } - return list; + return item.getItemMeta().getItemFlags().stream().toList(); + } + + private String getOriginalItemsAdderId(ItemStack item) { + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + return container.get(originalItemsAdderKey, PersistentDataType.STRING); + } + + private String getOriginalOraxenId(ItemStack item) { + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + return container.get(originalOraxenKey, PersistentDataType.STRING); } + private String getOriginalMythicId(ItemStack item) { + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + return container.get(originalMythicKey, PersistentDataType.STRING); + } + + private String getOriginalMaterial(ItemStack item) { + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + var value = container.get(originalMaterialKey, PersistentDataType.STRING); + return value == null ? "" : value; + } @Override public ItemStack setOriginalData(ItemStack item, WrapValues wrapValues) { @@ -356,6 +563,18 @@ public ItemStack setOriginalData(ItemStack item, WrapValues wrapValues) { meta.getPersistentDataContainer().set(originalFlagsKey, PersistentDataType.STRING, wrapValues.flags().stream().map(ItemFlag::toString).collect(Collectors.joining(SEPARATOR))); } + if (wrapValues.itemsAdder() != null) { + meta.getPersistentDataContainer().set(originalItemsAdderKey, PersistentDataType.STRING, wrapValues.itemsAdder()); + } + if (wrapValues.oraxen() != null) { + meta.getPersistentDataContainer().set(originalOraxenKey, PersistentDataType.STRING, wrapValues.oraxen()); + } + if (wrapValues.mythic() != null) { + meta.getPersistentDataContainer().set(originalMythicKey, PersistentDataType.STRING, wrapValues.mythic()); + } + if (wrapValues.material() != null) { + meta.getPersistentDataContainer().set(originalMaterialKey, PersistentDataType.STRING, wrapValues.material()); + } editing.setItemMeta(meta); return editing; } @@ -409,35 +628,110 @@ public ItemStack setPhysical(ItemStack item, boolean physical) { @Override public boolean isValid(ItemStack item, Wrap wrap) { + return wrap.getRange() == null || (isValidType(wrap.getRange().getModelId(), getRealModelId(item)) && isValidColor(wrap.getRange().getColor(), getRealColor(item)) && + isValidType(wrap.getRange().getItemsAdder(), getRealItemsAdderId(item)) && isValidType(wrap.getRange().getOraxen(), getRealOraxenId(item)) && isValidType(wrap.getRange().getMythic(), getRealMythicId(item))); + } + + private boolean isValidType(ValueRangeSettings settings, T value) { + if (settings == null) { + return true; + } + return (settings.getExclude() == null || !settings.getExclude().contains(value)) && (settings.getInclude() == null || settings.getInclude().contains(value)); + } + + private boolean isValidColor(ValueRangeSettings settings, Color value) { + if (settings == null) { + return true; + } + List exclude = null; + List include = null; + if (settings.getExclude() != null) { + exclude = settings.getExclude().stream().map(StringUtil::colorFromString).collect(Collectors.toList()); + } + if (settings.getInclude() != null) { + include = settings.getInclude().stream().map(StringUtil::colorFromString).collect(Collectors.toList()); + } + return (exclude == null || !exclude.contains(value)) && (include == null || include.contains(value)) && + !(settings.getExclude().contains("none") && value != null); + } + + private int getRealModelId(ItemStack item) { var modelData = -1; if (getWrap(item) != null) { modelData = getOriginalModelId(item); } else if (item.getItemMeta().hasCustomModelData()) { modelData = item.getItemMeta().getCustomModelData(); } + return modelData; + } + + private Color getRealColor(ItemStack item) { Color color = null; if (getWrap(item) != null) { color = getOriginalColor(item); } else if (item.getItemMeta() instanceof LeatherArmorMeta meta) { color = meta.getColor(); } - return wrap.getRange() == null || (isValidType(wrap.getRange().getModelId(), modelData) && isValidColor(wrap.getRange().getColor(), color)); + return color; } - private boolean isValidType(ValueRangeSettings settings, T value) { - return (settings.getExclude() == null || !settings.getExclude().contains(value)) && (settings.getInclude() == null || settings.getInclude().contains(value)); + private String getRealItemsAdderId(ItemStack item) { + String itemsAdderId = null; + if (getWrap(item) != null) { + itemsAdderId = getOriginalItemsAdderId(item); + } else if (Bukkit.getPluginManager().getPlugin("ItemsAdder") != null) { + var id = CustomStack.byItemStack(item); + if (id != null) { + itemsAdderId = id.getNamespacedID(); + } + } + return itemsAdderId; } - private boolean isValidColor(ValueRangeSettings settings, Color value) { - List exclude = null; - List include = null; - if (settings.getExclude() != null) { - exclude = settings.getExclude().stream().map(StringUtil::colorFromString).collect(Collectors.toList()); + private String getRealOraxenId(ItemStack item) { + String oraxenId = null; + if (getWrap(item) != null) { + oraxenId = getOriginalOraxenId(item); + } else if (Bukkit.getPluginManager().getPlugin("Oraxen") != null) { + var id = OraxenItems.getIdByItem(item); + if (id != null) { + oraxenId = id; + } } - if (settings.getInclude() != null) { - include = settings.getInclude().stream().map(StringUtil::colorFromString).collect(Collectors.toList()); + return oraxenId; + } + + private String getRealMythicId(ItemStack item) { + String mythicId = null; + if (getWrap(item) != null) { + mythicId = getOriginalMythicId(item); + } else if (Bukkit.getPluginManager().getPlugin("MythicMobs") != null) { + var id = MythicBukkit.inst().getItemManager().getMythicTypeFromItem(item); + if (id != null) { + mythicId = id; + } + } + return mythicId; + } + + @Override + public boolean isGloballyDisabled(ItemStack item) { + if (plugin.getConfiguration().getGlobalDisable().getModelId().contains(getRealModelId(item))) { + return true; + } + if (plugin.getConfiguration().getGlobalDisable().getColor().stream().map(StringUtil::colorFromString).toList().contains(getRealColor(item))) { + return true; + } + if (plugin.getConfiguration().getGlobalDisable().getItemsAdderId().contains(getRealItemsAdderId(item))) { + return true; + } + if (plugin.getConfiguration().getGlobalDisable().getOraxenId().contains(getRealOraxenId(item))) { + return true; + } + if (plugin.getConfiguration().getGlobalDisable().getMythicId().contains(getRealMythicId(item))) { + return true; } - return (exclude == null || !exclude.contains(value)) && (include == null || include.contains(value)); + return false; } } diff --git a/src/main/java/de/skyslycer/hmcwraps/wrap/WrapsLoaderImpl.java b/src/main/java/de/skyslycer/hmcwraps/wrap/WrapsLoaderImpl.java index 95b09c7..5e3e7a4 100644 --- a/src/main/java/de/skyslycer/hmcwraps/wrap/WrapsLoaderImpl.java +++ b/src/main/java/de/skyslycer/hmcwraps/wrap/WrapsLoaderImpl.java @@ -7,6 +7,7 @@ import de.skyslycer.hmcwraps.serialization.files.WrapFile; import de.skyslycer.hmcwraps.serialization.wrap.Wrap; import de.skyslycer.hmcwraps.serialization.wrap.WrappableItem; +import de.skyslycer.hmcwraps.transformation.WrapFileTransformations; import org.jetbrains.annotations.NotNull; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationOptions; @@ -75,14 +76,16 @@ private void loadWrapFiles() { ((path, attributes) -> attributes.isRegularFile() && (path.toString().endsWith(".yml") || path.toString().endsWith(".yaml"))))) { paths.forEach(path -> { try { - var wrapFile = YamlConfigurationLoader.builder() + var loader = YamlConfigurationLoader.builder() .defaultOptions(ConfigurationOptions.defaults().implicitInitialization(false)) .path(path) - .build().load().get(WrapFile.class); + .build(); + new WrapFileTransformations().updateToLatest(path); + var wrapFile = loader.load().get(WrapFile.class); if (wrapFile != null && wrapFile.isEnabled()) { wrapFiles.add(wrapFile); } - } catch (ConfigurateException exception) { + } catch (IOException exception) { plugin.logSevere( "Could not load the wrap file " + path.getFileName().toString() + " (please report this to the developers)!", exception); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e8ff5f4..15bfa00 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,5 +1,5 @@ # Settings on how permissions should be handled -permission-settings: +permissions: # If the wrap inventory open permission should be checked on wraps inventory open inventory-permission: false # If the preview should be disabled if the player doesn't have the permission for the wrap @@ -14,9 +14,15 @@ permission-settings: permission-physical: false # ...virtual wraps permission-virtual: true + # The interval in minutes to check for wraps without permission, set to -1 to disable + inventory-check-interval: 10 # Preview settings preview: + # The type of the preview, either 'FLOATING' or 'HAND', floating being the item turning in the air and + # item being the players item in hand turning into the wrap temporarily. + # When using 'HAND', rotation and bobbing will be ignored. (The preview item is client-side only) + type: 'FLOATING' # Duration of the preview in seconds duration: 5 # Rotation per tick (50ms) @@ -36,6 +42,16 @@ preview: # How far it should bob up and down intensity: 0.25 +# Items with these properties can't be wrapped +global-disable: + # Any model id in this list can't be wrapped. If you want to disable items with no model id, use -1. + model-id: [ ] + # You can use hex or rgb, check the documentation. If you want to disable items with no color, use 'none'. + color: [ ] + oraxen: [ ] + itemsadder: [ ] + mythic: [] + # The items with wraps # You can configure them here or in a wrap file, which are located in plugins/HMCWraps/wraps/ items: @@ -67,7 +83,7 @@ items: # The flags the item should have in the wraps inventory (nullable) flags: - 'HIDE_ATTRIBUTES' - # Item actions, all possible action triggers are listed below. For a full list of actions, see the wiki. + # Item actions, most action triggers are listed below. For a full list of actions, see the wiki. # Examples: TITLE: ['0.5 5 1 HMCWRaps'], COMMAND: ['me is mega sus'], PARTICLE: ['heart'] # Note: The actions entry and all action lists are nullable, so you can just remove this section if you don't need it actions: @@ -204,6 +220,16 @@ updater: # Where the version checker should check for updates (POLYMART, SPIGOT_MC) platform: 'POLYMART' +# Settings related to wrapping +wrapping: + # If wraps should be able to be rewrapped (wrapped again while wrapped) + rewrap: + # If rewrapping should be enabled for... + # ...virtual wrapping + virtual-enabled: true + # ...physical wrapping + physical-enabled: true + # The inventory (/wraps) inventory: # Shortcut settings @@ -212,6 +238,9 @@ inventory: enabled: true # What items can't be used to open the inventory exclude: [ ] + # If the player should be able to switch the wrapping item in the inventory. + # When enabled, the inventory won't close after wrapping or unwrapping. + item-change-enabled: true # The title title: 'Wraps' # Type of inventory, SCROLLING or PAGINATED @@ -279,4 +308,8 @@ inventory: actions: any: UNWRAP: - - '' \ No newline at end of file + - '' + +# DON'T TOUCH THIS +config: 1 +# DON'T TOUCH THIS \ No newline at end of file diff --git a/src/main/resources/emerald_wraps.yml b/src/main/resources/emerald_wraps.yml index 7c4061a..c9b9ee6 100644 --- a/src/main/resources/emerald_wraps.yml +++ b/src/main/resources/emerald_wraps.yml @@ -12,7 +12,7 @@ items: 1: permission: 'hmcwraps.emerald_sword' uuid: 'emerald_sword' - id: '2' + id: '3' name: 'Emerald Wrap' lore: - 'Apply this wrap to make your sword look emerald!' @@ -23,7 +23,7 @@ items: 1: permission: 'hmcwraps.emerald_pickaxe' uuid: 'emerald_pickaxe' - id: '2' + id: '3' name: 'Emerald Wrap' lore: - 'Apply this wrap to make your pickaxe look emerald!' @@ -34,7 +34,7 @@ items: 1: permission: 'hmcwraps.emerald_axe' uuid: 'emerald_axe' - id: '1' + id: '2' name: 'Emerald Wrap' lore: - 'Apply this wrap to make your axe look emerald!' @@ -45,7 +45,7 @@ items: 1: permission: 'hmcwraps.emerald_shovel' uuid: 'emerald_shovel' - id: '1' + id: '2' name: 'Emerald Wrap' lore: - 'Apply this wrap to make your shovel look emerald!' @@ -56,9 +56,13 @@ items: 1: permission: 'hmcwraps.emerald_hoe' uuid: 'emerald_hoe' - id: '1' + id: '2' name: 'Emerald Wrap' lore: - 'Apply this wrap to make your hoe look emerald!' flags: - 'HIDE_ATTRIBUTES' + +# DON'T TOUCH THIS +config: 1 +# DON'T TOUCH THIS \ No newline at end of file diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index d836aec..86b0967 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -4,8 +4,12 @@ apply-wrap=Successfully applied the wrap to the item! remove-wrap=Successfully removed your current wrap! no-item=You need to have an item in your main hand! no-wraps=There are no wraps for this item! +no-rewrap=You have to unwrap this item before you can wrap it! preview.disabled=You can't preview this wrap! preview.bar=Press to cancel the preview +favorites.set=You have successfully set your favorite wrap! +favorites.clear=You have successfully cleared your favorite wrap! +armor-imitation.forbidden-inventory=You can't use this inventory with a wrapped item! Please unwrap it first. inventory.filter.active=Filtering enabled! inventory.filter.inactive=Filtering disabled! command.missing-argument=You have to specify the ! @@ -36,4 +40,6 @@ command.list.custom-model-id=Model ID: command.convert.success=Successfully converted all ItemSkins files! The new files are located in wraps/generated/ and collections/generated/! command.convert.confirm=In order to confirm this action, please run /wraps convert confirm. NOTE: This should be safe, but please have a backup of your files! command.convert.no-confirm=You currently don't have anything to confirm! In order to start the process, run /wraps convert. -command.convert.failed=Some or all files failed to convert! Please check the console for more information, delete the folders wraps/generated/ and collections/generated/, and try again! \ No newline at end of file +command.convert.failed=Some or all files failed to convert! Please check the console for more information, delete the folders wraps/generated/ and collections/generated/, and try again! +command.create.failed=An error occurred while generating the wrap file! Please report the error in the console to the developers. +command.create.success=Successfully created the wrap file! You can find it at: ! Type /wraps reload once you want the new wrap to be loaded. \ No newline at end of file diff --git a/src/main/resources/silver_wraps.yml b/src/main/resources/silver_wraps.yml index 0fb3f57..ac9dc8b 100644 --- a/src/main/resources/silver_wraps.yml +++ b/src/main/resources/silver_wraps.yml @@ -61,4 +61,8 @@ items: lore: - 'Apply this wrap to make your hoe look silver!' flags: - - 'HIDE_ATTRIBUTES' \ No newline at end of file + - 'HIDE_ATTRIBUTES' + +# DON'T TOUCH THIS +config: 1 +# DON'T TOUCH THIS \ No newline at end of file