From ea15eb56c1c17131ab8205cfff48a6aeaa72584b Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:53:47 -0600 Subject: [PATCH 001/139] no changes --- .../utils/controller/DisplayController.java | 2 +- .../listeners/autogroup/AutoGroup.java | 4 +--- .../listeners/autogroup/DEULoadingListeners.java | 11 +---------- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayController.java b/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayController.java index 8346e0cd..817934e3 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayController.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayController.java @@ -91,7 +91,7 @@ boolean isMarkedNull(){ return grouplessControllers.containsKey(this); } - @ApiStatus.Internal + /** * Set the {@link DisplayEntityGroup} this controller should use * @param group diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java index ba8b721f..a2b17bcd 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java @@ -46,10 +46,8 @@ static void detectGroups(Chunk chunk, List entities){ World world = chunk.getWorld(); String worldName = world.getName(); - Set chunks = readChunks - .computeIfAbsent(worldName, name -> Collections.newSetFromMap(new ConcurrentHashMap<>())); + Set chunks = readChunks.computeIfAbsent(worldName, name -> Collections.newSetFromMap(new ConcurrentHashMap<>())); - //Bukkit.broadcastMessage(chunk.getX()+" X | "+chunk.getZ()+" Z | TICK="+Bukkit.getCurrentTick()); if (chunks.contains(chunk.getChunkKey())){ refreshGroupPartEntities(entities); if (!DisplayConfig.readSameChunks()) return; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/DEULoadingListeners.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/DEULoadingListeners.java index 1f19e1da..de2aef54 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/DEULoadingListeners.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/DEULoadingListeners.java @@ -23,16 +23,7 @@ public final class DEULoadingListeners implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onEntityLoad(EntitiesLoadEvent e){ - Chunk chunk = e.getChunk(); - //if (chunk.isLoaded()){ - AutoGroup.detectGroups(chunk, e.getEntities()); - //} -// else{ -// CompletableFuture futureChunk = e.getWorld().getChunkAtAsync(chunk.getX(), chunk.getZ()); -// futureChunk.thenAccept(c -> { -// Bukkit.getScheduler().runTask(DisplayAPI.getPlugin(), () -> AutoGroup.detectGroups(c, e.getEntities())); -// }); -// } + AutoGroup.detectGroups(e.getChunk(), e.getEntities()); } @EventHandler(priority = EventPriority.LOWEST) From 86d5b8a132a5a971c2173526022eb2a8ce9f796c Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 15 Dec 2025 23:49:07 -0600 Subject: [PATCH 002/139] Add more #teleport methods that teleport in a direction, instantly --- .../utils/DisplayEntities/ActiveGroup.java | 27 ++++++++++++++++++- .../PacketDisplayEntityGroup.java | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java index ded292db..199dcdd0 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java @@ -138,6 +138,31 @@ public void removeCulling(){ */ public abstract boolean teleport(@NotNull Location location, boolean respectGroupDirection); + + /** + * Teleport this group in the given direction. + * @param direction The direction to translate the group + * @param distance How far the group should be translated + * @return true if the teleport was successful + */ + public boolean teleport(@NotNull Direction direction, double distance){ + return teleport(direction.getVector(masterPart, false), distance); + } + + /** + * Teleport this group in the given vector's direction. + * @param direction The direction to translate the group + * @param distance How far the group should be translated + * @return true if the teleport was successful + */ + public boolean teleport(@NotNull Vector direction, double distance){ + Location l = getLocation(); + if (l == null) return false; + l.add(direction.clone().normalize().multiply(distance)); + teleport(l, true); + return true; + } + /** * Move the model through smooth teleportation of both interaction and display entities. Doing this multiple times in a short amount of time may bring unexpected results. * @param direction The direction to translate the group @@ -154,7 +179,7 @@ public void teleportMove(@NotNull Direction direction, double distance, int dura * @param distance How far the group should be translated * @param durationInTicks How long it should take for the translation to complete */ - public abstract void teleportMove(Vector direction, double distance, int durationInTicks); + public abstract void teleportMove(@NotNull Vector direction, double distance, int durationInTicks); /** * Set the teleportation duration of all parts in this group diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index 5c9c42c6..2bbae303 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -545,7 +545,7 @@ public void pivot(float angleInDegrees) { } @Override - public void teleportMove(Vector direction, double distance, int durationInTicks) { + public void teleportMove(@NotNull Vector direction, double distance, int durationInTicks) { Location destination = getLocation().add(direction.clone().normalize().multiply(distance)); double movementIncrement = distance/(double) Math.max(durationInTicks, 1); From f9d9c7174d07ff1c1d575552e9413956768a7989 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 15 Dec 2025 23:50:06 -0600 Subject: [PATCH 003/139] Make tick-duration optional in "/deu group move" command --- .../displayentityutils/command/group/GroupCMD.java | 4 ++-- .../command/group/GroupMoveCMD.java | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java index 7e6ec8e0..7f2d3dc3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java @@ -118,9 +118,9 @@ else if (page == 4){ CMDUtils.sendCMD(sender, "/deu group brightness ", "Set your selected group's brightness. Enter values between 0-15. -1 resets"); CMDUtils.sendCMD(sender, "/deu group clone", "Spawn a cloned group at your selected group's location"); CMDUtils.sendCMD(sender, "/deu group clonehere", "Spawn a cloned group at your location"); - CMDUtils.sendCMD(sender, "/deu group move ", "Change the actual location of your selected group"); - CMDUtils.sendCMD(sender, "/deu group translate ","Changes your selected group's translation, use \"move\" instead if this group uses animations"); + CMDUtils.sendCMD(sender, "/deu group move [tick-duration]", "Change the actual location of your selected group, with an optional duration"); CMDUtils.sendCMD(sender, "/deu group movehere", "Change your selected group's actual location to your location"); + CMDUtils.sendCMD(sender, "/deu group translate ","Changes your selected group's translation, use \"move\" instead if this group uses animations"); } else if (page == 5){ CMDUtils.sendCMD(sender, "/deu group merge ","Merge groups near your selected group"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java index 0e227cf5..12c0869c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java @@ -13,16 +13,16 @@ class GroupMoveCMD extends GroupSubCommand { GroupMoveCMD(@NotNull DEUSubCommand parentSubCommand) { - super("move", parentSubCommand, Permission.GROUP_TRANSFORM, 5, false); + super("move", parentSubCommand, Permission.GROUP_TRANSFORM, 4, false); setTabComplete(2, TabSuggestion.DIRECTIONS); setTabComplete(3, ""); - setTabComplete(4, ""); + setTabComplete(4, "[tick-duration]"); } @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("/deu group move ", NamedTextColor.RED)); + player.sendMessage(Component.text("/deu group move [tick-duration]", NamedTextColor.RED)); } @Override @@ -39,6 +39,14 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a number greater than 0 for the distance!", NamedTextColor.RED))); return; } + + if (args.length == 4){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Teleporting your selected group!", NamedTextColor.GREEN))); + group.teleport(direction, distance); + return; + } + + //With duration int duration = Integer.parseInt(args[4]); if (duration <= 0){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a whole number greater than 0 for the duration!", NamedTextColor.RED))); From 318a0c59ef7e468032691b94834971f27f3ffda7 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 16 Dec 2025 04:52:18 -0600 Subject: [PATCH 004/139] Move relativepoint related code to "plugin" module --- api/pom.xml | 2 +- plugin/pom.xml | 2 +- .../command/parts/PartsSelectCMD.java | 14 ++++++++------ .../utils/command/DEUCommandUtils.java | 2 -- .../utils/relativepoints/FramePointSelector.java | 0 .../utils/relativepoints/GroupPointSelector.java | 1 - .../relativepoints/MultiFramePointHelper.java | 0 .../utils/relativepoints/PacketGroupSelector.java | 0 .../relativepoints/RelativePointSelector.java | 0 .../utils/relativepoints/RelativePointUtils.java | 5 ----- pom.xml | 2 +- 11 files changed, 11 insertions(+), 17 deletions(-) rename {api => plugin}/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/FramePointSelector.java (100%) rename {api => plugin}/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java (94%) rename {api => plugin}/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/MultiFramePointHelper.java (100%) rename {api => plugin}/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java (100%) rename {api => plugin}/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java (100%) rename {api => plugin}/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java (97%) diff --git a/api/pom.xml b/api/pom.xml index 294e8694..4a290c6e 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.3.8 + 3.3.9 api diff --git a/plugin/pom.xml b/plugin/pom.xml index 05c414c2..605faded 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.3.8 + 3.3.9 plugin diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java index 3127c321..ce4b9ffd 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java @@ -44,18 +44,19 @@ public void execute(Player player, String[] args) { Entity entity = player.getTargetEntity(10); if (!(entity instanceof Interaction)) { player.sendMessage(Component.text("Your targeted entity must be an interaction entity within 10 blocks of you", NamedTextColor.RED)); - return; } - select(player, entity.getUniqueId()); + else{ + select(player, entity.getUniqueId()); + } return; } + double distance = Double.parseDouble(arg); if (distance <= 0){ throw new IllegalArgumentException(); } - - player.sendMessage(Component.text("Finding entities within "+distance+" blocks...", NamedTextColor.YELLOW)); - getSelectableEntities(player, distance); + player.sendMessage(Component.text("Finding entities within "+distance+" blocks...", NamedTextColor.YELLOW)); + getSelectableEntities(player, distance); } catch(IllegalArgumentException e){ player.sendMessage(Component.text("Invalid input! Enter a positive number for the distance, or -target to select a targeted Interaction entity", NamedTextColor.RED)); @@ -95,7 +96,8 @@ private void getSelectableEntities(Player player, double distance){ private void select(Player player, UUID entityUUID){ SpawnedDisplayEntityPart existing = SpawnedDisplayEntityPart.getPart(Bukkit.getEntity(entityUUID)); if (existing != null){ - player.sendMessage(Component.text("That part is already in a group! Select the group, then cycle through the group's parts!", NamedTextColor.RED)); + player.sendMessage(Component.text("That part is already in a group!", NamedTextColor.RED)); + player.sendMessage(Component.text("| Select the group, then cycle through the group's parts", NamedTextColor.GRAY)); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/command/DEUCommandUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/command/DEUCommandUtils.java index a8aba4b9..66e62c4f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/command/DEUCommandUtils.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/command/DEUCommandUtils.java @@ -21,14 +21,12 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.util.RayTraceResult; -import org.jetbrains.annotations.ApiStatus; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.UUID; -@ApiStatus.Internal public class DEUCommandUtils { public static void removeRelativePoint(Player player, RelativePointSelector selector){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/FramePointSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/FramePointSelector.java similarity index 100% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/FramePointSelector.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/FramePointSelector.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java similarity index 94% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java index 97364631..e460b57f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java @@ -1,7 +1,6 @@ package net.donnypz.displayentityutils.utils.relativepoints; import net.donnypz.displayentityutils.utils.DisplayEntities.GroupPoint; -import net.donnypz.displayentityutils.utils.DisplayEntities.RelativePoint; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; import org.bukkit.Location; import org.bukkit.Material; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/MultiFramePointHelper.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/MultiFramePointHelper.java similarity index 100% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/MultiFramePointHelper.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/MultiFramePointHelper.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java similarity index 100% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java similarity index 100% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java similarity index 97% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java index b1c7c514..516e156e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java @@ -7,7 +7,6 @@ import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.Player; -import org.jetbrains.annotations.ApiStatus; import java.util.*; @@ -16,7 +15,6 @@ public class RelativePointUtils { public static final HashMap>> relativePointSelectors = new HashMap<>(); public static final HashMap> selectedSelector = new HashMap<>(); - @ApiStatus.Internal public static void spawnFramePointDisplays(ActiveGroup group, Player player, SpawnedDisplayAnimationFrame frame){ if (stopIfViewing(player)){ return; @@ -38,7 +36,6 @@ public static void spawnFramePointDisplays(ActiveGroup group, Player player, } - @ApiStatus.Internal public static void spawnPacketGroupPoints(Chunk chunk, Player player){ if (stopIfViewing(player)){ return; @@ -56,10 +53,8 @@ public static void spawnPacketGroupPoints(Chunk chunk, Player player){ setDisplays(player, displays); player.sendMessage(Component.text("| Right click a point to select its packet-based group", NamedTextColor.AQUA)); } - } - @ApiStatus.Internal public static boolean removeRelativePoints(Player player){ if (player == null) return false; Set> selectors = RelativePointUtils.relativePointSelectors.remove(player.getUniqueId()); diff --git a/pom.xml b/pom.xml index ac75a46d..c5866863 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.3.8 + 3.3.9 pom DisplayEntityUtils From 13c080a4fd0e64544668dd06d5419841ba938473 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 16 Dec 2025 04:52:35 -0600 Subject: [PATCH 005/139] Remove player's relative point data on disconnect --- .../listeners/player/DEUPlayerConnectionListener.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerConnectionListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerConnectionListener.java index 1ea005a7..3b4ae2d9 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerConnectionListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerConnectionListener.java @@ -4,6 +4,7 @@ import com.google.gson.JsonParser; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; @@ -67,6 +68,7 @@ public void onQuit(PlayerQuitEvent e){ if (user != null){ user.remove(); } + RelativePointUtils.removeRelativePoints(player); } private String getLatest() throws IOException, InterruptedException, URISyntaxException { From cc4c27646a6597db9885c8ed495b864e85f59662 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 16 Dec 2025 09:18:22 -0600 Subject: [PATCH 006/139] Properly remove relative point selector's parts when calling #despawn --- .../utils/relativepoints/RelativePointSelector.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java index c26d6d68..af858f17 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java @@ -109,8 +109,8 @@ public void despawn(){ relativePoint = null; Player player = Bukkit.getPlayer(playerUUID); if (player != null){ - displayPart.hideFromPlayer(player); - selectPart.hideFromPlayer(player); + displayPart.remove(); + selectPart.remove(); } isValid = false; } From c3dc3348a7c44e6ee3dab12f53525205dfc01598 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 16 Dec 2025 11:24:03 -0600 Subject: [PATCH 007/139] Added `/deu text addline` --- .../command/text/TextAddLineCMD.java | 45 +++++++++++++++++++ .../command/text/TextCMD.java | 28 +++++++----- .../command/text/TextSetCMD.java | 19 ++++---- 3 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java new file mode 100644 index 00000000..0f416842 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java @@ -0,0 +1,45 @@ +package net.donnypz.displayentityutils.command.text; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; +import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class TextAddLineCMD extends PartsSubCommand { + + public TextAddLineCMD(@NotNull DEUSubCommand parentSubCommand) { + super("addline", parentSubCommand, Permission.TEXT_SET_TEXT, 3, 0); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(Component.text("Incorrect Usage! /deu text addline ", NamedTextColor.RED)); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + return false; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + Component currentText = selectedPart.getTextDisplayText(); + Key font = currentText.font(); + Component comp = currentText.appendNewline().append(LegacyComponentSerializer.legacyAmpersand().deserialize(TextSetCMD.getTextResult(args))); + selectedPart.setTextDisplayText(comp.font(font)); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully added line to text display!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextCMD.java index 991f599b..0d9fac15 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextCMD.java @@ -11,6 +11,7 @@ public TextCMD(){ super(Permission.HELP, new TextHelpCMD()); new TextEditCMD(this); new TextSetCMD(this); + new TextAddLineCMD(this); new TextFontCMD(this); new TextShadowCMD(this); new TextSeeThroughCMD(this); @@ -38,16 +39,21 @@ public void execute(CommandSender sender, String[] args) { static void help(CommandSender sender, int page){ sender.sendMessage(DisplayAPI.pluginPrefixLong); - CMDUtils.sendCMD(sender, "/deu text help", "Get help for text displays"); - CMDUtils.sendCMD(sender, "/deu text edit [-&]", "Open a dialog menu to edit all text display properties. Add the \"-&\" parameter to format the text with \"&\""); - CMDUtils.sendCMD(sender, "/deu text set ", "Set this text for your selected text display"); - CMDUtils.sendCMD(sender, "/deu text font [-all]", "Set the text font for your selected text display"); - CMDUtils.sendCMD(sender, "/deu text shadow [-all ]", "Toggle shadows visibility in your selected text display"); - CMDUtils.sendCMD(sender, "/deu text seethrough [-all ]", "Toggle see through setting of your selected text display"); - CMDUtils.sendCMD(sender, "/deu text align [-all]", "Set your selected text display's text alignment"); - CMDUtils.sendCMD(sender, "/deu text linewidth [-all]", "Set the line width of your selected text display"); - CMDUtils.sendCMD(sender, "/deu text background <0-1> [-all]", "Set the background color of a text display, and the opacity"); - CMDUtils.sendCMD(sender, "/deu text opacity <0-1> [-all]", "Set the text opacity for your selected text display"); - sender.sendMessage(MiniMessage.miniMessage().deserialize("--------------------------")); + if (page == 1){ + CMDUtils.sendCMD(sender, "/deu text help", "Get help for text displays"); + CMDUtils.sendCMD(sender, "/deu text edit [-&]", "Open a dialog menu to edit all text display properties. Add the \"-&\" parameter to format the text with \"&\""); + CMDUtils.sendCMD(sender, "/deu text set ", "Set this text for your selected text display"); + CMDUtils.sendCMD(sender, "/deu text addline ", "Add a line of text to your selected text display"); + CMDUtils.sendCMD(sender, "/deu text font [-all]", "Set the text font for your selected text display"); + CMDUtils.sendCMD(sender, "/deu text shadow [-all ]", "Toggle shadows visibility in your selected text display"); + CMDUtils.sendCMD(sender, "/deu text seethrough [-all ]", "Toggle see through setting of your selected text display"); + } + else{ + CMDUtils.sendCMD(sender, "/deu text align [-all]", "Set your selected text display's text alignment"); + CMDUtils.sendCMD(sender, "/deu text linewidth [-all]", "Set the line width of your selected text display"); + CMDUtils.sendCMD(sender, "/deu text background <0-1> [-all]", "Set the background color of a text display, and the opacity"); + CMDUtils.sendCMD(sender, "/deu text opacity <0-1> [-all]", "Set the text opacity for your selected text display"); + } + sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java index d9d096af..bf15782a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java @@ -35,6 +35,16 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + Component currentText = selectedPart.getTextDisplayText(); + Key font = currentText.font(); + Component comp = LegacyComponentSerializer.legacyAmpersand().deserialize(getTextResult(args)); + selectedPart.setTextDisplayText(comp.font(font)); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set text on text display!", NamedTextColor.GREEN))); + player.sendMessage(Component.text("You can include \"\\n\" in your to create a new line.", NamedTextColor.GRAY)); + return true; + } + + static String getTextResult(String[] args){ StringBuilder builder = new StringBuilder(); for (int i = 2; i < args.length; i++){ builder.append(args[i]); @@ -42,13 +52,6 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti builder.append(" "); } } - Component currentText = selectedPart.getTextDisplayText(); - String textResult = builder.toString().replace("\\n", "\n"); - Key oldFont = currentText.font(); - Component comp = LegacyComponentSerializer.legacyAmpersand().deserialize(textResult); - selectedPart.setTextDisplayText(comp.font(oldFont)); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set text on text display!", NamedTextColor.GREEN))); - player.sendMessage(Component.text("Keep in mind, you can include \"\\n\" in your text display to create a new line.", NamedTextColor.GRAY)); - return true; + return builder.toString().replace("\\n", "\n"); } } From 094aebc66c6db2ab056a0834b99c253f409efd64 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 16 Dec 2025 11:45:00 -0600 Subject: [PATCH 008/139] Check if player's selected part is a text display when executing --- .../displayentityutils/command/text/TextAddLineCMD.java | 9 +++++---- .../displayentityutils/command/text/TextSetCMD.java | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java index 0f416842..6808b980 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java @@ -4,10 +4,7 @@ import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.PartsSubCommand; import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -35,6 +32,10 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); + return false; + } Component currentText = selectedPart.getTextDisplayText(); Key font = currentText.font(); Component comp = currentText.appendNewline().append(LegacyComponentSerializer.legacyAmpersand().deserialize(TextSetCMD.getTextResult(args))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java index bf15782a..d4c6fc31 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java @@ -4,10 +4,7 @@ import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.PartsSubCommand; import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -35,6 +32,10 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); + return false; + } Component currentText = selectedPart.getTextDisplayText(); Key font = currentText.font(); Component comp = LegacyComponentSerializer.legacyAmpersand().deserialize(getTextResult(args)); From 7113904f24c5e3e74861f6957cb3a26b5046b191 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 16 Dec 2025 20:55:49 -0600 Subject: [PATCH 009/139] Updated `/mdis parts select` to visually mark entities instead of creating a list in chat --- .../command/parts/PartsCMD.java | 2 +- .../command/parts/PartsSelectCMD.java | 64 ++--------------- .../relativepoints/DisplayEntitySelector.java | 68 +++++++++++++++++++ .../relativepoints/GroupPointSelector.java | 3 - .../relativepoints/PacketGroupSelector.java | 1 - .../relativepoints/RelativePointSelector.java | 29 ++++++++ .../relativepoints/RelativePointUtils.java | 23 +++++++ 7 files changed, 127 insertions(+), 63 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java index 7584e422..5755d122 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java @@ -71,7 +71,7 @@ static void partsHelp(CommandSender sender, int page){ CMDUtils.sendCMD(sender, "/deu parts help ", "Get help for parts"); CMDUtils.sendCMD(sender, "/deu parts info", "Get information about your current part/selection"); CMDUtils.sendCMD(sender, "/deu parts create ", "Spawn an entity at your location and automatically select it"); - CMDUtils.sendCMD(sender, "/deu parts select ", "Select an ungrouped display/interaction entity near your location. Use \"-target\" to select your targeted Interaction"); + CMDUtils.sendCMD(sender, "/deu parts select ", "Select a nearby, ungrouped, Display entity. Use \"-target\" to select your targeted Interaction"); } else if (page == 2) { CMDUtils.sendCMD(sender, "/deu parts cycle [jump]", "Cycle through parts of your selected group"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java index ce4b9ffd..225c6d00 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java @@ -9,6 +9,8 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.SinglePartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.relativepoints.DisplayEntitySelector; +import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickCallback; import net.kyori.adventure.text.event.ClickEvent; @@ -46,7 +48,7 @@ public void execute(Player player, String[] args) { player.sendMessage(Component.text("Your targeted entity must be an interaction entity within 10 blocks of you", NamedTextColor.RED)); } else{ - select(player, entity.getUniqueId()); + DisplayEntitySelector.select(player, entity); } return; } @@ -55,66 +57,12 @@ public void execute(Player player, String[] args) { if (distance <= 0){ throw new IllegalArgumentException(); } - player.sendMessage(Component.text("Finding entities within "+distance+" blocks...", NamedTextColor.YELLOW)); - getSelectableEntities(player, distance); + player.sendMessage(Component.empty()); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Finding display entities within "+distance+" blocks...", NamedTextColor.YELLOW))); + RelativePointUtils.spawnDisplayEntityPoints(distance, player); } catch(IllegalArgumentException e){ player.sendMessage(Component.text("Invalid input! Enter a positive number for the distance, or -target to select a targeted Interaction entity", NamedTextColor.RED)); } } - - private void getSelectableEntities(Player player, double distance){ - List parts = DisplayUtils.getUngroupedPartEntities(player.getLocation(), distance); - if (parts.isEmpty()){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("No nearby ungrouped entities found!", NamedTextColor.RED))); - player.sendMessage(Component.text("| Ensure that any nearby ungrouped entities do not have passengers", NamedTextColor.GRAY, TextDecoration.ITALIC)); - return; - } - - if (parts.size() == 1){ - select(player, parts.getFirst().getUniqueId()); - player.sendMessage(PartsCycleCMD.getPartInfo(parts.getFirst()).color(NamedTextColor.GRAY)); - return; - } - - player.sendMessage(Component.text("| Entities found! Click to select.", NamedTextColor.GREEN).appendNewline()); - for (Entity e : parts){ - UUID entityUUID = e.getUniqueId(); - SpawnedDisplayEntityPart.PartType partType = SpawnedDisplayEntityPart.PartType.getType(e); - String coords = ConversionUtils.getCoordinateString(e.getLocation()); - Component comp = Component.text("- "+partType.name()+": ") - .append(PartsCycleCMD.getPartInfo(e)) - .hoverEvent(HoverEvent.showText(Component.text("Location: ", NamedTextColor.AQUA).append(Component.text(coords, NamedTextColor.YELLOW)))) - .clickEvent(ClickEvent.callback(audience -> { - Player p = (Player) audience; - select(p, entityUUID); - }, ClickCallback.Options.builder().uses(ClickCallback.UNLIMITED_USES).lifetime(Duration.ofMinutes(10)).build())); - player.sendMessage(comp); - } - } - - private void select(Player player, UUID entityUUID){ - SpawnedDisplayEntityPart existing = SpawnedDisplayEntityPart.getPart(Bukkit.getEntity(entityUUID)); - if (existing != null){ - player.sendMessage(Component.text("That part is already in a group!", NamedTextColor.RED)); - player.sendMessage(Component.text("| Select the group, then cycle through the group's parts", NamedTextColor.GRAY)); - return; - } - - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.create(entityUUID); - if (part == null){ - player.sendMessage(Component.text("That entity is no longer valid!", NamedTextColor.RED)); - return; - } - DEUUser - .getOrCreateUser(player) - .setSelectedPartSelection(new SinglePartSelection(part), false); - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - part.markInteraction(player, 30); - } - else{ - part.glow(player, 30); - } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Part Entity Selected!", NamedTextColor.GREEN))); - } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java new file mode 100644 index 00000000..839dc610 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java @@ -0,0 +1,68 @@ +package net.donnypz.displayentityutils.utils.relativepoints; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.utils.DisplayEntities.RelativePoint; +import net.donnypz.displayentityutils.utils.DisplayEntities.SinglePartSelection; +import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Material; +import org.bukkit.entity.Display; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +public class DisplayEntitySelector extends RelativePointSelector { + + Display display; + + DisplayEntitySelector(Player player, Display display){ + super(player, + DisplayUtils.getModelLocation(display), + null, + Material.LIME_STAINED_GLASS, + display.getTransformation()); + this.display = display; + } + + @Override + public boolean removeFromPointHolder() { + return true; + } + + @Override + public void sendInfo(Player player) { + player.sendMessage(MiniMessage.miniMessage().deserialize("Entity Type: " + display.getType().name())); + player.sendMessage(MiniMessage.miniMessage().deserialize("Persistent: "+(display.isPersistent() ? "TRUE" : "FALSE"))); + } + + @Override + public void rightClick(Player player) { + DisplayAPI.getScheduler().run(() -> { + select(player, display); + }); + } + + public static void select(Player player, Entity entity){ + SpawnedDisplayEntityPart existing = SpawnedDisplayEntityPart.getPart(entity); + if (existing != null){ + player.sendMessage(Component.text("That part is already in a group!", NamedTextColor.RED)); + player.sendMessage(Component.text("| Select the group, then cycle through the group's parts", NamedTextColor.GRAY)); + return; + } + + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.create(entity.getUniqueId()); + if (part == null){ + player.sendMessage(Component.text("That entity is no longer valid!", NamedTextColor.RED)); + return; + } + DEUUser + .getOrCreateUser(player) + .setSelectedPartSelection(new SinglePartSelection(part), false); + part.glow(player, 30); + RelativePointUtils.removeRelativePoints(player); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text((entity instanceof Display ? "Display" : "Interaction")+" Entity Selected!", NamedTextColor.GREEN))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java index e460b57f..f89a8f9b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java @@ -5,11 +5,8 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Player; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -@ApiStatus.Internal -@ApiStatus.Experimental public class GroupPointSelector extends RelativePointSelector { SpawnedDisplayEntityGroup group; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java index 5cdac536..5217084b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java @@ -67,7 +67,6 @@ public void rightClick(Player player) { boolean selectResult = DisplayGroupManager.setSelectedGroup(player, group); if (selectResult){ group.glowAndMarkInteractions(player, 40); - RelativePointUtils.deselectRelativePoint(player); RelativePointUtils.removeRelativePoints(player); player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Selected the clicked point's packet-based group!"))); player.playSound(spawnLocation, Sound.UI_STONECUTTER_TAKE_RESULT, 1, 2f); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java index af858f17..245dfa3e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java @@ -11,6 +11,7 @@ import org.bukkit.entity.Display; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Transformation; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -61,6 +62,34 @@ public abstract class RelativePointSelector { this.relativePoint = relativePoint; } + RelativePointSelector(Player player, Location spawnLocation, T relativePoint, Material itemType, Transformation transformation){ + Vector3f scaleVector = transformation.getScale(); + float xInteractionScale = scaleVector.x+0.075f; + float yInteractionScale = scaleVector.y+0.075f; + float zInteractionScale = scaleVector.z+0.075f; + this.playerUUID = player.getUniqueId(); + ItemStack stack = new ItemStack(itemType); + displayPart = new PacketAttributeContainer() + .setAttribute(DisplayAttributes.Transform.LEFT_ROTATION, transformation.getLeftRotation()) + .setAttribute(DisplayAttributes.Transform.SCALE, transformation.getScale().add(0.05f, 0.05f, 0.05f)) + .setAttribute(DisplayAttributes.GLOW_COLOR_OVERRIDE, Color.BLACK) + .setAttribute(DisplayAttributes.GLOWING, true) + .setAttribute(DisplayAttributes.BRIGHTNESS, new Display.Brightness(15,15)) + .setAttribute(DisplayAttributes.ItemDisplay.ITEMSTACK, stack) + .createPart(SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY, spawnLocation, pointDisplayTag); + displayPart.showToPlayer(player, GroupSpawnedEvent.SpawnReason.INTERNAL); + + selectPart = new PacketAttributeContainer() + .setAttribute(DisplayAttributes.Interaction.WIDTH, Math.max(xInteractionScale, zInteractionScale)) + .setAttribute(DisplayAttributes.Interaction.HEIGHT, yInteractionScale) + .createPart(SpawnedDisplayEntityPart.PartType.INTERACTION, spawnLocation.clone().subtract(0, yInteractionScale/2, 0), pointDisplayTag); + selectPart.showToPlayer(player, GroupSpawnedEvent.SpawnReason.INTERNAL); + + interactionParts.put(selectPart, this); + + this.spawnLocation = spawnLocation; + this.relativePoint = relativePoint; + } public void select(){ if (!isValid) return; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java index 516e156e..0d4a854b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java @@ -1,11 +1,14 @@ package net.donnypz.displayentityutils.utils.relativepoints; import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.donnypz.displayentityutils.utils.DisplayUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Sound; +import org.bukkit.entity.Display; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.util.*; @@ -55,6 +58,26 @@ public static void spawnPacketGroupPoints(Chunk chunk, Player player){ } } + public static void spawnDisplayEntityPoints(double distance, Player player){ + removeRelativePoints(player); + Set> displays = new HashSet<>(); + for (Entity e : player.getNearbyEntities(distance, distance, distance)){ + if (DisplayUtils.isInGroup(e)) continue; + DisplayEntitySelector selector; + if (e instanceof Display d){ + selector = new DisplayEntitySelector(player, d); + displays.add(selector); + } + } + if (displays.isEmpty()){ + player.sendMessage(Component.text("Failed to find ungrouped Display entities within the given range!", NamedTextColor.RED)); + } + else{ + setDisplays(player, displays); + player.sendMessage(Component.text("| Right click a point to select an entity", NamedTextColor.AQUA)); + } + } + public static boolean removeRelativePoints(Player player){ if (player == null) return false; Set> selectors = RelativePointUtils.relativePointSelectors.remove(player.getUniqueId()); From 41083bc7a9eb2846ac0b40ff9f08d8f7a8e16b88 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 16 Dec 2025 21:01:15 -0600 Subject: [PATCH 010/139] Remove unused GroupPoints --- .../utils/DisplayEntities/GroupPoint.java | 28 ------------- .../relativepoints/GroupPointSelector.java | 40 ------------------- 2 files changed, 68 deletions(-) delete mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupPoint.java delete mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupPoint.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupPoint.java deleted file mode 100644 index 9e2d5adb..00000000 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupPoint.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.donnypz.displayentityutils.utils.DisplayEntities; - -import org.bukkit.Location; -import org.bukkit.util.Vector; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.joml.Vector3f; - -import java.io.Serializable; - -@ApiStatus.Experimental -public class GroupPoint extends RelativePoint implements Serializable { - public GroupPoint(@NotNull String pointTag, @NotNull SpawnedDisplayEntityGroup group, @NotNull Location location) { - super(pointTag, group, location); - } - - GroupPoint(@NotNull String pointTag, @NotNull Vector vector, float initialYaw, float initialPitch) { - super(pointTag, vector, initialYaw, initialPitch); - } - - GroupPoint(@NotNull String pointTag, @NotNull Vector3f vector, float initialYaw, float initialPitch) { - super(pointTag, vector, initialYaw, initialPitch); - } - - protected GroupPoint(@NotNull GroupPoint point) { - super(point); - } -} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java deleted file mode 100644 index f89a8f9b..00000000 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.donnypz.displayentityutils.utils.relativepoints; - -import net.donnypz.displayentityutils.utils.DisplayEntities.GroupPoint; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -public class GroupPointSelector extends RelativePointSelector { - SpawnedDisplayEntityGroup group; - - GroupPointSelector(Player player, Location spawnLocation, GroupPoint relativePoint, SpawnedDisplayEntityGroup group){ - super(player, spawnLocation, relativePoint, Material.ORANGE_CONCRETE); - this.group = group; - } - - @Override - public void sendInfo(@NotNull Player player) { - - } - - @Override - public void rightClick(@NotNull Player player) { - - } - - @Override - public boolean removeFromPointHolder() { - //group.relativePoints.remove(relativePoint); - return true; - } - - - @Override - public void despawn(){ - super.despawn(); - group = null; - } -} From 2238ff070ecd745566dd63aa9d82bbe6a32220fc Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 17 Dec 2025 05:09:32 -0600 Subject: [PATCH 011/139] Allow event to be called async --- .../displayentityutils/events/PrePacketGroupCreateEvent.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/PrePacketGroupCreateEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/PrePacketGroupCreateEvent.java index a542f3b6..80d51c29 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/PrePacketGroupCreateEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/PrePacketGroupCreateEvent.java @@ -3,6 +3,7 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.GroupSpawnSettings; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; @@ -23,6 +24,7 @@ public class PrePacketGroupCreateEvent extends Event implements Cancellable { private boolean isCancelled = false; public PrePacketGroupCreateEvent(DisplayEntityGroup group, GroupSpawnedEvent.SpawnReason spawnReason){ + super(!Bukkit.isPrimaryThread()); this.displayEntityGroup = group; this.spawnReason = spawnReason; } From 5e963c403dafe7a3709e4a656852ca7e3dc93333 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 17 Dec 2025 23:08:29 -0600 Subject: [PATCH 012/139] Rename AnimationSound to DEUSound --- .../managers/DisplayAnimationInputStream.java | 10 +++++- .../managers/DisplayObjectInputStream.java | 7 ++-- .../{AnimationSound.java => DEUSound.java} | 17 +++++----- .../DisplayAnimationFrame.java | 24 +++++++------- .../utils/DisplayEntities/FramePoint.java | 32 +++++++++---------- .../command/anim/AnimAddSoundCMD.java | 4 +-- 6 files changed, 50 insertions(+), 44 deletions(-) rename api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/{AnimationSound.java => DEUSound.java} (90%) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java index 43547b59..b5725474 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java @@ -1,5 +1,6 @@ package net.donnypz.displayentityutils.managers; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; import net.donnypz.displayentityutils.utils.DisplayEntities.saved.OldSound; import java.io.IOException; @@ -7,6 +8,9 @@ import java.io.ObjectStreamClass; class DisplayAnimationInputStream extends DisplayObjectInputStream{ + + private static final String ANIMATION_SOUND = "AnimationSound"; + DisplayAnimationInputStream(InputStream in) throws IOException { super(in); } @@ -14,11 +18,15 @@ class DisplayAnimationInputStream extends DisplayObjectInputStream{ @Override protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { ObjectStreamClass desc = super.readClassDescriptor(); - if (desc.getName().equals("org.bukkit.Sound")){ //Because of old sound HashMaps using an enum + String name = desc.getName(); + if (name.equals("org.bukkit.Sound")){ //Because of old sound HashMaps using an enum //if (VersionUtils.is_1_21_2){ return ObjectStreamClass.lookup(OldSound.class); //} } + if (name.endsWith(ANIMATION_SOUND)){ + return ObjectStreamClass.lookup(DEUSound.class); + } return desc; } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java index 86fa2287..03bf9117 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java @@ -7,7 +7,7 @@ class DisplayObjectInputStream extends ObjectInputStream { - private static final String oldPackage = "com.pzdonny"; + private static final String OLD_PACKAGE = "com.pzdonny"; DisplayObjectInputStream(InputStream in) throws IOException { super(in); } @@ -17,10 +17,9 @@ protected Class resolveClass(ObjectStreamClass desc) throws ClassNotFoundExce //Convert Old Serialized Objects with new package name String name = desc.getName(); - if (name.startsWith(oldPackage)) { - name = "net.donnypz" + name.substring(oldPackage.length()); + if (name.startsWith(OLD_PACKAGE)) { + name = "net.donnypz" + name.substring(OLD_PACKAGE.length()); } - return Class.forName(name); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationSound.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUSound.java similarity index 90% rename from api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationSound.java rename to api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUSound.java index 32a6c9b1..2658d994 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationSound.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUSound.java @@ -12,7 +12,7 @@ import java.util.Collection; @ApiStatus.Internal -public class AnimationSound implements Externalizable, Cloneable { +public class DEUSound implements Externalizable, Cloneable { transient Sound sound; String soundName; float volume; @@ -24,27 +24,26 @@ public class AnimationSound implements Externalizable, Cloneable { private static final long serialVersionUID = 0; @ApiStatus.Internal - public AnimationSound(){} + public DEUSound(){} - public AnimationSound(@NotNull String soundName, float volume, float pitch, int delayInTicks){ + public DEUSound(@NotNull String soundName, float volume, float pitch, int delayInTicks){ this.soundName = soundName; this.volume = volume; this.pitch = pitch; this.delay = delayInTicks; this.sound = VersionUtils.getSound(soundName); - existsInGameVersion = this.sound != null; + this.existsInGameVersion = this.sound != null; } - public AnimationSound(@NotNull Sound sound, float volume, float pitch, int delayInTicks){ + public DEUSound(@NotNull Sound sound, float volume, float pitch, int delayInTicks){ this.sound = sound; this.soundName = sound.getKey().getKey(); this.volume = volume; this.pitch = pitch; this.delay = delayInTicks; - this.existsInGameVersion = true; } - public AnimationSound(@NotNull AnimationSound sound){ + public DEUSound(@NotNull DEUSound sound){ this.sound = sound.sound; this.soundName = sound.soundName; this.volume = sound.volume; @@ -175,9 +174,9 @@ public boolean existsInGameVersion() { } @Override - public AnimationSound clone() { + public DEUSound clone() { try { - return (AnimationSound) super.clone(); + return (DEUSound) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java index f4f1020f..0aeb0726 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java @@ -28,8 +28,8 @@ public final class DisplayAnimationFrame implements Serializable { HashMap startSoundMap; HashMap endSoundMap; - HashMap startSounds; - HashMap endSounds; + HashMap startSounds; + HashMap endSounds; transient Set frameStartParticles; transient Set frameEndParticles; @@ -79,9 +79,9 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ //Start Sounds if (startSounds != null){ - for (Map.Entry entry : startSounds.entrySet()){ + for (Map.Entry entry : startSounds.entrySet()){ String soundName = entry.getKey(); - AnimationSound sound = entry.getValue(); + DEUSound sound = entry.getValue(); sound.delay = 0; point.sounds.put(soundName, sound); } @@ -89,9 +89,9 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ //End Sounds if (endSounds != null){ - for (Map.Entry entry : endSounds.entrySet()){ + for (Map.Entry entry : endSounds.entrySet()){ String soundName = entry.getKey(); - AnimationSound sound = entry.getValue(); + DEUSound sound = entry.getValue(); sound.delay = duration; point.sounds.put(soundName, sound); } @@ -177,25 +177,25 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo void repairOldSounds(){ - HashMap map1 = handleOldSoundMaps(startSoundMap, 0); + HashMap map1 = handleOldSoundMaps(startSoundMap, 0); if (!map1.isEmpty()){ if (startSounds == null) startSounds = new HashMap<>(); startSounds.putAll(map1); } - HashMap map2 = handleOldSoundMaps(endSoundMap, duration); + HashMap map2 = handleOldSoundMaps(endSoundMap, duration); if (!map2.isEmpty()){ if (endSounds == null) endSounds = new HashMap<>(); endSounds.putAll(map2); } } - private HashMap handleOldSoundMaps(HashMap soundMap, int delayInTicks) { + private HashMap handleOldSoundMaps(HashMap soundMap, int delayInTicks) { if (soundMap == null || soundMap.isEmpty()){ return new HashMap<>(); } - HashMap convertedMap = new HashMap<>(); + HashMap convertedMap = new HashMap<>(); for (Map.Entry entry : soundMap.entrySet()) { OldSound sound = entry.getKey(); Float[] values = entry.getValue(); @@ -204,10 +204,10 @@ private HashMap handleOldSoundMaps(HashMap particles = new HashSet<>(); - Map sounds = new HashMap<>(); + Map sounds = new HashMap<>(); @Serial private static final long serialVersionUID = 99L; @@ -44,7 +44,7 @@ public FramePoint(@NotNull FramePoint point) { for (AnimationParticle p : point.particles){ this.particles.add(p.clone()); } - for (Map.Entry entry : point.sounds.entrySet()){ + for (Map.Entry entry : point.sounds.entrySet()){ this.sounds.put(entry.getKey(), entry.getValue().clone()); } } @@ -234,7 +234,7 @@ public void showParticles(@NotNull Location location){ * @param limited whether to limit the played audio only to players who can visibly see the group */ public void playSounds(@NotNull ActiveGroup group, @Nullable DisplayAnimator animator, boolean limited){ - for (AnimationSound sound : sounds.values()){ + for (DEUSound sound : sounds.values()){ if (limited){ sound.playSound(getLocation(group), group, animator, getPlayers(group)); } @@ -252,7 +252,7 @@ public void playSounds(@NotNull ActiveGroup group, @Nullable DisplayAnimator * @param limited whether to limit the played audio only to players who can visibly see the group */ public void playSounds(@NotNull ActiveGroup group, @NotNull Location location, @Nullable DisplayAnimator animator, boolean limited){ - for (AnimationSound sound : sounds.values()){ + for (DEUSound sound : sounds.values()){ if (limited){ sound.playSound(location, group, animator, getPlayers(group)); } @@ -284,7 +284,7 @@ public void playSounds(@NotNull ActiveGroup group, boolean limited){ * @param player the player */ public void playSounds(@NotNull Location location, @NotNull Player player){ - for (AnimationSound sound : sounds.values()){ + for (DEUSound sound : sounds.values()){ sound.playSound(location, player); } } @@ -295,7 +295,7 @@ public void playSounds(@NotNull Location location, @NotNull Player player){ * @param players the players */ public void playSounds(@NotNull Location location, @NotNull Collection players){ - for (AnimationSound sound : sounds.values()){ + for (DEUSound sound : sounds.values()){ sound.playSound(location, players); } } @@ -323,23 +323,23 @@ public void playSounds(@NotNull ActiveGroup group, @NotNull Collection getParticles(){ } /** - * Get the {@link AnimationSound}s that will be played at this frame point - * @return a collection of {@link AnimationSound} + * Get the {@link DEUSound}s that will be played at this frame point + * @return a collection of {@link DEUSound} */ - public Collection getSounds(){ + public Collection getSounds(){ return sounds.values(); } @@ -440,7 +440,7 @@ public void sendInfo(Player player){ player.sendMessage(Component.text("| NONE", NamedTextColor.GRAY)); } else{ - for (AnimationSound sound : sounds.values()){ + for (DEUSound sound : sounds.values()){ Component msgComp = Component.text("- "+sound.getSoundName(), NamedTextColor.YELLOW); Component hoverComp = Component.text("| Vol: "+sound.getVolume()+", Pitch: "+sound.getPitch(), NamedTextColor.GRAY); if (!sound.existsInGameVersion()){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java index af8febcd..c144c3f8 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java @@ -5,7 +5,7 @@ import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayAnimationManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.AnimationSound; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayAnimation; import net.donnypz.displayentityutils.utils.relativepoints.FramePointSelector; import net.donnypz.displayentityutils.utils.relativepoints.RelativePointSelector; @@ -56,7 +56,7 @@ public void execute(Player player, String[] args) { float pitch = Float.parseFloat(args[4]); int delayInTicks = Integer.parseInt(args[5]); - display.getRelativePoint().addSound(new AnimationSound(sound, volume, pitch, delayInTicks)); + display.getRelativePoint().addSound(new DEUSound(sound, volume, pitch, delayInTicks)); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Sound Added to Frame Point!", NamedTextColor.GREEN))); player.sendMessage(MiniMessage.miniMessage().deserialize("| Sound: "+sound)); From 3c7123d6b47386ecbca4da691e5b5f1c2e4dedd3 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 17 Dec 2025 23:09:32 -0600 Subject: [PATCH 013/139] Rename DEGJSONAdapter to DEUJsonAdapter --- .../displayentityutils/managers/DisplayAnimationManager.java | 2 +- .../displayentityutils/managers/DisplayGroupManager.java | 4 ++-- .../{DEGJSONAdapter.java => DEUJSONAdapter.java} | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/{DEGJSONAdapter.java => DEUJSONAdapter.java} (88%) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java index c2e92657..e061482a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java @@ -384,7 +384,7 @@ private static DisplayAnimation getAnimationFromJson(JsonObject jsonObject){ DisplayGroupManager.deserializeJsonElement(jsonObject); jsonObject.remove(DisplayGroupManager.PLUGIN_VERSION_FIELD); - return DEGJSONAdapter + return DEUJSONAdapter .GSON .fromJson(jsonObject, DisplayAnimation.class); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java index b995b99d..79e9209f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java @@ -208,7 +208,7 @@ public static boolean saveDisplayEntityGroupJson(@NotNull DisplayEntityGroup dis saveFile.createNewFile(); FileWriter fileWriter = new FileWriter(saveFile); - Gson gson = DEGJSONAdapter.GSON; + Gson gson = DEUJSONAdapter.GSON; JsonElement jsonEl = gson.toJsonTree(displayEntityGroup); JsonObject jsonObj = jsonEl.getAsJsonObject(); @@ -488,7 +488,7 @@ private static DisplayEntityGroup getGroupFromJson(JsonObject jsonObject){ deserializeJsonElement(jsonObject); jsonObject.remove(PLUGIN_VERSION_FIELD); - return DEGJSONAdapter + return DEUJSONAdapter .GSON .fromJson(jsonObject, DisplayEntityGroup.class); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEGJSONAdapter.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUJSONAdapter.java similarity index 88% rename from api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEGJSONAdapter.java rename to api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUJSONAdapter.java index b083adce..3e38ac9f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEGJSONAdapter.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUJSONAdapter.java @@ -3,7 +3,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -public final class DEGJSONAdapter { +public final class DEUJSONAdapter { public static final Gson GSON = new GsonBuilder() .registerTypeAdapter(DisplayEntity.class, new JSONAdapter_DisplayEntity()) @@ -11,5 +11,5 @@ public final class DEGJSONAdapter { .registerTypeHierarchyAdapter(FramePoint.class, new JSONAdapter_FramePoint()) .create(); - private DEGJSONAdapter(){} + private DEUJSONAdapter(){} } From e46bed1880c1e73205a6a40974926551b6a594ba Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 17 Dec 2025 23:50:31 -0600 Subject: [PATCH 014/139] Add placeable groups --- .../displayentityutils/DisplayAPI.java | 25 +- .../events/GroupSpawnedEvent.java | 1 + .../events/ItemPlaceGroupEvent.java | 62 +++++ .../events/PreItemPlaceGroupEvent.java | 76 ++++++ .../managers/PlaceableGroupManager.java | 244 ++++++++++++++++++ .../utils/DisplayUtils.java | 6 +- .../DisplayEntityPlugin.java | 11 +- .../command/DisplayEntityPluginCommand.java | 7 +- .../command/Permission.java | 5 + .../command/place/PlaceCMD.java | 68 +++++ .../command/place/PlaceHelpCMD.java | 27 ++ .../command/place/PlaceSetCMD.java | 41 +++ .../command/place/PlaceSetPermissionCMD.java | 35 +++ .../command/place/PlaceTogglePacketCMD.java | 36 +++ .../place/PlaceTogglePlayerFacingCMD.java | 33 +++ .../command/place/PlaceUnsetCMD.java | 26 ++ .../place/PlaceUnsetPermissionCMD.java | 32 +++ .../player/DEUPlayerPlaceBlockListener.java | 44 ++++ 18 files changed, 764 insertions(+), 15 deletions(-) create mode 100644 api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java create mode 100644 api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java create mode 100644 api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceHelpCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetPermissionCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java index ecee2a1f..aae13161 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java +++ b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java @@ -27,6 +27,10 @@ public final class DisplayAPI { static NamespacedKey spawnAnimationTypeKey; static NamespacedKey spawnAnimationLoadMethodKey; static NamespacedKey chunkPacketGroupsKey; + static NamespacedKey placeableGroupKey; + static NamespacedKey placeableGroupPacketBasedKey; + static NamespacedKey placeableGroupPermissionKey; + static NamespacedKey placeableGroupRespectFacingKey; static boolean isMythicMobsInstalled; static boolean isLibsDisguisesInstalled; @@ -85,10 +89,23 @@ private DisplayAPI(){} return chunkPacketGroupsKey; } - /** - * Used for older versions of DisplayEntityUtils Plugin - * This will NEVER have to be called manually - */ + public static @NotNull NamespacedKey getPlaceableGroupKey(){ + return placeableGroupKey; + } + + public static @NotNull NamespacedKey getPlaceableGroupPacketBasedKey(){ + return placeableGroupPacketBasedKey; + } + + public static @NotNull NamespacedKey getPlaceableGroupPermissionKey(){ + return placeableGroupPermissionKey; + } + + public static @NotNull NamespacedKey getPlaceableGroupRespectFacing(){ + return placeableGroupRespectFacingKey; + } + + @ApiStatus.Internal public static String getLegacyPartTagPrefix(){ return legacyPartTagPrefix; diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java index 95de4314..722419a6 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java @@ -54,6 +54,7 @@ public enum SpawnReason{ */ PLAYER_SENT_CHUNK, PLAYER_SENT_PASSENGER_GROUP, + ITEMSTACK, SKRIPT, INTERNAL; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java new file mode 100644 index 00000000..02b291c4 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java @@ -0,0 +1,62 @@ +package net.donnypz.displayentityutils.events; + +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Called when a player places an {@link ActiveGroup} using an item that + * has an assigned group through {@link PlaceableGroupManager#assign(ItemStack, String, boolean)} (ItemStack, String)} or similar methods. + */ +public class ItemPlaceGroupEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + ActiveGroup activeGroup; + ItemStack itemStack; + Player player; + + public ItemPlaceGroupEvent(@NotNull ActiveGroup group, @NotNull ItemStack itemStack, @Nullable Player player){ + super(!Bukkit.isPrimaryThread()); + this.activeGroup = group; + this.itemStack = itemStack; + this.player = player; + } + + /** + * Get the {@link ActiveGroup} involved in this event. + * @return a {@link ActiveGroup} + */ + public @NotNull ActiveGroup getGroup() { + return activeGroup; + } + + /** + * Get the {@link ItemStack} invovled in this event. + * @return an item + */ + public @NotNull ItemStack getItemStack() { + return itemStack; + } + + /** + * Get the player involved in this event + * @return a player + */ + public @Nullable Player getPlayer() { + return player; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java new file mode 100644 index 00000000..cf1eea2e --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java @@ -0,0 +1,76 @@ +package net.donnypz.displayentityutils.events; + +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Called before the stored {@link DisplayEntityGroup} on an item can be spawned when a player places the item's block or when + * {@link PlaceableGroupManager#spawnGroup(ItemStack, Location, Player)} is called. + */ +public class PreItemPlaceGroupEvent extends Event implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + DisplayEntityGroup group; + ItemStack itemStack; + Player player; + + private boolean isCancelled = false; + + public PreItemPlaceGroupEvent(@Nullable DisplayEntityGroup group, @NotNull ItemStack itemStack, @Nullable Player player){ + super(!Bukkit.isPrimaryThread()); + this.group = group; + this.itemStack = itemStack; + this.player = player; + } + + /** + * Get the {@link DisplayEntityGroup} involved in this event. + * @return a {@link DisplayEntityGroup} or null if the item's group could not be found + */ + public @Nullable DisplayEntityGroup getGroup() { + return group; + } + + /** + * Get the {@link ItemStack} involved in this event. + * @return an {@link ItemStack} + */ + public @NotNull ItemStack getItemStack() { + return itemStack; + } + + /** + * Get the player involved in this event + * @return a player + */ + public @Nullable Player getPlayer() { + return player; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public boolean isCancelled() { + return isCancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.isCancelled = cancel; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java new file mode 100644 index 00000000..73f81697 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -0,0 +1,244 @@ +package net.donnypz.displayentityutils.managers; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.events.GroupSpawnedEvent; +import net.donnypz.displayentityutils.events.ItemPlaceGroupEvent; +import net.donnypz.displayentityutils.events.PreItemPlaceGroupEvent; +import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public final class PlaceableGroupManager { + + private PlaceableGroupManager(){} + + /** + * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. + * @param itemStack the item + * @param groupTag the tag of the group that will be associated with the item + * @throws IllegalArgumentException if the given itemstack is not a block + */ + public static void assign(@NotNull ItemStack itemStack, @NotNull String groupTag, boolean spawnUsingPackets){ + if (!itemStack.getType().isBlock()){ + throw new IllegalArgumentException("The provided ItemStack is not a block type"); + } + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); + pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, spawnUsingPackets); + pdc.set(DisplayAPI.getPlaceableGroupRespectFacing(), PersistentDataType.BOOLEAN, true); + itemStack.setItemMeta(meta); + } + + /** + * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. + * @param itemStack the item + * @param group the group that will be associated with the item + * @throws IllegalArgumentException if the item is not a block + */ + public static void assign(@NotNull ItemStack itemStack, @NotNull DisplayEntityGroup group, boolean spawnUsingPackets){ + assign(itemStack, group.getTag(), spawnUsingPackets); + } + + /** + * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. + * @param itemStack the item + * @param groupTag the tag of the group that will be associated with the item + * @throws IllegalArgumentException if the given itemstack is not a block + */ + public static void assign(@NotNull ItemStack itemStack, @NotNull String groupTag, boolean spawnUsingPackets, @NotNull String placePermission){ + if (!itemStack.getType().isBlock()){ + throw new IllegalArgumentException("The provided ItemStack is not a block type"); + } + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); + pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, spawnUsingPackets); + pdc.set(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING, placePermission); + pdc.set(DisplayAPI.getPlaceableGroupRespectFacing(), PersistentDataType.BOOLEAN, true); + itemStack.setItemMeta(meta); + } + + /** + * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. + * @param itemStack the item + * @param group the group that will be associated with the item + * @throws IllegalArgumentException if the item is not a block + */ + public static void assign(@NotNull ItemStack itemStack, @NotNull DisplayEntityGroup group, boolean spawnUsingPackets, @NotNull String placePermission){ + assign(itemStack, group.getTag(), spawnUsingPackets, placePermission); + } + + /** + * Unassign a {@link DisplayEntityGroup} from an {@link ItemStack} + * @param itemStack the item + */ + public static void unassign(@NotNull ItemStack itemStack){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.remove(DisplayAPI.getPlaceableGroupKey()); + pdc.remove(DisplayAPI.getPlaceableGroupPacketBasedKey()); + pdc.remove(DisplayAPI.getPlaceableGroupPermissionKey()); + pdc.remove(DisplayAPI.getPlaceableGroupRespectFacing()); + itemStack.setItemMeta(meta); + } + + /** + * Check if a item has an assigned {@link DisplayEntityGroup} + * @param itemStack the item + * @return a boolean + */ + public static boolean hasAssignedGroup(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return pdc.has(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING); + } + + /** + * Get the tag of the group assigned to an {@link ItemStack} + * @param itemStack the item + * @return the group's tag or null + */ + public static @Nullable String getAssignedGroupTag(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return pdc.get(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING); + } + + /** + * Get the {@link DisplayEntityGroup} assigned to an {@link ItemStack} based on the group tag stored on the item + * @param itemStack the item + * @return the group's tag or null + */ + public static @Nullable DisplayEntityGroup getAssignedGroup(@NotNull ItemStack itemStack){ + String tag = getAssignedGroupTag(itemStack); + return tag == null ? null : DisplayGroupManager.getGroup(tag); + } + + /** + * Set whether the group associated with the given item should spawn as a {@link PacketDisplayEntityGroup} + * @param itemStack the item + * @param packet whether the group should spawn pack-based + */ + public static void setSpawnPacketGroup(@NotNull ItemStack itemStack, boolean packet){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, packet); + itemStack.setItemMeta(meta); + } + + /** + * Get whether the group associated with the given item will spawn as a {@link PacketDisplayEntityGroup} + * @param itemStack the item + * @return a boolean + */ + public static boolean isSpawningPacketGroup(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN)); + } + + /** + * Set the permission a player needs to place an itemstack's assigned group. Set the permission to {@code null} to unset it + * @param itemStack the item + * @param placePermission the permission + */ + public static void setPlacePermission(@NotNull ItemStack itemStack, @Nullable String placePermission){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + if (placePermission == null){ + pdc.remove(DisplayAPI.getPlaceableGroupPermissionKey()); + } + else{ + pdc.set(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING, placePermission); + } + itemStack.setItemMeta(meta); + } + + /** + * Check if an itemstack has a place permission, determining if a player can place its assigned group + * @param itemStack the itemstack + * @return a boolean + */ + public static boolean hasPlacePermission(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return pdc.has(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING); + } + + /** + * Get the permission that determines whether a player can place an itemstack's assigned group + * @param itemStack the item + * @return a String or null + */ + public static @Nullable String getPlacePermission(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return pdc.get(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING); + } + + /** + * Check if the given player has permission to place the itemstack's assigned group + * @param itemStack the item + * @param player the player + * @return a boolean + */ + public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player player){ + String placePerm = getPlacePermission(itemStack); + if (placePerm == null) return true; + return player.hasPermission(placePerm); + } + + /** + * Set whether the group associated with the given item should spawn with respect to the player's facing direction + * @param itemStack the item + * @param respect whether the group should respect the player's facing direction + */ + public static void setRespectPlayerFacing(@NotNull ItemStack itemStack, boolean respect){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.set(DisplayAPI.getPlaceableGroupRespectFacing(), PersistentDataType.BOOLEAN, respect); + itemStack.setItemMeta(meta); + } + + /** + * Get whether the group associated with the given item will respect the player's facing direction + * @param itemStack the item + * @return a boolean + */ + public static boolean isRespectingPlayerFacing(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupRespectFacing(), PersistentDataType.BOOLEAN)); + } + + + /** + * Spawn the {@link DisplayEntityGroup} associated with an item at a location + * @param itemStack the item + * @param spawnLocation the spawn location + */ + public static void spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @Nullable Player itemHolder){ + String tag = getAssignedGroupTag(itemStack); + boolean isPacket = isSpawningPacketGroup(itemStack); + if (tag == null) return; + DisplayAPI.getScheduler().runAsync(() -> { + DisplayEntityGroup group = DisplayGroupManager.getGroup(tag); + if (!new PreItemPlaceGroupEvent(group, itemStack, itemHolder).callEvent()) return; + if (group == null) return; + if (isPacket){ + PacketDisplayEntityGroup pg = group.createPacketGroup(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK, true, true); + pg.setPersistent(true); + new ItemPlaceGroupEvent(pg, itemStack, itemHolder).callEvent(); + } + else{ + DisplayAPI.getScheduler().run(() -> { + SpawnedDisplayEntityGroup sg = group.spawn(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK); + new ItemPlaceGroupEvent(sg, itemStack, itemHolder).callEvent(); + }); + } + }); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java index b8000b5c..071ff44a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java @@ -4,10 +4,7 @@ import net.donnypz.displayentityutils.DisplayConfig; import net.donnypz.displayentityutils.events.PartTranslateEvent; import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; -import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityPart; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.donnypz.displayentityutils.utils.version.folia.FoliaUtils; import net.donnypz.displayentityutils.utils.version.folia.Scheduler; import org.bukkit.Location; @@ -1034,5 +1031,4 @@ public static boolean isMaster(Display display){ } - } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index e2a46f49..9bda1190 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -11,10 +11,7 @@ import net.donnypz.displayentityutils.listeners.entity.DEUEntityListener; import net.donnypz.displayentityutils.listeners.entity.DEUInteractionListener; import net.donnypz.displayentityutils.listeners.entity.mythic.DEUMythicListener; -import net.donnypz.displayentityutils.listeners.player.DEUPlayerChatListener; -import net.donnypz.displayentityutils.listeners.player.DEUPlayerConnectionListener; -import net.donnypz.displayentityutils.listeners.player.DEUPlayerPacketListener; -import net.donnypz.displayentityutils.listeners.player.DEUPlayerWorldListener; +import net.donnypz.displayentityutils.listeners.player.*; import net.donnypz.displayentityutils.managers.LocalManager; import net.donnypz.displayentityutils.managers.MYSQLManager; import net.donnypz.displayentityutils.managers.MongoManager; @@ -89,6 +86,11 @@ private void initializeNamespacedKeys(){ //DO NOT CHANGE DisplayAPI.spawnAnimationTypeKey = new NamespacedKey(this, "spawnanimationtype"); DisplayAPI.spawnAnimationLoadMethodKey = new NamespacedKey(this, "spawnanimationloader"); DisplayAPI.chunkPacketGroupsKey = new NamespacedKey(this, "chunkpacketgroups"); + DisplayAPI.placeableGroupKey = new NamespacedKey(this, "placeablegroup"); + DisplayAPI.placeableGroupPacketBasedKey = new NamespacedKey(this, "placeablegrouppacketbased"); + DisplayAPI.placeableGroupPermissionKey = new NamespacedKey(this, "placeablegroupperm"); + DisplayAPI.placeableGroupRespectFacingKey = new NamespacedKey(this, "placeblegroupfacing"); + } private void initializeDependencies(){ @@ -132,6 +134,7 @@ private void registerListeners(){ Bukkit.getPluginManager().registerEvents(new DEUEntityListener(), this); Bukkit.getPluginManager().registerEvents(new DEULoadingListeners(), this); Bukkit.getPluginManager().registerEvents(new DEUInteractionListener(), this); + Bukkit.getPluginManager().registerEvents(new DEUPlayerPlaceBlockListener(), this); } private void initializeBStats(){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java index c2ae4ec8..b67cdb34 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java @@ -7,6 +7,7 @@ import net.donnypz.displayentityutils.command.interaction.InteractionCMD; import net.donnypz.displayentityutils.command.item.ItemCMD; import net.donnypz.displayentityutils.command.parts.PartsCMD; +import net.donnypz.displayentityutils.command.place.PlaceCMD; import net.donnypz.displayentityutils.command.text.TextCMD; import net.donnypz.displayentityutils.utils.Direction; import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; @@ -46,6 +47,7 @@ public DisplayEntityPluginCommand(){ subCommands.put("item", new ItemCMD()); subCommands.put("text", new TextCMD()); subCommands.put("interaction", new InteractionCMD()); + subCommands.put("place", new PlaceCMD()); subCommands.put("anim", new AnimCMD()); subCommands.put("bdengine", new BDEngineCMD()); subCommands.put("reload", new ReloadCMD()); @@ -191,11 +193,12 @@ static void mainCommandHelp(CommandSender sender){ sender.sendMessage(DisplayAPI.pluginPrefixLong); sender.sendMessage(Component.text("v"+DisplayAPI.getVersion(), NamedTextColor.GRAY)); CMDUtils.sendCMD(sender, "/deu group", "Display Entity Models/Groups related commands"); - CMDUtils.sendCMD(sender, "/deu anim", "Animation related commands"); CMDUtils.sendCMD(sender, "/deu parts", "Commands related to the parts (individual display entities) of a Display Entity Model/Group"); CMDUtils.sendCMD(sender, "/deu item", "Commands related to the Item Display parts of a Display Entity Model/Group"); CMDUtils.sendCMD(sender, "/deu text", "Commands related to the Text Display parts of a Display Entity Model/Group"); CMDUtils.sendCMD(sender, "/deu interaction", "Commands related to manipulating Interaction entities"); + CMDUtils.sendCMD(sender, "/deu place", "Assign a Display Entity Model/Group to an block that will spawn when placed"); + CMDUtils.sendCMD(sender, "/deu anim", "Animation related commands"); CMDUtils.sendCMD(sender, "/deu listgroups [page-number]", "List all saved Display Entity Models/Groups"); CMDUtils.sendCMD(sender, "/deu listanims [page-number]", "List all saved animations"); CMDUtils.sendCMD(sender, "/deu hidepoints", "Hide any visible points (frame points, persistent packet group points, etc.)"); @@ -218,7 +221,7 @@ public List onTabComplete(CommandSender sender, Command command, String String subcmd = args[0].toLowerCase(); String current = args[1]; switch (subcmd) { - case "interaction", "anim", "group", "parts", "bdengine", "text", "item" -> { + case "interaction", "anim", "group", "parts", "bdengine", "text", "item", "place" -> { return getTabComplete(subcmd, current); } case "listgroups", "listanims" -> suggestions.addAll(DEUSubCommand.TabSuggestion.STORAGES.suggestions); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index 19c2f00c..8d8b278a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -34,6 +34,11 @@ public enum Permission { GROUP_CULLING("deu.group.culling"), GROUP_WORLD_EDIT("deu.group.worldedit"), + PLACE_SET_ITEM("deu.place.setitem"), + PLACE_TOGGLE_PACKET("deu.place.togglepacket"), + PLACE_TOGGLE_FACING("deu.place.togglefacing"), + PLACE_SET_PERMISSION("deu.place.setpermission"), + PARTS_INFO("deu.parts.info"), PARTS_CREATE("deu.parts.create"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java new file mode 100644 index 00000000..58f293e8 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -0,0 +1,68 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.*; +import net.donnypz.displayentityutils.command.item.ItemHelpCMD; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class PlaceCMD extends ConsoleUsableSubCommand { + public PlaceCMD() { + super(Permission.HELP, new ItemHelpCMD()); + new PlaceSetCMD(this); + new PlaceUnsetCMD(this); + new PlaceSetPermissionCMD(this); + new PlaceUnsetPermissionCMD(this); + new PlaceTogglePacketCMD(this); + new PlaceTogglePlayerFacingCMD(this); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 2){ + help(sender, 1); + return; + } + String arg = args[1]; + DEUSubCommand subCommand = subCommands.get(arg); + if (subCommand == null){ + help(sender, 1); + } + else{ + DisplayEntityPluginCommand.executeCommand(subCommand, sender, args); + } + } + + static void help(CommandSender sender, int page){ + sender.sendMessage(Component.empty()); + sender.sendMessage(DisplayAPI.pluginPrefixLong); + CMDUtils.sendCMD(sender, "/deu place help", "Get help for placeable groups"); + CMDUtils.sendCMD(sender, "/deu place set ", "Assign a group to your held block, which will be spawned when the block is placed"); + CMDUtils.sendCMD(sender, "/deu place unset", "Unassign a group from your held block"); + CMDUtils.sendCMD(sender, "/deu place setpermission", "Set the permission required to place the group"); + CMDUtils.sendCMD(sender, "/deu place unsetpermission", "Set the permission required to place the group"); + CMDUtils.sendCMD(sender, "/deu place togglepacket", "Toggle whether the placed group will be packet-based. True by default"); + CMDUtils.sendCMD(sender, "/deu place togglerespectfacing", "Toggle whether the placed group will respect the player's facing direction. True by default"); + sender.sendMessage(MiniMessage.miniMessage().deserialize("--------------------------")); + } + + static ItemStack getHeldItem(Player player, boolean mustBeAssigned){ + ItemStack heldItem = player.getInventory().getItemInMainHand(); + if (!heldItem.getType().isBlock() || heldItem.getType() == Material.AIR){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You must be holding a block to do this command!", NamedTextColor.RED))); + return null; + } + + if (mustBeAssigned && !PlaceableGroupManager.hasAssignedGroup(heldItem)){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item does not have an assigned group!", NamedTextColor.RED))); + return null; + } + return heldItem; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceHelpCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceHelpCMD.java new file mode 100644 index 00000000..7f60c8d9 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceHelpCMD.java @@ -0,0 +1,27 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.command.ConsoleUsableSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.item.ItemCMD; +import org.bukkit.command.CommandSender; + +public class PlaceHelpCMD extends ConsoleUsableSubCommand { + public PlaceHelpCMD() { + super(Permission.HELP); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 3){ + PlaceCMD.help(sender, 1); + } + else{ + try{ + PlaceCMD.help(sender, Integer.parseInt(args[2])); + } + catch(NumberFormatException e){ + PlaceCMD.help(sender, 1); + } + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java new file mode 100644 index 00000000..a77d731a --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java @@ -0,0 +1,41 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceSetCMD extends PlayerSubCommand { + PlaceSetCMD(@NotNull DEUSubCommand parentSubCommand) { + super("set", parentSubCommand, Permission.PLACE_SET_ITEM); + setTabComplete(2, ""); + } + + @Override + public void execute(Player player, String[] args) { + if (args.length < 3) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu place set ", NamedTextColor.RED))); + return; + } + + ItemStack heldItem = player.getInventory().getItemInMainHand(); + if (!heldItem.getType().isBlock() || heldItem.getType() == Material.AIR){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You must be holding a block to do this command!", NamedTextColor.RED))); + return; + } + + String groupTag = args[2]; + + PlaceableGroupManager.assign(heldItem, groupTag, true); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully assigned a group to your held block (Tag: "+groupTag+")"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("| The group will spawn using packets")); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java new file mode 100644 index 00000000..78c918f1 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java @@ -0,0 +1,35 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceSetPermissionCMD extends PlayerSubCommand { + PlaceSetPermissionCMD(@NotNull DEUSubCommand parentSubCommand) { + super("setpermission", parentSubCommand, Permission.PLACE_SET_PERMISSION); + setTabComplete(2, ""); + } + + @Override + public void execute(Player player, String[] args) { + if (args.length < 3) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu place setpermission ", NamedTextColor.RED))); + return; + } + + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + String permission = args[2]; + PlaceableGroupManager.setPlacePermission(heldItem, permission); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully set the permission to place your held item's assigned group (Permission: "+permission+")"))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java new file mode 100644 index 00000000..f8be4954 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java @@ -0,0 +1,36 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceTogglePacketCMD extends PlayerSubCommand { + PlaceTogglePacketCMD(@NotNull DEUSubCommand parentSubCommand) { + super("togglepacket", parentSubCommand, Permission.PLACE_TOGGLE_PACKET); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (PlaceableGroupManager.isSpawningPacketGroup(heldItem)){ + PlaceableGroupManager.setSpawnPacketGroup(heldItem, false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will no longer spawn using packets", NamedTextColor.RED))); + } + else{ + PlaceableGroupManager.setSpawnPacketGroup(heldItem, true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will spawn using packets", NamedTextColor.GREEN))); + } + PlaceableGroupManager.unassign(heldItem); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Your held item no longer has an assigned group"))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java new file mode 100644 index 00000000..18d4eb31 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java @@ -0,0 +1,33 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceTogglePlayerFacingCMD extends PlayerSubCommand { + PlaceTogglePlayerFacingCMD(@NotNull DEUSubCommand parentSubCommand) { + super("toggleplayerfacing", parentSubCommand, Permission.PLACE_TOGGLE_FACING); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (PlaceableGroupManager.isRespectingPlayerFacing(heldItem)){ + PlaceableGroupManager.setRespectPlayerFacing(heldItem, false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will no longer respect the player's facing direction", NamedTextColor.RED))); + } + else{ + PlaceableGroupManager.setRespectPlayerFacing(heldItem, true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will respect the player's facing direction", NamedTextColor.GREEN))); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetCMD.java new file mode 100644 index 00000000..b93fc065 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetCMD.java @@ -0,0 +1,26 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceUnsetCMD extends PlayerSubCommand { + PlaceUnsetCMD(@NotNull DEUSubCommand parentSubCommand) { + super("unset", parentSubCommand, Permission.PLACE_SET_ITEM); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + PlaceableGroupManager.unassign(heldItem); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Your held item no longer has an assigned group"))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetPermissionCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetPermissionCMD.java new file mode 100644 index 00000000..70d9ab23 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetPermissionCMD.java @@ -0,0 +1,32 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceUnsetPermissionCMD extends PlayerSubCommand { + PlaceUnsetPermissionCMD(@NotNull DEUSubCommand parentSubCommand) { + super("unsetpermission", parentSubCommand, Permission.PLACE_SET_PERMISSION); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (!PlaceableGroupManager.hasPlacePermission(heldItem)) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item does not have a set permission to place its group!", NamedTextColor.RED))); + return; + } + PlaceableGroupManager.setPlacePermission(heldItem, null); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Removed the set permission to your held item's group."))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java new file mode 100644 index 00000000..4e01989b --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java @@ -0,0 +1,44 @@ +package net.donnypz.displayentityutils.listeners.player; + +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.inventory.ItemStack; + + +public class DEUPlayerPlaceBlockListener implements Listener { + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlaceBlock(BlockPlaceEvent e){ + Player player = e.getPlayer(); + ItemStack heldItem = player.getInventory().getItemInMainHand(); + if (!heldItem.getType().isBlock()){ + return; + } + + if (!PlaceableGroupManager.hasAssignedGroup(heldItem)){ + return; + } + + e.setCancelled(true); + if (!PlaceableGroupManager.canPlace(heldItem, player)){ + player.sendMessage(Component.text("You do not have permission to use this!", NamedTextColor.RED)); + return; + } + + Location placeLoc = e.getBlockPlaced().getLocation(); + placeLoc.add(0.5, 0, 0.5); + + if (PlaceableGroupManager.isRespectingPlayerFacing(heldItem)){ + placeLoc.setYaw(player.getYaw()+180); + } + + PlaceableGroupManager.spawnGroup(heldItem, placeLoc, player); + } +} From dd406506586b4e301e09396200d38efeb248fac8 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 18 Dec 2025 01:27:12 -0600 Subject: [PATCH 015/139] Remove Animation input stream --- .../managers/DisplayAnimationInputStream.java | 32 ------------------- .../managers/DisplayAnimationManager.java | 4 +-- .../managers/DisplayObjectInputStream.java | 21 +++++++++++- 3 files changed, 22 insertions(+), 35 deletions(-) delete mode 100644 api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java deleted file mode 100644 index b5725474..00000000 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.donnypz.displayentityutils.managers; - -import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; -import net.donnypz.displayentityutils.utils.DisplayEntities.saved.OldSound; - -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectStreamClass; - -class DisplayAnimationInputStream extends DisplayObjectInputStream{ - - private static final String ANIMATION_SOUND = "AnimationSound"; - - DisplayAnimationInputStream(InputStream in) throws IOException { - super(in); - } - - @Override - protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { - ObjectStreamClass desc = super.readClassDescriptor(); - String name = desc.getName(); - if (name.equals("org.bukkit.Sound")){ //Because of old sound HashMaps using an enum - //if (VersionUtils.is_1_21_2){ - return ObjectStreamClass.lookup(OldSound.class); - //} - } - if (name.endsWith(ANIMATION_SOUND)){ - return ObjectStreamClass.lookup(DEUSound.class); - } - return desc; - } -} diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java index e061482a..28675070 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java @@ -252,7 +252,7 @@ private static void attemptCacheAnimation(String tag, SpawnedDisplayAnimation an } try(ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes); GZIPInputStream gzipInputStream = new GZIPInputStream(byteStream); - ObjectInputStream objIn = new DisplayAnimationInputStream(gzipInputStream) + ObjectInputStream objIn = new DisplayObjectInputStream(gzipInputStream) ){ DisplayAnimation anim = (DisplayAnimation) objIn.readObject(); @@ -277,7 +277,7 @@ private static void attemptCacheAnimation(String tag, SpawnedDisplayAnimation an //Not Compressed (Will be an older file version, before gzip compression) catch (ZipException z){ try(ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes); - ObjectInputStream objIn = new DisplayAnimationInputStream(byteStream) + ObjectInputStream objIn = new DisplayObjectInputStream(byteStream) ){ DisplayAnimation anim = (DisplayAnimation) objIn.readObject(); anim.adaptOldSounds(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java index 03bf9117..c3921046 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java @@ -1,5 +1,8 @@ package net.donnypz.displayentityutils.managers; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; +import net.donnypz.displayentityutils.utils.DisplayEntities.saved.OldSound; + import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; @@ -8,6 +11,9 @@ class DisplayObjectInputStream extends ObjectInputStream { private static final String OLD_PACKAGE = "com.pzdonny"; + private static final String NEW_PACKAGE = "net.donnypz"; + private static final String BUKKIT_SOUND_ENUM = "org.bukkit.Sound"; + private static final String ANIMATION_SOUND = "AnimationSound"; DisplayObjectInputStream(InputStream in) throws IOException { super(in); } @@ -18,8 +24,21 @@ protected Class resolveClass(ObjectStreamClass desc) throws ClassNotFoundExce //Convert Old Serialized Objects with new package name String name = desc.getName(); if (name.startsWith(OLD_PACKAGE)) { - name = "net.donnypz" + name.substring(OLD_PACKAGE.length()); + name = NEW_PACKAGE + name.substring(OLD_PACKAGE.length()); } return Class.forName(name); } + + @Override + protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { + ObjectStreamClass desc = super.readClassDescriptor(); + String name = desc.getName(); + if (name.equals(BUKKIT_SOUND_ENUM)){ //Because of old sound HashMaps using an enum + return ObjectStreamClass.lookup(OldSound.class); + } + if (name.endsWith(ANIMATION_SOUND)){ + return ObjectStreamClass.lookup(DEUSound.class); + } + return desc; + } } From 10b4069fbade59c5fd10b9c3be51a46b7812619d Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 18 Dec 2025 01:27:18 -0600 Subject: [PATCH 016/139] No changes --- .../main/java/net/donnypz/displayentityutils/DisplayAPI.java | 2 +- .../java/net/donnypz/displayentityutils/managers/DEUUser.java | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java index aae13161..95874277 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java +++ b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java @@ -121,7 +121,7 @@ public static boolean isMythicMobsInstalled() { /** * Get whether LibsDisguises is installed on this server - * @return true if MythicMobs is present + * @return true if LibsDisguises is present */ public static boolean isLibsDisguisesInstalled() { return isLibsDisguisesInstalled; diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java index dcba35bc..006670ad 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java @@ -42,8 +42,6 @@ public class DEUUser { private UUID cameraPlayerUUID; - - private DEUUser(UUID userUUID){ this.userUUID = userUUID; synchronized (userLock){ From 0094eb4ee89a6393512bcf4fc1ed8df413523dd8 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 18 Dec 2025 03:05:07 -0600 Subject: [PATCH 017/139] Use correct help command --- .../net/donnypz/displayentityutils/command/place/PlaceCMD.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java index 58f293e8..c3674854 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -2,7 +2,6 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.*; -import net.donnypz.displayentityutils.command.item.ItemHelpCMD; import net.donnypz.displayentityutils.managers.PlaceableGroupManager; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -14,7 +13,7 @@ public class PlaceCMD extends ConsoleUsableSubCommand { public PlaceCMD() { - super(Permission.HELP, new ItemHelpCMD()); + super(Permission.HELP, new PlaceHelpCMD()); new PlaceSetCMD(this); new PlaceUnsetCMD(this); new PlaceSetPermissionCMD(this); From 39c498cdd9173704a7dbcc8ae51cbf98246471a3 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 18 Dec 2025 06:56:40 -0600 Subject: [PATCH 018/139] Use DisplayEntityPluginCommand#noPartSelection instead of PartsCMD's --- .../command/DisplayEntityPluginCommand.java | 3 ++- .../displayentityutils/command/anim/AnimUseFilterCMD.java | 2 +- .../donnypz/displayentityutils/command/parts/PartsCMD.java | 5 ----- .../command/parts/PartsFilterBlocksCMD.java | 3 ++- .../command/parts/PartsFilterItemsCMD.java | 3 ++- .../displayentityutils/command/parts/PartsFilterTagsCMD.java | 4 ++-- .../command/parts/PartsFilterTypesCMD.java | 3 ++- .../displayentityutils/command/parts/PartsListTagsCMD.java | 3 ++- .../command/parts/PartsRefreshFilterCMD.java | 4 ++-- .../command/parts/PartsResetFilterCMD.java | 5 ++--- 10 files changed, 17 insertions(+), 18 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java index b67cdb34..60fd6799 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java @@ -119,8 +119,9 @@ public static void disallowPacketGroup(Player player){ } public static void noPartSelection(Player player){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have not selected a part!", NamedTextColor.RED))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have not selected any part(s)!", NamedTextColor.RED))); player.sendMessage(Component.text("/deu parts cycle ", NamedTextColor.GRAY)); + player.sendMessage(Component.text("/deu parts select ", NamedTextColor.GRAY)); } public static void invalidTag(Player player, String tag){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimUseFilterCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimUseFilterCMD.java index ef6b39ce..535fec15 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimUseFilterCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimUseFilterCMD.java @@ -35,7 +35,7 @@ public void execute(Player player, String[] args) { ActivePartSelection selection = DisplayGroupManager.getPartSelection(player); if (selection == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java index 5755d122..fe9a7f98 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java @@ -111,11 +111,6 @@ else if (page == 4){ sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } - public static void noPartSelection(Player player){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have not selected any part(s)!", NamedTextColor.RED))); - player.sendMessage(Component.text("/deu parts cycle ", NamedTextColor.GRAY)); - } - public static void invalidPartSelection(CommandSender sender){ sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your part selection is invalid!", NamedTextColor.RED))); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterBlocksCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterBlocksCMD.java index a689ab76..fe565b5d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterBlocksCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterBlocksCMD.java @@ -2,6 +2,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; @@ -30,7 +31,7 @@ class PartsFilterBlocksCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterItemsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterItemsCMD.java index cadc01ba..dbac5238 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterItemsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterItemsCMD.java @@ -2,6 +2,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; @@ -30,7 +31,7 @@ class PartsFilterItemsCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTagsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTagsCMD.java index 3305f697..93976a98 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTagsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTagsCMD.java @@ -2,13 +2,13 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.PartFilter; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedPartSelection; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -26,7 +26,7 @@ class PartsFilterTagsCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java index e47e6b73..c253497b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java @@ -2,6 +2,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; @@ -29,7 +30,7 @@ class PartsFilterTypesCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsListTagsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsListTagsCMD.java index 7f2eb8a0..9aa7ffce 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsListTagsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsListTagsCMD.java @@ -1,6 +1,7 @@ package net.donnypz.displayentityutils.command.parts; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; @@ -23,7 +24,7 @@ public void execute(Player player, String[] args) { ActivePartSelection partSelection = DisplayGroupManager.getPartSelection(player); if (partSelection == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRefreshFilterCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRefreshFilterCMD.java index b8f4dce0..f14e2075 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRefreshFilterCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRefreshFilterCMD.java @@ -2,12 +2,12 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedPartSelection; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; @@ -22,7 +22,7 @@ class PartsRefreshFilterCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsResetFilterCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsResetFilterCMD.java index a15b8e07..7abbb7ec 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsResetFilterCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsResetFilterCMD.java @@ -2,13 +2,12 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedPartSelection; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; @@ -23,7 +22,7 @@ class PartsResetFilterCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } From d695d0016706b16116832ad9cf25c04426ca6fd3 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 18 Dec 2025 06:57:14 -0600 Subject: [PATCH 019/139] Fix duplicate command output and incorrect usage msg --- .../command/item/ItemToggleGlintCMD.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java index 0cf293e5..9b8f5ede 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java @@ -23,7 +23,7 @@ class ItemToggleGlintCMD extends PartsSubCommand { @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu item toggleglint -all ", NamedTextColor.RED))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu item toggleglint [-all ]", NamedTextColor.RED))); } @Override @@ -38,12 +38,12 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (s.equalsIgnoreCase("on")){ status = true; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled glint for ALL selected item displays ON"))); + .append(MiniMessage.miniMessage().deserialize("Toggled glint for ALL selected item displays ON"))); } else if (s.equalsIgnoreCase("off")){ status = false; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled glint for ALL selected item displays OFF"))); + .append(MiniMessage.miniMessage().deserialize("Toggled glint for ALL selected item displays OFF"))); } else{ sendIncorrectUsage(player); @@ -55,7 +55,6 @@ else if (s.equalsIgnoreCase("off")){ part.setItemDisplayItemGlint(status); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully toggled glint of ALL selected item displays!", NamedTextColor.GREEN))); return true; } @@ -68,7 +67,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti ItemStack item = selectedPart.getItemDisplayItem(); if (item == null) return false; selectedPart.setItemDisplayItemGlint(!item.getItemMeta().getEnchantmentGlintOverride()); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully toggled glint of selected item display!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Toggled glint of selected item display!", NamedTextColor.GREEN))); return true; } } From 9b1d376d1ff40691cab4fb15138c4dfbe90aff65 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 19 Dec 2025 18:13:35 -0600 Subject: [PATCH 020/139] Start implementation of Shulker (collision) and Mannequins --- .../utils/DisplayEntities/ActivePart.java | 44 ++- .../PacketDisplayEntityGroup.java | 2 +- .../PacketDisplayEntityPart.java | 142 ++++++-- .../SpawnedDisplayEntityGroup.java | 2 +- .../SpawnedDisplayEntityPart.java | 306 +++++++++++------- .../packet/PacketAttributeContainer.java | 225 +++++++------ .../attributes/AttributeDisplayAttribute.java | 23 ++ .../packet/attributes/DisplayAttribute.java | 27 ++ .../packet/attributes/DisplayAttributes.java | 10 + .../packet/attributes/EquipmentAttribute.java | 19 ++ .../attributes/MainHandDisplayAttribute.java | 15 + .../attributes/PoseDisplayAttribute.java | 15 + .../ResolvableProfileDisplayAttribute.java | 16 + .../utils/version/VersionUtils.java | 6 +- .../command/DEUSubCommand.java | 11 +- .../command/DisplayEntityPluginCommand.java | 5 +- .../command/PartsSubCommand.java | 11 + .../command/Permission.java | 6 + .../command/mannequin/MannequinCMD.java | 58 ++++ .../mannequin/MannequinHeldItemCMD.java | 82 +++++ .../command/mannequin/MannequinHelpCMD.java | 26 ++ .../mannequin/MannequinMainHandCMD.java | 62 ++++ .../command/mannequin/MannequinPoseCMD.java | 64 ++++ .../command/mannequin/MannequinScaleCMD.java | 59 ++++ .../mannequin/MannequinToggleGravityCMD.java | 67 ++++ .../MannequinToggleImmovableCMD.java | 67 ++++ .../command/parts/PartsCreateCMD.java | 15 +- .../command/parts/PartsSelectCMD.java | 17 +- .../relativepoints/DisplayEntitySelector.java | 22 +- 29 files changed, 1139 insertions(+), 285 deletions(-) create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/MainHandDisplayAttribute.java create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHelpCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 37a529bc..afab2f47 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -16,6 +16,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.entity.*; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MainHand; import org.bukkit.util.Transformation; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; @@ -187,6 +188,20 @@ public SpawnedDisplayEntityPart.PartType getType(){ return type; } + /** + * Get whether this part will visually glow if glowing is applied to it + * @return a boolean + */ + public boolean canGlow(){ + return type != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY && type != SpawnedDisplayEntityPart.PartType.INTERACTION; + } + + public boolean isDisplay(){ + return type == SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY + || type == SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY + || type == SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY; + } + /** * Make this part glow for a player * @param player the player @@ -202,9 +217,8 @@ public void glow(@NotNull Player player){ */ @Override public void glow(long durationInTicks){ - if (type == SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY || type == SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY){ + if (canGlow()){ glow(); - DisplayAPI.getScheduler().partRunLater(this, this::unglow, durationInTicks); } } @@ -217,7 +231,7 @@ public void glow(long durationInTicks){ */ @Override public void glow(@NotNull Player player, long durationInTicks){ - if (type == SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY || type == SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY){ + if (canGlow()){ if (durationInTicks <= -1){ PacketUtils.setGlowing(player, getEntityId(), true); } @@ -267,7 +281,7 @@ public void markInteraction(@NotNull Player player, long durationInTicks){ */ @Override public void unglow(@NotNull Player player) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!canGlow()) return; PacketUtils.setGlowing(player, getEntityId(), false); } @@ -434,6 +448,28 @@ public void unglow(@NotNull Player player) { */ public abstract @Nullable ItemStack getItemDisplayItem(); + public abstract void setMannequinPose(Pose pose); + + public abstract @Nullable Pose getMannequinPose(); + + public abstract void setMannequinScale(double scale); + + public abstract double getMannequinScale(); + + public abstract void setMannequinImmovable(boolean immovable); + + public abstract boolean isMannequinImmovable(); + + public abstract void setMannequinGravity(boolean gravity); + + public abstract boolean hasMannequinGravity(); + + public abstract void setMannequinMainHand(@NotNull MainHand mainHand); + + public abstract @Nullable MainHand getMannequinMainHand(); + + public abstract void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand); + /** * Set an attribute on this part, and send the updated attribute to viewing players. * @param attribute the attribute diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index 2bbae303..bfa5d9ea 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -288,7 +288,7 @@ public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scal for (PacketDisplayEntityPart p : groupParts.values()){ //Displays - if (p.getType() != SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (p.isDisplay()){ DisplayAttributeMap attributeMap = new DisplayAttributeMap(); Transformation transformation = p.getTransformation(); //Reset Scale then multiply by newScaleMultiplier diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index ff6e5bb9..1ca18237 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -22,11 +22,9 @@ import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Display; -import org.bukkit.entity.ItemDisplay; -import org.bukkit.entity.Player; -import org.bukkit.entity.TextDisplay; +import org.bukkit.entity.*; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MainHand; import org.bukkit.util.Transformation; import org.bukkit.util.Vector; import org.jetbrains.annotations.ApiStatus; @@ -289,19 +287,19 @@ public void hideFromPlayers(@NotNull Collection players) { @Override public void setTransformation(@NotNull Transformation transformation) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!isDisplay()) return; attributeContainer.setTransformationAndSend(transformation, getEntityId(), viewers); } @Override public void setTransformationMatrix(@NotNull Matrix4f matrix) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!isDisplay()) return; attributeContainer.setTransformationMatrixAndSend(matrix, getEntityId(), viewers); } @Override public boolean setXScale(float scale) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return false; + if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.x = scale; attributeContainer.setAttributeAndSend(DisplayAttributes.Transform.SCALE, vec, getEntityId(), viewers); @@ -310,7 +308,7 @@ public boolean setXScale(float scale) { @Override public boolean setYScale(float scale) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return false; + if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.y = scale; attributeContainer.setAttributeAndSend(DisplayAttributes.Transform.SCALE, vec, getEntityId(), viewers); @@ -319,7 +317,7 @@ public boolean setYScale(float scale) { @Override public boolean setZScale(float scale) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return false; + if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.z = scale; attributeContainer.setAttributeAndSend(DisplayAttributes.Transform.SCALE, vec, getEntityId(), viewers); @@ -328,7 +326,7 @@ public boolean setZScale(float scale) { @Override public boolean setScale(float x, float y, float z) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return false; + if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.x = x; vec.y = y; @@ -531,6 +529,72 @@ public boolean isTextDisplayDefaultBackground() { return attributeContainer.getAttribute(DisplayAttributes.ItemDisplay.ITEMSTACK); } + @Override + public void setMannequinPose(Pose pose) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.POSE, pose); + } + + @Override + public @Nullable Pose getMannequinPose() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return null; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.POSE); + } + + @Override + public void setMannequinScale(double scale) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.SCALE, (float) scale); + } + + @Override + public double getMannequinScale() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return -1; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.SCALE); + } + + @Override + public void setMannequinImmovable(boolean immovable) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.IMMOVABLE, immovable); + } + + @Override + public boolean isMannequinImmovable() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return false; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.IMMOVABLE); + } + + @Override + public void setMannequinGravity(boolean gravity) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.NO_GRAVITY, !gravity); + } + + @Override + public boolean hasMannequinGravity() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return false; + return !attributeContainer.getAttribute(DisplayAttributes.Mannequin.NO_GRAVITY); + } + + @Override + public void setMannequinMainHand(@NotNull MainHand mainHand) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.MAIN_HAND, mainHand); + } + + @Override + public @Nullable MainHand getMannequinMainHand() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return null; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.MAIN_HAND); + } + + @Override + public void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + //TODO + } + @Override public void setAttribute(@NotNull DisplayAttribute attribute, T value) { @@ -557,7 +621,7 @@ public void resendAttributes(@NotNull Player player){ @Override public Transformation getTransformation(){ - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!isDisplay()){ return null; } return new Transformation( @@ -570,7 +634,7 @@ public Transformation getTransformation(){ @Override public int getTeleportDuration() { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!isDisplay()){ return -1; } return attributeContainer.getAttributeOrDefault(DisplayAttributes.TELEPORTATION_DURATION, 0); @@ -583,7 +647,7 @@ public int getTeleportDuration() { @Override public float getViewRange(){ - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!isDisplay()){ return -1; } return attributeContainer.getAttributeOrDefault(DisplayAttributes.VIEW_RANGE, 1f); @@ -719,7 +783,7 @@ private NamespacedKey getInteractionCMDKey(boolean isLeftClick, boolean isConsol @Override protected void cull(float width, float height) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!isDisplay()) return; attributeContainer .setAttributesAndSend(new DisplayAttributeMap() .add(DisplayAttributes.Culling.HEIGHT, height) @@ -748,25 +812,31 @@ public Collection getTrackingPlayers() { @Override public @Nullable Color getGlowColor() { - return attributeContainer.getAttribute(DisplayAttributes.GLOW_COLOR_OVERRIDE); + if (isDisplay()){ + return attributeContainer.getAttribute(DisplayAttributes.GLOW_COLOR_OVERRIDE); + } + return null; } @Override public void setGlowColor(@Nullable Color color) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.GLOW_COLOR_OVERRIDE, color); + if (isDisplay()){ + setAndSend(DisplayAttributes.GLOW_COLOR_OVERRIDE, color); + } } @Override public void glow() { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.GLOWING, true); + if (canGlow()){ + setAndSend(DisplayAttributes.GLOWING, true); + } } @Override public void unglow() { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.GLOWING, false); + if (canGlow()){ + setAndSend(DisplayAttributes.GLOWING, false); + } } /** @@ -774,8 +844,9 @@ public void unglow() { */ @Override public void setTeleportDuration(int teleportDuration) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.TELEPORTATION_DURATION, teleportDuration); + if (isDisplay()){ + setAndSend(DisplayAttributes.TELEPORTATION_DURATION, teleportDuration); + } } /** @@ -784,10 +855,9 @@ public void setTeleportDuration(int teleportDuration) { */ @Override public void setInterpolationDuration(int interpolationDuration) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - return; + if (isDisplay()){ + setAndSend(DisplayAttributes.Interpolation.DURATION, interpolationDuration); } - setAndSend(DisplayAttributes.Interpolation.DURATION, interpolationDuration); } /** @@ -796,28 +866,30 @@ public void setInterpolationDuration(int interpolationDuration) { */ @Override public void setInterpolationDelay(int interpolationDelay) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - return; + if (isDisplay()){ + setAndSend(DisplayAttributes.Interpolation.DELAY, interpolationDelay); } - setAndSend(DisplayAttributes.Interpolation.DELAY, interpolationDelay); } @Override public void setViewRange(float viewRangeMultiplier) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.VIEW_RANGE, viewRangeMultiplier); + if (isDisplay()){ + setAndSend(DisplayAttributes.VIEW_RANGE, viewRangeMultiplier); + } } @Override public void setBillboard(Display.@NotNull Billboard billboard) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.BILLBOARD, billboard); + if (isDisplay()){ + setAndSend(DisplayAttributes.BILLBOARD, billboard); + } } @Override public void setBrightness(Display.@Nullable Brightness brightness) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.BRIGHTNESS, brightness); + if (isDisplay()){ + setAndSend(DisplayAttributes.BRIGHTNESS, brightness); + } } @Override diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index 5aa85d0f..ca915c6c 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -469,7 +469,7 @@ public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scal for (SpawnedDisplayEntityPart p : groupParts.values()){ //Displays - if (p.getType() != SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (p.isDisplay()){ Display d = (Display) p.getEntity(); Transformation transformation = d.getTransformation(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 8de8e9cc..12d40460 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -10,9 +10,11 @@ import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; import net.kyori.adventure.text.Component; import org.bukkit.*; +import org.bukkit.attribute.Attribute; import org.bukkit.block.data.BlockData; import org.bukkit.entity.*; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MainHand; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.bukkit.util.Transformation; @@ -34,36 +36,17 @@ public final class SpawnedDisplayEntityPart extends ActivePart implements Spawne private UUID entityUUID; private final boolean isSingle; - SpawnedDisplayEntityPart(SpawnedDisplayEntityGroup group, Display displayEntity, Random random){ - super(displayEntity.getEntityId(), true); + SpawnedDisplayEntityPart(SpawnedDisplayEntityGroup group, Entity entity, Random random){ + super(entity.getEntityId(), true); this.group = group; - this.entity = displayEntity; - if (displayEntity instanceof BlockDisplay){ - this.type = PartType.BLOCK_DISPLAY; - } - else if (displayEntity instanceof ItemDisplay){ - this.type = PartType.ITEM_DISPLAY; - } - else { - this.type = PartType.TEXT_DISPLAY; - } + this.entity = entity; + this.type = PartType.getType(entity); applyData(random, entity); if (isMaster()){ group.masterPart = this; } - partTags.addAll(DisplayUtils.getTags(displayEntity)); - isSingle = false; - } - - - SpawnedDisplayEntityPart(SpawnedDisplayEntityGroup group, Interaction interactionEntity, Random random){ - super(interactionEntity.getEntityId(), false); - this.group = group; - this.entity = interactionEntity; - this.type = PartType.INTERACTION; - applyData(random, interactionEntity); - partTags.addAll(DisplayUtils.getTags(interactionEntity)); + partTags.addAll(DisplayUtils.getTags(entity)); isSingle = false; } @@ -73,7 +56,12 @@ else if (displayEntity instanceof ItemDisplay){ case BlockDisplay blockDisplay -> this.type = PartType.BLOCK_DISPLAY; case ItemDisplay itemDisplay -> this.type = PartType.ITEM_DISPLAY; case TextDisplay textDisplay -> this.type = PartType.TEXT_DISPLAY; - default -> this.type = PartType.INTERACTION; + case Interaction interaction -> this.type = PartType.INTERACTION; + case Shulker shulker -> this.type = PartType.SHULKER; + case Mannequin mannequin -> this.type = PartType.MANNEQUIN; + default -> { + throw new IllegalArgumentException("The provided entity is not a valid part entity!"); + } } this.entity = entity; this.entityUUID = entity.getUniqueId(); @@ -86,42 +74,24 @@ else if (displayEntity instanceof ItemDisplay){ * If the entity is already included in a group, its respective part will be returned. * @param uuid the entity uuid * @return a {@link SpawnedDisplayEntityPart} or null if the entity uuid is not a display or interaction + * @throws IllegalArgumentException if the entity is not a valid entity */ - public static @Nullable SpawnedDisplayEntityPart create(@NotNull UUID uuid){ - Entity entity = Bukkit.getEntity(uuid); - if (entity instanceof Interaction i){ - return create(i); - } - else if (entity instanceof Display d){ - return create(d); - } - return null; + public static @NotNull SpawnedDisplayEntityPart create(@NotNull UUID uuid){ + return new SpawnedDisplayEntityPart(Bukkit.getEntity(uuid)); } /** * Create a {@link SpawnedDisplayEntityPart} that is not included in any group. *
* If the entity is already included in a group, its respective part will be returned. - * @param display the display entity + * @param entity the valid part entity * @return a {@link SpawnedDisplayEntityPart} + * @throws IllegalArgumentException if the entity is not a valid entity */ - public static @NotNull SpawnedDisplayEntityPart create(@NotNull Display display){ - SpawnedDisplayEntityPart part = getPart(display); + public static @NotNull SpawnedDisplayEntityPart create(@NotNull Entity entity){ + SpawnedDisplayEntityPart part = getPart(entity); if (part != null) return part; - return new SpawnedDisplayEntityPart(display); - } - - /** - * Create a {@link SpawnedDisplayEntityPart} that is not included in any group. - *
- * If the entity is already included in a group, its respective part will be returned. - * @param interaction the interaction entity - * @return a {@link SpawnedDisplayEntityPart} - */ - public static @NotNull SpawnedDisplayEntityPart create(@NotNull Interaction interaction){ - SpawnedDisplayEntityPart part = getPart(interaction); - if (part != null) return part; - return new SpawnedDisplayEntityPart(interaction); + return new SpawnedDisplayEntityPart(entity); } private void applyData(Random random, Entity entity){ @@ -134,8 +104,6 @@ private void applyData(Random random, Entity entity){ removeFromPreviousGroup((Interaction) entity); } - - this.partData = new PartData(entity); this.entityUUID = entity.getUniqueId(); allParts.put(partData, this); @@ -221,7 +189,7 @@ private void removeFromPreviousGroup(Interaction i){ /** * Get whether this part can be added to a group. This returns false if the part was - * created through {@link #create(Display)} or {@link #create(Interaction)} + * created through {@link #create(Entity)} * @return a boolean. */ @Override @@ -298,7 +266,7 @@ PartData getPartData() { } /** - * Get the {@link SpawnedDisplayEntityPart} of an entity, during this play session. Use {@link #create(Display)} or similar methods if the part is not grouped. + * Get the {@link SpawnedDisplayEntityPart} of an entity, during this play session. Use {@link #create(Entity)} if the part is not grouped. * @param entity the part entity (Display/Interaction) * @return The SpawnedDisplayEntityPart. Null if not created during play session or not associated with any group */ @@ -477,18 +445,13 @@ public boolean isInLoadedChunk(){ } - - - /** * Adds the glow effect to this SpawnDisplayEntityPart. This does NOT apply to Interaction or Text Display entities. Use {@link #markInteraction(Player, long)} to show an outline of * an interaction for a specific player. */ public void glow(){ + if (!canGlow()) return; Entity entity = getEntity(); - if (type == PartType.INTERACTION || type == PartType.TEXT_DISPLAY) { - return; - } entity.setGlowing(true); } @@ -499,10 +462,9 @@ public void glow(){ */ @Override public void glow(long durationInTicks){ + if (!canGlow()) return; + Entity entity = getEntity(); - if (type == PartType.INTERACTION || type == PartType.TEXT_DISPLAY) { - return; - } entity.setGlowing(true); DisplayAPI.getScheduler().entityRunLater(entity, () -> { @@ -521,7 +483,7 @@ public boolean isGlowing() { */ @Override public void unglow(){ - if (type != PartType.INTERACTION) { + if (canGlow()) { getEntity().setGlowing(false); } } @@ -532,7 +494,7 @@ public void unglow(){ */ @Override public void unglow(@NotNull Player player){ - if (type != PartType.INTERACTION) { + if (canGlow()) { PacketUtils.setGlowing(player, getEntityId(), false); } } @@ -568,9 +530,7 @@ public void setPitch(float pitch){ @Override public boolean setXScale(float scale){ - if (type == PartType.INTERACTION){ - return false; - } + if (!isDisplay()) return false; Transformation t = getTransformation(); Vector3f v = t.getScale(); Transformation newT = new Transformation(t.getTranslation(), t.getLeftRotation(), new Vector3f(scale, v.y, v.z), t.getRightRotation()); @@ -581,7 +541,7 @@ public boolean setXScale(float scale){ @Override public boolean setYScale(float scale){ - if (type == PartType.INTERACTION) return false; + if (!isDisplay()) return false; Transformation t = getTransformation(); Vector3f v = t.getScale(); Transformation newT = new Transformation(t.getTranslation(), t.getLeftRotation(), new Vector3f(v.x, scale, v.z), t.getRightRotation()); @@ -592,7 +552,7 @@ public boolean setYScale(float scale){ @Override public boolean setZScale(float scale){ - if (type == PartType.INTERACTION) return false; + if (!isDisplay()) return false; Transformation t = getTransformation(); Vector3f v = t.getScale(); Transformation newT = new Transformation(t.getTranslation(), t.getLeftRotation(), new Vector3f(v.x, v.y, scale), t.getRightRotation()); @@ -603,7 +563,7 @@ public boolean setZScale(float scale){ @Override public boolean setScale(float x, float y, float z){ - if (type == PartType.INTERACTION) return false; + if (!isDisplay()) return false; Transformation t = getTransformation(); Transformation newT = new Transformation(t.getTranslation(), t.getLeftRotation(), new Vector3f(x, y, z), t.getRightRotation()); Display entity = (Display) getEntity(); @@ -612,8 +572,6 @@ public boolean setScale(float x, float y, float z){ } - - /** * Set the brightness of this part * @param brightness the brightness to set, null to use brightness based on position @@ -621,11 +579,9 @@ public boolean setScale(float x, float y, float z){ @Override public void setBrightness(@Nullable Display.Brightness brightness){ Entity entity = getEntity(); - if (entity instanceof Interaction){ - return; + if (entity instanceof Display display){ + display.setBrightness(brightness); } - Display display = (Display) entity; - display.setBrightness(brightness); } /** @@ -635,11 +591,9 @@ public void setBrightness(@Nullable Display.Brightness brightness){ @Override public void setBillboard(@NotNull Display.Billboard billboard){ Entity entity = getEntity(); - if (entity instanceof Interaction){ - return; + if (entity instanceof Display display){ + display.setBillboard(billboard); } - Display display = (Display) entity; - display.setBillboard(billboard); } /** @@ -647,9 +601,10 @@ public void setBillboard(@NotNull Display.Billboard billboard){ */ @Override public void setTeleportDuration(int teleportDuration) { - if (type == PartType.INTERACTION) return; - Display display = (Display) getEntity(); - display.setTeleportDuration(teleportDuration); + Entity entity = getEntity(); + if (entity instanceof Display display){ + display.setTeleportDuration(teleportDuration); + } } /** @@ -658,11 +613,10 @@ public void setTeleportDuration(int teleportDuration) { */ @Override public void setInterpolationDuration(int interpolationDuration) { - if (type == PartType.INTERACTION){ - return; + Entity entity = getEntity(); + if (entity instanceof Display display){ + display.setInterpolationDuration(interpolationDuration); } - Display display = (Display) getEntity(); - display.setInterpolationDuration(interpolationDuration); } /** @@ -671,11 +625,10 @@ public void setInterpolationDuration(int interpolationDuration) { */ @Override public void setInterpolationDelay(int interpolationDelay) { - if (type == PartType.INTERACTION){ - return; + Entity entity = getEntity(); + if (entity instanceof Display display){ + display.setInterpolationDelay(interpolationDelay); } - Display display = (Display) getEntity(); - display.setInterpolationDelay(interpolationDelay); } /** @@ -685,16 +638,15 @@ public void setInterpolationDelay(int interpolationDelay) { @Override public void setViewRange(float viewRangeMultiplier){ Entity entity = getEntity(); - if (entity instanceof Interaction){ - return; + if (entity instanceof Display display){ + display.setViewRange(viewRangeMultiplier); } - Display display = (Display) entity; - display.setViewRange(viewRangeMultiplier); } @Override protected void cull(float width, float height){ + if (!isDisplay()) return; Entity entity = getEntity(); if (entity instanceof Display display){ display.setDisplayHeight(height); @@ -777,9 +729,7 @@ void translateForce(Direction direction, float distance, int durationInTicks, in @Override public void pivot(float angleInDegrees){ Entity entity = getEntity(); - if (type != PartType.INTERACTION || isSingle){ - return; - } + if (isDisplay() || isSingle) return; Interaction i = (Interaction) entity; DisplayUtils.pivot(i, group.getLocation(), angleInDegrees); } @@ -814,13 +764,13 @@ public Interaction spawnInteractionAtDisplay(){ @Override public void setTransformation(@NotNull Transformation transformation) { - if (type == PartType.INTERACTION) return; + if (!isDisplay()) return; ((Display) getEntity()).setTransformation(transformation); } @Override public void setTransformationMatrix(@NotNull Matrix4f matrix) { - if (type == PartType.INTERACTION) return; + if (!isDisplay()) return; ((Display) getEntity()).setTransformationMatrix(matrix); } @@ -989,6 +939,100 @@ public boolean isTextDisplayDefaultBackground() { return display.getItemStack(); } + @Override + public void setMannequinPose(Pose pose) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + if (pose == null) pose = Pose.STANDING; + mannequin.setPose(pose, true); + } + + @Override + public @Nullable Pose getMannequinPose() { + if (type != PartType.MANNEQUIN) return null; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return null; + return mannequin.getPose(); + } + + @Override + public void setMannequinScale(double scale) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.getAttribute(Attribute.SCALE).setBaseValue(scale); + } + + @Override + public double getMannequinScale() { + if (type != PartType.MANNEQUIN) return -1; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return -1; + return mannequin.getAttribute(Attribute.SCALE).getBaseValue(); + } + + @Override + public void setMannequinImmovable(boolean immovable) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.setImmovable(immovable); + } + + @Override + public boolean isMannequinImmovable() { + if (type != PartType.MANNEQUIN) return false; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return false; + return mannequin.isImmovable(); + } + + @Override + public void setMannequinGravity(boolean gravity) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.setGravity(gravity); + } + + @Override + public boolean hasMannequinGravity() { + if (type != PartType.MANNEQUIN) return false; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return false; + return mannequin.hasGravity(); + } + + @Override + public void setMannequinMainHand(@NotNull MainHand mainHand) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.setMainHand(mainHand); + } + + @Override + public @Nullable MainHand getMannequinMainHand() { + if (type != PartType.MANNEQUIN) return null; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return null; + return mannequin.getMainHand(); + } + + @Override + public void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + if (mainHand){ + mannequin.getEquipment().setItemInMainHand(itemStack, true); + } + else{ + mannequin.getEquipment().setItemInOffHand(itemStack, true); + } + } + /** * {@inheritDoc} * The applied changes do not reflect the entity data server-side @@ -1045,7 +1089,7 @@ public void setInteractionResponsive(boolean responsive) { @Override public @Nullable Transformation getTransformation() { - if (type == PartType.INTERACTION) { + if (!isDisplay()) { return null; } return ((Display) getEntity()).getTransformation(); @@ -1053,7 +1097,7 @@ public void setInteractionResponsive(boolean responsive) { @Override public @Nullable Display.Brightness getBrightness() { - if (type == PartType.INTERACTION){ + if (!isDisplay()){ return null; } return ((Display) getEntity()).getBrightness(); @@ -1061,7 +1105,7 @@ public void setInteractionResponsive(boolean responsive) { @Override public float getViewRange() { - if (type == PartType.INTERACTION){ + if (!isDisplay()){ return -1; } return ((Display) getEntity()).getViewRange(); @@ -1115,7 +1159,7 @@ public void removeInteractionCommand(@NotNull InteractionCommand command) { @Override public int getTeleportDuration() { - if (type == PartType.INTERACTION){ + if (!isDisplay()){ return -1; } return ((Display) getEntity()).getTeleportDuration(); @@ -1125,23 +1169,43 @@ public enum PartType{ BLOCK_DISPLAY, ITEM_DISPLAY, TEXT_DISPLAY, - INTERACTION; - + INTERACTION, + SHULKER, + MANNEQUIN; + + /** + * Get a type, respective of the given entity + * @param entity the entity + * @return a {@link PartType} or null if the entity does not have a type. + */ public static PartType getType(@NotNull Entity entity){ - switch (entity){ - case Interaction i -> { - return INTERACTION; - } - case BlockDisplay d -> { - return BLOCK_DISPLAY; + try{ + switch (entity){ + case Interaction i -> { + return INTERACTION; + } + case BlockDisplay d -> { + return BLOCK_DISPLAY; + } + case ItemDisplay d -> { + return ITEM_DISPLAY; + } + case TextDisplay d -> { + return TEXT_DISPLAY; + } + case Shulker s -> { + return SHULKER; + } + case Mannequin m -> { + return MANNEQUIN; + } + default -> { + return null; + } } - case ItemDisplay d -> { - return ITEM_DISPLAY; - } - case TextDisplay d -> { - return TEXT_DISPLAY; - } - default -> throw new IllegalStateException("Unexpected value: " + entity); + } + catch (NoClassDefFoundError e){ //Mannequin on < 1.21.9 + return null; } } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java index 0135456f..f6eb1595 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java @@ -5,13 +5,19 @@ import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; +import com.github.retrooper.packetevents.protocol.item.ItemStack; +import com.github.retrooper.packetevents.protocol.player.Equipment; +import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes; import io.github.retrooper.packetevents.util.SpigotConversionUtil; import io.github.retrooper.packetevents.util.SpigotReflectionUtil; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityPart; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.packet.attributes.AttributeDisplayAttribute; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import org.bukkit.Bukkit; @@ -138,7 +144,7 @@ public PacketAttributeContainer setAttributes(@NotNull DisplayAttributeMap attri */ public PacketAttributeContainer setAttributeAndSend(@NotNull DisplayAttribute attribute, T value, int entityId, @NotNull Player player){ this.attributes.put(attribute, value); - sendAttributes(player, entityId, getMetadataList(Map.of(attribute, value))); + new PacketResult(entityId, attribute, value).send(player); return this; } @@ -151,7 +157,7 @@ public PacketAttributeContainer setAttributeAndSend(@NotNull DisplayAttri */ public void setAttributeAndSend(@NotNull DisplayAttribute attribute, T value, int entityId, @NotNull Collection playerUUIDs){ this.attributes.put(attribute, value); - sendAttributesToUUIDs(playerUUIDs, entityId, getMetadataList(new DisplayAttributeMap().add(attribute, value).attributes)); + new PacketResult(entityId, attribute, value).sendUUIDs(playerUUIDs); } /** @@ -164,7 +170,7 @@ public void setAttributeAndSend(@NotNull DisplayAttribute attribute */ public PacketAttributeContainer setAttributesAndSend(@NotNull DisplayAttributeMap attributeMap, int entityId, @NotNull Player player){ this.attributes.putAll(attributeMap.attributes); - sendAttributes(player, entityId, getMetadataList(attributeMap.attributes)); + new PacketResult(entityId, attributeMap).send(player); return this; } @@ -178,7 +184,7 @@ public PacketAttributeContainer setAttributesAndSend(@NotNull DisplayAttributeMa */ public PacketAttributeContainer setAttributesAndSend(@NotNull DisplayAttributeMap attributeMap, int entityId, @NotNull Collection playerUUIDs){ this.attributes.putAll(attributeMap.attributes); - sendAttributesToUUIDs(playerUUIDs, entityId, getMetadataList(attributeMap.attributes)); + new PacketResult(entityId, attributeMap).sendUUIDs(playerUUIDs); return this; } @@ -358,7 +364,7 @@ public int sendEntityUsingUUIDs(@NotNull SpawnedDisplayEntityPart.PartType partT * @return this */ private PacketAttributeContainer sendAttributes(SpawnedDisplayEntityPart.PartType partType, Player player, int entityId){ - sendAttributes(player, entityId, getMetadataList(attributes, partType)); + new PacketResult(entityId).send(player); return this; } @@ -370,7 +376,7 @@ private PacketAttributeContainer sendAttributes(SpawnedDisplayEntityPart.PartTyp * @return this */ public PacketAttributeContainer sendAttributes(@NotNull Player player, int entityId){ - sendAttributes(player, entityId, getMetadataList(attributes)); + new PacketResult(entityId).send(player); return this; } @@ -381,7 +387,7 @@ public PacketAttributeContainer sendAttributes(@NotNull Player player, int entit * @return this */ public PacketAttributeContainer sendAttributesUsingUUIDs(@NotNull Collection playerUUIDs, int entityId){ - sendAttributesToUUIDs(playerUUIDs, entityId, getMetadataList(attributes)); + new PacketResult(entityId).sendUUIDs(playerUUIDs); return this; } @@ -392,26 +398,10 @@ public PacketAttributeContainer sendAttributesUsingUUIDs(@NotNull Collection players, int entityId){ - sendAttributesToPlayers(players, entityId, getMetadataList(attributes)); + new PacketResult(entityId).send(players); return this; } - private void sendAttributes(@NotNull Player player, int entityId, List> data){ - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityMetadata(entityId, data)); - } - - private void sendAttributesToPlayers(@NotNull Collection players, int entityId, List> data){ - for (Player player : players){ - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityMetadata(entityId, data)); - } - } - - private void sendAttributesToUUIDs(@NotNull Collection playerUUIDs, int entityId, List> data){ - for (UUID uuid : playerUUIDs){ - PacketEvents.getAPI().getPlayerManager().sendPacket(Bukkit.getPlayer(uuid), new WrapperPlayServerEntityMetadata(entityId, data)); - } - } - private WrapperPlayServerSpawnEntity createEntityPacket(int entityId, SpawnedDisplayEntityPart.PartType partType, Location location){ return new WrapperPlayServerSpawnEntity( entityId, @@ -424,81 +414,6 @@ private WrapperPlayServerSpawnEntity createEntityPacket(int entityId, SpawnedDis null); } - private WrapperPlayServerEntityMetadata createFullMetadataPacket(int entityId){ - return new WrapperPlayServerEntityMetadata(entityId, getMetadataList()); - } - - - - private List> getMetadataList() { - return getMetadataList(attributes); - } - - private List> getMetadataList(Map, Object> attributes){ - List> metadata = new ArrayList<>(); - for (Map.Entry, Object> entry : attributes.entrySet()) { - DisplayAttribute attr = entry.getKey(); - Object val = entry.getValue(); - - - DisplayAttribute castedAttr = (DisplayAttribute) attr; - - Object outputValue = castedAttr.getOutputValue(castedAttr.getInputType().cast(val)); - - EntityDataType entityDataType = (EntityDataType) castedAttr.getEntityDataType(); - - metadata.add(new EntityData<>( - castedAttr.getIndex(), - entityDataType, - outputValue - )); - } - return metadata; - } - - private List> getMetadataList(Map, Object> attributes, SpawnedDisplayEntityPart.PartType partType){ - List> metadata = new ArrayList<>(); - for (Map.Entry, Object> entry : attributes.entrySet()) { - DisplayAttribute attr = entry.getKey(); - Object val = entry.getValue(); - - - DisplayAttribute castedAttr = (DisplayAttribute) attr; - - - Object outputValue = castedAttr.getOutputValue(castedAttr.getInputType().cast(val)); - - EntityDataType entityDataType = (EntityDataType) castedAttr.getEntityDataType(); - - metadata.add(new EntityData<>( - castedAttr.getIndex(), - entityDataType, - outputValue - )); - } - return metadata; - } - - /*private List> getDefinedMetadataList(Map, T> attributes){ - List> metadata = new ArrayList<>(); - for (Map.Entry, T> entry : attributes.entrySet()) { - DisplayAttribute attr = entry.getKey(); - Object val = entry.getValue(); - - - V outputValue = attr.getOutputValue(attr.getInputType().cast(val)); - - EntityDataType entityDataType = (EntityDataType) attr.getEntityDataType(); - - metadata.add(new EntityData<>( - attr.getIndex(), - entityDataType, - outputValue - )); - } - return metadata; - }*/ - EntityType getEntityType(SpawnedDisplayEntityPart.PartType partType){ switch (partType){ case BLOCK_DISPLAY -> { @@ -513,8 +428,14 @@ EntityType getEntityType(SpawnedDisplayEntityPart.PartType partType){ case INTERACTION -> { return EntityTypes.INTERACTION; } + case SHULKER -> { + return EntityTypes.SHULKER; + } + case MANNEQUIN -> { + return EntityTypes.MANNEQUIN; + } default -> { - throw new IllegalArgumentException("Invalid part type, expected a display entity type."); + throw new IllegalArgumentException("Invalid part type."); } } } @@ -551,4 +472,108 @@ else if (value instanceof Color c){ throw new RuntimeException(e); } } + + class PacketResult{ + int entityId; + WrapperPlayServerEntityMetadata metadataPacket; + WrapperPlayServerEntityEquipment equipmentPacket; + WrapperPlayServerUpdateAttributes attributesPacket; + + PacketResult(int entityId){ + this.entityId = entityId; + setPackets(attributes); + } + + PacketResult(int entityId, DisplayAttributeMap map){ + this.entityId = entityId; + setPackets(map.attributes); + } + + PacketResult(int entityId, DisplayAttribute attribute, Object value){ + this.entityId = entityId; + setPackets(Map.of(attribute, value)); + } + + void setPackets(Map, Object> attributeMap){ + List> entityData = new ArrayList<>(); + List equipmentData = new ArrayList<>(); + List attributeData = new ArrayList<>(); + for(Map.Entry, Object> entry : attributeMap.entrySet()){ + DisplayAttribute attr = entry.getKey(); + Object val = entry.getValue(); + if (attr.isMetadata()){ + entityData.add(createEntityData(attr, val)); + } + else if (attr.isEquipment()){ + equipmentData.add(createEquipmentData(attr, val)); + } + else if (attr.isAttribute()){ + attributeData.add(createAttributeData(attr, val)); + } + } + + if (!entityData.isEmpty()){ + metadataPacket = new WrapperPlayServerEntityMetadata(entityId, entityData); + } + if (!equipmentData.isEmpty()){ + equipmentPacket = new WrapperPlayServerEntityEquipment(entityId, equipmentData); + } + if (!attributeData.isEmpty()){ + attributesPacket = new WrapperPlayServerUpdateAttributes(entityId, attributeData); + } + } + + EntityData createEntityData(DisplayAttribute attribute, Object value){ + DisplayAttribute castedAttr = (DisplayAttribute) attribute; + Object outputValue = castedAttr.getOutputValue(castedAttr.getInputType().cast(value)); + + EntityDataType entityDataType = (EntityDataType) castedAttr.getEntityDataType(); + return new EntityData<>( + castedAttr.getIndex(), + entityDataType, + outputValue + ); + } + + Equipment createEquipmentData(DisplayAttribute attribute, Object value){ + return new Equipment(EquipmentSlot.values()[attribute.getIndex()], (ItemStack) value); + } + + WrapperPlayServerUpdateAttributes.Property createAttributeData(DisplayAttribute attribute, Object value){ + return new WrapperPlayServerUpdateAttributes.Property(((AttributeDisplayAttribute) attribute).getAttribute(), + (float) value, + List.of()); + } + + void send(Player player){ + if (metadataPacket != null){ + PacketEvents.getAPI().getPlayerManager().sendPacket(player, metadataPacket); + } + + if (equipmentPacket != null){ + PacketEvents.getAPI().getPlayerManager().sendPacket(player, equipmentPacket); + } + + if (attributesPacket != null){ + PacketEvents.getAPI().getPlayerManager().sendPacket(player, attributesPacket); + } + } + + void send(UUID playerUUID){ + Player p = Bukkit.getPlayer(playerUUID); + if (p != null) send(p); + } + + void send(Collection players){ + for (Player p : players){ + send(p); + } + } + + void sendUUIDs(Collection playerUUIDs){ + for (UUID uuid : playerUUIDs){ + send(uuid); + } + } + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java new file mode 100644 index 00000000..f7766982 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java @@ -0,0 +1,23 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.attribute.Attribute; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; + +public class AttributeDisplayAttribute extends DisplayAttribute{ + + Attribute attribute; + protected AttributeDisplayAttribute(Attribute attribute) { + super(0, Float.class, EntityDataTypes.FLOAT); + this.attribute = attribute; + setAttributeType(AttributeType.ATTRIBUTE); + } + + public Attribute getAttribute() { + return attribute; + } + + @Override + public Float getOutputValue(Float value) { + return value; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttribute.java index 130933ae..fc670182 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttribute.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttribute.java @@ -8,6 +8,7 @@ public abstract class DisplayAttribute { Class inputType; Class outputType; EntityDataType entityDataType; + AttributeType type = AttributeType.METADATA; protected DisplayAttribute(int index, Class type, EntityDataType entityDataType){ this.index = index; @@ -39,4 +40,30 @@ public Class getOutputType(){ } public abstract V getOutputValue(T value); + + DisplayAttribute setAttributeType(AttributeType type){ + this.type = type; + return this; + } + + public boolean isMetadata(){ + return type == AttributeType.METADATA; + } + + public boolean isEquipment(){ + return type == AttributeType.EQUIPMENT; + } + + public boolean isAttribute(){ + return type == AttributeType.ATTRIBUTE; + } + + + + + enum AttributeType{ + METADATA, + EQUIPMENT, + ATTRIBUTE + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java index 1cfa7b79..e9a5a8f4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java @@ -1,5 +1,6 @@ package net.donnypz.displayentityutils.utils.packet.attributes; +import com.github.retrooper.packetevents.protocol.attribute.Attributes; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; import net.kyori.adventure.text.Component; @@ -66,4 +67,13 @@ public static final class Interaction{ public static final BasicDisplayAttribute RESPONSIVE = new BasicDisplayAttribute<>(10, Boolean.class, EntityDataTypes.BOOLEAN); } + public static final class Mannequin{ + public static final BasicDisplayAttribute NO_GRAVITY = new BasicDisplayAttribute<>(5, Boolean.class, EntityDataTypes.BOOLEAN); + public static final AttributeDisplayAttribute SCALE = new AttributeDisplayAttribute(Attributes.SCALE); + public static final PoseDisplayAttribute POSE = new PoseDisplayAttribute(6); + public static final MainHandDisplayAttribute MAIN_HAND = new MainHandDisplayAttribute(15); + public static final ResolvableProfileDisplayAttribute RESOLVABLE_PROFILE = new ResolvableProfileDisplayAttribute(17); + public static final BasicDisplayAttribute IMMOVABLE = new BasicDisplayAttribute<>(18, Boolean.class, EntityDataTypes.BOOLEAN); + } + } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java new file mode 100644 index 00000000..e19c6025 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java @@ -0,0 +1,19 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import io.github.retrooper.packetevents.util.SpigotConversionUtil; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; + +public class EquipmentAttribute extends DisplayAttribute{ + + protected EquipmentAttribute(EquipmentSlot slot) { + super(slot.ordinal(), ItemStack.class, EntityDataTypes.ITEMSTACK); + setAttributeType(AttributeType.EQUIPMENT); + } + + @Override + public com.github.retrooper.packetevents.protocol.item.ItemStack getOutputValue(ItemStack value) { + return SpigotConversionUtil.fromBukkitItemStack(value); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/MainHandDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/MainHandDisplayAttribute.java new file mode 100644 index 00000000..cf5d5edb --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/MainHandDisplayAttribute.java @@ -0,0 +1,15 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import org.bukkit.inventory.MainHand; + +public class MainHandDisplayAttribute extends DisplayAttribute{ + protected MainHandDisplayAttribute(int index) { + super(index, MainHand.class, Byte.class, EntityDataTypes.BYTE); + } + + @Override + public Byte getOutputValue(MainHand value) { + return (byte) (value == MainHand.LEFT ? 0 : 1); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java new file mode 100644 index 00000000..06ad7a78 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java @@ -0,0 +1,15 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import org.bukkit.entity.Pose; + +public class PoseDisplayAttribute extends DisplayAttribute{ + PoseDisplayAttribute(int index) { + super(index, Pose.class, Integer.class, EntityDataTypes.INT); + } + + @Override + public Integer getOutputValue(Pose pose) { + return pose == null ? Pose.STANDING.ordinal() : pose.ordinal(); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java new file mode 100644 index 00000000..0f6dcb0d --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java @@ -0,0 +1,16 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemProfile; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import io.papermc.paper.datacomponent.item.ResolvableProfile; + +public class ResolvableProfileDisplayAttribute extends DisplayAttribute { + protected ResolvableProfileDisplayAttribute(int index) { + super(index, ResolvableProfile.class, ItemProfile.class, EntityDataTypes.RESOLVABLE_PROFILE); + } + + @Override + public ItemProfile getOutputValue(ResolvableProfile value) { + return null; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java index f3afa02a..d8891a36 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java @@ -22,7 +22,7 @@ public final class VersionUtils { public static boolean IS_1_21_7 = Bukkit.getUnsafe().getProtocolVersion() >= 772; public static boolean IS_1_21_9 = Bukkit.getUnsafe().getProtocolVersion() >= 773; - public static boolean canViewDialogs(Player player, boolean sendErrorMessage){ + public static boolean canViewDialogs(@NotNull Player player, boolean sendErrorMessage){ if (!serverHasDialogs()){ if (sendErrorMessage){ player.sendMessage(DisplayAPI.pluginPrefix @@ -42,6 +42,10 @@ else if (getProtocolVersion(player) < 771){ //1.21.6 return true; } + public static boolean canSpawnMannequins(){ + return IS_1_21_9; + } + private static int getProtocolVersion(Player player){ if (DisplayAPI.isViaVerInstalled()){ return ViaVersionUtil.getProtocolVersion(player); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/DEUSubCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/DEUSubCommand.java index 391f47b3..17e95716 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/DEUSubCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/DEUSubCommand.java @@ -3,6 +3,7 @@ import net.donnypz.displayentityutils.utils.Direction; import org.bukkit.entity.Display; import org.bukkit.entity.ItemDisplay; +import org.bukkit.entity.Pose; import org.bukkit.entity.TextDisplay; import org.jetbrains.annotations.NotNull; @@ -57,7 +58,15 @@ protected static class TabSuggestion{ .suggestUsingCurrentString(); public static final TabSuggestion BILLBOARDS = new TabSuggestion(Arrays.stream(Display.Billboard.values()).map(Enum::name).toList()) .suggestUsingCurrentString(); - public static final TabSuggestion PART_TYPES = new TabSuggestion(List.of("block", "item", "text", "interaction")) + public static final TabSuggestion PART_TYPES = new TabSuggestion(List.of("block", "item", "text", "interaction", "mannequin")) + .suggestUsingCurrentString(); + public static final TabSuggestion MANNEQUIN_POSES = new TabSuggestion(List.of( + Pose.SLEEPING.name(), + Pose.SWIMMING.name(), + Pose.SNEAKING.name(), + Pose.STANDING.name(), + Pose.FALL_FLYING.name() //ELYTRA + )) .suggestUsingCurrentString(); public static final TabSuggestion ITEM_DISPLAY_TRANSFORMS = new TabSuggestion(Arrays.stream(ItemDisplay.ItemDisplayTransform.values()).map(Enum::name).toList()) .suggestUsingCurrentString(); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java index 60fd6799..68fc8b67 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java @@ -6,6 +6,7 @@ import net.donnypz.displayentityutils.command.group.GroupCMD; import net.donnypz.displayentityutils.command.interaction.InteractionCMD; import net.donnypz.displayentityutils.command.item.ItemCMD; +import net.donnypz.displayentityutils.command.mannequin.MannequinCMD; import net.donnypz.displayentityutils.command.parts.PartsCMD; import net.donnypz.displayentityutils.command.place.PlaceCMD; import net.donnypz.displayentityutils.command.text.TextCMD; @@ -47,6 +48,7 @@ public DisplayEntityPluginCommand(){ subCommands.put("item", new ItemCMD()); subCommands.put("text", new TextCMD()); subCommands.put("interaction", new InteractionCMD()); + subCommands.put("mannequin", new MannequinCMD()); subCommands.put("place", new PlaceCMD()); subCommands.put("anim", new AnimCMD()); subCommands.put("bdengine", new BDEngineCMD()); @@ -198,6 +200,7 @@ static void mainCommandHelp(CommandSender sender){ CMDUtils.sendCMD(sender, "/deu item", "Commands related to the Item Display parts of a Display Entity Model/Group"); CMDUtils.sendCMD(sender, "/deu text", "Commands related to the Text Display parts of a Display Entity Model/Group"); CMDUtils.sendCMD(sender, "/deu interaction", "Commands related to manipulating Interaction entities"); + CMDUtils.sendCMD(sender, "/deu mannequin", "Commands related to manipulating Mannequin entities"); CMDUtils.sendCMD(sender, "/deu place", "Assign a Display Entity Model/Group to an block that will spawn when placed"); CMDUtils.sendCMD(sender, "/deu anim", "Animation related commands"); CMDUtils.sendCMD(sender, "/deu listgroups [page-number]", "List all saved Display Entity Models/Groups"); @@ -222,7 +225,7 @@ public List onTabComplete(CommandSender sender, Command command, String String subcmd = args[0].toLowerCase(); String current = args[1]; switch (subcmd) { - case "interaction", "anim", "group", "parts", "bdengine", "text", "item", "place" -> { + case "interaction", "anim", "group", "parts", "bdengine", "text", "item", "place", "mannequin" -> { return getTabComplete(subcmd, current); } case "listgroups", "listanims" -> suggestions.addAll(DEUSubCommand.TabSuggestion.STORAGES.suggestions); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java index 5aa8d794..4f01b144 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java @@ -1,8 +1,11 @@ package net.donnypz.displayentityutils.command; +import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.parts.PartsCMD; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -64,4 +67,12 @@ public void execute(Player player, String[] args){ protected abstract boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args); protected abstract boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args); + + protected boolean isInvalidType(Player player, ActivePart part, SpawnedDisplayEntityPart.PartType validType){ + if (part.getType() != validType){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with "+validType.name().toLowerCase().replace("_"," ")+" entities", NamedTextColor.RED))); + return true; + } + return false; + } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index 8d8b278a..f6dd3a41 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -81,6 +81,12 @@ public enum Permission { INTERACTION_SPAWN("deu.interaction.spawn"), INTERACTION_INFO("deu.interaction.info"), + MANNEQUIN_POSE("deu.mannequin.pose"), + MANNEQUIN_SCALE("deu.mannequin.scale"), + MANNEQUIN_GRAVITY("deu.mannequin.gravity"), + MANNEQUIN_IMMOVABLE("deu.mannequin.immovable"), + MANNEQUIN_SET_EQUIPMENT("deu.mannequin.equipment"), + ANIM_NEW("deu.anim.new"), ANIM_SAVE("deu.anim.save"), ANIM_DELETE("deu.anim.delete"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java new file mode 100644 index 00000000..ea948c52 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -0,0 +1,58 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.command.CommandSender; + +public class MannequinCMD extends ConsoleUsableSubCommand { + public MannequinCMD() { + super(Permission.HELP, new MannequinHelpCMD()); + new MannequinPoseCMD(this); + new MannequinScaleCMD(this); + new MannequinToggleGravityCMD(this); + new MannequinToggleImmovableCMD(this); + new MannequinMainHandCMD(this); + new MannequinHeldItemCMD(this); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 2){ + help(sender, 1); + return; + } + String arg = args[1]; + DEUSubCommand subCommand = subCommands.get(arg); + if (subCommand == null){ + help(sender, 1); + } + else{ + DisplayEntityPluginCommand.executeCommand(subCommand, sender, args); + } + } + + static void help(CommandSender sender, int page){ + sender.sendMessage(Component.empty()); + sender.sendMessage(DisplayAPI.pluginPrefixLong); + if (page == 1){ + sender.sendMessage(Component.text("| Commands with \"-all\" will apply the command to all mannequins within a part selection", NamedTextColor.GOLD)); + CMDUtils.sendCMD(sender, "/deu mannequin help", "Get help for mannequins"); + CMDUtils.sendCMD(sender, "/deu mannequin pose [-all]", "Change your selected mannequin's pose"); + CMDUtils.sendCMD(sender, "/deu mannequin scale [-all]", "Set your selected mannequin's scale"); + CMDUtils.sendCMD(sender, "/deu mannequin togglegravity [-all ]", "Toggle the gravity of an mannequin"); + CMDUtils.sendCMD(sender, "/deu mannequin toggleimmovable [-all ]", "Toggle the immovability of an mannequin"); + CMDUtils.sendCMD(sender, "/deu mannequin mainhand ", "Set the mannequin's main hand"); + CMDUtils.sendCMD(sender, "/deu mannequin helditem
<\"-held\" | item-id>", "Set the item in a mannequin's main or offhand"); + } + else{ + CMDUtils.sendCMD(sender, "/deu mannequin armor [-stop]", "Set the armor of a mannequin by clicking it with armor pieces. \"-stop\" stops editing"); + CMDUtils.sendCMD(sender, "/deu mannequin clone", "Clone a mannequin"); + CMDUtils.sendCMD(sender, "/deu mannequin clonehere", "Clone a mannequin at your current location"); + } + + sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java new file mode 100644 index 00000000..81ad7c15 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java @@ -0,0 +1,82 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.donnypz.displayentityutils.utils.command.DEUCommandUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +class MannequinHeldItemCMD extends PartsSubCommand { + MannequinHeldItemCMD(@NotNull DEUSubCommand parentSubCommand) { + super("helditem", parentSubCommand, Permission.MANNEQUIN_SET_EQUIPMENT,4, 4); + setTabComplete(2, List.of("main", "off")); + setTabComplete(3, List.of("-held", "")); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(Component.text("Incorrect Usage! /deu mannequin helditem
<\"-held\" | item-id> [-all]", NamedTextColor.RED)); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + String hand = args[2]; + boolean isMainHand; + if (hand.equalsIgnoreCase("main")){ + isMainHand = true; + } + else if (hand.equalsIgnoreCase("off") || hand.equalsIgnoreCase("offhand")) { + isMainHand = false; + } + else{ + sendIncorrectUsage(player); + return false; + } + + String item = args[3]; + ItemStack itemStack = DEUCommandUtils.getItemFromText(item, player); + if (itemStack == null) return false; + + for (ActivePart part : selection.getSelectedParts()){ + if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) { + part.setMannequinHandItem(itemStack, isMainHand); + } + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set "+hand.toLowerCase()+" hand item of ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String hand = args[2]; + boolean isMainHand; + if (hand.equalsIgnoreCase("main")){ + isMainHand = true; + } + else if (hand.equalsIgnoreCase("off") || hand.equalsIgnoreCase("offhand")) { + isMainHand = false; + } + else{ + sendIncorrectUsage(player); + return false; + } + + String item = args[3]; + ItemStack itemStack = DEUCommandUtils.getItemFromText(item, player); + if (itemStack == null) return false; + + selectedPart.setMannequinHandItem(itemStack, isMainHand); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set "+hand.toLowerCase()+" hand item of selected mannequin!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHelpCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHelpCMD.java new file mode 100644 index 00000000..cef03219 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHelpCMD.java @@ -0,0 +1,26 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.command.ConsoleUsableSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import org.bukkit.command.CommandSender; + +public class MannequinHelpCMD extends ConsoleUsableSubCommand { + public MannequinHelpCMD() { + super(Permission.HELP); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 3){ + MannequinCMD.help(sender, 1); + } + else{ + try{ + MannequinCMD.help(sender, Integer.parseInt(args[2])); + } + catch(NumberFormatException e){ + MannequinCMD.help(sender, 1); + } + } + } +} \ No newline at end of file diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java new file mode 100644 index 00000000..fdb8ffcb --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java @@ -0,0 +1,62 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.MainHand; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +class MannequinMainHandCMD extends PartsSubCommand { + MannequinMainHandCMD(@NotNull DEUSubCommand parentSubCommand) { + super("mainhand", parentSubCommand, Permission.MANNEQUIN_POSE, 3, 3); + setTabComplete(2, List.of("left", "right")); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin mainhand [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + String handStr = args[2]; + try{ + MainHand hand = MainHand.valueOf(handStr); + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; + p.setMannequinMainHand(hand); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set main hand of ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid Main Hand!", NamedTextColor.RED))); + return false; + } + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + + String handStr = args[2]; + try{ + MainHand hand = MainHand.valueOf(handStr); + selectedPart.setMannequinMainHand(hand); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set mannequin's main hand!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid Main Hand!", NamedTextColor.RED))); + return false; + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java new file mode 100644 index 00000000..a58f7c63 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java @@ -0,0 +1,64 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.entity.Pose; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinPoseCMD extends PartsSubCommand { + MannequinPoseCMD(@NotNull DEUSubCommand parentSubCommand) { + super("pose", parentSubCommand, Permission.MANNEQUIN_POSE, 3, 3); + setTabComplete(2, TabSuggestion.MANNEQUIN_POSES); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin pose [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + String poseStr = args[2]; + try{ + Pose pose = Pose.valueOf(poseStr.toUpperCase()); + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; + p.setMannequinPose(pose); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set pose of ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid Pose!", NamedTextColor.RED))); + return false; + } + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String poseStr = args[2]; + try{ + Pose pose = Pose.valueOf(poseStr.toUpperCase()); + selectedPart.setMannequinPose(pose); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set mannequin pose!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid Pose!", NamedTextColor.RED))); + return false; + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java new file mode 100644 index 00000000..8007d8a7 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java @@ -0,0 +1,59 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.entity.Pose; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinScaleCMD extends PartsSubCommand { + MannequinScaleCMD(@NotNull DEUSubCommand parentSubCommand) { + super("scale", parentSubCommand, Permission.MANNEQUIN_SCALE, 3, 3); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin scale [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + String scaleStr = args[2]; + try{ + float scale = Float.parseFloat(scaleStr); + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; + p.setMannequinScale(scale); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set scale of ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + sendIncorrectUsage(player); + return false; + } + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String scaleStr = args[2]; + try{ + float scale = Float.parseFloat(scaleStr); + selectedPart.setMannequinScale(scale); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set mannequin scale!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + sendIncorrectUsage(player); + return false; + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java new file mode 100644 index 00000000..0849f064 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java @@ -0,0 +1,67 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +class MannequinToggleGravityCMD extends PartsSubCommand { + MannequinToggleGravityCMD(@NotNull DEUSubCommand parentSubCommand) { + super("togglegravity", parentSubCommand, Permission.MANNEQUIN_GRAVITY, 2, 2); + setTabComplete(3, List.of("on", "off")); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu mannequin togglegravity [-all ]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + if (args.length < 4){ + sendIncorrectUsage(player); + return false; + } + + boolean status; + String s = args[3]; + if (s.equalsIgnoreCase("on")){ + status = true; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled gravity for ALL selected mannequins ON"))); + } + else if (s.equalsIgnoreCase("off")){ + status = false; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled gravity for ALL selected mannequins OFF"))); + } + else{ + sendIncorrectUsage(player); + return false; + } + + for (ActivePart part : selection.getSelectedParts()){ + if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) { + part.setMannequinGravity(status); + } + } + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + selectedPart.setMannequinGravity(!selectedPart.hasMannequinGravity()); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Toggled gravity of selected mannequin!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java new file mode 100644 index 00000000..7b8c3e29 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java @@ -0,0 +1,67 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +class MannequinToggleImmovableCMD extends PartsSubCommand { + MannequinToggleImmovableCMD(@NotNull DEUSubCommand parentSubCommand) { + super("toggleimmovable", parentSubCommand, Permission.MANNEQUIN_IMMOVABLE, 2, 2); + setTabComplete(3, List.of("on", "off")); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu mannequin toggleimmovable [-all ]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + if (args.length < 4){ + sendIncorrectUsage(player); + return false; + } + + boolean status; + String s = args[3]; + if (s.equalsIgnoreCase("on")){ + status = true; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled immovability for ALL selected mannequins ON"))); + } + else if (s.equalsIgnoreCase("off")){ + status = false; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled immovability for ALL selected mannequins OFF"))); + } + else{ + sendIncorrectUsage(player); + return false; + } + + for (ActivePart part : selection.getSelectedParts()){ + if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) { + part.setMannequinImmovable(status); + } + } + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN); + selectedPart.setMannequinImmovable(!selectedPart.isMannequinImmovable()); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Toggled immovability of selected mannequin!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java index d9e029e3..9ef1b8a4 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java @@ -1,5 +1,6 @@ package net.donnypz.displayentityutils.command.parts; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.Permission; @@ -77,6 +78,17 @@ public void execute(Player player, String[] args) { }); selectEntity(player, entity.getUniqueId(), "Interaction"); } + case "mannequin" -> { + if (!VersionUtils.canSpawnMannequins()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your server version cannot spawn Mannequins!", NamedTextColor.RED))); + return; + } + Mannequin entity = loc.getWorld().spawn(loc, Mannequin.class, m -> { + m.setProfile(ResolvableProfile.resolvableProfile(player.getPlayerProfile())); + m.setInvulnerable(true); + }); + selectEntity(player, entity.getUniqueId(), "Mannequin"); + } default -> { incorrectUsage(player); } @@ -84,7 +96,7 @@ public void execute(Player player, String[] args) { } private void incorrectUsage(Player player){ - player.sendMessage(Component.text("Incorrect Usage! /deu parts create ", NamedTextColor.RED)); + player.sendMessage(Component.text("Incorrect Usage! /deu parts create ", NamedTextColor.RED)); } private void selectEntity(Player player, UUID entityUUID, String displayName){ @@ -94,5 +106,4 @@ private void selectEntity(Player player, UUID entityUUID, String displayName){ player.sendMessage(Component.text("| The created part has been automatically selected, removing previous selections", NamedTextColor.GRAY, TextDecoration.ITALIC)); DEUUser.getOrCreateUser(player).setSelectedPartSelection(new SinglePartSelection(SpawnedDisplayEntityPart.create(entityUUID)), false); } - } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java index 225c6d00..9825b895 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java @@ -4,28 +4,17 @@ import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; -import net.donnypz.displayentityutils.managers.DEUUser; -import net.donnypz.displayentityutils.utils.ConversionUtils; -import net.donnypz.displayentityutils.utils.DisplayEntities.SinglePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; -import net.donnypz.displayentityutils.utils.DisplayUtils; import net.donnypz.displayentityutils.utils.relativepoints.DisplayEntitySelector; import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.event.ClickCallback; -import net.kyori.adventure.text.event.ClickEvent; -import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.TextDecoration; -import org.bukkit.Bukkit; import org.bukkit.entity.Entity; import org.bukkit.entity.Interaction; +import org.bukkit.entity.Mannequin; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.time.Duration; import java.util.List; -import java.util.UUID; class PartsSelectCMD extends PlayerSubCommand { @@ -44,8 +33,8 @@ public void execute(Player player, String[] args) { String arg = args[2]; if (arg.equalsIgnoreCase("-target")){ Entity entity = player.getTargetEntity(10); - if (!(entity instanceof Interaction)) { - player.sendMessage(Component.text("Your targeted entity must be an interaction entity within 10 blocks of you", NamedTextColor.RED)); + if (!(entity instanceof Interaction || entity instanceof Mannequin)) { + player.sendMessage(Component.text("Your targeted entity must be an interaction or mannequin entity within 10 blocks of you", NamedTextColor.RED)); } else{ DisplayEntitySelector.select(player, entity); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java index 839dc610..84da9606 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java @@ -10,9 +10,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Material; -import org.bukkit.entity.Display; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; public class DisplayEntitySelector extends RelativePointSelector { @@ -63,6 +61,22 @@ public static void select(Player player, Entity entity){ .setSelectedPartSelection(new SinglePartSelection(part), false); part.glow(player, 30); RelativePointUtils.removeRelativePoints(player); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text((entity instanceof Display ? "Display" : "Interaction")+" Entity Selected!", NamedTextColor.GREEN))); + String entityType; + switch(entity){ + case Display d -> { + entityType = "Display"; + } + case Interaction i -> { + entityType = "Interaction"; + } + case Mannequin m -> { + entityType = "Mannequin"; + } + case Shulker s -> { + entityType = "Shulker"; + } + default -> entityType = ""; + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text(entityType+" Entity Selected!", NamedTextColor.GREEN))); } } From a10fb9140356ef8dea1eb4fc6eabf33528d0a5ab Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 19 Dec 2025 18:26:57 -0600 Subject: [PATCH 021/139] remove unused method --- .../displayentityutils/utils/PacketUtils.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java index 00540419..34280435 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java @@ -622,27 +622,4 @@ public static void setGlowing(@NotNull Player player, int entityId, long duratio setGlowing(player, entityId, false); }, durationInTicks); } - - @ApiStatus.Internal - public static int[] getTrackedIntersection(DEUUser user, SequencedCollection parts){ - Player p = Bukkit.getPlayer(user.getUserUUID()); - return parts.stream() - .filter(part -> { - if (part.isTrackedBy(user.getUserUUID())){ - part.hideFromPlayer(p); - return true; - } - return false; - }) - .mapToInt(PacketDisplayEntityPart::getEntityId) - .toArray(); - - /*int[] ids = new int[parts.size()]; - int i = 0; - for (PacketDisplayEntityPart part : parts){ - ids[i] = part.getEntityId(); - i++; - } - return ids;*/ - } } From 8017eaecdad0db4fb3025fa5835c865a4c1b52b3 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 19 Dec 2025 18:53:42 -0600 Subject: [PATCH 022/139] Rename #getInteractionTranslation methods to #getNonDisplayTranslation/#getTranslation for ActivePart & DisplayUtils --- .../utils/DisplayEntities/ActivePart.java | 51 +++++++++---------- .../DisplayEntities/AnimationPlayer.java | 2 +- .../DisplayEntities/InteractionEntity.java | 4 +- .../InteractionTransformation.java | 10 ++++ .../PacketDisplayEntityGroup.java | 2 +- .../PacketDisplayEntityPart.java | 35 ++++++------- .../SpawnedDisplayAnimationFrame.java | 4 +- .../SpawnedDisplayEntityGroup.java | 2 +- .../SpawnedDisplayEntityPart.java | 4 +- .../utils/DisplayUtils.java | 29 ++++------- 10 files changed, 70 insertions(+), 73 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index afab2f47..a65a3f0a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -448,28 +448,6 @@ public void unglow(@NotNull Player player) { */ public abstract @Nullable ItemStack getItemDisplayItem(); - public abstract void setMannequinPose(Pose pose); - - public abstract @Nullable Pose getMannequinPose(); - - public abstract void setMannequinScale(double scale); - - public abstract double getMannequinScale(); - - public abstract void setMannequinImmovable(boolean immovable); - - public abstract boolean isMannequinImmovable(); - - public abstract void setMannequinGravity(boolean gravity); - - public abstract boolean hasMannequinGravity(); - - public abstract void setMannequinMainHand(@NotNull MainHand mainHand); - - public abstract @Nullable MainHand getMannequinMainHand(); - - public abstract void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand); - /** * Set an attribute on this part, and send the updated attribute to viewing players. * @param attribute the attribute @@ -509,11 +487,10 @@ public void unglow(@NotNull Player player) { public abstract int getTeleportDuration(); /** - * Get the interaction translation of this part, relative to its group's location - * group's location only if the part's type is {@link SpawnedDisplayEntityPart.PartType#INTERACTION}. - * @return a {@link Vector} or null if the part is not an Interaction, or if the part is ungrouped + * Get the translation of this non-display entity part, relative to its group's location + * @return a {@link Vector} or null if the part is a display entity, or if the part is ungrouped */ - public abstract @Nullable Vector getInteractionTranslation(); + public abstract @Nullable Vector getNonDisplayTranslation(); public abstract void setInteractionHeight(float height); @@ -539,6 +516,28 @@ public void unglow(@NotNull Player player) { */ public abstract boolean isInteractionResponsive(); + public abstract void setMannequinPose(Pose pose); + + public abstract void setMannequinScale(double scale); + + public abstract void setMannequinImmovable(boolean immovable); + + public abstract void setMannequinGravity(boolean gravity); + + public abstract void setMannequinMainHand(@NotNull MainHand mainHand); + + public abstract void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand); + + public abstract @Nullable Pose getMannequinPose(); + + public abstract double getMannequinScale(); + + public abstract boolean isMannequinImmovable(); + + public abstract boolean hasMannequinGravity(); + + public abstract @Nullable MainHand getMannequinMainHand(); + /** * Adds a command to this part to execute when clicked, if its type is {@link SpawnedDisplayEntityPart.PartType#INTERACTION} * @param command The command to assign diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java index c45717e3..662065db 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java @@ -187,7 +187,7 @@ void animateInteractions(Collection players, Location groupLoc, SpawnedD continue; } - Vector currentVector = part.getInteractionTranslation(); + Vector currentVector = part.getNonDisplayTranslation(); if (currentVector == null){ continue; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java index 2a90bbc3..203e577c 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java @@ -38,7 +38,7 @@ final class InteractionEntity implements Serializable { this.height = interaction.getInteractionHeight(); this.width = interaction.getInteractionWidth(); this.isResponsive = interaction.isResponsive(); - this.vector = DisplayUtils.getInteractionTranslation(interaction).toVector3f(); + this.vector = DisplayUtils.getNonDisplayTranslation(interaction).toVector3f(); this.partUUID = DisplayUtils.getPartUUID(interaction); try{ @@ -55,7 +55,7 @@ final class InteractionEntity implements Serializable { this.height = c.getAttributeOrDefault(DisplayAttributes.Interaction.HEIGHT, 1f); this.width = c.getAttributeOrDefault(DisplayAttributes.Interaction.WIDTH, 1f); this.isResponsive = c.getAttributeOrDefault(DisplayAttributes.Interaction.RESPONSIVE, false); - this.vector = part.getInteractionTranslation().toVector3f(); + this.vector = part.getNonDisplayTranslation().toVector3f(); this.partUUID = part.partUUID; try{ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionTransformation.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionTransformation.java index 8fedab40..d794061e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionTransformation.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionTransformation.java @@ -30,6 +30,16 @@ public InteractionTransformation(){} this.width = width; } + + InteractionTransformation(Vector vector, float groupYawAtCreation, float groupPitchAtCreation, float height, float width){ + super(vector.toVector3f()); + this.vector = new Vector(vector.getX(), vector.getY(), vector.getZ()); + this.groupYawAtCreation = groupYawAtCreation; + this.groupPitchAtCreation = groupPitchAtCreation; + this.height = height; + this.width = width; + } + @ApiStatus.Internal public void writeExternal(ObjectOutput out) throws IOException { out.writeFloat(this.x); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index bfa5d9ea..e089bc25 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -326,7 +326,7 @@ else if (scaleInteractions){ PacketUtils.scaleInteraction(p, newHeight, newWidth, durationInTicks, 0); //Reset Translation then multiply by newScaleMultiplier - Vector translationVector = p.getInteractionTranslation(); + Vector translationVector = p.getNonDisplayTranslation(); if (translationVector == null){ continue; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 1ca18237..08f20892 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -158,7 +158,7 @@ public void showToPlayer(@NotNull Player player, GroupSpawnedEvent.@NotNull Spaw } DEUUser.getOrCreateUser(player).trackPacketEntity(this); if (type == SpawnedDisplayEntityPart.PartType.INTERACTION && hasGroup()){ - Vector translation = getInteractionTranslation(group.getLocation()); + Vector translation = getNonDisplayTranslation(group.getLocation()); location = location.clone().add(translation); } attributeContainer.sendEntity(type, getEntityId(), player, location); @@ -207,7 +207,7 @@ public void showToPlayers(@NotNull Collection players, GroupSpawnedEvent } } if (type == SpawnedDisplayEntityPart.PartType.INTERACTION && hasGroup()){ - Vector translation = getInteractionTranslation(group.getLocation()); + Vector translation = getNonDisplayTranslation(group.getLocation()); location = location.clone().add(translation); } attributeContainer.sendEntityUsingPlayers(type, getEntityId(), plrs, location); @@ -655,12 +655,19 @@ public float getViewRange(){ @Override - public @Nullable Vector getInteractionTranslation() { - if (type != SpawnedDisplayEntityPart.PartType.INTERACTION) { - return null; - } - if (group == null) return null; - return getInteractionTranslation(group.getLocation()); + public @Nullable Vector getNonDisplayTranslation() { + if (isDisplay() || group == null) return null; + return getNonDisplayTranslation(group.getLocation()); + } + + /** + * Get the Interaction's translation vector relative to a location + * @param referenceLocation the reference location + * @return A vector or null if the part is not an interaction + */ + public Vector getNonDisplayTranslation(@NotNull Location referenceLocation){ + if (isDisplay()) return null; + return referenceLocation.toVector().subtract(getLocation().toVector()); } @Override @@ -684,18 +691,6 @@ public void setInteractionResponsive(boolean responsive) { } } - /** - * Get the Interaction's translation vector relative to a location - * @param referenceLocation the reference location - * @return A vector or null if the part is not an interaction - */ - public Vector getInteractionTranslation(@NotNull Location referenceLocation){ - if (type != SpawnedDisplayEntityPart.PartType.INTERACTION) { - return null; - } - return referenceLocation.toVector().subtract(getLocation().toVector()); - } - @Override public float getInteractionHeight() { diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimationFrame.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimationFrame.java index 44b2b846..25ffd83f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimationFrame.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimationFrame.java @@ -124,7 +124,7 @@ public SpawnedDisplayAnimationFrame setTransformation(@NotNull ActiveGroup gr if (p.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ InteractionTransformation transform = new InteractionTransformation( - p.getInteractionTranslation().toVector3f(), + p.getNonDisplayTranslation(), gLoc.getYaw(), gLoc.getPitch(), p.getInteractionHeight(), @@ -157,7 +157,7 @@ public SpawnedDisplayAnimationFrame setTransformation(@NotNull ActiveGroup gr if (p.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ InteractionTransformation transform = new InteractionTransformation( - p.getInteractionTranslation().toVector3f(), + p.getNonDisplayTranslation(), gLoc.getYaw(), gLoc.getPitch(), p.getInteractionHeight(), diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index ca915c6c..6fbf24ba 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -506,7 +506,7 @@ else if (scaleInteractions){ DisplayUtils.scaleInteraction(i, newHeight, newWidth, durationInTicks, 0); //Reset Translation then multiply by newScaleMultiplier - Vector translationVector = DisplayUtils.getInteractionTranslation(i); + Vector translationVector = DisplayUtils.getNonDisplayTranslation(i); if (translationVector == null){ continue; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 12d40460..1bbd6a23 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -1057,12 +1057,12 @@ public void setAttributes(@NotNull DisplayAttributeMap attributeMap) { } @Override - public @Nullable Vector getInteractionTranslation() { + public @Nullable Vector getNonDisplayTranslation() { if (type != PartType.INTERACTION) { return null; } if (group == null) return null; - return DisplayUtils.getInteractionTranslation((Interaction) getEntity(), group.getLocation()); + return DisplayUtils.getNonDisplayTranslation((Interaction) getEntity(), group.getLocation()); } @Override diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java index 071ff44a..40dfe3bf 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java @@ -314,33 +314,26 @@ public static Location getInteractionCenter(@NotNull Interaction interaction){ /** - * Get the translation vector from the group's master part to the interaction's location - * @param interaction the interaction - * @return a vector or null if the Interaction entity is not in a group + * Get the translation vector from the entity's group's master part to the entity's location + * @param entity the interaction + * @return a vector or null if the entity is not in a group */ - public static Vector getInteractionTranslation(@NotNull Interaction interaction){ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(interaction); + public static @Nullable Vector getNonDisplayTranslation(@NotNull Entity entity){ + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); if (part == null){ return null; } - return getInteractionTranslation(interaction, part.getGroup().getLocation()); - /*return part - .getGroup() - .getMasterPart() - .getEntity() - .getLocation() - .toVector() - .subtract(interaction.getLocation().toVector());*/ + return getNonDisplayTranslation(entity, part.getGroup().getLocation()); } /** - * Get the translation vector from a location to the interaction's location - * @param interaction the interaction + * Get the translation vector from a location to the entity's location + * @param entity the entity * @param referenceLocation the reference location * @return a vector */ - public static Vector getInteractionTranslation(@NotNull Interaction interaction, @NotNull Location referenceLocation){ - return referenceLocation.toVector().subtract(interaction.getLocation().toVector()); + public static @NotNull Vector getNonDisplayTranslation(@NotNull Entity entity, @NotNull Location referenceLocation){ + return referenceLocation.toVector().subtract(entity.getLocation().toVector()); } /** @@ -581,7 +574,7 @@ public static void translate(@NotNull SpawnedDisplayEntityPart part, @NotNull Di * @param angleInDegrees the pivot angle in degrees */ public static void pivot(@NotNull Interaction interaction, @NotNull Location center, double angleInDegrees){ - Vector3f translationVector = DisplayUtils.getInteractionTranslation(interaction, center).toVector3f(); + Vector3f translationVector = DisplayUtils.getNonDisplayTranslation(interaction, center).toVector3f(); new Quaternionf() .rotateY((float) Math.toRadians(-angleInDegrees)) .transform(translationVector); From 47a2c2f39abe70b271fcb2980a0ef4159a4ff7cb Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 19 Dec 2025 19:27:29 -0600 Subject: [PATCH 023/139] rename PacketUtils#translateInteraction to #translateNonDisplay --- .../DisplayEntities/AnimationPlayer.java | 2 +- .../PacketDisplayEntityGroup.java | 4 +- .../PacketDisplayEntityPart.java | 2 +- .../displayentityutils/utils/PacketUtils.java | 68 +++++++++---------- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java index 662065db..5e973b52 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java @@ -227,7 +227,7 @@ void animateInteractions(Collection players, Location groupLoc, SpawnedD part.translate(moveVector, (float) moveVector.length(), frame.duration, 0); } else { - PacketUtils.translateInteraction(players, part, moveVector, (float) moveVector.length(), frame.duration, 0); + PacketUtils.translateNonDisplay(players, part, moveVector, (float) moveVector.length(), frame.duration, 0); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index e089bc25..54f6e474 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -336,7 +336,7 @@ else if (scaleInteractions){ translationVector.setZ((translationVector.getZ()/scaleMultiplier)*newScaleMultiplier); Vector moveVector = oldVector.subtract(translationVector); - PacketUtils.translateInteraction(p, moveVector, moveVector.length(), durationInTicks, 0); + PacketUtils.translateNonDisplay(p, moveVector, moveVector.length(), durationInTicks, 0); } } @@ -556,7 +556,7 @@ public void teleportMove(@NotNull Vector direction, double distance, int duratio for (PacketDisplayEntityPart part : groupParts.values()){ if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - PacketUtils.translateInteraction(part, direction, distance, durationInTicks, 0); + PacketUtils.translateNonDisplay(part, direction, distance, durationInTicks, 0); } } DisplayAPI.getScheduler().partRunTimerAsync(masterPart, new Scheduler.SchedulerRunnable() { diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 08f20892..0536cf07 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -1034,7 +1034,7 @@ public boolean hasLocation(){ @Override public boolean translate(@NotNull Vector direction, float distance, int durationInTicks, int delayInTicks) { if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - PacketUtils.translateInteraction(this, direction, distance, durationInTicks, delayInTicks); + PacketUtils.translateNonDisplay(this, direction, distance, durationInTicks, delayInTicks); } else{ PacketUtils.translate(this, direction, distance, durationInTicks, delayInTicks); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java index 34280435..3cfdb74a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java @@ -6,7 +6,6 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport; import io.github.retrooper.packetevents.util.SpigotConversionUtil; import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.managers.DEUUser; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityPart; @@ -16,18 +15,15 @@ import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import net.donnypz.displayentityutils.utils.version.folia.Scheduler; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Interaction; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; import java.util.Collection; import java.util.List; -import java.util.SequencedCollection; public final class PacketUtils { @@ -279,7 +275,7 @@ private static void sendInteractionPacket(int entityId, float newHeight, float n /** * Change the translation of a {@link PacketDisplayEntityPart} if it's not an {@link SpawnedDisplayEntityPart.PartType#INTERACTION}.

- * If it is an interaction, {@link #translateInteraction(PacketDisplayEntityPart, Direction, double, int, int)} will be called instead. + * If it is an interaction, {@link #translateNonDisplay(PacketDisplayEntityPart, Direction, double, int, int)} will be called instead. * @param part the part to translate * @param direction the direction to translate the display entity * @param distance translation distance @@ -288,8 +284,8 @@ private static void sendInteractionPacket(int entityId, float newHeight, float n */ public static void translate(@NotNull PacketDisplayEntityPart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ if (distance == 0) return; - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - translateInteraction(part, direction, distance, durationInTicks, delayInTicks); + if (part.isDisplay()){ + translateNonDisplay(part, direction, distance, durationInTicks, delayInTicks); return; } translate(part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); @@ -297,7 +293,7 @@ public static void translate(@NotNull PacketDisplayEntityPart part, @NotNull Dir /** * Change the translation of a {@link PacketDisplayEntityPart} if it's not an {@link SpawnedDisplayEntityPart.PartType#INTERACTION}.

- * If it is an interaction, {@link #translateInteraction(PacketDisplayEntityPart, Vector, double, int, int)} will be called instead. + * If it is an interaction, {@link #translateNonDisplay(PacketDisplayEntityPart, Vector, double, int, int)} will be called instead. * @param part the part to translate * @param direction the direction to translate the display entity * @param distance translation distance @@ -306,8 +302,8 @@ public static void translate(@NotNull PacketDisplayEntityPart part, @NotNull Dir */ public static void translate(@NotNull PacketDisplayEntityPart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ if (distance == 0) return; - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - translateInteraction(part, direction, distance, durationInTicks, delayInTicks); + if (!part.isDisplay()){ + translateNonDisplay(part, direction, distance, durationInTicks, delayInTicks); return; } if (delayInTicks < 0){ @@ -333,8 +329,8 @@ public static void translate(@NotNull PacketDisplayEntityPart part, @NotNull Vec * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull PacketDisplayEntityPart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull PacketDisplayEntityPart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); } @@ -348,8 +344,8 @@ public static void translateInteraction(@NotNull PacketDisplayEntityPart part, @ * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull PacketDisplayEntityPart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - if (part.getType() != SpawnedDisplayEntityPart.PartType.INTERACTION) return; + public static void translateNonDisplay(@NotNull PacketDisplayEntityPart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + if (part.isDisplay()) return; Location destination = part.getLocation().clone().add(direction.clone().normalize().multiply(distance)); if (durationInTicks <= 0 && delayInTicks <= 0){ @@ -398,8 +394,8 @@ public void run() { * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Player player, @NotNull Interaction interaction, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(player, interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Player player, @NotNull Interaction interaction, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(player, interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); } /** @@ -413,8 +409,8 @@ public static void translateInteraction(@NotNull Player player, @NotNull Interac * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Player player, @NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(List.of(player), interaction, direction, distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Player player, @NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(List.of(player), interaction, direction, distance, durationInTicks, delayInTicks); } /** @@ -428,8 +424,8 @@ public static void translateInteraction(@NotNull Player player, @NotNull Interac * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Player player, @NotNull ActivePart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(player, part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Player player, @NotNull ActivePart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(player, part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); } /** @@ -443,8 +439,8 @@ public static void translateInteraction(@NotNull Player player, @NotNull ActiveP * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Player player, @NotNull ActivePart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(List.of(player), part, direction, distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Player player, @NotNull ActivePart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(List.of(player), part, direction, distance, durationInTicks, delayInTicks); } /** @@ -458,8 +454,8 @@ public static void translateInteraction(@NotNull Player player, @NotNull ActiveP * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Collection players, @NotNull Interaction interaction, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(players, interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Collection players, @NotNull Interaction interaction, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(players, interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); } /** @@ -473,9 +469,9 @@ public static void translateInteraction(@NotNull Collection players, @No * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Collection players, @NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + public static void translateNonDisplay(@NotNull Collection players, @NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ Location l = interaction.getLocation(); - translateInteraction(players, interaction.getEntityId(), l, l.getYaw(), direction, distance, durationInTicks, delayInTicks); + translateNonDisplay(players, interaction.getEntityId(), l, l.getYaw(), direction, distance, durationInTicks, delayInTicks); } /** @@ -489,8 +485,8 @@ public static void translateInteraction(@NotNull Collection players, @No * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Collection players, @NotNull ActivePart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(players, part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Collection players, @NotNull ActivePart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(players, part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); } /** @@ -504,17 +500,17 @@ public static void translateInteraction(@NotNull Collection players, @No * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Collection players, @NotNull ActivePart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - if (part.getType() != SpawnedDisplayEntityPart.PartType.INTERACTION) return; + public static void translateNonDisplay(@NotNull Collection players, @NotNull ActivePart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + if (part.isDisplay()) return; Location l = part.getLocation(); if (l == null) return; - translateInteraction(players, part.getEntityId(), l, l.getYaw(), direction, distance, durationInTicks, delayInTicks); + translateNonDisplay(players, part.getEntityId(), l, l.getYaw(), direction, distance, durationInTicks, delayInTicks); } - private static void translateInteraction(Collection players, int entityId, Location location, float lastYaw, Vector direction, double distance, int durationInTicks, int delayInTicks){ + private static void translateNonDisplay(Collection players, int entityId, Location location, float lastYaw, Vector direction, double distance, int durationInTicks, int delayInTicks){ Location destination = location.clone().add(direction.clone().normalize().multiply(distance)); if (durationInTicks <= 0 && delayInTicks <= 0){ - sendInteractionTeleportPacket(entityId, destination, players); + sendTranslateTeleportPacket(entityId, destination, players); return; } @@ -539,17 +535,17 @@ public void run() { tpLoc.add(incrementVector); if (currentDistance >= distance){ - sendInteractionTeleportPacket(entityId, destination, players); + sendTranslateTeleportPacket(entityId, destination, players); cancel(); } else{ - sendInteractionTeleportPacket(entityId, tpLoc, players); + sendTranslateTeleportPacket(entityId, tpLoc, players); } } }, delayInTicks, 1); } - private static void sendInteractionTeleportPacket(int entityId, Location location, Collection players){ + private static void sendTranslateTeleportPacket(int entityId, Location location, Collection players){ for (Player p : players){ PacketEvents.getAPI().getPlayerManager().sendPacket(p, new WrapperPlayServerEntityTeleport(entityId, SpigotConversionUtil.fromBukkitLocation(location), From bde76977013723c282fc86face429ad50059428f Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 19 Dec 2025 19:35:01 -0600 Subject: [PATCH 024/139] Remove redundant #getGroupTag & #getPartUUID for multiple part entity types --- .../utils/DisplayUtils.java | 46 ++++--------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java index 40dfe3bf..e50c1a10 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java @@ -652,49 +652,24 @@ public void run() { } /** - * Gets the group tag of a Display Entity - * @param display Display Entity to retrieve the tag from - * @return Group tag of the entity. Null if the entity did not have a group tag. + * Gets the group tag of a valid part entity + * @param entity entity to retrieve the tag from + * @return a string, null if the entity did not have a group tag. */ - public static @Nullable String getGroupTag(Display display){ - return getPDCGroupTag(display); - } - - /** - * Gets the group tag of an Interaction Entity - * @param interaction Interaction Entity to retrieve the tag from - * @return Group tag of the entity. Null if the entity did not have a group tag. - */ - public static @Nullable String getGroupTag(Interaction interaction){ - return getPDCGroupTag(interaction); - } - - private static String getPDCGroupTag(Entity entity){ + public static @Nullable String getGroupTag(Entity entity){ + if (entity == null) return null; PersistentDataContainer pdc = entity.getPersistentDataContainer(); return pdc.get(DisplayAPI.getGroupTagKey(), PersistentDataType.STRING); } /** - * Gets the part uuid of a Display Entity - * @param display Display Entity to retrieve the uuid from - * @return Part UUID of the entity. Null if the entity is not part of a display entity group. Will still return a value if the entity - * was previously part of a group, but later removed. - */ - public static @Nullable UUID getPartUUID(Display display){ - return getPDCPartUUID(display); - } - - /** - * Gets the part uuid of an Interaction Entity - * @param interaction Interaction Entity to retrieve the uuid from - * @return Part UUID of the entity. Null if the entity is not part of a display entity group. Will still return a value if the entity + * Gets the part uuid of a valid part entity + * @param entity entity to retrieve the uuid from + * @return a UUID or null if the entity is not part of a group. Will still return a value if the entity * was previously part of a group, but later removed. */ - public static @Nullable UUID getPartUUID(Interaction interaction){ - return getPDCPartUUID(interaction); - } - - private static UUID getPDCPartUUID(Entity entity){ + public static @Nullable UUID getPartUUID(Entity entity){ + if (entity == null) return null; PersistentDataContainer pdc = entity.getPersistentDataContainer(); String value = pdc.get(DisplayAPI.getPartUUIDKey(), PersistentDataType.STRING); if (value != null){ @@ -709,7 +684,6 @@ private static UUID getPDCPartUUID(Entity entity){ * @return List of commands stored on this interaction entity */ public static @NotNull List getInteractionCommands(@NotNull Interaction interaction){ - List commands = new ArrayList<>(); commands.addAll(getInteractionLeftConsoleCommands(interaction)); commands.addAll(getInteractionLeftPlayerCommands(interaction)); From 31f10cd0d0f90204c8eb70328cdd16467840647b Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 19 Dec 2025 19:52:38 -0600 Subject: [PATCH 025/139] Remove redundant methods for multiple entity part types. Implementation for new part types --- .../utils/DisplayUtils.java | 78 ++++++------------- 1 file changed, 23 insertions(+), 55 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java index e50c1a10..9924fff7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java @@ -40,11 +40,15 @@ public final class DisplayUtils { private static final ListPersistentDataType tagPDCType = PersistentDataType.LIST.strings(); private DisplayUtils(){} + public static boolean isPartEntity(@NotNull Entity entity){ + return SpawnedDisplayEntityPart.PartType.getType(entity) != null; + } + public static @NotNull List getUngroupedPartEntities(@NotNull Location location, double distance){ List parts = new ArrayList<>(); for (Entity e : location.getNearbyEntities(distance, distance, distance)) { - if (!(e instanceof Display) && !(e instanceof Interaction)) continue; + if (!isPartEntity(e)) continue; if (e instanceof Display){ if (e.getVehicle() instanceof BlockDisplay) continue; } @@ -166,13 +170,13 @@ public static Vector pivotPitchAndYaw(@NotNull Vector vector, float pitchChange, } /** - * Get the location where a {@link PacketDisplayEntityPart} display entity is translated based off of its {@link Transformation}'s translation alone.
+ * Get the location where an {@link PacketDisplayEntityPart} display entity is translated based off of its {@link Transformation}'s translation alone.
* This may not be a perfect representation of where the model's location actually is, due to the shape of models varying (e.g.: Stone Block vs Stone Pressure Plate) * @param part The entity to get the location from * @return the location where the part is translated at. Null if the part is an interaction entity or if the transformation/location of the entity is unset */ public static @Nullable Location getFixedModelLocation(@NotNull PacketDisplayEntityPart part){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ return null; } @@ -185,13 +189,13 @@ public static Vector pivotPitchAndYaw(@NotNull Vector vector, float pitchChange, } /** - * Get the location where a {@link PacketDisplayEntityPart} display entity is translated based off of its {@link Transformation} and pitch and yaw.
+ * Get the location where an {@link ActivePart} display entity is translated based off of its {@link Transformation} and pitch and yaw.
* This may not be a perfect representation of where the model's location actually is, due to the shape of models varying (e.g.: Stone Block vs Stone Pressure Plate) * @param part The entity to get the location from - * @return the location where the part is translated at. Null if the part is an interaction entity + * @return the location where the part is translated at. Null if the part is not a display */ public static @Nullable Location getModelLocation(@NotNull ActivePart part){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ return null; } @@ -218,7 +222,7 @@ public static Vector pivotPitchAndYaw(@NotNull Vector vector, float pitchChange, /** * Calculate and get the culling values that would be applied to a {@link Display} * @param display the display - * @return a float array containing the width and height, respectively + * @return a float array containing the width and height, respectively. null if the part is not a display */ public static float[] getAutoCullValues(@NotNull Display display){ return getAutoCullValues(display, DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); @@ -229,7 +233,7 @@ public static float[] getAutoCullValues(@NotNull Display display){ * @param display the display * @param widthAdder the fixed value to increase the calculated width by * @param heightAdder the fixed value to increase the calculated height by - * @return a float array containing the width and height, respectively + * @return a float array containing the width and height, respectively. null if the part is not a display */ public static float[] getAutoCullValues(@NotNull Display display, float widthAdder, float heightAdder){ SpawnedDisplayEntityPart.PartType type = display instanceof BlockDisplay ? SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY : null; @@ -240,7 +244,7 @@ public static float[] getAutoCullValues(@NotNull Display display, float widthAdd /** * Calculate and get the culling values that would be applied to an {@link ActivePart} * @param part the part - * @return a float array containing the width and height, respectively + * @return a float array containing the width and height, respectively. null if the part is not a display */ public static float[] getAutoCullValues(@NotNull ActivePart part){ return getAutoCullValues(part, DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); @@ -251,9 +255,10 @@ public static float[] getAutoCullValues(@NotNull ActivePart part){ * @param part the part * @param widthAdder the fixed value to increase the calculated width by * @param heightAdder the fixed value to increase the calculated height by - * @return a float array containing the width and height, respectively + * @return a float array containing the width and height, respectively. null if the part is not a display */ public static float[] getAutoCullValues(@NotNull ActivePart part, float widthAdder, float heightAdder){ + if (!part.isDisplay()) return null; Transformation t = part.getTransformation(); return getAutoCullValues(part.getType(), t.getTranslation(), t.getScale(), t.getLeftRotation(), widthAdder, heightAdder); } @@ -915,27 +920,14 @@ public static boolean hasPartTag(@NotNull Entity entity, @NotNull String tag){ /** - * Checks if this display entity has the specified group tag - * @param display Display Entity to check for a group tag - * @param tag The tag to check for - * @return boolean whether this display entity has the group tag - */ - public static boolean isGroupTag(Display display, @NotNull String tag){ - String value = display.getPersistentDataContainer().get(DisplayAPI.getGroupTagKey(), PersistentDataType.STRING); - if (value == null){ - return false; - } - return tag.equals(value); - } - - /** - * Checks if this interaction entity has the specified group tag - * @param interaction Interaction Entity to check for a group tag - * @param tag The tag to check for - * @return boolean whether this interaction entity has the group tag + * Checks if an entity has the specified group tag + * @param entity entity to check for a group tag + * @param tag the group tag + * @return a boolean */ - public static boolean isGroupTag(Interaction interaction, @NotNull String tag){ - String value = interaction.getPersistentDataContainer().get(DisplayAPI.getGroupTagKey(), PersistentDataType.STRING); + public static boolean isGroupTag(Entity entity, @NotNull String tag){ + if (entity == null) return false; + String value = entity.getPersistentDataContainer().get(DisplayAPI.getGroupTagKey(), PersistentDataType.STRING); if (value == null){ return false; } @@ -948,31 +940,7 @@ public static boolean isGroupTag(Interaction interaction, @NotNull String tag){ * @return a boolean */ public static boolean isInGroup(Entity entity){ - if (entity instanceof Display display){ - return SpawnedDisplayEntityPart.getPart(display) != null; - } - else if (entity instanceof Interaction interaction){ - return SpawnedDisplayEntityPart.getPart(interaction) != null; - } - return false; - } - - /** - * Get the creation time of a Display Entity - * @param display The Display Entity to check for a creation time - * @return The Display Entity's Group's Creation time. -1 if this display is not part of a group - */ - public static long getCreationTime(Display display){ - return getCreationTime((Entity) display); - } - - /** - * Get the creation time of an Interaction Entity - * @param interaction The Interaction to check for a creation time - * @return The Interaction's Group's Creation time. -1 if this interaction is not part of a group - */ - public static long getCreationTime(Interaction interaction){ - return getCreationTime((Entity) interaction); + return SpawnedDisplayEntityPart.getPart(entity) != null; } /** From 60f305812ef7f3186946cb3fd6e10706ccbaf6d2 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 19 Dec 2025 19:53:05 -0600 Subject: [PATCH 026/139] Add SpawnedDisplayEntityPart#isOfType --- .../DisplayEntities/SpawnedDisplayEntityPart.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 1bbd6a23..afa6e104 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -1208,6 +1208,16 @@ public static PartType getType(@NotNull Entity entity){ return null; } } + + public boolean isOfType(Entity e){ + if (e instanceof BlockDisplay && this == BLOCK_DISPLAY) return true; + if (e instanceof ItemDisplay && this == ITEM_DISPLAY) return true; + if (e instanceof TextDisplay && this == TEXT_DISPLAY) return true; + if (e instanceof Interaction && this == INTERACTION) return true; + if (e instanceof Shulker && this == SHULKER) return true; + if (e instanceof Mannequin && this == MANNEQUIN) return true; + return false; + } } /** From 5ecf62796c5da82c05465667ec52872aceac771c Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 19 Dec 2025 21:21:15 -0600 Subject: [PATCH 027/139] Rework logic previously hardcoded for/against only Interaction parts --- .../events/PartTranslateEvent.java | 25 ++---- .../managers/DisplayGroupManager.java | 21 ++--- .../displayentityutils/utils/Direction.java | 10 +-- .../DisplayEntities/DisplayEntityGroup.java | 2 +- .../PacketDisplayEntityPart.java | 1 - .../SpawnedDisplayEntityGroup.java | 80 +++++++------------ .../SpawnedDisplayEntityPart.java | 27 +++---- .../utils/DisplayUtils.java | 2 +- .../command/group/GroupAddTargetCMD.java | 20 ++--- .../command/group/GroupSelectCMD.java | 2 +- .../command/group/GroupSelectNearestCMD.java | 2 +- .../interaction/InteractionAddToGroupCMD.java | 2 +- .../listeners/autogroup/AutoGroup.java | 4 +- .../bdengine/DatapackEntitySpawned.java | 4 +- .../expressions/ExprActiveGetGroup.java | 5 +- .../ExprActivePartTransLocation.java | 23 ++---- 16 files changed, 89 insertions(+), 141 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/PartTranslateEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/PartTranslateEvent.java index 80f4484c..d0aac4fa 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/PartTranslateEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/PartTranslateEvent.java @@ -11,12 +11,13 @@ import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.util.Transformation; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * Called when a {@link Display} or {@link Interaction} changes its translation using methods within the {@link DisplayGroupManager}. - * Can be cancelled + * Called when an entity changes its translation through the {@link DisplayUtils#translate(Display, Vector, double, int, int)} or similar methods. + *
Can be cancelled */ public final class PartTranslateEvent extends Event implements Cancellable { @@ -28,10 +29,6 @@ public final class PartTranslateEvent extends Event implements Cancellable { Transformation oldTransformation; Transformation newTransformation; - /** - * Called when a Display Entity or Interaction Entity changes its translation through the DisplayGroupManager. - * Can be cancelled - */ public PartTranslateEvent(@NotNull Entity entity, Location destination, Transformation oldTransformation, Transformation newTransformation){ this.entity = entity; this.destination = destination; @@ -61,12 +58,7 @@ public boolean isDisplay(){ * @return a {@link SpawnedDisplayEntityPart}, null if this entity is not a part */ public @Nullable SpawnedDisplayEntityPart getEntityAsSpawnedDisplayEntityPart(){ - if (entity instanceof Interaction i){ - return SpawnedDisplayEntityPart.getPart(i); - } - else{ - return SpawnedDisplayEntityPart.getPart((Display) entity); - } + return SpawnedDisplayEntityPart.getPart(entity); } /** @@ -93,19 +85,12 @@ public Location getDestination() { return newTransformation; } - - /** * Get the tag of this entity's group. * @return group tag, null if not grouped */ public String getGroupTag(){ - if (entity instanceof Interaction i){ - return DisplayUtils.getGroupTag(i); - } - else{ - return DisplayUtils.getGroupTag((Display) entity); - } + return DisplayUtils.getGroupTag(entity); } @Override diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java index 79e9209f..a21e2a10 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java @@ -548,26 +548,27 @@ else if (displayEntity.getPassengers().isEmpty()) { /** - * Get a Spawned Display Entity Group through an interaction entity - * - * @param interaction The interaction entity part of a display entity group - * @param radius The radius to check for a spawned display entity group - * @return SpawnedDisplayEntityGroup containing the interaction entity. Null if not found. + * Get a {@link SpawnedDisplayEntityGroup} through an eligible part entity + * @param entity The entity that's in a group + * @param radius The radius to search for the group + * @return a {@link SpawnedDisplayEntityGroup} containing the entity. Null if not found. */ - public static SpawnedDisplayEntityGroup getSpawnedGroup(@NotNull Interaction interaction, double radius) { + public static @Nullable SpawnedDisplayEntityGroup getSpawnedGroup(@NotNull Entity entity, double radius) { + if (!DisplayUtils.isPartEntity(entity)) return null; + //Check for existing group - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(interaction); + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); if (part != null && part.getGroup() != null) { return part.getGroup(); } //Get Nearby Groups - List results = getSpawnedGroupsNearLocation(interaction.getLocation(), radius); + List results = getSpawnedGroupsNearLocation(entity.getLocation(), radius); if (results.isEmpty()){ return null; } //Check if Interaction is part of group - part = SpawnedDisplayEntityPart.getPart(interaction); + part = SpawnedDisplayEntityPart.getPart(entity); return part == null ? null : part.getGroup(); } @@ -635,7 +636,7 @@ public static SpawnedDisplayEntityGroup getSpawnedGroup(@NotNull Interaction int continue; } if (addInteractions){ - result.group().addMissingInteractionEntities(DisplayConfig.getMaximumInteractionSearchRange()); + result.group().addMissingEntities(DisplayConfig.getMaximumInteractionSearchRange()); } results.add(result); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/Direction.java b/api/src/main/java/net/donnypz/displayentityutils/utils/Direction.java index 30cc3be0..0fc2195e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/Direction.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/Direction.java @@ -1,10 +1,9 @@ package net.donnypz.displayentityutils.utils; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import org.bukkit.Location; +import org.bukkit.entity.Display; import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; import org.bukkit.util.Vector; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -89,8 +88,8 @@ else if (this != FORWARD && this != BACK){ * @return A vector */ public Vector getVector(@NotNull Entity entity, boolean localSpace) { - boolean isInteraction = entity instanceof Interaction; - return getVector(entity.getLocation(), localSpace && !isInteraction); + boolean isDisplay = entity instanceof Display; + return getVector(entity.getLocation(), localSpace && isDisplay); } /** @@ -99,8 +98,7 @@ public Vector getVector(@NotNull Entity entity, boolean localSpace) { * @return A vector */ public Vector getVector(@NotNull ActivePart part, boolean localSpace) { - boolean isInteraction = part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION; - return getVector(part.getLocation(), localSpace && !isInteraction); + return getVector(part.getLocation(), localSpace && part.isDisplay()); } /** diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java index ddd2a8e7..9d9fecdd 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java @@ -236,7 +236,7 @@ public String getTag() { masterDisplay.getLocation(), settings); - SpawnedDisplayEntityPart part = group.addInteractionEntity(interaction); + SpawnedDisplayEntityPart part = group.addEntity(interaction); if (entity.hasLegacyPartTags()){ part.adaptScoreboardTags(true); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 0536cf07..c455da84 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -691,7 +691,6 @@ public void setInteractionResponsive(boolean responsive) { } } - @Override public float getInteractionHeight() { if (type != SpawnedDisplayEntityPart.PartType.INTERACTION) { diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index 6fbf24ba..6b79cfc5 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -151,44 +151,29 @@ else if (!groupParts.isEmpty()){ return part; } - /** - * Add an interaction entity to this group. If this group already contains this interaction entity as a registered part it will return the existing - * {@link SpawnedDisplayEntityPart}. If it doesn't then it will return a new {@link SpawnedDisplayEntityPart} - * @param interactionEntity - * @return a {@link SpawnedDisplayEntityPart} representing the Interaction entity + * Add a valid part entity to this group, when you don't know the type of entity you're dealing with + * @param entity the part entity to add + * @return a corresponding {@link SpawnedDisplayEntityPart} or null if the entity is not an eligible part entity */ - public SpawnedDisplayEntityPart addInteractionEntity(@NotNull Interaction interactionEntity){ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(interactionEntity); + public @Nullable SpawnedDisplayEntityPart addEntity(@NotNull Entity entity){ + if (entity instanceof Display display){ + return addDisplayEntity(display); + } + + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); if (part == null){ - part = new SpawnedDisplayEntityPart(this, interactionEntity, partUUIDRandom); + part = new SpawnedDisplayEntityPart(this, entity, partUUIDRandom); } else{ part.setGroup(this); } if (getVehicle() != null){ - alignInteractionWithMountedGroup(part, getVehicle()); + alignNonDisplayWithMountedGroup(part, getVehicle()); } return part; } - /** - * Add a valid part entity (Display or Interaction) to this group, when you don't know the type of entity you're dealing with - * @param entity the part entity to add - * @return a corresponding {@link SpawnedDisplayEntityPart} or null if the entity is not a part entity - */ - public SpawnedDisplayEntityPart addPartEntity(@NotNull Entity entity){ - if (entity instanceof Interaction interaction){ - return addInteractionEntity(interaction); - } - else if (entity instanceof Display display){ - return addDisplayEntity(display); - } - else{ - return null; - } - } - /** * Check if this group and a Display entity share the same creation time. If this returns true this does not guarantee * that the part is registered to this group. Using {@link SpawnedDisplayEntityGroup#addDisplayEntity(Display)} will @@ -202,7 +187,7 @@ public boolean hasSameCreationTime(Display display){ /** * Check if this group and an Interaction entity share the same creation time. If this returns true this does not guarantee - * that the part is registered to this group. Using {@link SpawnedDisplayEntityGroup#addInteractionEntity(Interaction)} will + * that the part is registered to this group. Using {@link SpawnedDisplayEntityGroup#addEntity(Interaction)} will * add the interaction entity to the group if it is not added already * @param interaction * @return a boolean @@ -223,27 +208,21 @@ private boolean sameCreationTime(Entity entity){ } /** - * Add Interactions that are meant to be a part of this group - * Usually these Interactions are unadded when a SpawnedDisplayEntityGroup is created during a new play session - * @param searchRange Distance to search for Interaction entities from the group's location - * @return a list of the interaction entities added to the group + * Add entities that are meant to be a part of this group. + * Usually these entities are unadded when a {@link SpawnedDisplayEntityGroup} is created during a new play session + * @param searchRange distance to search for entities from the group's location + * @return a list of the entities added to the group */ - public List addMissingInteractionEntities(double searchRange){ - List interactions = new ArrayList<>(); - //List existingInteractions = getSpawnedPartEntities(SpawnedDisplayEntityPart.PartType.INTERACTION); + public @NotNull List addMissingEntities(double searchRange){ + List entities = new ArrayList<>(); for (Entity e : getMasterPart().getEntity().getNearbyEntities(searchRange, searchRange, searchRange)) { - if (!(e instanceof Interaction i)){ - continue; - } - //if (!existingInteractions.contains(i) && sameCreationTime(i)){ - if (!sameCreationTime(i)){ - continue; - } + if (!DisplayUtils.isPartEntity(e) || e instanceof Display) continue; + if (!sameCreationTime(e)) continue; - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(i); + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(e); if (part == null){ - new SpawnedDisplayEntityPart(this, i, partUUIDRandom); + new SpawnedDisplayEntityPart(this, e, partUUIDRandom); } else{ if (this == part.getGroup()){ //Already in this group @@ -251,9 +230,9 @@ public List addMissingInteractionEntities(double searchRange){ } part.setGroup(this); } - interactions.add(i); + entities.add(e); } - return interactions; + return entities; } @ApiStatus.Internal @@ -275,8 +254,8 @@ public void seedPartUUIDs(long seed){ */ @Override public void showToPlayer(@NotNull Player player){ - for (ActivePart part : groupParts.values()){ - ((SpawnedDisplayEntityPart) part).showToPlayer(player); + for (SpawnedDisplayEntityPart part : groupParts.values()){ + part.showToPlayer(player); } } @@ -330,8 +309,7 @@ public List getUnaddedInteractionEntitiesInRange(double searchRange if ((e instanceof Interaction interaction)){ if (!existingInteractions.contains(e)){ if (addToGroup){ - addInteractionEntity(interaction); - + addEntity(interaction); } interactions.add(interaction); } @@ -844,7 +822,7 @@ public boolean rideEntity(@NotNull Entity vehicle){ } for (SpawnedDisplayEntityPart interactionPart: this.getParts(SpawnedDisplayEntityPart.PartType.INTERACTION)){ - alignInteractionWithMountedGroup(interactionPart, vehicle); + alignNonDisplayWithMountedGroup(interactionPart, vehicle); } return true; } @@ -871,7 +849,7 @@ public boolean isRiding(){ return getVehicle() != null; } - private void alignInteractionWithMountedGroup(SpawnedDisplayEntityPart part, Entity vehicle){ + private void alignNonDisplayWithMountedGroup(SpawnedDisplayEntityPart part, Entity vehicle){ final Interaction interaction = (Interaction) part.getEntity(); DisplayAPI.getScheduler().entityRunTimer(interaction, new Scheduler.SchedulerRunnable() { Location lastLoc = getLocation(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index afa6e104..b0ef9459 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -271,7 +271,7 @@ PartData getPartData() { * @return The SpawnedDisplayEntityPart. Null if not created during play session or not associated with any group */ public static @Nullable SpawnedDisplayEntityPart getPart(@NotNull Entity entity){ - if (!(entity instanceof Interaction || entity instanceof Display)) return null; + if (DisplayUtils.isPartEntity(entity)) return null; return allParts.get(new PartData(entity)); } @@ -347,7 +347,7 @@ public SpawnedDisplayEntityPart setGroup(@NotNull SpawnedDisplayEntityGroup newG } this.group = newGroup; - if (type != PartType.INTERACTION){ + if (isDisplay()){ Display display = (Display) getEntity(); if (isMaster() && this != newGroup.masterPart){ newGroup.masterPart = this; @@ -662,20 +662,18 @@ protected void cull(float width, float height){ @Override public void setGlowColor(@Nullable Color color){ Entity entity = getEntity(); - if (entity instanceof Interaction){ - return; + if (entity instanceof Display display){ + display.setGlowColorOverride(color); } - Display display = (Display) entity; - display.setGlowColorOverride(color); } @Override public @Nullable Color getGlowColor(){ - if (type == PartType.INTERACTION){ - return null; - } Entity entity = getEntity(); - return ((Display) entity).getGlowColorOverride(); + if (entity instanceof Display display){ + return display.getGlowColorOverride(); + } + return null; } /** @@ -757,7 +755,7 @@ public Interaction spawnInteractionAtDisplay(){ i.setInteractionWidth(width); i.setInteractionHeight(height); }); - group.addInteractionEntity(interaction); + group.addEntity(interaction); return interaction; } @@ -1058,11 +1056,8 @@ public void setAttributes(@NotNull DisplayAttributeMap attributeMap) { @Override public @Nullable Vector getNonDisplayTranslation() { - if (type != PartType.INTERACTION) { - return null; - } - if (group == null) return null; - return DisplayUtils.getNonDisplayTranslation((Interaction) getEntity(), group.getLocation()); + if (isDisplay() || group == null) return null; + return DisplayUtils.getNonDisplayTranslation(getEntity(), group.getLocation()); } @Override diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java index 9924fff7..1fb1ad39 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java @@ -40,7 +40,7 @@ public final class DisplayUtils { private static final ListPersistentDataType tagPDCType = PersistentDataType.LIST.strings(); private DisplayUtils(){} - public static boolean isPartEntity(@NotNull Entity entity){ + public static boolean isPartEntity(Entity entity){ // don't add notnull annotation return SpawnedDisplayEntityPart.PartType.getType(entity) != null; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java index a0ce139d..fe068a0d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java @@ -9,10 +9,12 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedPartSelection; +import net.donnypz.displayentityutils.utils.DisplayUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Entity; import org.bukkit.entity.Interaction; +import org.bukkit.entity.Mannequin; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -33,19 +35,17 @@ public void execute(Player player, String[] args) { return; } + Entity entity = player.getTargetEntity(10); - if (!(entity instanceof Interaction interaction)) { - player.sendMessage(Component.text("Your targeted entity must be an interaction entity within 10 blocks of you", NamedTextColor.RED)); + if (!(entity instanceof Interaction || entity instanceof Mannequin)) { + player.sendMessage(Component.text("Your targeted entity must be an interaction or mannequin entity within 10 blocks of you", NamedTextColor.RED)); return; } - /*if (FramePointDisplay.isRelativePointEntity(entity)){ - player.sendMessage(Component.text("Your cannot add the interaction entity from a point preview!", NamedTextColor.RED)); - return; - }*/ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(interaction); + + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); if (part != null) { if (part.getGroup() == group) { - player.sendMessage(Component.text("That interaction entity is already apart of your selected group!", NamedTextColor.RED)); + player.sendMessage(Component.text("That entity is already apart of your selected group!", NamedTextColor.RED)); } else { part.setGroup(group); @@ -53,10 +53,10 @@ public void execute(Player player, String[] args) { return; } else { - group.addInteractionEntity(interaction); + group.addEntity(entity); SpawnedPartSelection sel = (SpawnedPartSelection) DisplayGroupManager.getPartSelection(player); sel.refresh(); } - player.sendMessage(Component.text("Successfully added interaction entity to your selected group!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Successfully added entity to your selected group!", NamedTextColor.GREEN)); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java index 3e31d7fb..99e09a12 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java @@ -96,7 +96,7 @@ private void getSelectableGroups(Player player, double distance){ } boolean selectResult = DisplayGroupManager.setSelectedGroup(p, g); if (selectResult){ - g.addMissingInteractionEntities(distance); + g.addMissingEntities(distance); p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully selected group!", NamedTextColor.GREEN))); DisplayEntityPluginCommand.hideRelativePoints(player); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectNearestCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectNearestCMD.java index 49b9225e..5c7c4110 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectNearestCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectNearestCMD.java @@ -54,7 +54,7 @@ public void execute(Player player, String[] args) { return; } - group.addMissingInteractionEntities(searchDistance); + group.addMissingEntities(searchDistance); int selectDuration = 50; group.glowAndMarkInteractions(player, selectDuration); Entity entity = group.getMasterPart().getEntity(); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionAddToGroupCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionAddToGroupCMD.java index fd431df4..dca92698 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionAddToGroupCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionAddToGroupCMD.java @@ -40,7 +40,7 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ if (group instanceof SpawnedDisplayEntityGroup sg){ Interaction i = spawnInteraction(player, spawn, args); if (i == null) return; - sg.addInteractionEntity(i); + sg.addEntity(i); } else if (group instanceof PacketDisplayEntityGroup pg){ spawnInteraction(pg, player, spawn, args); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java index a2b17bcd..58c6c6ca 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java @@ -79,7 +79,7 @@ static void detectGroups(Chunk chunk, List entities){ SpawnedDisplayEntityGroup group = result.group(); foundGroups.add(group); - group.addMissingInteractionEntities(DisplayConfig.getMaximumInteractionSearchRange()); + group.addMissingEntities(DisplayConfig.getMaximumInteractionSearchRange()); if (!result.alreadyLoaded()){ group.playSpawnAnimation(); @@ -133,7 +133,7 @@ else if (entity instanceof Interaction interaction) { SpawnedDisplayEntityGroup group = result.group(); if (group.hasSameCreationTime(interaction)) { - group.addInteractionEntity(interaction); + group.addEntity(interaction); if (!events.containsKey(group)){ addedInteractionsForEvent.putIfAbsent(result.group(), new HashSet<>()); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java index f136b3df..342e4027 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java @@ -119,8 +119,8 @@ else if (display.getScoreboardTags().contains(LocalManager.datapackUngroupedAddL } } - for (Entity part : laterParts){ - group.addPartEntity(part); + for (Entity partEntity : laterParts){ + group.addEntity(partEntity); } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGetGroup.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGetGroup.java index 0c8c0d18..8abbe22e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGetGroup.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGetGroup.java @@ -12,6 +12,7 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; import net.donnypz.displayentityutils.utils.GroupResult; import org.bukkit.entity.Display; +import org.bukkit.entity.Entity; import org.bukkit.entity.Interaction; import org.jetbrains.annotations.Nullable; @@ -50,8 +51,8 @@ else if (obj instanceof Display display){ if (result == null) return null; return result.group(); } - else if (obj instanceof Interaction interaction){ - return DisplayGroupManager.getSpawnedGroup(interaction, DisplayConfig.getMaximumInteractionSearchRange()); + else if (obj instanceof Entity entity){ + return DisplayGroupManager.getSpawnedGroup(entity, DisplayConfig.getMaximumInteractionSearchRange()); } return null; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActivePartTransLocation.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActivePartTransLocation.java index 572f5c1d..32d0bb5b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActivePartTransLocation.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActivePartTransLocation.java @@ -5,12 +5,11 @@ import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; -import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityPart; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; import net.donnypz.displayentityutils.utils.DisplayUtils; import org.bukkit.Location; import org.bukkit.entity.Display; -import org.bukkit.entity.Interaction; +import org.bukkit.entity.Entity; import org.jetbrains.annotations.Nullable; @Name("Translated Location of Active Part / Entity") @@ -32,27 +31,19 @@ public Class getReturnType() { @Override @Nullable public Location convert(Object o) { - if (o instanceof SpawnedDisplayEntityPart part){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - return part.getLocation(); + if (o instanceof ActivePart part){ + if (part.isDisplay()){ + return DisplayUtils.getModelLocation(part); } else{ - return DisplayUtils.getModelLocation((Display) part.getEntity()); - } - } - else if (o instanceof PacketDisplayEntityPart part){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ return part.getLocation(); } - else{ - return DisplayUtils.getModelLocation(part); - } } else if (o instanceof Display d){ return DisplayUtils.getModelLocation(d); } - else if (o instanceof Interaction i){ - return i.getLocation(); + else if (o instanceof Entity e && DisplayUtils.isPartEntity(e)){ + return e.getLocation(); } return null; } From d85394a769a1d79504457206d8c0e56234ac57b2 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 19 Dec 2025 21:24:29 -0600 Subject: [PATCH 028/139] Remove redundant "-target" selector when using commands --- .../command/DisplayEntityPluginCommand.java | 12 ++++++++++++ .../command/group/GroupAddTargetCMD.java | 7 ++----- .../command/parts/PartsSelectCMD.java | 14 +++++--------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java index 68fc8b67..386c3e7c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java @@ -18,6 +18,9 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Interaction; +import org.bukkit.entity.Mannequin; import org.bukkit.entity.Player; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -147,6 +150,15 @@ public static void hideRelativePoints(Player player){ } } + public static Entity getTargetEntity(Player player){ + Entity entity = player.getTargetEntity(10); + if (!(entity instanceof Interaction || entity instanceof Mannequin)) { + player.sendMessage(Component.text("Your targeted entity must be an interaction or mannequin entity within 10 blocks of you", NamedTextColor.RED)); + return null; + } + return entity; + } + @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (args.length == 0) { diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java index fe068a0d..20d66cb7 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java @@ -36,11 +36,8 @@ public void execute(Player player, String[] args) { } - Entity entity = player.getTargetEntity(10); - if (!(entity instanceof Interaction || entity instanceof Mannequin)) { - player.sendMessage(Component.text("Your targeted entity must be an interaction or mannequin entity within 10 blocks of you", NamedTextColor.RED)); - return; - } + Entity entity = DisplayEntityPluginCommand.getTargetEntity(player); + if (entity == null) return; SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); if (part != null) { diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java index 9825b895..9c943519 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java @@ -2,6 +2,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.utils.relativepoints.DisplayEntitySelector; @@ -9,8 +10,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; -import org.bukkit.entity.Mannequin; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -32,13 +31,10 @@ public void execute(Player player, String[] args) { try{ String arg = args[2]; if (arg.equalsIgnoreCase("-target")){ - Entity entity = player.getTargetEntity(10); - if (!(entity instanceof Interaction || entity instanceof Mannequin)) { - player.sendMessage(Component.text("Your targeted entity must be an interaction or mannequin entity within 10 blocks of you", NamedTextColor.RED)); - } - else{ - DisplayEntitySelector.select(player, entity); - } + Entity entity = DisplayEntityPluginCommand.getTargetEntity(player); + if (entity == null) return; + + DisplayEntitySelector.select(player, entity); return; } From 6a06057c02a8554ae270c3e9efe52c53fe3d755e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 19 Dec 2025 23:28:38 -0600 Subject: [PATCH 029/139] Update teleport and translate methods to support more non-display parts --- .../PacketDisplayEntityGroup.java | 4 +- .../SpawnedDisplayEntityGroup.java | 32 ++++++----- .../SpawnedDisplayEntityPart.java | 18 ++----- .../utils/DisplayUtils.java | 54 +++++++++---------- 4 files changed, 51 insertions(+), 57 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index 54f6e474..24e01a33 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -555,7 +555,7 @@ public void teleportMove(@NotNull Vector direction, double distance, int duratio .multiply(movementIncrement); for (PacketDisplayEntityPart part : groupParts.values()){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ PacketUtils.translateNonDisplay(part, direction, distance, durationInTicks, 0); } } @@ -600,7 +600,7 @@ public boolean teleport(@NotNull Location tpLocation, boolean respectGroupDirect } masterPart.teleportUnsetPassengers(tpLocation); for (PacketDisplayEntityPart part : groupParts.values()){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ Vector vector = oldMasterLoc.toVector().subtract(part.getLocation().toVector()); Location interactionTpLoc = tpLocation.clone().subtract(vector); part.teleport(interactionTpLoc); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index 6b79cfc5..db6fcbed 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -532,8 +532,8 @@ private void teleportWithoutEvent(Location location, boolean respectGroupDirecti for (SpawnedDisplayEntityPart part : this.getParts()){ part.getEntity().setRotation(location.getYaw(), location.getPitch()); - //Interaction Entity TP - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + //Non-Display TP + if (!part.isDisplay()){ Interaction interaction = (Interaction) part.getEntity(); Vector vector = oldMasterLoc.toVector().subtract(interaction.getLocation().toVector()); Location tpLocation = location.clone().subtract(vector); @@ -546,37 +546,43 @@ private void teleportWithoutEvent(Location location, boolean respectGroupDirecti } } - private static void translateInteractionEventless(@NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - Location destination = interaction.getLocation().clone().add(direction.clone().normalize().multiply(distance)); + private static void translateEntityEventless(@NotNull Entity entity, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + DisplayUtils.translate(entity, direction, distance, durationInTicks, delayInTicks); + Location destination = entity.getLocation().clone().add(direction.clone().normalize().multiply(distance)); + + if (durationInTicks <= 0 && delayInTicks <= 0){ + FoliaUtils.teleport(entity, destination); + return; + } + double movementIncrement = distance/(double) Math.max(durationInTicks, 1); Vector incrementVector = direction .clone() .normalize() .multiply(movementIncrement); - DisplayAPI.getScheduler().entityRunTimer(interaction, new Scheduler.SchedulerRunnable(){ + DisplayAPI.getScheduler().entityRunTimer(entity, new Scheduler.SchedulerRunnable() { double currentDistance = 0; - float lastYaw = interaction.getYaw(); + float lastYaw = entity.getYaw(); @Override public void run() { - float newYaw = interaction.getYaw(); + float newYaw = entity.getYaw(); if (newYaw != lastYaw){ incrementVector.rotateAroundY(Math.toRadians(lastYaw-newYaw)); lastYaw = newYaw; } currentDistance+=Math.abs(movementIncrement); - Location tpLoc = interaction.getLocation().clone().add(incrementVector); + Location tpLoc = entity.getLocation().clone().add(incrementVector); if (currentDistance >= distance){ - FoliaUtils.teleport(interaction, destination); + FoliaUtils.teleport(entity, destination); cancel(); } else{ - FoliaUtils.teleport(interaction, tpLoc); + FoliaUtils.teleport(entity, tpLoc); } } }, delayInTicks, 1); - } @Override @@ -594,8 +600,8 @@ public void teleportMove(@NotNull Vector direction, double distance, int duratio .multiply(movementIncrement); for (SpawnedDisplayEntityPart part : groupParts.values()){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - translateInteractionEventless((Interaction) part.getEntity(), direction, distance, durationInTicks, 0); + if (!part.isDisplay()){ + translateEntityEventless(part.getEntity(), direction, distance, durationInTicks, 0); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index b0ef9459..be667402 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -97,12 +97,7 @@ public final class SpawnedDisplayEntityPart extends ActivePart implements Spawne private void applyData(Random random, Entity entity){ adaptLegacyPartTags(); entity.getPersistentDataContainer().set(SpawnedDisplayEntityGroup.creationTimeKey, PersistentDataType.LONG, group.getCreationTime()); - if (entity instanceof Display display){ - removeFromPreviousGroup(display); - } - else{ - removeFromPreviousGroup((Interaction) entity); - } + removeFromPreviousGroup(entity); this.partData = new PartData(entity); this.entityUUID = entity.getUniqueId(); @@ -164,15 +159,8 @@ private boolean groupContainsUUID(UUID partUUID){ return group.groupParts.containsKey(partUUID); } - private void removeFromPreviousGroup(Display display){ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(display); - if (part != null){ - part.remove(false); - } - } - - private void removeFromPreviousGroup(Interaction i){ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(i); + private void removeFromPreviousGroup(Entity entity){ + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); if (part != null){ part.remove(false); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java index 1fb1ad39..ab40d895 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java @@ -467,24 +467,24 @@ public static void translate(@NotNull Display display, @NotNull Direction direct } /** - * Attempts to change the translation of an interaction entity similar + * Attempts to change the translation of an entity similar * to a Display Entity, through smooth teleportation. - * Doing multiple translations on an Interaction entity at the same time may have unexpected results - * @param direction The direction to translate the interaction entity - * @param interaction Interaction Entity to translate - * @param distance How far the interaction entity should be translated + * Doing multiple translations on an entity at the same time may have unexpected results + * @param direction The direction to translate the entity + * @param entity entity to translate + * @param distance How far the entity should be translated * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translate(@NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + public static void translate(@NotNull Entity entity, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ if (distance == 0) return; - Location destination = interaction.getLocation().clone().add(direction.clone().normalize().multiply(distance)); - if (!new PartTranslateEvent(interaction, destination, null,null).callEvent()){ + Location destination = entity.getLocation().clone().add(direction.clone().normalize().multiply(distance)); + if (!new PartTranslateEvent(entity, destination, null,null).callEvent()){ return; } if (durationInTicks <= 0 && delayInTicks <= 0){ - FoliaUtils.teleport(interaction, destination); + FoliaUtils.teleport(entity, destination); return; } @@ -494,25 +494,25 @@ public static void translate(@NotNull Interaction interaction, @NotNull Vector d .normalize() .multiply(movementIncrement); - DisplayAPI.getScheduler().entityRunTimer(interaction, new Scheduler.SchedulerRunnable() { + DisplayAPI.getScheduler().entityRunTimer(entity, new Scheduler.SchedulerRunnable() { double currentDistance = 0; - float lastYaw = interaction.getYaw(); + float lastYaw = entity.getYaw(); @Override public void run() { - float newYaw = interaction.getYaw(); + float newYaw = entity.getYaw(); if (newYaw != lastYaw){ incrementVector.rotateAroundY(Math.toRadians(lastYaw-newYaw)); lastYaw = newYaw; } currentDistance+=Math.abs(movementIncrement); - Location tpLoc = interaction.getLocation().clone().add(incrementVector); + Location tpLoc = entity.getLocation().clone().add(incrementVector); if (currentDistance >= distance){ - FoliaUtils.teleport(interaction, destination); + FoliaUtils.teleport(entity, destination); cancel(); } else{ - FoliaUtils.teleport(interaction, tpLoc); + FoliaUtils.teleport(entity, tpLoc); } } }, delayInTicks, 1); @@ -520,17 +520,17 @@ public void run() { /** - * Attempts to change the translation of an interaction entity similar + * Attempts to change the translation of an entity similar * to a Display Entity, through smooth teleportation. - * Doing multiple translations on an Interaction entity at the same time may have unexpected results - * @param interaction Interaction Entity to translate - * @param direction The direction to translate the interaction entity - * @param distance How far the interaction entity should be translated + * Doing multiple translations on an entity at the same time may have unexpected results + * @param entity entity to translate + * @param direction The direction to translate the entity + * @param distance How far the entity should be translated * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translate(@NotNull Interaction interaction, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translate(interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); + public static void translate(@NotNull Entity entity, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translate(entity, direction.getVector(entity, true), distance, durationInTicks, delayInTicks); } /** @@ -544,8 +544,8 @@ public static void translate(@NotNull Interaction interaction, @NotNull Directio * @param delayInTicks How long before the translation should begin */ public static void translate(@NotNull SpawnedDisplayEntityPart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - translate((Interaction) part.getEntity(), direction, distance, durationInTicks, delayInTicks); + if (!part.isDisplay()){ + translate(part.getEntity(), direction, distance, durationInTicks, delayInTicks); return; } translate((Display) part.getEntity(), direction, distance, durationInTicks, delayInTicks); @@ -562,9 +562,9 @@ public static void translate(@NotNull SpawnedDisplayEntityPart part, @NotNull Ve * @param delayInTicks How long before the translation should begin */ public static void translate(@NotNull SpawnedDisplayEntityPart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - Interaction interaction = (Interaction) part.getEntity(); - translate(interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); + if (!part.isDisplay()){ + Entity entity = part.getEntity(); + translate(entity, direction.getVector(entity, true), distance, durationInTicks, delayInTicks); return; } Display display = (Display) part.getEntity(); From d1516ffb1e4e9b40465c40d7135628447edbaa1a Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 20 Dec 2025 00:56:09 -0600 Subject: [PATCH 030/139] rework more logic to support new part types --- .../managers/DisplayGroupManager.java | 2 +- .../utils/DisplayEntities/ActiveGroup.java | 6 ++-- .../utils/DisplayEntities/ActivePart.java | 11 ++++--- .../DisplayEntities/GroupEntityFollower.java | 2 +- .../DisplayEntities/GroupSpawnSettings.java | 2 +- .../PacketDisplayEntityGroup.java | 2 +- .../PacketDisplayEntityPart.java | 21 +++++++------ .../command/parts/PartsBillboardCMD.java | 4 +-- .../command/parts/PartsGlowColorCMD.java | 4 +-- .../command/parts/PartsInfoCMD.java | 30 +++++++++---------- .../command/parts/PartsScaleCMD.java | 6 ++-- .../expressions/ExprActiveGlowColor.java | 4 +-- 12 files changed, 46 insertions(+), 48 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java index a21e2a10..9031f947 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java @@ -136,7 +136,7 @@ public static void removeSpawnedGroup(SpawnedDisplayEntityGroup spawnedGroup, bo Chunk mainChunk = spawnedGroup.getLocation().getChunk(); ticketChunk(mainChunk, chunks); for (SpawnedDisplayEntityPart part : spawnedGroup.getParts()) { - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ //Chunk may be different from main chunk + if (!part.isDisplay()){ //Chunk may be different from main chunk Entity e = part.getEntity(); Chunk c = e.getChunk(); if (c != mainChunk){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java index 199dcdd0..031577c2 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java @@ -325,9 +325,7 @@ public void glow(long durationInTicks){ @Override public void glow(@NotNull Player player, long durationInTicks){ for (ActivePart part : groupParts.values()){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION || part.type == SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY){ - continue; - } + if (!part.canGlow()) continue; if (!part.isGlowing()){ part.glow(player, durationInTicks); } @@ -466,7 +464,7 @@ public List getParts(@NotNull SpawnedDisplayEntityPart.PartType partType){ public List getDisplayParts(){ List partList = new ArrayList<>(); for (T part : groupParts.sequencedValues()){ - if (part.type != SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (part.isDisplay()){ partList.add(part); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index a65a3f0a..523b4913 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -169,7 +169,7 @@ public boolean hasTag(@NotNull String tag){ * @param heightAdder The amount of height to be added to the culling range */ public void autoCull(float widthAdder, float heightAdder){ - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!isDisplay()) return; Transformation transformation = getTransformation(); if (transformation == null) return; DisplayAPI.getScheduler().partRunAsync(this, () -> { @@ -193,7 +193,9 @@ public SpawnedDisplayEntityPart.PartType getType(){ * @return a boolean */ public boolean canGlow(){ - return type != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY && type != SpawnedDisplayEntityPart.PartType.INTERACTION; + return type != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY + && type != SpawnedDisplayEntityPart.PartType.INTERACTION + && type != SpawnedDisplayEntityPart.PartType.SHULKER; } public boolean isDisplay(){ @@ -207,8 +209,9 @@ public boolean isDisplay(){ * @param player the player */ public void glow(@NotNull Player player){ - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - PacketUtils.setGlowing(player, getEntityId(), true); + if (canGlow()){ + PacketUtils.setGlowing(player, getEntityId(), true); + } } /** diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupEntityFollower.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupEntityFollower.java index 56d048de..33f89ab0 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupEntityFollower.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupEntityFollower.java @@ -173,7 +173,7 @@ private void apply(Entity entity, MultiPartSelection selection, float newYaw, private void pivotDisplayPitch(ActivePart part, boolean zero, float newPitch){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ return; } Transformation t = part.getTransformation(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java index be49aa02..4a19d055 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java @@ -154,7 +154,7 @@ boolean applyVisibility(PacketDisplayEntityPart part, Player player){ } boolean applyAttributes(PacketDisplayEntityPart part){ - if (part.type != SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (part.isDisplay()){ //Teleport Duration part.attributeContainer.setAttribute(DisplayAttributes.TELEPORTATION_DURATION, teleportationDuration); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index 24e01a33..fb168f51 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -538,7 +538,7 @@ public void setRotation(float pitch, float yaw, boolean pivotIfInteraction){ @Override public void pivot(float angleInDegrees) { for (PacketDisplayEntityPart part : groupParts.values()){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ part.pivot(angleInDegrees); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index c455da84..311f26ef 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -80,13 +80,12 @@ public PacketDisplayEntityPart(@NotNull SpawnedDisplayEntityPart.PartType partTy } private void setDefaultTransformValues(){ - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - return; + if (isDisplay()){ + attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.TRANSLATION, new Vector3f()); + attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.SCALE, new Vector3f(1)); + attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.LEFT_ROTATION, new Quaternionf()); + attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.RIGHT_ROTATION, new Quaternionf()); } - attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.TRANSLATION, new Vector3f()); - attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.SCALE, new Vector3f(1)); - attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.LEFT_ROTATION, new Quaternionf()); - attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.RIGHT_ROTATION, new Quaternionf()); } /** @@ -157,7 +156,7 @@ public void showToPlayer(@NotNull Player player, GroupSpawnedEvent.@NotNull Spaw return; } DEUUser.getOrCreateUser(player).trackPacketEntity(this); - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION && hasGroup()){ + if (!isDisplay() && hasGroup()){ Vector translation = getNonDisplayTranslation(group.getLocation()); location = location.clone().add(translation); } @@ -206,7 +205,7 @@ public void showToPlayers(@NotNull Collection players, GroupSpawnedEvent DEUUser.getOrCreateUser(player).trackPacketEntity(this); } } - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION && hasGroup()){ + if (!isDisplay() && hasGroup()){ Vector translation = getNonDisplayTranslation(group.getLocation()); location = location.clone().add(translation); } @@ -928,7 +927,7 @@ public float getYaw(){ */ @Override public void pivot(float angleInDegrees) { - if (type != SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!isDisplay()) return; pivot(getYaw(), getPitch(), angleInDegrees); } @@ -994,7 +993,7 @@ void teleportUnsetPassengers(@NotNull Location location){ */ @Override public @Nullable Location getLocation(){ - if (!isMaster && group != null && type != SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!isMaster && group != null && isDisplay()){ return group.getLocation(); } if (packetLocation != null){ @@ -1032,7 +1031,7 @@ public boolean hasLocation(){ */ @Override public boolean translate(@NotNull Vector direction, float distance, int durationInTicks, int delayInTicks) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!isDisplay()){ PacketUtils.translateNonDisplay(this, direction, distance, durationInTicks, delayInTicks); } else{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java index 1d0e93fb..f958dcd8 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java @@ -35,8 +35,8 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Interaction entities cannot have a billboard applied!", NamedTextColor.RED))); + if (!selectedPart.isDisplay()) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Only display entities can have a billboard applied!", NamedTextColor.RED))); } else{ Display.Billboard billboard = getBillboard(player, args[2]); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java index 57060a77..6b7b236c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java @@ -39,8 +39,8 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { Color color = getColor(player, args[2]); if (color == null) return false; - if (selectedPart.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Interaction entities cannot have a glow color applied!", NamedTextColor.RED))); + if (!selectedPart.isDisplay()) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Only display entities cannot have a glow color applied!", NamedTextColor.RED))); return false; } else{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsInfoCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsInfoCMD.java index f18f5747..35f62042 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsInfoCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsInfoCMD.java @@ -91,26 +91,26 @@ else if (type.equalsIgnoreCase("selection") || type.equalsIgnoreCase("filter")){ .hoverEvent(HoverEvent.showText(Component.text("Click to copy", NamedTextColor.GREEN))) .clickEvent(ClickEvent.copyToClipboard(partUUID.toString()))); - - player.sendMessage(MiniMessage.miniMessage().deserialize("Is Master Part: "+(part.isMaster() ? "TRUE" : "FALSE"))); player.sendMessage(Component.empty()); - if (part.getType() != SpawnedDisplayEntityPart.PartType.INTERACTION){ - player.sendMessage(MiniMessage.miniMessage().deserialize("View Range Multiplier: "+part.getViewRange())); - sendBrightness(player, part); - DEUCommandUtils.sendGlowColor(player, part.getGlowColor()); - } - else{ - player.sendMessage(MiniMessage.miniMessage().deserialize("Height: "+part.getInteractionHeight())); - player.sendMessage(MiniMessage.miniMessage().deserialize("Width: "+part.getInteractionWidth())); - player.sendMessage(MiniMessage.miniMessage().deserialize("Responsive: "+(part.isInteractionResponsive() ? "ENABLED" : "DISABLED"))); - } } - else{ + if (part.isDisplay()){ player.sendMessage(MiniMessage.miniMessage().deserialize("View Range Multiplier: "+part.getViewRange())); sendBrightness(player, part); DEUCommandUtils.sendGlowColor(player, part.getGlowColor()); } + else if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + player.sendMessage(MiniMessage.miniMessage().deserialize("Height: "+part.getInteractionHeight())); + player.sendMessage(MiniMessage.miniMessage().deserialize("Width: "+part.getInteractionWidth())); + player.sendMessage(MiniMessage.miniMessage().deserialize("Responsive: "+(part.isInteractionResponsive() ? "ENABLED" : "DISABLED"))); + } + else if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + player.sendMessage(MiniMessage.miniMessage().deserialize("Immovable: "+(part.isMannequinImmovable() ? "ENABLED" : "DISABLED"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("Gravity: "+(part.hasMannequinGravity() ? "ENABLED" : "DISABLED"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("Pose: "+part.getMannequinPose())); + player.sendMessage(MiniMessage.miniMessage().deserialize("Scale: "+part.getMannequinScale())); + } + player.sendMessage(Component.empty()); player.sendMessage(Component.text("| Click to view Part Tags", NamedTextColor.GOLD) .clickEvent(ClickEvent.suggestCommand("/deu parts listtags"))); @@ -122,9 +122,7 @@ private void incorrectUsage(Player player){ } private void sendBrightness(Player player, ActivePart part){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - return; - } + if (!part.isDisplay()) return; Display.Brightness brightness = part.getBrightness(); if (brightness == null){ player.sendMessage(MiniMessage.miniMessage().deserialize("Brightness: NOT SET")); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java index 2f33affd..0497d741 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java @@ -24,7 +24,7 @@ class PartsScaleCMD extends PartsSubCommand { @Override protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { for (ActivePart selectedPart : selection.getSelectedParts()){ - if (selectedPart.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!selectedPart.isDisplay()){ continue; } try { @@ -41,8 +41,8 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION) { - player.sendMessage(Component.text("You cannot do this with an interaction part entity!", NamedTextColor.RED)); + if (!selectedPart.isDisplay()) { + player.sendMessage(Component.text("You can only do this with a display entity!", NamedTextColor.RED)); player.sendMessage(Component.text("| Use \"/deu interaction scale\" instead", NamedTextColor.GRAY)); return false; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGlowColor.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGlowColor.java index eec4c379..8e7fa978 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGlowColor.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGlowColor.java @@ -49,8 +49,8 @@ else if (object instanceof ActivePart part){ if (part.getGlowColor() != null){ return ColorRGB.fromBukkitColor(part.getGlowColor()); } - else if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - Skript.error("You can not get the glow color of an INTERACTION active part"); + else if (!part.isDisplay()){ + Skript.error("You can only get the glow color of a DISPLAY active part"); } return null; } From 5b5957303b53ff4b4b5ffcb55eb629d5854129c6 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 20 Dec 2025 04:31:20 -0600 Subject: [PATCH 031/139] Add new LibsDisguises repo --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c5866863..f7c2024e 100644 --- a/pom.xml +++ b/pom.xml @@ -143,8 +143,8 @@ - md_5-public - https://repo.md-5.net/content/groups/public/ + libsdisguises-public + https://mvn.lib.co.nz/public From 1c0af4b4fe96d440b3e266d84f9ede3da2d5d8f9 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 20 Dec 2025 04:31:52 -0600 Subject: [PATCH 032/139] Update PacketEvents to 2.11.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f7c2024e..9c6dc101 100644 --- a/pom.xml +++ b/pom.xml @@ -158,7 +158,7 @@ com.github.retrooper packetevents-spigot - 2.9.5 + 2.11.0 provided From 0f28f5440a7235299f181e0662250d8972be4f0e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 20 Dec 2025 06:47:39 -0600 Subject: [PATCH 033/139] add more mannequin related methods, fix part cycling mannequins --- .../utils/DisplayEntities/ActivePart.java | 12 +++++ .../PacketDisplayEntityPart.java | 31 +++++++++++++ .../SpawnedDisplayEntityPart.java | 41 +++++++++++++++++ .../packet/attributes/DisplayAttributes.java | 4 +- .../OptionalComponentDisplayAttribute.java | 17 +++++++ .../ResolvableProfileDisplayAttribute.java | 31 ++++++++++++- .../command/parts/PartsCycleCMD.java | 45 ++++--------------- 7 files changed, 141 insertions(+), 40 deletions(-) create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/OptionalComponentDisplayAttribute.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 523b4913..51fdd8e8 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -1,5 +1,7 @@ package net.donnypz.displayentityutils.utils.DisplayEntities; +import com.destroystokyo.paper.profile.PlayerProfile; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.DisplayConfig; import net.donnypz.displayentityutils.events.GroupSpawnedEvent; @@ -519,6 +521,12 @@ public void unglow(@NotNull Player player) { */ public abstract boolean isInteractionResponsive(); + public abstract void setMannequinProfile(@NotNull PlayerProfile profile); + + public abstract void setMannequinProfile(@NotNull ResolvableProfile profile); + + public abstract void setMannequinBelowName(@Nullable Component text); + public abstract void setMannequinPose(Pose pose); public abstract void setMannequinScale(double scale); @@ -531,6 +539,10 @@ public void unglow(@NotNull Player player) { public abstract void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand); + public abstract ResolvableProfile getMannequinProfile(); + + public abstract @Nullable Component getMannequinBelowName(); + public abstract @Nullable Pose getMannequinPose(); public abstract double getMannequinScale(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 311f26ef..0c3428e6 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -1,9 +1,11 @@ package net.donnypz.displayentityutils.utils.DisplayEntities; +import com.destroystokyo.paper.profile.PlayerProfile; import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.util.Vector3d; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.events.GroupSpawnedEvent; import net.donnypz.displayentityutils.managers.DEUUser; @@ -594,6 +596,35 @@ public void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand) //TODO } + @Override + public void setMannequinProfile(@NotNull PlayerProfile profile) { + setMannequinProfile(ResolvableProfile.resolvableProfile(profile)); + } + + @Override + public void setMannequinProfile(@NotNull ResolvableProfile profile) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, profile); + } + + @Override + public void setMannequinBelowName(@Nullable Component text) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.BELOW_NAME, text); + } + + @Override + public ResolvableProfile getMannequinProfile() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return null; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.RESOLVABLE_PROFILE); + } + + @Override + public @Nullable Component getMannequinBelowName() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return null; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.BELOW_NAME); + } + @Override public void setAttribute(@NotNull DisplayAttribute attribute, T value) { diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index be667402..f0f29409 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -1,5 +1,7 @@ package net.donnypz.displayentityutils.utils.DisplayEntities; +import com.destroystokyo.paper.profile.PlayerProfile; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.utils.Direction; import net.donnypz.displayentityutils.utils.DisplayUtils; @@ -1019,6 +1021,43 @@ public void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand) } } + @Override + public void setMannequinProfile(@NotNull PlayerProfile profile) { + setMannequinProfile(ResolvableProfile.resolvableProfile(profile)); + } + + @Override + public void setMannequinProfile(@NotNull ResolvableProfile profile) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.setProfile(profile); + } + + @Override + public void setMannequinBelowName(@Nullable Component text) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.setDescription(text); + } + + @Override + public ResolvableProfile getMannequinProfile() { + if (type != PartType.MANNEQUIN) return null; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return null; + return mannequin.getProfile(); + } + + @Override + public @Nullable Component getMannequinBelowName() { + if (type != PartType.MANNEQUIN) return null; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return null; + return mannequin.getDescription(); + } + /** * {@inheritDoc} * The applied changes do not reflect the entity data server-side @@ -1118,6 +1157,8 @@ public boolean isInteractionResponsive() { return ((Interaction) getEntity()).isResponsive(); } + + @Override public void addInteractionCommand(@NotNull String command, boolean isLeftClick, boolean isConsole) { if (type == PartType.INTERACTION) DisplayUtils.addInteractionCommand((Interaction) getEntity(), command, isLeftClick, isConsole); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java index e9a5a8f4..6e7d6ea8 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java @@ -5,7 +5,7 @@ import net.kyori.adventure.text.Component; /** - * A class containing all {@link DisplayAttribute}s that apply to both Display and Interaction entities + * A class containing all {@link DisplayAttribute}s that apply to eligible part type entities */ public final class DisplayAttributes { @@ -74,6 +74,6 @@ public static final class Mannequin{ public static final MainHandDisplayAttribute MAIN_HAND = new MainHandDisplayAttribute(15); public static final ResolvableProfileDisplayAttribute RESOLVABLE_PROFILE = new ResolvableProfileDisplayAttribute(17); public static final BasicDisplayAttribute IMMOVABLE = new BasicDisplayAttribute<>(18, Boolean.class, EntityDataTypes.BOOLEAN); + public static final OptionalComponentDisplayAttribute BELOW_NAME = new OptionalComponentDisplayAttribute(19); } - } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/OptionalComponentDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/OptionalComponentDisplayAttribute.java new file mode 100644 index 00000000..0a7e324f --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/OptionalComponentDisplayAttribute.java @@ -0,0 +1,17 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import net.kyori.adventure.text.Component; + +import java.util.Optional; + +public class OptionalComponentDisplayAttribute extends DisplayAttribute> { + protected OptionalComponentDisplayAttribute(int index) { + super(index, Component.class, EntityDataTypes.OPTIONAL_ADV_COMPONENT); + } + + @Override + public Optional getOutputValue(Component value) { + return Optional.of(value); + } +} \ No newline at end of file diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java index 0f6dcb0d..a473d82c 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java @@ -1,8 +1,16 @@ package net.donnypz.displayentityutils.utils.packet.attributes; +import com.destroystokyo.paper.profile.ProfileProperty; import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemProfile; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.player.PlayerModelType; +import com.github.retrooper.packetevents.resources.ResourceLocation; import io.papermc.paper.datacomponent.item.ResolvableProfile; +import org.bukkit.profile.PlayerTextures; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; public class ResolvableProfileDisplayAttribute extends DisplayAttribute { protected ResolvableProfileDisplayAttribute(int index) { @@ -11,6 +19,27 @@ protected ResolvableProfileDisplayAttribute(int index) { @Override public ItemProfile getOutputValue(ResolvableProfile value) { - return null; + String name = value.name(); + UUID uuid = value.uuid(); + value.properties(); + + List properties = new ArrayList<>(); + for (ProfileProperty prop : value.properties()){ + properties.add(new ItemProfile.Property(prop.getName(), prop.getValue(), prop.getSignature())); + } + ResolvableProfile.SkinPatch bukkitSkinPatch = value.skinPatch(); + PlayerModelType modelType; + if (bukkitSkinPatch.model() == null){ + modelType = PlayerModelType.WIDE; + } + else{ + modelType = (bukkitSkinPatch.model() == PlayerTextures.SkinModel.CLASSIC) ? PlayerModelType.WIDE : PlayerModelType.SLIM; + } + ItemProfile.SkinPatch skinPatch = new ItemProfile.SkinPatch( + new ResourceLocation(bukkitSkinPatch.body()), + new ResourceLocation(bukkitSkinPatch.cape()), + new ResourceLocation(bukkitSkinPatch.elytra()), + modelType); + return new ItemProfile(name, uuid, properties, skinPatch); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java index 5067062e..959d4cfc 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java @@ -1,5 +1,6 @@ package net.donnypz.displayentityutils.command.parts; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; @@ -7,7 +8,6 @@ import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.*; -import net.donnypz.displayentityutils.utils.DisplayUtils; import net.donnypz.displayentityutils.utils.PacketUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -122,48 +122,19 @@ else if (part.getBlockDisplayBlock().getMaterial() == Material.AIR){ case ITEM_DISPLAY -> { ItemStack i = part.getItemDisplayItem(); if (i.getType() == Material.AIR){ - desc = Component.text("(Invisible Item Display | AIR, CAVE_AIR, or VOID_AIR)", NamedTextColor.GRAY); + desc = Component.text("(Invisible Item Display | AIR)", NamedTextColor.GRAY); } else{ desc = Component.text("("+i.getType().key().value()+")", NamedTextColor.AQUA); } } - default -> throw new IllegalStateException("Unexpected part type"); - } - return desc; - } - - static Component getPartInfo(@NotNull Entity entity){ - Component desc; - switch(entity){ - case Interaction i -> { - desc = MiniMessage.miniMessage().deserialize("(Interaction, H: "+i.getInteractionHeight()+" W:"+i.getInteractionWidth()+")"); + case MANNEQUIN -> { + ResolvableProfile profile = part.getMannequinProfile(); + String name = profile.name(); + if (name == null) name = "Unnamed Mannequin"; + desc = Component.text("("+name+")"); } - case TextDisplay display -> { - desc = Component.text("(Text Display: \"", NamedTextColor.LIGHT_PURPLE) - .append(display.text()) - .append(Component.text("\")", NamedTextColor.LIGHT_PURPLE)); - } - case BlockDisplay display -> { - if (DisplayUtils.isMaster(display)){ - desc = Component.text("(Master Entity/Part)", NamedTextColor.GOLD); - } - else if (display.getBlock().getMaterial() == Material.AIR){ - desc = Component.text("(Invisible Block Display | AIR, CAVE_AIR, or VOID_AIR)", NamedTextColor.GRAY); - } - else{ - desc = Component.text("("+display.getBlock().getMaterial().key().value()+")", NamedTextColor.YELLOW); - } - } - case ItemDisplay display -> { - if (display.getItemStack().getType() == Material.AIR){ - desc = Component.text("(Invisible Item Display | AIR, CAVE_AIR, or VOID_AIR)", NamedTextColor.GRAY); - } - else{ - desc = Component.text("("+display.getItemStack().getType().key().value()+")", NamedTextColor.AQUA); - } - } - default -> throw new IllegalStateException("Unexpected value: " + entity); + default -> throw new IllegalStateException("Unexpected part type"); } return desc; } From 5536459858bb5fb95a78a75e98007d8d4364de5e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 20 Dec 2025 18:34:33 -0600 Subject: [PATCH 034/139] Add ActivePart#hasItemDisplayItemGlint --- .../utils/DisplayEntities/ActivePart.java | 2 ++ .../DisplayEntities/PacketDisplayEntityPart.java | 11 +++++++++++ .../DisplayEntities/SpawnedDisplayEntityPart.java | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 51fdd8e8..7509a308 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -429,6 +429,8 @@ public void unglow(@NotNull Player player) { */ public abstract void setItemDisplayItemGlint(boolean hasGlint); + public abstract boolean hasItemDisplayItemGlint(); + public abstract @Nullable Component getTextDisplayText(); public abstract int getTextDisplayLineWidth(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 0c3428e6..046fa46c 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -444,6 +444,17 @@ public void setItemDisplayItemGlint(boolean hasGlint) { } } + @Override + public boolean hasItemDisplayItemGlint() { + if (type == SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY){ + ItemStack i = attributeContainer.getAttribute(DisplayAttributes.ItemDisplay.ITEMSTACK); + if (i == null) return false; + return i.getItemMeta().getEnchantmentGlintOverride(); + } + return false; + } + + @Override public @Nullable Component getTextDisplayText() { if (type == SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index f0f29409..2833323e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -847,6 +847,13 @@ public void setItemDisplayItemGlint(boolean hasGlint) { ((ItemDisplay) getEntity()).setItemStack(itemStack); } + @Override + public boolean hasItemDisplayItemGlint() { + ItemStack itemStack = getItemDisplayItem(); + if (itemStack == null) return false; + return itemStack.getItemMeta().getEnchantmentGlintOverride(); + } + @Override public @Nullable Component getTextDisplayText() { if (type != PartType.TEXT_DISPLAY) return null; From 948fe64927a9698af06be1ac1053f943068ff619 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 20 Dec 2025 18:48:20 -0600 Subject: [PATCH 035/139] Updated command output --- .../command/anim/AnimAddFrameAfterCMD.java | 2 +- .../command/anim/AnimAddFrameCMD.java | 2 +- .../command/anim/AnimDrawPosCMD.java | 2 +- .../command/anim/AnimEditAllFramesCMD.java | 2 +- .../command/anim/AnimMovePointCMD.java | 2 +- .../command/anim/AnimOverwriteFrameCMD.java | 2 +- .../command/anim/AnimRemoveFrameCMD.java | 2 +- .../command/anim/AnimReverseCMD.java | 2 +- .../displayentityutils/command/anim/AnimSelectCMD.java | 2 +- .../command/anim/AnimSelectJSONCMD.java | 2 +- .../displayentityutils/command/anim/AnimSetTagCMD.java | 2 +- .../command/group/GroupAddTargetCMD.java | 2 +- .../command/group/GroupAutoCullCMD.java | 2 +- .../command/group/GroupBillboardCMD.java | 2 +- .../command/group/GroupCloneCMD.java | 2 +- .../command/group/GroupDespawnCMD.java | 2 +- .../command/group/GroupDismountCMD.java | 4 ++-- .../command/group/GroupGlowColorCMD.java | 2 +- .../command/group/GroupMergeCMD.java | 2 +- .../command/group/GroupSafeDismountCMD.java | 2 +- .../command/group/GroupSelectCMD.java | 2 +- .../command/group/GroupSetTagCMD.java | 2 +- .../command/group/GroupSpawnCMD.java | 2 +- .../command/interaction/InteractionHeightCMD.java | 2 +- .../displayentityutils/command/item/ItemSetCMD.java | 4 ++-- .../command/item/ItemToggleGlintCMD.java | 5 +++-- .../command/item/ItemTransformCMD.java | 4 ++-- .../command/mannequin/MannequinHeldItemCMD.java | 4 ++-- .../command/mannequin/MannequinMainHandCMD.java | 4 ++-- .../command/mannequin/MannequinPoseCMD.java | 4 ++-- .../command/mannequin/MannequinScaleCMD.java | 4 ++-- .../command/mannequin/MannequinToggleGravityCMD.java | 3 ++- .../command/mannequin/MannequinToggleImmovableCMD.java | 3 ++- .../command/parts/PartsAddTagCMD.java | 4 ++-- .../command/parts/PartsBillboardCMD.java | 4 ++-- .../command/parts/PartsGlowColorCMD.java | 6 +++--- .../command/parts/PartsRemoveCMD.java | 4 ++-- .../command/parts/PartsSetBlockCMD.java | 4 ++-- .../displayentityutils/command/place/PlaceSetCMD.java | 2 +- .../command/place/PlaceSetPermissionCMD.java | 2 +- .../command/text/TextAddLineCMD.java | 2 +- .../displayentityutils/command/text/TextAlignCMD.java | 4 ++-- .../command/text/TextBackgroundCMD.java | 4 ++-- .../displayentityutils/command/text/TextFontCMD.java | 4 ++-- .../command/text/TextLineWidthCMD.java | 4 ++-- .../command/text/TextOpacityCMD.java | 4 ++-- .../command/text/TextSeeThroughCMD.java | 7 ++++--- .../displayentityutils/command/text/TextSetCMD.java | 2 +- .../displayentityutils/command/text/TextShadowCMD.java | 10 ++++++---- 49 files changed, 79 insertions(+), 73 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameAfterCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameAfterCMD.java index d085e41a..61bccc79 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameAfterCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameAfterCMD.java @@ -68,7 +68,7 @@ public void execute(Player player, String[] args) { frames.add(id + 1, frame); anim.setFrames(frames); - player.sendMessage(Component.text( "Frame successfully added after frame-id " + id + "!", NamedTextColor.GREEN)); + player.sendMessage(Component.text( "Added frame after frame-id " + id + "!", NamedTextColor.GREEN)); player.playSound(player, Sound.ENTITY_SHEEP_SHEAR, 1, 0.75f); } catch (NumberFormatException e) { diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameCMD.java index fc26ad4e..3b02b054 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameCMD.java @@ -52,7 +52,7 @@ public void execute(Player player, String[] args) { boolean isUnique = anim.addFrame(frame); if (isUnique){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully captured animation frame", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Animation frame captured!", NamedTextColor.GREEN))); player.playSound(player, Sound.ENTITY_SHEEP_SHEAR, 1, 0.75f); } else{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimDrawPosCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimDrawPosCMD.java index 3a2a529c..90e61243 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimDrawPosCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimDrawPosCMD.java @@ -38,7 +38,7 @@ public void execute(Player player, String[] args) { int pos = Integer.parseInt(args[2]); user.setPointPos(player.getLocation(), pos); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set draw pos", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Draw pos set", NamedTextColor.GREEN))); player.sendMessage(Component.text("| Pos: "+pos, NamedTextColor.GRAY)); } catch(NumberFormatException e) { diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimEditAllFramesCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimEditAllFramesCMD.java index 1d4b3fc5..2653bda0 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimEditAllFramesCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimEditAllFramesCMD.java @@ -48,7 +48,7 @@ public void execute(Player player, String[] args) { frame.setDelay(delay); frame.setDuration(duration); } - player.sendMessage(Component.text("All frames successfully edited!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("All frames have been edited!", NamedTextColor.GREEN)); player.sendMessage(Component.text("Delay: " + delay, NamedTextColor.GRAY)); player.sendMessage(Component.text("Duration: " + duration, NamedTextColor.GRAY)); } catch (NumberFormatException e) { diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimMovePointCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimMovePointCMD.java index 8b0c3153..f8188de9 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimMovePointCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimMovePointCMD.java @@ -47,6 +47,6 @@ public void execute(Player player, String[] args) { pLoc.setPitch(0); pLoc.setYaw(0); rp.setLocation(group, pLoc); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully moved frame point to your location"))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Moved the frame point to your location"))); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimOverwriteFrameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimOverwriteFrameCMD.java index 6714bbdf..4f330cc9 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimOverwriteFrameCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimOverwriteFrameCMD.java @@ -60,7 +60,7 @@ public void execute(Player player, String[] args) { frame.setDelay(delay); frame.setDuration(duration); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully overwritten animation frame", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("The animation frame has been overwritten", NamedTextColor.GREEN))); player.playSound(player, Sound.ENTITY_SHEEP_SHEAR, 1, 0.75f); } catch (NumberFormatException e) { player.sendMessage(Component.text("Invalid value entered! Enter whole numbers >= 0", NamedTextColor.RED)); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimRemoveFrameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimRemoveFrameCMD.java index 9e074588..5e929fa3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimRemoveFrameCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimRemoveFrameCMD.java @@ -46,7 +46,7 @@ public void execute(Player player, String[] args) { return; } anim.removeFrame(frames.get(id)); - player.sendMessage(Component.text("Frame successfully removed!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Frame removed!", NamedTextColor.GREEN)); } catch (NumberFormatException e) { player.sendMessage(Component.text("Invalid ID! ID's must be 0 or larger", NamedTextColor.RED)); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimReverseCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimReverseCMD.java index 1801ea9d..8ebac083 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimReverseCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimReverseCMD.java @@ -33,6 +33,6 @@ public void execute(Player player, String[] args) { return; } anim.reverse(); - player.sendMessage(Component.text("Animation successfully reversed!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("The animation has been reversed!", NamedTextColor.GREEN)); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectCMD.java index dac544ee..60ce7999 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectCMD.java @@ -62,7 +62,7 @@ static void getAnimation(Player p, String tag, String storage){ DisplayAnimationManager.setSelectedSpawnedAnimation(p, anim); - p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully selected animation! (Tagged: "+anim.getAnimationTag()+")"))); + p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Selected animation! (Tagged: "+anim.getAnimationTag()+")"))); DisplayEntityPluginCommand.hideRelativePoints(p); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectJSONCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectJSONCMD.java index 6dcf55d2..5e834fab 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectJSONCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectJSONCMD.java @@ -44,7 +44,7 @@ static void getAnimation(Player p, String tag){ DisplayAnimationManager.setSelectedSpawnedAnimation(p, anim); - p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully selected animation! (Tagged: "+anim.getAnimationTag()+")"))); + p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Selected animation! (Tagged: "+anim.getAnimationTag()+")"))); DisplayEntityPluginCommand.hideRelativePoints(p); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSetTagCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSetTagCMD.java index 602ba68b..fb6df5ae 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSetTagCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSetTagCMD.java @@ -31,6 +31,6 @@ public void execute(Player player, String[] args) { } String tag = args[2]; anim.setAnimationTag(tag); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Animation tag successfully set to \"" + tag + "\"", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Animation tag set to \"" + tag + "\"", NamedTextColor.GREEN))); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java index 20d66cb7..38ffa548 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java @@ -54,6 +54,6 @@ public void execute(Player player, String[] args) { SpawnedPartSelection sel = (SpawnedPartSelection) DisplayGroupManager.getPartSelection(player); sel.refresh(); } - player.sendMessage(Component.text("Successfully added entity to your selected group!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Added entity to your selected group!", NamedTextColor.GREEN)); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAutoCullCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAutoCullCMD.java index 76bd90b9..00b6aec5 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAutoCullCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAutoCullCMD.java @@ -20,7 +20,7 @@ protected void sendIncorrectUsage(@NotNull Player player) {} @Override protected void execute(@NotNull Player player, @NotNull ActiveGroup group, @NotNull String[] args) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully added culling bounds to your selected group!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Added culling bounds to your selected group!", NamedTextColor.GREEN))); group.autoCull(DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupBillboardCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupBillboardCMD.java index ff811f86..9b7cbff5 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupBillboardCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupBillboardCMD.java @@ -29,7 +29,7 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ try{ Display.Billboard billboard = Display.Billboard.valueOf(args[2].toUpperCase()); group.setBillboard(billboard); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard successfully set for your selected group!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard set for your selected group!", NamedTextColor.GREEN))); } catch(IllegalArgumentException e){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid billboard type!", NamedTextColor.RED))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCloneCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCloneCMD.java index 9310dd45..8aa9645a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCloneCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCloneCMD.java @@ -30,7 +30,7 @@ static void clone(Player p, ActiveGroup clonedGroup){ p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to clone your selected group!", NamedTextColor.RED))); } else{ - p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully cloned your selected group", NamedTextColor.GREEN))); + p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Cloned your selected group", NamedTextColor.GREEN))); p.sendMessage(Component.text("- Your group selection has been changed to the newly created group", NamedTextColor.GRAY, TextDecoration.ITALIC)); DisplayGroupManager.setSelectedGroup(p, clonedGroup); clonedGroup.glowAndMarkInteractions(p, 80); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java index dd0e1bec..3c01de3e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java @@ -22,7 +22,7 @@ protected void sendIncorrectUsage(@NotNull Player player) {} @Override protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @NotNull String[] args) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully despawned your selected display entity group!", NamedTextColor.GRAY))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Despawned your selected display entity group!", NamedTextColor.GRAY))); if (group instanceof SpawnedDisplayEntityGroup sg){ DisplayGroupManager.deselectGroup(player); sg.unregister(true, true); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDismountCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDismountCMD.java index 70590409..9c5961f7 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDismountCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDismountCMD.java @@ -61,7 +61,7 @@ public void execute(CommandSender sender, String[] args) { sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your selected group is not riding an entity!", NamedTextColor.RED))); } else{ - sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully dismounted your selected group!", NamedTextColor.GREEN))); + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Dismounted your selected group!", NamedTextColor.GREEN))); dismount(group, despawn); if (despawn) despawnMessage(sender); DisplayControllerManager.unregisterEntity(vehicle); @@ -79,7 +79,7 @@ public void execute(CommandSender sender, String[] args) { } DisplayControllerManager.unregisterEntity(vehicle); - sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully dismounted all non-packet groups riding the entity!", NamedTextColor.GREEN))); + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Dismounted all non-packet groups riding the entity!", NamedTextColor.GREEN))); if (despawn) despawnMessage(sender); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupGlowColorCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupGlowColorCMD.java index 1e41f114..7cb38b70 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupGlowColorCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupGlowColorCMD.java @@ -34,7 +34,7 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ } group.setGlowColor(c); group.glow(player, 60); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color successfully set for display entity group!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color set for display entity group!", NamedTextColor.GREEN))); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMergeCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMergeCMD.java index f867b039..11f119ee 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMergeCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMergeCMD.java @@ -52,7 +52,7 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ } sg.merge(result.group()); } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully merged nearby groups", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Nearby non-packet groups have been merged", NamedTextColor.GREEN))); sg.glowAndMarkInteractions(player, 60); } catch(NumberFormatException e){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSafeDismountCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSafeDismountCMD.java index f9647acd..1af90e8b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSafeDismountCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSafeDismountCMD.java @@ -100,7 +100,7 @@ public void execute(CommandSender sender, String[] args) { DisplayControllerManager.unregisterEntity(vehicle); - sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully dismounted all groups riding the entity!", NamedTextColor.GREEN))); + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Dismounted all groups riding the entity!", NamedTextColor.GREEN))); } } \ No newline at end of file diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java index 99e09a12..51f8379a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java @@ -97,7 +97,7 @@ private void getSelectableGroups(Player player, double distance){ boolean selectResult = DisplayGroupManager.setSelectedGroup(p, g); if (selectResult){ g.addMissingEntities(distance); - p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully selected group!", NamedTextColor.GREEN))); + p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Group selected!", NamedTextColor.GREEN))); DisplayEntityPluginCommand.hideRelativePoints(player); } else{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSetTagCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSetTagCMD.java index 5278430b..dd0344c3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSetTagCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSetTagCMD.java @@ -25,6 +25,6 @@ protected void sendIncorrectUsage(@NotNull Player player) { protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @NotNull String[] args) { String tag = args[2]; group.setTag(tag); - player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully tagged your selected group! (Tagged: "+tag+")"))); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Tagged your selected group! (Tagged: "+tag+")"))); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSpawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSpawnCMD.java index a41a071e..fa0beb77 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSpawnCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSpawnCMD.java @@ -147,7 +147,7 @@ else if (storage == LoadMethod.MONGODB){ return; } DisplayAnimationManager.setSelectedSpawnedAnimation(p, anim.toSpawnedDisplayAnimation()); - p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully selected display animation! (Tagged: "+tag+")"))); + p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Animation selected! (Tagged: "+tag+")"))); } }); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionHeightCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionHeightCMD.java index 9c4d446e..7d950509 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionHeightCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionHeightCMD.java @@ -39,7 +39,7 @@ static void setInteractionDimensions(Player p , String[] args, String dim){ i.setWidth(change); } - p.sendMessage(Component.text("Successfully set interaction's "+dim+" to "+change, NamedTextColor.GREEN)); + p.sendMessage(Component.text("Set interaction's "+dim+" to "+change, NamedTextColor.GREEN)); } catch(NumberFormatException e) { p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid " + dim + ", enter a number!", NamedTextColor.RED))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java index f6a3e563..d7e491a6 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java @@ -37,7 +37,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active part.setItemDisplayItem(itemStack); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set item of ALL selected item displays!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set item of ALL selected item displays!", NamedTextColor.GREEN))); return true; } @@ -52,7 +52,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti return false; } selectedPart.setItemDisplayItem(itemStack); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set item of selected item display!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set item of selected item display!", NamedTextColor.GREEN))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java index 9b8f5ede..804c9cad 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java @@ -66,8 +66,9 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti } ItemStack item = selectedPart.getItemDisplayItem(); if (item == null) return false; - selectedPart.setItemDisplayItemGlint(!item.getItemMeta().getEnchantmentGlintOverride()); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Toggled glint of selected item display!", NamedTextColor.GREEN))); + selectedPart.setItemDisplayItemGlint(!selectedPart.hasItemDisplayItemGlint()); + String status = selectedPart.hasItemDisplayItemGlint() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled glint of selected item display "+status))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java index f7f89451..5be796eb 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java @@ -30,7 +30,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active for (ActivePart part : selection.getSelectedParts()){ part.setItemDisplayTransform(transform); } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set item transform of ALL selected item displays!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set item transform of ALL selected item displays!", NamedTextColor.GREEN))); return true; } @@ -43,7 +43,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti return false; } selectedPart.setItemDisplayTransform(transform); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set item transform of selected item display!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set item transform of selected item display!", NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java index 81ad7c15..5f2b1947 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java @@ -51,7 +51,7 @@ else if (hand.equalsIgnoreCase("off") || hand.equalsIgnoreCase("offhand")) { part.setMannequinHandItem(itemStack, isMainHand); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set "+hand.toLowerCase()+" hand item of ALL selected mannequins!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set "+hand.toLowerCase()+" hand item of ALL selected mannequins!", NamedTextColor.GREEN))); return true; } @@ -76,7 +76,7 @@ else if (hand.equalsIgnoreCase("off") || hand.equalsIgnoreCase("offhand")) { if (itemStack == null) return false; selectedPart.setMannequinHandItem(itemStack, isMainHand); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set "+hand.toLowerCase()+" hand item of selected mannequin!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set "+hand.toLowerCase()+" hand item of selected mannequin!", NamedTextColor.GREEN))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java index fdb8ffcb..13a565c3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java @@ -34,7 +34,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; p.setMannequinMainHand(hand); } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set main hand of ALL selected mannequins!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set main hand of ALL selected mannequins!", NamedTextColor.GREEN))); return true; } catch(IllegalArgumentException e){ @@ -51,7 +51,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti try{ MainHand hand = MainHand.valueOf(handStr); selectedPart.setMannequinMainHand(hand); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set mannequin's main hand!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set mannequin's main hand!", NamedTextColor.GREEN))); return true; } catch(IllegalArgumentException e){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java index a58f7c63..6d8c0adf 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java @@ -37,7 +37,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; p.setMannequinPose(pose); } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set pose of ALL selected mannequins!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set pose of ALL selected mannequins!", NamedTextColor.GREEN))); return true; } catch(IllegalArgumentException e){ @@ -53,7 +53,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti try{ Pose pose = Pose.valueOf(poseStr.toUpperCase()); selectedPart.setMannequinPose(pose); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set mannequin pose!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set mannequin pose!", NamedTextColor.GREEN))); return true; } catch(IllegalArgumentException e){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java index 8007d8a7..1b5ea9ce 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java @@ -32,7 +32,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; p.setMannequinScale(scale); } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set scale of ALL selected mannequins!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set scale of ALL selected mannequins!", NamedTextColor.GREEN))); return true; } catch(IllegalArgumentException e){ @@ -48,7 +48,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti try{ float scale = Float.parseFloat(scaleStr); selectedPart.setMannequinScale(scale); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set mannequin scale!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set mannequin scale!", NamedTextColor.GREEN))); return true; } catch(IllegalArgumentException e){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java index 0849f064..671679d4 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java @@ -61,7 +61,8 @@ else if (s.equalsIgnoreCase("off")){ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; selectedPart.setMannequinGravity(!selectedPart.hasMannequinGravity()); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Toggled gravity of selected mannequin!", NamedTextColor.GREEN))); + String status = selectedPart.hasMannequinGravity() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled gravity of selected mannequin "+status))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java index 7b8c3e29..edd01f5a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java @@ -61,7 +61,8 @@ else if (s.equalsIgnoreCase("off")){ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN); selectedPart.setMannequinImmovable(!selectedPart.isMannequinImmovable()); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Toggled immovability of selected mannequin!", NamedTextColor.GREEN))); + String status = selectedPart.isMannequinImmovable() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled immovability of selected mannequin "+status))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAddTagCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAddTagCMD.java index 7048e451..47086629 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAddTagCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAddTagCMD.java @@ -28,7 +28,7 @@ protected void sendIncorrectUsage(@NotNull Player player) { protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { String tag = args[2]; if (selection.addTag(tag)){ - player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Adding part tag to ALL selected parts! (Added Tag: "+tag+")"))); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Added part tag to ALL selected parts! (Added Tag: "+tag+")"))); return true; } else{ @@ -41,7 +41,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { String tag = args[2]; if (selectedPart.addTag(tag)){ - player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Adding part tag to selected part! (Added Tag: "+tag+")"))); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Added part tag to selected part! (Added Tag: "+tag+")"))); return true; } else{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java index f958dcd8..c743189d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java @@ -29,7 +29,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active Display.Billboard billboard = getBillboard(player, args[2]); if (billboard == null) return false; selection.setBillboard(billboard); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard successfully set for selected display entity part(s) in your selection!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard set for selected display entity part(s) in your selection!", NamedTextColor.GREEN))); return true; } @@ -42,7 +42,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti Display.Billboard billboard = getBillboard(player, args[2]); if (billboard == null) return false; selectedPart.setBillboard(billboard); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard successfully set for your selected part!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard set for your selected part!", NamedTextColor.GREEN))); } return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java index 6b7b236c..5cf30d45 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java @@ -31,7 +31,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (color == null) return false; selection.setGlowColor(color); selection.glow(player, 60); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color successfully set for selected display entity part(s) in your selection!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color set for selected display entity part(s) in your selection!", NamedTextColor.GREEN))); return true; } @@ -40,13 +40,13 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti Color color = getColor(player, args[2]); if (color == null) return false; if (!selectedPart.isDisplay()) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Only display entities cannot have a glow color applied!", NamedTextColor.RED))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Only display entities can have a glow color applied!", NamedTextColor.RED))); return false; } else{ selectedPart.setGlowColor(color); selectedPart.glow(player, 60); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color successfully set for your selected part!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color set for your selected part!", NamedTextColor.GREEN))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRemoveCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRemoveCMD.java index 6074662f..d9100463 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRemoveCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRemoveCMD.java @@ -34,7 +34,7 @@ else if (part instanceof SpawnedDisplayEntityPart p){ p.remove(true); } } - player.sendMessage(Component.text("Successfully despawned all selected parts!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Despawned all selected parts!", NamedTextColor.GREEN)); removeGroupIfEmpty(player, group); return true; } @@ -51,7 +51,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti else if (selectedPart instanceof PacketDisplayEntityPart pp){ pp.remove(); } - player.sendMessage(Component.text("Successfully despawned your selected part!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Despawned your selected part!", NamedTextColor.GREEN)); removePartSelectionIfEmpty(player, selection); removeGroupIfEmpty(player, group); return true; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSetBlockCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSetBlockCMD.java index 096d478d..790868d5 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSetBlockCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSetBlockCMD.java @@ -36,7 +36,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active setBlock(part, blockData); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set block of ALL selected block displays!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set block of ALL selected block displays!", NamedTextColor.GREEN))); return true; } @@ -49,7 +49,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti return false; } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set block of selected block display!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set block of selected block display!", NamedTextColor.GREEN))); setBlock(selectedPart, blockData); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java index a77d731a..fc6dfcad 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java @@ -35,7 +35,7 @@ public void execute(Player player, String[] args) { String groupTag = args[2]; PlaceableGroupManager.assign(heldItem, groupTag, true); - player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully assigned a group to your held block (Tag: "+groupTag+")"))); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Assigned a group to your held block (Tag: "+groupTag+")"))); player.sendMessage(MiniMessage.miniMessage().deserialize("| The group will spawn using packets")); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java index 78c918f1..4c154a6d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java @@ -30,6 +30,6 @@ public void execute(Player player, String[] args) { String permission = args[2]; PlaceableGroupManager.setPlacePermission(heldItem, permission); - player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully set the permission to place your held item's assigned group (Permission: "+permission+")"))); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Set the permission to place your held item's assigned group (Permission: "+permission+")"))); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java index 6808b980..c3bcfcd8 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java @@ -40,7 +40,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti Key font = currentText.font(); Component comp = currentText.appendNewline().append(LegacyComponentSerializer.legacyAmpersand().deserialize(TextSetCMD.getTextResult(args))); selectedPart.setTextDisplayText(comp.font(font)); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully added line to text display!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Added line to text display!", NamedTextColor.GREEN))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java index fd633873..dfbfb704 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java @@ -33,7 +33,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active part.setTextDisplayAlignment(alignment); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Text alignment successfully set to "+args[2]+" for ALL selected text displays", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Text alignment set to "+args[2]+" for ALL selected text displays", NamedTextColor.GREEN))); return true; } @@ -46,7 +46,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti TextDisplay.TextAlignment alignment = getAlignment(args[2], player); if (alignment == null) return false; selectedPart.setTextDisplayAlignment(alignment); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Text alignment successfully set to "+args[2], NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Text alignment set to "+args[2], NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java index 18be9bf2..c146fbe4 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java @@ -34,7 +34,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active part.setTextDisplayBackgroundColor(color); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set background color for ALL selected text displays", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set background color for ALL selected text displays", NamedTextColor.GREEN))); return true; } @@ -47,7 +47,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti return false; } selectedPart.setTextDisplayBackgroundColor(color); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set text display's background color", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set text display's background color", NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java index bec3e32e..2828f5ab 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java @@ -33,7 +33,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active part.setTextDisplayText(part.getTextDisplayText().font(font)); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Font successfully set to "+args[2]+" for ALL selected text displays", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Font set to "+args[2]+" for ALL selected text displays", NamedTextColor.GREEN))); return true; } @@ -46,7 +46,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti Key font = getFont(args, player); if (font == null) return false; selectedPart.setTextDisplayText(selectedPart.getTextDisplayText().font(font)); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Font successfully set to "+args[2], NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Font set to "+args[2], NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java index 073678e9..5a58fb1c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java @@ -31,7 +31,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active part.setTextDisplayLineWidth(width); } } - player.sendMessage(Component.text("Successfully set text display's line width to "+width+" for ALL selected text displays", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Set text display's line width to "+width+" for ALL selected text displays", NamedTextColor.GREEN)); return true; } @@ -44,7 +44,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti return false; } selectedPart.setTextDisplayLineWidth(width); - player.sendMessage(Component.text("Successfully set text display's line width to "+width, NamedTextColor.GREEN)); + player.sendMessage(Component.text("Set text display's line width to "+width, NamedTextColor.GREEN)); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java index 905dc9fd..660e095d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java @@ -32,7 +32,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active } } player.sendMessage(DisplayAPI.pluginPrefix - .append(Component.text("Successfully set text display's opacity to "+opacity+" for ALL selected text displays", NamedTextColor.GREEN))); + .append(Component.text("Set text display's opacity to "+opacity+" for ALL selected text displays", NamedTextColor.GREEN))); return true; } @@ -46,7 +46,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti } selectedPart.setTextDisplayTextOpacity(opacity); player.sendMessage(DisplayAPI.pluginPrefix - .append(Component.text("Successfully set text display's opacity to "+opacity, NamedTextColor.GREEN))); + .append(Component.text("Set text display's opacity to "+opacity, NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java index 68d50598..39ab457b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java @@ -37,12 +37,12 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (s.equalsIgnoreCase("on")){ status = true; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled see through for ALL selected text displays ON"))); + .append(MiniMessage.miniMessage().deserialize("Toggled see through for ALL selected text displays ON"))); } else if (s.equalsIgnoreCase("off")){ status = false; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled see through for ALL selected text displays OFF"))); + .append(MiniMessage.miniMessage().deserialize("Toggled see through for ALL selected text displays OFF"))); } else{ sendIncorrectUsage(player); @@ -64,7 +64,8 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti return false; } selectedPart.setTextDisplaySeeThrough(!selectedPart.isTextDisplaySeeThrough()); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully toggled see through for text display!", NamedTextColor.GREEN))); + String status = selectedPart.isTextDisplaySeeThrough() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled see through for your selected text display "+status))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java index d4c6fc31..ca048003 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java @@ -40,7 +40,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti Key font = currentText.font(); Component comp = LegacyComponentSerializer.legacyAmpersand().deserialize(getTextResult(args)); selectedPart.setTextDisplayText(comp.font(font)); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set text on text display!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set text display's text!", NamedTextColor.GREEN))); player.sendMessage(Component.text("You can include \"\\n\" in your to create a new line.", NamedTextColor.GRAY)); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java index 66ebfde4..ff96ffa3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java @@ -37,12 +37,12 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (s.equalsIgnoreCase("on")){ status = true; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled shadowed for ALL selected text displays ON"))); + .append(MiniMessage.miniMessage().deserialize("Toggled shadowed for ALL selected text displays ON"))); } else if (s.equalsIgnoreCase("off")){ status = false; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled shadowed for ALL selected text displays OFF"))); + .append(MiniMessage.miniMessage().deserialize("Toggled shadowed for ALL selected text displays OFF"))); } else{ sendIncorrectUsage(player); @@ -54,7 +54,7 @@ else if (s.equalsIgnoreCase("off")){ part.setTextDisplayShadowed(status); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully toggled shadowed for ALL selected text displays!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Toggled shadowed for ALL selected text displays!", NamedTextColor.GREEN))); return true; } @@ -64,8 +64,10 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); return false; } + selectedPart.setTextDisplayShadowed(!selectedPart.isTextDisplayShadowed()); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully toggled shadow for text display!", NamedTextColor.GREEN))); + String status = selectedPart.isTextDisplayShadowed() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled shadow for your selected text display "+status))); return true; } } From 648599bb9d61a1dccc83c3ba6a8eeff124b0a60c Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 20 Dec 2025 19:14:33 -0600 Subject: [PATCH 036/139] Add ActivePart#teleport --- .../utils/DisplayEntities/ActivePart.java | 6 ++++++ .../utils/DisplayEntities/PacketDisplayEntityPart.java | 10 +++++----- .../DisplayEntities/SpawnedDisplayEntityPart.java | 9 +++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 7509a308..2cb907fe 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -160,6 +160,12 @@ public boolean hasTag(@NotNull String tag){ public abstract boolean hasGroup(); + /** + * Teleport this part to the given location. This will fail if the part is a display entity, in a group, and is not the group's master part. + * @param location the teleport location + */ + public abstract void teleport(@NotNull Location location); + public abstract @Nullable Location getLocation(); protected abstract void cull(float width, float height); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 046fa46c..581f8ad4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -995,10 +995,13 @@ private void pivot(float yaw, float pitch, float angleInDegrees){ } /** - * Set the location of this packet-based entity. The part should be hidden first with {@link #hide()} if being teleported to a different world. + * Set the location of this packet-based entity. + * {@inheritDoc} + *
The part should be hidden first with {@link #hide()} if being teleported to a different world. * @param location the location */ public void teleport(@NotNull Location location){ + if (hasGroup() && isDisplay() && !isMaster) return; packetLocation = new PacketLocation(location); for (UUID uuid : getViewers()){ Player player = Bukkit.getPlayer(uuid); @@ -1007,10 +1010,7 @@ public void teleport(@NotNull Location location){ } } - /** - * Set the location of this packet-based entity. The part should be hidden first with {@link #hide()} if being teleported to a different world. - * @param location the location - */ + void teleportUnsetPassengers(@NotNull Location location){ packetLocation = new PacketLocation(location); for (UUID uuid : getViewers()){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 2833323e..625a2b30 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -187,6 +187,15 @@ public boolean hasGroup(){ return !isSingle; } + @Override + public void teleport(@NotNull Location location) { + if (group != null && isDisplay() && !isMaster()){ + return; + } + Entity e = getEntity(); + if (e != null) e.teleport(location); + } + @Override public float getPitch() { return getEntity().getPitch(); From c20a8f7c2ac3f3fb332bf54c68f50f78db91d8e3 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 20 Dec 2025 20:22:06 -0600 Subject: [PATCH 037/139] Fix `/mdis parts adapttags` not functioning --- .../displayentityutils/command/parts/PartsAdaptTagsCMD.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAdaptTagsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAdaptTagsCMD.java index f1476a5e..d309955e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAdaptTagsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAdaptTagsCMD.java @@ -15,9 +15,6 @@ class PartsAdaptTagsCMD extends PartsSubCommand { setTabComplete(2, "-remove"); } - @Override - public void execute(Player player, String[] args) {} - @Override protected void sendIncorrectUsage(@NotNull Player player) {} From 4d4ce2b10b20712c8218027c9953fb59f938e092 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 02:56:45 -0600 Subject: [PATCH 038/139] Fix `/mdis parts move` & `/mdis parts movehere` not working correctly in certain situations and added "-all" param --- .../command/parts/PartsCMD.java | 4 +- .../command/parts/PartsMoveCMD.java | 82 +++++++++++++------ .../command/parts/PartsMoveHereCMD.java | 62 ++++++++------ 3 files changed, 95 insertions(+), 53 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java index fe9a7f98..7580258b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java @@ -104,8 +104,8 @@ else if (page == 4){ } else{ CMDUtils.sendCMD(sender, "/deu parts scale [-all]", "Change the scale of your selected part, by axis"); - CMDUtils.sendCMD(sender, "/deu parts move ", "Change the actual location of your selected part"); - CMDUtils.sendCMD(sender, "/deu parts movehere", "Change your selected part's actual location to your location"); + CMDUtils.sendCMD(sender, "/deu parts move [-all]", "Change the actual location of your selected part"); + CMDUtils.sendCMD(sender, "/deu parts movehere [-all]", "Change your selected part's actual location to your location"); CMDUtils.sendCMD(sender, "/deu parts setblock <\"-held\" | \"-target\" | block-id> [-all]", "Change the block of a block display part"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java index becdcf2f..419d48e4 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java @@ -3,13 +3,11 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.command.PlayerSubCommand; -import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.Direction; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; -import net.donnypz.displayentityutils.utils.version.folia.FoliaUtils; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -17,57 +15,87 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -class PartsMoveCMD extends PlayerSubCommand { +class PartsMoveCMD extends PartsSubCommand { - PartsMoveCMD(@NotNull DEUSubCommand parentSubCommand) { - super("move", parentSubCommand, Permission.PARTS_TRANSFORM); - setTabComplete(2, TabSuggestion.DIRECTIONS); - setTabComplete(3, ""); + public PartsMoveCMD(@NotNull DEUSubCommand parentSubCommand) { + super("move", parentSubCommand, Permission.PARTS_TRANSFORM, 4, 4); } @Override public void execute(Player player, String[] args) { - ActivePartSelection selection = DisplayGroupManager.getPartSelection(player); - if (selection == null){ - DisplayEntityPluginCommand.noPartSelection(player); + if (RelativePointUtils.isViewingRelativePoints(player)){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot play do that while viewing points!", NamedTextColor.RED))); return; } + super.execute(player, args); + } - if (PartsCMD.isUnwantedMultiSelection(player, selection)){ - return; - } + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(Component.text("Incorrect Usage! /deu parts move ", NamedTextColor.RED)); + } - if (args.length < 3){ - player.sendMessage(Component.text("Incorrect Usage! /deu parts move ", NamedTextColor.RED)); - return; + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + try{ + Direction direction = Direction.valueOf(args[2].toUpperCase()); + float distance = Float.parseFloat(args[3]); + if (distance <= 0){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a number greater than 0 for the distance!", NamedTextColor.RED))); + return false; + } + for (ActivePart part : selection.getSelectedParts()){ + if (part.isDisplay()) continue; + Location loc = part.getLocation(); + Vector v = direction.getVector(selection.getSelectedPart(), false).normalize().multiply(distance); + loc.add(v); + part.teleport(loc); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Moved ALL selected non-display parts!", NamedTextColor.GREEN))); + } } - - if (!selection.hasSelectedPart()){ - PartsCMD.invalidPartSelection(player); - return; + catch(NumberFormatException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter valid numbers!", NamedTextColor.RED))); + player.sendMessage(Component.text("Duration must be a positive whole number, distance can be any positive number", NamedTextColor.GRAY, TextDecoration.ITALIC)); + return false; } + catch(IllegalArgumentException e){ + DisplayEntityPluginCommand.invalidDirection(player); + return false; + } + return true; + } + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (selectedPart.isDisplay() && group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot do this for grouped display entities!", NamedTextColor.RED))); + player.sendMessage(Component.text("| Use \"/deu parts translate\" instead", NamedTextColor.GRAY)); + return false; + } try{ Direction direction = Direction.valueOf(args[2].toUpperCase()); float distance = Float.parseFloat(args[3]); if (distance <= 0){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a number greater than 0 for the distance!", NamedTextColor.RED))); - return; + return false; } - SpawnedDisplayEntityPart part = (SpawnedDisplayEntityPart) selection.getSelectedPart(); - Location loc = part.getLocation(); + Location loc = selectedPart.getLocation(); Vector v = direction.getVector(selection.getSelectedPart(), false).normalize().multiply(distance); loc.add(v); - FoliaUtils.teleport(part.getEntity(), loc); + selectedPart.teleport(loc); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Moved your selected part!", NamedTextColor.GREEN))); } catch(NumberFormatException e){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter valid numbers!", NamedTextColor.RED))); player.sendMessage(Component.text("Duration must be a positive whole number, distance can be any positive number", NamedTextColor.GRAY, TextDecoration.ITALIC)); + return false; } catch(IllegalArgumentException e){ DisplayEntityPluginCommand.invalidDirection(player); + return false; } + return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java index 0db8c20d..f08c26a5 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java @@ -1,48 +1,62 @@ package net.donnypz.displayentityutils.command.parts; import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.command.DEUSubCommand; -import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; -import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.command.PlayerSubCommand; -import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; -import net.donnypz.displayentityutils.utils.version.folia.FoliaUtils; +import net.donnypz.displayentityutils.command.*; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Location; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -class PartsMoveHereCMD extends PlayerSubCommand { +class PartsMoveHereCMD extends PartsSubCommand { - PartsMoveHereCMD(@NotNull DEUSubCommand parentSubCommand) { - super("movehere", parentSubCommand, Permission.PARTS_TRANSFORM); + public PartsMoveHereCMD(@NotNull DEUSubCommand parentSubCommand) { + super("movehere", parentSubCommand, Permission.PARTS_TRANSFORM, 2, 2); } @Override public void execute(Player player, String[] args) { - ActivePartSelection selection = DisplayGroupManager.getPartSelection(player); - if (selection == null){ - DisplayEntityPluginCommand.noPartSelection(player); + if (RelativePointUtils.isViewingRelativePoints(player)){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot play do that while viewing points!", NamedTextColor.RED))); return; } + super.execute(player, args); + } - if (PartsCMD.isUnwantedMultiSelection(player, selection)){ - return; + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(Component.text("Incorrect Usage! /deu parts movehere [-all]", NamedTextColor.RED)); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + for (ActivePart part : selection.getSelectedParts()){ + if (part.isDisplay()) continue; + Location loc = player.getLocation(); + loc.setYaw(part.getYaw()); + loc.setPitch(part.getPitch()); + part.teleport(loc); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Moved ALL selected non-display parts to your location!", NamedTextColor.GREEN))); } + return true; + } - if (!selection.hasSelectedPart()){ - PartsCMD.invalidPartSelection(player); - return; + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (selectedPart.isDisplay() && group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot do this for grouped display entities!", NamedTextColor.RED))); + player.sendMessage(Component.text("| Use \"/deu parts translate\" instead", NamedTextColor.GRAY)); + return false; } - Entity e = ((SpawnedDisplayEntityPart) selection.getSelectedPart()).getEntity(); + Location loc = player.getLocation(); - loc.setYaw(e.getYaw()); - loc.setPitch(e.getPitch()); - FoliaUtils.teleport(e, loc); + loc.setYaw(selectedPart.getYaw()); + loc.setPitch(selectedPart.getPitch()); + selectedPart.teleport(loc); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Moved your selected part to your location!", NamedTextColor.GREEN))); + return true; } } From 9e08afae9956df85b37872fe732fc99543ba6f52 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 03:14:44 -0600 Subject: [PATCH 039/139] Fix #getPart returning null for eligible entities --- .../utils/DisplayEntities/SpawnedDisplayEntityPart.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 625a2b30..dfb1ac27 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -270,7 +270,7 @@ PartData getPartData() { * @return The SpawnedDisplayEntityPart. Null if not created during play session or not associated with any group */ public static @Nullable SpawnedDisplayEntityPart getPart(@NotNull Entity entity){ - if (DisplayUtils.isPartEntity(entity)) return null; + if (!DisplayUtils.isPartEntity(entity)) return null; return allParts.get(new PartData(entity)); } From c78f07801df4ef01d78a0a287739654e8588e764 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 04:00:00 -0600 Subject: [PATCH 040/139] Remove "/deu interaction pivotselection", add -all param to "/deu interaction pivot" --- .../command/interaction/InteractionCMD.java | 4 +- .../interaction/InteractionPivotCMD.java | 35 ++++++++---- .../InteractionPivotSelectionCMD.java | 53 ------------------- 3 files changed, 26 insertions(+), 66 deletions(-) delete mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotSelectionCMD.java diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionCMD.java index fd3b7069..c122185c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionCMD.java @@ -28,7 +28,6 @@ public InteractionCMD(){ new InteractionWidthCMD(this); new InteractionScaleCMD(this); new InteractionPivotCMD(this); - new InteractionPivotSelectionCMD(this); new InteractionResponsiveCMD(this); new InteractionAddToGroupCMD(this); new InteractionSpawnHereCMD(this); @@ -66,8 +65,7 @@ static void interactionHelp(CommandSender sender, int page){ CMDUtils.sendCMD(sender, "/deu interaction scale ", "Scale an interaction entity over a period of time"); CMDUtils.sendCMD(sender, "/deu interaction addcmd ", "Add a command to an interaction"); CMDUtils.sendCMD(sender, "/deu interaction listcmds", "List all commands stored on an interaction"); - CMDUtils.sendCMD(sender, "/deu interaction pivot ", " Pivot an interaction around it's group's actual location center"); - CMDUtils.sendCMD(sender, "/deu interaction pivotselection ", "Pivot all Interactions included in your selected group's part filter"); + CMDUtils.sendCMD(sender, "/deu interaction pivot [-all]", " Pivot an interaction around it's group's"); CMDUtils.sendCMD(sender, "/deu interaction responsive", "Toggle the hit sound of an interaction entity"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotCMD.java index cf72eb88..3942b1eb 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotCMD.java @@ -8,10 +8,8 @@ import net.donnypz.displayentityutils.command.parts.PartsCMD; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.*; -import net.donnypz.displayentityutils.utils.DisplayUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.entity.Interaction; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -19,6 +17,7 @@ class InteractionPivotCMD extends PlayerSubCommand { InteractionPivotCMD(@NotNull DEUSubCommand parentSubCommand) { super("pivot", parentSubCommand, Permission.INTERACTION_PIVOT); setTabComplete(2, ""); + setTabComplete(3, "-all"); } @Override @@ -39,22 +38,38 @@ public void execute(Player player, String[] args) { return; } - MultiPartSelection selection = (MultiPartSelection) sel; if (args.length < 3){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage! /deu interaction pivot ", NamedTextColor.RED))); - return; - } - InteractionCMD.SelectedInteraction interaction = InteractionCMD.getInteraction(player, false); - if (interaction == null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage! /deu interaction pivot [-all]", NamedTextColor.RED))); return; } + double angle; try{ - interaction.pivot(selection.getGroup().getLocation(), Double.parseDouble(args[2])); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivoting Interaction around group", NamedTextColor.GREEN))); + angle = Double.parseDouble(args[2]);; } catch(NumberFormatException e){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid number for the angle!", NamedTextColor.RED))); + return; + } + + + MultiPartSelection selection = (MultiPartSelection) sel; + boolean isAll = args.length >= 4 && args[3].equalsIgnoreCase("-all"); + if (isAll){ + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + p.pivot((float) angle); + } + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivoting ALL Interaction entities in your selection around your group", NamedTextColor.GREEN))); + } + else{ + InteractionCMD.SelectedInteraction interaction = InteractionCMD.getInteraction(player, false); + if (interaction == null){ + return; + } + interaction.pivot(selection.getGroup().getLocation(), angle); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivoting Interaction around group", NamedTextColor.GREEN))); } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotSelectionCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotSelectionCMD.java deleted file mode 100644 index 5ac80b09..00000000 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotSelectionCMD.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.donnypz.displayentityutils.command.interaction; - -import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.command.DEUSubCommand; -import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; -import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.command.PlayerSubCommand; -import net.donnypz.displayentityutils.command.parts.PartsCMD; -import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.*; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -class InteractionPivotSelectionCMD extends PlayerSubCommand { - InteractionPivotSelectionCMD(@NotNull DEUSubCommand parentSubCommand) { - super("pivotselection", parentSubCommand, Permission.INTERACTION_PIVOT); - setTabComplete(2, ""); - } - - @Override - public void execute(Player player, String[] args) { - ActiveGroup group = DisplayGroupManager.getSelectedGroup(player); - if (group == null){ - DisplayEntityPluginCommand.noGroupSelection(player); - return; - } - - if (args.length < 3){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage! /deu interaction pivotselection ", NamedTextColor.RED))); - return; - } - - try{ - float angle = Float.parseFloat(args[2]); - ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); - - if (PartsCMD.isUnwantedSingleSelection(player, sel)){ - return; - } - - sel.pivot(angle); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivoting all Interaction Entities in part selection around group!", NamedTextColor.GREEN))); - if (group instanceof PacketDisplayEntityGroup pg){ - pg.update(); - } - } - catch(NumberFormatException e){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid number for the angle!", NamedTextColor.RED))); - } - } -} From 3e81b97c6571016e95058e4a970c45938c2fe16f Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 04:21:50 -0600 Subject: [PATCH 041/139] remove redundant #hasSameCreationTime methods --- .../SpawnedDisplayEntityGroup.java | 29 ++++--------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index db6fcbed..41ce9817 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -175,35 +175,18 @@ else if (!groupParts.isEmpty()){ } /** - * Check if this group and a Display entity share the same creation time. If this returns true this does not guarantee - * that the part is registered to this group. Using {@link SpawnedDisplayEntityGroup#addDisplayEntity(Display)} will - * add the display entity to the group if it is not added already - * @param display - * @return a boolean - */ - public boolean hasSameCreationTime(Display display){ - return sameCreationTime(display); - } - - /** - * Check if this group and an Interaction entity share the same creation time. If this returns true this does not guarantee - * that the part is registered to this group. Using {@link SpawnedDisplayEntityGroup#addEntity(Interaction)} will + * Check if this group and an entity share the same creation time. If this returns true this does not guarantee + * that the part is registered to this group. + *
Using {@link SpawnedDisplayEntityGroup#addEntity(Entity)} will * add the interaction entity to the group if it is not added already - * @param interaction + * @param entity the entity * @return a boolean */ - public boolean hasSameCreationTime(Interaction interaction){ - return sameCreationTime(interaction); - } - - - - private boolean sameCreationTime(Entity entity){ + public boolean hasSameCreationTime(Entity entity){ PersistentDataContainer container = entity.getPersistentDataContainer(); if (!container.has(creationTimeKey, PersistentDataType.LONG)){ return false; } - return creationTime == container.get(creationTimeKey, PersistentDataType.LONG); } @@ -218,7 +201,7 @@ private boolean sameCreationTime(Entity entity){ for (Entity e : getMasterPart().getEntity().getNearbyEntities(searchRange, searchRange, searchRange)) { if (!DisplayUtils.isPartEntity(e) || e instanceof Display) continue; - if (!sameCreationTime(e)) continue; + if (!hasSameCreationTime(e)) continue; SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(e); if (part == null){ From 9102a6ec624422302e42f0fdbae6780b1ae08ee7 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 04:25:16 -0600 Subject: [PATCH 042/139] Update group entity detection for new part types. Renamed ChunkAddGroupInteractionsEvent to ChunkAddGroupEntitiesEvent --- ...t.java => ChunkAddGroupEntitiesEvent.java} | 29 ++++++------ .../events/ChunkRegisterGroupEvent.java | 7 ++- .../listeners/autogroup/AutoGroup.java | 47 +++++++++---------- 3 files changed, 39 insertions(+), 44 deletions(-) rename api/src/main/java/net/donnypz/displayentityutils/events/{ChunkAddGroupInteractionsEvent.java => ChunkAddGroupEntitiesEvent.java} (50%) diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupInteractionsEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupEntitiesEvent.java similarity index 50% rename from api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupInteractionsEvent.java rename to api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupEntitiesEvent.java index d1761d47..0a6c9bd7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupInteractionsEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupEntitiesEvent.java @@ -3,28 +3,29 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import org.bukkit.Chunk; -import org.bukkit.entity.Interaction; +import org.bukkit.entity.Entity; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.HashSet; /** - * Called when a Chunk adds a {@link SpawnedDisplayEntityPart} of the type {@link SpawnedDisplayEntityPart.PartType#INTERACTION} to an already registered {@link SpawnedDisplayEntityGroup}. + * Called when a Chunk adds a non-display {@link SpawnedDisplayEntityPart} to an already registered {@link SpawnedDisplayEntityGroup}. *

- * It is not guaranteed that every expected Interaction entity for a group will be added with this event, it may only be a partial amount. + * It is not guaranteed that every entity expected to be in a group will be added with this event, due to config settings and loaded chunks. */ -public class ChunkAddGroupInteractionsEvent extends Event { +public class ChunkAddGroupEntitiesEvent extends Event { private static final HandlerList handlers = new HandlerList(); SpawnedDisplayEntityGroup spawnedDisplayEntityGroup; - Collection interactions; + Collection entities; Chunk chunk; - public ChunkAddGroupInteractionsEvent(SpawnedDisplayEntityGroup group, Collection interactions, Chunk chunk){ + public ChunkAddGroupEntitiesEvent(SpawnedDisplayEntityGroup group, Collection entities, Chunk chunk){ this.spawnedDisplayEntityGroup = group; - this.interactions = interactions; + this.entities = entities; this.chunk = chunk; } @@ -32,24 +33,24 @@ public ChunkAddGroupInteractionsEvent(SpawnedDisplayEntityGroup group, Collectio * Get the {@link SpawnedDisplayEntityGroup} involved in this event * @return a group */ - public SpawnedDisplayEntityGroup getGroup() { + public @NotNull SpawnedDisplayEntityGroup getGroup() { return spawnedDisplayEntityGroup; } /** - * Get the {@link Interaction} entities involved in this event - *

Use {@link SpawnedDisplayEntityPart#getPart(Interaction)} to get the entities as parts

- * @return a collection of {@link Interaction} entities. + * Get the entities involved in this event + *

Use {@link SpawnedDisplayEntityPart#getEntity()} to get the entities as parts

+ * @return a collection of entities. */ - public Collection getInteractions() { - return new HashSet<>(interactions); + public @NotNull Collection getEntities() { + return new HashSet<>(entities); } /** * Get the chunk involved in this event * @return a chunk */ - public Chunk getChunk() { + public @NotNull Chunk getChunk() { return chunk; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/ChunkRegisterGroupEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/ChunkRegisterGroupEvent.java index fe289bf5..6cedd6e7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/ChunkRegisterGroupEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/ChunkRegisterGroupEvent.java @@ -7,9 +7,10 @@ /** * Called when a Chunk loads a {@link SpawnedDisplayEntityGroup} and registers it. - *

It is not guaranteed that all Interaction entities in the given group will be added at group registration time. + *

It is not guaranteed that all non-display entities in the given group will be added at group registration time. *
- * In rare cases, it is recommended to use the {@link ChunkAddGroupInteractionsEvent} if Interaction entities are expected, but are infrequently (or not at all) added found in a group, through this event.

+ * In rare cases, it is recommended to use the {@link ChunkAddGroupEntitiesEvent} if non-display entities are expected, + * but are infrequently (or not at all) added found in a group, through this event.

*/ public class ChunkRegisterGroupEvent extends Event { private static final HandlerList handlers = new HandlerList(); @@ -38,8 +39,6 @@ public Chunk getChunk() { return chunk; } - - @Override public HandlerList getHandlers() { return handlers; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java index 58c6c6ca..f2b0d0cf 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java @@ -2,7 +2,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.DisplayConfig; -import net.donnypz.displayentityutils.events.ChunkAddGroupInteractionsEvent; +import net.donnypz.displayentityutils.events.ChunkAddGroupEntitiesEvent; import net.donnypz.displayentityutils.events.ChunkRegisterGroupEvent; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; @@ -15,7 +15,6 @@ import org.bukkit.World; import org.bukkit.entity.Display; import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -48,22 +47,18 @@ static void detectGroups(Chunk chunk, List entities){ String worldName = world.getName(); Set chunks = readChunks.computeIfAbsent(worldName, name -> Collections.newSetFromMap(new ConcurrentHashMap<>())); - if (chunks.contains(chunk.getChunkKey())){ + if (!chunks.add(chunk.getChunkKey())){ //Already Contained refreshGroupPartEntities(entities); if (!DisplayConfig.readSameChunks()) return; } - else{ - chunks.add(chunk.getChunkKey()); - } - - DisplayGroupManager.spawnPersistentPacketGroups(chunk); + DisplayGroupManager.spawnPersistentPacketGroups(chunk); if (entities.isEmpty()) return; Set foundGroups = new HashSet<>(); - HashMap> addedInteractionsForEvent = new HashMap<>(); - Set interactions = new HashSet<>(); + HashMap> addedEntitiesForEvent = new HashMap<>(); + Set eligibleNonDisplays = new HashSet<>(); HashMap events = new HashMap<>(); for (Entity entity : entities){ @@ -98,13 +93,13 @@ static void detectGroups(Chunk chunk, List entities){ events.put(group, new ChunkRegisterGroupEvent(group, chunk)); } } - - //Interaction Entities (Required if the interaction happens to be in a different chunk) - else if (entity instanceof Interaction interaction) { - interactions.add(interaction); - } - //Entity with Packet Based Controller else{ + //(Required if the entity happens to be in a different chunk) + if (DisplayUtils.isPartEntity(entity)) { + eligibleNonDisplays.add(entity); + } + + //Entity with Packet Based Controller PersistentDataContainer pdc = entity.getPersistentDataContainer(); String controllerID = pdc.get(DisplayControllerManager.controllerIdKey, PersistentDataType.STRING); if (controllerID == null) continue; //Not a packet based controller @@ -118,13 +113,13 @@ else if (entity instanceof Interaction interaction) { } } - for (Interaction interaction : interactions){ //Processed after all Display Entities - if (SpawnedDisplayEntityPart.getPart(interaction) != null){ //Already added to a group + for (Entity entity : eligibleNonDisplays){ //Processed after all Display Entities + if (SpawnedDisplayEntityPart.getPart(entity) != null){ //Already added to a group continue; } //Bukkit.getScheduler().runTask(DisplayAPI.getPlugin(), () -> { - List results = DisplayGroupManager.getSpawnedGroupsNearLocation(interaction.getLocation(), DisplayConfig.getMaximumInteractionSearchRange()); + List results = DisplayGroupManager.getSpawnedGroupsNearLocation(entity.getLocation(), DisplayConfig.getMaximumInteractionSearchRange()); if (results.isEmpty()){ //Group has not been created yet, or it is not a group interaction continue; } @@ -132,12 +127,12 @@ else if (entity instanceof Interaction interaction) { for (GroupResult result : results){ SpawnedDisplayEntityGroup group = result.group(); - if (group.hasSameCreationTime(interaction)) { - group.addEntity(interaction); + if (group.hasSameCreationTime(entity)) { + group.addEntity(entity); if (!events.containsKey(group)){ - addedInteractionsForEvent.putIfAbsent(result.group(), new HashSet<>()); - addedInteractionsForEvent.get(group).add(interaction); + addedEntitiesForEvent.putIfAbsent(result.group(), new HashSet<>()); + addedEntitiesForEvent.get(group).add(entity); } } } @@ -156,15 +151,15 @@ else if (entity instanceof Interaction interaction) { event.callEvent(); } - for (Map.Entry> entry : addedInteractionsForEvent.entrySet()){ + for (Map.Entry> entry : addedEntitiesForEvent.entrySet()){ SpawnedDisplayEntityGroup g = entry.getKey(); if (!g.isSpawned()){ continue; } - Collection coll = entry.getValue(); + Set coll = entry.getValue(); if (!coll.isEmpty()){ - new ChunkAddGroupInteractionsEvent(g, addedInteractionsForEvent.get(g), chunk).callEvent(); + new ChunkAddGroupEntitiesEvent(g, addedEntitiesForEvent.get(g), chunk).callEvent(); } } } From ad60c08c66c70763256af21293af190a0f81c9ea Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 04:37:07 -0600 Subject: [PATCH 043/139] prevent breaking change --- .../managers/DisplayGroupManager.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java index 9031f947..8c356a7a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java @@ -507,8 +507,8 @@ private static DisplayEntityGroup getGroupFromJson(JsonObject jsonObject){ * Get the {@link GroupResult} of a display entity containing its {@link SpawnedDisplayEntityGroup}, if applicable. *
* If a group is created as a result of this, {@link GroupRegisteredEvent} will be called - * - * @param displayEntity The display entity within a group + * @param displayEntity The display entity that's in a group + * @return a {@link GroupResult} or null */ public static @Nullable GroupResult getSpawnedGroup(@NotNull Display displayEntity) { //Check for already registered group @@ -547,6 +547,17 @@ else if (displayEntity.getPassengers().isEmpty()) { } + /** + * Get a {@link SpawnedDisplayEntityGroup} through an Interaction entity + * @param interaction The interaction + * @param radius The radius to search for the group + * @return a {@link SpawnedDisplayEntityGroup} containing the interaction. Null if not found. + */ + public static @Nullable SpawnedDisplayEntityGroup getSpawnedGroup(@NotNull Interaction interaction, double radius){ //Keep this just to prevent breakage + return getSpawnedGroup((Entity) interaction, radius); + } + + /** * Get a {@link SpawnedDisplayEntityGroup} through an eligible part entity * @param entity The entity that's in a group From 238810ded62fae640c28619d2303cd190b9408fe Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 05:33:05 -0600 Subject: [PATCH 044/139] Fix #getType always returning null on <1.21.9 servers --- .../SpawnedDisplayEntityPart.java | 36 +++++-------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index dfb1ac27..ba18f0d4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -10,6 +10,7 @@ import net.donnypz.displayentityutils.utils.packet.DisplayAttributeMap; import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; +import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.kyori.adventure.text.Component; import org.bukkit.*; import org.bukkit.attribute.Attribute; @@ -1219,34 +1220,13 @@ public enum PartType{ * @return a {@link PartType} or null if the entity does not have a type. */ public static PartType getType(@NotNull Entity entity){ - try{ - switch (entity){ - case Interaction i -> { - return INTERACTION; - } - case BlockDisplay d -> { - return BLOCK_DISPLAY; - } - case ItemDisplay d -> { - return ITEM_DISPLAY; - } - case TextDisplay d -> { - return TEXT_DISPLAY; - } - case Shulker s -> { - return SHULKER; - } - case Mannequin m -> { - return MANNEQUIN; - } - default -> { - return null; - } - } - } - catch (NoClassDefFoundError e){ //Mannequin on < 1.21.9 - return null; - } + if (entity instanceof BlockDisplay) return BLOCK_DISPLAY; + if (entity instanceof ItemDisplay) return ITEM_DISPLAY; + if (entity instanceof TextDisplay) return TEXT_DISPLAY; + if (entity instanceof Interaction) return INTERACTION; + if (entity instanceof Shulker) return SHULKER; + if (VersionUtils.IS_1_21_9 && entity instanceof Mannequin) return MANNEQUIN; + return null; } public boolean isOfType(Entity e){ From f4cfed9b06639b7ea55cd84cba260d9ec19947ed Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 19:13:45 -0600 Subject: [PATCH 045/139] Rework #scale, #setYaw, #setRotation, and #pivot methods to support new part types --- .../utils/DisplayEntities/ActiveGroup.java | 6 ++-- .../utils/DisplayEntities/ActivePart.java | 28 +++++++++---------- .../DisplayEntities/MultiPartSelection.java | 7 +++-- .../PacketDisplayEntityGroup.java | 8 ++++-- .../PacketDisplayEntityPart.java | 12 ++++++-- .../DisplayEntities/PacketPartSelection.java | 4 +-- .../utils/DisplayEntities/Packeted.java | 2 +- .../DisplayEntities/SinglePartSelection.java | 4 +++ .../SpawnedDisplayEntityGroup.java | 4 +-- .../SpawnedDisplayEntityPart.java | 14 +++++----- 10 files changed, 52 insertions(+), 37 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java index 031577c2..4edd56e1 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java @@ -216,12 +216,12 @@ public void setInterpolationDelay(int interpolationDelay){ /** * Change the yaw of this group * @param yaw The yaw to set for this group - * @param pivotInteractions true if interactions should pivot around the group with the yaw change + * @param pivot whether non-display entities should pivot around the group */ @Override - public void setYaw(float yaw, boolean pivotInteractions){ + public void setYaw(float yaw, boolean pivot){ for (ActivePart part : groupParts.values()){ - part.setYaw(yaw, pivotInteractions); + part.setYaw(yaw, pivot); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 2cb907fe..0ee2e5d1 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -334,32 +334,32 @@ public void unglow(@NotNull Player player) { public abstract void setTransformationMatrix(@NotNull Matrix4f matrix); /** - * Change the X scale of this part - * @param scale The X scale to set for this part - * @return false if this part is an Interaction + * Change this display entity part's X scale + * @param scale The X scale to set + * @return false if this part is not a display entity */ public abstract boolean setXScale(float scale); /** - * Change the Y scale of this part - * @param scale The Y scale to set for this part - * @return false if this part is an Interaction + * Change this display entity part's Y scale + * @param scale The Y scale to set + * @return false if this part is not a display entity */ public abstract boolean setYScale(float scale); /** - * Change the Z scale of this part - * @param scale The Z scale to set for this part - * @return false if this part is an Interaction + * Change this display entity part's Z scale + * @param scale The Z scale to set + * @return false if this part is not a display entity */ public abstract boolean setZScale(float scale); /** - * Change the scale of this part - * @param x The X scale to set for this part - * @param y The Y scale to set for this part - * @param z The Z scale to set for this part - * @return false if this part is an Interaction + * Change this display entity part's scale + * @param x The X scale to set + * @param y The Y scale to set + * @param z The Z scale to set + * @return false if this part is not a display entity */ public abstract boolean setScale(float x, float y, float z); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MultiPartSelection.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MultiPartSelection.java index 64d93f0c..1ecf1d54 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MultiPartSelection.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MultiPartSelection.java @@ -487,7 +487,7 @@ public void unglow(@NotNull Player player){ } /** - * Pivot all Interaction parts in this selection around the SpawnedDisplayEntityGroup's master part + * Pivot all non-display parts in this selection around this selection's group * @param angleInDegrees the pivot angle */ @Override @@ -500,11 +500,12 @@ public void pivot(float angleInDegrees){ /** * Set the yaw of all parts in this selection * @param yaw the yaw to set + * @param pivot whether non-display entities should pivot around the group */ @Override - public void setYaw(float yaw, boolean pivotInteractions){ + public void setYaw(float yaw, boolean pivot){ for (T part : selectedParts){ - part.setYaw(yaw, pivotInteractions); + part.setYaw(yaw, pivot); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index fb168f51..8672e0f4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -529,12 +529,16 @@ public void setAttributes(@NotNull DisplayAttributeMap attributeMap, SpawnedDisp } @Override - public void setRotation(float pitch, float yaw, boolean pivotIfInteraction){ + public void setRotation(float pitch, float yaw, boolean pivot){ for (PacketDisplayEntityPart part : groupParts.values()){ - part.setRotation(pitch, yaw, pivotIfInteraction); + part.setRotation(pitch, yaw, pivot); } } + /** + * Pivot all non-display parts in this group around the group + * @param angleInDegrees the pivot angle + */ @Override public void pivot(float angleInDegrees) { for (PacketDisplayEntityPart part : groupParts.values()){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 581f8ad4..14a55243 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -928,8 +928,8 @@ public void setBrightness(Display.@Nullable Brightness brightness) { } @Override - public void setRotation(float pitch, float yaw, boolean pivotIfInteraction){ - if (pivotIfInteraction && type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + public void setRotation(float pitch, float yaw, boolean pivot){ + if (pivot && !isDisplay()){ pivot(yaw, pitch); } else if (!viewers.isEmpty()){ @@ -948,6 +948,11 @@ public void setPitch(float pitch) { setRotation(pitch, getYaw(), false); } + /** + * Change the yaw of this part + * @param yaw The yaw to set for this part + * @param pivot whether the part should pivot around its group's location, if it has one, and if the part is an Interaction + */ @Override public void setYaw(float yaw, boolean pivot) { setRotation(getPitch(), yaw, pivot); @@ -964,7 +969,7 @@ public float getYaw(){ } /** - * Pivot an Interaction Entity around its group's master part + * Pivot a non-display entity around its group's master part * @param angleInDegrees the pivot angle */ @Override @@ -978,6 +983,7 @@ private void pivot(float yaw, float pitch){ } private void pivot(float yaw, float pitch, float angleInDegrees){ + if (group == null || isDisplay()) return; Location groupLoc = group.getLocation(); Location pivotedLoc = DisplayUtils.getPivotLocation(getLocation(), groupLoc, angleInDegrees); packetLocation.setCoordinates(pivotedLoc); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketPartSelection.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketPartSelection.java index c301dcbb..e3e5f84c 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketPartSelection.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketPartSelection.java @@ -84,9 +84,9 @@ public void remove() { } @Override - public void setRotation(float pitch, float yaw, boolean pivotIfInteraction) { + public void setRotation(float pitch, float yaw, boolean pivot) { for (PacketDisplayEntityPart part : selectedParts){ - part.setRotation(pitch, yaw, pivotIfInteraction); + part.setRotation(pitch, yaw, pivot); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/Packeted.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/Packeted.java index c054c043..164c5670 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/Packeted.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/Packeted.java @@ -10,7 +10,7 @@ public interface Packeted{ - void setRotation(float pitch, float yaw, boolean pivotIfInteraction); + void setRotation(float pitch, float yaw, boolean pivot); @Nullable Location getLocation(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java index 2eda5174..2df3a853 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java @@ -106,6 +106,10 @@ public void setYaw(float yaw, boolean pivot) { selectedPart.setYaw(yaw, pivot); } + /** + * Pivot a non-display entity around its group's master part + * @param angleInDegrees the pivot angle + */ @Override public void pivot(float angleInDegrees) { selectedPart.pivot(angleInDegrees); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index 41ce9817..8018529f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -651,13 +651,13 @@ public List getTeleportMoveLocations(Vector direction, double distance /** - * Pivot all Interaction parts in this selection around this group's master part + * Pivot all non-display parts in this group around the group * @param angleInDegrees the pivot angle */ @Override public void pivot(float angleInDegrees){ for (ActivePart part : groupParts.values()){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ part.pivot(angleInDegrees); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index ba18f0d4..8d0d9804 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -507,12 +507,12 @@ public Collection getTrackingPlayers() { /** * Change the yaw of this part * @param yaw The yaw to set for this part - * @param pivotIfInteraction true if this part's type is {@link PartType#INTERACTION} and it should pivot around the group's location + * @param pivot whether the part should pivot around its group's location, if it has one, and if the part is an Interaction */ @Override - public void setYaw(float yaw, boolean pivotIfInteraction){ + public void setYaw(float yaw, boolean pivot){ Entity entity = getEntity(); - if (type == PartType.INTERACTION && pivotIfInteraction){ + if (!isDisplay() && pivot){ pivot(yaw-entity.getYaw()); } entity.setRotation(yaw, entity.getPitch()); @@ -721,14 +721,14 @@ void translateForce(Direction direction, float distance, int durationInTicks, in } /** - * Pivot an Interaction Entity around its group's master part + * Pivot a non-display entity around its group's master part * @param angleInDegrees the pivot angle */ @Override public void pivot(float angleInDegrees){ - Entity entity = getEntity(); - if (isDisplay() || isSingle) return; - Interaction i = (Interaction) entity; + if (isDisplay() || isSingle || group == null) return; + Interaction i = (Interaction) getEntity(); + if (i == null) return; DisplayUtils.pivot(i, group.getLocation(), angleInDegrees); } From acefc99f49d6c5dd120ef41fc9a65441fd2ca1e6 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 20:18:52 -0600 Subject: [PATCH 046/139] Remove interaction count tracking when adding/removing parts --- .../PacketDisplayEntityGroup.java | 19 ++----------------- .../PacketDisplayEntityPart.java | 2 +- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index 8672e0f4..da8aaa73 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -34,7 +34,6 @@ public class PacketDisplayEntityGroup extends ActiveGroup allPacketGroups = new ConcurrentHashMap<>(); private static final ConcurrentHashMap groupVehicles = new ConcurrentHashMap<>(); - int interactionCount; int[] passengerIds; UUID vehicleUUID; boolean autoShow; @@ -196,7 +195,7 @@ public void chunkUnloadLocation(){ @Override public void addPart(@NotNull PacketDisplayEntityPart part){ addPartSilent(part); - updatePartCount(part, true); + updatePassengerIds(part.getEntityId(), true); } void addPartSilent(PacketDisplayEntityPart part){ @@ -216,21 +215,7 @@ void addPartSilent(PacketDisplayEntityPart part){ } } - void updatePartCount(PacketDisplayEntityPart part, boolean add){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - if (add){ - interactionCount++; - } - else{ - interactionCount--; - } - } - else{ - updatePassengerIds(part.getEntityId(), add); - } - } - - private void updatePassengerIds(int passengerId, boolean add){ + void updatePassengerIds(int passengerId, boolean add){ int[] ids; if (add){ ids = new int[passengerIds.length+1]; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 14a55243..240366c7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -1198,7 +1198,7 @@ public void removeFromGroup(boolean unregister){ if (!hasGroup()) return; group.groupParts.remove(partUUID); if (!isMaster){ - group.updatePartCount(this, false); + group.updatePassengerIds(getEntityId(), false); } group = null; if (unregister){ From 52053bb4b281ae076277b5ff3c4cd03e02653b71 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 21:00:54 -0600 Subject: [PATCH 047/139] Rename display entity scale methods --- .../utils/DisplayEntities/ActivePart.java | 8 ++++---- .../utils/DisplayEntities/PacketDisplayEntityPart.java | 8 ++++---- .../utils/DisplayEntities/SpawnedDisplayEntityPart.java | 8 ++++---- .../displayentityutils/command/parts/PartsScaleCMD.java | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 0ee2e5d1..88e1855f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -338,21 +338,21 @@ public void unglow(@NotNull Player player) { * @param scale The X scale to set * @return false if this part is not a display entity */ - public abstract boolean setXScale(float scale); + public abstract boolean setDisplayXScale(float scale); /** * Change this display entity part's Y scale * @param scale The Y scale to set * @return false if this part is not a display entity */ - public abstract boolean setYScale(float scale); + public abstract boolean setDisplayYScale(float scale); /** * Change this display entity part's Z scale * @param scale The Z scale to set * @return false if this part is not a display entity */ - public abstract boolean setZScale(float scale); + public abstract boolean setDisplayZScale(float scale); /** * Change this display entity part's scale @@ -361,7 +361,7 @@ public void unglow(@NotNull Player player) { * @param z The Z scale to set * @return false if this part is not a display entity */ - public abstract boolean setScale(float x, float y, float z); + public abstract boolean setDisplayScale(float x, float y, float z); /** * Set the text of this part if its type is {@link SpawnedDisplayEntityPart.PartType#TEXT_DISPLAY}. diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 240366c7..e27676ef 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -299,7 +299,7 @@ public void setTransformationMatrix(@NotNull Matrix4f matrix) { } @Override - public boolean setXScale(float scale) { + public boolean setDisplayXScale(float scale) { if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.x = scale; @@ -308,7 +308,7 @@ public boolean setXScale(float scale) { } @Override - public boolean setYScale(float scale) { + public boolean setDisplayYScale(float scale) { if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.y = scale; @@ -317,7 +317,7 @@ public boolean setYScale(float scale) { } @Override - public boolean setZScale(float scale) { + public boolean setDisplayZScale(float scale) { if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.z = scale; @@ -326,7 +326,7 @@ public boolean setZScale(float scale) { } @Override - public boolean setScale(float x, float y, float z) { + public boolean setDisplayScale(float x, float y, float z) { if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.x = x; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 8d0d9804..0412b871 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -529,7 +529,7 @@ public void setPitch(float pitch){ } @Override - public boolean setXScale(float scale){ + public boolean setDisplayXScale(float scale){ if (!isDisplay()) return false; Transformation t = getTransformation(); Vector3f v = t.getScale(); @@ -540,7 +540,7 @@ public boolean setXScale(float scale){ } @Override - public boolean setYScale(float scale){ + public boolean setDisplayYScale(float scale){ if (!isDisplay()) return false; Transformation t = getTransformation(); Vector3f v = t.getScale(); @@ -551,7 +551,7 @@ public boolean setYScale(float scale){ } @Override - public boolean setZScale(float scale){ + public boolean setDisplayZScale(float scale){ if (!isDisplay()) return false; Transformation t = getTransformation(); Vector3f v = t.getScale(); @@ -562,7 +562,7 @@ public boolean setZScale(float scale){ } @Override - public boolean setScale(float x, float y, float z){ + public boolean setDisplayScale(float x, float y, float z){ if (!isDisplay()) return false; Transformation t = getTransformation(); Transformation newT = new Transformation(t.getTranslation(), t.getLeftRotation(), new Vector3f(x, y, z), t.getRightRotation()); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java index 0497d741..fba9ad99 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java @@ -76,16 +76,16 @@ private float getScale(String[] args){ private boolean applyScaleChange(String dim, float scale, ActivePart part, Player player){ switch (dim){ case "x" -> { - part.setXScale(scale); + part.setDisplayXScale(scale); } case "y" -> { - part.setYScale(scale); + part.setDisplayYScale(scale); } case "z" -> { - part.setZScale(scale); + part.setDisplayZScale(scale); } case "-all" -> { - part.setScale(scale, scale, scale); + part.setDisplayScale(scale, scale, scale); } default -> { sendIncorrectUsage(player); From bf9a62822de038af3a3e43fc7fcedf09af7ad483 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 21 Dec 2025 21:54:54 -0600 Subject: [PATCH 048/139] Move display related part commands to its own subcommand, changed permissions, added help pages --- .../command/DisplayEntityPluginCommand.java | 70 ++++++++++++++----- .../command/PartsSubCommand.java | 10 ++- .../command/Permission.java | 14 ++-- .../DisplayBillboardCMD.java} | 12 ++-- .../DisplayBrightnessCMD.java} | 29 ++++---- .../command/display/DisplayCMD.java | 55 +++++++++++++++ .../DisplayGlowColorCMD.java} | 28 ++++---- .../command/display/DisplayHelpCMD.java | 27 +++++++ .../DisplayScaleCMD.java} | 18 ++--- .../DisplaySetBlockCMD.java} | 15 ++-- .../DisplayTranslateCMD.java} | 15 ++-- .../DisplayViewRangeCMD.java} | 12 ++-- .../command/parts/PartsCMD.java | 24 ++----- .../command/parts/PartsMoveCMD.java | 2 +- .../command/parts/PartsMoveHereCMD.java | 2 +- 15 files changed, 217 insertions(+), 116 deletions(-) rename plugin/src/main/java/net/donnypz/displayentityutils/command/{parts/PartsBillboardCMD.java => display/DisplayBillboardCMD.java} (83%) rename plugin/src/main/java/net/donnypz/displayentityutils/command/{parts/PartsBrightnessCMD.java => display/DisplayBrightnessCMD.java} (71%) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java rename plugin/src/main/java/net/donnypz/displayentityutils/command/{parts/PartsGlowColorCMD.java => display/DisplayGlowColorCMD.java} (66%) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayHelpCMD.java rename plugin/src/main/java/net/donnypz/displayentityutils/command/{parts/PartsScaleCMD.java => display/DisplayScaleCMD.java} (82%) rename plugin/src/main/java/net/donnypz/displayentityutils/command/{parts/PartsSetBlockCMD.java => display/DisplaySetBlockCMD.java} (78%) rename plugin/src/main/java/net/donnypz/displayentityutils/command/{parts/PartsTranslateCMD.java => display/DisplayTranslateCMD.java} (86%) rename plugin/src/main/java/net/donnypz/displayentityutils/command/{parts/PartsViewRangeCMD.java => display/DisplayViewRangeCMD.java} (83%) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java index 386c3e7c..0357c0d4 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java @@ -3,6 +3,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.anim.AnimCMD; import net.donnypz.displayentityutils.command.bdengine.BDEngineCMD; +import net.donnypz.displayentityutils.command.display.DisplayCMD; import net.donnypz.displayentityutils.command.group.GroupCMD; import net.donnypz.displayentityutils.command.interaction.InteractionCMD; import net.donnypz.displayentityutils.command.item.ItemCMD; @@ -15,6 +16,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -48,6 +50,7 @@ public DisplayEntityPluginCommand(){ subCommands.put("hidepoints", new HidePointsCMD()); subCommands.put("group", new GroupCMD()); subCommands.put("parts", new PartsCMD()); + subCommands.put("display", new DisplayCMD()); subCommands.put("item", new ItemCMD()); subCommands.put("text", new TextCMD()); subCommands.put("interaction", new InteractionCMD()); @@ -162,13 +165,34 @@ public static Entity getTargetEntity(Player player){ @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (args.length == 0) { - mainCommandHelp(sender); + mainCommandHelp(sender, 1); return true; } + + int pageNum; String arg = args[0]; + if (arg.equalsIgnoreCase("help")){ + if (args.length >= 2){ + try{ + pageNum = Integer.parseInt(args[1]); + } + catch(IllegalArgumentException e){ + pageNum = 1; + } + } + else{ + pageNum = 1; + } + } + else{ + pageNum = 1; + } + + DEUSubCommand subCommand = subCommands.get(arg); + if (subCommand == null){ - mainCommandHelp(sender); + mainCommandHelp(sender, pageNum); } else{ executeCommand(subCommand, sender, args); @@ -201,26 +225,34 @@ public static boolean hasPermission(@NotNull CommandSender sender, @NotNull Perm } - static void mainCommandHelp(CommandSender sender){ + static void mainCommandHelp(CommandSender sender, int page){ if (!hasPermission(sender, Permission.HELP)) { return; } + sender.sendMessage(Component.empty()); sender.sendMessage(DisplayAPI.pluginPrefixLong); - sender.sendMessage(Component.text("v"+DisplayAPI.getVersion(), NamedTextColor.GRAY)); - CMDUtils.sendCMD(sender, "/deu group", "Display Entity Models/Groups related commands"); - CMDUtils.sendCMD(sender, "/deu parts", "Commands related to the parts (individual display entities) of a Display Entity Model/Group"); - CMDUtils.sendCMD(sender, "/deu item", "Commands related to the Item Display parts of a Display Entity Model/Group"); - CMDUtils.sendCMD(sender, "/deu text", "Commands related to the Text Display parts of a Display Entity Model/Group"); - CMDUtils.sendCMD(sender, "/deu interaction", "Commands related to manipulating Interaction entities"); - CMDUtils.sendCMD(sender, "/deu mannequin", "Commands related to manipulating Mannequin entities"); - CMDUtils.sendCMD(sender, "/deu place", "Assign a Display Entity Model/Group to an block that will spawn when placed"); - CMDUtils.sendCMD(sender, "/deu anim", "Animation related commands"); - CMDUtils.sendCMD(sender, "/deu listgroups [page-number]", "List all saved Display Entity Models/Groups"); - CMDUtils.sendCMD(sender, "/deu listanims [page-number]", "List all saved animations"); - CMDUtils.sendCMD(sender, "/deu hidepoints", "Hide any visible points (frame points, persistent packet group points, etc.)"); - CMDUtils.sendCMD(sender, "/deu bdengine", "Import/Convert models from BDEngine"); - CMDUtils.sendCMD(sender, "/deu reload ", "Reload the plugin's config or Display Controllers." + - " To reload Local, MySQL or MongoDB config save options, the server must be restarted"); + if (page == 1){ + sender.sendMessage(Component.text("v"+DisplayAPI.getVersion(), NamedTextColor.GRAY)); + CMDUtils.sendCMD(sender, "/deu help ", "Display the plugin's help commands"); + CMDUtils.sendCMD(sender, "/deu group", "Display Entity Models/Groups related commands"); + CMDUtils.sendCMD(sender, "/deu parts", "Commands related to the parts (individual display entities) of a Display Entity Model/Group"); + CMDUtils.sendCMD(sender, "/deu display", "Commands related to display entities"); + CMDUtils.sendCMD(sender, "/deu item", "Commands related to specifically Item Displays"); + CMDUtils.sendCMD(sender, "/deu text", "Commands related to specifically Text Displays"); + CMDUtils.sendCMD(sender, "/deu interaction", "Commands related to Interaction entities"); + CMDUtils.sendCMD(sender, "/deu mannequin", "Commands related to Mannequin entities"); + } + else{ + CMDUtils.sendCMD(sender, "/deu place", "Assign a Display Entity Model/Group to an block that will spawn when placed"); + CMDUtils.sendCMD(sender, "/deu anim", "Animation related commands"); + CMDUtils.sendCMD(sender, "/deu listgroups [page-number]", "List all saved Display Entity Models/Groups"); + CMDUtils.sendCMD(sender, "/deu listanims [page-number]", "List all saved animations"); + CMDUtils.sendCMD(sender, "/deu hidepoints", "Hide any visible points (frame points, persistent packet group points, etc.)"); + CMDUtils.sendCMD(sender, "/deu bdengine", "Import/Convert models from BDEngine"); + CMDUtils.sendCMD(sender, "/deu reload ", "Reload the plugin's config or Display Controllers." + + " To reload Local, MySQL or MongoDB config save options, the server must be restarted"); + } + sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } @Override @@ -237,7 +269,7 @@ public List onTabComplete(CommandSender sender, Command command, String String subcmd = args[0].toLowerCase(); String current = args[1]; switch (subcmd) { - case "interaction", "anim", "group", "parts", "bdengine", "text", "item", "place", "mannequin" -> { + case "interaction", "anim", "group", "parts", "display", "bdengine", "text", "item", "place", "mannequin" -> { return getTabComplete(subcmd, current); } case "listgroups", "listanims" -> suggestions.addAll(DEUSubCommand.TabSuggestion.STORAGES.suggestions); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java index 4f01b144..83b5bb87 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java @@ -70,7 +70,15 @@ public void execute(Player player, String[] args){ protected boolean isInvalidType(Player player, ActivePart part, SpawnedDisplayEntityPart.PartType validType){ if (part.getType() != validType){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with "+validType.name().toLowerCase().replace("_"," ")+" entities", NamedTextColor.RED))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with "+validType.name().toLowerCase().replace("_"," ")+" entities!", NamedTextColor.RED))); + return true; + } + return false; + } + + protected boolean isNotDisplay(Player player, ActivePart part){ + if (!part.isDisplay()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with display entities!", NamedTextColor.RED))); return true; } return false; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index f6dd3a41..429ddbd0 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -44,19 +44,21 @@ public enum Permission { PARTS_CREATE("deu.parts.create"), PARTS_CYCLE("deu.parts.cycle"), PARTS_GLOW("deu.parts.glow"), - PARTS_GLOW_COLOR("deu.parts.glow.set"), PARTS_SELECT("deu.parts.select"), PARTS_TAG("deu.parts.tag"), PARTS_LIST_TAGS("deu.parts.tag.list"), PARTS_REMOVE("deu.parts.remove"), - PARTS_TRANSLATE("deu.parts.translate"), PARTS_TRANSFORM("deu.parts.transform"), - PARTS_SET_BLOCK("deu.parts.setblock"), - PARTS_BILLBOARD("deu.parts.billboard"), - PARTS_BRIGHTNESS("deu.parts.brightness"), - PARTS_VIEWRANGE("deu.parts.viewrange"), + DISPLAY_SET_BLOCK("deu.parts.setblock"), + DISPLAY_GLOW_COLOR("deu.display.glowcolor"), + DISPLAY_TRANSLATE("deu.display.translate"), + DISPLAY_TRANSFORM("deu.display.transform"), + DISPLAY_BILLBOARD("deu.display.billboard"), + DISPLAY_BRIGHTNESS("deu.display.brightness"), + DISPLAY_VIEW_RANGE("deu.display.viewrange"), + TEXT_EDIT("deu.text.edit"), TEXT_SET_TEXT("deu.text.set"), TEXT_SET_FONT("deu.text.font"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBillboardCMD.java similarity index 83% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBillboardCMD.java index c743189d..cfa471ab 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBillboardCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -12,16 +12,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PartsBillboardCMD extends PartsSubCommand { - PartsBillboardCMD(@NotNull DEUSubCommand parentSubCommand) { - super("billboard", parentSubCommand, Permission.PARTS_BILLBOARD, 3, 3); +class DisplayBillboardCMD extends PartsSubCommand { + DisplayBillboardCMD(@NotNull DEUSubCommand parentSubCommand) { + super("billboard", parentSubCommand, Permission.DISPLAY_BILLBOARD, 3, 3); setTabComplete(2, TabSuggestion.BILLBOARDS); } @Override protected void sendIncorrectUsage(@NotNull Player player) { player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid billboard type!", NamedTextColor.RED))); - player.sendMessage(Component.text("/deu parts billboard [-all]", NamedTextColor.GRAY)); + player.sendMessage(Component.text("/deu display billboard [-all]", NamedTextColor.GRAY)); } @Override @@ -42,7 +42,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti Display.Billboard billboard = getBillboard(player, args[2]); if (billboard == null) return false; selectedPart.setBillboard(billboard); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard set for your selected part!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard set for your selected display!", NamedTextColor.GREEN))); } return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBrightnessCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBrightnessCMD.java similarity index 71% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBrightnessCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBrightnessCMD.java index ec2fa6d0..832d3bdf 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBrightnessCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBrightnessCMD.java @@ -1,10 +1,13 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.PartsSubCommand; import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.parts.PartsCMD; import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.donnypz.displayentityutils.utils.command.DEUCommandUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Display; @@ -12,33 +15,33 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PartsBrightnessCMD extends PartsSubCommand { - PartsBrightnessCMD(@NotNull DEUSubCommand parentSubCommand) { - super("brightness", parentSubCommand, Permission.PARTS_BRIGHTNESS, 4, 4); +class DisplayBrightnessCMD extends PartsSubCommand { + DisplayBrightnessCMD(@NotNull DEUSubCommand parentSubCommand) { + super("brightness", parentSubCommand, Permission.DISPLAY_BRIGHTNESS, 4, 4); setTabComplete(2, ""); setTabComplete(3, ""); } @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("/deu parts brightness [-all]", NamedTextColor.RED)); + player.sendMessage(Component.text("/deu display brightness [-all]", NamedTextColor.RED)); player.sendMessage(Component.text("| Brightness can be whole numbers between 0 and 15", NamedTextColor.GRAY)); player.sendMessage(Component.text("| Set both \"block\" and \"sky\" to -1 to reset brightness", NamedTextColor.GRAY)); } @Override protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { - BrightnessResult result = buildBrightness(player, args[2], args[3]); + BrightnessResult result = buildBrightness(args[2], args[3]); if (!result.correctNumbers()){ sendIncorrectUsage(player); return false; } Display.Brightness brightness = result.brightness; if (brightness == null){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness reset for part selection!", NamedTextColor.YELLOW))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness reset for displays in your selection!", NamedTextColor.YELLOW))); } else{ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness set for your part selection!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness set for displays in your selection!", NamedTextColor.GREEN))); } selection.setBrightness(brightness); return true; @@ -46,23 +49,24 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - BrightnessResult result = buildBrightness(player, args[2], args[3]); + if (isNotDisplay(player, selectedPart)) return false; + BrightnessResult result = buildBrightness(args[2], args[3]); if (!result.correctNumbers()){ sendIncorrectUsage(player); return false; } Display.Brightness brightness = result.brightness; if (brightness == null){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness reset for your selected part!", NamedTextColor.YELLOW))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness reset for your selected display!", NamedTextColor.YELLOW))); } else{ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness set for your selected part!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness set for your selected display!", NamedTextColor.GREEN))); } selectedPart.setBrightness(brightness); return true; } - private BrightnessResult buildBrightness(Player player, String arg1, String arg2){ + private BrightnessResult buildBrightness(String arg1, String arg2){ try{ int block = Integer.parseInt(arg1); int sky = Integer.parseInt(arg2); @@ -79,7 +83,6 @@ private BrightnessResult buildBrightness(Player player, String arg1, String arg2 } } catch(IllegalArgumentException e){ - sendIncorrectUsage(player); return new BrightnessResult(null, false); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java new file mode 100644 index 00000000..b5655c7e --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java @@ -0,0 +1,55 @@ +package net.donnypz.displayentityutils.command.display; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.command.CommandSender; + +public final class DisplayCMD extends ConsoleUsableSubCommand { + + + public DisplayCMD(){ + super(Permission.HELP, new DisplayHelpCMD()); + new DisplayGlowColorCMD(this); + new DisplayBrightnessCMD(this); + new DisplayViewRangeCMD(this); + new DisplayBillboardCMD(this); + new DisplayTranslateCMD(this); + new DisplayScaleCMD(this); + new DisplaySetBlockCMD(this); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 2){ + help(sender, 1); + return; + } + String arg = args[1]; + DEUSubCommand subCommand = subCommands.get(arg); + if (subCommand == null){ + help(sender, 1); + } + else{ + DisplayEntityPluginCommand.executeCommand(subCommand, sender, args); + } + } + + static void help(CommandSender sender, int page){ + sender.sendMessage(Component.empty()); + sender.sendMessage(DisplayAPI.pluginPrefixLong); + sender.sendMessage(Component.text("| Commands with \"-all\" will apply the command to all display entities in your selection", NamedTextColor.GOLD)); + + CMDUtils.sendCMD(sender, "/deu display glowcolor [-all]", "Set your selected display part's glow color"); + CMDUtils.sendCMD(sender, "/deu display brightness [-all]", "Set your selected display part's brightness. Enter values between 0-15. -1 resets"); + CMDUtils.sendCMD(sender, "/deu display viewrange [-all]", "Set the view range multiplier for your selected display part"); + CMDUtils.sendCMD(sender, "/deu display billboard [-all]", "Set the billboard of your selected display part"); + CMDUtils.sendCMD(sender, "/deu display translate [-all]", "Translate your selected display part"); + CMDUtils.sendCMD(sender, "/deu display scale [-all]", "Change the scale of your selected display part, by axis"); + CMDUtils.sendCMD(sender, "/deu display setblock <\"-held\" | \"-target\" | block-id> [-all]", "Change the block of a block display part"); + sender.sendMessage(MiniMessage.miniMessage().deserialize("--------------------------")); + //sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayGlowColorCMD.java similarity index 66% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayGlowColorCMD.java index 5cf30d45..1f3ba2cc 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayGlowColorCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -13,16 +13,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PartsGlowColorCMD extends PartsSubCommand { - PartsGlowColorCMD(@NotNull DEUSubCommand parentSubCommand) { - super("glowcolor", parentSubCommand, Permission.PARTS_GLOW_COLOR, 3, 3); +class DisplayGlowColorCMD extends PartsSubCommand { + DisplayGlowColorCMD(@NotNull DEUSubCommand parentSubCommand) { + super("glowcolor", parentSubCommand, Permission.DISPLAY_GLOW_COLOR, 3, 3); setTabComplete(2, TabSuggestion.COLORS); } @Override protected void sendIncorrectUsage(@NotNull Player player) { player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid color!", NamedTextColor.RED))); - player.sendMessage(Component.text("/deu parts glowcolor [-all]", NamedTextColor.GRAY)); + player.sendMessage(Component.text("/deu display glowcolor [-all]", NamedTextColor.GRAY)); } @Override @@ -37,25 +37,21 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isNotDisplay(player, selectedPart)) return false; + Color color = getColor(player, args[2]); if (color == null) return false; - if (!selectedPart.isDisplay()) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Only display entities can have a glow color applied!", NamedTextColor.RED))); - return false; - } - else{ - selectedPart.setGlowColor(color); - selectedPart.glow(player, 60); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color set for your selected part!", NamedTextColor.GREEN))); - return true; - } + selectedPart.setGlowColor(color); + selectedPart.glow(player, 60); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color set for your selected display!", NamedTextColor.GREEN))); + return true; } private Color getColor(Player player, String arg){ Color c = ConversionUtils.getColorFromText(arg); if (c == null){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid color!", NamedTextColor.RED))); - player.sendMessage(Component.text("/deu parts glowcolor [-all]", NamedTextColor.GRAY)); + player.sendMessage(Component.text("/deu display glowcolor [-all]", NamedTextColor.GRAY)); } return c; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayHelpCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayHelpCMD.java new file mode 100644 index 00000000..0d55f2df --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayHelpCMD.java @@ -0,0 +1,27 @@ +package net.donnypz.displayentityutils.command.display; + +import net.donnypz.displayentityutils.command.ConsoleUsableSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.item.ItemCMD; +import org.bukkit.command.CommandSender; + +public class DisplayHelpCMD extends ConsoleUsableSubCommand { + public DisplayHelpCMD() { + super(Permission.HELP); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 3){ + DisplayCMD.help(sender, 1); + } + else{ + try{ + DisplayCMD.help(sender, Integer.parseInt(args[2])); + } + catch(NumberFormatException e){ + DisplayCMD.help(sender, 1); + } + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayScaleCMD.java similarity index 82% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayScaleCMD.java index fba9ad99..08417eb0 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayScaleCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -13,9 +13,9 @@ import java.util.List; -class PartsScaleCMD extends PartsSubCommand { +class DisplayScaleCMD extends PartsSubCommand { - PartsScaleCMD(@NotNull DEUSubCommand parentSubCommand) { + DisplayScaleCMD(@NotNull DEUSubCommand parentSubCommand) { super("scale", parentSubCommand, Permission.PARTS_TRANSFORM, 4, 4); setTabComplete(2, List.of("x", "y", "z", "-all")); setTabComplete(3, ""); @@ -29,7 +29,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active } try { if (applyScaleChange(getDimension(args), getScale(args), selectedPart, player)) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Scale Updated!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Scale updated for selected display parts!", NamedTextColor.GREEN))); } } catch (NumberFormatException e) { player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid number for the scale!", NamedTextColor.RED))); @@ -41,14 +41,10 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (!selectedPart.isDisplay()) { - player.sendMessage(Component.text("You can only do this with a display entity!", NamedTextColor.RED)); - player.sendMessage(Component.text("| Use \"/deu interaction scale\" instead", NamedTextColor.GRAY)); - return false; - } + if (isNotDisplay(player, selectedPart)) return false; try { if (applyScaleChange(getDimension(args), getScale(args), selectedPart, player)) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Scale Updated!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Scale updated!", NamedTextColor.GREEN))); return true; } else{ @@ -62,7 +58,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("Incorrect Usage! /deu parts scale [-all]", NamedTextColor.RED)); + player.sendMessage(Component.text("Incorrect Usage! /deu display scale [-all]", NamedTextColor.RED)); } private String getDimension(String[] args){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSetBlockCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplaySetBlockCMD.java similarity index 78% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSetBlockCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplaySetBlockCMD.java index 790868d5..e5f486d3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSetBlockCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplaySetBlockCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -15,15 +15,15 @@ import java.util.List; -class PartsSetBlockCMD extends PartsSubCommand { - PartsSetBlockCMD(@NotNull DEUSubCommand parentSubCommand) { - super("setblock", parentSubCommand, Permission.PARTS_SET_BLOCK, 3, 3); +class DisplaySetBlockCMD extends PartsSubCommand { + DisplaySetBlockCMD(@NotNull DEUSubCommand parentSubCommand) { + super("setblock", parentSubCommand, Permission.DISPLAY_SET_BLOCK, 3, 3); setTabComplete(2, List.of("-held", "-target", "")); } @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("Incorrect Usage! /deu parts setblock <\"-held\" | \"-target\" | block-id> [-all]", NamedTextColor.RED)); + player.sendMessage(Component.text("Incorrect Usage! /deu display setblock <\"-held\" | \"-target\" | block-id> [-all]", NamedTextColor.RED)); } @Override @@ -42,12 +42,9 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY)) return false; BlockData blockData = DEUCommandUtils.getBlockFromText(args[2], player); if (blockData == null) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with block display entities", NamedTextColor.RED))); - return false; - } player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set block of selected block display!", NamedTextColor.GREEN))); setBlock(selectedPart, blockData); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsTranslateCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayTranslateCMD.java similarity index 86% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsTranslateCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayTranslateCMD.java index c348ae06..040e0c6d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsTranslateCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayTranslateCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -15,9 +15,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PartsTranslateCMD extends PartsSubCommand { - PartsTranslateCMD(@NotNull DEUSubCommand parentSubCommand) { - super("translate", parentSubCommand, Permission.PARTS_TRANSLATE, 5, 5); +class DisplayTranslateCMD extends PartsSubCommand { + DisplayTranslateCMD(@NotNull DEUSubCommand parentSubCommand) { + super("translate", parentSubCommand, Permission.DISPLAY_TRANSLATE, 5, 5); setTabComplete(2, TabSuggestion.DIRECTIONS); setTabComplete(3, ""); setTabComplete(4, ""); @@ -34,7 +34,7 @@ public void execute(Player player, String[] args) { @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("/deu parts translate [-all]", NamedTextColor.RED))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("/deu display translate [-all]", NamedTextColor.RED))); } @Override @@ -43,16 +43,17 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (objects == null) return false; selection.translate((Direction) objects[0], (float) objects[1], (int) objects[2], -1); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translating all selected parts!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translating all selected display parts!", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isNotDisplay(player, selectedPart)) return false; Object[] objects = getArgs(player, args); if (objects == null) return false; selectedPart.translate((Direction) objects[0], (float) objects[1], (int) objects[2], -1); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translating your selected part!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translating your selected display!", NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsViewRangeCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayViewRangeCMD.java similarity index 83% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsViewRangeCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayViewRangeCMD.java index ed8ec528..4419464d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsViewRangeCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayViewRangeCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -11,15 +11,15 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PartsViewRangeCMD extends PartsSubCommand { - PartsViewRangeCMD(@NotNull DEUSubCommand parentSubCommand) { - super("viewrange", parentSubCommand, Permission.PARTS_VIEWRANGE, 3, 3); +class DisplayViewRangeCMD extends PartsSubCommand { + DisplayViewRangeCMD(@NotNull DEUSubCommand parentSubCommand) { + super("viewrange", parentSubCommand, Permission.DISPLAY_VIEW_RANGE, 3, 3); setTabComplete(2, ""); } @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("Provide a part tag! /deu parts viewrange [-all]", NamedTextColor.RED)); + player.sendMessage(Component.text("Provide a part tag! /deu display viewrange [-all]", NamedTextColor.RED)); } @Override @@ -27,7 +27,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active Float viewRange = getViewRange(player, args[2]); if (viewRange == null) return false; selection.setViewRange(viewRange); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("View range multiplier updated for all selected parts!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("View range multiplier updated for all selected displays!", NamedTextColor.GREEN))); player.sendMessage(Component.text("New View Range: "+viewRange, NamedTextColor.GRAY)); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java index 7580258b..8b647229 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java @@ -20,7 +20,6 @@ public PartsCMD(){ new PartsCycleCMD(this); new PartsGlowCMD(this); new PartsUnglowCMD(this); - new PartsGlowColorCMD(this); new PartsFilterTagsCMD(this); new PartsFilterTypesCMD(this); new PartsFilterBlocksCMD(this); @@ -32,16 +31,10 @@ public PartsCMD(){ new PartsRemoveTagCMD(this); new PartsListTagsCMD(this); new PartsRemoveCMD(this); - new PartsTranslateCMD(this); - new PartsSetBlockCMD(this); - new PartsBillboardCMD(this); - new PartsViewRangeCMD(this); - new PartsBrightnessCMD(this); new PartsPitchCMD(this); new PartsYawCMD(this); new PartsMoveHereCMD(this); new PartsMoveCMD(this); - new PartsScaleCMD(this); } @Override @@ -64,9 +57,9 @@ static void partsHelp(CommandSender sender, int page){ sender.sendMessage(Component.empty()); sender.sendMessage(DisplayAPI.pluginPrefixLong); if (page <= 1){ - sender.sendMessage(Component.text("\"Parts\" are each individual display/interaction entity that is contained within a group", NamedTextColor.AQUA)); - sender.sendMessage(Component.text("| Add tags to parts to identify each part in a group", NamedTextColor.AQUA)); - sender.sendMessage(Component.text("| \"-all\" will apply the command to all parts within your part selection where valid. By default a selected group's parts is your part selection", NamedTextColor.GOLD)); + sender.sendMessage(Component.text("- \"Parts\" are each entity in a group/model", NamedTextColor.AQUA)); + sender.sendMessage(Component.text("- Add tags to parts to identify each part in a group", NamedTextColor.AQUA)); + sender.sendMessage(Component.text("- \"-all\" will apply a command to all parts in your selection/filter where valid. By default, all of your selected group's parts are your in selection", NamedTextColor.GOLD)); sender.sendMessage(Component.empty()); CMDUtils.sendCMD(sender, "/deu parts help ", "Get help for parts"); CMDUtils.sendCMD(sender, "/deu parts info", "Get information about your current part/selection"); @@ -93,20 +86,11 @@ else if (page == 3){ CMDUtils.sendCMD(sender, "/deu parts glow [-all]", "Make your selected part glow"); CMDUtils.sendCMD(sender, "/deu parts unglow [-all]", "Remove the glow from your selected part"); } - else if (page == 4){ - CMDUtils.sendCMD(sender, "/deu parts glowcolor [-all]", "Set your selected part's glow color"); - CMDUtils.sendCMD(sender, "/deu parts brightness [-all]", "Set your selected part's brightness. Enter values between 0-15. -1 resets"); - CMDUtils.sendCMD(sender, "/deu parts viewrange [-all]", "Set the view range multiplier for your selected part"); - CMDUtils.sendCMD(sender, "/deu parts billboard [-all]", "Set the billboard of your selected part"); - CMDUtils.sendCMD(sender, "/deu parts translate [-all]", "Translate your selected part"); + else{ CMDUtils.sendCMD(sender, "/deu parts pitch ", "Set the pitch of an ungrouped part entity"); CMDUtils.sendCMD(sender, "/deu parts yaw ", "Set the yaw of an ungrouped part entity"); - } - else{ - CMDUtils.sendCMD(sender, "/deu parts scale [-all]", "Change the scale of your selected part, by axis"); CMDUtils.sendCMD(sender, "/deu parts move [-all]", "Change the actual location of your selected part"); CMDUtils.sendCMD(sender, "/deu parts movehere [-all]", "Change your selected part's actual location to your location"); - CMDUtils.sendCMD(sender, "/deu parts setblock <\"-held\" | \"-target\" | block-id> [-all]", "Change the block of a block display part"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java index 419d48e4..329f571f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java @@ -71,7 +71,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { if (selectedPart.isDisplay() && group != null){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot do this for grouped display entities!", NamedTextColor.RED))); - player.sendMessage(Component.text("| Use \"/deu parts translate\" instead", NamedTextColor.GRAY)); + player.sendMessage(Component.text("| Use \"/deu display translate\" instead", NamedTextColor.GRAY)); return false; } try{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java index f08c26a5..55a25878 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java @@ -48,7 +48,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { if (selectedPart.isDisplay() && group != null){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot do this for grouped display entities!", NamedTextColor.RED))); - player.sendMessage(Component.text("| Use \"/deu parts translate\" instead", NamedTextColor.GRAY)); + player.sendMessage(Component.text("| Use \"/deu display translate\" instead", NamedTextColor.GRAY)); return false; } From f8b1f320ddef730f18b7824bff600e380a7abb15 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 22 Dec 2025 01:34:45 -0600 Subject: [PATCH 049/139] add ActivePart#setMannequinName and name attributes --- .../utils/DisplayEntities/ActivePart.java | 2 ++ .../utils/DisplayEntities/PacketDisplayEntityPart.java | 6 ++++++ .../utils/DisplayEntities/SpawnedDisplayEntityPart.java | 8 ++++++++ .../utils/packet/attributes/DisplayAttributes.java | 3 ++- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 88e1855f..acd36da3 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -533,6 +533,8 @@ public void unglow(@NotNull Player player) { public abstract void setMannequinProfile(@NotNull ResolvableProfile profile); + public abstract void setMannequinName(@Nullable Component text); + public abstract void setMannequinBelowName(@Nullable Component text); public abstract void setMannequinPose(Pose pose); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index e27676ef..1655008f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -618,6 +618,12 @@ public void setMannequinProfile(@NotNull ResolvableProfile profile) { setAndSend(DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, profile); } + @Override + public void setMannequinName(@Nullable Component text) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.CUSTOM_NAME, text); + } + @Override public void setMannequinBelowName(@Nullable Component text) { if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 0412b871..bba6f4c6 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -1051,6 +1051,14 @@ public void setMannequinProfile(@NotNull ResolvableProfile profile) { mannequin.setProfile(profile); } + @Override + public void setMannequinName(@Nullable Component text) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.customName(text); + } + @Override public void setMannequinBelowName(@Nullable Component text) { if (type != PartType.MANNEQUIN) return; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java index 6e7d6ea8..8ffcf685 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java @@ -10,6 +10,8 @@ public final class DisplayAttributes { public static final GlowingDisplayAttribute GLOWING = new GlowingDisplayAttribute(0); + public static final OptionalComponentDisplayAttribute CUSTOM_NAME = new OptionalComponentDisplayAttribute(2); + public static final BasicDisplayAttribute CUSTOM_NAME_VISIBLE = new BasicDisplayAttribute<>(3, Boolean.class, EntityDataTypes.BOOLEAN); public static final class Interpolation { public static final BasicDisplayAttribute DELAY = new BasicDisplayAttribute<>(8, Integer.class, EntityDataTypes.INT); @@ -41,7 +43,6 @@ public static final class Culling{ public static final BasicDisplayAttribute HEIGHT = new BasicDisplayAttribute<>(21, Float.class, EntityDataTypes.FLOAT); } - public static final ColorDisplayAttribute GLOW_COLOR_OVERRIDE = new ColorDisplayAttribute(22); public static final class BlockDisplay{ From 16cd32ff55b5b552af93f6f45f17687161c5f367 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 22 Dec 2025 02:08:05 -0600 Subject: [PATCH 050/139] Add custom name methods, rename #setMannequinName to #setCustomName --- .../utils/DisplayEntities/ActivePart.java | 11 +++++-- .../PacketDisplayEntityPart.java | 18 +++++++++-- .../SpawnedDisplayEntityPart.java | 30 +++++++++++++++---- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index acd36da3..1ab5b600 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -505,6 +505,15 @@ public void unglow(@NotNull Player player) { */ public abstract @Nullable Vector getNonDisplayTranslation(); + + public abstract void setCustomName(@Nullable Component text); + + public abstract void setCustomNameVisible(boolean visible); + + public abstract @Nullable Component getCustomName(); + + public abstract boolean isCustomNameVisible(); + public abstract void setInteractionHeight(float height); public abstract void setInteractionWidth(float width); @@ -533,8 +542,6 @@ public void unglow(@NotNull Player player) { public abstract void setMannequinProfile(@NotNull ResolvableProfile profile); - public abstract void setMannequinName(@Nullable Component text); - public abstract void setMannequinBelowName(@Nullable Component text); public abstract void setMannequinPose(Pose pose); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 1655008f..0e80d11b 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -619,11 +619,25 @@ public void setMannequinProfile(@NotNull ResolvableProfile profile) { } @Override - public void setMannequinName(@Nullable Component text) { - if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + public void setCustomName(@Nullable Component text) { setAndSend(DisplayAttributes.CUSTOM_NAME, text); } + @Override + public void setCustomNameVisible(boolean visible) { + setAndSend(DisplayAttributes.CUSTOM_NAME_VISIBLE, visible); + } + + @Override + public @Nullable Component getCustomName() { + return attributeContainer.getAttribute(DisplayAttributes.CUSTOM_NAME); + } + + @Override + public boolean isCustomNameVisible(){ + return attributeContainer.getAttributeOrDefault(DisplayAttributes.CUSTOM_NAME_VISIBLE, false); + } + @Override public void setMannequinBelowName(@Nullable Component text) { if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index bba6f4c6..b95e0ed9 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -1052,11 +1052,31 @@ public void setMannequinProfile(@NotNull ResolvableProfile profile) { } @Override - public void setMannequinName(@Nullable Component text) { - if (type != PartType.MANNEQUIN) return; - Mannequin mannequin = (Mannequin) getEntity(); - if (mannequin == null) return; - mannequin.customName(text); + public void setCustomName(@Nullable Component text) { + Entity e = getEntity(); + if (e == null) return; + e.customName(text); + } + + @Override + public void setCustomNameVisible(boolean visible) { + Entity e = getEntity(); + if (e == null) return; + e.setCustomNameVisible(visible); + } + + @Override + public @Nullable Component getCustomName() { + Entity e = getEntity(); + if (e == null) return null; + return e.customName(); + } + + @Override + public boolean isCustomNameVisible() { + Entity e = getEntity(); + if (e == null) return false; + return e.isCustomNameVisible(); } @Override From 4bd596e58c891333cb85537dec35b0194589f2c7 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 22 Dec 2025 02:37:42 -0600 Subject: [PATCH 051/139] add profile related commands for mannequins --- .../command/Permission.java | 3 + .../mannequin/MannequinBelowNameCMD.java | 40 +++++++++++ .../command/mannequin/MannequinCMD.java | 17 +++-- .../command/mannequin/MannequinNameCMD.java | 40 +++++++++++ .../command/mannequin/MannequinSkinCMD.java | 47 +++++++++++++ .../MannequinToggleNameVisibilityCMD.java | 68 +++++++++++++++++++ .../command/text/TextSetCMD.java | 4 +- 7 files changed, 212 insertions(+), 7 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinBelowNameCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinNameCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSkinCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleNameVisibilityCMD.java diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index 429ddbd0..19af6448 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -83,6 +83,9 @@ public enum Permission { INTERACTION_SPAWN("deu.interaction.spawn"), INTERACTION_INFO("deu.interaction.info"), + MANNEQUIN_SKIN("deu.mannequin.skin"), + MANNEQUIN_NAME("deu.mannequin.name"), + MANNEQUIN_NAME_VISIBLE("deu.mannequin.namevisible"), MANNEQUIN_POSE("deu.mannequin.pose"), MANNEQUIN_SCALE("deu.mannequin.scale"), MANNEQUIN_GRAVITY("deu.mannequin.gravity"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinBelowNameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinBelowNameCMD.java new file mode 100644 index 00000000..6cd35b9e --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinBelowNameCMD.java @@ -0,0 +1,40 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.text.TextSetCMD; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinBelowNameCMD extends PartsSubCommand { + MannequinBelowNameCMD(@NotNull DEUSubCommand parentSubCommand) { + super("belowname", parentSubCommand, Permission.MANNEQUIN_NAME, 3, 0); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin belowname ", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + return false; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String name = TextSetCMD.getTextResult(args); + selectedPart.setMannequinBelowName(LegacyComponentSerializer.legacyAmpersand().deserialize(name)); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set text below mannequin name!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java index ea948c52..38e8c482 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -10,6 +10,10 @@ public class MannequinCMD extends ConsoleUsableSubCommand { public MannequinCMD() { super(Permission.HELP, new MannequinHelpCMD()); + new MannequinNameCMD(this); + new MannequinBelowNameCMD(this); + new MannequinToggleNameVisibilityCMD(this); + new MannequinSkinCMD(this); new MannequinPoseCMD(this); new MannequinScaleCMD(this); new MannequinToggleGravityCMD(this); @@ -40,19 +44,22 @@ static void help(CommandSender sender, int page){ if (page == 1){ sender.sendMessage(Component.text("| Commands with \"-all\" will apply the command to all mannequins within a part selection", NamedTextColor.GOLD)); CMDUtils.sendCMD(sender, "/deu mannequin help", "Get help for mannequins"); - CMDUtils.sendCMD(sender, "/deu mannequin pose [-all]", "Change your selected mannequin's pose"); - CMDUtils.sendCMD(sender, "/deu mannequin scale [-all]", "Set your selected mannequin's scale"); + CMDUtils.sendCMD(sender, "/deu mannequin name ", "Set your selected mannequin's name"); + CMDUtils.sendCMD(sender, "/deu mannequin belowname ", "Set the text below your selected mannequin's name"); + CMDUtils.sendCMD(sender, "/deu mannequin togglenamevisibility [-all ]", "Toggle the gravity of an mannequin"); + CMDUtils.sendCMD(sender, "/deu mannequin skin [-all]", "Set your selected mannequin's skin"); CMDUtils.sendCMD(sender, "/deu mannequin togglegravity [-all ]", "Toggle the gravity of an mannequin"); CMDUtils.sendCMD(sender, "/deu mannequin toggleimmovable [-all ]", "Toggle the immovability of an mannequin"); - CMDUtils.sendCMD(sender, "/deu mannequin mainhand ", "Set the mannequin's main hand"); - CMDUtils.sendCMD(sender, "/deu mannequin helditem
<\"-held\" | item-id>", "Set the item in a mannequin's main or offhand"); } else{ + CMDUtils.sendCMD(sender, "/deu mannequin mainhand ", "Set the mannequin's main hand"); + CMDUtils.sendCMD(sender, "/deu mannequin helditem
<\"-held\" | item-id>", "Set the item in a mannequin's main or offhand"); CMDUtils.sendCMD(sender, "/deu mannequin armor [-stop]", "Set the armor of a mannequin by clicking it with armor pieces. \"-stop\" stops editing"); + CMDUtils.sendCMD(sender, "/deu mannequin pose [-all]", "Change your selected mannequin's pose"); + CMDUtils.sendCMD(sender, "/deu mannequin scale [-all]", "Set your selected mannequin's scale"); CMDUtils.sendCMD(sender, "/deu mannequin clone", "Clone a mannequin"); CMDUtils.sendCMD(sender, "/deu mannequin clonehere", "Clone a mannequin at your current location"); } - sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinNameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinNameCMD.java new file mode 100644 index 00000000..faf726f5 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinNameCMD.java @@ -0,0 +1,40 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.text.TextSetCMD; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinNameCMD extends PartsSubCommand { + MannequinNameCMD(@NotNull DEUSubCommand parentSubCommand) { + super("name", parentSubCommand, Permission.MANNEQUIN_NAME, 3, 0); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin name ", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + return false; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String name = TextSetCMD.getTextResult(args); + selectedPart.setCustomName(LegacyComponentSerializer.legacyAmpersand().deserialize(name)); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set mannequin name!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSkinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSkinCMD.java new file mode 100644 index 00000000..2d737990 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSkinCMD.java @@ -0,0 +1,47 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinSkinCMD extends PartsSubCommand { + MannequinSkinCMD(@NotNull DEUSubCommand parentSubCommand) { + super("skin", parentSubCommand, Permission.MANNEQUIN_SKIN, 3, 3); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin skin [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + String name = args[2]; + ResolvableProfile profile = ResolvableProfile.resolvableProfile(Bukkit.createProfile(name)); + for (ActivePart p : selection.getSelectedParts()){ + p.setMannequinProfile(profile); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set skin of ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String name = args[2]; + ResolvableProfile profile = ResolvableProfile.resolvableProfile(Bukkit.createProfile(name)); + selectedPart.setMannequinProfile(profile); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set mannequin skin!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleNameVisibilityCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleNameVisibilityCMD.java new file mode 100644 index 00000000..20eaf419 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleNameVisibilityCMD.java @@ -0,0 +1,68 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +class MannequinToggleNameVisibilityCMD extends PartsSubCommand { + MannequinToggleNameVisibilityCMD(@NotNull DEUSubCommand parentSubCommand) { + super("togglenamevisibility", parentSubCommand, Permission.MANNEQUIN_NAME_VISIBLE, 2, 2); + setTabComplete(3, List.of("on", "off")); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu mannequin togglenamevisibility [-all ]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + if (args.length < 4){ + sendIncorrectUsage(player); + return false; + } + + boolean status; + String s = args[3]; + if (s.equalsIgnoreCase("on")){ + status = true; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled name visibility for ALL selected mannequins ON"))); + } + else if (s.equalsIgnoreCase("off")){ + status = false; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled name visibility for ALL selected mannequins OFF"))); + } + else{ + sendIncorrectUsage(player); + return false; + } + + for (ActivePart part : selection.getSelectedParts()){ + if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) { + part.setCustomNameVisible(status); + } + } + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + selectedPart.setCustomNameVisible(!selectedPart.isCustomNameVisible()); + String status = selectedPart.isCustomNameVisible() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled name visibility of selected mannequin "+status))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java index ca048003..613b2928 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java @@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class TextSetCMD extends PartsSubCommand { +public class TextSetCMD extends PartsSubCommand { public TextSetCMD(@NotNull DEUSubCommand parentSubCommand) { super("set", parentSubCommand, Permission.TEXT_SET_TEXT, 3, 0); @@ -45,7 +45,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti return true; } - static String getTextResult(String[] args){ + public static String getTextResult(String[] args){ StringBuilder builder = new StringBuilder(); for (int i = 2; i < args.length; i++){ builder.append(args[i]); From 8e036e9b311c6658ce5550971836a695335b48a3 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 22 Dec 2025 18:06:48 -0600 Subject: [PATCH 052/139] Update Mannequin SCALE Attribute to accept a double instead of float --- .../utils/DisplayEntities/PacketDisplayEntityPart.java | 2 +- .../utils/packet/attributes/AttributeDisplayAttribute.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 0e80d11b..a99e50e3 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -556,7 +556,7 @@ public void setMannequinPose(Pose pose) { @Override public void setMannequinScale(double scale) { if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; - setAndSend(DisplayAttributes.Mannequin.SCALE, (float) scale); + setAndSend(DisplayAttributes.Mannequin.SCALE, scale); } @Override diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java index f7766982..94e7e3c7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java @@ -3,11 +3,11 @@ import com.github.retrooper.packetevents.protocol.attribute.Attribute; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -public class AttributeDisplayAttribute extends DisplayAttribute{ +public class AttributeDisplayAttribute extends DisplayAttribute{ Attribute attribute; protected AttributeDisplayAttribute(Attribute attribute) { - super(0, Float.class, EntityDataTypes.FLOAT); + super(0, Double.class, EntityDataTypes.FLOAT); this.attribute = attribute; setAttributeType(AttributeType.ATTRIBUTE); } @@ -17,7 +17,7 @@ public Attribute getAttribute() { } @Override - public Float getOutputValue(Float value) { + public Double getOutputValue(Double value) { return value; } } From b38fb61a2911442380d7268f1239507d5319e686 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 22 Dec 2025 20:20:28 -0600 Subject: [PATCH 053/139] Fix part uuid not applying to newly created packet-based interaction entities --- .../DisplayEntities/InteractionEntity.java | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java index 203e577c..7b17e74d 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java @@ -39,7 +39,7 @@ final class InteractionEntity implements Serializable { this.width = interaction.getInteractionWidth(); this.isResponsive = interaction.isResponsive(); this.vector = DisplayUtils.getNonDisplayTranslation(interaction).toVector3f(); - this.partUUID = DisplayUtils.getPartUUID(interaction); + this.partUUID = DisplayUtils.getPartUUID(interaction); //for json file try{ persistentDataContainer = interaction.getPersistentDataContainer().serializeToBytes(); @@ -56,12 +56,13 @@ final class InteractionEntity implements Serializable { this.width = c.getAttributeOrDefault(DisplayAttributes.Interaction.WIDTH, 1f); this.isResponsive = c.getAttributeOrDefault(DisplayAttributes.Interaction.RESPONSIVE, false); this.vector = part.getNonDisplayTranslation().toVector3f(); - this.partUUID = part.partUUID; + this.partUUID = part.partUUID; //for json file try{ ItemStack i = new ItemStack(Material.STICK); PersistentDataContainer pdc = i.getItemMeta().getPersistentDataContainer(); pdc.set(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings(), new ArrayList<>(part.getTags())); + pdc.set(DisplayAPI.getPartUUIDKey(), PersistentDataType.STRING, part.partUUID.toString()); persistentDataContainer = pdc.serializeToBytes(); } catch(IOException e){ @@ -92,7 +93,11 @@ Interaction createEntity(Location origin, GroupSpawnSettings settings){ } if (partUUID != null){ - i.getPersistentDataContainer().set(DisplayAPI.getPartUUIDKey(), PersistentDataType.STRING, partUUID.toString()); + i + .getPersistentDataContainer() + .set(DisplayAPI.getPartUUIDKey(), + PersistentDataType.STRING, + partUUID.toString()); } settings.apply(i); @@ -123,7 +128,7 @@ PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings set } part.partTags = DisplayEntity.getSetFromPDC(pdc, DisplayAPI.getPartPDCTagKey()); - part.partUUID = DisplayEntity.getPDCPartUUID(pdc); + part.partUUID = partUUID != null ? partUUID : DisplayEntity.getPDCPartUUID(pdc); part.interactionCommands = getInteractionCommands(pdc); } settings.applyAttributes(part); @@ -147,20 +152,4 @@ Vector getVector(){ boolean hasLegacyPartTags(){ return partTags != null && !partTags.isEmpty(); } - - ArrayList getLegacyPartTags() { - return partTags; - } - - float getHeight() { - return height; - } - - float getWidth() { - return width; - } - - boolean isReponsive(){ - return isResponsive; - } } From b2a0bf5c9513ee64beed18fc92628b50b6bf4ab4 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:29:58 -0600 Subject: [PATCH 054/139] Add mannequin equipment attributes. remove ActivePart#setMannequinHandItem --- .../utils/DisplayEntities/ActivePart.java | 5 ++- .../PacketDisplayEntityPart.java | 16 ++++--- .../SpawnedDisplayEntityPart.java | 19 +++++---- .../packet/PacketAttributeContainer.java | 6 ++- .../packet/attributes/DisplayAttributes.java | 42 +++++++++++++++++++ .../packet/attributes/EquipmentAttribute.java | 2 +- .../command/mannequin/MannequinCMD.java | 5 +++ .../mannequin/MannequinHeldItemCMD.java | 5 ++- 8 files changed, 81 insertions(+), 19 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 1ab5b600..76ee3809 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -17,6 +17,7 @@ import org.bukkit.Location; import org.bukkit.block.data.BlockData; import org.bukkit.entity.*; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.MainHand; import org.bukkit.util.Transformation; @@ -554,7 +555,7 @@ public void unglow(@NotNull Player player) { public abstract void setMannequinMainHand(@NotNull MainHand mainHand); - public abstract void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand); + public abstract void setMannequinEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack); public abstract ResolvableProfile getMannequinProfile(); @@ -570,6 +571,8 @@ public void unglow(@NotNull Player player) { public abstract @Nullable MainHand getMannequinMainHand(); + public abstract @NotNull ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot); + /** * Adds a command to this part to execute when clicked, if its type is {@link SpawnedDisplayEntityPart.PartType#INTERACTION} * @param command The command to assign diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index a99e50e3..24b23859 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -19,12 +19,10 @@ import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import net.donnypz.displayentityutils.utils.packet.attributes.TextDisplayOptions; import net.kyori.adventure.text.Component; -import org.bukkit.Bukkit; -import org.bukkit.Color; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; +import org.bukkit.*; import org.bukkit.block.data.BlockData; import org.bukkit.entity.*; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.MainHand; import org.bukkit.util.Transformation; @@ -602,9 +600,15 @@ public void setMannequinMainHand(@NotNull MainHand mainHand) { } @Override - public void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand) { + public @NotNull ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return ItemStack.of(Material.AIR); + return attributeContainer.getAttribute(DisplayAttributes.Equipment.getAttribute(equipmentSlot)); + } + + @Override + public void setMannequinEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) { if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; - //TODO + setAndSend(DisplayAttributes.Equipment.getAttribute(slot), itemStack); } @Override diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index b95e0ed9..8b32067e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -16,6 +16,7 @@ import org.bukkit.attribute.Attribute; import org.bukkit.block.data.BlockData; import org.bukkit.entity.*; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.MainHand; import org.bukkit.persistence.PersistentDataContainer; @@ -1026,16 +1027,20 @@ public void setMannequinMainHand(@NotNull MainHand mainHand) { } @Override - public void setMannequinHandItem(@NotNull ItemStack itemStack, boolean mainHand) { + public @NotNull ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot) { + if (type != PartType.MANNEQUIN) return null; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return null; + return mannequin.getEquipment().getItem(equipmentSlot); + } + + + @Override + public void setMannequinEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) { if (type != PartType.MANNEQUIN) return; Mannequin mannequin = (Mannequin) getEntity(); if (mannequin == null) return; - if (mainHand){ - mannequin.getEquipment().setItemInMainHand(itemStack, true); - } - else{ - mannequin.getEquipment().setItemInOffHand(itemStack, true); - } + mannequin.getEquipment().setItem(slot, itemStack); } @Override diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java index f6eb1595..d16796cb 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java @@ -5,7 +5,6 @@ import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; -import com.github.retrooper.packetevents.protocol.item.ItemStack; import com.github.retrooper.packetevents.protocol.player.Equipment; import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment; @@ -20,10 +19,12 @@ import net.donnypz.displayentityutils.utils.packet.attributes.AttributeDisplayAttribute; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; +import net.donnypz.displayentityutils.utils.packet.attributes.EquipmentAttribute; import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.bukkit.util.Transformation; import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; @@ -536,7 +537,8 @@ EntityData createEntityData(DisplayAttribute attribute, Object value){ } Equipment createEquipmentData(DisplayAttribute attribute, Object value){ - return new Equipment(EquipmentSlot.values()[attribute.getIndex()], (ItemStack) value); + return new Equipment(EquipmentSlot.values()[attribute.getIndex()], + ((EquipmentAttribute) attribute).getOutputValue((ItemStack) value)); } WrapperPlayServerUpdateAttributes.Property createAttributeData(DisplayAttribute attribute, Object value){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java index 8ffcf685..1e288714 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java @@ -2,7 +2,9 @@ import com.github.retrooper.packetevents.protocol.attribute.Attributes; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; /** * A class containing all {@link DisplayAttribute}s that apply to eligible part type entities @@ -13,6 +15,46 @@ public final class DisplayAttributes { public static final OptionalComponentDisplayAttribute CUSTOM_NAME = new OptionalComponentDisplayAttribute(2); public static final BasicDisplayAttribute CUSTOM_NAME_VISIBLE = new BasicDisplayAttribute<>(3, Boolean.class, EntityDataTypes.BOOLEAN); + + public static final class Equipment{ + public static final EquipmentAttribute HELMET = new EquipmentAttribute(EquipmentSlot.HELMET); + public static final EquipmentAttribute CHESTPLATE = new EquipmentAttribute(EquipmentSlot.CHEST_PLATE); + public static final EquipmentAttribute LEGGINGS = new EquipmentAttribute(EquipmentSlot.LEGGINGS); + public static final EquipmentAttribute BOOTS = new EquipmentAttribute(EquipmentSlot.BOOTS); + public static final EquipmentAttribute MAIN_HAND = new EquipmentAttribute(EquipmentSlot.MAIN_HAND); + public static final EquipmentAttribute OFF_HAND = new EquipmentAttribute(EquipmentSlot.OFF_HAND); + public static final EquipmentAttribute BODY = new EquipmentAttribute(EquipmentSlot.BODY); + + public static EquipmentAttribute getAttribute(@NotNull org.bukkit.inventory.EquipmentSlot slot){ + switch (slot){ + case HEAD -> { + return HELMET; + } + case CHEST -> { + return CHESTPLATE; + } + case LEGS -> { + return LEGGINGS; + } + case FEET -> { + return BOOTS; + } + case BODY -> { + return BODY; + } + case HAND -> { + return MAIN_HAND; + } + case OFF_HAND -> { + return OFF_HAND; + } + default -> { + throw new IllegalArgumentException("Invalid/Unexpected slot type"); + } + } + } + } + public static final class Interpolation { public static final BasicDisplayAttribute DELAY = new BasicDisplayAttribute<>(8, Integer.class, EntityDataTypes.INT); public static final BasicDisplayAttribute DURATION = new BasicDisplayAttribute<>(9, Integer.class, EntityDataTypes.INT); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java index e19c6025..53429bb3 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java @@ -1,8 +1,8 @@ package net.donnypz.displayentityutils.utils.packet.attributes; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; import io.github.retrooper.packetevents.util.SpigotConversionUtil; -import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; public class EquipmentAttribute extends DisplayAttribute{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java index 38e8c482..2eb3e3ad 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -2,6 +2,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.*; +import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; @@ -34,6 +35,10 @@ public void execute(CommandSender sender, String[] args) { help(sender, 1); } else{ + if (VersionUtils.IS_1_21_9){ + sender.sendMessage(Component.text("Your server version does not support Mannequin entities!", NamedTextColor.RED)); + return; + } DisplayEntityPluginCommand.executeCommand(subCommand, sender, args); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java index 5f2b1947..34de0333 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java @@ -9,6 +9,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,7 +49,7 @@ else if (hand.equalsIgnoreCase("off") || hand.equalsIgnoreCase("offhand")) { for (ActivePart part : selection.getSelectedParts()){ if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) { - part.setMannequinHandItem(itemStack, isMainHand); + part.setMannequinEquipment(isMainHand ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND, itemStack); } } player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set "+hand.toLowerCase()+" hand item of ALL selected mannequins!", NamedTextColor.GREEN))); @@ -75,7 +76,7 @@ else if (hand.equalsIgnoreCase("off") || hand.equalsIgnoreCase("offhand")) { ItemStack itemStack = DEUCommandUtils.getItemFromText(item, player); if (itemStack == null) return false; - selectedPart.setMannequinHandItem(itemStack, isMainHand); + selectedPart.setMannequinEquipment(isMainHand ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND, itemStack); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set "+hand.toLowerCase()+" hand item of selected mannequin!", NamedTextColor.GREEN))); return true; } From fae493f3a92ebc51fb3225d2492de7821ca32d0c Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:30:42 -0600 Subject: [PATCH 055/139] make position of packet-based group more accurate when riding an entity --- .../utils/DisplayEntities/PacketDisplayEntityGroup.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index da8aaa73..845c4cfc 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -160,7 +160,7 @@ void updateChunkAndWorld(@NotNull Location location){ Location oldLoc = getLocation(); //Remove from previous if (oldLoc != null){ - if (location.getWorld().equals(oldLoc.getWorld()) && location.getChunk().getChunkKey() == oldLoc.getChunk().getChunkKey()){ + if (location.getWorld().equals(oldLoc.getWorld()) && location.getChunk().getChunkKey() == oldLoc.getChunk().getChunkKey() && vehicleUUID == null){ return; } String oldWorldName = oldLoc.getWorld().getName(); @@ -403,7 +403,7 @@ public void run() { } updateChunkAndWorld(entity.getLocation()); } - }, 0, 30); + }, 0, 20); } return true; } From d0df5ba3d80516f1c9ad24da35f3b6e5b263545b Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:31:14 -0600 Subject: [PATCH 056/139] Display mannequin's custom name when cycling parts --- .../displayentityutils/command/parts/PartsCycleCMD.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java index 959d4cfc..86445e04 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java @@ -129,10 +129,9 @@ else if (part.getBlockDisplayBlock().getMaterial() == Material.AIR){ } } case MANNEQUIN -> { - ResolvableProfile profile = part.getMannequinProfile(); - String name = profile.name(); - if (name == null) name = "Unnamed Mannequin"; - desc = Component.text("("+name+")"); + Component customName = part.getCustomName(); + if (customName == null) customName = Component.text("Unnamed Mannequin"); + desc = Component.text("(").append(customName).append(Component.text(")")); } default -> throw new IllegalStateException("Unexpected part type"); } From 34540acca5f631bf05972347f0db6800965a9e14 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 02:55:00 -0600 Subject: [PATCH 057/139] Implement saving/loading of mannequin entities in display groups --- .../DisplayEntities/DisplayEntityGroup.java | 113 ++++++---------- .../DisplayEntities/GroupSpawnSettings.java | 39 ++++-- .../DisplayEntities/MannequinEntity.java | 125 ++++++++++++++++++ .../DisplayEntities/SavedEntityBuilder.java | 122 +++++++++++++++++ .../DisplayEntities/SavedEntityLoader.java | 58 ++++++++ 5 files changed, 371 insertions(+), 86 deletions(-) create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java index 9d9fecdd..3c8a304b 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java @@ -5,10 +5,9 @@ import net.donnypz.displayentityutils.events.PreGroupSpawnedEvent; import net.donnypz.displayentityutils.events.PrePacketGroupCreateEvent; import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.version.VersionUtils; import org.bukkit.Location; import org.bukkit.entity.*; -import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,8 +19,9 @@ public final class DisplayEntityGroup implements Serializable{ private final ArrayList displayEntities = new ArrayList<>(); private final ArrayList interactionEntities = new ArrayList<>(); + private final ArrayList mannequinEntities = new ArrayList<>(); DisplayEntity masterEntity; - private String tag; + private final String tag; private Boolean isPersistent = true; @Serial @@ -35,9 +35,11 @@ public final class DisplayEntityGroup implements Serializable{ this.masterEntity = addDisplayEntity(spawnedMasterEntity).setMaster(); for (SpawnedDisplayEntityPart part : spawnedGroup.getParts()){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - Interaction i = (Interaction) part.getEntity(); - addInteractionEntity(i); + if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + addInteractionEntity((Interaction) part.getEntity()); + } + else if (VersionUtils.IS_1_21_9 && part.type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + addMannequinEntity(part.getEntity()); } else{ if (!part.isMaster()){ @@ -55,10 +57,12 @@ public final class DisplayEntityGroup implements Serializable{ this.masterEntity = addDisplayEntity(packetGroup.masterPart, packetGroup).setMaster(); for (PacketDisplayEntityPart part : packetGroup.getParts()){ - - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ addInteractionEntity(part); } + else if (VersionUtils.IS_1_21_9 && part.type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + addMannequinEntity(part); + } else{ if (!part.isMaster()){ addDisplayEntity(part, packetGroup); @@ -105,81 +109,34 @@ private DisplayEntity addDisplayEntity(PacketDisplayEntityPart part, PacketDispl return display; } - private InteractionEntity addInteractionEntity(Interaction entity){ - InteractionEntity interaction = new InteractionEntity(entity); - interactionEntities.add(interaction); - return interaction; + private void addInteractionEntity(Interaction entity){ + interactionEntities.add(new InteractionEntity(entity)); } - private InteractionEntity addInteractionEntity(PacketDisplayEntityPart part){ - InteractionEntity interaction = new InteractionEntity(part); - interactionEntities.add(interaction); - return interaction; + private void addInteractionEntity(PacketDisplayEntityPart part){ + interactionEntities.add(new InteractionEntity(part)); } - - /** - * Get the DisplayEntities in this group - * @return DisplayEntity List containing the ones in this group - */ - List getDisplayEntities() { - return new ArrayList<>(displayEntities); + private void addMannequinEntity(Entity entity){ + mannequinEntities.add(SavedEntityBuilder.buildMannequin(entity)); } - /** - * Get the DisplayEntities in this group of the specified type - * @return DisplayEntity List containing the ones in this group with the specified type - */ - List getDisplayEntities(DisplayEntity.Type type){ - ArrayList displayEntities = new ArrayList<>(); - for (DisplayEntity entity : this.displayEntities){ - if (entity.getType() == type){ - displayEntities.add(entity); - } - } - return displayEntities; - } - - /** - * Get the InteractionEntities in this group - * @return InteractionEntity List containing the ones in this group - */ - List getInteractionEntities() { - return new ArrayList<>(interactionEntities); - } - - /** - * Get whether this DisplayEntityGroup has display entities - * @return boolean of whether the group has display entities - */ - public boolean hasDisplayEntities(){ - return !displayEntities.isEmpty(); + private void addMannequinEntity(PacketDisplayEntityPart part){ + mannequinEntities.add(SavedEntityBuilder.buildMannequin(part)); } - /** - * Get whether this DisplayEntityGroup has display entities of the specified type - * @return boolean of whether the group has display entities of the specified type - */ - public boolean hasDisplayEntities(DisplayEntity.Type type){ - for (DisplayEntity entity : displayEntities){ - if (entity.getType() == type){ - return true; - } - } - return false; - } /** - * Get whether this DisplayEntityGroup has interaction entities - * @return boolean of whether the group has interaction entities + * Get whether this group has interaction entities + * @return a boolean */ public boolean hasInteractionEntities(){ return !interactionEntities.isEmpty(); } /** - * Get the tag of this Display Entity Group - * @return This DisplayEntityGroup's Tag + * Get this group's tag + * @return a string */ public String getTag() { return tag; @@ -199,7 +156,7 @@ public String getTag() { * Spawns this {@link DisplayEntityGroup} at a specified location returning a {@link SpawnedDisplayEntityGroup} that represents this. * @param location The location to spawn the group * @param spawnReason The reason for this display entity group to spawn - * @param settings The settings to apply to every display and interaction entity created from this. This may be overridden with the {@link PreGroupSpawnedEvent}. + * @param settings The settings to apply when spawning this group. This may be overridden with the {@link PreGroupSpawnedEvent}. * @return A {@link SpawnedDisplayEntityGroup} representative of this. Null if the {@link PreGroupSpawnedEvent} is cancelled */ public @Nullable SpawnedDisplayEntityGroup spawn(@NotNull Location location, @NotNull GroupSpawnedEvent.SpawnReason spawnReason, @NotNull GroupSpawnSettings settings){ @@ -242,6 +199,13 @@ public String getTag() { } } + if (mannequinEntities != null){ + for (MannequinEntity entity : mannequinEntities){ + Entity e = SavedEntityLoader.spawnMannequin(masterDisplay.getLocation(), settings, entity); + group.addEntity(e); + } + } + group.setPersistenceOverride(settings.persistenceOverride); if (tag != null){ @@ -261,9 +225,6 @@ public String getTag() { return group; } - - - /** * Spawns this {@link DisplayEntityGroup} at a specified location returning a {@link PacketDisplayEntityGroup} that represents this. * @param spawnLocation The location where this group spawn be spawned for players @@ -314,7 +275,7 @@ public String getTag() { * @param spawnLocation The location where this group spawn be spawned for players * @param spawnReason The reason for this display entity group to spawn * @param playSpawnAnimation whether this packet group should automatically play its spawn animation when created - * @param settings The settings to apply to every display and interaction entity created from this. This may be overridden with the {@link PrePacketGroupCreateEvent}.
The persistence of the settings is ignored for packet-based groups + * @param settings The settings to apply when spawning this group. This may be overridden with the {@link PrePacketGroupCreateEvent}.
The persistence of the settings is ignored for packet-based groups * @return A {@link PacketDisplayEntityGroup} representative of this. Null if the {@link PrePacketGroupCreateEvent} is cancelled */ public @Nullable PacketDisplayEntityGroup createPacketGroup(@NotNull Location spawnLocation, @NotNull GroupSpawnedEvent.SpawnReason spawnReason, boolean playSpawnAnimation, @NotNull GroupSpawnSettings settings){ @@ -351,6 +312,14 @@ public String getTag() { packetGroup.addPartSilent(part); } + if (mannequinEntities != null){ + for (MannequinEntity entity : mannequinEntities){ + PacketDisplayEntityPart part = entity.createPacketPart(spawnLocation, settings); + packetGroup.addPartSilent(part); + } + } + + if (playSpawnAnimation){ packetGroup.playSpawnAnimation(); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java index 4a19d055..6080f22e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java @@ -7,10 +7,7 @@ import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.entity.Display; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -285,21 +282,35 @@ void apply(Interaction interaction){ interaction.setPersistent(persistentByDefault); } - private void determineVisibleByDefault(Display display){ - for (String tag : hiddenPartTags.keySet()){ - if (DisplayUtils.hasPartTag(display, tag)){ - display.setVisibleByDefault(false); - reveal(display, tag); - break; + void apply(Mannequin mannequin){ + //Determine Visibility + if (!visibleByDefault){ + mannequin.setVisibleByDefault(false); + if (!visiblePlayers.isEmpty()){ //Reveal for players + for (UUID uuid : visiblePlayers){ + Player player = Bukkit.getPlayer(uuid); + if (player != null && player.isOnline()){ + player.showEntity(DisplayAPI.getPlugin(), mannequin); + } + } + } + } + else{ + if (hiddenPartTags.isEmpty()){ + mannequin.setVisibleByDefault(true); + } + else{ + determineVisibleByDefault(mannequin); } } } - private void determineVisibleByDefault(Interaction interaction){ + + private void determineVisibleByDefault(Entity entity){ for (String tag : hiddenPartTags.keySet()){ - if (DisplayUtils.hasPartTag(interaction, tag)){ - interaction.setVisibleByDefault(false); - reveal(interaction, tag); + if (DisplayUtils.hasPartTag(entity, tag)){ + entity.setVisibleByDefault(false); + reveal(entity, tag); break; } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java new file mode 100644 index 00000000..b7166537 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java @@ -0,0 +1,125 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; +import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Pose; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MainHand; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.util.Vector; +import org.joml.Vector3f; + +import java.io.IOException; +import java.io.Serial; +import java.io.Serializable; +import java.util.UUID; + + +//DTO +final class MannequinEntity implements Serializable { + @Serial + private static final long serialVersionUID = 99L; + + Vector3f vector; + String customName; + boolean customNameVisible; + String description; + String profileName; + UUID profileUUID; + double scale; + String pose; + boolean isRightMainHand; + byte[] mainHandItemStack; + byte[] offHandItemStack; + byte[][] armorItemStacks; //0,1,2,3 = helm,chest,legs,boots, x bytes for itemstack + byte[] persistentDataContainer = null; + + + MannequinEntity(){} + + PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings settings){ + PacketAttributeContainer attributeContainer = new PacketAttributeContainer() + .setAttribute(DisplayAttributes.Mannequin.IMMOVABLE, true) + .setAttribute(DisplayAttributes.Mannequin.NO_GRAVITY, true) + .setAttribute(DisplayAttributes.CUSTOM_NAME, customName != null ? MiniMessage.miniMessage().deserialize(customName): null) + .setAttribute(DisplayAttributes.CUSTOM_NAME_VISIBLE, customNameVisible) + .setAttribute(DisplayAttributes.Mannequin.BELOW_NAME, description != null ? MiniMessage.miniMessage().deserialize(description): null) + .setAttribute(DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, ResolvableProfile.resolvableProfile() + .name(profileName) + .uuid(profileUUID) + .build()) + .setAttribute(DisplayAttributes.Mannequin.POSE, Pose.valueOf(pose)) + .setAttribute(DisplayAttributes.Mannequin.MAIN_HAND, isRightMainHand ? MainHand.RIGHT : MainHand.LEFT) + .setAttribute(DisplayAttributes.Equipment.HELMET, getHelmet()) + .setAttribute(DisplayAttributes.Equipment.CHESTPLATE, getChestplate()) + .setAttribute(DisplayAttributes.Equipment.LEGGINGS, getLeggings()) + .setAttribute(DisplayAttributes.Equipment.BOOTS, getBoots()) + .setAttribute(DisplayAttributes.Equipment.MAIN_HAND, getMainHand()) + .setAttribute(DisplayAttributes.Equipment.OFF_HAND, getOffHand()); + + //TODO ARMOR AND ITEMS + + Location spawnLoc = DisplayUtils.getPivotLocation( + vector, + origin, + origin.getYaw()); + + PacketDisplayEntityPart part = attributeContainer.createPart(SpawnedDisplayEntityPart.PartType.MANNEQUIN, spawnLoc); + + if (persistentDataContainer != null){ + ItemStack i = new ItemStack(Material.STICK); + PersistentDataContainer pdc = i.getItemMeta().getPersistentDataContainer(); + + try { + pdc.readFromBytes(persistentDataContainer); + } catch (IOException e) { + throw new RuntimeException(e); + } + + part.partTags = DisplayEntity.getSetFromPDC(pdc, DisplayAPI.getPartPDCTagKey()); + part.partUUID = DisplayEntity.getPDCPartUUID(pdc); + } + settings.applyAttributes(part); + + return part; + } + + ItemStack getMainHand(){ + return getItemStack(mainHandItemStack); + } + + ItemStack getOffHand(){ + return getItemStack(offHandItemStack); + } + + ItemStack getHelmet(){ + return getItemStack(armorItemStacks[0]); + } + + ItemStack getChestplate(){ + return getItemStack(armorItemStacks[1]); + } + + ItemStack getLeggings(){ + return getItemStack(armorItemStacks[2]); + } + + ItemStack getBoots(){ + return getItemStack(armorItemStacks[3]); + } + + Vector getVector(){ + return Vector.fromJOML(vector); + } + + ItemStack getItemStack(byte[] itemStack){ + if (itemStack == null) return ItemStack.of(Material.AIR); + return ItemStack.deserializeBytes(itemStack); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java new file mode 100644 index 00000000..b953a962 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java @@ -0,0 +1,122 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; +import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Pose; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MainHand; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +import java.io.IOException; +import java.util.ArrayList; + +class SavedEntityBuilder { + + static MannequinEntity buildMannequin(Entity entity){ //Accept entity instead of mannequin, preventing issues on versions below 1.21.9 + MannequinEntity mannequinEntity = new MannequinEntity(); + org.bukkit.entity.Mannequin mannequin = (org.bukkit.entity.Mannequin) entity; + + Component customName = mannequin.customName(); + mannequinEntity.customName = customName != null ? MiniMessage.miniMessage().serialize(customName) : null; + mannequinEntity.customNameVisible = mannequin.isCustomNameVisible(); + + Component description = mannequin.getDescription(); + mannequinEntity.description = description != null ? MiniMessage.miniMessage().serialize(description) : null; + + ResolvableProfile profile = mannequin.getProfile(); + if (profile != null){ + mannequinEntity.profileName = profile.name(); + mannequinEntity.profileUUID = profile.uuid(); + } + + mannequinEntity.scale = mannequin.getAttribute(Attribute.SCALE).getBaseValue(); + mannequinEntity.pose = mannequin.getPose().name(); + + mannequinEntity.isRightMainHand = mannequin.getMainHand() == MainHand.RIGHT; + EntityEquipment equipment = mannequin.getEquipment(); + mannequinEntity.mainHandItemStack = serializeItemStack(equipment.getItemInMainHand()); + mannequinEntity.offHandItemStack = serializeItemStack(equipment.getItemInOffHand()); + mannequinEntity.armorItemStacks = new byte[][]{ + serializeItemStack(equipment.getHelmet()), + serializeItemStack(equipment.getChestplate()), + serializeItemStack(equipment.getLeggings()), + serializeItemStack(equipment.getBoots()) + }; + + mannequinEntity.vector = DisplayUtils.getNonDisplayTranslation(mannequin).toVector3f(); + + try{ + mannequinEntity.persistentDataContainer = mannequin.getPersistentDataContainer().serializeToBytes(); + } + catch(IOException e){ + e.printStackTrace(); + } + return mannequinEntity; + } + + static MannequinEntity buildMannequin(PacketDisplayEntityPart part){ + MannequinEntity mannequinEntity = new MannequinEntity(); + PacketAttributeContainer c = part.attributeContainer; + + Component customName = part.getCustomName(); + mannequinEntity.customName = customName != null ? MiniMessage.miniMessage().serialize(customName) : null; + mannequinEntity.customNameVisible = part.isCustomNameVisible(); + + Component description = part.getMannequinBelowName(); + mannequinEntity.description = description != null ? MiniMessage.miniMessage().serialize(description) : null; + + ResolvableProfile profile = part.getMannequinProfile(); + if (profile != null){ + mannequinEntity.profileName = profile.name(); + mannequinEntity.profileUUID = profile.uuid(); + } + + mannequinEntity.scale = c.getAttributeOrDefault(DisplayAttributes.Mannequin.SCALE, 1.0); + Pose pose = part.getMannequinPose(); + if (pose == null){ + pose = Pose.STANDING; + } + mannequinEntity.pose = pose.name(); + + mannequinEntity.isRightMainHand = part.getMannequinMainHand() == MainHand.RIGHT; + mannequinEntity.mainHandItemStack = serializeItemStack(part.getMannequinEquipment(EquipmentSlot.HAND)); + mannequinEntity.offHandItemStack = serializeItemStack(part.getMannequinEquipment(EquipmentSlot.OFF_HAND)); + mannequinEntity.armorItemStacks = new byte[][]{ + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.HEAD)), + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.CHEST)), + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.LEGS)), + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.FEET)) + }; + + + mannequinEntity.vector = part.getNonDisplayTranslation().toVector3f(); + + try{ + ItemStack i = new ItemStack(Material.STICK); + PersistentDataContainer pdc = i.getItemMeta().getPersistentDataContainer(); + pdc.set(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings(), new ArrayList<>(part.getTags())); + pdc.set(DisplayAPI.getPartUUIDKey(), PersistentDataType.STRING, part.partUUID.toString()); + mannequinEntity.persistentDataContainer = pdc.serializeToBytes(); + } + catch(IOException e){ + e.printStackTrace(); + } + return mannequinEntity; + } + + static byte[] serializeItemStack(ItemStack itemStack){ + if (itemStack == null || itemStack.isEmpty()) return null; + return itemStack.serializeAsBytes(); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java new file mode 100644 index 00000000..e66937bf --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java @@ -0,0 +1,58 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Location; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Mannequin; +import org.bukkit.entity.Pose; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.MainHand; + +import java.io.IOException; + +class SavedEntityLoader { + + static Mannequin spawnMannequin(Location origin, GroupSpawnSettings settings, MannequinEntity mannequinEntity){ + Location spawnLoc = DisplayUtils.getPivotLocation( + mannequinEntity.vector, + origin, + origin.getYaw()); + + return spawnLoc.getWorld().spawn(spawnLoc, org.bukkit.entity.Mannequin.class, m ->{ + m.setInvulnerable(true); + m.setImmovable(true); + m.setGravity(false); + + m.customName(mannequinEntity.customName != null ? MiniMessage.miniMessage().deserialize(mannequinEntity.customName): null); + m.setDescription(mannequinEntity.description != null ? MiniMessage.miniMessage().deserialize(mannequinEntity.description) : null); + + m.setProfile(ResolvableProfile.resolvableProfile() + .name(mannequinEntity.profileName) + .uuid(mannequinEntity.profileUUID) + .build()); + m.getAttribute(Attribute.SCALE).setBaseValue(mannequinEntity.scale); + m.setPose(Pose.valueOf(mannequinEntity.pose)); + + m.setMainHand(mannequinEntity.isRightMainHand ? MainHand.RIGHT : MainHand.LEFT); + + EntityEquipment equipment = m.getEquipment(); + equipment.setItemInMainHand(mannequinEntity.getMainHand()); + equipment.setItemInOffHand(mannequinEntity.getOffHand()); + equipment.setHelmet(mannequinEntity.getHelmet()); + equipment.setHelmet(mannequinEntity.getChestplate()); + equipment.setHelmet(mannequinEntity.getLeggings()); + equipment.setHelmet(mannequinEntity.getBoots()); + + if (mannequinEntity.persistentDataContainer != null){ + try{ + m.getPersistentDataContainer().readFromBytes(mannequinEntity.persistentDataContainer); + } + catch(IOException ignore){} + } + + settings.apply(m); + }); + } +} From c16dc6f87804f906c6aa581a932eafc4a38efea1 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 02:55:15 -0600 Subject: [PATCH 058/139] invert condition --- .../displayentityutils/command/mannequin/MannequinCMD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java index 2eb3e3ad..56366de7 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -35,7 +35,7 @@ public void execute(CommandSender sender, String[] args) { help(sender, 1); } else{ - if (VersionUtils.IS_1_21_9){ + if (!VersionUtils.IS_1_21_9){ sender.sendMessage(Component.text("Your server version does not support Mannequin entities!", NamedTextColor.RED)); return; } From 655fef3a8f77f4f6f47ac9a132b316f4a7629b16 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 03:41:58 -0600 Subject: [PATCH 059/139] Always prevent mannequin movement when it is included in a group --- .../utils/DisplayEntities/SavedEntityLoader.java | 4 +--- .../DisplayEntities/SpawnedDisplayEntityPart.java | 15 ++++----------- .../displayentityutils/utils/DisplayUtils.java | 12 ++++++++---- .../mannequin/MannequinToggleGravityCMD.java | 9 +++++++++ .../mannequin/MannequinToggleImmovableCMD.java | 12 +++++++++++- .../command/parts/PartsCreateCMD.java | 3 ++- 6 files changed, 35 insertions(+), 20 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java index e66937bf..12222b2b 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java @@ -21,9 +21,7 @@ static Mannequin spawnMannequin(Location origin, GroupSpawnSettings settings, Ma origin.getYaw()); return spawnLoc.getWorld().spawn(spawnLoc, org.bukkit.entity.Mannequin.class, m ->{ - m.setInvulnerable(true); - m.setImmovable(true); - m.setGravity(false); + DisplayUtils.prepareMannequin(m); m.customName(mannequinEntity.customName != null ? MiniMessage.miniMessage().deserialize(mannequinEntity.customName): null); m.setDescription(mannequinEntity.description != null ? MiniMessage.miniMessage().deserialize(mannequinEntity.description) : null); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 8b32067e..d0967f46 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -50,23 +50,16 @@ public final class SpawnedDisplayEntityPart extends ActivePart implements Spawne if (isMaster()){ group.masterPart = this; } + if (VersionUtils.IS_1_21_9 && entity instanceof Mannequin m){ + DisplayUtils.prepareMannequin(m); + } partTags.addAll(DisplayUtils.getTags(entity)); isSingle = false; } SpawnedDisplayEntityPart(Entity entity){ super(entity.getEntityId(), false); - switch (entity) { - case BlockDisplay blockDisplay -> this.type = PartType.BLOCK_DISPLAY; - case ItemDisplay itemDisplay -> this.type = PartType.ITEM_DISPLAY; - case TextDisplay textDisplay -> this.type = PartType.TEXT_DISPLAY; - case Interaction interaction -> this.type = PartType.INTERACTION; - case Shulker shulker -> this.type = PartType.SHULKER; - case Mannequin mannequin -> this.type = PartType.MANNEQUIN; - default -> { - throw new IllegalArgumentException("The provided entity is not a valid part entity!"); - } - } + this.type = PartType.getType(entity); this.entity = entity; this.entityUUID = entity.getUniqueId(); isSingle = true; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java index ab40d895..aa79e3d0 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java @@ -9,10 +9,7 @@ import net.donnypz.displayentityutils.utils.version.folia.Scheduler; import org.bukkit.Location; import org.bukkit.NamespacedKey; -import org.bukkit.entity.BlockDisplay; -import org.bukkit.entity.Display; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; +import org.bukkit.entity.*; import org.bukkit.persistence.ListPersistentDataType; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -965,5 +962,12 @@ public static boolean isMaster(Display display){ return container.has(DisplayAPI.getMasterKey(), PersistentDataType.BOOLEAN); } + @ApiStatus.Internal + public static void prepareMannequin(Mannequin mannequin){ + mannequin.setInvulnerable(true); + mannequin.setImmovable(true); + mannequin.setGravity(false); + } + } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java index 671679d4..dc607863 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java @@ -32,6 +32,11 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active return false; } + if (group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot change the gravity of mannequins in a group!", NamedTextColor.RED))); + return false; + } + boolean status; String s = args[3]; if (s.equalsIgnoreCase("on")){ @@ -60,6 +65,10 @@ else if (s.equalsIgnoreCase("off")){ @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + if (group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot change the gravity of a mannequin in a group!", NamedTextColor.RED))); + return false; + } selectedPart.setMannequinGravity(!selectedPart.hasMannequinGravity()); String status = selectedPart.hasMannequinGravity() ? "ON" : "OFF"; player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled gravity of selected mannequin "+status))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java index edd01f5a..ea1039da 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java @@ -32,6 +32,11 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active return false; } + if (group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot change the immovability of mannequins in a group!", NamedTextColor.RED))); + return false; + } + boolean status; String s = args[3]; if (s.equalsIgnoreCase("on")){ @@ -59,7 +64,12 @@ else if (s.equalsIgnoreCase("off")){ @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN); + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + + if (group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot change the immovability of a mannequin in a group!", NamedTextColor.RED))); + return false; + } selectedPart.setMannequinImmovable(!selectedPart.isMannequinImmovable()); String status = selectedPart.isMannequinImmovable() ? "ON" : "OFF"; player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled immovability of selected mannequin "+status))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java index 9ef1b8a4..4118f727 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java @@ -8,6 +8,7 @@ import net.donnypz.displayentityutils.managers.DEUUser; import net.donnypz.displayentityutils.utils.DisplayEntities.SinglePartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.DisplayUtils; import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.donnypz.displayentityutils.utils.dialogs.TextDisplayDialog; import net.kyori.adventure.text.Component; @@ -85,7 +86,7 @@ public void execute(Player player, String[] args) { } Mannequin entity = loc.getWorld().spawn(loc, Mannequin.class, m -> { m.setProfile(ResolvableProfile.resolvableProfile(player.getPlayerProfile())); - m.setInvulnerable(true); + DisplayUtils.prepareMannequin(m); }); selectEntity(player, entity.getUniqueId(), "Mannequin"); } From 61269350a06c237d8f36a858de718088732ea983 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 07:05:28 -0600 Subject: [PATCH 060/139] use PartsSubCommand#isInvalidType instead of manually check part validity --- .../displayentityutils/command/item/ItemSetCMD.java | 5 +---- .../command/item/ItemToggleGlintCMD.java | 6 ++---- .../displayentityutils/command/item/ItemTransformCMD.java | 5 +---- .../displayentityutils/command/text/TextAddLineCMD.java | 6 ++---- .../displayentityutils/command/text/TextAlignCMD.java | 6 ++---- .../command/text/TextBackgroundCMD.java | 5 +---- .../displayentityutils/command/text/TextEditCMD.java | 8 +------- .../displayentityutils/command/text/TextFontCMD.java | 6 ++---- .../displayentityutils/command/text/TextLineWidthCMD.java | 7 +++---- .../displayentityutils/command/text/TextOpacityCMD.java | 6 ++---- .../command/text/TextSeeThroughCMD.java | 6 ++---- .../displayentityutils/command/text/TextSetCMD.java | 6 ++---- .../displayentityutils/command/text/TextShadowCMD.java | 5 +---- 13 files changed, 22 insertions(+), 55 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java index d7e491a6..b1764b45 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java @@ -43,14 +43,11 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY)) return false; String item = args[2]; ItemStack itemStack = DEUCommandUtils.getItemFromText(item, player); if (itemStack == null) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with item display entities", NamedTextColor.RED))); - return false; - } selectedPart.setItemDisplayItem(itemStack); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set item of selected item display!", NamedTextColor.GREEN))); return true; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java index 804c9cad..515ab49d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java @@ -60,10 +60,8 @@ else if (s.equalsIgnoreCase("off")){ @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with item display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY)) return false; + ItemStack item = selectedPart.getItemDisplayItem(); if (item == null) return false; selectedPart.setItemDisplayItemGlint(!selectedPart.hasItemDisplayItemGlint()); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java index 5be796eb..4f27f463 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java @@ -36,12 +36,9 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY)) return false; ItemDisplay.ItemDisplayTransform transform = getTransform(player, args[2]); if (transform == null) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with item display entities", NamedTextColor.RED))); - return false; - } selectedPart.setItemDisplayTransform(transform); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set item transform of selected item display!", NamedTextColor.GREEN))); return true; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java index c3bcfcd8..0ea370e5 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java @@ -32,10 +32,8 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + Component currentText = selectedPart.getTextDisplayText(); Key font = currentText.font(); Component comp = currentText.appendNewline().append(LegacyComponentSerializer.legacyAmpersand().deserialize(TextSetCMD.getTextResult(args))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java index dfbfb704..3c99dcf8 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java @@ -39,10 +39,8 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + TextDisplay.TextAlignment alignment = getAlignment(args[2], player); if (alignment == null) return false; selectedPart.setTextDisplayAlignment(alignment); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java index c146fbe4..963ff92c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java @@ -40,12 +40,9 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; Color color = getColor(args, player); if (color == null) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } selectedPart.setTextDisplayBackgroundColor(color); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set text display's background color", NamedTextColor.GREEN))); return true; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextEditCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextEditCMD.java index 890927a1..3963c522 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextEditCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextEditCMD.java @@ -1,14 +1,11 @@ package net.donnypz.displayentityutils.command.text; -import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.PartsSubCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.donnypz.displayentityutils.utils.dialogs.TextDisplayDialog; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -29,10 +26,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; boolean legacy = args.length >= 3 && args[2].equals("-&"); if (VersionUtils.canViewDialogs(player, true)){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java index 2828f5ab..23c2e3fa 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java @@ -39,10 +39,8 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + Key font = getFont(args, player); if (font == null) return false; selectedPart.setTextDisplayText(selectedPart.getTextDisplayText().font(font)); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java index 5a58fb1c..2c16a3cb 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java @@ -37,12 +37,11 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + int width = getLineWidth(args, player); if (width == -1) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + selectedPart.setTextDisplayLineWidth(width); player.sendMessage(Component.text("Set text display's line width to "+width, NamedTextColor.GREEN)); return true; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java index 660e095d..ba0f69cd 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java @@ -38,12 +38,10 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + Byte opacity = getOpacity(args, player); if (opacity == null) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } selectedPart.setTextDisplayTextOpacity(opacity); player.sendMessage(DisplayAPI.pluginPrefix .append(Component.text("Set text display's opacity to "+opacity, NamedTextColor.GREEN))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java index 39ab457b..55979f4f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java @@ -59,10 +59,8 @@ else if (s.equalsIgnoreCase("off")){ @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + selectedPart.setTextDisplaySeeThrough(!selectedPart.isTextDisplaySeeThrough()); String status = selectedPart.isTextDisplaySeeThrough() ? "ON" : "OFF"; player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled see through for your selected text display "+status))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java index 613b2928..d98ee98b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java @@ -32,10 +32,8 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + Component currentText = selectedPart.getTextDisplayText(); Key font = currentText.font(); Component comp = LegacyComponentSerializer.legacyAmpersand().deserialize(getTextResult(args)); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java index ff96ffa3..465fa01b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java @@ -60,10 +60,7 @@ else if (s.equalsIgnoreCase("off")){ @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; selectedPart.setTextDisplayShadowed(!selectedPart.isTextDisplayShadowed()); String status = selectedPart.isTextDisplayShadowed() ? "ON" : "OFF"; From 6dc19e055d321a6e82db94bb92448943bada9203 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 17:47:35 -0600 Subject: [PATCH 061/139] manually set item meta instead of using ItemStack#editMeta --- .../DisplayEntities/PacketDisplayEntityPart.java | 7 ++++--- .../DisplayEntities/SpawnedDisplayEntityPart.java | 11 ++++++----- .../utils/bdengine/convert/file/BDEItemDisplay.java | 10 +++++----- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 24b23859..adf70d87 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -25,6 +25,7 @@ import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.MainHand; +import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.util.Transformation; import org.bukkit.util.Vector; import org.jetbrains.annotations.ApiStatus; @@ -435,9 +436,9 @@ public void setItemDisplayItemGlint(boolean hasGlint) { if (type != SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY) return; ItemStack item = getItemDisplayItem(); if (item != null){ - item.editMeta(meta -> { - meta.setEnchantmentGlintOverride(hasGlint); - }); + ItemMeta meta = item.getItemMeta(); + meta.setEnchantmentGlintOverride(hasGlint); + item.setItemMeta(meta); setAndSend(DisplayAttributes.ItemDisplay.ITEMSTACK, item); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index d0967f46..21fbcdba 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -19,6 +19,7 @@ import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.MainHand; +import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.bukkit.util.Transformation; @@ -261,8 +262,8 @@ PartData getPartData() { /** * Get the {@link SpawnedDisplayEntityPart} of an entity, during this play session. Use {@link #create(Entity)} if the part is not grouped. - * @param entity the part entity (Display/Interaction) - * @return The SpawnedDisplayEntityPart. Null if not created during play session or not associated with any group + * @param entity the part entity + * @return a {@link SpawnedDisplayEntityPart} or null if not created during play session */ public static @Nullable SpawnedDisplayEntityPart getPart(@NotNull Entity entity){ if (!DisplayUtils.isPartEntity(entity)) return null; @@ -845,9 +846,9 @@ public void setItemDisplayTransform(ItemDisplay.@NotNull ItemDisplayTransform tr public void setItemDisplayItemGlint(boolean hasGlint) { ItemStack itemStack = getItemDisplayItem(); if (itemStack == null) return; - itemStack.editMeta(meta -> { - meta.setEnchantmentGlintOverride(hasGlint); - }); + ItemMeta meta = itemStack.getItemMeta(); + meta.setEnchantmentGlintOverride(hasGlint); + itemStack.setItemMeta(meta); ((ItemDisplay) getEntity()).setItemStack(itemStack); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/file/BDEItemDisplay.java b/api/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/file/BDEItemDisplay.java index 1eb24bd8..30bf14d5 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/file/BDEItemDisplay.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/file/BDEItemDisplay.java @@ -40,11 +40,11 @@ void apply(ItemDisplay display) { //For Player Heads if (playerHeadTexture != null && !playerHeadTexture.isBlank()){ - item.editMeta(SkullMeta.class, meta -> { - PlayerProfile profile = Bukkit.createProfile(UUID.randomUUID()); - profile.setProperty(new ProfileProperty("textures", playerHeadTexture)); - meta.setPlayerProfile(profile); - }); + SkullMeta meta = (SkullMeta) item.getItemMeta(); + PlayerProfile profile = Bukkit.createProfile(UUID.randomUUID()); + profile.setProperty(new ProfileProperty("textures", playerHeadTexture)); + meta.setPlayerProfile(profile); + item.setItemMeta(meta); } display.setItemStack(item); } From a9e90f9022b82d6b0ce94b3a634417c2990fc983 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 19:42:50 -0600 Subject: [PATCH 062/139] Add a GUI to edit mannequin equipment, remove "helditem" cmd --- .../displayentityutils/managers/DEUUser.java | 16 ++ .../utils/DisplayEntities/ActivePart.java | 13 ++ .../DisplayEntityPlugin.java | 2 + .../command/mannequin/MannequinCMD.java | 5 +- .../mannequin/MannequinEquipmentCMD.java | 36 ++++ .../mannequin/MannequinHeldItemCMD.java | 83 -------- .../mannequin/ui/MannequinEquipmentGUI.java | 191 ++++++++++++++++++ .../entity/DEUMannequinEditorListener.java | 90 +++++++++ 8 files changed, 350 insertions(+), 86 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinEquipmentCMD.java delete mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/ui/MannequinEquipmentGUI.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java index 006670ad..c56571d6 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java @@ -36,6 +36,7 @@ public class DEUUser { private AnimationParticleBuilder particleBuilder; private final Location[] pointPositions = new Location[3]; private final Set trackedPacketEntities = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private Integer armorEditMannequinEntityId; private PreAnimationCameraData preAnimationCameraData; private final Object animationCameraLock = new Object(); @@ -86,6 +87,21 @@ public boolean unsuppressIfEqual(int entityId, @NotNull Vector3f vector3f) { return false; } + @ApiStatus.Internal + public boolean isEditingMannequinArmor(){ + return armorEditMannequinEntityId != null; + } + + @ApiStatus.Internal + public int getEditingMannequin(){ + return armorEditMannequinEntityId; + } + + @ApiStatus.Internal + public void setEditingMannequinArmor(Integer armorEditMannequinEntityId){ + this.armorEditMannequinEntityId = armorEditMannequinEntityId; + } + /** * Set the selected {@link ActiveGroup} of a user * @param activeGroup the group diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 76ee3809..23adb643 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -44,6 +44,9 @@ protected ActivePart(int entityId, boolean mapped){ if (mapped) { partsById.put(entityId, this); } + else{ + partUUID = UUID.randomUUID(); + } } protected synchronized void unregister(){ @@ -543,6 +546,16 @@ public void unglow(@NotNull Player player) { public abstract void setMannequinProfile(@NotNull ResolvableProfile profile); + public void setMannequinProfile(@NotNull PlayerProfile profile, Player player){ + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setMannequinProfile(ResolvableProfile.resolvableProfile(profile), player); + } + + public void setMannequinProfile(@NotNull ResolvableProfile profile, Player player){ + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + PacketUtils.setAttribute(player, entityId, DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, profile); + } + public abstract void setMannequinBelowName(@Nullable Component text); public abstract void setMannequinPose(Pose pose); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index 9bda1190..e215cf7f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -10,6 +10,7 @@ import net.donnypz.displayentityutils.listeners.bdengine.DatapackEntitySpawned; import net.donnypz.displayentityutils.listeners.entity.DEUEntityListener; import net.donnypz.displayentityutils.listeners.entity.DEUInteractionListener; +import net.donnypz.displayentityutils.listeners.entity.DEUMannequinEditorListener; import net.donnypz.displayentityutils.listeners.entity.mythic.DEUMythicListener; import net.donnypz.displayentityutils.listeners.player.*; import net.donnypz.displayentityutils.managers.LocalManager; @@ -135,6 +136,7 @@ private void registerListeners(){ Bukkit.getPluginManager().registerEvents(new DEULoadingListeners(), this); Bukkit.getPluginManager().registerEvents(new DEUInteractionListener(), this); Bukkit.getPluginManager().registerEvents(new DEUPlayerPlaceBlockListener(), this); + Bukkit.getPluginManager().registerEvents(new DEUMannequinEditorListener(), this); } private void initializeBStats(){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java index 56366de7..fcc0f382 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -20,7 +20,7 @@ public MannequinCMD() { new MannequinToggleGravityCMD(this); new MannequinToggleImmovableCMD(this); new MannequinMainHandCMD(this); - new MannequinHeldItemCMD(this); + new MannequinEquipmentCMD(this); } @Override @@ -58,8 +58,7 @@ static void help(CommandSender sender, int page){ } else{ CMDUtils.sendCMD(sender, "/deu mannequin mainhand ", "Set the mannequin's main hand"); - CMDUtils.sendCMD(sender, "/deu mannequin helditem
<\"-held\" | item-id>", "Set the item in a mannequin's main or offhand"); - CMDUtils.sendCMD(sender, "/deu mannequin armor [-stop]", "Set the armor of a mannequin by clicking it with armor pieces. \"-stop\" stops editing"); + CMDUtils.sendCMD(sender, "/deu mannequin equipment ", "Open a GUI to edit your selected mannequin's equipment."); CMDUtils.sendCMD(sender, "/deu mannequin pose [-all]", "Change your selected mannequin's pose"); CMDUtils.sendCMD(sender, "/deu mannequin scale [-all]", "Set your selected mannequin's scale"); CMDUtils.sendCMD(sender, "/deu mannequin clone", "Clone a mannequin"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinEquipmentCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinEquipmentCMD.java new file mode 100644 index 00000000..039341e0 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinEquipmentCMD.java @@ -0,0 +1,36 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.mannequin.ui.MannequinEquipmentGUI; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinEquipmentCMD extends PartsSubCommand { + MannequinEquipmentCMD(@NotNull DEUSubCommand parentSubCommand) { + super("equipment", parentSubCommand, Permission.MANNEQUIN_SET_EQUIPMENT, 2, 0); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu mannequin equipment", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + return false; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + MannequinEquipmentGUI.edit(player, selectedPart); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java deleted file mode 100644 index 34de0333..00000000 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHeldItemCMD.java +++ /dev/null @@ -1,83 +0,0 @@ -package net.donnypz.displayentityutils.command.mannequin; - -import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.command.DEUSubCommand; -import net.donnypz.displayentityutils.command.PartsSubCommand; -import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.utils.DisplayEntities.*; -import net.donnypz.displayentityutils.utils.command.DEUCommandUtils; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.entity.Player; -import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -class MannequinHeldItemCMD extends PartsSubCommand { - MannequinHeldItemCMD(@NotNull DEUSubCommand parentSubCommand) { - super("helditem", parentSubCommand, Permission.MANNEQUIN_SET_EQUIPMENT,4, 4); - setTabComplete(2, List.of("main", "off")); - setTabComplete(3, List.of("-held", "")); - } - - @Override - protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("Incorrect Usage! /deu mannequin helditem
<\"-held\" | item-id> [-all]", NamedTextColor.RED)); - } - - @Override - protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { - String hand = args[2]; - boolean isMainHand; - if (hand.equalsIgnoreCase("main")){ - isMainHand = true; - } - else if (hand.equalsIgnoreCase("off") || hand.equalsIgnoreCase("offhand")) { - isMainHand = false; - } - else{ - sendIncorrectUsage(player); - return false; - } - - String item = args[3]; - ItemStack itemStack = DEUCommandUtils.getItemFromText(item, player); - if (itemStack == null) return false; - - for (ActivePart part : selection.getSelectedParts()){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) { - part.setMannequinEquipment(isMainHand ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND, itemStack); - } - } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set "+hand.toLowerCase()+" hand item of ALL selected mannequins!", NamedTextColor.GREEN))); - return true; - } - - @Override - protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; - String hand = args[2]; - boolean isMainHand; - if (hand.equalsIgnoreCase("main")){ - isMainHand = true; - } - else if (hand.equalsIgnoreCase("off") || hand.equalsIgnoreCase("offhand")) { - isMainHand = false; - } - else{ - sendIncorrectUsage(player); - return false; - } - - String item = args[3]; - ItemStack itemStack = DEUCommandUtils.getItemFromText(item, player); - if (itemStack == null) return false; - - selectedPart.setMannequinEquipment(isMainHand ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND, itemStack); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set "+hand.toLowerCase()+" hand item of selected mannequin!", NamedTextColor.GREEN))); - return true; - } -} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/ui/MannequinEquipmentGUI.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/ui/MannequinEquipmentGUI.java new file mode 100644 index 00000000..e38bbc2c --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/ui/MannequinEquipmentGUI.java @@ -0,0 +1,191 @@ +package net.donnypz.displayentityutils.command.mannequin.ui; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +import java.util.HashMap; +import java.util.Map; + +public class MannequinEquipmentGUI { + + private final static Map mannequins = new HashMap<>(); + private final static ItemStack BACKGROUND_ITEM; + private final static ItemStack EXIT_ITEM; + private final static int EXIT_SLOT = 49; + private final static NamespacedKey BACKGROUND_KEY = new NamespacedKey(DisplayAPI.getPlugin(), "gui_background"); + private final static NamespacedKey EXIT_KEY = new NamespacedKey(DisplayAPI.getPlugin(), "gui_exit"); + + static{ + BACKGROUND_ITEM = new ItemStack(Material.GRAY_STAINED_GLASS_PANE); + ItemMeta bgMeta = BACKGROUND_ITEM.getItemMeta(); + if (VersionUtils.IS_1_20_5){ + bgMeta.setHideTooltip(true); + } + else{ + bgMeta.displayName(Component.empty()); + } + setGUIItem(bgMeta, BACKGROUND_KEY); + BACKGROUND_ITEM.setItemMeta(bgMeta); + + EXIT_ITEM = new ItemStack(Material.BARRIER); + ItemMeta exitMeta = EXIT_ITEM.getItemMeta(); + exitMeta.displayName(Component.text("Exit", NamedTextColor.RED).decoration(TextDecoration.ITALIC, false)); + setGUIItem(exitMeta, EXIT_KEY); + EXIT_ITEM.setItemMeta(exitMeta); + } + + public static void edit(Player player, ActivePart part){ + DEUUser user = DEUUser.getOrCreateUser(player); + int entityId = part.getEntityId(); + user.setEditingMannequinArmor(entityId); + + + Inventory inv = Bukkit.createInventory(null, 6*9, Component.text("Set Mannequin Equipment")); + + for (int i = 0; i <6*9; i++){ + inv.setItem(i, BACKGROUND_ITEM); + } + inv.setItem(EXIT_SLOT, EXIT_ITEM); + + + //Indicator Item Slots + inv.setItem(getHelmetSlot()-2, getHelmetIndicatorItem()); + inv.setItem(getChestplateSlot()-2, getChestplateIndicatorItem()); + inv.setItem(getLeggingsSlot()-2, getLeggingsIndicatorItem()); + inv.setItem(getBootsSlot()-2, getBootsIndicatorItem()); + inv.setItem(getMainHandSlot()-18, getMainHandIndicatorItem()); + inv.setItem(getOffHandSlot()-18, getOffHandIndicatorItem()); + + //Equipment Item Slots + inv.setItem(getHelmetSlot(), part.getMannequinEquipment(EquipmentSlot.HEAD).clone()); + inv.setItem(getChestplateSlot(), part.getMannequinEquipment(EquipmentSlot.CHEST).clone()); + inv.setItem(getLeggingsSlot(), part.getMannequinEquipment(EquipmentSlot.LEGS).clone()); + inv.setItem(getBootsSlot(), part.getMannequinEquipment(EquipmentSlot.FEET).clone()); + inv.setItem(getMainHandSlot(), part.getMannequinEquipment(EquipmentSlot.HAND).clone()); + inv.setItem(getOffHandSlot(), part.getMannequinEquipment(EquipmentSlot.OFF_HAND).clone()); + + + mannequins.put(entityId, inv); + player.openInventory(inv); + } + + public static void removeMannequin(Integer entityId){ + mannequins.remove(entityId); + } + + public static boolean isMannequinInventory(Inventory inventory, ActivePart part){ + return inventory.equals(mannequins.get(part.getEntityId())); + } + + private static void setGUIItem(ItemMeta meta, NamespacedKey key){ + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.set(key, PersistentDataType.BOOLEAN, true); + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + } + + public static boolean isBackgroundItem(ItemStack itemStack){ + if (itemStack == null) return false; + ItemMeta meta = itemStack.getItemMeta(); + return meta.getPersistentDataContainer().has(BACKGROUND_KEY); + } + + public static boolean isExitItem(ItemStack itemStack){ + if (itemStack == null) return false; + ItemMeta meta = itemStack.getItemMeta(); + return meta.getPersistentDataContainer().has(EXIT_KEY); + } + + public static int getHelmetSlot(){ + return 3; + } + + public static int getChestplateSlot(){ + return 12; + } + + public static int getLeggingsSlot(){ + return 21; + } + + public static int getBootsSlot(){ + return 30; + } + + public static int getMainHandSlot(){ + return 32; + } + + public static int getOffHandSlot(){ + return 34; + } + + private static ItemStack getHelmetIndicatorItem(){ + ItemStack item = new ItemStack(Material.LEATHER_HELMET); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("Set Helmet →", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } + + private static ItemStack getChestplateIndicatorItem(){ + ItemStack item = new ItemStack(Material.LEATHER_CHESTPLATE); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("Set Chestplate →", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } + + private static ItemStack getLeggingsIndicatorItem(){ + ItemStack item = new ItemStack(Material.LEATHER_LEGGINGS); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("Set Leggings →", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } + + private static ItemStack getBootsIndicatorItem(){ + ItemStack item = new ItemStack(Material.LEATHER_BOOTS); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("Set Boots →", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } + + private static ItemStack getMainHandIndicatorItem(){ + ItemStack item = new ItemStack(Material.WOODEN_SWORD); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("↓ Set Mainhand Item ↓", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } + + private static ItemStack getOffHandIndicatorItem(){ + ItemStack item = new ItemStack(Material.WOODEN_SWORD); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("↓ Set Offhand Item ↓", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java new file mode 100644 index 00000000..9821d370 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java @@ -0,0 +1,90 @@ +package net.donnypz.displayentityutils.listeners.entity; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.mannequin.ui.MannequinEquipmentGUI; +import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +public class DEUMannequinEditorListener implements Listener { + + +// @EventHandler(priority = EventPriority.HIGHEST) +// public void onInventoryDrag(InventoryDragEvent event){ +// if (!VersionUtils.IS_1_21_9) return; +// Inventory inv = event.getInventory(); +// +// Player player = (Player) event.getWhoClicked(); +// DEUUser user = DEUUser.getUser(player); +// if (user == null || !user.isEditingMannequinArmor()) return; +// +// ActivePart part = ActivePart.getPart(user.getEditingMannequin()); +// if (part == null || !MannequinArmorGUI.isMannequinInventory(inv, part)) return; +// +// event.setCancelled(true); +// } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onInventoryClick(InventoryClickEvent event){ + if (!VersionUtils.IS_1_21_9) return; + Inventory inv = event.getInventory(); + + Player player = (Player) event.getWhoClicked(); + DEUUser user = DEUUser.getUser(player); + if (user == null || !user.isEditingMannequinArmor()) return; + + ActivePart part = ActivePart.getPart(user.getEditingMannequin()); + if (part == null || !MannequinEquipmentGUI.isMannequinInventory(inv, part)) return; + + if (MannequinEquipmentGUI.isBackgroundItem(event.getCurrentItem())){ + event.setCancelled(true); + return; + } + + if (MannequinEquipmentGUI.isExitItem(event.getCurrentItem())) { + event.setCancelled(true); + player.closeInventory(); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClose(InventoryCloseEvent event) { + if (!VersionUtils.IS_1_21_9) return; + Inventory inv = event.getInventory(); + + Player player = (Player) event.getPlayer(); + DEUUser user = DEUUser.getUser(player); + if (user == null || !user.isEditingMannequinArmor()) return; + + ActivePart part = ActivePart.getPart(user.getEditingMannequin()); + if (part == null || !MannequinEquipmentGUI.isMannequinInventory(inv, part)) return; + + user.setEditingMannequinArmor(null); + MannequinEquipmentGUI.removeMannequin(part.getEntityId()); + + part.setMannequinEquipment(EquipmentSlot.HEAD, getItem(inv, MannequinEquipmentGUI.getHelmetSlot())); + part.setMannequinEquipment(EquipmentSlot.CHEST, getItem(inv, MannequinEquipmentGUI.getChestplateSlot())); + part.setMannequinEquipment(EquipmentSlot.LEGS, getItem(inv, MannequinEquipmentGUI.getLeggingsSlot())); + part.setMannequinEquipment(EquipmentSlot.FEET, getItem(inv, MannequinEquipmentGUI.getBootsSlot())); + part.setMannequinEquipment(EquipmentSlot.HAND, getItem(inv, MannequinEquipmentGUI.getMainHandSlot())); + part.setMannequinEquipment(EquipmentSlot.OFF_HAND, getItem(inv, MannequinEquipmentGUI.getOffHandSlot())); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Mannequin Equipment Set!", NamedTextColor.GREEN))); + } + + private ItemStack getItem(Inventory inv, int slot){ + ItemStack i = inv.getItem(slot); + return i == null ? new ItemStack(Material.AIR) : i; + } +} From 25dfa426af94f8d21208d9fef8d0ccaa8bb05a17 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 19:50:56 -0600 Subject: [PATCH 063/139] Correctly check if an entity is in a group --- .../net/donnypz/displayentityutils/utils/DisplayUtils.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java index aa79e3d0..d320407c 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java @@ -937,7 +937,8 @@ public static boolean isGroupTag(Entity entity, @NotNull String tag){ * @return a boolean */ public static boolean isInGroup(Entity entity){ - return SpawnedDisplayEntityPart.getPart(entity) != null; + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); + return part != null && part.hasGroup(); } /** @@ -968,6 +969,4 @@ public static void prepareMannequin(Mannequin mannequin){ mannequin.setImmovable(true); mannequin.setGravity(false); } - - } From 84bcc24da6ecc26b46e3736345579ab070cf48e4 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 19:57:04 -0600 Subject: [PATCH 064/139] Disable entity damage if it's in a group (including creative player dmg) --- .../listeners/entity/DEUEntityListener.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUEntityListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUEntityListener.java index 3fcf4c05..65b2eb60 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUEntityListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUEntityListener.java @@ -10,6 +10,7 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.machine.DisplayStateMachine; import net.donnypz.displayentityutils.utils.DisplayEntities.machine.MachineState; +import net.donnypz.displayentityutils.utils.DisplayUtils; import net.donnypz.displayentityutils.utils.controller.DisplayControllerManager; import org.bukkit.Location; import org.bukkit.damage.DamageSource; @@ -44,6 +45,14 @@ public void onDamaged(EntityDamageEvent e){ applyState(e.getEntity(), MachineState.StateType.DAMAGED); } + //Disable non-display entity damage, if in a group + @EventHandler(priority = EventPriority.HIGHEST) + public void onMannequinDamaged(EntityDamageByEntityEvent e){ + if (DisplayUtils.isInGroup(e.getEntity())) { + e.setCancelled(true); + } + } + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onMelee(EntityDamageByEntityEvent e){ DamageSource source = e.getDamageSource(); From 270336fdfae4a736f09d16937098806642fe15e5 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 20:39:42 -0600 Subject: [PATCH 065/139] Fix message --- .../displayentityutils/command/DisplayEntityPluginCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java index 0357c0d4..5ed1663a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java @@ -144,7 +144,7 @@ public static void invalidTagRestrictions(Player player){ public static void invalidStorage(CommandSender sender){ sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid Storage!", NamedTextColor.RED))); - sender.sendMessage(Component.text("| Valid Storages: local, mysql, mongodb>", NamedTextColor.GRAY)); + sender.sendMessage(MiniMessage.miniMessage().deserialize("| Storages: local, mysql, mongodb")); } public static void hideRelativePoints(Player player){ From 8359a9c1c1513126e3f08d9e6f012317dbf9a31f Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 21:02:50 -0600 Subject: [PATCH 066/139] Allow DisplayUtils#pivot to accept any entity --- .../SpawnedDisplayEntityPart.java | 6 +++--- .../utils/DisplayUtils.java | 20 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 21fbcdba..383bcbc1 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -722,9 +722,9 @@ void translateForce(Direction direction, float distance, int durationInTicks, in @Override public void pivot(float angleInDegrees){ if (isDisplay() || isSingle || group == null) return; - Interaction i = (Interaction) getEntity(); - if (i == null) return; - DisplayUtils.pivot(i, group.getLocation(), angleInDegrees); + Entity e = getEntity(); + if (e == null) return; + DisplayUtils.pivot(e, group.getLocation(), angleInDegrees); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java index d320407c..0e450277 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java @@ -570,22 +570,22 @@ public static void translate(@NotNull SpawnedDisplayEntityPart part, @NotNull Di /** - * Pivot an Interaction entity around a location - * @param interaction the interaction - * @param center the location the interaction should pivot around + * Pivot an entity around a location + * @param entity the entity + * @param center the location the entity should pivot around * @param angleInDegrees the pivot angle in degrees */ - public static void pivot(@NotNull Interaction interaction, @NotNull Location center, double angleInDegrees){ - Vector3f translationVector = DisplayUtils.getNonDisplayTranslation(interaction, center).toVector3f(); + public static void pivot(@NotNull Entity entity, @NotNull Location center, double angleInDegrees){ + Vector3f translationVector = DisplayUtils.getNonDisplayTranslation(entity, center).toVector3f(); new Quaternionf() .rotateY((float) Math.toRadians(-angleInDegrees)) .transform(translationVector); Location newLoc = center.clone().subtract(Vector.fromJOML(translationVector)); - FoliaUtils.teleport(interaction, newLoc); + FoliaUtils.teleport(entity, newLoc); } /** - * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Interaction, Location, double)} + * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Entity, Location, double)} * @param offsetLocation the interaction entity's location * @param origin the location the interaction should pivot around * @param angleInDegrees the pivot angle in degrees @@ -597,7 +597,7 @@ public static void pivot(@NotNull Interaction interaction, @NotNull Location cen } /** - * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Interaction, Location, double)} + * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Entity, Location, double)} * @param translationVector the translation offset for an interaction entity from a center location * @param origin the location the interaction should pivot around * @param angleInDegrees the pivot angle in degrees @@ -608,7 +608,7 @@ public static void pivot(@NotNull Interaction interaction, @NotNull Location cen } /** - * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Interaction, Location, double)} + * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Entity, Location, double)} * @param translationVector the translation offset for an interaction entity from a center location * @param origin the location the interaction should pivot around * @param angleInDegrees the pivot angle in degrees @@ -628,7 +628,7 @@ public static void pivot(@NotNull Interaction interaction, @NotNull Location cen * @param durationInTicks how long the scaling should take * @param delayInTicks how long before the scaling should start */ - public static void scaleInteraction(Interaction interaction, float newHeight, float newWidth, int durationInTicks, int delayInTicks){ + public static void scaleInteraction(@NotNull Interaction interaction, float newHeight, float newWidth, int durationInTicks, int delayInTicks){ if (durationInTicks <= 0 && delayInTicks <= 0){ interaction.setInteractionHeight(newHeight); interaction.setInteractionWidth(newWidth); From b57163d56bafdb87650116bc3ed0080132f4be26 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 23 Dec 2025 21:03:46 -0600 Subject: [PATCH 067/139] Store held items in equipment 2d array --- .../DisplayEntities/MannequinEntity.java | 30 ++++++++----------- .../DisplayEntities/SavedEntityBuilder.java | 16 +++++----- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java index b7166537..3610ad78 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java @@ -35,9 +35,7 @@ final class MannequinEntity implements Serializable { double scale; String pose; boolean isRightMainHand; - byte[] mainHandItemStack; - byte[] offHandItemStack; - byte[][] armorItemStacks; //0,1,2,3 = helm,chest,legs,boots, x bytes for itemstack + byte[][] equipment; //0,1,2,3,4,5 = helm,chest,legs,boots,main,off | x bytes for itemstack byte[] persistentDataContainer = null; @@ -63,8 +61,6 @@ PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings set .setAttribute(DisplayAttributes.Equipment.MAIN_HAND, getMainHand()) .setAttribute(DisplayAttributes.Equipment.OFF_HAND, getOffHand()); - //TODO ARMOR AND ITEMS - Location spawnLoc = DisplayUtils.getPivotLocation( vector, origin, @@ -90,28 +86,28 @@ PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings set return part; } - ItemStack getMainHand(){ - return getItemStack(mainHandItemStack); - } - - ItemStack getOffHand(){ - return getItemStack(offHandItemStack); - } - ItemStack getHelmet(){ - return getItemStack(armorItemStacks[0]); + return getItemStack(equipment[0]); } ItemStack getChestplate(){ - return getItemStack(armorItemStacks[1]); + return getItemStack(equipment[1]); } ItemStack getLeggings(){ - return getItemStack(armorItemStacks[2]); + return getItemStack(equipment[2]); } ItemStack getBoots(){ - return getItemStack(armorItemStacks[3]); + return getItemStack(equipment[3]); + } + + ItemStack getMainHand(){ + return getItemStack(equipment[4]); + } + + ItemStack getOffHand(){ + return getItemStack(equipment[5]); } Vector getVector(){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java index b953a962..ea612900 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java @@ -45,13 +45,13 @@ static MannequinEntity buildMannequin(Entity entity){ //Accept entity instead of mannequinEntity.isRightMainHand = mannequin.getMainHand() == MainHand.RIGHT; EntityEquipment equipment = mannequin.getEquipment(); - mannequinEntity.mainHandItemStack = serializeItemStack(equipment.getItemInMainHand()); - mannequinEntity.offHandItemStack = serializeItemStack(equipment.getItemInOffHand()); - mannequinEntity.armorItemStacks = new byte[][]{ + mannequinEntity.equipment = new byte[][]{ serializeItemStack(equipment.getHelmet()), serializeItemStack(equipment.getChestplate()), serializeItemStack(equipment.getLeggings()), - serializeItemStack(equipment.getBoots()) + serializeItemStack(equipment.getBoots()), + serializeItemStack(equipment.getItemInMainHand()), + serializeItemStack(equipment.getItemInOffHand()) }; mannequinEntity.vector = DisplayUtils.getNonDisplayTranslation(mannequin).toVector3f(); @@ -90,13 +90,13 @@ static MannequinEntity buildMannequin(PacketDisplayEntityPart part){ mannequinEntity.pose = pose.name(); mannequinEntity.isRightMainHand = part.getMannequinMainHand() == MainHand.RIGHT; - mannequinEntity.mainHandItemStack = serializeItemStack(part.getMannequinEquipment(EquipmentSlot.HAND)); - mannequinEntity.offHandItemStack = serializeItemStack(part.getMannequinEquipment(EquipmentSlot.OFF_HAND)); - mannequinEntity.armorItemStacks = new byte[][]{ + mannequinEntity.equipment = new byte[][]{ serializeItemStack(part.getMannequinEquipment(EquipmentSlot.HEAD)), serializeItemStack(part.getMannequinEquipment(EquipmentSlot.CHEST)), serializeItemStack(part.getMannequinEquipment(EquipmentSlot.LEGS)), - serializeItemStack(part.getMannequinEquipment(EquipmentSlot.FEET)) + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.FEET)), + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.HAND)), + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.OFF_HAND)) }; From f1ab8d5eb6591002cb9bbad91ef03bc5d4ecf1fd Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 24 Dec 2025 22:36:26 -0600 Subject: [PATCH 068/139] Fix mannequin saving to json. save all pdc's as base64 --- .../managers/DisplayGroupManager.java | 16 --- .../utils/DisplayEntities/DEUJSONAdapter.java | 5 + .../DisplayEntities/InteractionEntity.java | 6 +- .../JSONAdapter_DisplayEntity.java | 36 +++-- .../JSONAdapter_InteractionEntity.java | 76 +++++++++++ .../JSONAdapter_MannequinEntity.java | 123 ++++++++++++++++++ .../DisplayEntities/MannequinEntity.java | 22 ++-- 7 files changed, 240 insertions(+), 44 deletions(-) create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_InteractionEntity.java create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_MannequinEntity.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java index 8c356a7a..a91e5a24 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java @@ -252,22 +252,6 @@ static void serializeJsonElement(JsonElement el) { } } -// if (obj.has(PART_TAG_FIELD)){ -// JsonArray arr = obj.getAsJsonArray(PDC_FIELD); -// if (arr != null){ -// byte[] bytes = new byte[arr.size()]; -// ItemStack stick = new ItemStack(Material.STICK); -// PersistentDataContainer pdc = stick.getItemMeta().getPersistentDataContainer(); -// try{ -// pdc.readFromBytes(bytes); -// List tags = pdc.get(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings()); -// obj.add(PART_TAG_FIELD, gson.toJsonTree(tags)); -// } -// catch(IOException e){} -// } -// } - - for (Map.Entry entry : obj.entrySet()) { serializeJsonElement(entry.getValue()); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUJSONAdapter.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUJSONAdapter.java index 3e38ac9f..09f0a66a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUJSONAdapter.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUJSONAdapter.java @@ -5,8 +5,13 @@ public final class DEUJSONAdapter { + static final String PART_UUID_FIELD = "partUUID"; + static final String PDC_FIELD = "persistentDataContainer"; + public static final Gson GSON = new GsonBuilder() .registerTypeAdapter(DisplayEntity.class, new JSONAdapter_DisplayEntity()) + .registerTypeAdapter(InteractionEntity.class, new JSONAdapter_InteractionEntity()) + .registerTypeAdapter(MannequinEntity.class, new JSONAdapter_MannequinEntity()) .registerTypeHierarchyAdapter(DisplayEntitySpecifics.class, new JSONAdapter_DisplayEntitySpecifics()) .registerTypeHierarchyAdapter(FramePoint.class, new JSONAdapter_FramePoint()) .create(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java index 7b17e74d..680a46e5 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java @@ -31,15 +31,16 @@ final class InteractionEntity implements Serializable { UUID partUUID; float height; float width; - private byte[] persistentDataContainer = null; + byte[] persistentDataContainer = null; boolean isResponsive; + InteractionEntity(){} + InteractionEntity(Interaction interaction){ this.height = interaction.getInteractionHeight(); this.width = interaction.getInteractionWidth(); this.isResponsive = interaction.isResponsive(); this.vector = DisplayUtils.getNonDisplayTranslation(interaction).toVector3f(); - this.partUUID = DisplayUtils.getPartUUID(interaction); //for json file try{ persistentDataContainer = interaction.getPersistentDataContainer().serializeToBytes(); @@ -56,7 +57,6 @@ final class InteractionEntity implements Serializable { this.width = c.getAttributeOrDefault(DisplayAttributes.Interaction.WIDTH, 1f); this.isResponsive = c.getAttributeOrDefault(DisplayAttributes.Interaction.RESPONSIVE, false); this.vector = part.getNonDisplayTranslation().toVector3f(); - this.partUUID = part.partUUID; //for json file try{ ItemStack i = new ItemStack(Material.STICK); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_DisplayEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_DisplayEntity.java index 68691b63..23218f84 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_DisplayEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_DisplayEntity.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.lang.reflect.Type; +import java.util.Base64; import java.util.List; @ApiStatus.Internal @@ -25,15 +26,22 @@ public DisplayEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializa entity.type = DisplayEntity.Type.valueOf(obj.get("type").getAsString().toUpperCase()); entity.isMaster = obj.get("isMaster").getAsBoolean(); - List list = ctx.deserialize(obj.get("persistentDataContainer"), List.class); - byte[] bytes = new byte[list.size()]; - for (int i = 0; i < list.size(); i++) { - bytes[i] = list.get(i).byteValue(); + if (obj.has(DEUJSONAdapter.PDC_FIELD)){ + try{ + List list = ctx.deserialize(obj.get(DEUJSONAdapter.PDC_FIELD), List.class); + byte[] bytes = new byte[list.size()]; + for (int i = 0; i < list.size(); i++) { + bytes[i] = list.get(i).byteValue(); + } + + entity.persistentDataContainer = bytes; + } + catch(JsonParseException e){ + String base64 = ctx.deserialize(obj.get(DEUJSONAdapter.PDC_FIELD), String.class); + entity.persistentDataContainer = Base64.getDecoder().decode(base64); + } } - entity.persistentDataContainer = bytes; - - JsonObject specificsJson = obj.getAsJsonObject("specifics"); switch (entity.type) { case BLOCK: @@ -59,6 +67,9 @@ public JsonElement serialize(DisplayEntity src, Type typeOfSrc, JsonSerializatio //Convert Specifics, and remove legacy part tags array json.add("specifics", ctx.serialize(src.specifics, DisplayEntitySpecifics.class)); + //partUUID + json.addProperty(DEUJSONAdapter.PART_UUID_FIELD, src.specifics.getPartUUID().toString()); + //Add part tags try{ PersistentDataContainer pdc = new ItemStack(Material.STICK).getItemMeta().getPersistentDataContainer(); @@ -66,14 +77,13 @@ public JsonElement serialize(DisplayEntity src, Type typeOfSrc, JsonSerializatio List tags = pdc.get(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings()); json.add("partTags", new Gson().toJsonTree(tags)); } - catch(IOException e){} + catch(IOException | NullPointerException e){} - //Convert byte arr to int arr - JsonArray arr = new JsonArray(); - for (byte b : src.persistentDataContainer){ - arr.add((int) b); + //pdc to base64 + byte[] pdc = src.persistentDataContainer; + if (pdc != null){ + json.addProperty(DEUJSONAdapter.PDC_FIELD, Base64.getEncoder().encodeToString(pdc)); } - json.add("persistentDataContainer", arr); return json; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_InteractionEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_InteractionEntity.java new file mode 100644 index 00000000..bcf83380 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_InteractionEntity.java @@ -0,0 +1,76 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import com.google.gson.*; +import net.donnypz.displayentityutils.DisplayAPI; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.joml.Vector3f; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Base64; +import java.util.List; +import java.util.UUID; + +public class JSONAdapter_InteractionEntity implements JsonSerializer, JsonDeserializer { + + @Override + public InteractionEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) throws JsonParseException { + JsonObject obj = json.getAsJsonObject(); + InteractionEntity entity = new InteractionEntity(); + + entity.vector = ctx.deserialize(obj.get("vector"), Vector3f.class); + entity.partUUID = UUID.fromString(obj.get(DEUJSONAdapter.PART_UUID_FIELD).getAsString()); + entity.height = obj.get("height").getAsFloat(); + entity.width = obj.get("width").getAsFloat(); + entity.isResponsive = obj.get("isResponsive").getAsBoolean(); + + + //PDC + String base64 = ctx.deserialize(obj.get(DEUJSONAdapter.PDC_FIELD), String.class); + entity.persistentDataContainer = Base64.getDecoder().decode(base64); + + return null; + } + + + @Override + public JsonElement serialize(InteractionEntity src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject json = new Gson().toJsonTree(src).getAsJsonObject(); + PersistentDataContainer pdc = new ItemStack(Material.STICK).getItemMeta().getPersistentDataContainer(); + byte[] pdcBytes = src.persistentDataContainer; + + + + if (pdcBytes != null){ + + //Add part tags + try{ + pdc.readFromBytes(pdcBytes); + List tags = pdc.get(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings()); + json.add("partTags", new Gson().toJsonTree(tags)); + } + catch(IOException | NullPointerException e){} + + //partuuid + UUID partUUID; + if (src.partUUID != null){ + partUUID = src.partUUID; + } + else{ + partUUID = UUID.fromString(pdc.get(DisplayAPI.getPartUUIDKey(), PersistentDataType.STRING)); + } + json.addProperty(DEUJSONAdapter.PART_UUID_FIELD, partUUID.toString()); + + + //pdc to base 64 + json.addProperty(DEUJSONAdapter.PDC_FIELD, Base64.getEncoder().encodeToString(pdcBytes)); + } + + return json; + } + + +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_MannequinEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_MannequinEntity.java new file mode 100644 index 00000000..8455fca6 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_MannequinEntity.java @@ -0,0 +1,123 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import com.google.gson.*; +import net.donnypz.displayentityutils.DisplayAPI; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.joml.Vector3f; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Base64; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class JSONAdapter_MannequinEntity implements JsonSerializer, JsonDeserializer { + Gson gson = new Gson(); + Map AIR_AS_MAP = new ItemStack(Material.AIR).serialize(); + + JSONAdapter_MannequinEntity(){} + + + @Override + public JsonElement serialize(MannequinEntity src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject json = gson.toJsonTree(src).getAsJsonObject(); + + //Equipment items as json objects + JsonArray equipmentArr = new JsonArray(); + for (byte[] itemBytes : src.equipment){ + Map itemStackMap; + if (itemBytes != null){ + itemStackMap = ItemStack.deserializeBytes(itemBytes).serialize(); + } + else{ + itemStackMap = AIR_AS_MAP; + } + JsonElement jsonElement = gson.toJsonTree(itemStackMap); + equipmentArr.add(jsonElement); + + } + + json.add("equipment", equipmentArr); + + //Add part tags + try{ + PersistentDataContainer pdc = new ItemStack(Material.STICK).getItemMeta().getPersistentDataContainer(); + pdc.readFromBytes(src.persistentDataContainer); + List tags = pdc.get(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings()); + json.add("partTags", new Gson().toJsonTree(tags)); + } + catch(IOException | NullPointerException e){} + + //pdc to base 64 + json.addProperty(DEUJSONAdapter.PDC_FIELD, + Base64.getEncoder().encodeToString(src.persistentDataContainer)); + return json; + } + + @Override + public MannequinEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject obj = json.getAsJsonObject(); + + MannequinEntity mannequin = new MannequinEntity(); + + mannequin.vector = context.deserialize(obj.get("vector"), Vector3f.class); + + mannequin.customName = getString(obj, "customName"); + mannequin.customNameVisible = getBoolean(obj, "customNameVisible"); + mannequin.description = getString(obj, "description"); + + mannequin.profileName = getString(obj, "profileName"); + mannequin.profileUUID = obj.has("profileUUID") && !obj.get("profileUUID").isJsonNull() + ? UUID.fromString(obj.get("profileUUID").getAsString()) + : null; + + mannequin.scale = getDouble(obj, "scale"); + mannequin.pose = getString(obj, "pose"); + mannequin.isRightMainHand = getBoolean(obj, "isRightMainHand"); + + //Equipment + if (obj.has("equipment") && obj.get("equipment").isJsonArray()) { + JsonArray arr = obj.getAsJsonArray("equipment"); + mannequin.equipment = new byte[arr.size()][]; + + for (int i = 0; i < arr.size(); i++) { + JsonElement el = arr.get(i); + if (el == null || el.isJsonNull()) { + mannequin.equipment[i] = null; + continue; + } + + Map map = gson.fromJson(el, Map.class); + ItemStack stack = ItemStack.deserialize(map); + try{ + mannequin.equipment[i] = stack.serializeAsBytes(); + } + catch(IllegalArgumentException e){} //thrown if itemstack is empty (air, or 0 count) + } + } + + //PDC + if (obj.has("persistentDataContainer") && !obj.get("persistentDataContainer").isJsonNull()) { + String pdcBase64 = obj.get("persistentDataContainer").getAsString(); + mannequin.persistentDataContainer = Base64.getDecoder().decode(pdcBase64); + } + + return mannequin; + } + + private static String getString(JsonObject obj, String key) { + return obj.has(key) && !obj.get(key).isJsonNull() ? obj.get(key).getAsString() : null; + } + + private static boolean getBoolean(JsonObject obj, String key) { + return obj.has(key) && !obj.get(key).isJsonNull() && obj.get(key).getAsBoolean(); + } + + private static double getDouble(JsonObject obj, String key) { + return obj.has(key) && !obj.get(key).isJsonNull() ? obj.get(key).getAsDouble() : 0.0D; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java index 3610ad78..f0817265 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java @@ -36,7 +36,7 @@ final class MannequinEntity implements Serializable { String pose; boolean isRightMainHand; byte[][] equipment; //0,1,2,3,4,5 = helm,chest,legs,boots,main,off | x bytes for itemstack - byte[] persistentDataContainer = null; + byte[] persistentDataContainer; MannequinEntity(){} @@ -68,19 +68,17 @@ PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings set PacketDisplayEntityPart part = attributeContainer.createPart(SpawnedDisplayEntityPart.PartType.MANNEQUIN, spawnLoc); - if (persistentDataContainer != null){ - ItemStack i = new ItemStack(Material.STICK); - PersistentDataContainer pdc = i.getItemMeta().getPersistentDataContainer(); + ItemStack i = new ItemStack(Material.STICK); + PersistentDataContainer pdc = i.getItemMeta().getPersistentDataContainer(); - try { - pdc.readFromBytes(persistentDataContainer); - } catch (IOException e) { - throw new RuntimeException(e); - } - - part.partTags = DisplayEntity.getSetFromPDC(pdc, DisplayAPI.getPartPDCTagKey()); - part.partUUID = DisplayEntity.getPDCPartUUID(pdc); + try { + pdc.readFromBytes(persistentDataContainer); + } catch (IOException e) { + throw new RuntimeException(e); } + + part.partTags = DisplayEntity.getSetFromPDC(pdc, DisplayAPI.getPartPDCTagKey()); + part.partUUID = DisplayEntity.getPDCPartUUID(pdc); settings.applyAttributes(part); return part; From 807f4337456ff94ba6c589c4da6deaf60607ac78 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 03:31:36 -0600 Subject: [PATCH 069/139] Fix mannequin part type not being filterable --- .../command/parts/PartsFilterTypesCMD.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java index c253497b..413f9b64 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java @@ -72,7 +72,8 @@ public void execute(Player player, String[] args) { } try{ - if (!typeText.equals(SpawnedDisplayEntityPart.PartType.INTERACTION.name())){ + if (!typeText.equals(SpawnedDisplayEntityPart.PartType.INTERACTION.name()) + && !typeText.equals(SpawnedDisplayEntityPart.PartType.MANNEQUIN.name())){ typeText = typeText+"_DISPLAY"; } @@ -87,7 +88,7 @@ public void execute(Player player, String[] args) { } catch(IllegalArgumentException e){ player.sendMessage(Component.text("Invalid Part Type listed!", NamedTextColor.RED)); - player.sendMessage(Component.text("Valid Types: BLOCK, ITEM, TEXT, INTERACTION", NamedTextColor.GRAY, TextDecoration.ITALIC)); + player.sendMessage(Component.text("Valid Types: BLOCK, ITEM, TEXT, INTERACTION, MANNEQUIN", NamedTextColor.GRAY, TextDecoration.ITALIC)); return; } player.sendMessage(Component.text("- "+typeText, NamedTextColor.YELLOW)); From d95517c531ec8d3f51c83d2927a62811cbc33366 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 03:32:11 -0600 Subject: [PATCH 070/139] No changes --- .../command/mannequin/MannequinCMD.java | 2 +- .../command/parts/PartsYawCMD.java | 49 +++++++------------ 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java index fcc0f382..bb7f3724 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -57,8 +57,8 @@ static void help(CommandSender sender, int page){ CMDUtils.sendCMD(sender, "/deu mannequin toggleimmovable [-all ]", "Toggle the immovability of an mannequin"); } else{ - CMDUtils.sendCMD(sender, "/deu mannequin mainhand ", "Set the mannequin's main hand"); CMDUtils.sendCMD(sender, "/deu mannequin equipment ", "Open a GUI to edit your selected mannequin's equipment."); + CMDUtils.sendCMD(sender, "/deu mannequin mainhand ", "Set your selected mannequin's main hand"); CMDUtils.sendCMD(sender, "/deu mannequin pose [-all]", "Change your selected mannequin's pose"); CMDUtils.sendCMD(sender, "/deu mannequin scale [-all]", "Set your selected mannequin's scale"); CMDUtils.sendCMD(sender, "/deu mannequin clone", "Clone a mannequin"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsYawCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsYawCMD.java index 61b93379..8d1ed136 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsYawCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsYawCMD.java @@ -1,58 +1,45 @@ package net.donnypz.displayentityutils.command.parts; import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.command.DEUSubCommand; -import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; -import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.command.*; import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -class PartsYawCMD extends PlayerSubCommand { +class PartsYawCMD extends PartsSubCommand { PartsYawCMD(@NotNull DEUSubCommand parentSubCommand) { - super("yaw", parentSubCommand, Permission.PARTS_TRANSFORM); + super("yaw", parentSubCommand, Permission.PARTS_TRANSFORM, 3, 0); setTabComplete(2, ""); } @Override - public void execute(Player player, String[] args) { - ActivePartSelection selection = DisplayGroupManager.getPartSelection(player); - if (selection == null){ - DisplayEntityPluginCommand.noPartSelection(player); - return; - } - - if (PartsCMD.isUnwantedMultiSelection(player, selection)){ - return; - } - - if (args.length < 3){ - player.sendMessage(Component.text("Incorrect Usage! /deu parts yaw ", NamedTextColor.RED)); - return; - } + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(Component.text("Incorrect Usage! /deu parts yaw ", NamedTextColor.RED)); + } - if (!selection.hasSelectedPart()){ - PartsCMD.invalidPartSelection(player); - return; - } + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + return false; + } + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { try{ float yaw = Float.parseFloat(args[2]); - ActivePart part = selection.getSelectedPart(); - double oldYaw = part.getYaw(); - part.setYaw(yaw, false); + double oldYaw = selectedPart.getYaw(); + selectedPart.setYaw(yaw, false); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Yaw set!", NamedTextColor.GREEN))); player.sendMessage(Component.text("| Old Yaw: "+oldYaw, NamedTextColor.GRAY)); + return true; } catch(NumberFormatException e){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid number for the yaw!", NamedTextColor.RED))); + return false; } } } From e9f3164db9cf5d0cf24c60e7f1b2211e18a6fd72 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 03:32:29 -0600 Subject: [PATCH 071/139] Update mannequin bodyyaw when updating part yaw --- .../utils/DisplayEntities/SpawnedDisplayEntityPart.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 383bcbc1..33492bbe 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -511,6 +511,9 @@ public void setYaw(float yaw, boolean pivot){ pivot(yaw-entity.getYaw()); } entity.setRotation(yaw, entity.getPitch()); + if (entity instanceof LivingEntity le){ + le.setBodyYaw(yaw); + } } /** From fec70d113b1d9ce6e0b41cfd35e542969305a211 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 03:36:26 -0600 Subject: [PATCH 072/139] Remove SHULKER part type --- .../displayentityutils/utils/DisplayEntities/ActivePart.java | 3 +-- .../utils/DisplayEntities/SpawnedDisplayEntityPart.java | 3 --- .../utils/packet/PacketAttributeContainer.java | 3 --- .../utils/relativepoints/DisplayEntitySelector.java | 3 --- 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 23adb643..17b305ae 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -206,8 +206,7 @@ public SpawnedDisplayEntityPart.PartType getType(){ */ public boolean canGlow(){ return type != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY - && type != SpawnedDisplayEntityPart.PartType.INTERACTION - && type != SpawnedDisplayEntityPart.PartType.SHULKER; + && type != SpawnedDisplayEntityPart.PartType.INTERACTION; } public boolean isDisplay(){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 33492bbe..885e898a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -1241,7 +1241,6 @@ public enum PartType{ ITEM_DISPLAY, TEXT_DISPLAY, INTERACTION, - SHULKER, MANNEQUIN; /** @@ -1254,7 +1253,6 @@ public static PartType getType(@NotNull Entity entity){ if (entity instanceof ItemDisplay) return ITEM_DISPLAY; if (entity instanceof TextDisplay) return TEXT_DISPLAY; if (entity instanceof Interaction) return INTERACTION; - if (entity instanceof Shulker) return SHULKER; if (VersionUtils.IS_1_21_9 && entity instanceof Mannequin) return MANNEQUIN; return null; } @@ -1264,7 +1262,6 @@ public boolean isOfType(Entity e){ if (e instanceof ItemDisplay && this == ITEM_DISPLAY) return true; if (e instanceof TextDisplay && this == TEXT_DISPLAY) return true; if (e instanceof Interaction && this == INTERACTION) return true; - if (e instanceof Shulker && this == SHULKER) return true; if (e instanceof Mannequin && this == MANNEQUIN) return true; return false; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java index d16796cb..d485767e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java @@ -429,9 +429,6 @@ EntityType getEntityType(SpawnedDisplayEntityPart.PartType partType){ case INTERACTION -> { return EntityTypes.INTERACTION; } - case SHULKER -> { - return EntityTypes.SHULKER; - } case MANNEQUIN -> { return EntityTypes.MANNEQUIN; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java index 84da9606..aa9b7c64 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java @@ -72,9 +72,6 @@ public static void select(Player player, Entity entity){ case Mannequin m -> { entityType = "Mannequin"; } - case Shulker s -> { - entityType = "Shulker"; - } default -> entityType = ""; } player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text(entityType+" Entity Selected!", NamedTextColor.GREEN))); From 90185dd09d1cc7cd9c08aad6c41282c520b5cd9c Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 13:57:52 -0600 Subject: [PATCH 073/139] add mannequin part type to skript --- .../net/donnypz/displayentityutils/skript/SkriptTypes.java | 3 ++- plugin/src/main/resources/lang/default.lang | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/SkriptTypes.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/SkriptTypes.java index ef4930f8..3594409e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/SkriptTypes.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/SkriptTypes.java @@ -448,10 +448,11 @@ public String toVariableNameString(InteractionCommand o) { EnumWrapper partTypeWrapper = new EnumWrapper<>(SpawnedDisplayEntityPart.PartType.class, null, null); partTypeWrapper.replace("interaction", "deu_interaction"); + partTypeWrapper.replace("mannequin", "deu_mannequin"); Classes.registerClass(partTypeWrapper.getClassInfo("parttype") .user("part( | -)?type") .name("Part Type") - .description("Represents a part type being BLOCK_DISPLAY, ITEM_DISPLAY, TEXT_DISPLAY, or INTERACTION") + .description("Represents a part's (display, interaction, etc.) type") .since("2.6.2, 3.3.6 (Removed \"parttype_\" prefix)")); EnumWrapper clickTypeWrapper = new EnumWrapper<>(InteractionClickEvent.ClickType.class, "iClickType", null); diff --git a/plugin/src/main/resources/lang/default.lang b/plugin/src/main/resources/lang/default.lang index 5a2e437b..6a01c9fe 100644 --- a/plugin/src/main/resources/lang/default.lang +++ b/plugin/src/main/resources/lang/default.lang @@ -22,6 +22,7 @@ parttype: item_display: item text_display: text interaction: interaction + mannequin: mannequin types: groupspawnreason: group spawn reason¦s From 661d8eaa6a2e20b844e4fd710a889e820e03a9bb Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 17:19:52 -0600 Subject: [PATCH 074/139] Allow resourcepack sounds in animations --- .../utils/DisplayEntities/AnimationSound.java | 15 +++++++++++++-- .../utils/version/VersionUtils.java | 10 +++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationSound.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationSound.java index 32a6c9b1..332cedd0 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationSound.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationSound.java @@ -111,11 +111,22 @@ else if (group.isActiveAnimator(animator)){ } public void playSound(@NotNull Location location){ - location.getWorld().playSound(location, sound, volume, pitch); + if (sound == null){ + location.getWorld().playSound(location, soundName, volume, pitch); + } + else{ + location.getWorld().playSound(location, sound, volume, pitch); + } + } public void playSound(@NotNull Location location, Player player){ - player.playSound(location, sound, volume, pitch); + if (sound == null){ + player.playSound(location, soundName, volume, pitch); + } + else{ + player.playSound(location, sound, volume, pitch); + } } public void playSound(@NotNull Location location, Collection players){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java index f3afa02a..bf7dac1d 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java @@ -83,7 +83,15 @@ public static Particle getItemParticle(){ public static Sound getSound(String soundName){ if (soundName == null) return null; - return Registry.SOUNDS.get(NamespacedKey.minecraft(soundName)); + String[] split = soundName.split(":"); + if (split.length < 2){ + return Registry.SOUNDS.get(NamespacedKey.minecraft(soundName)); + } + else{ + String namespace = split[0]; + String key = split[1]; + return Registry.SOUNDS.get(new NamespacedKey(namespace, key)); + } } public static boolean serverHasDialogs(){ //Dialog API came to Paper in 1.21.7, Dialog System came to MC in 1.21.6 From d8f6f318e6750bb673fa628f6e9ee95eb3a3ae3e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 17:20:11 -0600 Subject: [PATCH 075/139] Allow resourcepack sounds in animations --- .../displayentityutils/utils/DisplayEntities/FramePoint.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java index 6bdb532c..b292b8fc 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java @@ -447,7 +447,7 @@ public void sendInfo(Player player){ msgComp = msgComp.append(Component.text(" [UNKNOWN]", NamedTextColor.GRAY)); hoverComp = hoverComp .append(Component.newline()) - .append(Component.text("This sound no longer exists!", NamedTextColor.RED)); + .append(Component.text("This sound no longer exists or is a resource pack sound!", NamedTextColor.RED)); } msgComp = msgComp.hoverEvent(HoverEvent.showText(hoverComp)); From 88e38768c471f10d51e089c3576e07c50805a4ee Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 17:50:41 -0600 Subject: [PATCH 076/139] Include sounds from playsound commands in animation --- .../bdengine/DatapackEntitySpawned.java | 8 +-- .../managers/LocalManager.java | 2 - .../convert/datapack/BDEngineDPConverter.java | 66 ++++++++++++++++--- .../datapack/BDEngineLegacyDPConverter.java | 2 +- 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java index f136b3df..30cb27cd 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java @@ -1,8 +1,8 @@ package net.donnypz.displayentityutils.listeners.bdengine; -import net.donnypz.displayentityutils.managers.LocalManager; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.bdengine.convert.datapack.BDEngineDPConverter; import org.bukkit.Location; import org.bukkit.entity.Display; import org.bukkit.entity.Entity; @@ -71,7 +71,7 @@ private static void applyToEntity(Display display, Object projectValue){ //DisplayEntityGroups created outside the animator spawn ungrouped parts last, //while the animator spawns them after the MAIN master part if (tag.contains(projectValue +"_")) { - display.addScoreboardTag(LocalManager.datapackUngroupedAddLaterTag); + display.addScoreboardTag(BDEngineDPConverter.UNGROUPED_ADD_LATER_TAG); } group.addDisplayEntity(display); } @@ -108,10 +108,10 @@ private static void finalize(SpawnedDisplayEntityGroup group){ } Display display = (Display) part.getEntity(); - if (display.getScoreboardTags().contains(LocalManager.datapackConvertDeleteSubParentTag)){ + if (display.getScoreboardTags().contains(BDEngineDPConverter.CONVERT_DELETE_SUB_PARENT_TAG)){ part.remove(true); } - else if (display.getScoreboardTags().contains(LocalManager.datapackUngroupedAddLaterTag)){ + else if (display.getScoreboardTags().contains(BDEngineDPConverter.UNGROUPED_ADD_LATER_TAG)){ laterParts.add(part.remove(false)); } else{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java b/plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java index aba3da71..01da25ab 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java @@ -17,8 +17,6 @@ import java.util.zip.GZIPOutputStream; public final class LocalManager implements DisplayStorage{ - public static final String datapackConvertDeleteSubParentTag = "deu_delete_sub_parent"; - public static final String datapackUngroupedAddLaterTag = "deu_add_later"; public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){ try{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java index 8cbecd76..661a3be0 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java @@ -4,10 +4,7 @@ import net.donnypz.displayentityutils.listeners.bdengine.DatapackEntitySpawned; import net.donnypz.displayentityutils.managers.*; import net.donnypz.displayentityutils.utils.ConversionUtils; -import net.donnypz.displayentityutils.utils.DisplayEntities.AnimationCamera; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayAnimation; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayAnimationFrame; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.donnypz.displayentityutils.utils.version.folia.Scheduler; import net.kyori.adventure.text.Component; @@ -23,15 +20,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.LinkedHashMap; -import java.util.List; +import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class BDEngineDPConverter { + private static final String FRAME_POINT_SOUND_TAG = "deu_dp_convert"; + public static final String CONVERT_DELETE_SUB_PARENT_TAG = "deu_delete_sub_parent"; + public static final String UNGROUPED_ADD_LATER_TAG = "deu_add_later"; + static final CommandSender silentSender = Bukkit.createCommandSender(feedback -> {}); static final String FUNCTION_FOLDER = VersionUtils.IS_1_21 ? "function" : "functions"; private static final String CREATE_MODEL_PATH = "/create.mcfunction"; @@ -40,6 +38,8 @@ public class BDEngineDPConverter { private final String groupSaveTag; private final String animationSavePrefix; private final LinkedHashMap> animations = new LinkedHashMap<>(); + private final HashSet bufferedSounds = new HashSet<>(); + Location spawnLoc; public BDEngineDPConverter(@NotNull Player player, @NotNull String datapackName, @NotNull String groupSaveTag, @NotNull String animationSavePrefix){ @@ -201,6 +201,17 @@ public void run() { //Create Frame frame.setTransformation(createdGroup); + + //Add Sounds + if (!bufferedSounds.isEmpty()){ + FramePoint point = new FramePoint(FRAME_POINT_SOUND_TAG, createdGroup, spawnLoc); + for (AnimationSound sound : bufferedSounds){ + point.addSound(sound); + } + bufferedSounds.clear(); + frame.addFramePoint(point); + } + anim.addFrame(frame); i++; } @@ -261,8 +272,9 @@ else if (line.contains("@s")){ line = line.replace("@s", player.getName()); line = "execute"+line.split("nearest]")[1]; } - - line = line.substring(0, line.length()-2)+",\""+LocalManager.datapackConvertDeleteSubParentTag+"\"]}"; + if (!line.startsWith("ride")) { + line = line.substring(0, line.length()-2)+",\""+CONVERT_DELETE_SUB_PARENT_TAG+"\"]}"; + } } else if (line.startsWith("schedule")) { @@ -277,6 +289,20 @@ else if (line.startsWith("schedule")) { continue; } + //Animation Sound + if (line.startsWith("playsound")){ + AnimationSound sound = getSound(line); + if (sound != null){ + bufferedSounds.add(sound); + } + } + else if (line.startsWith("execute") && line.contains("playsound")){ + AnimationSound sound = getSound("."+line.split(" playsound ")[1]); + if (sound != null){ + bufferedSounds.add(sound); + } + } + String coordinates = ConversionUtils.getCoordinateString(spawnLoc); World w = spawnLoc.getWorld(); String worldName = ConversionUtils.getExecuteCommandWorldName(w); @@ -308,7 +334,27 @@ private void setCameraVectorAndDirection(SpawnedDisplayAnimationFrame frame, Str Location cameraLoc = spawnLoc.clone().add(x, y, z); cameraLoc.getWorld().spawnParticle(Particle.DRAGON_BREATH, cameraLoc, 1, 0,0,0,0); } catch(IndexOutOfBoundsException e){} + } + + AnimationSound getSound(String line){ + String[] strings = line.split(" "); + String soundStr = strings[1]; + float volume = -1; + float pitch = -1; + try{ + volume = Float.parseFloat(strings[7]); + pitch = Float.parseFloat(strings[8]); + } + catch(IllegalArgumentException | IndexOutOfBoundsException e){ + if (volume == -1){ + volume = 1; + } + if (pitch == -1){ + pitch = 1; + } + } + return new AnimationSound(soundStr, volume, pitch, 0); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineLegacyDPConverter.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineLegacyDPConverter.java index fa2340a2..35af044e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineLegacyDPConverter.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineLegacyDPConverter.java @@ -231,7 +231,7 @@ else if (line.contains("@s")){ String replacement = player.getName(); line = line.replace("@s", replacement); } - line = line.substring(0, line.length()-2)+",\""+LocalManager.datapackConvertDeleteSubParentTag+"\"]}"; + line = line.substring(0, line.length()-2)+",\""+BDEngineDPConverter.CONVERT_DELETE_SUB_PARENT_TAG +"\"]}"; } else if (zipEntry.getName().contains("start_animation.mcfunction")){ From 625f7ba641a43a0c74e35e83061dad0efb62512e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 18:02:34 -0600 Subject: [PATCH 077/139] 3.4.0-PRE-1 --- api/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 294e8694..58bd5cdc 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.3.8 + 3.4.0-PRE-1 api diff --git a/plugin/pom.xml b/plugin/pom.xml index 05c414c2..89229dec 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.3.8 + 3.4.0-PRE-1 plugin diff --git a/pom.xml b/pom.xml index ac75a46d..974dcd7a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.3.8 + 3.4.0-PRE-1 pom DisplayEntityUtils From 2ce9c147ffde42e006fd9c8496cf1178a58d3c6f Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 18:12:59 -0600 Subject: [PATCH 078/139] Allow addition of rp sounds to frame points through commands --- .../command/anim/AnimAddSoundCMD.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java index af8febcd..9377af07 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java @@ -47,22 +47,22 @@ public void execute(Player player, String[] args) { return; } try { - Sound sound = VersionUtils.getSound(args[2]); - if (sound == null){ - player.sendMessage(Component.text("Invalid Sound Name!", NamedTextColor.RED)); - return; - } + String soundStr = args[2]; float volume = Float.parseFloat(args[3]); float pitch = Float.parseFloat(args[4]); int delayInTicks = Integer.parseInt(args[5]); - display.getRelativePoint().addSound(new AnimationSound(sound, volume, pitch, delayInTicks)); + display.getRelativePoint().addSound(new AnimationSound(soundStr, volume, pitch, delayInTicks)); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Sound Added to Frame Point!", NamedTextColor.GREEN))); - player.sendMessage(MiniMessage.miniMessage().deserialize("| Sound: "+sound)); + player.sendMessage(MiniMessage.miniMessage().deserialize("| Sound: "+soundStr)); player.sendMessage(MiniMessage.miniMessage().deserialize("| Volume: "+volume)); player.sendMessage(MiniMessage.miniMessage().deserialize("| Pitch: "+pitch)); player.sendMessage(MiniMessage.miniMessage().deserialize("| Delay: "+delayInTicks)); + + if (VersionUtils.getSound(args[2]) == null){ + player.sendMessage(Component.text("| The provided sound is not a vanilla Minecraft sound!", NamedTextColor.GRAY)); + } } catch (NumberFormatException | IndexOutOfBoundsException e) { player.sendMessage(Component.text("Invalid number entered! Enter a number >= 0", NamedTextColor.RED)); player.sendMessage(Component.text("| Delay must be a whole number", NamedTextColor.GRAY)); From d87a3b35fd67f7e36fc2a9c9980ebfe4d19395b6 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 18:14:11 -0600 Subject: [PATCH 079/139] Allow addition of rp sounds to frame points through commands --- .../displayentityutils/command/anim/AnimAddSoundCMD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java index 9377af07..9758c68e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java @@ -61,7 +61,7 @@ public void execute(Player player, String[] args) { player.sendMessage(MiniMessage.miniMessage().deserialize("| Delay: "+delayInTicks)); if (VersionUtils.getSound(args[2]) == null){ - player.sendMessage(Component.text("| The provided sound is not a vanilla Minecraft sound!", NamedTextColor.GRAY)); + player.sendMessage(Component.text("| The provided sound is not a vanilla Minecraft sound, or does not exist in this game version!", NamedTextColor.GRAY)); } } catch (NumberFormatException | IndexOutOfBoundsException e) { player.sendMessage(Component.text("Invalid number entered! Enter a number >= 0", NamedTextColor.RED)); From b8aefb4c7208c113a6c793d0d45158ef9e51d7ba Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 18:57:30 -0600 Subject: [PATCH 080/139] Fix missed merge differences --- .../command/anim/AnimAddSoundCMD.java | 5 ++--- .../convert/datapack/BDEngineDPConverter.java | 12 ++++++------ pom.xml | 6 +++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java index 9758c68e..31a0fbbc 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java @@ -5,7 +5,7 @@ import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayAnimationManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.AnimationSound; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayAnimation; import net.donnypz.displayentityutils.utils.relativepoints.FramePointSelector; import net.donnypz.displayentityutils.utils.relativepoints.RelativePointSelector; @@ -14,7 +14,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.Sound; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -52,7 +51,7 @@ public void execute(Player player, String[] args) { float pitch = Float.parseFloat(args[4]); int delayInTicks = Integer.parseInt(args[5]); - display.getRelativePoint().addSound(new AnimationSound(soundStr, volume, pitch, delayInTicks)); + display.getRelativePoint().addSound(new DEUSound(soundStr, volume, pitch, delayInTicks)); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Sound Added to Frame Point!", NamedTextColor.GREEN))); player.sendMessage(MiniMessage.miniMessage().deserialize("| Sound: "+soundStr)); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java index 661a3be0..cb8d9e82 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java @@ -38,7 +38,7 @@ public class BDEngineDPConverter { private final String groupSaveTag; private final String animationSavePrefix; private final LinkedHashMap> animations = new LinkedHashMap<>(); - private final HashSet bufferedSounds = new HashSet<>(); + private final HashSet bufferedSounds = new HashSet<>(); Location spawnLoc; @@ -205,7 +205,7 @@ public void run() { //Add Sounds if (!bufferedSounds.isEmpty()){ FramePoint point = new FramePoint(FRAME_POINT_SOUND_TAG, createdGroup, spawnLoc); - for (AnimationSound sound : bufferedSounds){ + for (DEUSound sound : bufferedSounds){ point.addSound(sound); } bufferedSounds.clear(); @@ -291,13 +291,13 @@ else if (line.startsWith("schedule")) { //Animation Sound if (line.startsWith("playsound")){ - AnimationSound sound = getSound(line); + DEUSound sound = getSound(line); if (sound != null){ bufferedSounds.add(sound); } } else if (line.startsWith("execute") && line.contains("playsound")){ - AnimationSound sound = getSound("."+line.split(" playsound ")[1]); + DEUSound sound = getSound("."+line.split(" playsound ")[1]); if (sound != null){ bufferedSounds.add(sound); } @@ -337,7 +337,7 @@ private void setCameraVectorAndDirection(SpawnedDisplayAnimationFrame frame, Str } - AnimationSound getSound(String line){ + DEUSound getSound(String line){ String[] strings = line.split(" "); String soundStr = strings[1]; @@ -355,6 +355,6 @@ AnimationSound getSound(String line){ pitch = 1; } } - return new AnimationSound(soundStr, volume, pitch, 0); + return new DEUSound(soundStr, volume, pitch, 0); } } diff --git a/pom.xml b/pom.xml index 974dcd7a..ee864b91 100644 --- a/pom.xml +++ b/pom.xml @@ -143,8 +143,8 @@ - md_5-public - https://repo.md-5.net/content/groups/public/ + libsdisguises-public + https://mvn.lib.co.nz/public @@ -158,7 +158,7 @@ com.github.retrooper packetevents-spigot - 2.9.5 + 2.11.0 provided From 6af89567e6c880aefbb82dd61f4b1400e57f8cf7 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 25 Dec 2025 20:41:18 -0600 Subject: [PATCH 081/139] Add "/deu mannequin pivot" --- .../command/Permission.java | 1 + .../command/mannequin/MannequinCMD.java | 2 + .../command/mannequin/MannequinPivotCMD.java | 56 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPivotCMD.java diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index 19af6448..eb73756b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -87,6 +87,7 @@ public enum Permission { MANNEQUIN_NAME("deu.mannequin.name"), MANNEQUIN_NAME_VISIBLE("deu.mannequin.namevisible"), MANNEQUIN_POSE("deu.mannequin.pose"), + MANNEQUIN_PIVOT("deu.mannequin.pivot"), MANNEQUIN_SCALE("deu.mannequin.scale"), MANNEQUIN_GRAVITY("deu.mannequin.gravity"), MANNEQUIN_IMMOVABLE("deu.mannequin.immovable"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java index bb7f3724..74bd7855 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -16,6 +16,7 @@ public MannequinCMD() { new MannequinToggleNameVisibilityCMD(this); new MannequinSkinCMD(this); new MannequinPoseCMD(this); + new MannequinPivotCMD(this); new MannequinScaleCMD(this); new MannequinToggleGravityCMD(this); new MannequinToggleImmovableCMD(this); @@ -59,6 +60,7 @@ static void help(CommandSender sender, int page){ else{ CMDUtils.sendCMD(sender, "/deu mannequin equipment ", "Open a GUI to edit your selected mannequin's equipment."); CMDUtils.sendCMD(sender, "/deu mannequin mainhand ", "Set your selected mannequin's main hand"); + CMDUtils.sendCMD(sender, "/deu mannequin pivot [-all]"); CMDUtils.sendCMD(sender, "/deu mannequin pose [-all]", "Change your selected mannequin's pose"); CMDUtils.sendCMD(sender, "/deu mannequin scale [-all]", "Set your selected mannequin's scale"); CMDUtils.sendCMD(sender, "/deu mannequin clone", "Clone a mannequin"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPivotCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPivotCMD.java new file mode 100644 index 00000000..ee4e4777 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPivotCMD.java @@ -0,0 +1,56 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinPivotCMD extends PartsSubCommand { + MannequinPivotCMD(@NotNull DEUSubCommand parentSubCommand) { + super("pivot", parentSubCommand, Permission.MANNEQUIN_PIVOT, 3, 3); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin pivot [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + try{ + float angle = Float.parseFloat(args[2]); + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; + p.pivot(angle); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivoted ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + sendIncorrectUsage(player); + return false; + } + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + try{ + float angle = Float.parseFloat(args[2]); + selectedPart.pivot(angle); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivot applied to mannequin!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + sendIncorrectUsage(player); + return false; + } + } +} From 0bb289cff31e8543dfc4a4eceaf68829dc910974 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 26 Dec 2025 20:21:36 -0600 Subject: [PATCH 082/139] Corrected pose output and entity attributedisplayattribute input/output --- .../utils/DisplayEntities/MannequinEntity.java | 1 + .../utils/DisplayEntities/SavedEntityBuilder.java | 2 +- .../attributes/AttributeDisplayAttribute.java | 6 +++--- .../packet/attributes/DisplayAttributes.java | 3 ++- .../packet/attributes/PoseDisplayAttribute.java | 15 +++++++++++---- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java index f0817265..21c675ca 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java @@ -43,6 +43,7 @@ final class MannequinEntity implements Serializable { PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings settings){ PacketAttributeContainer attributeContainer = new PacketAttributeContainer() + .setAttribute(DisplayAttributes.Mannequin.SCALE, (float) scale) .setAttribute(DisplayAttributes.Mannequin.IMMOVABLE, true) .setAttribute(DisplayAttributes.Mannequin.NO_GRAVITY, true) .setAttribute(DisplayAttributes.CUSTOM_NAME, customName != null ? MiniMessage.miniMessage().deserialize(customName): null) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java index ea612900..5fdf35e2 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java @@ -82,7 +82,7 @@ static MannequinEntity buildMannequin(PacketDisplayEntityPart part){ mannequinEntity.profileUUID = profile.uuid(); } - mannequinEntity.scale = c.getAttributeOrDefault(DisplayAttributes.Mannequin.SCALE, 1.0); + mannequinEntity.scale = c.getAttributeOrDefault(DisplayAttributes.Mannequin.SCALE, 1.0f); Pose pose = part.getMannequinPose(); if (pose == null){ pose = Pose.STANDING; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java index 94e7e3c7..f7766982 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java @@ -3,11 +3,11 @@ import com.github.retrooper.packetevents.protocol.attribute.Attribute; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -public class AttributeDisplayAttribute extends DisplayAttribute{ +public class AttributeDisplayAttribute extends DisplayAttribute{ Attribute attribute; protected AttributeDisplayAttribute(Attribute attribute) { - super(0, Double.class, EntityDataTypes.FLOAT); + super(0, Float.class, EntityDataTypes.FLOAT); this.attribute = attribute; setAttributeType(AttributeType.ATTRIBUTE); } @@ -17,7 +17,7 @@ public Attribute getAttribute() { } @Override - public Double getOutputValue(Double value) { + public Float getOutputValue(Float value) { return value; } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java index 1e288714..2fb8bbe2 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java @@ -15,6 +15,7 @@ public final class DisplayAttributes { public static final OptionalComponentDisplayAttribute CUSTOM_NAME = new OptionalComponentDisplayAttribute(2); public static final BasicDisplayAttribute CUSTOM_NAME_VISIBLE = new BasicDisplayAttribute<>(3, Boolean.class, EntityDataTypes.BOOLEAN); + private DisplayAttributes(){} public static final class Equipment{ public static final EquipmentAttribute HELMET = new EquipmentAttribute(EquipmentSlot.HELMET); @@ -111,8 +112,8 @@ public static final class Interaction{ } public static final class Mannequin{ - public static final BasicDisplayAttribute NO_GRAVITY = new BasicDisplayAttribute<>(5, Boolean.class, EntityDataTypes.BOOLEAN); public static final AttributeDisplayAttribute SCALE = new AttributeDisplayAttribute(Attributes.SCALE); + public static final BasicDisplayAttribute NO_GRAVITY = new BasicDisplayAttribute<>(5, Boolean.class, EntityDataTypes.BOOLEAN); public static final PoseDisplayAttribute POSE = new PoseDisplayAttribute(6); public static final MainHandDisplayAttribute MAIN_HAND = new MainHandDisplayAttribute(15); public static final ResolvableProfileDisplayAttribute RESOLVABLE_PROFILE = new ResolvableProfileDisplayAttribute(17); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java index 06ad7a78..d78242af 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java @@ -1,15 +1,22 @@ package net.donnypz.displayentityutils.utils.packet.attributes; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose; import org.bukkit.entity.Pose; -public class PoseDisplayAttribute extends DisplayAttribute{ +public class PoseDisplayAttribute extends DisplayAttribute{ PoseDisplayAttribute(int index) { - super(index, Pose.class, Integer.class, EntityDataTypes.INT); + super(index, Pose.class, EntityPose.class, EntityDataTypes.ENTITY_POSE); } @Override - public Integer getOutputValue(Pose pose) { - return pose == null ? Pose.STANDING.ordinal() : pose.ordinal(); + public EntityPose getOutputValue(Pose pose) { + if (pose == null) return EntityPose.STANDING; + try{ + return EntityPose.valueOf(pose.name()); + } + catch(IllegalArgumentException e){ + return EntityPose.STANDING; + } } } From ecadfd763cfc40dc7418aa3233b6e10f7fc05930 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 26 Dec 2025 20:26:05 -0600 Subject: [PATCH 083/139] Corrected pose output and entity attributedisplayattribute input/output --- .../utils/DisplayEntities/PacketDisplayEntityPart.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index adf70d87..34a6643a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -555,7 +555,7 @@ public void setMannequinPose(Pose pose) { @Override public void setMannequinScale(double scale) { if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; - setAndSend(DisplayAttributes.Mannequin.SCALE, scale); + setAndSend(DisplayAttributes.Mannequin.SCALE, (float) scale); } @Override From 163150e191ec40c9539985701d507258e29568d6 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 26 Dec 2025 20:35:11 -0600 Subject: [PATCH 084/139] Properly save and load mannequin profiles --- .../DisplayEntities/MannequinEntity.java | 56 ++++++++++++++++--- .../DisplayEntities/SavedEntityBuilder.java | 48 ++++++++++++---- .../DisplayEntities/SavedEntityLoader.java | 44 +++++++++++++-- .../ResolvableProfileDisplayAttribute.java | 31 ++++++---- 4 files changed, 147 insertions(+), 32 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java index 21c675ca..d80d9096 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java @@ -1,6 +1,5 @@ package net.donnypz.displayentityutils.utils.DisplayEntities; -import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.utils.DisplayUtils; import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; @@ -18,6 +17,7 @@ import java.io.IOException; import java.io.Serial; import java.io.Serializable; +import java.util.List; import java.util.UUID; @@ -32,6 +32,12 @@ final class MannequinEntity implements Serializable { String description; String profileName; UUID profileUUID; + List profileProperties; + String profileSkinPatchBody; + String profileSkinPatchCape; + String profileSkinPatchElytra; + String profileSkinPatchModel; + double scale; String pose; boolean isRightMainHand; @@ -46,13 +52,7 @@ PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings set .setAttribute(DisplayAttributes.Mannequin.SCALE, (float) scale) .setAttribute(DisplayAttributes.Mannequin.IMMOVABLE, true) .setAttribute(DisplayAttributes.Mannequin.NO_GRAVITY, true) - .setAttribute(DisplayAttributes.CUSTOM_NAME, customName != null ? MiniMessage.miniMessage().deserialize(customName): null) .setAttribute(DisplayAttributes.CUSTOM_NAME_VISIBLE, customNameVisible) - .setAttribute(DisplayAttributes.Mannequin.BELOW_NAME, description != null ? MiniMessage.miniMessage().deserialize(description): null) - .setAttribute(DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, ResolvableProfile.resolvableProfile() - .name(profileName) - .uuid(profileUUID) - .build()) .setAttribute(DisplayAttributes.Mannequin.POSE, Pose.valueOf(pose)) .setAttribute(DisplayAttributes.Mannequin.MAIN_HAND, isRightMainHand ? MainHand.RIGHT : MainHand.LEFT) .setAttribute(DisplayAttributes.Equipment.HELMET, getHelmet()) @@ -62,6 +62,22 @@ PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings set .setAttribute(DisplayAttributes.Equipment.MAIN_HAND, getMainHand()) .setAttribute(DisplayAttributes.Equipment.OFF_HAND, getOffHand()); + if (customName != null){ + attributeContainer.setAttribute(DisplayAttributes.CUSTOM_NAME, MiniMessage.miniMessage().deserialize(customName)); + } + + if (description != null){ + attributeContainer.setAttribute(DisplayAttributes.Mannequin.BELOW_NAME, MiniMessage.miniMessage().deserialize(description)); + } + + if (profileName != null || profileUUID != null){ + attributeContainer + .setAttribute( + DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, + SavedEntityLoader.getMannequinProfile(this) + ); + } + Location spawnLoc = DisplayUtils.getPivotLocation( vector, origin, @@ -114,7 +130,31 @@ Vector getVector(){ } ItemStack getItemStack(byte[] itemStack){ - if (itemStack == null) return ItemStack.of(Material.AIR); + if (itemStack == null) return new ItemStack(Material.AIR); return ItemStack.deserializeBytes(itemStack); } + + static class ProfileProperty implements Serializable{ + + @Serial + private static final long serialVersionUID = 99L; + + String name; + String value; + String signature; + + ProfileProperty(com.destroystokyo.paper.profile.ProfileProperty property){ + this(property.getName(), property.getValue(), property.getSignature()); + } + + ProfileProperty(String name, String value, String signature){ + this.name = name; + this.value = value; + this.signature = signature; + } + + com.destroystokyo.paper.profile.ProfileProperty toBukkitProperty(){ + return new com.destroystokyo.paper.profile.ProfileProperty(name, value, signature); + } + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java index 5fdf35e2..7ef6902b 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java @@ -1,10 +1,12 @@ package net.donnypz.displayentityutils.utils.DisplayEntities; +import com.destroystokyo.paper.profile.ProfileProperty; import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.utils.DisplayUtils; import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Material; @@ -17,9 +19,12 @@ import org.bukkit.inventory.MainHand; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; +import org.bukkit.profile.PlayerTextures; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; +import java.util.List; class SavedEntityBuilder { @@ -34,11 +39,7 @@ static MannequinEntity buildMannequin(Entity entity){ //Accept entity instead of Component description = mannequin.getDescription(); mannequinEntity.description = description != null ? MiniMessage.miniMessage().serialize(description) : null; - ResolvableProfile profile = mannequin.getProfile(); - if (profile != null){ - mannequinEntity.profileName = profile.name(); - mannequinEntity.profileUUID = profile.uuid(); - } + setProfileFields(mannequinEntity, mannequin.getProfile()); mannequinEntity.scale = mannequin.getAttribute(Attribute.SCALE).getBaseValue(); mannequinEntity.pose = mannequin.getPose().name(); @@ -76,11 +77,7 @@ static MannequinEntity buildMannequin(PacketDisplayEntityPart part){ Component description = part.getMannequinBelowName(); mannequinEntity.description = description != null ? MiniMessage.miniMessage().serialize(description) : null; - ResolvableProfile profile = part.getMannequinProfile(); - if (profile != null){ - mannequinEntity.profileName = profile.name(); - mannequinEntity.profileUUID = profile.uuid(); - } + setProfileFields(mannequinEntity, part.getMannequinProfile()); mannequinEntity.scale = c.getAttributeOrDefault(DisplayAttributes.Mannequin.SCALE, 1.0f); Pose pose = part.getMannequinPose(); @@ -119,4 +116,35 @@ static byte[] serializeItemStack(ItemStack itemStack){ if (itemStack == null || itemStack.isEmpty()) return null; return itemStack.serializeAsBytes(); } + + private static void setProfileFields(MannequinEntity mannequinEntity, ResolvableProfile profile){ + if (profile != null){ + mannequinEntity.profileName = profile.name(); + mannequinEntity.profileUUID = profile.uuid(); + + Collection bukkitProperties = profile.properties(); + if (bukkitProperties != null){ + List properties = new ArrayList<>(); + for (ProfileProperty prop : bukkitProperties){ + properties.add(new MannequinEntity.ProfileProperty(prop)); + } + mannequinEntity.profileProperties = properties; + } + + ResolvableProfile.SkinPatch skinPatch = profile.skinPatch(); + if (skinPatch.isEmpty()) { + return; + } + + Key body = skinPatch.body(); + Key cape = skinPatch.cape(); + Key elytra = skinPatch.elytra(); + PlayerTextures.SkinModel model = skinPatch.model(); + + if (body != null) mannequinEntity.profileSkinPatchBody = body.asString(); + if (cape != null) mannequinEntity.profileSkinPatchCape = cape.asString(); + if (elytra != null) mannequinEntity.profileSkinPatchElytra = elytra.asString(); + if (model != null) mannequinEntity.profileSkinPatchModel = model.name(); + } + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java index 12222b2b..3615d418 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java @@ -2,6 +2,7 @@ import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Location; import org.bukkit.attribute.Attribute; @@ -9,6 +10,7 @@ import org.bukkit.entity.Pose; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.MainHand; +import org.bukkit.profile.PlayerTextures; import java.io.IOException; @@ -26,10 +28,7 @@ static Mannequin spawnMannequin(Location origin, GroupSpawnSettings settings, Ma m.customName(mannequinEntity.customName != null ? MiniMessage.miniMessage().deserialize(mannequinEntity.customName): null); m.setDescription(mannequinEntity.description != null ? MiniMessage.miniMessage().deserialize(mannequinEntity.description) : null); - m.setProfile(ResolvableProfile.resolvableProfile() - .name(mannequinEntity.profileName) - .uuid(mannequinEntity.profileUUID) - .build()); + m.setProfile(getMannequinProfile(mannequinEntity)); m.getAttribute(Attribute.SCALE).setBaseValue(mannequinEntity.scale); m.setPose(Pose.valueOf(mannequinEntity.pose)); @@ -53,4 +52,41 @@ static Mannequin spawnMannequin(Location origin, GroupSpawnSettings settings, Ma settings.apply(m); }); } + + static ResolvableProfile getMannequinProfile(MannequinEntity mannequin){ + Key body = null; + Key cape = null; + Key elytra = null; + PlayerTextures.SkinModel model = null; + if (mannequin.profileSkinPatchBody != null){ + body = Key.key(mannequin.profileSkinPatchBody); + } + if (mannequin.profileSkinPatchCape != null){ + cape = Key.key(mannequin.profileSkinPatchCape); + } + if (mannequin.profileSkinPatchElytra != null){ + elytra = Key.key(mannequin.profileSkinPatchElytra); + } + if (mannequin.profileSkinPatchModel != null){ + model = PlayerTextures.SkinModel.valueOf(mannequin.profileSkinPatchModel); + } + + ResolvableProfile.Builder builder = ResolvableProfile.resolvableProfile() + .name(mannequin.profileName) + .uuid(mannequin.profileUUID) + .skinPatch(ResolvableProfile.SkinPatch.skinPatch() + .body(body) + .cape(cape) + .elytra(elytra) + .model(model) + .build()); + + if (mannequin.profileProperties != null){ + for (MannequinEntity.ProfileProperty prop : mannequin.profileProperties){ + builder.addProperty(prop.toBukkitProperty()); + } + } + + return builder.build(); + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java index a473d82c..3700db12 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java @@ -6,6 +6,7 @@ import com.github.retrooper.packetevents.protocol.player.PlayerModelType; import com.github.retrooper.packetevents.resources.ResourceLocation; import io.papermc.paper.datacomponent.item.ResolvableProfile; +import net.kyori.adventure.key.Key; import org.bukkit.profile.PlayerTextures; import java.util.ArrayList; @@ -21,25 +22,35 @@ protected ResolvableProfileDisplayAttribute(int index) { public ItemProfile getOutputValue(ResolvableProfile value) { String name = value.name(); UUID uuid = value.uuid(); - value.properties(); List properties = new ArrayList<>(); for (ProfileProperty prop : value.properties()){ properties.add(new ItemProfile.Property(prop.getName(), prop.getValue(), prop.getSignature())); } + ItemProfile.SkinPatch skinPatch; ResolvableProfile.SkinPatch bukkitSkinPatch = value.skinPatch(); - PlayerModelType modelType; - if (bukkitSkinPatch.model() == null){ - modelType = PlayerModelType.WIDE; + if (bukkitSkinPatch.isEmpty()){ + skinPatch = ItemProfile.SkinPatch.EMPTY; } else{ - modelType = (bukkitSkinPatch.model() == PlayerTextures.SkinModel.CLASSIC) ? PlayerModelType.WIDE : PlayerModelType.SLIM; + PlayerModelType modelType; + if (bukkitSkinPatch.model() == null){ + modelType = null; + } + else{ + modelType = (bukkitSkinPatch.model() == PlayerTextures.SkinModel.CLASSIC) ? PlayerModelType.WIDE : PlayerModelType.SLIM; + } + Key bodyKey = bukkitSkinPatch.body(); + Key capeKey = bukkitSkinPatch.cape(); + Key elytraKey = bukkitSkinPatch.elytra(); + + skinPatch = new ItemProfile.SkinPatch( + bodyKey == null ? null : new ResourceLocation(bodyKey), + capeKey == null ? null : new ResourceLocation(capeKey), + elytraKey == null ? null : new ResourceLocation(elytraKey), + modelType); } - ItemProfile.SkinPatch skinPatch = new ItemProfile.SkinPatch( - new ResourceLocation(bukkitSkinPatch.body()), - new ResourceLocation(bukkitSkinPatch.cape()), - new ResourceLocation(bukkitSkinPatch.elytra()), - modelType); + return new ItemProfile(name, uuid, properties, skinPatch); } } From 5c3db8bdad2ae17999292bd8b8ee678c902d8cb9 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 26 Dec 2025 20:35:17 -0600 Subject: [PATCH 085/139] No changes --- .../utils/DisplayEntities/DisplayEntityGroup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java index 3c8a304b..9d4a9ae7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java @@ -312,7 +312,7 @@ public String getTag() { packetGroup.addPartSilent(part); } - if (mannequinEntities != null){ + if (mannequinEntities != null){ //old models won't have this field for (MannequinEntity entity : mannequinEntities){ PacketDisplayEntityPart part = entity.createPacketPart(spawnLocation, settings); packetGroup.addPartSilent(part); From 86b81bcb4d29545a01f29cd465584277c26560b8 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 26 Dec 2025 20:49:56 -0600 Subject: [PATCH 086/139] Deselect group when despawning, regardless of group type --- .../displayentityutils/command/group/GroupDespawnCMD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java index 3c01de3e..93fd57c5 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java @@ -24,7 +24,6 @@ protected void sendIncorrectUsage(@NotNull Player player) {} protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @NotNull String[] args) { player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Despawned your selected display entity group!", NamedTextColor.GRAY))); if (group instanceof SpawnedDisplayEntityGroup sg){ - DisplayGroupManager.deselectGroup(player); sg.unregister(true, true); } else if (group instanceof PacketDisplayEntityGroup pg){ @@ -35,6 +34,7 @@ else if (group instanceof PacketDisplayEntityGroup pg){ pg.unregister(); } } + DisplayGroupManager.deselectGroup(player); DisplayEntityPluginCommand.hideRelativePoints(player); } } From 399242d53ed46d9ae6577426f4d522d92c52086a Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 27 Dec 2025 00:21:17 -0600 Subject: [PATCH 087/139] Fixed clone & toPacket pivoting due to mannequin addition error --- .../PacketDisplayEntityGroup.java | 27 +++++++----- .../PacketDisplayEntityPart.java | 4 +- .../SpawnedDisplayEntityGroup.java | 43 +++++++++---------- .../SpawnedDisplayEntityPart.java | 2 +- 4 files changed, 39 insertions(+), 37 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index 845c4cfc..27d762b2 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -695,23 +695,28 @@ public PacketDisplayEntityGroup clone(@NotNull Location location){ * @return a cloned {@link PacketDisplayEntityGroup} */ public PacketDisplayEntityGroup clone(@NotNull Location location, boolean playSpawnAnimation, boolean autoShow){ - //Reset Interaction pivot to 0 yaw - HashMap oldYaws = new HashMap<>(); - for (ActivePart part : this.getParts(SpawnedDisplayEntityPart.PartType.INTERACTION)){ - float oldYaw = part.getYaw(); - oldYaws.put(part, oldYaw); - part.pivot(-oldYaw); + //Reset pivot to 0 + float groupYaw = getLocation().getYaw(); + HashSet resettedParts = new HashSet<>(); + for (ActivePart part : groupParts.values()){ + if (part.isDisplay()) continue; + part.pivot(-groupYaw); + resettedParts.add(part); } + DisplayEntityGroup group = toDisplayEntityGroup(); + float newYaw = location.getYaw(); + location = location.clone(); + location.setYaw(0); PacketDisplayEntityGroup clone = group.createPacketGroup(location, GroupSpawnedEvent.SpawnReason.CLONE, playSpawnAnimation, autoShow); - //Restore Interaction Pivot - for (Map.Entry entry : oldYaws.entrySet()){ - ActivePart part = entry.getKey(); - float oldYaw = entry.getValue(); - part.pivot(oldYaw); + //Restore pivot + for (ActivePart part : resettedParts){ + part.pivot(groupYaw); } + + clone.setYaw(newYaw, true); if (this.isPersistent()) clone.setPersistent(true); return clone; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 34a6643a..c1cd3481 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -994,12 +994,12 @@ public float getYaw(){ } /** - * Pivot a non-display entity around its group's master part + * Pivot a non-display entity around its group\ * @param angleInDegrees the pivot angle */ @Override public void pivot(float angleInDegrees) { - if (!isDisplay()) return; + if (isDisplay() || group == null) return; pivot(getYaw(), getPitch(), angleInDegrees); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index 8018529f..39146014 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -1123,12 +1123,13 @@ public SpawnedDisplayEntityGroup clone(@NotNull Location location){ * @return a cloned {@link SpawnedDisplayEntityGroup} */ public SpawnedDisplayEntityGroup clone(@NotNull Location location, @NotNull GroupSpawnSettings settings){ - //Reset Interaction pivot to 0 yaw - HashMap oldYaws = new HashMap<>(); - for (SpawnedDisplayEntityPart part : this.getParts(SpawnedDisplayEntityPart.PartType.INTERACTION)){ - float oldYaw = part.getYaw(); - oldYaws.put(part, oldYaw); - part.pivot(-oldYaw); + //Reset pivot to 0 yaw + float groupYaw = getLocation().getYaw(); + HashSet resettedParts = new HashSet<>(); + for (ActivePart part : groupParts.values()){ + if (part.isDisplay()) continue; + part.pivot(-groupYaw); + resettedParts.add(part); } DisplayEntityGroup savedGroup = toDisplayEntityGroup(); @@ -1137,23 +1138,22 @@ public SpawnedDisplayEntityGroup clone(@NotNull Location location, @NotNull Grou location.setYaw(0); SpawnedDisplayEntityGroup cloned = savedGroup.spawn(location, GroupSpawnedEvent.SpawnReason.CLONE, settings); - //Restore Interaction Pivot - for (Map.Entry entry : oldYaws.entrySet()){ - SpawnedDisplayEntityPart part = entry.getKey(); - float oldYaw = entry.getValue(); - part.pivot(oldYaw); + //Restore pivot + for (ActivePart part : resettedParts){ + part.pivot(groupYaw); } + cloned.setYaw(newYaw, true); return cloned; } public PacketDisplayEntityGroup toPacket(@NotNull Location location, boolean playSpawnAnimation, boolean autoShow, boolean persistent){ - //Reset Interaction pivot to 0 yaw - HashMap oldYaws = new HashMap<>(); - for (SpawnedDisplayEntityPart part : this.getParts(SpawnedDisplayEntityPart.PartType.INTERACTION)){ - float oldYaw = part.getEntity().getYaw(); - oldYaws.put(part, oldYaw); - part.pivot(-oldYaw); + //Reset pivot to 0 yaw + float groupYaw = getLocation().getYaw(); + HashSet resettedParts = new HashSet<>(); + for (ActivePart part : groupParts.values()){ + part.pivot(-groupYaw); + resettedParts.add(part); } DisplayEntityGroup savedGroup = toDisplayEntityGroup(); @@ -1162,7 +1162,6 @@ public PacketDisplayEntityGroup toPacket(@NotNull Location location, boolean pla location.setYaw(0); PacketDisplayEntityGroup packetGroup; - if (persistent){ packetGroup = DisplayGroupManager.addPersistentPacketGroup(location, savedGroup, autoShow, GroupSpawnedEvent.SpawnReason.INTERNAL); } @@ -1170,11 +1169,9 @@ public PacketDisplayEntityGroup toPacket(@NotNull Location location, boolean pla packetGroup = savedGroup.createPacketGroup(location, GroupSpawnedEvent.SpawnReason.INTERNAL, playSpawnAnimation, autoShow); } - //Restore Interaction Pivot - for (Map.Entry entry : oldYaws.entrySet()){ - SpawnedDisplayEntityPart part = entry.getKey(); - float oldYaw = entry.getValue(); - part.pivot(oldYaw); + //Restore pivot + for (ActivePart part : resettedParts){ + part.pivot(groupYaw); } packetGroup.setYaw(newYaw, true); return packetGroup; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 885e898a..4736e1b5 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -719,7 +719,7 @@ void translateForce(Direction direction, float distance, int durationInTicks, in } /** - * Pivot a non-display entity around its group's master part + * Pivot a non-display entity around its group * @param angleInDegrees the pivot angle */ @Override From ced9db8f532548fea9d8955c48e82d2cf623f97a Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 27 Dec 2025 00:33:08 -0600 Subject: [PATCH 088/139] add "/deu mannequin unname" --- .../command/mannequin/MannequinCMD.java | 4 +- .../command/mannequin/MannequinUnnameCMD.java | 43 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java index 74bd7855..d9d46e9f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -12,6 +12,7 @@ public class MannequinCMD extends ConsoleUsableSubCommand { public MannequinCMD() { super(Permission.HELP, new MannequinHelpCMD()); new MannequinNameCMD(this); + new MannequinUnnameCMD(this); new MannequinBelowNameCMD(this); new MannequinToggleNameVisibilityCMD(this); new MannequinSkinCMD(this); @@ -51,13 +52,14 @@ static void help(CommandSender sender, int page){ sender.sendMessage(Component.text("| Commands with \"-all\" will apply the command to all mannequins within a part selection", NamedTextColor.GOLD)); CMDUtils.sendCMD(sender, "/deu mannequin help", "Get help for mannequins"); CMDUtils.sendCMD(sender, "/deu mannequin name ", "Set your selected mannequin's name"); + CMDUtils.sendCMD(sender, "/deu mannequin unname", "Remove your selected mannequin's name"); CMDUtils.sendCMD(sender, "/deu mannequin belowname ", "Set the text below your selected mannequin's name"); CMDUtils.sendCMD(sender, "/deu mannequin togglenamevisibility [-all ]", "Toggle the gravity of an mannequin"); CMDUtils.sendCMD(sender, "/deu mannequin skin [-all]", "Set your selected mannequin's skin"); CMDUtils.sendCMD(sender, "/deu mannequin togglegravity [-all ]", "Toggle the gravity of an mannequin"); - CMDUtils.sendCMD(sender, "/deu mannequin toggleimmovable [-all ]", "Toggle the immovability of an mannequin"); } else{ + CMDUtils.sendCMD(sender, "/deu mannequin toggleimmovable [-all ]", "Toggle the immovability of an mannequin"); CMDUtils.sendCMD(sender, "/deu mannequin equipment ", "Open a GUI to edit your selected mannequin's equipment."); CMDUtils.sendCMD(sender, "/deu mannequin mainhand ", "Set your selected mannequin's main hand"); CMDUtils.sendCMD(sender, "/deu mannequin pivot [-all]"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java new file mode 100644 index 00000000..750f93fd --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java @@ -0,0 +1,43 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.mannequin.ui.MannequinEquipmentGUI; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinUnnameCMD extends PartsSubCommand { + MannequinUnnameCMD(@NotNull DEUSubCommand parentSubCommand) { + super("unname", parentSubCommand, Permission.MANNEQUIN_NAME, 2, 2); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect usage! /deu mannequin unname [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + p.setCustomName(null); + } + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Name removed for ALL selected mannequins!", NamedTextColor.YELLOW))); + return false; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + selectedPart.setCustomName(null); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your selected mannequin's name has been removed!", NamedTextColor.YELLOW))); + return true; + } +} From 34b649a71c345eb47b7e19f24b9823ad6dc3cf4e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 27 Dec 2025 00:33:56 -0600 Subject: [PATCH 089/139] add "/deu mannequin unname" --- .../displayentityutils/command/mannequin/MannequinCMD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java index d9d46e9f..80646da0 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -52,7 +52,7 @@ static void help(CommandSender sender, int page){ sender.sendMessage(Component.text("| Commands with \"-all\" will apply the command to all mannequins within a part selection", NamedTextColor.GOLD)); CMDUtils.sendCMD(sender, "/deu mannequin help", "Get help for mannequins"); CMDUtils.sendCMD(sender, "/deu mannequin name ", "Set your selected mannequin's name"); - CMDUtils.sendCMD(sender, "/deu mannequin unname", "Remove your selected mannequin's name"); + CMDUtils.sendCMD(sender, "/deu mannequin unname [-all]", "Remove your selected mannequin's name"); CMDUtils.sendCMD(sender, "/deu mannequin belowname ", "Set the text below your selected mannequin's name"); CMDUtils.sendCMD(sender, "/deu mannequin togglenamevisibility [-all ]", "Toggle the gravity of an mannequin"); CMDUtils.sendCMD(sender, "/deu mannequin skin [-all]", "Set your selected mannequin's skin"); From 45aab60986177f06e13fa97ef76e005345842f10 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 27 Dec 2025 02:35:03 -0600 Subject: [PATCH 090/139] Update mannequin head yaw when updating body yaw --- .../PacketDisplayEntityPart.java | 32 +++++++++++++++---- .../packet/PacketAttributeContainer.java | 2 +- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index c1cd3481..ff97195e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -3,6 +3,7 @@ import com.destroystokyo.paper.profile.PlayerProfile; import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.util.Vector3d; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityHeadLook; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport; import io.papermc.paper.datacomponent.item.ResolvableProfile; @@ -958,9 +959,15 @@ public void setRotation(float pitch, float yaw, boolean pivot){ pivot(yaw, pitch); } else if (!viewers.isEmpty()){ + WrapperPlayServerEntityHeadLook headLook = getHeadLookPacket(yaw); WrapperPlayServerEntityRotation rotPacket = new WrapperPlayServerEntityRotation(getEntityId(), yaw, pitch, false); for (UUID uuid : getViewers()){ - PacketEvents.getAPI().getPlayerManager().sendPacket(Bukkit.getPlayer(uuid), rotPacket); + Player p = Bukkit.getPlayer(uuid); + if (p == null) continue; + PacketEvents.getAPI().getPlayerManager().sendPacket(p, rotPacket); + if (packetLocation.yaw != yaw && type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + PacketEvents.getAPI().getPlayerManager().sendPacket(p, headLook); + } } } packetLocation.pitch = pitch; @@ -1014,14 +1021,19 @@ private void pivot(float yaw, float pitch, float angleInDegrees){ packetLocation.setCoordinates(pivotedLoc); + WrapperPlayServerEntityHeadLook headLook = getHeadLookPacket(yaw); + WrapperPlayServerEntityTeleport teleport = new WrapperPlayServerEntityTeleport(getEntityId(), + new Vector3d(pivotedLoc.x(), pivotedLoc.y(), pivotedLoc.z()), + yaw, + pitch, + false); for (UUID uuid : getViewers()){ Player player = Bukkit.getPlayer(uuid); if (player == null) continue; - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityTeleport(getEntityId(), - new Vector3d(pivotedLoc.x(), pivotedLoc.y(), pivotedLoc.z()), - yaw, - pitch, - false)); + PacketEvents.getAPI().getPlayerManager().sendPacket(player, teleport); + if (type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + PacketEvents.getAPI().getPlayerManager().sendPacket(player, headLook); + } } } @@ -1231,6 +1243,14 @@ public void removeFromGroup(boolean unregister){ } } + private WrapperPlayServerEntityHeadLook getHeadLookPacket(float yaw){ + return new WrapperPlayServerEntityHeadLook(getEntityId(), yaw); + } + + private void sendHeadLookPacket(Player player, float yaw){ + PacketEvents.getAPI().getPlayerManager().sendPacket(player, getHeadLookPacket(yaw)); + } + static final class PacketLocation { String worldName; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java index d485767e..888a9549 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java @@ -410,7 +410,7 @@ private WrapperPlayServerSpawnEntity createEntityPacket(int entityId, SpawnedDis getEntityType(partType), //SpigotConversionUtil.fromBukkitLocation(getTrueLocation(partType, location)), SpigotConversionUtil.fromBukkitLocation(location), - 0, + location.getYaw(), 0, null); } From 9d39bb548af3d6fa9e0b73123bf3212f17cc80e5 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 28 Dec 2025 03:00:45 -0600 Subject: [PATCH 091/139] Added ActiveGroup#rotateDisplays & ActivePart#rotateDisplay --- .../utils/DisplayEntities/ActiveGroup.java | 11 ++++++++++ .../utils/DisplayEntities/ActivePart.java | 8 ++++++++ .../PacketDisplayEntityPart.java | 18 +++++++++++++++++ .../SpawnedDisplayEntityPart.java | 20 +++++++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java index 4edd56e1..3524de1d 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.Quaternionf; import java.util.*; @@ -213,6 +214,16 @@ public void setInterpolationDelay(int interpolationDelay){ } } + /** + * Rotate the display entities in this group + * @param rotation the rotation + */ + public void rotateDisplays(@NotNull Quaternionf rotation){ + for (ActivePart p : groupParts.values()){ + p.rotateDisplay(rotation, true); + } + } + /** * Change the yaw of this group * @param yaw The yaw to set for this group diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 17b305ae..85d259ee 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; +import org.joml.Quaternionf; import org.joml.Vector3f; import java.util.*; @@ -366,6 +367,13 @@ public void unglow(@NotNull Player player) { */ public abstract boolean setDisplayScale(float x, float y, float z); + /** + * Rotate this display entity part by a given quaternion + * @param rotation the rotation + * @param rotateTranslation whether the display's translation should be rotated, pivoting it around the entity's location + */ + public abstract void rotateDisplay(@NotNull Quaternionf rotation, boolean rotateTranslation); + /** * Set the text of this part if its type is {@link SpawnedDisplayEntityPart.PartType#TEXT_DISPLAY}. * @param text the text diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index ff97195e..e065beeb 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -336,6 +336,24 @@ public boolean setDisplayScale(float x, float y, float z) { return true; } + @Override + public void rotateDisplay(@NotNull Quaternionf rotation, boolean rotateTranslation) { + if (!isDisplay()) return; + Vector3f translation = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.TRANSLATION, new Vector3f()); + Quaternionf originalRot = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.LEFT_ROTATION, new Quaternionf()); + + //World Space Rot + if (rotateTranslation){ + translation.rotate(rotation); + } + + rotation.mul(originalRot, originalRot); + + attributeContainer.setAttributesAndSend(new DisplayAttributeMap() + .add(DisplayAttributes.Transform.TRANSLATION, translation) + .add(DisplayAttributes.Transform.LEFT_ROTATION, originalRot), getEntityId(), viewers); + } + @Override public void setTextDisplayText(@NotNull Component text) { diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 4736e1b5..ece50674 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; +import org.joml.Quaternionf; import org.joml.Vector3f; import java.util.*; @@ -569,6 +570,25 @@ public boolean setDisplayScale(float x, float y, float z){ return true; } + @Override + public void rotateDisplay(@NotNull Quaternionf rotation, boolean rotateTranslation) { + if (!isDisplay()) return; + Display display = (Display) getEntity(); + if (display == null) return; + Transformation t = getTransformation(); + Vector3f translation = t.getTranslation(); + Quaternionf originalRot = t.getLeftRotation(); + + //World Space Rot + if (rotateTranslation){ + translation.rotate(rotation); + } + + rotation.mul(originalRot, originalRot); + + Transformation newT = new Transformation(translation, originalRot, t.getScale(), t.getRightRotation()); + display.setTransformation(newT); + } /** * Set the brightness of this part From a0d49d9c25d5b8c5da2a2724b4c83112a2056cef Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 28 Dec 2025 03:06:03 -0600 Subject: [PATCH 092/139] Update "/deu place" permissions --- .../java/net/donnypz/displayentityutils/command/Permission.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index eb73756b..dee59990 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -37,6 +37,8 @@ public enum Permission { PLACE_SET_ITEM("deu.place.setitem"), PLACE_TOGGLE_PACKET("deu.place.togglepacket"), PLACE_TOGGLE_FACING("deu.place.togglefacing"), + PLACE_TOGGLE_PACKET("deu.place.toggle.packet"), + PLACE_TOGGLE_FACING("deu.place.toggle.playerfacing"), PLACE_SET_PERMISSION("deu.place.setpermission"), From ee7f5ef96ce69f953b23f821e3889cc5774acc2c Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 28 Dec 2025 03:29:35 -0600 Subject: [PATCH 093/139] Added "/deu place toggleblockface", toggling block face respect for placeable groups --- .../displayentityutils/DisplayAPI.java | 7 ++- .../managers/PlaceableGroupManager.java | 44 ++++++++++++++++--- .../DisplayEntityPlugin.java | 7 +-- .../command/Permission.java | 5 +-- .../command/place/PlaceCMD.java | 22 ++++++---- .../place/PlaceToggleBlockFaceCMD.java | 33 ++++++++++++++ .../place/PlaceTogglePlayerFacingCMD.java | 2 +- .../player/DEUPlayerPlaceBlockListener.java | 31 +++++++++++-- 8 files changed, 126 insertions(+), 25 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleBlockFaceCMD.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java index 95874277..4f0ba79e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java +++ b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java @@ -31,6 +31,7 @@ public final class DisplayAPI { static NamespacedKey placeableGroupPacketBasedKey; static NamespacedKey placeableGroupPermissionKey; static NamespacedKey placeableGroupRespectFacingKey; + static NamespacedKey placeableGroupRespectBlockFace; static boolean isMythicMobsInstalled; static boolean isLibsDisguisesInstalled; @@ -101,10 +102,14 @@ private DisplayAPI(){} return placeableGroupPermissionKey; } - public static @NotNull NamespacedKey getPlaceableGroupRespectFacing(){ + public static @NotNull NamespacedKey getPlaceableGroupRespectPlayerFacing(){ return placeableGroupRespectFacingKey; } + public static @NotNull NamespacedKey getPlaceableGroupRespectBlockFace(){ + return placeableGroupRespectBlockFace; + } + @ApiStatus.Internal public static String getLegacyPartTagPrefix(){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index 73f81697..ba66dfde 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -15,6 +15,7 @@ import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.Quaternionf; public final class PlaceableGroupManager { @@ -34,7 +35,7 @@ public static void assign(@NotNull ItemStack itemStack, @NotNull String groupTag PersistentDataContainer pdc = meta.getPersistentDataContainer(); pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, spawnUsingPackets); - pdc.set(DisplayAPI.getPlaceableGroupRespectFacing(), PersistentDataType.BOOLEAN, true); + pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, true); itemStack.setItemMeta(meta); } @@ -63,7 +64,7 @@ public static void assign(@NotNull ItemStack itemStack, @NotNull String groupTag pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, spawnUsingPackets); pdc.set(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING, placePermission); - pdc.set(DisplayAPI.getPlaceableGroupRespectFacing(), PersistentDataType.BOOLEAN, true); + pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, true); itemStack.setItemMeta(meta); } @@ -87,7 +88,7 @@ public static void unassign(@NotNull ItemStack itemStack){ pdc.remove(DisplayAPI.getPlaceableGroupKey()); pdc.remove(DisplayAPI.getPlaceableGroupPacketBasedKey()); pdc.remove(DisplayAPI.getPlaceableGroupPermissionKey()); - pdc.remove(DisplayAPI.getPlaceableGroupRespectFacing()); + pdc.remove(DisplayAPI.getPlaceableGroupRespectPlayerFacing()); itemStack.setItemMeta(meta); } @@ -200,7 +201,7 @@ public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player pla public static void setRespectPlayerFacing(@NotNull ItemStack itemStack, boolean respect){ ItemMeta meta = itemStack.getItemMeta(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); - pdc.set(DisplayAPI.getPlaceableGroupRespectFacing(), PersistentDataType.BOOLEAN, respect); + pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, respect); itemStack.setItemMeta(meta); } @@ -211,7 +212,29 @@ public static void setRespectPlayerFacing(@NotNull ItemStack itemStack, boolean */ public static boolean isRespectingPlayerFacing(@NotNull ItemStack itemStack){ PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); - return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupRespectFacing(), PersistentDataType.BOOLEAN)); + return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN)); + } + + /** + * Set whether the group associated with the given item should spawn with respect to the block face its placed on + * @param itemStack the item + * @param respect whether the group should respect the block face its placed on + */ + public static void setRespectBlockFace(@NotNull ItemStack itemStack, boolean respect){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.set(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN, respect); + itemStack.setItemMeta(meta); + } + + /** + * Get whether the group associated with the given item will respect the block face its placed on + * @param itemStack the item + * @return a boolean + */ + public static boolean isRespectingBlockFace(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN)); } @@ -221,6 +244,15 @@ public static boolean isRespectingPlayerFacing(@NotNull ItemStack itemStack){ * @param spawnLocation the spawn location */ public static void spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @Nullable Player itemHolder){ + spawnGroup(itemStack, spawnLocation, new Quaternionf(), itemHolder); + } + + /** + * Spawn the {@link DisplayEntityGroup} associated with an item at a location + * @param itemStack the item + * @param spawnLocation the spawn location + */ + public static void spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @NotNull Quaternionf rotation, @Nullable Player itemHolder){ String tag = getAssignedGroupTag(itemStack); boolean isPacket = isSpawningPacketGroup(itemStack); if (tag == null) return; @@ -231,11 +263,13 @@ public static void spawnGroup(@NotNull ItemStack itemStack, @NotNull Location sp if (isPacket){ PacketDisplayEntityGroup pg = group.createPacketGroup(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK, true, true); pg.setPersistent(true); + pg.rotateDisplays(rotation); new ItemPlaceGroupEvent(pg, itemStack, itemHolder).callEvent(); } else{ DisplayAPI.getScheduler().run(() -> { SpawnedDisplayEntityGroup sg = group.spawn(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK); + sg.rotateDisplays(rotation); new ItemPlaceGroupEvent(sg, itemStack, itemHolder).callEvent(); }); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index e215cf7f..9557e54d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -88,9 +88,10 @@ private void initializeNamespacedKeys(){ //DO NOT CHANGE DisplayAPI.spawnAnimationLoadMethodKey = new NamespacedKey(this, "spawnanimationloader"); DisplayAPI.chunkPacketGroupsKey = new NamespacedKey(this, "chunkpacketgroups"); DisplayAPI.placeableGroupKey = new NamespacedKey(this, "placeablegroup"); - DisplayAPI.placeableGroupPacketBasedKey = new NamespacedKey(this, "placeablegrouppacketbased"); - DisplayAPI.placeableGroupPermissionKey = new NamespacedKey(this, "placeablegroupperm"); - DisplayAPI.placeableGroupRespectFacingKey = new NamespacedKey(this, "placeblegroupfacing"); + DisplayAPI.placeableGroupPacketBasedKey = new NamespacedKey(this, "placeablegroup_packet"); + DisplayAPI.placeableGroupPermissionKey = new NamespacedKey(this, "placeablegroup_perm"); + DisplayAPI.placeableGroupRespectFacingKey = new NamespacedKey(this, "placeblegroup_playerfacing"); + DisplayAPI.placeableGroupRespectFacingKey = new NamespacedKey(this, "placeblegroup_blockface"); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index dee59990..6166dbd7 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -35,10 +35,9 @@ public enum Permission { GROUP_WORLD_EDIT("deu.group.worldedit"), PLACE_SET_ITEM("deu.place.setitem"), - PLACE_TOGGLE_PACKET("deu.place.togglepacket"), - PLACE_TOGGLE_FACING("deu.place.togglefacing"), PLACE_TOGGLE_PACKET("deu.place.toggle.packet"), - PLACE_TOGGLE_FACING("deu.place.toggle.playerfacing"), + PLACE_TOGGLE_PLAYER_FACING("deu.place.toggle.playerfacing"), + PLACE_TOGGLE_BLOCK_FACE("deu.place.toggle.blockface"), PLACE_SET_PERMISSION("deu.place.setpermission"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java index c3674854..5ddc7f36 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -20,6 +20,7 @@ public PlaceCMD() { new PlaceUnsetPermissionCMD(this); new PlaceTogglePacketCMD(this); new PlaceTogglePlayerFacingCMD(this); + new PlaceToggleBlockFaceCMD(this); } @Override @@ -41,14 +42,19 @@ public void execute(CommandSender sender, String[] args) { static void help(CommandSender sender, int page){ sender.sendMessage(Component.empty()); sender.sendMessage(DisplayAPI.pluginPrefixLong); - CMDUtils.sendCMD(sender, "/deu place help", "Get help for placeable groups"); - CMDUtils.sendCMD(sender, "/deu place set ", "Assign a group to your held block, which will be spawned when the block is placed"); - CMDUtils.sendCMD(sender, "/deu place unset", "Unassign a group from your held block"); - CMDUtils.sendCMD(sender, "/deu place setpermission", "Set the permission required to place the group"); - CMDUtils.sendCMD(sender, "/deu place unsetpermission", "Set the permission required to place the group"); - CMDUtils.sendCMD(sender, "/deu place togglepacket", "Toggle whether the placed group will be packet-based. True by default"); - CMDUtils.sendCMD(sender, "/deu place togglerespectfacing", "Toggle whether the placed group will respect the player's facing direction. True by default"); - sender.sendMessage(MiniMessage.miniMessage().deserialize("--------------------------")); + if (page == 1){ + CMDUtils.sendCMD(sender, "/deu place help", "Get help for placeable groups"); + CMDUtils.sendCMD(sender, "/deu place set ", "Assign a group to your held block, which will be spawned when the block is placed"); + CMDUtils.sendCMD(sender, "/deu place unset", "Unassign a group from your held block"); + CMDUtils.sendCMD(sender, "/deu place setpermission", "Set the permission required to place the group"); + CMDUtils.sendCMD(sender, "/deu place unsetpermission", "Set the permission required to place the group"); + CMDUtils.sendCMD(sender, "/deu place togglepacket", "Toggle whether the placed group will be packet-based. True by default"); + CMDUtils.sendCMD(sender, "/deu place toggleplayerfacing", "Toggle whether the placed group will respect the player's facing direction. True by default"); + } + else{ + CMDUtils.sendCMD(sender, "/deu place toggleblockface", "Toggle whether the placed group will respect the block face it is placed on. True by default"); + } + sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } static ItemStack getHeldItem(Player player, boolean mustBeAssigned){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleBlockFaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleBlockFaceCMD.java new file mode 100644 index 00000000..e80933a6 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleBlockFaceCMD.java @@ -0,0 +1,33 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceToggleBlockFaceCMD extends PlayerSubCommand { + PlaceToggleBlockFaceCMD(@NotNull DEUSubCommand parentSubCommand) { + super("toggleblockface", parentSubCommand, Permission.PLACE_TOGGLE_BLOCK_FACE); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (PlaceableGroupManager.isRespectingBlockFace(heldItem)){ + PlaceableGroupManager.setRespectBlockFace(heldItem, false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will no longer respect the block face its placed on", NamedTextColor.RED))); + } + else{ + PlaceableGroupManager.setRespectBlockFace(heldItem, true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will respect the block face its placed on", NamedTextColor.GREEN))); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java index 18d4eb31..9e71843a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java @@ -13,7 +13,7 @@ class PlaceTogglePlayerFacingCMD extends PlayerSubCommand { PlaceTogglePlayerFacingCMD(@NotNull DEUSubCommand parentSubCommand) { - super("toggleplayerfacing", parentSubCommand, Permission.PLACE_TOGGLE_FACING); + super("toggleplayerfacing", parentSubCommand, Permission.PLACE_TOGGLE_PLAYER_FACING); } @Override diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java index 4e01989b..fe710ac6 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java @@ -4,12 +4,15 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Location; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; +import org.joml.Quaternionf; public class DEUPlayerPlaceBlockListener implements Listener { @@ -32,13 +35,33 @@ public void onPlaceBlock(BlockPlaceEvent e){ return; } - Location placeLoc = e.getBlockPlaced().getLocation(); - placeLoc.add(0.5, 0, 0.5); + BlockFace face = e.getBlockAgainst().getFace(e.getBlockPlaced()); + Quaternionf rot; + Location placeLoc; - if (PlaceableGroupManager.isRespectingPlayerFacing(heldItem)){ + if (face != null && PlaceableGroupManager.isRespectingBlockFace(heldItem)){ + Vector faceDir = face.getDirection(); + rot = getRotation(faceDir); + placeLoc = e.getBlockPlaced().getLocation() + .add(0.5f, 0.5f, 0.5f) + .subtract(faceDir.multiply(0.499)); + } + else{ + rot = new Quaternionf(); + placeLoc = e.getBlockPlaced().getLocation().add(0.5, 0, 0.5); + } + + + if ((face == BlockFace.UP || face == BlockFace.DOWN || face == BlockFace.SELF) && PlaceableGroupManager.isRespectingPlayerFacing(heldItem)){ placeLoc.setYaw(player.getYaw()+180); } - PlaceableGroupManager.spawnGroup(heldItem, placeLoc, player); + PlaceableGroupManager.spawnGroup(heldItem, placeLoc, rot, player); + + } + + private Quaternionf getRotation(Vector faceDir){ + Vector upVec = new Vector(0, 1, 0); + return upVec.toVector3f().rotationTo(faceDir.toVector3f(), new Quaternionf()); } } From e23a8a4ce9e40aa78f590861258ddb5e2f2062cc Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:12:01 -0600 Subject: [PATCH 094/139] correctly (un)set block face respect key --- .../displayentityutils/managers/PlaceableGroupManager.java | 1 + .../net/donnypz/displayentityutils/DisplayEntityPlugin.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index ba66dfde..ac562006 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -89,6 +89,7 @@ public static void unassign(@NotNull ItemStack itemStack){ pdc.remove(DisplayAPI.getPlaceableGroupPacketBasedKey()); pdc.remove(DisplayAPI.getPlaceableGroupPermissionKey()); pdc.remove(DisplayAPI.getPlaceableGroupRespectPlayerFacing()); + pdc.remove(DisplayAPI.getPlaceableGroupRespectBlockFace()); itemStack.setItemMeta(meta); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index 9557e54d..ab30124c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -91,7 +91,7 @@ private void initializeNamespacedKeys(){ //DO NOT CHANGE DisplayAPI.placeableGroupPacketBasedKey = new NamespacedKey(this, "placeablegroup_packet"); DisplayAPI.placeableGroupPermissionKey = new NamespacedKey(this, "placeablegroup_perm"); DisplayAPI.placeableGroupRespectFacingKey = new NamespacedKey(this, "placeblegroup_playerfacing"); - DisplayAPI.placeableGroupRespectFacingKey = new NamespacedKey(this, "placeblegroup_blockface"); + DisplayAPI.placeableGroupRespectBlockFace = new NamespacedKey(this, "placeblegroup_blockface"); } From b21e5682d3acf5416318b0da63837bd903f9c6f9 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 29 Dec 2025 03:38:00 -0600 Subject: [PATCH 095/139] Add a PlaceableGroupData class instead of setting data through the PlaceableGroupManager --- .../events/ItemPlaceGroupEvent.java | 4 +- .../events/PreItemPlaceGroupEvent.java | 2 +- .../managers/PlaceableGroupData.java | 99 ++++++++++ .../managers/PlaceableGroupManager.java | 177 ++++++++---------- .../command/place/PlaceSetCMD.java | 5 +- .../command/place/PlaceTogglePacketCMD.java | 6 +- 6 files changed, 189 insertions(+), 104 deletions(-) create mode 100644 api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java index 02b291c4..61ffd54e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java @@ -1,6 +1,6 @@ package net.donnypz.displayentityutils.events; -import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.managers.PlaceableGroupData; import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -12,7 +12,7 @@ /** * Called when a player places an {@link ActiveGroup} using an item that - * has an assigned group through {@link PlaceableGroupManager#assign(ItemStack, String, boolean)} (ItemStack, String)} or similar methods. + * has an assigned group with {@link PlaceableGroupData}. */ public class ItemPlaceGroupEvent extends Event { private static final HandlerList handlers = new HandlerList(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java index cf1eea2e..e67ca3ef 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java @@ -14,7 +14,7 @@ /** * Called before the stored {@link DisplayEntityGroup} on an item can be spawned when a player places the item's block or when - * {@link PlaceableGroupManager#spawnGroup(ItemStack, Location, Player)} is called. + * {@link PlaceableGroupManager#spawnGroup(ItemStack, Location, Player)} or similar is called. */ public class PreItemPlaceGroupEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java new file mode 100644 index 00000000..481c95e5 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java @@ -0,0 +1,99 @@ +package net.donnypz.displayentityutils.managers; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + + +/** + * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. + */ +public class PlaceableGroupData { + + String groupTag; + String permission; + boolean packetBased = true; + boolean respectPlayerFacing = true; + boolean respectBlockFace = true; + + + public PlaceableGroupData(@NotNull String groupTag) { + this.groupTag = groupTag; + } + + /** + * Set the group that should be spawned when the block is placed + * @param groupTag the group's tag + * @return this + */ + public PlaceableGroupData setGroupTag(@NotNull String groupTag){ + this.groupTag = groupTag; + return this; + } + + /** + * Set the required permission to spawn the group when the block is placed + * @param permission the permission + * @return this + */ + public PlaceableGroupData setPermission(@Nullable String permission) { + this.permission = permission; + return this; + } + + /** + * Set whether the group should be packet-based when spawned. True by default + * @param packetBased + * @return this + */ + public PlaceableGroupData setPacketBased(boolean packetBased) { + this.packetBased = packetBased; + return this; + } + + /** + * Set whether the group should spawn with respect to the player's facing direction. True by default + * @param respectPlayerFacing whether the group should respect the player's facing direction + * @return this + */ + public PlaceableGroupData setRespectPlayerFacing(boolean respectPlayerFacing) { + this.respectPlayerFacing = respectPlayerFacing; + return this; + } + + /** + * Set whether the group associated with the given item should spawn with respect to the block face its placed on. True by default + * @param respectBlockFace whether the group should respect the block face its placed on + * @return this + */ + public PlaceableGroupData setRespectBlockFace(boolean respectBlockFace) { + this.respectBlockFace = respectBlockFace; + return this; + } + + /** + * Apply the data to a provided itemstack, spawning the group when placed + * @param itemStack + * @throws IllegalArgumentException if the itemstack is not of a block type + */ + public void apply(@NotNull ItemStack itemStack){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + + pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); + pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, packetBased); + + if (permission != null){ + pdc.set(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING, permission); + } + + pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, respectPlayerFacing); + pdc.set(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN, respectBlockFace); + itemStack.setItemMeta(meta); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index ac562006..52a9b3e5 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -4,6 +4,7 @@ import net.donnypz.displayentityutils.events.GroupSpawnedEvent; import net.donnypz.displayentityutils.events.ItemPlaceGroupEvent; import net.donnypz.displayentityutils.events.PreItemPlaceGroupEvent; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; @@ -17,65 +18,90 @@ import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; +import java.util.concurrent.CompletableFuture; + public final class PlaceableGroupManager { private PlaceableGroupManager(){} /** - * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. - * @param itemStack the item - * @param groupTag the tag of the group that will be associated with the item - * @throws IllegalArgumentException if the given itemstack is not a block + * Set the group that will spawn where an itemstack of a block type is placed. + * @param itemStack the itemstack + * @param group the group + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} */ - public static void assign(@NotNull ItemStack itemStack, @NotNull String groupTag, boolean spawnUsingPackets){ - if (!itemStack.getType().isBlock()){ - throw new IllegalArgumentException("The provided ItemStack is not a block type"); - } + public static void setGroup(@NotNull ItemStack itemStack, @NotNull DisplayEntityGroup group){ + setGroup(itemStack, group.getTag()); + } + + /** + * Set the group that will spawn where an itemstack of a block type is placed. + * @param itemStack the itemstack + * @param groupTag the group's tag + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied through a {@link PlaceableGroupData} + */ + public static void setGroup(@NotNull ItemStack itemStack, @NotNull String groupTag){ ItemMeta meta = itemStack.getItemMeta(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); - pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, spawnUsingPackets); - pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, true); itemStack.setItemMeta(meta); } /** - * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. + * Set whether the group associated with the given item should spawn as a {@link PacketDisplayEntityGroup} * @param itemStack the item - * @param group the group that will be associated with the item - * @throws IllegalArgumentException if the item is not a block + * @param packet whether the group should spawn pack-based + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} */ - public static void assign(@NotNull ItemStack itemStack, @NotNull DisplayEntityGroup group, boolean spawnUsingPackets){ - assign(itemStack, group.getTag(), spawnUsingPackets); + public static void setUsePackets(@NotNull ItemStack itemStack, boolean packet){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, packet); + itemStack.setItemMeta(meta); } /** - * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. + * Set the permission a player needs to place an itemstack's assigned group. Set the permission to {@code null} to unset it * @param itemStack the item - * @param groupTag the tag of the group that will be associated with the item - * @throws IllegalArgumentException if the given itemstack is not a block + * @param placePermission the permission + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} */ - public static void assign(@NotNull ItemStack itemStack, @NotNull String groupTag, boolean spawnUsingPackets, @NotNull String placePermission){ - if (!itemStack.getType().isBlock()){ - throw new IllegalArgumentException("The provided ItemStack is not a block type"); + public static void setPlacePermission(@NotNull ItemStack itemStack, @Nullable String placePermission){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + if (placePermission == null){ + pdc.remove(DisplayAPI.getPlaceableGroupPermissionKey()); + } + else{ + pdc.set(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING, placePermission); } + itemStack.setItemMeta(meta); + } + + /** + * Set whether the group associated with the given item should spawn with respect to the player's facing direction + * @param itemStack the item + * @param respect whether the group should respect the player's facing direction + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void setRespectPlayerFacing(@NotNull ItemStack itemStack, boolean respect){ ItemMeta meta = itemStack.getItemMeta(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); - pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); - pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, spawnUsingPackets); - pdc.set(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING, placePermission); - pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, true); + pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, respect); itemStack.setItemMeta(meta); } /** - * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. + * Set whether the group associated with the given item should spawn with respect to the block face its placed on * @param itemStack the item - * @param group the group that will be associated with the item - * @throws IllegalArgumentException if the item is not a block + * @param respect whether the group should respect the block face its placed on + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} */ - public static void assign(@NotNull ItemStack itemStack, @NotNull DisplayEntityGroup group, boolean spawnUsingPackets, @NotNull String placePermission){ - assign(itemStack, group.getTag(), spawnUsingPackets, placePermission); + public static void setRespectBlockFace(@NotNull ItemStack itemStack, boolean respect){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.set(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN, respect); + itemStack.setItemMeta(meta); } /** @@ -94,7 +120,7 @@ public static void unassign(@NotNull ItemStack itemStack){ } /** - * Check if a item has an assigned {@link DisplayEntityGroup} + * Check if an item has an assigned {@link DisplayEntityGroup} * @param itemStack the item * @return a boolean */ @@ -116,51 +142,24 @@ public static boolean hasAssignedGroup(@NotNull ItemStack itemStack){ /** * Get the {@link DisplayEntityGroup} assigned to an {@link ItemStack} based on the group tag stored on the item * @param itemStack the item - * @return the group's tag or null + * @return the {@link DisplayEntityGroup} or null if the group doesn't exist or if the item doesn't have placeable group data */ public static @Nullable DisplayEntityGroup getAssignedGroup(@NotNull ItemStack itemStack){ String tag = getAssignedGroupTag(itemStack); return tag == null ? null : DisplayGroupManager.getGroup(tag); } - /** - * Set whether the group associated with the given item should spawn as a {@link PacketDisplayEntityGroup} - * @param itemStack the item - * @param packet whether the group should spawn pack-based - */ - public static void setSpawnPacketGroup(@NotNull ItemStack itemStack, boolean packet){ - ItemMeta meta = itemStack.getItemMeta(); - PersistentDataContainer pdc = meta.getPersistentDataContainer(); - pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, packet); - itemStack.setItemMeta(meta); - } /** * Get whether the group associated with the given item will spawn as a {@link PacketDisplayEntityGroup} * @param itemStack the item * @return a boolean */ - public static boolean isSpawningPacketGroup(@NotNull ItemStack itemStack){ + public static boolean isUsingPackets(@NotNull ItemStack itemStack){ PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN)); } - /** - * Set the permission a player needs to place an itemstack's assigned group. Set the permission to {@code null} to unset it - * @param itemStack the item - * @param placePermission the permission - */ - public static void setPlacePermission(@NotNull ItemStack itemStack, @Nullable String placePermission){ - ItemMeta meta = itemStack.getItemMeta(); - PersistentDataContainer pdc = meta.getPersistentDataContainer(); - if (placePermission == null){ - pdc.remove(DisplayAPI.getPlaceableGroupPermissionKey()); - } - else{ - pdc.set(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING, placePermission); - } - itemStack.setItemMeta(meta); - } /** * Check if an itemstack has a place permission, determining if a player can place its assigned group @@ -175,7 +174,7 @@ public static boolean hasPlacePermission(@NotNull ItemStack itemStack){ /** * Get the permission that determines whether a player can place an itemstack's assigned group * @param itemStack the item - * @return a String or null + * @return the permission or null if the item doesn't have placeable group data */ public static @Nullable String getPlacePermission(@NotNull ItemStack itemStack){ PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); @@ -194,18 +193,6 @@ public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player pla return player.hasPermission(placePerm); } - /** - * Set whether the group associated with the given item should spawn with respect to the player's facing direction - * @param itemStack the item - * @param respect whether the group should respect the player's facing direction - */ - public static void setRespectPlayerFacing(@NotNull ItemStack itemStack, boolean respect){ - ItemMeta meta = itemStack.getItemMeta(); - PersistentDataContainer pdc = meta.getPersistentDataContainer(); - pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, respect); - itemStack.setItemMeta(meta); - } - /** * Get whether the group associated with the given item will respect the player's facing direction * @param itemStack the item @@ -216,18 +203,6 @@ public static boolean isRespectingPlayerFacing(@NotNull ItemStack itemStack){ return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN)); } - /** - * Set whether the group associated with the given item should spawn with respect to the block face its placed on - * @param itemStack the item - * @param respect whether the group should respect the block face its placed on - */ - public static void setRespectBlockFace(@NotNull ItemStack itemStack, boolean respect){ - ItemMeta meta = itemStack.getItemMeta(); - PersistentDataContainer pdc = meta.getPersistentDataContainer(); - pdc.set(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN, respect); - itemStack.setItemMeta(meta); - } - /** * Get whether the group associated with the given item will respect the block face its placed on * @param itemStack the item @@ -240,40 +215,50 @@ public static boolean isRespectingBlockFace(@NotNull ItemStack itemStack){ /** - * Spawn the {@link DisplayEntityGroup} associated with an item at a location + * Spawn the placeable group stored on an item * @param itemStack the item * @param spawnLocation the spawn location + * @return an {@link ActiveGroup} or null if the itemstack does not contain placeable group data, or if the {@link PreItemPlaceGroupEvent} is cancelled */ - public static void spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @Nullable Player itemHolder){ - spawnGroup(itemStack, spawnLocation, new Quaternionf(), itemHolder); + public static @Nullable CompletableFuture> spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @Nullable Player itemHolder){ + return spawnGroup(itemStack, spawnLocation, new Quaternionf(), itemHolder); } /** - * Spawn the {@link DisplayEntityGroup} associated with an item at a location + * Spawn the placeable group stored on an item * @param itemStack the item * @param spawnLocation the spawn location + * @return a completable future with an {@link ActiveGroup}, or null if the itemstack does not contain placeable group data or if the {@link PreItemPlaceGroupEvent} is cancelled */ - public static void spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @NotNull Quaternionf rotation, @Nullable Player itemHolder){ + public static @Nullable CompletableFuture> spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @NotNull Quaternionf rotation, @Nullable Player itemHolder){ String tag = getAssignedGroupTag(itemStack); - boolean isPacket = isSpawningPacketGroup(itemStack); - if (tag == null) return; - DisplayAPI.getScheduler().runAsync(() -> { - DisplayEntityGroup group = DisplayGroupManager.getGroup(tag); - if (!new PreItemPlaceGroupEvent(group, itemStack, itemHolder).callEvent()) return; - if (group == null) return; + boolean isPacket = isUsingPackets(itemStack); + if (tag == null) return null; + + return CompletableFuture.supplyAsync(() -> { + return DisplayGroupManager.getGroup(tag); + }).thenCompose(group -> { + if (group == null) return CompletableFuture.completedFuture(null); + if (!new PreItemPlaceGroupEvent(group, itemStack, itemHolder).callEvent()) return CompletableFuture.completedFuture(null); + + CompletableFuture> result = new CompletableFuture<>(); + if (isPacket){ PacketDisplayEntityGroup pg = group.createPacketGroup(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK, true, true); pg.setPersistent(true); pg.rotateDisplays(rotation); new ItemPlaceGroupEvent(pg, itemStack, itemHolder).callEvent(); + result.complete(pg); } else{ DisplayAPI.getScheduler().run(() -> { SpawnedDisplayEntityGroup sg = group.spawn(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK); sg.rotateDisplays(rotation); new ItemPlaceGroupEvent(sg, itemStack, itemHolder).callEvent(); + result.complete(sg); }); } + return result; }); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java index fc6dfcad..8bada0c9 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java @@ -4,7 +4,7 @@ import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; -import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.managers.PlaceableGroupData; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; @@ -34,7 +34,8 @@ public void execute(Player player, String[] args) { String groupTag = args[2]; - PlaceableGroupManager.assign(heldItem, groupTag, true); + new PlaceableGroupData(groupTag) + .apply(heldItem); player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Assigned a group to your held block (Tag: "+groupTag+")"))); player.sendMessage(MiniMessage.miniMessage().deserialize("| The group will spawn using packets")); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java index f8be4954..e5be386d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java @@ -22,12 +22,12 @@ public void execute(Player player, String[] args) { ItemStack heldItem = PlaceCMD.getHeldItem(player, true); if (heldItem == null) return; - if (PlaceableGroupManager.isSpawningPacketGroup(heldItem)){ - PlaceableGroupManager.setSpawnPacketGroup(heldItem, false); + if (PlaceableGroupManager.isUsingPackets(heldItem)){ + PlaceableGroupManager.setUsePackets(heldItem, false); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will no longer spawn using packets", NamedTextColor.RED))); } else{ - PlaceableGroupManager.setSpawnPacketGroup(heldItem, true); + PlaceableGroupManager.setUsePackets(heldItem, true); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will spawn using packets", NamedTextColor.GREEN))); } PlaceableGroupManager.unassign(heldItem); From aee4ab10e58f7e5113c5517952a9b74430531249 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 29 Dec 2025 03:38:09 -0600 Subject: [PATCH 096/139] no changes --- .../DisplayAnimationFrame.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java index 0aeb0726..f280e0bd 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java @@ -90,10 +90,9 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ //End Sounds if (endSounds != null){ for (Map.Entry entry : endSounds.entrySet()){ - String soundName = entry.getKey(); DEUSound sound = entry.getValue(); - sound.delay = duration; - point.sounds.put(soundName, sound); + sound.delay = this.duration; + point.addSound(sound); } } @@ -108,9 +107,8 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ for (AnimationParticle particle : frameStartParticles){ String pointTag = OLD_ANIM_PARTICLE+animationParticle; FramePoint point = new FramePoint(pointTag, particle.getVector(), particle.getGroupYawAtCreation(), particle.getGroupPitchAtCreation()); - particle.setDelayInTicks(0); - point.particles.add(particle); - frame.framePoints.put(pointTag, point); + point.addParticle(particle); + frame.addFramePoint(point); animationParticle++; } } @@ -121,8 +119,8 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ String pointTag = OLD_ANIM_PARTICLE+animationParticle; FramePoint point = new FramePoint(pointTag, particle.getVector(), particle.getGroupYawAtCreation(), particle.getGroupPitchAtCreation()); particle.setDelayInTicks(duration); - point.particles.add(particle); - frame.framePoints.put(pointTag, point); + point.addParticle(particle); + frame.addFramePoint(point); animationParticle++; } } @@ -130,7 +128,7 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ //Frame Points if (framePoints != null){ for (FramePoint fp : framePoints.values()){ - frame.framePoints.put(fp.tag, new FramePoint(fp)); + frame.addFramePoint(new FramePoint(fp)); } } @@ -177,20 +175,20 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo void repairOldSounds(){ - HashMap map1 = handleOldSoundMaps(startSoundMap, 0); + HashMap map1 = handleEnumSoundMaps(startSoundMap, 0); if (!map1.isEmpty()){ if (startSounds == null) startSounds = new HashMap<>(); startSounds.putAll(map1); } - HashMap map2 = handleOldSoundMaps(endSoundMap, duration); + HashMap map2 = handleEnumSoundMaps(endSoundMap, duration); if (!map2.isEmpty()){ if (endSounds == null) endSounds = new HashMap<>(); endSounds.putAll(map2); } } - private HashMap handleOldSoundMaps(HashMap soundMap, int delayInTicks) { + private HashMap handleEnumSoundMaps(HashMap soundMap, int delayInTicks) { if (soundMap == null || soundMap.isEmpty()){ return new HashMap<>(); } From 78e8154d19473c901eedd8dbb1814af14448ea31 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 29 Dec 2025 03:43:10 -0600 Subject: [PATCH 097/139] completeExceptionally in case the placed group is null for wahtever reason (bad tag/cancelled event) --- .../managers/PlaceableGroupManager.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index 52a9b3e5..2b0a17de 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -244,18 +244,27 @@ public static boolean isRespectingBlockFace(@NotNull ItemStack itemStack){ CompletableFuture> result = new CompletableFuture<>(); if (isPacket){ - PacketDisplayEntityGroup pg = group.createPacketGroup(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK, true, true); - pg.setPersistent(true); - pg.rotateDisplays(rotation); - new ItemPlaceGroupEvent(pg, itemStack, itemHolder).callEvent(); - result.complete(pg); + try{ + PacketDisplayEntityGroup pg = group.createPacketGroup(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK, true, true); + pg.setPersistent(true); + pg.rotateDisplays(rotation); + new ItemPlaceGroupEvent(pg, itemStack, itemHolder).callEvent(); + result.complete(pg); + } + catch(NullPointerException e){ + result.completeExceptionally(e); + } } else{ DisplayAPI.getScheduler().run(() -> { - SpawnedDisplayEntityGroup sg = group.spawn(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK); - sg.rotateDisplays(rotation); - new ItemPlaceGroupEvent(sg, itemStack, itemHolder).callEvent(); - result.complete(sg); + try{ + SpawnedDisplayEntityGroup sg = group.spawn(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK); + sg.rotateDisplays(rotation); + new ItemPlaceGroupEvent(sg, itemStack, itemHolder).callEvent(); + result.complete(sg); + } catch (RuntimeException e) { + result.completeExceptionally(e); + } }); } return result; From 2c10f57d2417bed3671b732fe5778406e799060b Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 29 Dec 2025 04:05:18 -0600 Subject: [PATCH 098/139] Added "/deu place info" --- .../command/Permission.java | 1 + .../command/place/PlaceCMD.java | 4 +- .../command/place/PlaceInfoCMD.java | 40 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index 6166dbd7..e34134ea 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -34,6 +34,7 @@ public enum Permission { GROUP_CULLING("deu.group.culling"), GROUP_WORLD_EDIT("deu.group.worldedit"), + PLACE_INFO("deu.place.info"), PLACE_SET_ITEM("deu.place.setitem"), PLACE_TOGGLE_PACKET("deu.place.toggle.packet"), PLACE_TOGGLE_PLAYER_FACING("deu.place.toggle.playerfacing"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java index 5ddc7f36..200d70a2 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -21,6 +21,7 @@ public PlaceCMD() { new PlaceTogglePacketCMD(this); new PlaceTogglePlayerFacingCMD(this); new PlaceToggleBlockFaceCMD(this); + new PlaceInfoCMD(this); } @Override @@ -44,14 +45,15 @@ static void help(CommandSender sender, int page){ sender.sendMessage(DisplayAPI.pluginPrefixLong); if (page == 1){ CMDUtils.sendCMD(sender, "/deu place help", "Get help for placeable groups"); + CMDUtils.sendCMD(sender, "/deu place info", "Get placeable group information for your held block"); CMDUtils.sendCMD(sender, "/deu place set ", "Assign a group to your held block, which will be spawned when the block is placed"); CMDUtils.sendCMD(sender, "/deu place unset", "Unassign a group from your held block"); CMDUtils.sendCMD(sender, "/deu place setpermission", "Set the permission required to place the group"); CMDUtils.sendCMD(sender, "/deu place unsetpermission", "Set the permission required to place the group"); CMDUtils.sendCMD(sender, "/deu place togglepacket", "Toggle whether the placed group will be packet-based. True by default"); - CMDUtils.sendCMD(sender, "/deu place toggleplayerfacing", "Toggle whether the placed group will respect the player's facing direction. True by default"); } else{ + CMDUtils.sendCMD(sender, "/deu place toggleplayerfacing", "Toggle whether the placed group will respect the player's facing direction. True by default"); CMDUtils.sendCMD(sender, "/deu place toggleblockface", "Toggle whether the placed group will respect the block face it is placed on. True by default"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java new file mode 100644 index 00000000..0e084c56 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java @@ -0,0 +1,40 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceInfoCMD extends PlayerSubCommand { + PlaceInfoCMD(@NotNull DEUSubCommand parentSubCommand) { + super("info", parentSubCommand, Permission.PLACE_INFO); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + player.sendMessage(DisplayAPI.pluginPrefixLong); + + String groupTag = PlaceableGroupManager.getAssignedGroupTag(heldItem); + String permission = PlaceableGroupManager.getPlacePermission(heldItem); + if (permission == null){ + permission = "NOT SET"; + } + boolean respectPlayerFacing = PlaceableGroupManager.isRespectingPlayerFacing(heldItem); + boolean respectBlockFace = PlaceableGroupManager.isRespectingBlockFace(heldItem); + boolean packetBased = PlaceableGroupManager.isUsingPackets(heldItem); + + player.sendMessage(MiniMessage.miniMessage().deserialize("Group Tag: "+groupTag)); + player.sendMessage(MiniMessage.miniMessage().deserialize("Place Permission: "+permission)); + player.sendMessage(MiniMessage.miniMessage().deserialize("Respect Player Facing: "+(respectPlayerFacing ? "ENABLED" : "DISABLED"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("Respect Block Face: "+(respectBlockFace ? "ENABLED" : "DISABLED"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("Packet Based: "+(packetBased ? "TRUE" : "FALSE"))); + } +} \ No newline at end of file From a1fb436714fd97f452517eaf5087ad13cbaf8db1 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 29 Dec 2025 20:18:17 -0600 Subject: [PATCH 099/139] Added Placeable Group sounds and commands --- .../displayentityutils/DisplayAPI.java | 12 + .../managers/PlaceableGroupManager.java | 240 +++++++++++++++++- .../utils/DisplayEntities/DEUSound.java | 48 +++- .../utils/DisplayEntities/FramePoint.java | 21 +- .../DisplayEntityPlugin.java | 6 +- .../command/Permission.java | 1 + .../command/place/PlaceAddSoundCMD.java | 72 ++++++ .../command/place/PlaceCMD.java | 6 +- .../command/place/PlaceInfoCMD.java | 23 +- .../player/DEUPlayerPlaceBlockListener.java | 4 +- 10 files changed, 395 insertions(+), 38 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceAddSoundCMD.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java index 4f0ba79e..9798aa8b 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java +++ b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java @@ -32,6 +32,8 @@ public final class DisplayAPI { static NamespacedKey placeableGroupPermissionKey; static NamespacedKey placeableGroupRespectFacingKey; static NamespacedKey placeableGroupRespectBlockFace; + static NamespacedKey placeableGroupPlaceSounds; + static NamespacedKey placeableGroupBreakSounds; static boolean isMythicMobsInstalled; static boolean isLibsDisguisesInstalled; @@ -110,6 +112,16 @@ private DisplayAPI(){} return placeableGroupRespectBlockFace; } + public static @NotNull NamespacedKey getPlaceableGroupPlaceSounds(){ + return placeableGroupPlaceSounds; + } + + public static @NotNull NamespacedKey getPlaceableGroupBreakSounds(){ + return placeableGroupBreakSounds; + } + + + @ApiStatus.Internal public static String getLegacyPartTagPrefix(){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index 2b0a17de..fff83ad6 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -4,11 +4,10 @@ import net.donnypz.displayentityutils.events.GroupSpawnedEvent; import net.donnypz.displayentityutils.events.ItemPlaceGroupEvent; import net.donnypz.displayentityutils.events.PreItemPlaceGroupEvent; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; -import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; -import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.Sound; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -18,6 +17,9 @@ import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; +import java.io.*; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CompletableFuture; public final class PlaceableGroupManager { @@ -43,6 +45,8 @@ public static void setGroup(@NotNull ItemStack itemStack, @NotNull DisplayEntity public static void setGroup(@NotNull ItemStack itemStack, @NotNull String groupTag){ ItemMeta meta = itemStack.getItemMeta(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); itemStack.setItemMeta(meta); } @@ -56,6 +60,8 @@ public static void setGroup(@NotNull ItemStack itemStack, @NotNull String groupT public static void setUsePackets(@NotNull ItemStack itemStack, boolean packet){ ItemMeta meta = itemStack.getItemMeta(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, packet); itemStack.setItemMeta(meta); } @@ -69,6 +75,8 @@ public static void setUsePackets(@NotNull ItemStack itemStack, boolean packet){ public static void setPlacePermission(@NotNull ItemStack itemStack, @Nullable String placePermission){ ItemMeta meta = itemStack.getItemMeta(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + if (placePermission == null){ pdc.remove(DisplayAPI.getPlaceableGroupPermissionKey()); } @@ -87,6 +95,8 @@ public static void setPlacePermission(@NotNull ItemStack itemStack, @Nullable St public static void setRespectPlayerFacing(@NotNull ItemStack itemStack, boolean respect){ ItemMeta meta = itemStack.getItemMeta(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, respect); itemStack.setItemMeta(meta); } @@ -100,10 +110,220 @@ public static void setRespectPlayerFacing(@NotNull ItemStack itemStack, boolean public static void setRespectBlockFace(@NotNull ItemStack itemStack, boolean respect){ ItemMeta meta = itemStack.getItemMeta(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + pdc.set(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN, respect); itemStack.setItemMeta(meta); } + /** + * Add a sound to play when the given item's assigned group is placed or removed/broken + * @param itemStack the sound's index + * @param sound the sound + * @param isPlace whether the sound should play when placed or removed/broken + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void addSound(@NotNull ItemStack itemStack, @NotNull DEUSound sound, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + List sounds = getSounds(pdc, isPlace); + sounds.add(sound); + + pdc.set(getSoundKey(isPlace), PersistentDataType.BYTE_ARRAY, writeSoundList(sounds)); + itemStack.setItemMeta(meta); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param index the sound's index + * @param isPlace whether to remove a place or remove/break sound + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeSound(@NotNull ItemStack itemStack, int index, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + List sounds = getSounds(pdc, isPlace); + sounds.remove(index); + + pdc.set(getSoundKey(isPlace), PersistentDataType.BYTE_ARRAY, writeSoundList(sounds)); + itemStack.setItemMeta(meta); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param sound the sound + * @param isPlace whether to remove a place or remove/break sound + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeSound(@NotNull ItemStack itemStack, @NotNull DEUSound sound, boolean isPlace){ + removeSound(itemStack, sound.getSoundName(), sound.getVolume(), sound.getPitch(), isPlace); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param sound the sound + * @param isPlace whether to remove a place or remove/break sound + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeSound(@NotNull ItemStack itemStack, @NotNull Sound sound, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + List sounds = getSounds(pdc, isPlace); + sounds.removeIf(s -> sound == s.getSound()); + + pdc.set(getSoundKey(isPlace), PersistentDataType.BYTE_ARRAY, writeSoundList(sounds)); + itemStack.setItemMeta(meta); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param sound the sound + * @param isPlace whether to remove a place or remove/break sound + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeSound(@NotNull ItemStack itemStack, @NotNull String sound, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + List sounds = getSounds(pdc, isPlace); + sounds.removeIf(s -> s.getSoundName().equalsIgnoreCase(sound)); + + pdc.set(getSoundKey(isPlace), PersistentDataType.BYTE_ARRAY, writeSoundList(sounds)); + itemStack.setItemMeta(meta); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param sound the sound + * @param isPlace whether to remove a place or remove/break sound + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeSound(@NotNull ItemStack itemStack, @NotNull String sound, float volume, float pitch, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + List sounds = getSounds(pdc, isPlace); + sounds.removeIf(s -> + s.getSoundName().equalsIgnoreCase(sound) + && s.getVolume() == volume + && s.getPitch() == pitch + ); + + pdc.set(getSoundKey(isPlace), PersistentDataType.BYTE_ARRAY, writeSoundList(sounds)); + itemStack.setItemMeta(meta); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param isPlace whether to remove place or remove/break sounds + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeAllSounds(@NotNull ItemStack itemStack, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + pdc.remove(getSoundKey(isPlace)); + itemStack.setItemMeta(meta); + } + + /** + * Get the {@link DEUSound}s added to an item that will play when the item is placed or removed/broken + * @param itemStack the item + * @param isPlace whether to get place or break sounds + * @return a {@link DEUSound} list + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static @NotNull List getSounds(@NotNull ItemStack itemStack, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + return getSounds(pdc, isPlace); + } + + private static List getSounds(PersistentDataContainer pdc, boolean isPlace){ + NamespacedKey key = getSoundKey(isPlace); + byte[] soundArr = pdc.get(key, PersistentDataType.BYTE_ARRAY); + return soundArr == null ? new ArrayList<>() : readSoundList(soundArr); + } + + + /** + * + * @param itemStack the item + * @param location where the sounds should play + * @param isPlace whether to play place or break sounds + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void playSounds(@NotNull ItemStack itemStack, @NotNull Location location, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + for (DEUSound sound : getSounds(pdc, isPlace)){ + sound.playSound(location); + } + } + + private static NamespacedKey getSoundKey(boolean isPlace){ + return isPlace ? DisplayAPI.getPlaceableGroupPlaceSounds() : DisplayAPI.getPlaceableGroupBreakSounds(); + } + + private static byte[] writeSoundList(List sounds) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(baos); + + out.writeInt(sounds.size()); + for (DEUSound sound : sounds) { + sound.writeExternal(out); + } + + out.flush(); + return baos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException("Failed to write DEUSound list", e); + } + } + + private static List readSoundList(byte[] data) { + try { + ObjectInputStream in = + new ObjectInputStream(new ByteArrayInputStream(data)); + + int size = in.readInt(); + List sounds = new ArrayList<>(size); + + for (int i = 0; i < size; i++) { + DEUSound sound = new DEUSound(); + sound.readExternal(in); + sounds.add(sound); + } + + return sounds; + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException("Failed to read DEUSound list", e); + } + } + + private static void checkExistingData(PersistentDataContainer pdc){ + if (!pdc.has(DisplayAPI.getPlaceableGroupKey())) throw new IllegalArgumentException("ItemStack was never provided PlaceableGroupData"); + } + /** * Unassign a {@link DisplayEntityGroup} from an {@link ItemStack} * @param itemStack the item @@ -124,7 +344,7 @@ public static void unassign(@NotNull ItemStack itemStack){ * @param itemStack the item * @return a boolean */ - public static boolean hasAssignedGroup(@NotNull ItemStack itemStack){ + public static boolean hasData(@NotNull ItemStack itemStack){ PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); return pdc.has(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING); } @@ -134,7 +354,7 @@ public static boolean hasAssignedGroup(@NotNull ItemStack itemStack){ * @param itemStack the item * @return the group's tag or null */ - public static @Nullable String getAssignedGroupTag(@NotNull ItemStack itemStack){ + public static @Nullable String getGroupTag(@NotNull ItemStack itemStack){ PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); return pdc.get(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING); } @@ -144,8 +364,8 @@ public static boolean hasAssignedGroup(@NotNull ItemStack itemStack){ * @param itemStack the item * @return the {@link DisplayEntityGroup} or null if the group doesn't exist or if the item doesn't have placeable group data */ - public static @Nullable DisplayEntityGroup getAssignedGroup(@NotNull ItemStack itemStack){ - String tag = getAssignedGroupTag(itemStack); + public static @Nullable DisplayEntityGroup getGroup(@NotNull ItemStack itemStack){ + String tag = getGroupTag(itemStack); return tag == null ? null : DisplayGroupManager.getGroup(tag); } @@ -231,7 +451,7 @@ public static boolean isRespectingBlockFace(@NotNull ItemStack itemStack){ * @return a completable future with an {@link ActiveGroup}, or null if the itemstack does not contain placeable group data or if the {@link PreItemPlaceGroupEvent} is cancelled */ public static @Nullable CompletableFuture> spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @NotNull Quaternionf rotation, @Nullable Player itemHolder){ - String tag = getAssignedGroupTag(itemStack); + String tag = getGroupTag(itemStack); boolean isPacket = isUsingPackets(itemStack); if (tag == null) return null; @@ -270,4 +490,6 @@ public static boolean isRespectingBlockFace(@NotNull ItemStack itemStack){ return result; }); } + + } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUSound.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUSound.java index 2276564b..79614e6c 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUSound.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUSound.java @@ -2,6 +2,11 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.*; import org.bukkit.entity.Player; import org.jetbrains.annotations.ApiStatus; @@ -10,9 +15,9 @@ import java.io.*; import java.util.Collection; +import java.util.function.Consumer; -@ApiStatus.Internal -public class DEUSound implements Externalizable, Cloneable { +public class DEUSound implements Externalizable, Cloneable { //i have no clue what i was doing when making this class, now its externalizable forever transient Sound sound; String soundName; float volume; @@ -192,4 +197,43 @@ public DEUSound clone() { throw new AssertionError(); } } + + @ApiStatus.Internal + public void sendInfo(Player player, Consumer clickRemovalAction){ + Component msgComp = Component.text("- "+soundName, NamedTextColor.YELLOW); + Component hoverComp = Component.text("| Vol: "+volume+", Pitch: "+pitch, NamedTextColor.GRAY); + if (!existsInGameVersion){ + msgComp = msgComp.append(Component.text(" [UNKNOWN]", NamedTextColor.GRAY)); + hoverComp = hoverComp + .append(Component.newline()) + .append(Component.text("This sound no longer exists or is a resource pack sound!", NamedTextColor.RED)); + } + + if (clickRemovalAction != null){ + hoverComp = hoverComp.append(Component.newline()) + .append(Component.text("Click to remove this sound", NamedTextColor.YELLOW)); + msgComp = msgComp.clickEvent(ClickEvent.callback(a -> { + clickRemovalAction.accept(this); + a.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Sound Removed!", NamedTextColor.YELLOW))); + })); + } + + msgComp = msgComp.hoverEvent(HoverEvent.showText(hoverComp)); + player.sendMessage(msgComp); + } + + @ApiStatus.Internal + public static void sendInfo(Collection sounds, Player player, String soundListTitle, Consumer clickRemovalAction){ + if (soundListTitle == null) soundListTitle = "Sounds"; + player.sendMessage(MiniMessage.miniMessage().deserialize(soundListTitle+": "+sounds.size())); + if (sounds.isEmpty()){ + player.sendMessage(Component.text("| NONE", NamedTextColor.GRAY)); + } + else{ + for (DEUSound sound : sounds){ + sound.sendInfo(player, clickRemovalAction); + } + } + player.sendMessage(Component.empty()); + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java index cc52fd32..cebeffb4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java @@ -435,27 +435,8 @@ public void sendInfo(Player player){ player.sendMessage(Component.empty()); //Sounds - player.sendMessage(MiniMessage.miniMessage().deserialize("Sounds: "+sounds.size())); - if (sounds.isEmpty()){ - player.sendMessage(Component.text("| NONE", NamedTextColor.GRAY)); - } - else{ - for (DEUSound sound : sounds.values()){ - Component msgComp = Component.text("- "+sound.getSoundName(), NamedTextColor.YELLOW); - Component hoverComp = Component.text("| Vol: "+sound.getVolume()+", Pitch: "+sound.getPitch(), NamedTextColor.GRAY); - if (!sound.existsInGameVersion()){ - msgComp = msgComp.append(Component.text(" [UNKNOWN]", NamedTextColor.GRAY)); - hoverComp = hoverComp - .append(Component.newline()) - .append(Component.text("This sound no longer exists or is a resource pack sound!", NamedTextColor.RED)); - } - - msgComp = msgComp.hoverEvent(HoverEvent.showText(hoverComp)); - player.sendMessage(msgComp); - } - } + DEUSound.sendInfo(sounds.values(), player, null, null); - player.sendMessage(Component.empty()); player.sendMessage(MiniMessage.miniMessage().deserialize("RIGHT click to preview effects")); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index ab30124c..62d1a3ea 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -90,8 +90,10 @@ private void initializeNamespacedKeys(){ //DO NOT CHANGE DisplayAPI.placeableGroupKey = new NamespacedKey(this, "placeablegroup"); DisplayAPI.placeableGroupPacketBasedKey = new NamespacedKey(this, "placeablegroup_packet"); DisplayAPI.placeableGroupPermissionKey = new NamespacedKey(this, "placeablegroup_perm"); - DisplayAPI.placeableGroupRespectFacingKey = new NamespacedKey(this, "placeblegroup_playerfacing"); - DisplayAPI.placeableGroupRespectBlockFace = new NamespacedKey(this, "placeblegroup_blockface"); + DisplayAPI.placeableGroupRespectFacingKey = new NamespacedKey(this, "placeablegroup_playerfacing"); + DisplayAPI.placeableGroupRespectBlockFace = new NamespacedKey(this, "placeablegroup_blockface"); + DisplayAPI.placeableGroupPlaceSounds = new NamespacedKey(this, "placeablegroup_placesounds"); + DisplayAPI.placeableGroupBreakSounds = new NamespacedKey(this, "placeablegroup_breaksounds"); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index e34134ea..ce0f04ec 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -40,6 +40,7 @@ public enum Permission { PLACE_TOGGLE_PLAYER_FACING("deu.place.toggle.playerfacing"), PLACE_TOGGLE_BLOCK_FACE("deu.place.toggle.blockface"), PLACE_SET_PERMISSION("deu.place.setpermission"), + PLACE_SOUND("deu.place.sound"), PARTS_INFO("deu.parts.info"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceAddSoundCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceAddSoundCMD.java new file mode 100644 index 00000000..7d6281e3 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceAddSoundCMD.java @@ -0,0 +1,72 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; +import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +class PlaceAddSoundCMD extends PlayerSubCommand { + PlaceAddSoundCMD(@NotNull DEUSubCommand parentSubCommand) { + super("addsound", parentSubCommand, Permission.PLACE_SOUND); + setTabComplete(2, List.of("place", "break")); + setTabComplete(3, ""); + setTabComplete(4, ""); + setTabComplete(5, ""); + } + + private void incorrectUsage(Player player){ + player.sendMessage(Component.text("Incorrect Usage! /deu anim addsound ", NamedTextColor.RED)); + } + + @Override + public void execute(Player player, String[] args) { + + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (args.length < 6) { + incorrectUsage(player); + return; + } + try { + String isPlaceStr = args[2]; + boolean isPlace; + if (isPlaceStr.equalsIgnoreCase("place")){ + isPlace = true; + } + else if (isPlaceStr.equalsIgnoreCase("break")){ + isPlace = false; + } + else{ + incorrectUsage(player); + return; + } + + String soundStr = args[3]; + float volume = Float.parseFloat(args[4]); + float pitch = Float.parseFloat(args[5]); + PlaceableGroupManager.addSound(heldItem, new DEUSound(soundStr, volume, pitch, 0), isPlace); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Sound Added! ", NamedTextColor.GREEN).append(Component.text(isPlace ? "(Place)" : "(Break)", NamedTextColor.GRAY)))); + player.sendMessage(MiniMessage.miniMessage().deserialize("| Sound: "+soundStr)); + player.sendMessage(MiniMessage.miniMessage().deserialize("| Volume: "+volume)); + player.sendMessage(MiniMessage.miniMessage().deserialize("| Pitch: "+pitch)); + + if (VersionUtils.getSound(soundStr) == null){ + player.sendMessage(Component.text("| The provided sound is not a vanilla Minecraft sound, or does not exist in this game version!", NamedTextColor.GRAY)); + } + } catch (NumberFormatException | IndexOutOfBoundsException e) { + player.sendMessage(Component.text("Invalid number entered! Enter numbers >= 0", NamedTextColor.RED)); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java index 200d70a2..9146ac68 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -22,6 +22,7 @@ public PlaceCMD() { new PlaceTogglePlayerFacingCMD(this); new PlaceToggleBlockFaceCMD(this); new PlaceInfoCMD(this); + new PlaceAddSoundCMD(this); } @Override @@ -55,6 +56,7 @@ static void help(CommandSender sender, int page){ else{ CMDUtils.sendCMD(sender, "/deu place toggleplayerfacing", "Toggle whether the placed group will respect the player's facing direction. True by default"); CMDUtils.sendCMD(sender, "/deu place toggleblockface", "Toggle whether the placed group will respect the block face it is placed on. True by default"); + CMDUtils.sendCMD(sender, "/deu place addsound ", "Add a sound to play when the block is placed or broken"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } @@ -66,8 +68,8 @@ static ItemStack getHeldItem(Player player, boolean mustBeAssigned){ return null; } - if (mustBeAssigned && !PlaceableGroupManager.hasAssignedGroup(heldItem)){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item does not have an assigned group!", NamedTextColor.RED))); + if (mustBeAssigned && !PlaceableGroupManager.hasData(heldItem)){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item does not have placeable group data!", NamedTextColor.RED))); return null; } return heldItem; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java index 0e084c56..db87f6db 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java @@ -5,11 +5,14 @@ import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.List; + class PlaceInfoCMD extends PlayerSubCommand { PlaceInfoCMD(@NotNull DEUSubCommand parentSubCommand) { super("info", parentSubCommand, Permission.PLACE_INFO); @@ -22,7 +25,7 @@ public void execute(Player player, String[] args) { player.sendMessage(DisplayAPI.pluginPrefixLong); - String groupTag = PlaceableGroupManager.getAssignedGroupTag(heldItem); + String groupTag = PlaceableGroupManager.getGroupTag(heldItem); String permission = PlaceableGroupManager.getPlacePermission(heldItem); if (permission == null){ permission = "NOT SET"; @@ -30,11 +33,29 @@ public void execute(Player player, String[] args) { boolean respectPlayerFacing = PlaceableGroupManager.isRespectingPlayerFacing(heldItem); boolean respectBlockFace = PlaceableGroupManager.isRespectingBlockFace(heldItem); boolean packetBased = PlaceableGroupManager.isUsingPackets(heldItem); + List placeSounds = PlaceableGroupManager.getSounds(heldItem, true); + List breakSounds = PlaceableGroupManager.getSounds(heldItem, false); player.sendMessage(MiniMessage.miniMessage().deserialize("Group Tag: "+groupTag)); player.sendMessage(MiniMessage.miniMessage().deserialize("Place Permission: "+permission)); player.sendMessage(MiniMessage.miniMessage().deserialize("Respect Player Facing: "+(respectPlayerFacing ? "ENABLED" : "DISABLED"))); player.sendMessage(MiniMessage.miniMessage().deserialize("Respect Block Face: "+(respectBlockFace ? "ENABLED" : "DISABLED"))); player.sendMessage(MiniMessage.miniMessage().deserialize("Packet Based: "+(packetBased ? "TRUE" : "FALSE"))); + + DEUSound.sendInfo(placeSounds, player, "Place Sounds", + player.hasPermission(Permission.PLACE_SOUND.getPermission()) + ? s -> + { + PlaceableGroupManager.removeSound(heldItem, s, true); + } + : null); + + DEUSound.sendInfo(breakSounds, player, "Break Sounds", + player.hasPermission(Permission.PLACE_SOUND.getPermission()) + ? s -> + { + PlaceableGroupManager.removeSound(heldItem, s, false); + } + : null); } } \ No newline at end of file diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java index fe710ac6..e9e5125f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java @@ -25,7 +25,7 @@ public void onPlaceBlock(BlockPlaceEvent e){ return; } - if (!PlaceableGroupManager.hasAssignedGroup(heldItem)){ + if (!PlaceableGroupManager.hasData(heldItem)){ return; } @@ -57,7 +57,7 @@ public void onPlaceBlock(BlockPlaceEvent e){ } PlaceableGroupManager.spawnGroup(heldItem, placeLoc, rot, player); - + PlaceableGroupManager.playSounds(heldItem, placeLoc, true); } private Quaternionf getRotation(Vector faceDir){ From 2bf962248e9f1dfa8bc378e67d92f75a344ef074 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 00:51:57 -0600 Subject: [PATCH 100/139] fix "togglepacket" unassigning placed group --- .../displayentityutils/command/place/PlaceTogglePacketCMD.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java index e5be386d..10874321 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java @@ -7,7 +7,6 @@ import net.donnypz.displayentityutils.managers.PlaceableGroupManager; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -30,7 +29,5 @@ public void execute(Player player, String[] args) { PlaceableGroupManager.setUsePackets(heldItem, true); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will spawn using packets", NamedTextColor.GREEN))); } - PlaceableGroupManager.unassign(heldItem); - player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Your held item no longer has an assigned group"))); } } From 451e04ba719f10213a8ff6c906c6a6ef7c31ac7a Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 02:19:17 -0600 Subject: [PATCH 101/139] fix interaction click detection not working in some cases --- .../listeners/entity/DEUInteractionListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUInteractionListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUInteractionListener.java index dd325050..4762e361 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUInteractionListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUInteractionListener.java @@ -128,7 +128,7 @@ public void onPacketReceive(PacketReceiveEvent event) { } //Right Click - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST) private void rClick(PlayerInteractEntityEvent e){ if (e.getRightClicked() instanceof Interaction entity){ determineBukkitAction(entity, e.getPlayer(), InteractionClickEvent.ClickType.RIGHT); @@ -136,7 +136,7 @@ private void rClick(PlayerInteractEntityEvent e){ } //Left Click - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST) private void lClick(EntityDamageByEntityEvent e){ if (e.getEntity() instanceof Interaction entity){ determineBukkitAction(entity, (Player) e.getDamager(), InteractionClickEvent.ClickType.LEFT); From 3bd138787efb495e7d6155ff2e119b1ac4457e45 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 07:55:15 -0600 Subject: [PATCH 102/139] Disable placing group inside a block, decrement item count when placed --- .../player/DEUPlayerPlaceBlockListener.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java index e9e5125f..6aabe135 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java @@ -3,6 +3,7 @@ import net.donnypz.displayentityutils.managers.PlaceableGroupManager; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; @@ -36,6 +37,11 @@ public void onPlaceBlock(BlockPlaceEvent e){ } BlockFace face = e.getBlockAgainst().getFace(e.getBlockPlaced()); + if (face == BlockFace.SELF){ + player.sendMessage(Component.text("You cannot place this inside another block!", NamedTextColor.RED)); + return; + } + Quaternionf rot; Location placeLoc; @@ -52,12 +58,17 @@ public void onPlaceBlock(BlockPlaceEvent e){ } - if ((face == BlockFace.UP || face == BlockFace.DOWN || face == BlockFace.SELF) && PlaceableGroupManager.isRespectingPlayerFacing(heldItem)){ + if ((face == BlockFace.UP || face == BlockFace.DOWN) && PlaceableGroupManager.isRespectingPlayerFacing(heldItem)){ placeLoc.setYaw(player.getYaw()+180); } - PlaceableGroupManager.spawnGroup(heldItem, placeLoc, rot, player); - PlaceableGroupManager.playSounds(heldItem, placeLoc, true); + ItemStack itemClone = heldItem.clone(); + itemClone.setAmount(1); + PlaceableGroupManager.spawnGroup(itemClone, placeLoc, rot, player); + PlaceableGroupManager.playSounds(itemClone, placeLoc, true); + if (player.getGameMode() != GameMode.CREATIVE){ + heldItem.setAmount(heldItem.getAmount()-1); + } } private Quaternionf getRotation(Vector faceDir){ From 8d495335d21ab4ec2e7e52a8e033eae405eebe7f Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 08:01:32 -0600 Subject: [PATCH 103/139] added placed group block breaking, removed non-packet based placed group option --- .../displayentityutils/DisplayAPI.java | 29 ++- .../events/PlacedGroupBreakEvent.java | 68 +++++++ .../managers/PlaceableGroupData.java | 40 +++- .../managers/PlaceableGroupManager.java | 191 ++++++++++-------- .../DisplayEntityPlugin.java | 14 +- .../command/Permission.java | 2 + .../command/place/PlaceCMD.java | 8 +- .../command/place/PlaceInfoCMD.java | 7 +- .../command/place/PlaceSetCMD.java | 5 +- ...etCMD.java => PlaceToggleDropItemCMD.java} | 16 +- .../place/PlaceTogglePlacerOnlyCMD.java | 33 +++ .../player/DEUPlayerDigListener.java | 98 +++++++++ 12 files changed, 396 insertions(+), 115 deletions(-) create mode 100644 api/src/main/java/net/donnypz/displayentityutils/events/PlacedGroupBreakEvent.java rename plugin/src/main/java/net/donnypz/displayentityutils/command/place/{PlaceTogglePacketCMD.java => PlaceToggleDropItemCMD.java} (59%) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlacerOnlyCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java index 9798aa8b..ae4cc008 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java +++ b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java @@ -28,12 +28,16 @@ public final class DisplayAPI { static NamespacedKey spawnAnimationLoadMethodKey; static NamespacedKey chunkPacketGroupsKey; static NamespacedKey placeableGroupKey; - static NamespacedKey placeableGroupPacketBasedKey; static NamespacedKey placeableGroupPermissionKey; static NamespacedKey placeableGroupRespectFacingKey; static NamespacedKey placeableGroupRespectBlockFace; static NamespacedKey placeableGroupPlaceSounds; static NamespacedKey placeableGroupBreakSounds; + static NamespacedKey placeableGroupDropItem; + static NamespacedKey placeableGroupPlacerBreaksOnly; + static NamespacedKey placeableGroupItemStack; + static NamespacedKey placeableGroupPlacer; + static NamespacedKey placeableGroupId; static boolean isMythicMobsInstalled; static boolean isLibsDisguisesInstalled; @@ -96,9 +100,6 @@ private DisplayAPI(){} return placeableGroupKey; } - public static @NotNull NamespacedKey getPlaceableGroupPacketBasedKey(){ - return placeableGroupPacketBasedKey; - } public static @NotNull NamespacedKey getPlaceableGroupPermissionKey(){ return placeableGroupPermissionKey; @@ -120,6 +121,26 @@ private DisplayAPI(){} return placeableGroupBreakSounds; } + public static @NotNull NamespacedKey getPlaceableGroupPlacerBreaksOnly() { + return placeableGroupPlacerBreaksOnly; + } + + public static @NotNull NamespacedKey getPlaceableGroupDropItem() { + return placeableGroupDropItem; + } + + + public static @NotNull NamespacedKey getPlaceableGroupItemStack(){ + return placeableGroupItemStack; + } + + public static @NotNull NamespacedKey getPlaceableGroupId(){ + return placeableGroupId; + } + + public static @NotNull NamespacedKey getPlaceableGroupPlacer() { + return placeableGroupPlacer; + } diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/PlacedGroupBreakEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/PlacedGroupBreakEvent.java new file mode 100644 index 00000000..71fb9732 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/events/PlacedGroupBreakEvent.java @@ -0,0 +1,68 @@ +package net.donnypz.displayentityutils.events; + +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +/** + * Called when a group placed by an item is broken by a player. Cancellable + */ +public class PlacedGroupBreakEvent extends Event implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + boolean cancelled = false; + + Block block; + PacketDisplayEntityGroup packetDisplayEntityGroup; + Player player; + + public PlacedGroupBreakEvent(Block block, PacketDisplayEntityGroup packetDisplayEntityGroup, Player player){ + this.block = block; + this.packetDisplayEntityGroup = packetDisplayEntityGroup; + this.player = player; + } + + + /** + * Get the block involved in this event + * @return a block + */ + public Block getBlock() { + return block; + } + + /** + * Get the {@link PacketDisplayEntityGroup} involved in this event + * @return a packet-based group + */ + public PacketDisplayEntityGroup getGroup() { + return packetDisplayEntityGroup; + } + + /** + * Get the player involved in this event + * @return the player + */ + public Player getPlayer() { + return player; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java index 481c95e5..60e9e978 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java @@ -17,9 +17,10 @@ public class PlaceableGroupData { String groupTag; String permission; - boolean packetBased = true; boolean respectPlayerFacing = true; boolean respectBlockFace = true; + boolean dropItemOnBreak = true; + boolean placerBreaksOnly = true; public PlaceableGroupData(@NotNull String groupTag) { @@ -46,15 +47,6 @@ public PlaceableGroupData setPermission(@Nullable String permission) { return this; } - /** - * Set whether the group should be packet-based when spawned. True by default - * @param packetBased - * @return this - */ - public PlaceableGroupData setPacketBased(boolean packetBased) { - this.packetBased = packetBased; - return this; - } /** * Set whether the group should spawn with respect to the player's facing direction. True by default @@ -76,17 +68,39 @@ public PlaceableGroupData setRespectBlockFace(boolean respectBlockFace) { return this; } + /** + * Set whether the item used to place the group should be dropped when the group is destroyed + * @param dropItemOnDestroy + * @return this + */ + public PlaceableGroupData setDropItemOnDestroy(boolean dropItemOnDestroy){ + this.dropItemOnBreak = dropItemOnDestroy; + return this; + } + + /** + * Set whether only the placer of the group is the one who can break it + * @param placerBreaksOnly + * @return this + */ + public PlaceableGroupData setPlacerBreaksOnly(boolean placerBreaksOnly){ + this.placerBreaksOnly = placerBreaksOnly; + return this; + } + /** * Apply the data to a provided itemstack, spawning the group when placed * @param itemStack * @throws IllegalArgumentException if the itemstack is not of a block type */ public void apply(@NotNull ItemStack itemStack){ + if (!PlaceableGroupManager.isValidItem(itemStack)){ + throw new IllegalArgumentException("The provided ItemStack is not of a block type"); + } ItemMeta meta = itemStack.getItemMeta(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); - pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, packetBased); if (permission != null){ pdc.set(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING, permission); @@ -94,6 +108,10 @@ public void apply(@NotNull ItemStack itemStack){ pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, respectPlayerFacing); pdc.set(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN, respectBlockFace); + + + pdc.set(DisplayAPI.getPlaceableGroupPlacerBreaksOnly(), PersistentDataType.BOOLEAN, placerBreaksOnly); + pdc.set(DisplayAPI.getPlaceableGroupDropItem(), PersistentDataType.BOOLEAN, dropItemOnBreak); itemStack.setItemMeta(meta); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index fff83ad6..5af47f15 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -1,13 +1,13 @@ package net.donnypz.displayentityutils.managers; +import com.jeff_media.customblockdata.CustomBlockData; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.events.GroupSpawnedEvent; import net.donnypz.displayentityutils.events.ItemPlaceGroupEvent; import net.donnypz.displayentityutils.events.PreItemPlaceGroupEvent; import net.donnypz.displayentityutils.utils.DisplayEntities.*; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.Sound; +import org.bukkit.*; +import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -20,7 +20,7 @@ import java.io.*; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; +import java.util.UUID; public final class PlaceableGroupManager { @@ -51,20 +51,6 @@ public static void setGroup(@NotNull ItemStack itemStack, @NotNull String groupT itemStack.setItemMeta(meta); } - /** - * Set whether the group associated with the given item should spawn as a {@link PacketDisplayEntityGroup} - * @param itemStack the item - * @param packet whether the group should spawn pack-based - * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} - */ - public static void setUsePackets(@NotNull ItemStack itemStack, boolean packet){ - ItemMeta meta = itemStack.getItemMeta(); - PersistentDataContainer pdc = meta.getPersistentDataContainer(); - checkExistingData(pdc); - - pdc.set(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN, packet); - itemStack.setItemMeta(meta); - } /** * Set the permission a player needs to place an itemstack's assigned group. Set the permission to {@code null} to unset it @@ -116,6 +102,35 @@ public static void setRespectBlockFace(@NotNull ItemStack itemStack, boolean res itemStack.setItemMeta(meta); } + /** + * Set whether the item used to place the group should be dropped when the group is broken + * @param itemStack the item + * @param dropItem + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void setDropItemOnBreak(@NotNull ItemStack itemStack, boolean dropItem){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + pdc.set(DisplayAPI.getPlaceableGroupDropItem(), PersistentDataType.BOOLEAN, dropItem); + itemStack.setItemMeta(meta); + } + + /** + * Set whether only the placer of the group can break the group + * @param itemStack the item + * @param placerBreaksOnly + */ + public static void setPlacerBreaksOnly(@NotNull ItemStack itemStack, boolean placerBreaksOnly){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + pdc.set(DisplayAPI.getPlaceableGroupPlacerBreaksOnly(), PersistentDataType.BOOLEAN, placerBreaksOnly); + itemStack.setItemMeta(meta); + } + /** * Add a sound to play when the given item's assigned group is placed or removed/broken * @param itemStack the sound's index @@ -332,10 +347,13 @@ public static void unassign(@NotNull ItemStack itemStack){ ItemMeta meta = itemStack.getItemMeta(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); pdc.remove(DisplayAPI.getPlaceableGroupKey()); - pdc.remove(DisplayAPI.getPlaceableGroupPacketBasedKey()); pdc.remove(DisplayAPI.getPlaceableGroupPermissionKey()); pdc.remove(DisplayAPI.getPlaceableGroupRespectPlayerFacing()); pdc.remove(DisplayAPI.getPlaceableGroupRespectBlockFace()); + pdc.remove(DisplayAPI.getPlaceableGroupPlaceSounds()); + pdc.remove(DisplayAPI.getPlaceableGroupBreakSounds()); + pdc.remove(DisplayAPI.getPlaceableGroupPlacerBreaksOnly()); + pdc.remove(DisplayAPI.getPlaceableGroupDropItem()); itemStack.setItemMeta(meta); } @@ -370,16 +388,6 @@ public static boolean hasData(@NotNull ItemStack itemStack){ } - /** - * Get whether the group associated with the given item will spawn as a {@link PacketDisplayEntityGroup} - * @param itemStack the item - * @return a boolean - */ - public static boolean isUsingPackets(@NotNull ItemStack itemStack){ - PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); - return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupPacketBasedKey(), PersistentDataType.BOOLEAN)); - } - /** * Check if an itemstack has a place permission, determining if a player can place its assigned group @@ -401,18 +409,6 @@ public static boolean hasPlacePermission(@NotNull ItemStack itemStack){ return pdc.get(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING); } - /** - * Check if the given player has permission to place the itemstack's assigned group - * @param itemStack the item - * @param player the player - * @return a boolean - */ - public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player player){ - String placePerm = getPlacePermission(itemStack); - if (placePerm == null) return true; - return player.hasPermission(placePerm); - } - /** * Get whether the group associated with the given item will respect the player's facing direction * @param itemStack the item @@ -433,14 +429,46 @@ public static boolean isRespectingBlockFace(@NotNull ItemStack itemStack){ return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN)); } + /** + * Get whether only the placer of a placed group can break it + * @param itemStack the item + * @return a boolean + */ + public static boolean isPlacerBreaksOnly(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupPlacerBreaksOnly(), PersistentDataType.BOOLEAN)); + } + + /** + * Get whether the itemstack used to place a group will drop when the group is broken + * @param itemStack the item + * @return a boolean + */ + public static boolean isDropItem(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupDropItem(), PersistentDataType.BOOLEAN)); + } + + /** + * Check if the given player has permission to place the itemstack's assigned group + * @param itemStack the item + * @param player the player + * @return a boolean + */ + public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player player){ + String placePerm = getPlacePermission(itemStack); + if (placePerm == null) return true; + return player.hasPermission(placePerm); + } + /** * Spawn the placeable group stored on an item * @param itemStack the item * @param spawnLocation the spawn location - * @return an {@link ActiveGroup} or null if the itemstack does not contain placeable group data, or if the {@link PreItemPlaceGroupEvent} is cancelled + * @return a {@link PacketDisplayEntityGroup} or null if the itemstack does not contain placeable group data, or if the {@link PreItemPlaceGroupEvent} is cancelled */ - public static @Nullable CompletableFuture> spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @Nullable Player itemHolder){ + public static @Nullable PacketDisplayEntityGroup spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @Nullable Player itemHolder){ return spawnGroup(itemStack, spawnLocation, new Quaternionf(), itemHolder); } @@ -448,48 +476,53 @@ public static boolean isRespectingBlockFace(@NotNull ItemStack itemStack){ * Spawn the placeable group stored on an item * @param itemStack the item * @param spawnLocation the spawn location - * @return a completable future with an {@link ActiveGroup}, or null if the itemstack does not contain placeable group data or if the {@link PreItemPlaceGroupEvent} is cancelled + * @return a {@link PacketDisplayEntityGroup}, or null if the itemstack does not contain placeable group data or if the {@link PreItemPlaceGroupEvent} is cancelled */ - public static @Nullable CompletableFuture> spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @NotNull Quaternionf rotation, @Nullable Player itemHolder){ + public static @Nullable PacketDisplayEntityGroup spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @NotNull Quaternionf rotation, @Nullable Player itemHolder){ String tag = getGroupTag(itemStack); - boolean isPacket = isUsingPackets(itemStack); if (tag == null) return null; - return CompletableFuture.supplyAsync(() -> { - return DisplayGroupManager.getGroup(tag); - }).thenCompose(group -> { - if (group == null) return CompletableFuture.completedFuture(null); - if (!new PreItemPlaceGroupEvent(group, itemStack, itemHolder).callEvent()) return CompletableFuture.completedFuture(null); - - CompletableFuture> result = new CompletableFuture<>(); - - if (isPacket){ - try{ - PacketDisplayEntityGroup pg = group.createPacketGroup(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK, true, true); - pg.setPersistent(true); - pg.rotateDisplays(rotation); - new ItemPlaceGroupEvent(pg, itemStack, itemHolder).callEvent(); - result.complete(pg); - } - catch(NullPointerException e){ - result.completeExceptionally(e); - } - } - else{ - DisplayAPI.getScheduler().run(() -> { - try{ - SpawnedDisplayEntityGroup sg = group.spawn(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK); - sg.rotateDisplays(rotation); - new ItemPlaceGroupEvent(sg, itemStack, itemHolder).callEvent(); - result.complete(sg); - } catch (RuntimeException e) { - result.completeExceptionally(e); - } - }); - } - return result; + DisplayEntityGroup group = DisplayGroupManager.getGroup(tag); + if (group == null) return null; + if (!new PreItemPlaceGroupEvent(group, itemStack, itemHolder).callEvent()) return null; + + PacketDisplayEntityGroup pg = group.createPacketGroup(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK, true, true); + if (pg == null) return null; + pg.setPersistent(true); + pg.rotateDisplays(rotation); + + Bukkit.getScheduler().runTask(DisplayAPI.getPlugin(), () -> { + setBlockData(itemHolder, spawnLocation.getBlock(), itemStack.clone(), pg.getPersistentGlobalId()); + new ItemPlaceGroupEvent(pg, itemStack, itemHolder).callEvent(); }); + + return pg; + } + /** + * Get the UUID of the player who placed a group + * @param group the placed group + * @return a {@link UUID} or null if the group wasn't placed with an item or if a placer wasn't specified + */ + public static UUID getWhoPlaced(@NotNull PacketDisplayEntityGroup group){ + return null; } + private static void setBlockData(Player itemHolder, Block block, ItemStack itemStack, String groupID){ + block.setType(Material.BARRIER); + PersistentDataContainer pdc = new CustomBlockData(block, DisplayAPI.getPlugin()); + pdc.set(DisplayAPI.getPlaceableGroupId(), PersistentDataType.STRING, groupID); + + itemStack.setAmount(1); + pdc.set(DisplayAPI.getPlaceableGroupItemStack(), PersistentDataType.BYTE_ARRAY, itemStack.serializeAsBytes()); + if (itemHolder != null) pdc.set(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING, itemHolder.getUniqueId().toString()); + } + /** + * Get whether an itemstack can be used to place groups + * @param itemStack the itemstack + * @return a boolean + */ + public static boolean isValidItem(@NotNull ItemStack itemStack){ + return itemStack.getType() != Material.AIR && itemStack.getType().isBlock(); + } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index 62d1a3ea..86205063 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -87,13 +87,18 @@ private void initializeNamespacedKeys(){ //DO NOT CHANGE DisplayAPI.spawnAnimationTypeKey = new NamespacedKey(this, "spawnanimationtype"); DisplayAPI.spawnAnimationLoadMethodKey = new NamespacedKey(this, "spawnanimationloader"); DisplayAPI.chunkPacketGroupsKey = new NamespacedKey(this, "chunkpacketgroups"); + DisplayAPI.placeableGroupKey = new NamespacedKey(this, "placeablegroup"); - DisplayAPI.placeableGroupPacketBasedKey = new NamespacedKey(this, "placeablegroup_packet"); DisplayAPI.placeableGroupPermissionKey = new NamespacedKey(this, "placeablegroup_perm"); DisplayAPI.placeableGroupRespectFacingKey = new NamespacedKey(this, "placeablegroup_playerfacing"); DisplayAPI.placeableGroupRespectBlockFace = new NamespacedKey(this, "placeablegroup_blockface"); DisplayAPI.placeableGroupPlaceSounds = new NamespacedKey(this, "placeablegroup_placesounds"); DisplayAPI.placeableGroupBreakSounds = new NamespacedKey(this, "placeablegroup_breaksounds"); + DisplayAPI.placeableGroupPlacerBreaksOnly = new NamespacedKey(this, "placeablegroup_placerbreaks"); + DisplayAPI.placeableGroupDropItem = new NamespacedKey(this, "placeablegroup_dropitem"); + DisplayAPI.placeableGroupItemStack = new NamespacedKey(this, "placeablegroup_itemstack"); + DisplayAPI.placeableGroupPlacer = new NamespacedKey(this, "placeablegroup_placer"); + DisplayAPI.placeableGroupId = new NamespacedKey(this, "placeablegroup_groupid"); } @@ -131,14 +136,15 @@ private void initializeDependencies(){ private void registerListeners(){ Bukkit.getPluginManager().registerEvents(this, this); + Bukkit.getPluginManager().registerEvents(new DEULoadingListeners(), this); Bukkit.getPluginManager().registerEvents(new DatapackEntitySpawned(), this); + Bukkit.getPluginManager().registerEvents(new DEUEntityListener(), this); Bukkit.getPluginManager().registerEvents(new DEUPlayerConnectionListener(), this); Bukkit.getPluginManager().registerEvents(new DEUPlayerChatListener(), this); Bukkit.getPluginManager().registerEvents(new DEUPlayerWorldListener(), this); - Bukkit.getPluginManager().registerEvents(new DEUEntityListener(), this); - Bukkit.getPluginManager().registerEvents(new DEULoadingListeners(), this); - Bukkit.getPluginManager().registerEvents(new DEUInteractionListener(), this); Bukkit.getPluginManager().registerEvents(new DEUPlayerPlaceBlockListener(), this); + Bukkit.getPluginManager().registerEvents(new DEUPlayerDigListener(), this); + Bukkit.getPluginManager().registerEvents(new DEUInteractionListener(), this); Bukkit.getPluginManager().registerEvents(new DEUMannequinEditorListener(), this); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index ce0f04ec..b6f94463 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -39,6 +39,8 @@ public enum Permission { PLACE_TOGGLE_PACKET("deu.place.toggle.packet"), PLACE_TOGGLE_PLAYER_FACING("deu.place.toggle.playerfacing"), PLACE_TOGGLE_BLOCK_FACE("deu.place.toggle.blockface"), + PLACE_TOGGLE_DROP_ITEM("deu.place.toggle.dropitem"), + PLACE_TOGGLE_PLACER_ONLY("deu.place.toggle.placeronly"), PLACE_SET_PERMISSION("deu.place.setpermission"), PLACE_SOUND("deu.place.sound"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java index 9146ac68..d1deddc7 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -6,7 +6,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -18,9 +17,10 @@ public PlaceCMD() { new PlaceUnsetCMD(this); new PlaceSetPermissionCMD(this); new PlaceUnsetPermissionCMD(this); - new PlaceTogglePacketCMD(this); new PlaceTogglePlayerFacingCMD(this); new PlaceToggleBlockFaceCMD(this); + new PlaceToggleDropItemCMD(this); + new PlaceTogglePlacerOnlyCMD(this); new PlaceInfoCMD(this); new PlaceAddSoundCMD(this); } @@ -56,6 +56,8 @@ static void help(CommandSender sender, int page){ else{ CMDUtils.sendCMD(sender, "/deu place toggleplayerfacing", "Toggle whether the placed group will respect the player's facing direction. True by default"); CMDUtils.sendCMD(sender, "/deu place toggleblockface", "Toggle whether the placed group will respect the block face it is placed on. True by default"); + CMDUtils.sendCMD(sender, "/deu place toggledropitem", "Toggle whether the placed group will drop the item used to place it, when broken. True by default"); + CMDUtils.sendCMD(sender, "/deu place toggleplaceronly", "Toggle whether only the player who placed a group can break it. True by default"); CMDUtils.sendCMD(sender, "/deu place addsound ", "Add a sound to play when the block is placed or broken"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); @@ -63,7 +65,7 @@ static void help(CommandSender sender, int page){ static ItemStack getHeldItem(Player player, boolean mustBeAssigned){ ItemStack heldItem = player.getInventory().getItemInMainHand(); - if (!heldItem.getType().isBlock() || heldItem.getType() == Material.AIR){ + if (!PlaceableGroupManager.isValidItem(heldItem)){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You must be holding a block to do this command!", NamedTextColor.RED))); return null; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java index db87f6db..062130ea 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java @@ -32,7 +32,8 @@ public void execute(Player player, String[] args) { } boolean respectPlayerFacing = PlaceableGroupManager.isRespectingPlayerFacing(heldItem); boolean respectBlockFace = PlaceableGroupManager.isRespectingBlockFace(heldItem); - boolean packetBased = PlaceableGroupManager.isUsingPackets(heldItem); + boolean dropsItems = PlaceableGroupManager.isDropItem(heldItem); + boolean placerBreaksOnly = PlaceableGroupManager.isPlacerBreaksOnly(heldItem); List placeSounds = PlaceableGroupManager.getSounds(heldItem, true); List breakSounds = PlaceableGroupManager.getSounds(heldItem, false); @@ -40,8 +41,8 @@ public void execute(Player player, String[] args) { player.sendMessage(MiniMessage.miniMessage().deserialize("Place Permission: "+permission)); player.sendMessage(MiniMessage.miniMessage().deserialize("Respect Player Facing: "+(respectPlayerFacing ? "ENABLED" : "DISABLED"))); player.sendMessage(MiniMessage.miniMessage().deserialize("Respect Block Face: "+(respectBlockFace ? "ENABLED" : "DISABLED"))); - player.sendMessage(MiniMessage.miniMessage().deserialize("Packet Based: "+(packetBased ? "TRUE" : "FALSE"))); - + player.sendMessage(MiniMessage.miniMessage().deserialize("Item Drop: "+(dropsItems ? "ENABLED" : "DISABLED"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("Placer Breaks Only: "+(placerBreaksOnly ? "ENABLED" : "DISABLED"))); DEUSound.sendInfo(placeSounds, player, "Place Sounds", player.hasPermission(Permission.PLACE_SOUND.getPermission()) ? s -> diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java index 8bada0c9..d0e33147 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java @@ -5,10 +5,10 @@ import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.PlaceableGroupData; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -27,7 +27,7 @@ public void execute(Player player, String[] args) { } ItemStack heldItem = player.getInventory().getItemInMainHand(); - if (!heldItem.getType().isBlock() || heldItem.getType() == Material.AIR){ + if (!PlaceableGroupManager.isValidItem(heldItem)){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You must be holding a block to do this command!", NamedTextColor.RED))); return; } @@ -37,6 +37,5 @@ public void execute(Player player, String[] args) { new PlaceableGroupData(groupTag) .apply(heldItem); player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Assigned a group to your held block (Tag: "+groupTag+")"))); - player.sendMessage(MiniMessage.miniMessage().deserialize("| The group will spawn using packets")); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleDropItemCMD.java similarity index 59% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleDropItemCMD.java index 10874321..d114040d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePacketCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleDropItemCMD.java @@ -11,9 +11,9 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -class PlaceTogglePacketCMD extends PlayerSubCommand { - PlaceTogglePacketCMD(@NotNull DEUSubCommand parentSubCommand) { - super("togglepacket", parentSubCommand, Permission.PLACE_TOGGLE_PACKET); +class PlaceToggleDropItemCMD extends PlayerSubCommand { + PlaceToggleDropItemCMD(@NotNull DEUSubCommand parentSubCommand) { + super("toggledropitem", parentSubCommand, Permission.PLACE_TOGGLE_DROP_ITEM); } @Override @@ -21,13 +21,13 @@ public void execute(Player player, String[] args) { ItemStack heldItem = PlaceCMD.getHeldItem(player, true); if (heldItem == null) return; - if (PlaceableGroupManager.isUsingPackets(heldItem)){ - PlaceableGroupManager.setUsePackets(heldItem, false); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will no longer spawn using packets", NamedTextColor.RED))); + if (PlaceableGroupManager.isDropItem(heldItem)){ + PlaceableGroupManager.setDropItemOnBreak(heldItem, false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will no longer drop the item used to place it", NamedTextColor.RED))); } else{ - PlaceableGroupManager.setUsePackets(heldItem, true); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will spawn using packets", NamedTextColor.GREEN))); + PlaceableGroupManager.setDropItemOnBreak(heldItem, true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will drop the item used to place it", NamedTextColor.GREEN))); } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlacerOnlyCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlacerOnlyCMD.java new file mode 100644 index 00000000..2917c1bf --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlacerOnlyCMD.java @@ -0,0 +1,33 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceTogglePlacerOnlyCMD extends PlayerSubCommand { + PlaceTogglePlacerOnlyCMD(@NotNull DEUSubCommand parentSubCommand) { + super("toggleplaceronly", parentSubCommand, Permission.PLACE_TOGGLE_PLACER_ONLY); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (PlaceableGroupManager.isPlacerBreaksOnly(heldItem)){ + PlaceableGroupManager.setPlacerBreaksOnly(heldItem, false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group can only broken by any player", NamedTextColor.RED))); + } + else{ + PlaceableGroupManager.setPlacerBreaksOnly(heldItem, true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group can only be broken by the player who placed it", NamedTextColor.GREEN))); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java new file mode 100644 index 00000000..eeb9434e --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java @@ -0,0 +1,98 @@ +package net.donnypz.displayentityutils.listeners.player; + +import com.jeff_media.customblockdata.CustomBlockData; +import io.papermc.paper.event.block.BlockBreakProgressUpdateEvent; +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.events.PlacedGroupBreakEvent; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +import java.util.UUID; + +public class DEUPlayerDigListener implements Listener { + + @EventHandler(priority = EventPriority.HIGHEST) + public void onDig(BlockBreakProgressUpdateEvent e){ + if (!(e.getEntity() instanceof Player player)){ + return; + } + + if (e.getProgress() != 0){ + return; + } + + Block b = e.getBlock(); + breakPlacedGroup(player, b); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onBreak(BlockBreakEvent e){ + Player p = e.getPlayer(); + Block b = e.getBlock(); + if (p.getGameMode() == GameMode.CREATIVE && b.getType() == Material.BARRIER){ + breakPlacedGroup(e.getPlayer(), e.getBlock()); + } + } + + private void breakPlacedGroup(Player player, Block block){ + PersistentDataContainer pdc = new CustomBlockData(block, DisplayAPI.getPlugin()); + + String groupId = pdc.get(DisplayAPI.getPlaceableGroupId(), PersistentDataType.STRING); + if (groupId == null) return; //Not a placed group block + + PacketDisplayEntityGroup group = PacketDisplayEntityGroup.getGroup(groupId); + if (group == null){ //group was removed by other means + clearPDC(pdc); + if (block.getType() == Material.BARRIER) block.setType(Material.AIR); + return; + } + + if (!new PlacedGroupBreakEvent(block, group, player).callEvent()) return; + + + byte[] itemStackArr = pdc.get(DisplayAPI.getPlaceableGroupItemStack(), PersistentDataType.BYTE_ARRAY); + ItemStack itemStack = ItemStack.deserializeBytes(itemStackArr); + + String uuidString = pdc.get(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING); + UUID placerUUID = uuidString == null ? null : UUID.fromString(uuidString); + + if (placerUUID != null && PlaceableGroupManager.isPlacerBreaksOnly(itemStack) && !player.getUniqueId().equals(placerUUID)) { + player.sendMessage(Component.text("Only the player who placed this can break it!", NamedTextColor.RED)); + return; + } + + Location blockLoc = block.getLocation().add(0.5f, 0.5f, 0.5f); + + if (PlaceableGroupManager.isDropItem(itemStack)) { + final ItemStack finalItemStack = itemStack; + DisplayAPI.getScheduler().run(() -> { + block.getWorld().dropItemNaturally(blockLoc, finalItemStack); + }); + } + + group.unregister(); + PlaceableGroupManager.playSounds(itemStack, blockLoc, false); + clearPDC(pdc); + block.setType(Material.AIR); + } + + private void clearPDC(PersistentDataContainer pdc){ + pdc.remove(DisplayAPI.getPlaceableGroupId()); + pdc.remove(DisplayAPI.getPlaceableGroupPlacer()); + pdc.remove(DisplayAPI.getPlaceableGroupItemStack()); + } +} From 22cafd1e5c93ce39e1848e8c023ab1552aa23e12 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 18:27:53 -0600 Subject: [PATCH 104/139] Fix issues with data not saving in chunks correctly --- .../managers/DisplayGroupManager.java | 12 ++++++-- .../managers/PlaceableGroupManager.java | 4 ++- .../player/DEUPlayerDigListener.java | 28 ++++++++++--------- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java index a91e5a24..eb97034e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java @@ -860,9 +860,17 @@ public static void removePersistentPacketGroups(@NotNull Chunk chunk){ @ApiStatus.Internal public static void spawnPersistentPacketGroups(@NotNull Chunk chunk){ List list = getChunkList(chunk.getPersistentDataContainer()); - for (String json : list){ + Iterator i = list.iterator(); + + while (i.hasNext()){ + String json = i.next(); PersistentPacketGroup cpg = gson.fromJson(json, PersistentPacketGroup.class); - cpg.spawn(chunk).setPersistentIds(cpg.id, chunk); + if (cpg == null){ + i.remove(); + } + else{ + cpg.spawn(chunk).setPersistentIds(cpg.id, chunk); + } } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index 5af47f15..b9be5452 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -19,6 +19,7 @@ import java.io.*; import java.util.ArrayList; +import java.util.Base64; import java.util.List; import java.util.UUID; @@ -513,7 +514,8 @@ private static void setBlockData(Player itemHolder, Block block, ItemStack itemS pdc.set(DisplayAPI.getPlaceableGroupId(), PersistentDataType.STRING, groupID); itemStack.setAmount(1); - pdc.set(DisplayAPI.getPlaceableGroupItemStack(), PersistentDataType.BYTE_ARRAY, itemStack.serializeAsBytes()); + String b64 = Base64.getEncoder().encodeToString(itemStack.serializeAsBytes()); + pdc.set(DisplayAPI.getPlaceableGroupItemStack(), PersistentDataType.STRING, b64); if (itemHolder != null) pdc.set(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING, itemHolder.getUniqueId().toString()); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java index eeb9434e..237f4550 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java @@ -4,6 +4,7 @@ import io.papermc.paper.event.block.BlockBreakProgressUpdateEvent; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.events.PlacedGroupBreakEvent; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.managers.PlaceableGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.kyori.adventure.text.Component; @@ -18,9 +19,9 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; +import java.util.Base64; import java.util.UUID; public class DEUPlayerDigListener implements Listener { @@ -49,14 +50,14 @@ public void onBreak(BlockBreakEvent e){ } private void breakPlacedGroup(Player player, Block block){ - PersistentDataContainer pdc = new CustomBlockData(block, DisplayAPI.getPlugin()); + CustomBlockData data = new CustomBlockData(block, DisplayAPI.getPlugin()); - String groupId = pdc.get(DisplayAPI.getPlaceableGroupId(), PersistentDataType.STRING); + String groupId = data.get(DisplayAPI.getPlaceableGroupId(), PersistentDataType.STRING); if (groupId == null) return; //Not a placed group block PacketDisplayEntityGroup group = PacketDisplayEntityGroup.getGroup(groupId); if (group == null){ //group was removed by other means - clearPDC(pdc); + clearPDC(data); if (block.getType() == Material.BARRIER) block.setType(Material.AIR); return; } @@ -64,10 +65,10 @@ private void breakPlacedGroup(Player player, Block block){ if (!new PlacedGroupBreakEvent(block, group, player).callEvent()) return; - byte[] itemStackArr = pdc.get(DisplayAPI.getPlaceableGroupItemStack(), PersistentDataType.BYTE_ARRAY); - ItemStack itemStack = ItemStack.deserializeBytes(itemStackArr); + String b64 = data.get(DisplayAPI.getPlaceableGroupItemStack(), PersistentDataType.STRING); + ItemStack itemStack = ItemStack.deserializeBytes(Base64.getDecoder().decode(b64)); - String uuidString = pdc.get(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING); + String uuidString = data.get(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING); UUID placerUUID = uuidString == null ? null : UUID.fromString(uuidString); if (placerUUID != null && PlaceableGroupManager.isPlacerBreaksOnly(itemStack) && !player.getUniqueId().equals(placerUUID)) { @@ -84,15 +85,16 @@ private void breakPlacedGroup(Player player, Block block){ }); } - group.unregister(); + DisplayGroupManager.removePersistentPacketGroup(group, true); PlaceableGroupManager.playSounds(itemStack, blockLoc, false); - clearPDC(pdc); + clearPDC(data); block.setType(Material.AIR); } - private void clearPDC(PersistentDataContainer pdc){ - pdc.remove(DisplayAPI.getPlaceableGroupId()); - pdc.remove(DisplayAPI.getPlaceableGroupPlacer()); - pdc.remove(DisplayAPI.getPlaceableGroupItemStack()); + private void clearPDC(CustomBlockData data){ + data.clear(); +// data.remove(DisplayAPI.getPlaceableGroupId()); +// data.remove(DisplayAPI.getPlaceableGroupPlacer()); +// data.remove(DisplayAPI.getPlaceableGroupItemStack()); } } From f241502ecf241b0a35186d1be6b9d557a9fbcfc7 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 18:42:47 -0600 Subject: [PATCH 105/139] Fix placed group not saving with rotation applied --- .../displayentityutils/managers/PlaceableGroupManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index b9be5452..6b40fea9 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -489,8 +489,8 @@ public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player pla PacketDisplayEntityGroup pg = group.createPacketGroup(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK, true, true); if (pg == null) return null; - pg.setPersistent(true); pg.rotateDisplays(rotation); + pg.setPersistent(true); Bukkit.getScheduler().runTask(DisplayAPI.getPlugin(), () -> { setBlockData(itemHolder, spawnLocation.getBlock(), itemStack.clone(), pg.getPersistentGlobalId()); From 6e28ce3432fc4f7111f01c28cff1f6dfa8248f4b Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 18:44:03 -0600 Subject: [PATCH 106/139] Correctly unregister persistent packet-based groups --- .../skript/effects/EffActiveGroupUnregister.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/effects/EffActiveGroupUnregister.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/effects/EffActiveGroupUnregister.java index 064be915..5cc26ec3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/effects/EffActiveGroupUnregister.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/effects/EffActiveGroupUnregister.java @@ -9,6 +9,7 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; @@ -48,7 +49,12 @@ protected void execute(Event event) { sg.unregister(despawn, forced); } else if (g instanceof PacketDisplayEntityGroup pg){ - pg.unregister(); + if (pg.isPersistent()){ + DisplayGroupManager.removePersistentPacketGroup(pg, true); + } + else{ + pg.unregister(); + } } } From 13cea78abd6e5807368472f00fafeb649066ec08 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 19:13:51 -0600 Subject: [PATCH 107/139] Prevent placed group teleportation --- .../events/GroupSpawnedEvent.java | 16 ++++++++++++++++ .../managers/DisplayGroupManager.java | 17 ++++++++++++----- .../DisplayEntities/DisplayEntityGroup.java | 4 ++++ .../PacketDisplayEntityGroup.java | 19 +++++++++++++++++-- .../command/group/GroupMoveCMD.java | 6 ++++++ .../command/group/GroupMoveHereCMD.java | 6 ++++++ 6 files changed, 61 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java index 722419a6..2fa33c7a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java @@ -1,9 +1,15 @@ package net.donnypz.displayentityutils.events; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; +import org.bukkit.Location; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; /** @@ -54,8 +60,18 @@ public enum SpawnReason{ */ PLAYER_SENT_CHUNK, PLAYER_SENT_PASSENGER_GROUP, + /** + * This is only applicable to the {@link PacketDisplayEntityGroup} placed by an item, through {@link PlaceableGroupManager#spawnGroup(ItemStack, Location, Player)} or similar + */ + @ApiStatus.Internal ITEMSTACK, + /** + * This is only applicable to the {@link PacketDisplayEntityGroup} placed by an item, through {@link PlaceableGroupManager#spawnGroup(ItemStack, Location, Player)} or similar + */ + @ApiStatus.Internal + CHUNK_LOAD_PLACED, SKRIPT, + @ApiStatus.Internal INTERNAL; } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java index eb97034e..a9e04c24 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java @@ -707,7 +707,7 @@ static void addPersistentPacketGroupSilent(@NotNull PacketDisplayEntityGroup gro else{ id = gson.fromJson(list.getLast(), PersistentPacketGroup.class).id+1; } - PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, group.isAutoShow()); + PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, group.isAutoShow(), group.isPlaced()); if (cpg == null) return; String json = gson.toJson(cpg); @@ -731,7 +731,7 @@ public static PacketDisplayEntityGroup addPersistentPacketGroup(@NotNull Locatio else{ id = gson.fromJson(list.getLast(), PersistentPacketGroup.class).id+1; } - PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, autoShow); + PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, autoShow, false); if (cpg == null) return null; String json = gson.toJson(cpg); @@ -760,7 +760,7 @@ public static PacketDisplayEntityGroup addPersistentPacketGroup(@NotNull Locatio PacketDisplayEntityGroup pdeg = displayEntityGroup.createPacketGroup(location, spawnReason, true, settings); displayEntityGroup = pdeg.toDisplayEntityGroup(); - PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, pdeg.isAutoShow()); + PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, pdeg.isAutoShow(), false); if (cpg != null){ String json = gson.toJson(cpg); list.add(json); @@ -903,10 +903,11 @@ static class PersistentPacketGroup { String groupBase64; String groupTag; boolean autoShow = true; //Don't change + boolean isPlaced = false; private PersistentPacketGroup(){} - static PersistentPacketGroup create(int id, Location location, DisplayEntityGroup group, boolean autoShow){ + static PersistentPacketGroup create(int id, Location location, DisplayEntityGroup group, boolean autoShow, boolean isPlaced){ PersistentPacketGroup cpg = new PersistentPacketGroup(); cpg.id = id; cpg.x = location.x(); @@ -916,6 +917,7 @@ static PersistentPacketGroup create(int id, Location location, DisplayEntityGrou cpg.pitch = location.getPitch(); cpg.groupTag = group.getTag(); cpg.autoShow = autoShow; + cpg.isPlaced = isPlaced; cpg.setGroup(group); return (cpg.groupBase64 == null) ? null : cpg; } @@ -965,7 +967,12 @@ public PacketDisplayEntityGroup spawn(Chunk chunk){ Location spawnLoc = getLocation(chunk); DisplayEntityGroup g = getGroup(); if (spawnLoc == null || g == null) return null; - return g.createPacketGroup(spawnLoc, GroupSpawnedEvent.SpawnReason.INTERNAL, true, autoShow); + if (isPlaced){ + return g.createPacketGroup(spawnLoc, GroupSpawnedEvent.SpawnReason.CHUNK_LOAD_PLACED, true, autoShow); + } + else{ + return g.createPacketGroup(spawnLoc, GroupSpawnedEvent.SpawnReason.INTERNAL, true, autoShow); + } } } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java index 9d4a9ae7..8569d0b4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java @@ -332,6 +332,10 @@ public String getTag() { packetGroup.autoCull(widthCullingAdder, heightCullingAdder); } + if (spawnReason == GroupSpawnedEvent.SpawnReason.CHUNK_LOAD_PLACED || spawnReason == GroupSpawnedEvent.SpawnReason.ITEMSTACK){ + packetGroup.isPlaced = true; + } + return packetGroup; } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index 27d762b2..fc6cd6ad 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -40,6 +40,7 @@ public class PacketDisplayEntityGroup extends ActiveGroup autoShowCondition; int persistentLocalId = -1; String persistentGlobalId; + boolean isPlaced; PacketDisplayEntityGroup(String tag){ @@ -125,6 +126,11 @@ public static String buildPersistentGlobalId(@NotNull Chunk chunk, int localId){ return chunk.getWorld().getName()+"|"+chunk.getChunkKey()+"|"+localId; //world,chunkkey,localid } + /** + * {@inheritDoc} + *

The group cannot become persistent if {@link #isRiding()} is true + *
The group cannot become non-persistent if {@link #isPlaced()} is true + */ @Override public void setPersistent(boolean persistent) { if (persistent){ @@ -134,7 +140,7 @@ public void setPersistent(boolean persistent) { } } else{ - if (isPersistent()){ + if (isPersistent() && !isPlaced){ DisplayGroupManager.removePersistentPacketGroup(this, false); setPersistentIds(-1, null); } @@ -150,6 +156,14 @@ public boolean isPersistent(){ return this.persistentLocalId != -1; } + /** + * Get whether this group was placed by a player's held item + * @return a boolean + */ + public boolean isPlaced(){ + return this.isPlaced; + } + @ApiStatus.Internal public static void removeWorld(@NotNull World world){ //Viewers are already removed since this is only called on unloaded worlds (Viewers are forced to a new world) @@ -575,10 +589,11 @@ public void run() { /** * {@inheritDoc} *
It is not recommended to use this multiple times in the same tick, unexpected results may occur. + *

This will fail if {@link #isRiding()} or {@link #isPlaced()} is true */ @Override public boolean teleport(@NotNull Location tpLocation, boolean respectGroupDirection){ - if (isRiding()) return false; + if (isRiding() || isPlaced) return false; Location oldMasterLoc = getLocation(); attemptLocationUpdate(oldMasterLoc, tpLocation); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java index 12c0869c..85e6224f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java @@ -4,6 +4,7 @@ import net.donnypz.displayentityutils.command.*; import net.donnypz.displayentityutils.utils.Direction; import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -32,6 +33,11 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ return; } + if (group instanceof PacketDisplayEntityGroup pg && pg.isPlaced()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot move a group placed by a player's item!", NamedTextColor.RED))); + return; + } + try{ Direction direction = Direction.valueOf(args[2].toUpperCase()); double distance = Double.parseDouble(args[3]); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveHereCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveHereCMD.java index 9d70ed2d..f50eb7f1 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveHereCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveHereCMD.java @@ -3,6 +3,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.*; import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -25,6 +26,11 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ return; } + if (group instanceof PacketDisplayEntityGroup pg && pg.isPlaced()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot move a group placed by a player's item!", NamedTextColor.RED))); + return; + } + if (!group.teleport(player.getLocation(), true)){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to move your selected group to your location", NamedTextColor.RED))); return; From 44fbe96ac27bc0979e88b69240404dabb5335ca1 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 20:03:25 -0600 Subject: [PATCH 108/139] Add "/deu place whoplaced" --- .../managers/PlaceableGroupManager.java | 23 +++++++- .../command/Permission.java | 1 + .../command/place/PlaceCMD.java | 2 + .../command/place/PlaceWhoPlacedCMD.java | 53 +++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index 6b40fea9..7ed7dbde 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -499,13 +499,32 @@ public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player pla return pg; } + + /** * Get the UUID of the player who placed a group * @param group the placed group * @return a {@link UUID} or null if the group wasn't placed with an item or if a placer wasn't specified */ - public static UUID getWhoPlaced(@NotNull PacketDisplayEntityGroup group){ - return null; + public static @Nullable UUID getWhoPlaced(@NotNull PacketDisplayEntityGroup group){ + if (!group.isPlaced()) return null; + + Location loc = group.getLocation(); + if (loc == null) return null; + + return getWhoPlaced(loc.getBlock()); + } + + /** + * Get the UUID of the player who placed a group + * @param block the block where a placed group is + * @return a {@link UUID} or null if the group wasn't placed with an item or if a placer wasn't specified + */ + public static @Nullable UUID getWhoPlaced(@NotNull Block block){ + if (!CustomBlockData.hasCustomBlockData(block, DisplayAPI.getPlugin())) return null; + CustomBlockData data = new CustomBlockData(block, DisplayAPI.getPlugin()); + String uuidStr = data.get(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING); + return uuidStr == null ? null : UUID.fromString(uuidStr); } private static void setBlockData(Player itemHolder, Block block, ItemStack itemStack, String groupID){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index b6f94463..49294b73 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -43,6 +43,7 @@ public enum Permission { PLACE_TOGGLE_PLACER_ONLY("deu.place.toggle.placeronly"), PLACE_SET_PERMISSION("deu.place.setpermission"), PLACE_SOUND("deu.place.sound"), + PLACE_WHO_PLACED("deu.place.whoplaced"), PARTS_INFO("deu.parts.info"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java index d1deddc7..d8be44b3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -23,6 +23,7 @@ public PlaceCMD() { new PlaceTogglePlacerOnlyCMD(this); new PlaceInfoCMD(this); new PlaceAddSoundCMD(this); + new PlaceWhoPlacedCMD(this); } @Override @@ -59,6 +60,7 @@ static void help(CommandSender sender, int page){ CMDUtils.sendCMD(sender, "/deu place toggledropitem", "Toggle whether the placed group will drop the item used to place it, when broken. True by default"); CMDUtils.sendCMD(sender, "/deu place toggleplaceronly", "Toggle whether only the player who placed a group can break it. True by default"); CMDUtils.sendCMD(sender, "/deu place addsound ", "Add a sound to play when the block is placed or broken"); + CMDUtils.sendCMD(sender, "/deu place whoplaced", "Get the name and UUID of the player who placed a group"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java new file mode 100644 index 00000000..bb8d04eb --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java @@ -0,0 +1,53 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +class PlaceWhoPlacedCMD extends PlayerSubCommand { + PlaceWhoPlacedCMD(@NotNull DEUSubCommand parentSubCommand) { + super("whoplaced", parentSubCommand, Permission.PLACE_WHO_PLACED); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + Block targetBlock = player.getTargetBlock(null, 15); + final UUID uuid = PlaceableGroupManager.getWhoPlaced(targetBlock); + if (uuid == null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You are not looking at a placed group's block! (Barrier)", NamedTextColor.RED))); + return; + } + player.sendMessage(DisplayAPI.pluginPrefixLong); + player.sendMessage(Component.text("Block Location: ") + .append(Component.text(targetBlock.getX()+", "+targetBlock.getY()+", "+targetBlock.getZ(), NamedTextColor.YELLOW))); + DisplayAPI.getScheduler().runAsync(() -> { + OfflinePlayer plr = Bukkit.getOfflinePlayer(uuid); + player.sendMessage(Component.text("Player: ") + .append(Component.text(plr.getName(), NamedTextColor.YELLOW) + .clickEvent(ClickEvent.copyToClipboard(plr.getName())) + .hoverEvent(HoverEvent.showText(Component.text("Click to copy"))))); + player.sendMessage(Component.text("UUID: ") + .append(Component.text(uuid.toString(), NamedTextColor.YELLOW) + .clickEvent(ClickEvent.copyToClipboard(uuid.toString())) + .hoverEvent(HoverEvent.showText(Component.text("Click to copy"))) + )); + }); + } +} From dffb756f271c4c03c5674adf0ce75699acae891b Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 20:03:53 -0600 Subject: [PATCH 109/139] Don't drop broken group's item for creative players --- .../listeners/player/DEUPlayerDigListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java index 237f4550..65d5a0a0 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java @@ -78,7 +78,7 @@ private void breakPlacedGroup(Player player, Block block){ Location blockLoc = block.getLocation().add(0.5f, 0.5f, 0.5f); - if (PlaceableGroupManager.isDropItem(itemStack)) { + if (PlaceableGroupManager.isDropItem(itemStack) && player.getGameMode() != GameMode.CREATIVE) { final ItemStack finalItemStack = itemStack; DisplayAPI.getScheduler().run(() -> { block.getWorld().dropItemNaturally(blockLoc, finalItemStack); From 9643c6fa7e8bcc64d07a59e54b425adc98605e61 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 20:28:44 -0600 Subject: [PATCH 110/139] Added "/deu place getitem" --- .../managers/PlaceableGroupManager.java | 28 +++++++++++++++ .../command/Permission.java | 1 + .../command/place/PlaceCMD.java | 2 ++ .../command/place/PlaceGetItemCMD.java | 36 +++++++++++++++++++ .../player/DEUPlayerDigListener.java | 4 +-- 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceGetItemCMD.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index 7ed7dbde..21f189e1 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -527,6 +527,33 @@ public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player pla return uuidStr == null ? null : UUID.fromString(uuidStr); } + /** + * Get the ItemStack used to place a group + * @param group the placed group + * @return an item or null if the group wasn't placed with an item + */ + public static @Nullable ItemStack getItemStack(@NotNull PacketDisplayEntityGroup group){ + if (!group.isPlaced()) return null; + + Location loc = group.getLocation(); + if (loc == null) return null; + + return getItemStack(loc.getBlock()); + } + + /** + * Get the ItemStack used to place a group + * @param block the block where a placed group is + * @return an item or null if the group wasn't placed with an item + */ + public static @Nullable ItemStack getItemStack(@NotNull Block block){ + if (!CustomBlockData.hasCustomBlockData(block, DisplayAPI.getPlugin())) return null; + CustomBlockData data = new CustomBlockData(block, DisplayAPI.getPlugin()); + + String b64 = data.get(DisplayAPI.getPlaceableGroupItemStack(), PersistentDataType.STRING); + return ItemStack.deserializeBytes(Base64.getDecoder().decode(b64)); + } + private static void setBlockData(Player itemHolder, Block block, ItemStack itemStack, String groupID){ block.setType(Material.BARRIER); PersistentDataContainer pdc = new CustomBlockData(block, DisplayAPI.getPlugin()); @@ -538,6 +565,7 @@ private static void setBlockData(Player itemHolder, Block block, ItemStack itemS if (itemHolder != null) pdc.set(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING, itemHolder.getUniqueId().toString()); } + /** * Get whether an itemstack can be used to place groups * @param itemStack the itemstack diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index 49294b73..3300ad70 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -36,6 +36,7 @@ public enum Permission { PLACE_INFO("deu.place.info"), PLACE_SET_ITEM("deu.place.setitem"), + PLACE_GET_ITEM("deu.place.getitem"), PLACE_TOGGLE_PACKET("deu.place.toggle.packet"), PLACE_TOGGLE_PLAYER_FACING("deu.place.toggle.playerfacing"), PLACE_TOGGLE_BLOCK_FACE("deu.place.toggle.blockface"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java index d8be44b3..867e3b10 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -24,6 +24,7 @@ public PlaceCMD() { new PlaceInfoCMD(this); new PlaceAddSoundCMD(this); new PlaceWhoPlacedCMD(this); + new PlaceGetItemCMD(this); } @Override @@ -61,6 +62,7 @@ static void help(CommandSender sender, int page){ CMDUtils.sendCMD(sender, "/deu place toggleplaceronly", "Toggle whether only the player who placed a group can break it. True by default"); CMDUtils.sendCMD(sender, "/deu place addsound ", "Add a sound to play when the block is placed or broken"); CMDUtils.sendCMD(sender, "/deu place whoplaced", "Get the name and UUID of the player who placed a group"); + CMDUtils.sendCMD(sender, "/deu place getitem", "Get the item used to placed a group"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceGetItemCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceGetItemCMD.java new file mode 100644 index 00000000..a814ccd0 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceGetItemCMD.java @@ -0,0 +1,36 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceGetItemCMD extends PlayerSubCommand { + PlaceGetItemCMD(@NotNull DEUSubCommand parentSubCommand) { + super("getitem", parentSubCommand, Permission.PLACE_GET_ITEM); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + + Block targetBlock = player.getTargetBlock(null, 15); + final ItemStack itemStack = PlaceableGroupManager.getItemStack(targetBlock); + if (itemStack == null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You are not looking at a placed group's block! (Barrier)", NamedTextColor.RED))); + return; + } + + player.give(itemStack); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have been given the item to place the group", NamedTextColor.GREEN))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java index 65d5a0a0..cb53c2e0 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java @@ -65,8 +65,8 @@ private void breakPlacedGroup(Player player, Block block){ if (!new PlacedGroupBreakEvent(block, group, player).callEvent()) return; - String b64 = data.get(DisplayAPI.getPlaceableGroupItemStack(), PersistentDataType.STRING); - ItemStack itemStack = ItemStack.deserializeBytes(Base64.getDecoder().decode(b64)); + ItemStack itemStack = PlaceableGroupManager.getItemStack(block); + String uuidString = data.get(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING); UUID placerUUID = uuidString == null ? null : UUID.fromString(uuidString); From 2825efc687cc527bdd356768551c8841360fd64b Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 20:38:55 -0600 Subject: [PATCH 111/139] remove held item condition --- .../displayentityutils/command/place/PlaceWhoPlacedCMD.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java index bb8d04eb..bdc7b63f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java @@ -13,7 +13,6 @@ import org.bukkit.OfflinePlayer; import org.bukkit.block.Block; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import java.util.UUID; @@ -25,9 +24,6 @@ class PlaceWhoPlacedCMD extends PlayerSubCommand { @Override public void execute(Player player, String[] args) { - ItemStack heldItem = PlaceCMD.getHeldItem(player, true); - if (heldItem == null) return; - Block targetBlock = player.getTargetBlock(null, 15); final UUID uuid = PlaceableGroupManager.getWhoPlaced(targetBlock); if (uuid == null){ From 332c0a1c39546f9185ebbf9f637859b4fad4c6e0 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 20:59:46 -0600 Subject: [PATCH 112/139] Add "/deu place breakmode" & fix create players breaking barrier w/o removing placed group --- .../displayentityutils/managers/DEUUser.java | 18 ++++++++++ .../command/Permission.java | 1 + .../command/place/PlaceBreakModeCMD.java | 32 +++++++++++++++++ .../command/place/PlaceCMD.java | 8 +++-- .../player/DEUPlayerDigListener.java | 34 ++++++++++++------- 5 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceBreakModeCMD.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java index c56571d6..4fee270d 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java @@ -42,6 +42,8 @@ public class DEUUser { private final Object animationCameraLock = new Object(); private UUID cameraPlayerUUID; + private boolean placedGroupBreakMode = false; + private DEUUser(UUID userUUID){ this.userUUID = userUUID; @@ -320,6 +322,22 @@ public boolean isInAnimationCamera(@NotNull UUID cameraPlayerUUID){ } } + /** + * Set whether this user should be able to break any placed group, regardless of who placed it + * @param breakMode whether the break mode should be enabled + */ + public void setPlacedGroupBreakMode(boolean breakMode){ + this.placedGroupBreakMode = breakMode; + } + + /** + * Get whether this user can break any placed group, regardless of who placed it + * @return a boolean + */ + public boolean isInPlacedGroupBreakMode(){ + return this.placedGroupBreakMode; + } + /** * Check if this user is tracking a {@link PacketDisplayEntityPart} * @param part the {@link PacketDisplayEntityPart} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index 3300ad70..9177d014 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -45,6 +45,7 @@ public enum Permission { PLACE_SET_PERMISSION("deu.place.setpermission"), PLACE_SOUND("deu.place.sound"), PLACE_WHO_PLACED("deu.place.whoplaced"), + PLACE_BREAK_MODE("deu.place.breakmode"), PARTS_INFO("deu.parts.info"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceBreakModeCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceBreakModeCMD.java new file mode 100644 index 00000000..9daef9d5 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceBreakModeCMD.java @@ -0,0 +1,32 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceBreakModeCMD extends PlayerSubCommand { + PlaceBreakModeCMD(@NotNull DEUSubCommand parentSubCommand) { + super("breakmode", parentSubCommand, Permission.PLACE_BREAK_MODE); + } + + @Override + public void execute(Player player, String[] args) { + DEUUser user = DEUUser.getOrCreateUser(player); + if (user.isInPlacedGroupBreakMode()){ + user.setPlacedGroupBreakMode(false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have exited break-mode and can only break groups you have placed", NamedTextColor.RED))); + } + else{ + user.setPlacedGroupBreakMode(true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have entered break-mode and can break any placed groups", NamedTextColor.GREEN))); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java index 867e3b10..8d566de3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -25,6 +25,7 @@ public PlaceCMD() { new PlaceAddSoundCMD(this); new PlaceWhoPlacedCMD(this); new PlaceGetItemCMD(this); + new PlaceBreakModeCMD(this); } @Override @@ -49,19 +50,22 @@ static void help(CommandSender sender, int page){ if (page == 1){ CMDUtils.sendCMD(sender, "/deu place help", "Get help for placeable groups"); CMDUtils.sendCMD(sender, "/deu place info", "Get placeable group information for your held block"); + CMDUtils.sendCMD(sender, "/deu place breakmode", "Enter/Exit break-mode allowing you to break any placed group"); CMDUtils.sendCMD(sender, "/deu place set ", "Assign a group to your held block, which will be spawned when the block is placed"); CMDUtils.sendCMD(sender, "/deu place unset", "Unassign a group from your held block"); CMDUtils.sendCMD(sender, "/deu place setpermission", "Set the permission required to place the group"); CMDUtils.sendCMD(sender, "/deu place unsetpermission", "Set the permission required to place the group"); - CMDUtils.sendCMD(sender, "/deu place togglepacket", "Toggle whether the placed group will be packet-based. True by default"); } - else{ + else if (page == 2){ + CMDUtils.sendCMD(sender, "/deu place togglepacket", "Toggle whether the placed group will be packet-based. True by default"); CMDUtils.sendCMD(sender, "/deu place toggleplayerfacing", "Toggle whether the placed group will respect the player's facing direction. True by default"); CMDUtils.sendCMD(sender, "/deu place toggleblockface", "Toggle whether the placed group will respect the block face it is placed on. True by default"); CMDUtils.sendCMD(sender, "/deu place toggledropitem", "Toggle whether the placed group will drop the item used to place it, when broken. True by default"); CMDUtils.sendCMD(sender, "/deu place toggleplaceronly", "Toggle whether only the player who placed a group can break it. True by default"); CMDUtils.sendCMD(sender, "/deu place addsound ", "Add a sound to play when the block is placed or broken"); CMDUtils.sendCMD(sender, "/deu place whoplaced", "Get the name and UUID of the player who placed a group"); + } + else{ CMDUtils.sendCMD(sender, "/deu place getitem", "Get the item used to placed a group"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java index cb53c2e0..81db2ea3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java @@ -3,7 +3,9 @@ import com.jeff_media.customblockdata.CustomBlockData; import io.papermc.paper.event.block.BlockBreakProgressUpdateEvent; import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.events.PlacedGroupBreakEvent; +import net.donnypz.displayentityutils.managers.DEUUser; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.managers.PlaceableGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; @@ -21,7 +23,6 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataType; -import java.util.Base64; import java.util.UUID; public class DEUPlayerDigListener implements Listener { @@ -40,42 +41,48 @@ public void onDig(BlockBreakProgressUpdateEvent e){ breakPlacedGroup(player, b); } - @EventHandler(priority = EventPriority.MONITOR) + @EventHandler(priority = EventPriority.HIGHEST) public void onBreak(BlockBreakEvent e){ Player p = e.getPlayer(); Block b = e.getBlock(); if (p.getGameMode() == GameMode.CREATIVE && b.getType() == Material.BARRIER){ - breakPlacedGroup(e.getPlayer(), e.getBlock()); + if (!breakPlacedGroup(e.getPlayer(), e.getBlock())) e.setCancelled(true); } } - private void breakPlacedGroup(Player player, Block block){ + //bool determines whether to break the block or not + private boolean breakPlacedGroup(Player player, Block block){ CustomBlockData data = new CustomBlockData(block, DisplayAPI.getPlugin()); String groupId = data.get(DisplayAPI.getPlaceableGroupId(), PersistentDataType.STRING); - if (groupId == null) return; //Not a placed group block + if (groupId == null) return true; //Not a placed group block PacketDisplayEntityGroup group = PacketDisplayEntityGroup.getGroup(groupId); if (group == null){ //group was removed by other means clearPDC(data); if (block.getType() == Material.BARRIER) block.setType(Material.AIR); - return; + return true; } - if (!new PlacedGroupBreakEvent(block, group, player).callEvent()) return; - - ItemStack itemStack = PlaceableGroupManager.getItemStack(block); - - String uuidString = data.get(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING); UUID placerUUID = uuidString == null ? null : UUID.fromString(uuidString); - if (placerUUID != null && PlaceableGroupManager.isPlacerBreaksOnly(itemStack) && !player.getUniqueId().equals(placerUUID)) { + DEUUser user = DEUUser.getUser(player); + if ((user == null || !user.isInPlacedGroupBreakMode()) + && placerUUID != null + && PlaceableGroupManager.isPlacerBreaksOnly(itemStack) + && !player.getUniqueId().equals(placerUUID)) { player.sendMessage(Component.text("Only the player who placed this can break it!", NamedTextColor.RED)); - return; + if (player.hasPermission(Permission.PLACE_BREAK_MODE.getPermission())) { + player.sendMessage(Component.text("| You have permission to enter break-mode with \"/deu place breakmode\"", NamedTextColor.GRAY)); + } + return false; } + + if (!new PlacedGroupBreakEvent(block, group, player).callEvent()) return false; + Location blockLoc = block.getLocation().add(0.5f, 0.5f, 0.5f); if (PlaceableGroupManager.isDropItem(itemStack) && player.getGameMode() != GameMode.CREATIVE) { @@ -89,6 +96,7 @@ private void breakPlacedGroup(Player player, Block block){ PlaceableGroupManager.playSounds(itemStack, blockLoc, false); clearPDC(data); block.setType(Material.AIR); + return true; } private void clearPDC(CustomBlockData data){ From 12d3e1cae57d9b7a58c7e768edf045d32ee04387 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 22:33:05 -0600 Subject: [PATCH 113/139] Disallow "/deu group despawn" on placed groups --- .../displayentityutils/command/group/GroupDespawnCMD.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java index 93fd57c5..abd1661c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java @@ -22,11 +22,14 @@ protected void sendIncorrectUsage(@NotNull Player player) {} @Override protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @NotNull String[] args) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Despawned your selected display entity group!", NamedTextColor.GRAY))); if (group instanceof SpawnedDisplayEntityGroup sg){ sg.unregister(true, true); } else if (group instanceof PacketDisplayEntityGroup pg){ + if (pg.isPlaced()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You must manually break a placed group's block to remove it!", NamedTextColor.RED))); + return; + } if (pg.isPersistent()){ DisplayGroupManager.removePersistentPacketGroup(pg, true); } @@ -34,6 +37,7 @@ else if (group instanceof PacketDisplayEntityGroup pg){ pg.unregister(); } } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Despawned your selected display entity group!", NamedTextColor.GRAY))); DisplayGroupManager.deselectGroup(player); DisplayEntityPluginCommand.hideRelativePoints(player); } From 8d3be42a8c09c9fd795cf02b65c6b3f02f7a7e10 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 30 Dec 2025 22:33:28 -0600 Subject: [PATCH 114/139] Add "/deu group selectplaced" --- .../managers/PlaceableGroupManager.java | 13 ++++++ .../command/group/GroupCMD.java | 14 ++++--- .../command/group/GroupSelectPlacedCMD.java | 42 +++++++++++++++++++ 3 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectPlacedCMD.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index 21f189e1..1c8037cc 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -554,6 +554,19 @@ public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player pla return ItemStack.deserializeBytes(Base64.getDecoder().decode(b64)); } + /** + * Get the {@link PacketDisplayEntityGroup} placed at a block + * @param block the block where a placed group is + * @return an {@link PacketDisplayEntityGroup} or null + */ + public static @Nullable PacketDisplayEntityGroup getPlacedGroup(@NotNull Block block){ + if (!CustomBlockData.hasCustomBlockData(block, DisplayAPI.getPlugin())) return null; + CustomBlockData data = new CustomBlockData(block, DisplayAPI.getPlugin()); + + String id = data.get(DisplayAPI.getPlaceableGroupId(), PersistentDataType.STRING); + return PacketDisplayEntityGroup.getGroup(id); + } + private static void setBlockData(Player itemHolder, Block block, ItemStack itemStack, String groupID){ block.setType(Material.BARRIER); PersistentDataContainer pdc = new CustomBlockData(block, DisplayAPI.getPlugin()); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java index 7f2d3dc3..c6761a83 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java @@ -19,6 +19,7 @@ public GroupCMD(){ true)); new GroupSelectCMD(this); new GroupSelectNearestCMD(this); + new GroupSelectPlacedCMD(this); new GroupDeselectCMD(this); new GroupSaveCMD(this); new GroupSaveJsonCMD(this); @@ -90,11 +91,12 @@ static void groupHelp(CommandSender sender, int page){ CMDUtils.sendCMD(sender, "/deu anim list [page-number]", "List all saved display entity groups/models"); CMDUtils.sendCMD(sender, "/deu group select ", "Select from nearby groups within the given distance"); CMDUtils.sendCMD(sender, "/deu group selectnearest ", "Select the nearest group within the given distance"); + CMDUtils.sendCMD(sender, "/deu group selectplaced", "Select a group placed by a player's held item"); CMDUtils.sendCMD(sender, "/deu group deselect", "Clear your group selection"); CMDUtils.sendCMD(sender, "/deu group info", "List information about your selected group"); - CMDUtils.sendCMD(sender, "/deu group spawn [-packet]", "Spawn a saved display entity group/model from a storage location. \"-packet\" will spawn the group/model using packets"); } else if (page == 2) { + CMDUtils.sendCMD(sender, "/deu group spawn [-packet]", "Spawn a saved display entity group/model from a storage location. \"-packet\" will spawn the group/model using packets"); CMDUtils.sendCMD(sender, "/deu group spawnjson [-packet]", "Spawn a JSON saved display entity group/model from a local storage. \"-packet\" will spawn the group/model using packets"); CMDUtils.sendCMD(sender, "/deu group despawn", "Despawn your selected group"); CMDUtils.sendCMD(sender, "/deu group save ", "Save your selected group"); @@ -102,45 +104,45 @@ else if (page == 2) { CMDUtils.sendCMD(sender, "/deu group delete ", "Delete a saved group from a storage location"); CMDUtils.sendCMD(sender, "/deu group topacket [-confirm] [-keep]", "Make your selected group packet-based, making it unselectable. \"-confirm\" confirms the action." + " \"-keep\" keeps the non-packet based version of your group spawned."); - CMDUtils.sendCMD(sender, "/deu group markpacketgroups", "Create markers for all packet groups stored in your current chunk"); } else if (page == 3){ + CMDUtils.sendCMD(sender, "/deu group markpacketgroups", "Create markers for all packet groups stored in your current chunk"); CMDUtils.sendCMD(sender, "/deu group showpacketgroups [-self]", "Show all persistent packet-based groups in your current chunk. \n\"-self\" shows the group only for you"); CMDUtils.sendCMD(sender, "/deu group hidepacketgroups [-self]", "Hide all persistent packet-based groups in your current chunk. \n\"-self\" hides the group only for you"); CMDUtils.sendCMD(sender, "/deu group addtarget", "Add a targeted interaction entity to your group"); CMDUtils.sendCMD(sender, "/deu group ungroupinteractions", "Remove all interactions from your group"); CMDUtils.sendCMD(sender, "/deu group settag ", "Set this group's tag, or identifier"); CMDUtils.sendCMD(sender, "/deu group yaw [-pivot]","Set your selected group's yaw, \"-pivot\" pivots interaction entities around the group"); - CMDUtils.sendCMD(sender, "/deu group pitch ", "Set your selected group's pitch"); } else if (page == 4){ + CMDUtils.sendCMD(sender, "/deu group pitch ", "Set your selected group's pitch"); CMDUtils.sendCMD(sender, "/deu group scale ", "Scale your selected group with a given multiplier"); CMDUtils.sendCMD(sender, "/deu group brightness ", "Set your selected group's brightness. Enter values between 0-15. -1 resets"); CMDUtils.sendCMD(sender, "/deu group clone", "Spawn a cloned group at your selected group's location"); CMDUtils.sendCMD(sender, "/deu group clonehere", "Spawn a cloned group at your location"); CMDUtils.sendCMD(sender, "/deu group move [tick-duration]", "Change the actual location of your selected group, with an optional duration"); CMDUtils.sendCMD(sender, "/deu group movehere", "Change your selected group's actual location to your location"); - CMDUtils.sendCMD(sender, "/deu group translate ","Changes your selected group's translation, use \"move\" instead if this group uses animations"); } else if (page == 5){ + CMDUtils.sendCMD(sender, "/deu group translate ","Changes your selected group's translation, use \"move\" instead if this group uses animations"); CMDUtils.sendCMD(sender, "/deu group merge ","Merge groups near your selected group"); CMDUtils.sendCMD(sender, "/deu group billboard ", "Set the billboard of all parts in this group"); CMDUtils.sendCMD(sender, "/deu group glowcolor ", "Set the glow color for all parts in this group"); CMDUtils.sendCMD(sender, "/deu group glow", "Make all parts in this group glow"); CMDUtils.sendCMD(sender, "/deu group unglow", "Remove the glowing effect from all parts in this group"); CMDUtils.sendCMD(sender, "/deu group ride <-target | player-name | entity-uuid> [group-tag] [storage] [controller-id]", "Make a group ride an entity. Values in brackets [] are optional"); - CMDUtils.sendCMD(sender, "/deu group safedismount <-target | -selected | player-name | entity-uuid>", "Safely dismount a group from an entity"); } else if (page == 6){ + CMDUtils.sendCMD(sender, "/deu group safedismount <-target | -selected | player-name | entity-uuid>", "Safely dismount a group from an entity"); CMDUtils.sendCMD(sender, "/deu group dismount <-target | -selected | player-name | entity-uuid> [-despawn]", "Dismount a group from an entity, with optional despawning"); CMDUtils.sendCMD(sender, "/deu group setspawnanim ", "Set an animation to play when this group is spawned/loaded"); CMDUtils.sendCMD(sender, "/deu group unsetspawnanim", "Remove the spawn animation that's set on your selected group"); CMDUtils.sendCMD(sender, "/deu group viewrange ", "Set the view range multiplier for your selected group"); CMDUtils.sendCMD(sender, "/deu group autocull", "Calculate and set culling bounds for every part in your selected group"); CMDUtils.sendCMD(sender, "/deu group removecull", "Remove the culling bounds for every part in your selected group"); - CMDUtils.sendCMD(sender, "/deu group togglepersist", "Toggle if your group should persist after a server shutdown"); } else{ + CMDUtils.sendCMD(sender, "/deu group togglepersist", "Toggle if your group should persist after a server shutdown"); CMDUtils.sendCMD(sender, "/deu group togglepersistoverride", "Toggle if your group's persistence can be overriden when loaded by a chunk, " + "only if \"persistenceOverride\" is enabled in the config"); CMDUtils.sendCMD(sender, "/deu group wetogroup [-removeblocks]", "Convert your WorldEdit selection to a display group, with its origin at the lowest center block of the selection (Requires WorldEdit). \nUse \"-removeblocks\" to set all selected blocks to air"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectPlacedCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectPlacedCMD.java new file mode 100644 index 00000000..907bc419 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectPlacedCMD.java @@ -0,0 +1,42 @@ +package net.donnypz.displayentityutils.command.group; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +class GroupSelectPlacedCMD extends PlayerSubCommand { + GroupSelectPlacedCMD(@NotNull DEUSubCommand parentSubCommand) { + super("selectplaced", parentSubCommand, Permission.GROUP_SELECT); + } + + @Override + public void execute(Player player, String[] args) { + Block targetBlock = player.getTargetBlock(null, 15); + PacketDisplayEntityGroup group = PlaceableGroupManager.getPlacedGroup(targetBlock); + + if (group == null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You are not looking at a placed group's block! (Barrier)", NamedTextColor.RED))); + return; + } + + boolean selectResult = DisplayGroupManager.setSelectedGroup(player, group); + if (selectResult){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Selected placed group!", NamedTextColor.GREEN))); + } + else{ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to select placed group! Another player already has that group selected!", NamedTextColor.RED))); + } + + int selectDuration = 50; + group.glowAndMarkInteractions(player, selectDuration); + } +} From 39a6f6d5cf5e90057daf05e3da8b23ddbb5d440f Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 31 Dec 2025 00:34:47 -0600 Subject: [PATCH 115/139] Remove map storing SpawnedDisplayEntityParts in two different locations --- .../utils/DisplayEntities/ActivePart.java | 56 +------------------ .../SpawnedDisplayEntityGroup.java | 6 -- .../SpawnedDisplayEntityPart.java | 53 +++++++----------- 3 files changed, 21 insertions(+), 94 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 85d259ee..614e994e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -32,7 +32,7 @@ import java.util.concurrent.ConcurrentHashMap; public abstract class ActivePart implements Active{ - private static final ConcurrentHashMap partsById = new ConcurrentHashMap<>(); + protected static final ConcurrentHashMap partsById = new ConcurrentHashMap<>(); protected SpawnedDisplayEntityPart.PartType type; protected UUID partUUID; private int entityId; @@ -610,58 +610,4 @@ public void setMannequinProfile(@NotNull ResolvableProfile profile, Player playe public abstract @NotNull List getInteractionCommands(); public abstract @NotNull List getInteractionCommandsWithData(); - - static class PartData { - - private final UUID entityUUID; - private String worldName; - - PartData(@NotNull Entity entity) { - this(entity.getUniqueId(), entity.getWorld().getName()); - } - - PartData(@NotNull UUID entityUUID, @NotNull String worldName) { - this.entityUUID = entityUUID; - this.worldName = worldName; - } - - void setWorldName(String worldName) { - this.worldName = worldName; - } - - /** - * Get the UUID of the entity this PartData represents - * @return a UUID - */ - public UUID getUUID() { - return entityUUID; - } - - /** - * Get the world name of the entity this PartData represents - * - * @return a string - */ - public String getWorldName() { - return worldName; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - - PartData data = (PartData) obj; - return entityUUID.equals(data.entityUUID) && worldName.equals(data.worldName); - } - - @Override - public int hashCode() { - return Objects.hash(entityUUID, worldName); - } - } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index 39146014..3d8c2931 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -509,8 +509,6 @@ private void teleportWithoutEvent(Location location, boolean respectGroupDirecti } FoliaUtils.teleport(master, location, TeleportFlag.EntityState.RETAIN_PASSENGERS); - World w = location.getWorld(); - for (SpawnedDisplayEntityPart part : this.getParts()){ part.getEntity().setRotation(location.getYaw(), location.getPitch()); @@ -522,10 +520,6 @@ private void teleportWithoutEvent(Location location, boolean respectGroupDirecti Location tpLocation = location.clone().subtract(vector); FoliaUtils.teleport(part.getEntity(), tpLocation, TeleportFlag.EntityState.RETAIN_PASSENGERS); } - - if (w != null && part.getEntity().getWorld() != w){ //Keep world name consistent within part's data - part.getPartData().setWorldName(w.getName()); - } } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index ece50674..2b795aec 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -35,15 +35,13 @@ public final class SpawnedDisplayEntityPart extends ActivePart implements Spawned { - private static final HashMap allParts = new HashMap<>(); private SpawnedDisplayEntityGroup group; private Entity entity; - private PartData partData; private UUID entityUUID; private final boolean isSingle; SpawnedDisplayEntityPart(SpawnedDisplayEntityGroup group, Entity entity, Random random){ - super(entity.getEntityId(), true); + super(entity.getEntityId(), false); this.group = group; this.entity = entity; this.type = PartType.getType(entity); @@ -61,6 +59,7 @@ public final class SpawnedDisplayEntityPart extends ActivePart implements Spawne SpawnedDisplayEntityPart(Entity entity){ super(entity.getEntityId(), false); + if (PartType.getType(entity) == null) throw new IllegalArgumentException("Entity is not a valid part type entity"); this.type = PartType.getType(entity); this.entity = entity; this.entityUUID = entity.getUniqueId(); @@ -76,7 +75,7 @@ public final class SpawnedDisplayEntityPart extends ActivePart implements Spawne * @throws IllegalArgumentException if the entity is not a valid entity */ public static @NotNull SpawnedDisplayEntityPart create(@NotNull UUID uuid){ - return new SpawnedDisplayEntityPart(Bukkit.getEntity(uuid)); + return create(Bukkit.getEntity(uuid)); } /** @@ -89,18 +88,21 @@ public final class SpawnedDisplayEntityPart extends ActivePart implements Spawne */ public static @NotNull SpawnedDisplayEntityPart create(@NotNull Entity entity){ SpawnedDisplayEntityPart part = getPart(entity); - if (part != null) return part; - return new SpawnedDisplayEntityPart(entity); + return part != null ? part : new SpawnedDisplayEntityPart(entity); } private void applyData(Random random, Entity entity){ adaptLegacyPartTags(); entity.getPersistentDataContainer().set(SpawnedDisplayEntityGroup.creationTimeKey, PersistentDataType.LONG, group.getCreationTime()); - removeFromPreviousGroup(entity); - this.partData = new PartData(entity); + //Remove from previous group + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); + if (part != null && part.group != group){ + part.remove(false); + } + partsById.put(getEntityId(), this); + this.entityUUID = entity.getUniqueId(); - allParts.put(partData, this); setPartUUID(random); group.groupParts.put(partUUID, this); @@ -158,11 +160,15 @@ private boolean groupContainsUUID(UUID partUUID){ return group.groupParts.containsKey(partUUID); } - private void removeFromPreviousGroup(Entity entity){ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); - if (part != null){ - part.remove(false); + private void adaptLegacyPartTags(){ //Don't use getEntity() + List legacyTags = new ArrayList<>(); + for (String s : new HashSet<>(entity.getScoreboardTags())){ + if (s.contains(DisplayAPI.getLegacyPartTagPrefix())){ + legacyTags.add(s.replace(DisplayAPI.getLegacyPartTagPrefix(), "")); + entity.removeScoreboardTag(s); + } } + DisplayUtils.addTags(entity, legacyTags); } /** @@ -256,11 +262,6 @@ public void refreshEntity(@NotNull Entity nonStaleEntity){ return getEntity().getLocation(); } - - PartData getPartData() { - return partData; - } - /** * Get the {@link SpawnedDisplayEntityPart} of an entity, during this play session. Use {@link #create(Entity)} if the part is not grouped. * @param entity the part entity @@ -268,7 +269,7 @@ PartData getPartData() { */ public static @Nullable SpawnedDisplayEntityPart getPart(@NotNull Entity entity){ if (!DisplayUtils.isPartEntity(entity)) return null; - return allParts.get(new PartData(entity)); + return (SpawnedDisplayEntityPart) getPart(entity.getEntityId()); } @@ -314,18 +315,6 @@ public SpawnedDisplayEntityPart adaptScoreboardTags(boolean removeFromScoreboard return this; } - - private void adaptLegacyPartTags(){ //Don't use getEntity() - List legacyTags = new ArrayList<>(); - for (String s : new HashSet<>(entity.getScoreboardTags())){ - if (s.contains(DisplayAPI.getLegacyPartTagPrefix())){ - legacyTags.add(s.replace(DisplayAPI.getLegacyPartTagPrefix(), "")); - entity.removeScoreboardTag(s); - } - } - DisplayUtils.addTags(entity, legacyTags); - } - SpawnedDisplayEntityPart setMaster(){ group.masterPart = this; getEntity().getPersistentDataContainer().set(DisplayAPI.getMasterKey(), PersistentDataType.BOOLEAN, true); @@ -1305,7 +1294,6 @@ public Entity remove(boolean kill) { } } this.entity = null; - this.partData = null; this.unregister(); return entity; } @@ -1317,7 +1305,6 @@ public Entity remove(boolean kill) { */ public void removeFromGroup() { if (group != null){ - allParts.remove(partData); group.groupParts.remove(partUUID); for (SpawnedPartSelection selection : group.partSelections){ selection.removePart(this); From de0c0f3d3dd50e314d8c3e9b54cbae688308cb15 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 31 Dec 2025 02:28:12 -0600 Subject: [PATCH 116/139] don't return invalid group when getting a player's selected group --- .../java/net/donnypz/displayentityutils/managers/DEUUser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java index 4fee270d..ae3ac37e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java @@ -352,6 +352,7 @@ public int getTrackedPacketEntityCount(){ } public @Nullable ActiveGroup getSelectedGroup(){ + if (selectedGroup != null && !selectedGroup.isRegistered()) selectedGroup = null; return selectedGroup; } From 6d7be7a597fc646efe7cd8858b4d9a9bcb586200 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 31 Dec 2025 05:15:45 -0600 Subject: [PATCH 117/139] Fix stackoverflow --- .../utils/DisplayEntities/SpawnedDisplayEntityPart.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 2b795aec..23cc61cd 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -900,7 +900,7 @@ public byte getTextDisplayTextOpacity() { if (type != PartType.TEXT_DISPLAY) return -1; TextDisplay td = (TextDisplay) getEntity(); if (td == null) return -1; - return getTextDisplayTextOpacity(); + return td.getTextOpacity(); } @Override From 3c4b0382283c7d89e4b28412c5b24f29d46d6dd6 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 31 Dec 2025 18:51:54 -0600 Subject: [PATCH 118/139] Added PacketDisplayEntityPart#getPart & ActiveGroup#addEntity --- .../utils/DisplayEntities/ActiveGroup.java | 7 +++ .../utils/DisplayEntities/DisplayEntity.java | 10 +++-- .../DisplayEntities/InteractionEntity.java | 2 +- .../DisplayEntities/MannequinEntity.java | 2 +- .../PacketDisplayEntityGroup.java | 14 +++++- .../PacketDisplayEntityPart.java | 29 +++++++++++++ .../SpawnedDisplayEntityGroup.java | 43 ++++++++++--------- 7 files changed, 79 insertions(+), 28 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java index 3524de1d..7f744af4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java @@ -61,6 +61,13 @@ public ActiveGroup addPlayerSelection(Player player){ */ public abstract void addPart(T part); + /** + * Add an entity to this group as a part, when you don't know the type of entity you're dealing with + * @param entity the eligible entity to add + * @return a corresponding part or null if the entity is not an eligible part entity + */ + public abstract @Nullable T addEntity(@NotNull Entity entity); + /** * Get this group's tag diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntity.java index 50b3c1f9..5c18cad8 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntity.java @@ -137,12 +137,14 @@ PacketDisplayEntityPart createPacketPart(PacketDisplayEntityGroup group, Locatio part.partTags = getSetFromPDC(pdc, DisplayAPI.getPartPDCTagKey()); part.partUUID = specifics.getPartUUID(); - if (group.masterPart == null && isMaster){ - part.isMaster = true; - group.setSpawnAnimation(pdc); + if (group != null){ + if (group.masterPart == null && isMaster){ + part.isMaster = true; + group.setSpawnAnimation(pdc); + } } } - settings.applyAttributes(part); + if (settings != null) settings.applyAttributes(part); return part; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java index 680a46e5..8cd51ca0 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java @@ -131,7 +131,7 @@ PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings set part.partUUID = partUUID != null ? partUUID : DisplayEntity.getPDCPartUUID(pdc); part.interactionCommands = getInteractionCommands(pdc); } - settings.applyAttributes(part); + if (settings != null) settings.applyAttributes(part); return part; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java index d80d9096..c01d33f4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java @@ -96,7 +96,7 @@ PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings set part.partTags = DisplayEntity.getSetFromPDC(pdc, DisplayAPI.getPartPDCTagKey()); part.partUUID = DisplayEntity.getPDCPartUUID(pdc); - settings.applyAttributes(part); + if (settings != null) settings.applyAttributes(part); return part; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index fc6cd6ad..91604a49 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -212,7 +212,19 @@ public void addPart(@NotNull PacketDisplayEntityPart part){ updatePassengerIds(part.getEntityId(), true); } - void addPartSilent(PacketDisplayEntityPart part){ + /** + * {@inheritDoc} + * This will create a {@link PacketDisplayEntityPart} representative of the entity + */ + @Override + public @Nullable PacketDisplayEntityPart addEntity(@NotNull Entity entity) { + PacketDisplayEntityPart part = PacketDisplayEntityPart.getPart(entity, true); + if (part == null) return null; + addPart(part); + return part; + } + + void addPartSilent(PacketDisplayEntityPart part){ if (groupParts.get(part.partUUID) == part) return; if (part.partUUID == null){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index e065beeb..8ffc2243 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -81,6 +81,34 @@ public PacketDisplayEntityPart(@NotNull SpawnedDisplayEntityPart.PartType partTy setDefaultTransformValues(); } + /** + * Create a {@link PacketDisplayEntityPart} representative of the given entity + * @return a {@link PacketDisplayEntityPart} or null if the entity is not an eligible part entity + */ + public static @Nullable PacketDisplayEntityPart getPart(@NotNull Entity entity, boolean removeExistingEntity){ + SpawnedDisplayEntityPart.PartType pt = SpawnedDisplayEntityPart.PartType.getType(entity); + if (pt == null) return null; + PacketDisplayEntityPart part; + switch (entity){ + case Display d -> { + part = new DisplayEntity(d, DisplayEntity.Type.fromPartType(pt)) + .createPacketPart(null, entity.getLocation(), null); + } + case Interaction inter -> { + part = new InteractionEntity(inter).createPacketPart(entity.getLocation(), null); + } + case Mannequin man -> { + MannequinEntity m = SavedEntityBuilder.buildMannequin(entity); + part = m.createPacketPart(entity.getLocation(), null); + } + default -> { + return null; + } + } + if (removeExistingEntity) entity.remove(); + return part; + } + private void setDefaultTransformValues(){ if (isDisplay()){ attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.TRANSLATION, new Vector3f()); @@ -1269,6 +1297,7 @@ private void sendHeadLookPacket(Player player, float yaw){ PacketEvents.getAPI().getPlayerManager().sendPacket(player, getHeadLookPacket(yaw)); } + static final class PacketLocation { String worldName; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index 3d8c2931..4833b5f2 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -120,6 +120,28 @@ public void addPart(@NotNull SpawnedDisplayEntityPart part){ } + /** + * {@inheritDoc} + */ + @Override + public @Nullable SpawnedDisplayEntityPart addEntity(@NotNull Entity entity){ + if (entity instanceof Display display){ + return addDisplayEntity(display); + } + + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); + if (part == null){ + part = new SpawnedDisplayEntityPart(this, entity, partUUIDRandom); + } + else{ + part.setGroup(this); + } + if (getVehicle() != null){ + alignNonDisplayWithMountedGroup(part, getVehicle()); + } + return part; + } + /** * Add a display entity to this group. If this group already contains this display entity as a registered part it will return the existing * {@link SpawnedDisplayEntityPart}. If it doesn't then it will return a new {@link SpawnedDisplayEntityPart} @@ -151,28 +173,7 @@ else if (!groupParts.isEmpty()){ return part; } - /** - * Add a valid part entity to this group, when you don't know the type of entity you're dealing with - * @param entity the part entity to add - * @return a corresponding {@link SpawnedDisplayEntityPart} or null if the entity is not an eligible part entity - */ - public @Nullable SpawnedDisplayEntityPart addEntity(@NotNull Entity entity){ - if (entity instanceof Display display){ - return addDisplayEntity(display); - } - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); - if (part == null){ - part = new SpawnedDisplayEntityPart(this, entity, partUUIDRandom); - } - else{ - part.setGroup(this); - } - if (getVehicle() != null){ - alignNonDisplayWithMountedGroup(part, getVehicle()); - } - return part; - } /** * Check if this group and an entity share the same creation time. If this returns true this does not guarantee From cfb669280f1844c178bdef1699c75aebd6b4ce2c Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 03:26:57 -0600 Subject: [PATCH 119/139] Add "-addtogroup" to "/deu parts create" --- .../command/parts/PartsCMD.java | 3 +- .../command/parts/PartsCreateCMD.java | 133 ++++++++++++++---- .../utils/dialogs/TextDisplayDialog.java | 42 +----- 3 files changed, 108 insertions(+), 70 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java index 8b647229..206feb72 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java @@ -63,7 +63,8 @@ static void partsHelp(CommandSender sender, int page){ sender.sendMessage(Component.empty()); CMDUtils.sendCMD(sender, "/deu parts help ", "Get help for parts"); CMDUtils.sendCMD(sender, "/deu parts info", "Get information about your current part/selection"); - CMDUtils.sendCMD(sender, "/deu parts create ", "Spawn an entity at your location and automatically select it"); + CMDUtils.sendCMD(sender, "/deu parts create [-addtogroup]", "Spawn an entity at your location and automatically select it. " + + "\"-addtogroup\" will add the part to your selected group"); CMDUtils.sendCMD(sender, "/deu parts select ", "Select a nearby, ungrouped, Display entity. Use \"-target\" to select your targeted Interaction"); } else if (page == 2) { diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java index 4118f727..a8d1da02 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java @@ -3,12 +3,15 @@ import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DEUUser; -import net.donnypz.displayentityutils.utils.DisplayEntities.SinglePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; +import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.donnypz.displayentityutils.utils.dialogs.TextDisplayDialog; import net.kyori.adventure.text.Component; @@ -26,13 +29,16 @@ import org.jetbrains.annotations.NotNull; import java.time.Duration; -import java.util.UUID; +import java.util.function.Function; class PartsCreateCMD extends PlayerSubCommand { + private static final Component DEFAULT_TEXT = Component.text("New Text Display Entity"); + PartsCreateCMD(@NotNull DEUSubCommand parentSubCommand) { super("create", parentSubCommand, Permission.PARTS_CREATE); setTabComplete(2, TabSuggestion.PART_TYPES); + setTabComplete(3, "-addtogroup"); } @Override @@ -42,53 +48,95 @@ public void execute(Player player, String[] args) { return; } + boolean addToGroup; + if (args.length >= 4){ + addToGroup = args[3].equalsIgnoreCase("-addtogroup"); + if (addToGroup && DisplayGroupManager.getSelectedGroup(player) == null){ + DisplayEntityPluginCommand.noGroupSelection(player); + } + } + else{ + addToGroup = false; + } + Location loc = player.getLocation(); + PacketAttributeContainer container = new PacketAttributeContainer(); switch (args[2].toLowerCase()){ case "block" -> { - BlockDisplay entity = loc.getWorld().spawn(loc, BlockDisplay.class, e -> { - e.setBlock(Registry.MATERIAL.get(NamespacedKey.minecraft("stone")).createBlockData()); + selectOrAddEntity(player, "Block Display", addToGroup, bukkit -> { + return loc.getWorld().spawn(loc, BlockDisplay.class, e -> { + e.setBlock(Registry.MATERIAL.get(NamespacedKey.minecraft("stone")).createBlockData()); + }); + }, packet -> { + return container + .setAttribute(DisplayAttributes.BlockDisplay.BLOCK_STATE, Material.STONE.createBlockData()) + .createPart(SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY, loc); }); - selectEntity(player, entity.getUniqueId(), "Block Display"); } case "item" -> { - ItemDisplay entity = loc.getWorld().spawn(loc, ItemDisplay.class, e -> { - e.setItemStack(new ItemStack(Material.STICK)); + selectOrAddEntity(player, "Item Display", addToGroup, bukkit -> { + return loc.getWorld().spawn(loc, ItemDisplay.class, e -> { + e.setItemStack(new ItemStack(Material.STICK)); + }); + }, packet -> { + return container + .setAttribute(DisplayAttributes.ItemDisplay.ITEMSTACK, new ItemStack(Material.STICK)) + .createPart(SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY, loc); }); - selectEntity(player, entity.getUniqueId(), "Item Display"); } case "text" -> { loc.setYaw(loc.getYaw()+180); loc.setPitch(loc.getPitch()*-1); - TextDisplay entity = loc.getWorld().spawn(loc, TextDisplay.class, e -> { - e.text(Component.text("New Text Display Entity")); + + ActivePart part = selectOrAddEntity(player, "Text Display", addToGroup, bukkit -> { + return loc.getWorld().spawn(loc, TextDisplay.class, e -> { + e.text(DEFAULT_TEXT); + }); + }, packet -> { + return container + .setAttribute(DisplayAttributes.TextDisplay.TEXT, DEFAULT_TEXT) + .createPart(SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY, loc); }); - selectEntity(player, entity.getUniqueId(), "Text Display"); - if (VersionUtils.canViewDialogs(player, false)){ - UUID entityUUID = entity.getUniqueId(); - player.sendMessage(Component.text("| Click here to edit it!", NamedTextColor.LIGHT_PURPLE) - .clickEvent(ClickEvent.callback(audience -> { - Player p = (Player) audience; - TextDisplayDialog.sendDialog(p, entityUUID, true); - }, ClickCallback.Options.builder().uses(-1).lifetime(Duration.ofMinutes(5)).build()))); + if (part != null){ + if (VersionUtils.canViewDialogs(player, false)){ + player.sendMessage(Component.text("| Click here to edit it!", NamedTextColor.LIGHT_PURPLE) + .clickEvent(ClickEvent.callback(audience -> { + Player p = (Player) audience; + TextDisplayDialog.sendDialog(p, part, true); + }, ClickCallback.Options.builder().uses(-1).lifetime(Duration.ofMinutes(5)).build()))); + } } } case "interaction" -> { - Interaction entity = loc.getWorld().spawn(loc, Interaction.class, e -> { - e.setInteractionHeight(1); - e.setInteractionWidth(1); + selectOrAddEntity(player, "Interaction", addToGroup, bukkit -> { + return loc.getWorld().spawn(loc, Interaction.class, e -> { + e.setInteractionHeight(1); + e.setInteractionWidth(1); + }); + }, packet -> { + return container + .setAttribute(DisplayAttributes.Interaction.WIDTH, 1f) + .setAttribute(DisplayAttributes.Interaction.HEIGHT, 1f) + .createPart(SpawnedDisplayEntityPart.PartType.INTERACTION, loc); }); - selectEntity(player, entity.getUniqueId(), "Interaction"); } case "mannequin" -> { if (!VersionUtils.canSpawnMannequins()){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your server version cannot spawn Mannequins!", NamedTextColor.RED))); return; } - Mannequin entity = loc.getWorld().spawn(loc, Mannequin.class, m -> { - m.setProfile(ResolvableProfile.resolvableProfile(player.getPlayerProfile())); - DisplayUtils.prepareMannequin(m); + selectOrAddEntity(player, "Mannequin", addToGroup, bukkit -> { + return loc.getWorld().spawn(loc, Mannequin.class, m -> { + m.setProfile(ResolvableProfile.resolvableProfile(player.getPlayerProfile())); + DisplayUtils.prepareMannequin(m); + }); + }, packet -> { + return container + .setAttribute(DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, ResolvableProfile.resolvableProfile(player.getPlayerProfile())) + .setAttribute(DisplayAttributes.Mannequin.IMMOVABLE, true) + .setAttribute(DisplayAttributes.Mannequin.NO_GRAVITY, true) + .createPart(SpawnedDisplayEntityPart.PartType.MANNEQUIN, loc); }); - selectEntity(player, entity.getUniqueId(), "Mannequin"); } default -> { incorrectUsage(player); @@ -100,11 +148,34 @@ private void incorrectUsage(Player player){ player.sendMessage(Component.text("Incorrect Usage! /deu parts create ", NamedTextColor.RED)); } - private void selectEntity(Player player, UUID entityUUID, String displayName){ + private ActivePart selectOrAddEntity(Player player, String displayName, boolean addToGroup, Function bukkitEntity, Function packetPart){ player.sendMessage(DisplayAPI .pluginPrefix - .append(MiniMessage.miniMessage().deserialize("You have spawned a " + displayName + " entity at your location!"))); - player.sendMessage(Component.text("| The created part has been automatically selected, removing previous selections", NamedTextColor.GRAY, TextDecoration.ITALIC)); - DEUUser.getOrCreateUser(player).setSelectedPartSelection(new SinglePartSelection(SpawnedDisplayEntityPart.create(entityUUID)), false); + .append(MiniMessage.miniMessage().deserialize("You have spawned a " + displayName + " entity!"))); + + DEUUser user = DEUUser.getOrCreateUser(player); + ActivePart part; + if (addToGroup){ + ActiveGroup group = DisplayGroupManager.getSelectedGroup(player); + if (group instanceof PacketDisplayEntityGroup pdeg){ + part = packetPart.apply(null); + pdeg.addPart((PacketDisplayEntityPart) part); + } + else if (group instanceof SpawnedDisplayEntityGroup sdeg){ + part = sdeg.addEntity(bukkitEntity.apply(null)); + } + else{ + return null; + } + ((MultiPartSelection) user.getSelectedPartSelection()).refresh(); + player.sendMessage(Component.text("| The created part has been automatically added to your group", NamedTextColor.GRAY, TextDecoration.ITALIC)); + } + else{ + Entity entity = bukkitEntity.apply(null); + player.sendMessage(Component.text("| The created part has been automatically selected, removing previous selections", NamedTextColor.GRAY, TextDecoration.ITALIC)); + part = SpawnedDisplayEntityPart.create(entity); + user.setSelectedPartSelection(new SinglePartSelection((SpawnedDisplayEntityPart) part), false); + } + return part; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/dialogs/TextDisplayDialog.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/dialogs/TextDisplayDialog.java index e5275188..1717d2e1 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/dialogs/TextDisplayDialog.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/dialogs/TextDisplayDialog.java @@ -43,8 +43,6 @@ public final class TextDisplayDialog{ private static final String COLOR_CODE = "deu_text_display_color_code"; private static final String BACKGROUND_COLOR = "deu_text_display_background_color"; - private static final DialogAction CONFIRM_ACTION = getConfirmAction(); - private TextDisplayDialog(){} @@ -55,19 +53,7 @@ private TextDisplayDialog(){} * @param miniMessageFormatted whether the text display's text should be formatted as minimessage or ampersand */ public static void sendDialog(@NotNull Player player, @NotNull TextDisplay textDisplay, boolean miniMessageFormatted){ - Dialog dialog = Dialog.create(builder -> { - builder.empty() - .base(DialogBase.builder(Component.text("Edit a Text Display")) - .inputs(getInputs(textDisplay, miniMessageFormatted)) - .build()) - .type(DialogType.confirmation(ActionButton.create(Component.text("Confirm", NamedTextColor.GREEN), - Component.text("Set your selected text display's text", NamedTextColor.YELLOW), - 200, CONFIRM_ACTION), - ActionButton.create(Component.text("Cancel", NamedTextColor.RED), - Component.text("Cancel this action", NamedTextColor.YELLOW), - 200, null))); - }); - player.showDialog(dialog); + sendDialog(player, SpawnedDisplayEntityPart.create(textDisplay), miniMessageFormatted); } /** @@ -85,7 +71,7 @@ public static void sendDialog(@NotNull Player player, @NotNull ActivePart textDi .build()) .type(DialogType.confirmation(ActionButton.create(Component.text("Confirm", NamedTextColor.GREEN), Component.text("Set your selected text display's text", NamedTextColor.YELLOW), - 200, CONFIRM_ACTION), + 200, getConfirmAction(textDisplayPart)), ActionButton.create(Component.text("Cancel", NamedTextColor.RED), Component.text("Cancel this action", NamedTextColor.YELLOW), 200, null))); @@ -108,21 +94,6 @@ public static void sendDialog(@NotNull Player player, @NotNull UUID entityUUID, sendDialog(player, textDisplay, miniMessageFormatted); } - private static List getInputs(TextDisplay textDisplay, boolean miniMessageFormatted){ - return List.of( - getColorType(miniMessageFormatted), - getTextInput(textDisplay.text(), miniMessageFormatted), - getFont(textDisplay.text().font()), - getAlignment(textDisplay.getAlignment()), - getLineWidth(textDisplay.getLineWidth()), - getOpacity(textDisplay.getTextOpacity()), - getBackgroundColor(), - getShadow(textDisplay.isShadowed()), - getSeeThrough(textDisplay.isSeeThrough()), - getDefaultBackground(textDisplay.isDefaultBackground()) - ); - } - private static List getInputs(ActivePart part, boolean miniMessageFormatted){ Component text = part.getTextDisplayText(); return List.of( @@ -230,19 +201,14 @@ private static DialogInput getDefaultBackground(boolean defaultBackground){ .build(); } - private static DialogAction getConfirmAction(){ + private static DialogAction getConfirmAction(ActivePart part){ return DialogAction.customClick((view, audience) -> { Player p = (Player) audience; ActivePartSelection selection = DisplayGroupManager.getPartSelection(p); - if (selection == null){ + if (selection == null) { p.sendMessage(Component.text("Part selection lost!", NamedTextColor.RED)); return; } - ActivePart part = selection.getSelectedPart(); - if (part == null || part.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY){ - p.sendMessage(Component.text("You do not have a text display selected!", NamedTextColor.RED)); - return; - } //Set Text Display Properties Component text; From 47326f8b45e6842d9a64610b9a4fd9acc489174d Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 03:33:53 -0600 Subject: [PATCH 120/139] Add clickable text to add clicked display to player's selected group --- .../command/parts/PartsSelectCMD.java | 2 +- .../relativepoints/DisplayEntitySelector.java | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java index 9c943519..7a7a2467 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java @@ -47,7 +47,7 @@ public void execute(Player player, String[] args) { RelativePointUtils.spawnDisplayEntityPoints(distance, player); } catch(IllegalArgumentException e){ - player.sendMessage(Component.text("Invalid input! Enter a positive number for the distance, or -target to select a targeted Interaction entity", NamedTextColor.RED)); + player.sendMessage(Component.text("Invalid input! Enter a positive number for the distance, or -target to select a targeted Interaction/Mannequin entity", NamedTextColor.RED)); } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java index aa9b7c64..f7715585 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java @@ -2,13 +2,17 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.RelativePoint; import net.donnypz.displayentityutils.utils.DisplayEntities.SinglePartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import net.donnypz.displayentityutils.utils.DisplayUtils; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.*; @@ -34,6 +38,23 @@ public boolean removeFromPointHolder() { public void sendInfo(Player player) { player.sendMessage(MiniMessage.miniMessage().deserialize("Entity Type: " + display.getType().name())); player.sendMessage(MiniMessage.miniMessage().deserialize("Persistent: "+(display.isPersistent() ? "TRUE" : "FALSE"))); + player.sendMessage(Component.text("| Add to your selected group", NamedTextColor.AQUA) + .clickEvent(ClickEvent.callback(a -> { + Player p = (Player) a; + ActiveGroup group = DisplayGroupManager.getSelectedGroup(player); + if (group == null){ + p.sendMessage(DisplayAPI.pluginPrefix + .append(Component.text("You do not have a group selected!", NamedTextColor.RED))); + return; + } + player.sendMessage(DisplayAPI.pluginPrefix + .append(Component.text("Entity added to your selected group!", NamedTextColor.GREEN))); + Location groupLoc = group.getLocation(); + display.setRotation(groupLoc.getYaw(), groupLoc.getPitch()); + group.addEntity(display); + RelativePointUtils.removeRelativePoints(player); + }))); + player.sendMessage(Component.empty()); } @Override From f1fd667858b066a6b008fcd4b7386a75b81a554c Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 03:34:34 -0600 Subject: [PATCH 121/139] fix chunk pdc corruption? --- .../displayentityutils/managers/DisplayGroupManager.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java index a9e04c24..dc6671d7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java @@ -705,7 +705,13 @@ static void addPersistentPacketGroupSilent(@NotNull PacketDisplayEntityGroup gro id = 1; } else{ - id = gson.fromJson(list.getLast(), PersistentPacketGroup.class).id+1; + PersistentPacketGroup ppg = gson.fromJson(list.getLast(), PersistentPacketGroup.class); + if (ppg == null){ + id = list.size()+1; + } + else{ + id = gson.fromJson(list.getLast(), PersistentPacketGroup.class).id+1; + } } PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, group.isAutoShow(), group.isPlaced()); if (cpg == null) return; From 6763634b62bdbfbda43b42e167a96cd018377fb6 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 04:13:21 -0600 Subject: [PATCH 122/139] Place group async & move PreItemPlaceGroupEvent call --- .../events/PreItemPlaceGroupEvent.java | 16 ++++++---------- .../managers/PlaceableGroupManager.java | 1 - .../player/DEUPlayerPlaceBlockListener.java | 9 +++++++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java index e67ca3ef..d454c1db 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java @@ -3,7 +3,6 @@ import net.donnypz.displayentityutils.managers.PlaceableGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; @@ -13,30 +12,27 @@ import org.jetbrains.annotations.Nullable; /** - * Called before the stored {@link DisplayEntityGroup} on an item can be spawned when a player places the item's block or when - * {@link PlaceableGroupManager#spawnGroup(ItemStack, Location, Player)} or similar is called. + * Called before the stored {@link DisplayEntityGroup} on an item can be spawned when a player places the item's block */ public class PreItemPlaceGroupEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); - DisplayEntityGroup group; ItemStack itemStack; Player player; private boolean isCancelled = false; - public PreItemPlaceGroupEvent(@Nullable DisplayEntityGroup group, @NotNull ItemStack itemStack, @Nullable Player player){ + public PreItemPlaceGroupEvent(@NotNull ItemStack itemStack, @Nullable Player player){ super(!Bukkit.isPrimaryThread()); - this.group = group; this.itemStack = itemStack; this.player = player; } /** - * Get the {@link DisplayEntityGroup} involved in this event. - * @return a {@link DisplayEntityGroup} or null if the item's group could not be found + * Get the group tag of the group involved in this event. + * @return the group tag or null */ - public @Nullable DisplayEntityGroup getGroup() { - return group; + public @Nullable String getGroupTag() { + return PlaceableGroupManager.getGroupTag(itemStack); } /** diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index 1c8037cc..7c096963 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -485,7 +485,6 @@ public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player pla DisplayEntityGroup group = DisplayGroupManager.getGroup(tag); if (group == null) return null; - if (!new PreItemPlaceGroupEvent(group, itemStack, itemHolder).callEvent()) return null; PacketDisplayEntityGroup pg = group.createPacketGroup(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK, true, true); if (pg == null) return null; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java index 6aabe135..53daaece 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java @@ -1,5 +1,7 @@ package net.donnypz.displayentityutils.listeners.player; +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.events.PreItemPlaceGroupEvent; import net.donnypz.displayentityutils.managers.PlaceableGroupManager; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -64,8 +66,11 @@ public void onPlaceBlock(BlockPlaceEvent e){ ItemStack itemClone = heldItem.clone(); itemClone.setAmount(1); - PlaceableGroupManager.spawnGroup(itemClone, placeLoc, rot, player); - PlaceableGroupManager.playSounds(itemClone, placeLoc, true); + if (!new PreItemPlaceGroupEvent(itemClone, player).callEvent()) return; + DisplayAPI.getScheduler().runAsync(() -> { + PlaceableGroupManager.spawnGroup(itemClone, placeLoc, rot, player); + PlaceableGroupManager.playSounds(itemClone, placeLoc, true); + }); if (player.getGameMode() != GameMode.CREATIVE){ heldItem.setAmount(heldItem.getAmount()-1); } From cf10f8140ca918e805f209721b0d7dd5a328a13d Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 04:20:58 -0600 Subject: [PATCH 123/139] Add "/deu display resettranslation" --- .../command/display/DisplayCMD.java | 20 ++++++-- .../display/DisplayResetTranslationCMD.java | 46 +++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayResetTranslationCMD.java diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java index b5655c7e..193336fc 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java @@ -2,10 +2,12 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.*; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; public final class DisplayCMD extends ConsoleUsableSubCommand { @@ -17,6 +19,7 @@ public DisplayCMD(){ new DisplayViewRangeCMD(this); new DisplayBillboardCMD(this); new DisplayTranslateCMD(this); + new DisplayResetTranslationCMD(this); new DisplayScaleCMD(this); new DisplaySetBlockCMD(this); } @@ -41,15 +44,26 @@ static void help(CommandSender sender, int page){ sender.sendMessage(Component.empty()); sender.sendMessage(DisplayAPI.pluginPrefixLong); sender.sendMessage(Component.text("| Commands with \"-all\" will apply the command to all display entities in your selection", NamedTextColor.GOLD)); - + if (page == 1){ CMDUtils.sendCMD(sender, "/deu display glowcolor [-all]", "Set your selected display part's glow color"); CMDUtils.sendCMD(sender, "/deu display brightness [-all]", "Set your selected display part's brightness. Enter values between 0-15. -1 resets"); CMDUtils.sendCMD(sender, "/deu display viewrange [-all]", "Set the view range multiplier for your selected display part"); CMDUtils.sendCMD(sender, "/deu display billboard [-all]", "Set the billboard of your selected display part"); CMDUtils.sendCMD(sender, "/deu display translate [-all]", "Translate your selected display part"); + CMDUtils.sendCMD(sender, "/deu display resettranslation [-all]", "Reset the translation of your selected display part"); CMDUtils.sendCMD(sender, "/deu display scale [-all]", "Change the scale of your selected display part, by axis"); + } + else{ CMDUtils.sendCMD(sender, "/deu display setblock <\"-held\" | \"-target\" | block-id> [-all]", "Change the block of a block display part"); - sender.sendMessage(MiniMessage.miniMessage().deserialize("--------------------------")); - //sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); + } + sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); + } + + static boolean isDisplay(Player player, ActivePart part){ + if (!part.isDisplay()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this display entity parts!", NamedTextColor.RED))); + return false; + } + return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayResetTranslationCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayResetTranslationCMD.java new file mode 100644 index 00000000..439c1e1f --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayResetTranslationCMD.java @@ -0,0 +1,46 @@ +package net.donnypz.displayentityutils.command.display; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; +import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; + +class DisplayResetTranslationCMD extends PartsSubCommand { + DisplayResetTranslationCMD(@NotNull DEUSubCommand parentSubCommand) { + super("resettranslation", parentSubCommand, Permission.DISPLAY_TRANSLATE, 2, 2); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) {} + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + for (ActivePart p : selection.getSelectedParts()){ + if (!p.isDisplay()) continue; + Vector3f translation = p.getTransformation().getTranslation(); + p.translate(Vector.fromJOML(translation), translation.length(), 0, 0); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translation reset for all selected displays!", NamedTextColor.GREEN))); + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (!DisplayCMD.isDisplay(player, selectedPart)) return false; + Vector3f translation = selectedPart.getTransformation().getTranslation().negate(); + selectedPart.translate(Vector.fromJOML(translation), translation.length(), 0, 0); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Reset selected display part's translation!", NamedTextColor.GREEN))); + return true; + } +} From c4d7f16128ed6c0ac8ea53640dab836e675b423f Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 04:21:11 -0600 Subject: [PATCH 124/139] Correct incorrect usage message --- .../displayentityutils/command/display/DisplayViewRangeCMD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayViewRangeCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayViewRangeCMD.java index 4419464d..3f7aa48a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayViewRangeCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayViewRangeCMD.java @@ -19,7 +19,7 @@ class DisplayViewRangeCMD extends PartsSubCommand { @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("Provide a part tag! /deu display viewrange [-all]", NamedTextColor.RED)); + player.sendMessage(Component.text("Incorrect Usage! /deu display viewrange [-all]", NamedTextColor.RED)); } @Override From 640e7a799766f04ae5c5eec911f78eed5ce25f14 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 04:27:18 -0600 Subject: [PATCH 125/139] Update README.md --- README.md | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 8b9be4c5..4eeeae71 100644 --- a/README.md +++ b/README.md @@ -3,54 +3,57 @@ [Join the Discord Here!](https://discord.gg/k3wtdG5fRZ) -DisplayEntityUtils is a extensive plugin designed to make the usage of Display/Interaction entities simplier. It also supports BDEngine, a modeling/animation engine designed for display entities without the need for resource packs or mods. +DisplayEntityUtils makes handling customizable display entities simpler. -## What you'll need -### Dependencies: + +### Supported Entities +- **Block Displays** +- **Text Displays** +- **Item Displays** +- **Interactions** +- **Mannequins** + +### Dependencies - **[PacketEvents](https://modrinth.com/plugin/packetevents)** - - **_This dependency allows for usage of packet-based display entities and animations, and is used throughout the plugin_** -### BDEngine (Recommended) -BDEngine is what you'll use to create models and animations that can be transferred into your game world. Info on BDEngine and the Block Display Place, the collection of BDEngine models and animations, can be found [HERE](block-display.com) -> DISCLAIMER: I DO NOT OWN BDModels/BDEngine! ALL ISSUES AND SUGGESTIONS RELATED TO THAT PROJECT SHOULD BE BROUGHT TO THE OWNER, [ILLYSTRAY](https://illystray.com), IN THE BDENGINE DISCORD FOUND [HERE](https://discord.com/invite/VCeHfSd6Xa) +### Supports BDEngine (Recommended) +- **[BDEngine](block-display.com)** is a modeling and animation engine designed for display entities, + without the need for resource packs or mods +- The created models and animations can be transferred into your game world and reused with **DisplayEntityUtils**. +> DISCLAIMER: I DO NOT OWN **BDEngine**! ALL ISSUES AND SUGGESTIONS RELATED TO THAT PROJECT SHOULD BE BROUGHT TO THE OWNER, [ILLYSTRAY](https://illystray.com), IN THE BDENGINE DISCORD FOUND [HERE](https://discord.com/invite/VCeHfSd6Xa) ## What can DisplayEntityUtils do? -- Manipulate Individual Display/Interaction entities -- Manipulate Groups (BDEngine Models) -- Manipulate every part (Display Entity) within a model +- Manipulate Display Entities - Manipulate Interaction Entities +- Manipulate Mannequin Entities +- Save and load BDEngine models +- Manipulate entities in a model/group - Integration with [Skript](https://github.com/SkriptLang/Skript) [![SkriptHubViewTheDocs](http://skripthub.net/static/addon/ViewTheDocsButton.png)](http://skripthub.net/docs/?addon=DisplayEntityUtils) -- Create and Play Animations through the plugin -- Convert Datapack Animations from BDEngine (preferred over creating in-game) -- Include Interaction Entities as part of groups/models -- Execute commands through Interaction Entities -- Retrieve models from BDEngine and spawn them in-game +- Save/Load/Play BDEngine Animations +- Interaction entity click commands - Intergration with **MythicMobs** - Create Animation State Machines - Save groups and animations through Local Storage, MySQL, or MongoDB - And so much more! ## What more can it do for API/Skript users? -- Tools to manipulate Display and Interaction entity as individual entities -- Show/Hide groups to/from certain players +- Manipulate Display/Interaction/Mannequin entities +- Manage group visibility for players - Mount groups on entities (or vice-versa) - Request models from BDEngine's website -- Create packets based groups/entities -- Play packet-based animations -- Theres too many things to list! +- Play animations ## Showcases -- Display Controllers (Using Models as cosmetic equipment) - With(out) MythicMobs +- ### Display Controllers (Using Models as cosmetic equipment) - With(out) MythicMobs > ![ezgif-1-873ca90c95 (1)](https://github.com/user-attachments/assets/ee189856-3459-49b8-b75c-4c18d1b43818) -- Display Controllers (Creating Animation State Machines) - With(out) MythicMobs *(Credit goes to [Yegor_Mechanic](https://block-display.com/author/yegor_mechanic/) for all Dodo Bird Models/Animations)* +- ### Display Controllers (Creating Animation State Machines) - With(out) MythicMobs > ![](https://github.com/user-attachments/assets/594a4ffe-89cf-4e49-aff5-2f8c43ea21ad) - -- API: Display Entities rotating smoothly with yaw changes, and Interaction entities pivoting around the center -> ![](https://github.com/user-attachments/assets/5c333cd4-71ba-4ad1-a631-f8ec648651f0) + > + > *Dodo Bird Model and Animations by [Yegor_Mechanic](https://block-display.com/author/yegor_mechanic/)* ## WIKI ### Access the wiki [HERE](https://github.com/PZDonny/DisplayEntityUtils/wiki) From f59eb267227253d22ea3a21e89e6dd9a3dac4227 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 05:40:58 -0600 Subject: [PATCH 126/139] Add customblockdata dependency --- api/pom.xml | 7 +++++++ pom.xml | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/api/pom.xml b/api/pom.xml index 58bd5cdc..b7375ca0 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -45,6 +45,13 @@ 7.3.5 provided + + + com.jeff-media + custom-block-data + 2.2.4 + compile + \ No newline at end of file diff --git a/pom.xml b/pom.xml index ee864b91..8a51ca57 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,10 @@ org.bstats net.donnypz.displayentityutils.bstats + + com.jeff_media.customblockdata + net.donnypz.displayentityutils.customblockdata + From 5768e94b49c35db5e58266213fd7097173912384 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 07:30:01 -0600 Subject: [PATCH 127/139] rename #setDropItemOnDestroy to #setDropItemOnBreak and add #addSound --- .../managers/PlaceableGroupData.java | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java index 60e9e978..b8a9d5f7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java @@ -1,6 +1,7 @@ package net.donnypz.displayentityutils.managers; import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -9,6 +10,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; + /** * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. @@ -21,6 +24,8 @@ public class PlaceableGroupData { boolean respectBlockFace = true; boolean dropItemOnBreak = true; boolean placerBreaksOnly = true; + ArrayList placeSounds = new ArrayList<>(); + ArrayList breakSounds = new ArrayList<>(); public PlaceableGroupData(@NotNull String groupTag) { @@ -70,11 +75,11 @@ public PlaceableGroupData setRespectBlockFace(boolean respectBlockFace) { /** * Set whether the item used to place the group should be dropped when the group is destroyed - * @param dropItemOnDestroy + * @param dropItemOnBreak * @return this */ - public PlaceableGroupData setDropItemOnDestroy(boolean dropItemOnDestroy){ - this.dropItemOnBreak = dropItemOnDestroy; + public PlaceableGroupData setDropItemOnBreak(boolean dropItemOnBreak){ + this.dropItemOnBreak = dropItemOnBreak; return this; } @@ -88,6 +93,22 @@ public PlaceableGroupData setPlacerBreaksOnly(boolean placerBreaksOnly){ return this; } + + /** + * Add a sound to play when the group is placed or removed/broken + * @param sound the sound + * @param isPlace whether the sound should play when placed or removed/broken + */ + public PlaceableGroupData addSound(@NotNull DEUSound sound, boolean isPlace){ + if (isPlace){ + placeSounds.add(sound); + } + else{ + breakSounds.add(sound); + } + return this; + } + /** * Apply the data to a provided itemstack, spawning the group when placed * @param itemStack @@ -112,6 +133,11 @@ public void apply(@NotNull ItemStack itemStack){ pdc.set(DisplayAPI.getPlaceableGroupPlacerBreaksOnly(), PersistentDataType.BOOLEAN, placerBreaksOnly); pdc.set(DisplayAPI.getPlaceableGroupDropItem(), PersistentDataType.BOOLEAN, dropItemOnBreak); + + pdc.set(DisplayAPI.getPlaceableGroupPlaceSounds(), PersistentDataType.BYTE_ARRAY, + PlaceableGroupManager.writeSoundList(placeSounds)); + pdc.set(DisplayAPI.getPlaceableGroupBreakSounds(), PersistentDataType.BYTE_ARRAY, + PlaceableGroupManager.writeSoundList(breakSounds)); itemStack.setItemMeta(meta); } } From 5778a46903373d31d4314956c71afb555831e9ea Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 07:30:28 -0600 Subject: [PATCH 128/139] rename #setDropItemOnDestroy to #setDropItemOnBreak and add #addSound --- .../displayentityutils/managers/PlaceableGroupManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java index 7c096963..01915938 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -13,6 +13,7 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; @@ -299,7 +300,8 @@ private static NamespacedKey getSoundKey(boolean isPlace){ return isPlace ? DisplayAPI.getPlaceableGroupPlaceSounds() : DisplayAPI.getPlaceableGroupBreakSounds(); } - private static byte[] writeSoundList(List sounds) { + @ApiStatus.Internal + public static byte[] writeSoundList(List sounds) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); From 99d02aa1fb28c18ca4167da8e142340ef546624a Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 07:30:59 -0600 Subject: [PATCH 129/139] Remove removed command listing and unused permission --- .../donnypz/displayentityutils/command/Permission.java | 1 - .../displayentityutils/command/place/PlaceCMD.java | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index 9177d014..6a3e35e4 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -37,7 +37,6 @@ public enum Permission { PLACE_INFO("deu.place.info"), PLACE_SET_ITEM("deu.place.setitem"), PLACE_GET_ITEM("deu.place.getitem"), - PLACE_TOGGLE_PACKET("deu.place.toggle.packet"), PLACE_TOGGLE_PLAYER_FACING("deu.place.toggle.playerfacing"), PLACE_TOGGLE_BLOCK_FACE("deu.place.toggle.blockface"), PLACE_TOGGLE_DROP_ITEM("deu.place.toggle.dropitem"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java index 8d566de3..a97f793a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -54,18 +54,16 @@ static void help(CommandSender sender, int page){ CMDUtils.sendCMD(sender, "/deu place set ", "Assign a group to your held block, which will be spawned when the block is placed"); CMDUtils.sendCMD(sender, "/deu place unset", "Unassign a group from your held block"); CMDUtils.sendCMD(sender, "/deu place setpermission", "Set the permission required to place the group"); - CMDUtils.sendCMD(sender, "/deu place unsetpermission", "Set the permission required to place the group"); + CMDUtils.sendCMD(sender, "/deu place unsetpermission", "Remove the permission required to place the group"); } - else if (page == 2){ - CMDUtils.sendCMD(sender, "/deu place togglepacket", "Toggle whether the placed group will be packet-based. True by default"); + else{ CMDUtils.sendCMD(sender, "/deu place toggleplayerfacing", "Toggle whether the placed group will respect the player's facing direction. True by default"); CMDUtils.sendCMD(sender, "/deu place toggleblockface", "Toggle whether the placed group will respect the block face it is placed on. True by default"); - CMDUtils.sendCMD(sender, "/deu place toggledropitem", "Toggle whether the placed group will drop the item used to place it, when broken. True by default"); + CMDUtils.sendCMD(sender, "/deu place toggledropitem", "Toggle whether the placed group will drop the item used to place it, when broken. " + + "The item never drops for players in creative. True by default"); CMDUtils.sendCMD(sender, "/deu place toggleplaceronly", "Toggle whether only the player who placed a group can break it. True by default"); CMDUtils.sendCMD(sender, "/deu place addsound ", "Add a sound to play when the block is placed or broken"); CMDUtils.sendCMD(sender, "/deu place whoplaced", "Get the name and UUID of the player who placed a group"); - } - else{ CMDUtils.sendCMD(sender, "/deu place getitem", "Get the item used to placed a group"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); From b0d7aaa4af1c9df70d7348d379b4a91422204a38 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 18:31:15 -0600 Subject: [PATCH 130/139] Update mannequin javadocs --- .../utils/DisplayEntities/ActivePart.java | 87 ++++++++++++++++++- .../PacketDisplayEntityPart.java | 6 +- .../SpawnedDisplayEntityPart.java | 2 +- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 614e994e..c5208fa4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -549,49 +549,130 @@ public void unglow(@NotNull Player player) { */ public abstract boolean isInteractionResponsive(); + /** + * Set the profile of this mannequin part effectively changing its skin, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param profile the profile + */ public abstract void setMannequinProfile(@NotNull PlayerProfile profile); + /** + * Set the profile of this mannequin part effectively changing its skin, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param profile the profile + */ public abstract void setMannequinProfile(@NotNull ResolvableProfile profile); - public void setMannequinProfile(@NotNull PlayerProfile profile, Player player){ + /** + * Set the profile of this mannequin part effectively changing its skin, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN}. + * The profile change will only be visible for the provided player + * @param profile the profile + * @param player the player to send profile change to + */ + public void setMannequinProfile(@NotNull PlayerProfile profile, @NotNull Player player){ if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; setMannequinProfile(ResolvableProfile.resolvableProfile(profile), player); } - public void setMannequinProfile(@NotNull ResolvableProfile profile, Player player){ + /** + * Set the profile of this mannequin part effectively changing its skin, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN}. + * The profile change will only be visible for the provided player + * @param profile the profile + * @param player the player to send profile change to + */ + public void setMannequinProfile(@NotNull ResolvableProfile profile, @NotNull Player player){ if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; PacketUtils.setAttribute(player, entityId, DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, profile); } + /** + * Set the description/below name text of this mannequin part, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param text the pose text + */ public abstract void setMannequinBelowName(@Nullable Component text); + /** + * Set the pose of this mannequin part, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param pose the pose + */ public abstract void setMannequinPose(Pose pose); + /** + * Set the scale attribute of this mannequin part, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param scale the scale + */ public abstract void setMannequinScale(double scale); + /** + * Set whether the mannequin part should be immovable, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param immovable the immovability + */ public abstract void setMannequinImmovable(boolean immovable); + /** + * Set whether the mannequin part should have gravity, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param gravity the gravity + */ public abstract void setMannequinGravity(boolean gravity); + /** + * Set the mannequin part's main hand, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param mainHand the main hand + */ public abstract void setMannequinMainHand(@NotNull MainHand mainHand); + /** + * Set the item in mannequin part's equipment slot, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param slot the equipment slot + * @param itemStack the item to put in the slot + */ public abstract void setMannequinEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack); + /** + * Get a mannequin part's profile, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a {@link ResolvableProfile} or null + */ public abstract ResolvableProfile getMannequinProfile(); + /** + * Get a mannequin part's description/below name text, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a {@link Component} or null + */ public abstract @Nullable Component getMannequinBelowName(); + /** + * Get a mannequin part's pose, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a {@link Pose} or null + */ public abstract @Nullable Pose getMannequinPose(); + /** + * Get a mannequin part's scale attribute, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a double or -1 if the part is not a mannequin + */ public abstract double getMannequinScale(); + /** + * Get whether mannequin part is immovable, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a boolean, always false if the part is not a mannequin + */ public abstract boolean isMannequinImmovable(); + /** + * Get whether mannequin part has gravity, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a boolean, always false if the part is not a mannequin + */ public abstract boolean hasMannequinGravity(); + /** + * Get whether mannequin part has gravity, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a {@link MainHand} or null if the part is not a mannequin + */ public abstract @Nullable MainHand getMannequinMainHand(); - public abstract @NotNull ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot); + /** + * Get the item in a mannequin part's equipment slot, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a {@link ItemStack} or null if the part is not a mannequin + */ + public abstract @Nullable ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot); /** * Adds a command to this part to execute when clicked, if its type is {@link SpawnedDisplayEntityPart.PartType#INTERACTION} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 8ffc2243..53644af4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -648,9 +648,9 @@ public void setMannequinMainHand(@NotNull MainHand mainHand) { } @Override - public @NotNull ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot) { - if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return ItemStack.of(Material.AIR); - return attributeContainer.getAttribute(DisplayAttributes.Equipment.getAttribute(equipmentSlot)); + public @Nullable ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return null; + return attributeContainer.getAttributeOrDefault(DisplayAttributes.Equipment.getAttribute(equipmentSlot), new ItemStack(Material.AIR)); } @Override diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 23cc61cd..f1aaa64b 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -1033,7 +1033,7 @@ public void setMannequinMainHand(@NotNull MainHand mainHand) { } @Override - public @NotNull ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot) { + public @Nullable ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot) { if (type != PartType.MANNEQUIN) return null; Mannequin mannequin = (Mannequin) getEntity(); if (mannequin == null) return null; From c561a389c66de85842eb5e5cc912bb5aa64850ac Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:41:56 -0600 Subject: [PATCH 131/139] correct permission --- .../java/net/donnypz/displayentityutils/command/Permission.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index 6a3e35e4..531190a4 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -58,7 +58,7 @@ public enum Permission { PARTS_TRANSFORM("deu.parts.transform"), - DISPLAY_SET_BLOCK("deu.parts.setblock"), + DISPLAY_SET_BLOCK("deu.display.setblock"), DISPLAY_GLOW_COLOR("deu.display.glowcolor"), DISPLAY_TRANSLATE("deu.display.translate"), DISPLAY_TRANSFORM("deu.display.transform"), From 7d954f2818163e4fa84a29b5d78ab80c171b2600 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:58:33 -0600 Subject: [PATCH 132/139] Use correct permission --- .../displayentityutils/command/display/DisplayScaleCMD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayScaleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayScaleCMD.java index 08417eb0..26bdbb84 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayScaleCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayScaleCMD.java @@ -16,7 +16,7 @@ class DisplayScaleCMD extends PartsSubCommand { DisplayScaleCMD(@NotNull DEUSubCommand parentSubCommand) { - super("scale", parentSubCommand, Permission.PARTS_TRANSFORM, 4, 4); + super("scale", parentSubCommand, Permission.DISPLAY_TRANSFORM, 4, 4); setTabComplete(2, List.of("x", "y", "z", "-all")); setTabComplete(3, ""); } From 844fef7c2da37171eda6593118777bb67ad73411 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:58:55 -0600 Subject: [PATCH 133/139] remove commands never created --- .../displayentityutils/command/mannequin/MannequinCMD.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java index 80646da0..c4a9bc4e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -65,8 +65,6 @@ static void help(CommandSender sender, int page){ CMDUtils.sendCMD(sender, "/deu mannequin pivot [-all]"); CMDUtils.sendCMD(sender, "/deu mannequin pose [-all]", "Change your selected mannequin's pose"); CMDUtils.sendCMD(sender, "/deu mannequin scale [-all]", "Set your selected mannequin's scale"); - CMDUtils.sendCMD(sender, "/deu mannequin clone", "Clone a mannequin"); - CMDUtils.sendCMD(sender, "/deu mannequin clonehere", "Clone a mannequin at your current location"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } From 2144bd3ce50209fdb61f5a98df3b48fe53c3b5de Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 22:32:25 -0600 Subject: [PATCH 134/139] Prevent NoClassDefFoundError exceptions --- .../PacketDisplayEntityPart.java | 29 +++++++++---------- .../relativepoints/DisplayEntitySelector.java | 23 ++++++++------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index 53644af4..ab497f24 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -19,6 +19,7 @@ import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import net.donnypz.displayentityutils.utils.packet.attributes.TextDisplayOptions; +import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.kyori.adventure.text.Component; import org.bukkit.*; import org.bukkit.block.data.BlockData; @@ -89,21 +90,19 @@ public PacketDisplayEntityPart(@NotNull SpawnedDisplayEntityPart.PartType partTy SpawnedDisplayEntityPart.PartType pt = SpawnedDisplayEntityPart.PartType.getType(entity); if (pt == null) return null; PacketDisplayEntityPart part; - switch (entity){ - case Display d -> { - part = new DisplayEntity(d, DisplayEntity.Type.fromPartType(pt)) - .createPacketPart(null, entity.getLocation(), null); - } - case Interaction inter -> { - part = new InteractionEntity(inter).createPacketPart(entity.getLocation(), null); - } - case Mannequin man -> { - MannequinEntity m = SavedEntityBuilder.buildMannequin(entity); - part = m.createPacketPart(entity.getLocation(), null); - } - default -> { - return null; - } + if (entity instanceof Display d){ + part = new DisplayEntity(d, DisplayEntity.Type.fromPartType(pt)) + .createPacketPart(null, entity.getLocation(), null); + } + else if (entity instanceof Interaction i){ + part = new InteractionEntity(i).createPacketPart(entity.getLocation(), null); + } + else if (VersionUtils.canSpawnMannequins() && entity instanceof Mannequin){ + MannequinEntity m = SavedEntityBuilder.buildMannequin(entity); + part = m.createPacketPart(entity.getLocation(), null); + } + else{ + return null; } if (removeExistingEntity) entity.remove(); return part; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java index f7715585..45806e82 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java @@ -8,6 +8,7 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.SinglePartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; @@ -83,17 +84,17 @@ public static void select(Player player, Entity entity){ part.glow(player, 30); RelativePointUtils.removeRelativePoints(player); String entityType; - switch(entity){ - case Display d -> { - entityType = "Display"; - } - case Interaction i -> { - entityType = "Interaction"; - } - case Mannequin m -> { - entityType = "Mannequin"; - } - default -> entityType = ""; + if (entity instanceof Display){ + entityType = "Display"; + } + else if (entity instanceof Interaction){ + entityType = "Interaction"; + } + else if (VersionUtils.canSpawnMannequins() && entity instanceof Mannequin){ + entityType = "Mannequin"; + } + else{ + entityType = ""; } player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text(entityType+" Entity Selected!", NamedTextColor.GREEN))); } From 0ca10eab7e7262a3142021d17c938dc4c1b65b7e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 23:26:08 -0600 Subject: [PATCH 135/139] Fix mannequin equipment editor not working for ungrouped mannequins --- .../utils/DisplayEntities/ActivePart.java | 7 ++----- .../utils/DisplayEntities/SinglePartSelection.java | 1 + .../utils/DisplayEntities/SpawnedDisplayEntityPart.java | 5 +++-- .../listeners/entity/DEUMannequinEditorListener.java | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index c5208fa4..451b9628 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -40,14 +40,11 @@ public abstract class ActivePart implements Active{ private boolean valid = true; final Set clientAnimationPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>()); - protected ActivePart(int entityId, boolean mapped){ + protected ActivePart(int entityId, boolean autoMap){ this.entityId = entityId; - if (mapped) { + if (autoMap) { partsById.put(entityId, this); } - else{ - partUUID = UUID.randomUUID(); - } } protected synchronized void unregister(){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java index 2df3a853..5d628c56 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java @@ -23,6 +23,7 @@ public SinglePartSelection(@NotNull SpawnedDisplayEntityPart part){ @Override public void remove() { + selectedPart.remove(false); selectedPart = null; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index f1aaa64b..22ef2b02 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -58,12 +58,13 @@ public final class SpawnedDisplayEntityPart extends ActivePart implements Spawne } SpawnedDisplayEntityPart(Entity entity){ - super(entity.getEntityId(), false); + super(entity.getEntityId(), true); if (PartType.getType(entity) == null) throw new IllegalArgumentException("Entity is not a valid part type entity"); this.type = PartType.getType(entity); this.entity = entity; this.entityUUID = entity.getUniqueId(); - isSingle = true; + this.partUUID = UUID.randomUUID(); + this.isSingle = true; } /** diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java index 9821d370..b3c81d56 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java @@ -38,7 +38,7 @@ public class DEUMannequinEditorListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onInventoryClick(InventoryClickEvent event){ - if (!VersionUtils.IS_1_21_9) return; + if (!VersionUtils.canSpawnMannequins()) return; Inventory inv = event.getInventory(); Player player = (Player) event.getWhoClicked(); @@ -61,7 +61,7 @@ public void onInventoryClick(InventoryClickEvent event){ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onInventoryClose(InventoryCloseEvent event) { - if (!VersionUtils.IS_1_21_9) return; + if (!VersionUtils.canSpawnMannequins()) return; Inventory inv = event.getInventory(); Player player = (Player) event.getPlayer(); From 2b8425b5080c8f10d3fffc38f5864f8a445df9d2 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 1 Jan 2026 23:26:14 -0600 Subject: [PATCH 136/139] No changes --- .../displayentityutils/command/mannequin/MannequinUnnameCMD.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java index 750f93fd..fd261d3d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java @@ -4,7 +4,6 @@ import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.PartsSubCommand; import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.command.mannequin.ui.MannequinEquipmentGUI; import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; From 97c26baa9bc563940fa0e49740a69fafcfe68d70 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 2 Jan 2026 00:43:03 -0600 Subject: [PATCH 137/139] Update mannnequin scale when group's scale changes --- .../utils/DisplayEntities/ActiveGroup.java | 4 +- .../PacketDisplayEntityGroup.java | 56 ++++++++++--------- .../SpawnedDisplayEntityGroup.java | 55 ++++++++++-------- .../packet/PacketAttributeContainer.java | 3 + 4 files changed, 68 insertions(+), 50 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java index 7f744af4..284d522a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java @@ -133,10 +133,10 @@ public void removeCulling(){ * Change the scale of all parts in this group by the given scale multiplier * @param newScaleMultiplier the scale multiplier to apply to this group * @param durationInTicks how long it should take for the group to scale - * @param scaleInteractions whether interaction entities should be scaled + * @param scaleNonDisplays whether non-display entities should scale * @throws IllegalArgumentException if newScaleMultiplier is less than or equal to 0 */ - public abstract boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleInteractions); + public abstract boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleNonDisplays); /** * Change the true location of this group. diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index 91604a49..c956b616 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -289,7 +289,7 @@ void updatePassengerIds(int passengerId, boolean add){ @Override - public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleInteractions) { + public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleNonDisplays) { if (newScaleMultiplier <= 0){ throw new IllegalArgumentException("New Scale Multiplier cannot be <= 0"); } @@ -297,11 +297,11 @@ public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scal return true; } - for (PacketDisplayEntityPart p : groupParts.values()){ + for (PacketDisplayEntityPart part : groupParts.values()){ //Displays - if (p.isDisplay()){ + if (part.isDisplay()){ DisplayAttributeMap attributeMap = new DisplayAttributeMap(); - Transformation transformation = p.getTransformation(); + Transformation transformation = part.getTransformation(); //Reset Scale then multiply by newScaleMultiplier Vector3f scale = transformation.getScale(); scale.x = (scale.x/scaleMultiplier)*newScaleMultiplier; @@ -314,40 +314,46 @@ public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scal translationVector.y = (translationVector.y/scaleMultiplier)*newScaleMultiplier; translationVector.z = (translationVector.z/scaleMultiplier)*newScaleMultiplier; - if (!transformation.equals(p.getTransformation())){ + if (!transformation.equals(part.getTransformation())){ attributeMap.add(DisplayAttributes.Interpolation.DURATION, durationInTicks) .add(DisplayAttributes.Interpolation.DELAY, -1) .addTransformation(transformation); } //Culling if (DisplayConfig.autoCulling()){ - float[] values = DisplayUtils.getAutoCullValues(p, DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); + float[] values = DisplayUtils.getAutoCullValues(part, DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); attributeMap.add(DisplayAttributes.Culling.HEIGHT, values[1]) .add(DisplayAttributes.Culling.WIDTH, values[0]); } - p.attributeContainer.setAttributesAndSend(attributeMap, p.getEntityId(), p.viewers); + part.attributeContainer.setAttributesAndSend(attributeMap, part.getEntityId(), part.viewers); } - //Interactions - else if (scaleInteractions){ - - //Reset Scale then multiply by newScaleMultiplier - float newHeight = (p.getInteractionHeight()/scaleMultiplier)*newScaleMultiplier; - float newWidth = (p.getInteractionWidth()/scaleMultiplier)*newScaleMultiplier; - PacketUtils.scaleInteraction(p, newHeight, newWidth, durationInTicks, 0); + //Non Displays + else if (scaleNonDisplays){ + if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + //Reset Scale then multiply by newScaleMultiplier + float newHeight = (part.getInteractionHeight()/scaleMultiplier)*newScaleMultiplier; + float newWidth = (part.getInteractionWidth()/scaleMultiplier)*newScaleMultiplier; + PacketUtils.scaleInteraction(part, newHeight, newWidth, durationInTicks, 0); + + //Reset Translation then multiply by newScaleMultiplier + Vector translationVector = part.getNonDisplayTranslation(); + if (translationVector == null){ + continue; + } + Vector oldVector = new Vector(translationVector.getX(), translationVector.getY(), translationVector.getZ()); + translationVector.setX((translationVector.getX()/scaleMultiplier)*newScaleMultiplier); + translationVector.setY((translationVector.getY()/scaleMultiplier)*newScaleMultiplier); + translationVector.setZ((translationVector.getZ()/scaleMultiplier)*newScaleMultiplier); - //Reset Translation then multiply by newScaleMultiplier - Vector translationVector = p.getNonDisplayTranslation(); - if (translationVector == null){ - continue; + Vector moveVector = oldVector.subtract(translationVector); + PacketUtils.translateNonDisplay(part, moveVector, moveVector.length(), durationInTicks, 0); + } + else if (part.type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + double scale = part.attributeContainer.getAttributeOrDefault(DisplayAttributes.Mannequin.SCALE, 1f); + scale = (scale/scaleMultiplier)*newScaleMultiplier; + part.attributeContainer.setAttributeAndSend(DisplayAttributes.Mannequin.SCALE, (float) scale, part.getEntityId(), part.viewers); } - Vector oldVector = new Vector(translationVector.getX(), translationVector.getY(), translationVector.getZ()); - translationVector.setX((translationVector.getX()/scaleMultiplier)*newScaleMultiplier); - translationVector.setY((translationVector.getY()/scaleMultiplier)*newScaleMultiplier); - translationVector.setZ((translationVector.getZ()/scaleMultiplier)*newScaleMultiplier); - - Vector moveVector = oldVector.subtract(translationVector); - PacketUtils.translateNonDisplay(p, moveVector, moveVector.length(), durationInTicks, 0); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index 4833b5f2..d5bd72b6 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -14,6 +14,7 @@ import net.donnypz.displayentityutils.utils.version.folia.FoliaUtils; import net.donnypz.displayentityutils.utils.version.folia.Scheduler; import org.bukkit.*; +import org.bukkit.attribute.Attribute; import org.bukkit.entity.*; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -413,7 +414,7 @@ public SpawnedDisplayEntityGroup setPersistenceOverride(boolean override){ } @Override - public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleInteractions){ + public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleNonDisplays){ if (newScaleMultiplier <= 0){ throw new IllegalArgumentException("New Scale Multiplier cannot be <= 0"); } @@ -429,10 +430,10 @@ public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scal return false; } - for (SpawnedDisplayEntityPart p : groupParts.values()){ + for (SpawnedDisplayEntityPart part : groupParts.values()){ //Displays - if (p.isDisplay()){ - Display d = (Display) p.getEntity(); + if (part.isDisplay()){ + Display d = (Display) part.getEntity(); Transformation transformation = d.getTransformation(); //Reset Scale then multiply by newScaleMultiplier @@ -455,30 +456,38 @@ public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scal } //Culling if (DisplayConfig.autoCulling()){ - p.autoCull(DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); + part.autoCull(DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); } } //Interactions - else if (scaleInteractions){ - Interaction i = (Interaction) p.getEntity(); - - //Reset Scale then multiply by newScaleMultiplier - float newHeight = (i.getInteractionHeight()/scaleMultiplier)*newScaleMultiplier; - float newWidth = (i.getInteractionWidth()/scaleMultiplier)*newScaleMultiplier; - DisplayUtils.scaleInteraction(i, newHeight, newWidth, durationInTicks, 0); + else if (scaleNonDisplays){ + if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + Interaction i = (Interaction) part.getEntity(); + + //Reset Scale then multiply by newScaleMultiplier + float newHeight = (i.getInteractionHeight()/scaleMultiplier)*newScaleMultiplier; + float newWidth = (i.getInteractionWidth()/scaleMultiplier)*newScaleMultiplier; + DisplayUtils.scaleInteraction(i, newHeight, newWidth, durationInTicks, 0); + + //Reset Translation then multiply by newScaleMultiplier + Vector translationVector = DisplayUtils.getNonDisplayTranslation(i); + if (translationVector == null){ + continue; + } + Vector oldVector = new Vector(translationVector.getX(), translationVector.getY(), translationVector.getZ()); + translationVector.setX((translationVector.getX()/scaleMultiplier)*newScaleMultiplier); + translationVector.setY((translationVector.getY()/scaleMultiplier)*newScaleMultiplier); + translationVector.setZ((translationVector.getZ()/scaleMultiplier)*newScaleMultiplier); - //Reset Translation then multiply by newScaleMultiplier - Vector translationVector = DisplayUtils.getNonDisplayTranslation(i); - if (translationVector == null){ - continue; + Vector moveVector = oldVector.subtract(translationVector); + part.translateForce(moveVector, (float) moveVector.length(), durationInTicks, 0); + } + else if (part.type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + Mannequin m = (Mannequin) part.getEntity(); + double scale = m.getAttribute(Attribute.SCALE).getBaseValue(); + scale = (scale/scaleMultiplier)*newScaleMultiplier; + m.getAttribute(Attribute.SCALE).setBaseValue(scale); } - Vector oldVector = new Vector(translationVector.getX(), translationVector.getY(), translationVector.getZ()); - translationVector.setX((translationVector.getX()/scaleMultiplier)*newScaleMultiplier); - translationVector.setY((translationVector.getY()/scaleMultiplier)*newScaleMultiplier); - translationVector.setZ((translationVector.getZ()/scaleMultiplier)*newScaleMultiplier); - - Vector moveVector = oldVector.subtract(translationVector); - p.translateForce(moveVector, (float) moveVector.length(), durationInTicks, 0); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java index 888a9549..c0f9f62f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java @@ -539,6 +539,9 @@ Equipment createEquipmentData(DisplayAttribute attribute, Object value){ } WrapperPlayServerUpdateAttributes.Property createAttributeData(DisplayAttribute attribute, Object value){ + if (attribute == DisplayAttributes.Mannequin.SCALE){ + value = Math.clamp((float) value, 0, 16); + } return new WrapperPlayServerUpdateAttributes.Property(((AttributeDisplayAttribute) attribute).getAttribute(), (float) value, List.of()); From 78cd98c5ba4e2417411df5df60148ea6ba67c659 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 2 Jan 2026 00:51:57 -0600 Subject: [PATCH 138/139] Add place events to skript --- .../skript/events/SimpleEvents.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/events/SimpleEvents.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/events/SimpleEvents.java index cdffcfe6..a6c6e2cd 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/events/SimpleEvents.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/events/SimpleEvents.java @@ -11,6 +11,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Interaction; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.ApiStatus; import java.util.UUID; @@ -79,6 +80,22 @@ public class SimpleEvents extends SimpleEvent { EventValues.registerEventValue(PacketGroupDestroyEvent.class, PacketDisplayEntityGroup.class, PacketGroupDestroyEvent::getGroup); EventValues.registerEventValue(PacketGroupDestroyEvent.class, Player[].class, e -> e.getPlayers().toArray(new Player[0])); + //Pre Item Place Group Event + Skript.registerEvent("Item Place Group Event", SimpleEvents.class, PreItemPlaceGroupEvent.class, "pre item place[d] [packet] [display] group") + .description("Called before a player places a packet-based using an item") + .since("3.4.0"); + EventValues.registerEventValue(PreItemPlaceGroupEvent.class, String.class, PreItemPlaceGroupEvent::getGroupTag); + EventValues.registerEventValue(PreItemPlaceGroupEvent.class, Player.class, PreItemPlaceGroupEvent::getPlayer); + EventValues.registerEventValue(PreItemPlaceGroupEvent.class, ItemStack.class, PreItemPlaceGroupEvent::getItemStack); + + //Item Place Group Event + Skript.registerEvent("Item Place Group Event", SimpleEvents.class, ItemPlaceGroupEvent.class, "item place[d] [packet] [display] group") + .description("Called when a player places a packet-based using an item") + .since("3.4.0"); + EventValues.registerEventValue(ItemPlaceGroupEvent.class, ActiveGroup.class, ItemPlaceGroupEvent::getGroup); + EventValues.registerEventValue(ItemPlaceGroupEvent.class, Player.class, ItemPlaceGroupEvent::getPlayer); + EventValues.registerEventValue(ItemPlaceGroupEvent.class, ItemStack.class, ItemPlaceGroupEvent::getItemStack); + //Animation Start Event Skript.registerEvent("Animation Start", SimpleEvents.class, AnimationStartEvent.class, "[deu] anim[ation] start[ed]") .description("Called when a display animator starts playing an animation") From 9e41de3d9eb0a191e71f5fb0d3c6a5ca663ee792 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 2 Jan 2026 00:53:22 -0600 Subject: [PATCH 139/139] 3.4.0 --- api/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index b7375ca0..51976498 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.4.0-PRE-1 + 3.4.0 api diff --git a/plugin/pom.xml b/plugin/pom.xml index 89229dec..df39f8bd 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.4.0-PRE-1 + 3.4.0 plugin diff --git a/pom.xml b/pom.xml index 8a51ca57..75bec5f2 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.4.0-PRE-1 + 3.4.0 pom DisplayEntityUtils