From 5ca19fa71e72153228807f1964914ef494394c83 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 2 Apr 2026 17:51:56 -0500 Subject: [PATCH 01/55] remove spigot and bukkit from loaders --- .github/workflows/modrinth.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/modrinth.yml b/.github/workflows/modrinth.yml index 14e1cae1..4c8d25ac 100644 --- a/.github/workflows/modrinth.yml +++ b/.github/workflows/modrinth.yml @@ -35,8 +35,6 @@ jobs: changelog: ${{ github.event.release.body }} loaders: |- paper - spigot - bukkit game-versions: |- 1.20.x 1.21.x From ebcd4258a3253c7af35189047a2d24f42e31ac22 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 2 Apr 2026 17:52:10 -0500 Subject: [PATCH 02/55] update skript docs --- .../skript/group/activegroup/sections/SecSpawnGroup.java | 2 +- .../displayentityutils/skript/io/sections/SecSpawnBDEModel.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/sections/SecSpawnGroup.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/sections/SecSpawnGroup.java index 5762bcaa..44f4e645 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/sections/SecSpawnGroup.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/sections/SecSpawnGroup.java @@ -39,7 +39,7 @@ "`brightness` = the brightness of display entities in the group. Use `-1 and -1` for default brightness", "`spawnanimation` = whether the group should play its spawn animation. True by default", "", - "\"If a group is packet-based it's persistence cannot be set within the \\nsection and must be set afterwards.\"" + "If a group is packet-based it's persistence cannot be set within the section and must be set afterwards." }) @Examples({"deu spawn {_savedgroup} at {_location}", "deu spawn {_savedgroup} at {_location} and store the result in {_activegroup}", diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/io/sections/SecSpawnBDEModel.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/io/sections/SecSpawnBDEModel.java index 2a4e7694..4eaf7013 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/io/sections/SecSpawnBDEModel.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/io/sections/SecSpawnBDEModel.java @@ -40,7 +40,7 @@ "`brightness` = the brightness of display entities in the group. Use `-1 and -1` for default brightness", "`spawnanimation` = whether the group should play its spawn animation. True by default", "", - "If a group is packet-based it's persistence cannot be set within the \nsection and must be set afterwards." + "If a group is packet-based it's persistence cannot be set within the section and must be set afterwards." }) @Examples({ "deu spawn bde model \"mymodel\" at {_location}", From 650dd131aafc76c47cf2089aef1706428f2a3b07 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 7 Apr 2026 04:06:41 -0500 Subject: [PATCH 03/55] update skript examples --- .../group/activegroup/effects/EffActiveGroupUnregister.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/effects/EffActiveGroupUnregister.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/effects/EffActiveGroupUnregister.java index f5a2b43a..1c256fae 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/effects/EffActiveGroupUnregister.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/effects/EffActiveGroupUnregister.java @@ -20,9 +20,6 @@ @Name("Unregister Active Group") @Description("Unregister an active group, making the group unusable. Packet based groups do not require forced chunk loading, and will always despawn.") @Examples({ - "deu unregister {_activegroup}", - "", - "#3.4.3 and earlier", "deu unregister {_activegroup}", "deu unregister {_activegroup} and despawn", "deu unregister {_activegroup} and despawn with forced chunk loading", From 24a9be32caf7cbecf6c35cc87a836fded359e695 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 7 Apr 2026 04:10:26 -0500 Subject: [PATCH 04/55] no changes --- .../utils/DisplayEntities/PacketDisplayEntityGroup.java | 7 +------ 1 file changed, 1 insertion(+), 6 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 916e4c71..70e2bc66 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 @@ -1137,10 +1137,5 @@ PacketDisplayEntityGroup getGroup(long chunkKey, int localId){ } } - static class PassengerGroupData extends AsyncGroupHolder { - - Set getGroups(Entity entity){ - return getGroups(entity.getUniqueId()); - } - } + private final static class PassengerGroupData extends AsyncGroupHolder {} } \ No newline at end of file From 26899cd783282e3e4477950176960fac0d966e59 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 7 Apr 2026 04:13:26 -0500 Subject: [PATCH 05/55] update syntax to require "deu" --- .../group/activegroup/effects/EffActiveGroupRideEntity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/effects/EffActiveGroupRideEntity.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/effects/EffActiveGroupRideEntity.java index 9480466e..a8f9afd6 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/effects/EffActiveGroupRideEntity.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/group/activegroup/effects/EffActiveGroupRideEntity.java @@ -41,7 +41,7 @@ public class EffActiveGroupRideEntity extends Effect { public static void register(SyntaxRegistry registry){ registry.register(SyntaxRegistry.EFFECT, SyntaxInfo.builder(EffActiveGroupRideEntity.class) - .addPattern("[deu] make %activegroup/entity% (mount|ride) %activegroup/entity% [c:using controller [with id] %-string%]") + .addPattern("deu make %activegroup/entity% (mount|ride) %activegroup/entity% [c:using controller [with id] %-string%]") .supplier(EffActiveGroupRideEntity::new) .build() ); From 2b0d331684ffcccab59ba61aaf5444d6ee638830 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 15 Apr 2026 03:58:38 -0500 Subject: [PATCH 06/55] 3.5.2-PRE --- 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 b31b85b5..c9d4031c 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.1 + 3.5.2-PRE api diff --git a/plugin/pom.xml b/plugin/pom.xml index a28b9a3f..ec6a7872 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.1 + 3.5.2-PRE plugin diff --git a/pom.xml b/pom.xml index 2f346d91..8f10f076 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.1 + 3.5.2-PRE pom DisplayEntityUtils From a06597a8a76f6969086fcba0674db08047de2360 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:52:41 -0500 Subject: [PATCH 07/55] change #equals() and #hashCode() methods for groups --- .../utils/DisplayEntities/ActiveGroup.java | 39 ++----------------- .../SpawnedDisplayEntityGroup.java | 23 +++-------- 2 files changed, 9 insertions(+), 53 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 54731f80..968ecadb 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 @@ -1084,44 +1084,13 @@ static int next() { @Override public boolean equals(Object o) { - if (!(o instanceof ActiveGroup group)) return false; - return ID == group.ID - && Float.compare(scaleMultiplier, group.scaleMultiplier) == 0 - && lastAnimatedTick == group.lastAnimatedTick - && Objects.equals(masterPart, group.masterPart) - && Objects.equals(groupParts, group.groupParts) - && Objects.equals(tag, group.tag) - && Objects.equals(followers, group.followers) - && Objects.equals(followerLock, group.followerLock) - && Objects.equals(defaultFollower, group.defaultFollower) - && Objects.equals(animatorLock, group.animatorLock) - && Objects.equals(activeAnimators, group.activeAnimators) - && Objects.equals(spawnAnimationTag, group.spawnAnimationTag) - && spawnAnimationLoadMethod == group.spawnAnimationLoadMethod - && spawnAnimationType == group.spawnAnimationType - && Objects.equals(currentMachineState, group.currentMachineState) - && Objects.equals(rideOffset, group.rideOffset); + if (this == o) return true; + if (!(o instanceof ActiveGroup other)) return false; + return ID == other.ID; } @Override public int hashCode() { - return Objects.hash( - ID, - masterPart, - groupParts, - tag, - followers, - followerLock, - defaultFollower, - animatorLock, - activeAnimators, - spawnAnimationTag, - spawnAnimationLoadMethod, - spawnAnimationType, - currentMachineState, - scaleMultiplier, - rideOffset, - lastAnimatedTick - ); + return Integer.hashCode(ID); } } 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 d4f27187..b935a655 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 @@ -34,7 +34,7 @@ public final class SpawnedDisplayEntityGroup extends ActiveGroup partSelections = new HashSet<>(); - long creationTime = System.currentTimeMillis(); + private final long creationTime; boolean isVisibleByDefault; private boolean isPersistent = DisplayConfig.defaultPersistence(); private boolean persistenceOverride = DisplayConfig.persistenceOverride(); @@ -46,6 +46,7 @@ public final class SpawnedDisplayEntityGroup extends ActiveGroup chunks){ public boolean isSpawned(){ return masterPart != null && masterPart.isValid(); } - - @Override - public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; - SpawnedDisplayEntityGroup that = (SpawnedDisplayEntityGroup) o; - return creationTime == that.creationTime - && isVisibleByDefault == that.isVisibleByDefault - && isPersistent == that.isPersistent - && persistenceOverride == that.persistenceOverride - && Objects.equals(partUUIDRandom, that.partUUIDRandom) - && Objects.equals(partSelections, that.partSelections); - } - - @Override - public int hashCode() { - return Objects.hash(partUUIDRandom, partSelections, creationTime, isVisibleByDefault, isPersistent, persistenceOverride); - } } \ No newline at end of file From c852a7c49f1ab97c2ba8428178f960b27598b484 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:53:50 -0500 Subject: [PATCH 08/55] update #canContinueAnimation --- .../utils/DisplayEntities/ClientAnimationPlayerImpl.java | 5 +---- .../utils/DisplayEntities/DisplayAnimationPlayer.java | 2 +- .../utils/DisplayEntities/PacketAnimationPlayer.java | 5 +---- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ClientAnimationPlayerImpl.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ClientAnimationPlayerImpl.java index 511aa8d6..fc433cf7 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ClientAnimationPlayerImpl.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ClientAnimationPlayerImpl.java @@ -35,10 +35,7 @@ public void prepareAnimation(SpawnedDisplayAnimation animation, ActiveGroup g @Override protected boolean canContinueAnimation(ActiveGroup group) { - if (group instanceof SpawnedDisplayEntityGroup g && !g.isRegistered()){ - return false; - } - return group.masterPart != null; + return group.isRegistered(); } @Override diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationPlayer.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationPlayer.java index 3becf573..9c286d6a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationPlayer.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationPlayer.java @@ -28,7 +28,7 @@ protected void handleAnimationComplete(ActiveGroup group, MultiPartSelection< @Override protected boolean canContinueAnimation(ActiveGroup group) { - return group.isActiveAnimator(animator) && ((SpawnedDisplayEntityGroup) group).isRegistered(); + return group.isActiveAnimator(animator) && group.isRegistered(); } @Override diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketAnimationPlayer.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketAnimationPlayer.java index 598eec73..1b55782c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketAnimationPlayer.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketAnimationPlayer.java @@ -27,10 +27,7 @@ protected void handleAnimationComplete(ActiveGroup group, MultiPartSelection< @Override protected boolean canContinueAnimation(ActiveGroup group) { - if (group instanceof SpawnedDisplayEntityGroup g && !g.isRegistered()){ - return false; - } - return group.isActiveAnimator(animator); + return group.isActiveAnimator(animator) && group.isRegistered(); } @Override From 6db2cd491760d81fa2962e3bc5228aa1ff0d1f26 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:20:03 -0500 Subject: [PATCH 09/55] Use correct transformation in #applyDisplayTransformationWithPackets when sending attributes to players. formatted for some reason... --- .../DisplayEntities/AnimationPlayer.java | 305 ++++++++---------- 1 file changed, 139 insertions(+), 166 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 4cbb2e95..384859aa 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 @@ -34,7 +34,7 @@ public abstract class AnimationPlayer { int startFrameId, int delay, boolean playSingleFrame, - boolean packetAnimationPlayer){ + boolean packetAnimationPlayer) { this.animator = animator; this.group = group; this.playSingleFrame = playSingleFrame; @@ -45,68 +45,63 @@ public abstract class AnimationPlayer { AnimationPlayer(@NotNull DisplayAnimator animator, @NotNull ActiveGroup group, boolean playSingleFrame, - boolean packetAnimationPlayer){ + boolean packetAnimationPlayer) { this.animator = animator; this.group = group; this.playSingleFrame = playSingleFrame; this.packetAnimationPlayer = packetAnimationPlayer; } - protected void prepareAnimation(SpawnedDisplayAnimation animation, ActiveGroup group, SpawnedDisplayAnimationFrame frame, int frameId, int delay){ + protected void prepareAnimation(SpawnedDisplayAnimation animation, ActiveGroup group, SpawnedDisplayAnimationFrame frame, int frameId, int delay) { group.addActiveAnimator(animator); MultiPartSelection selection = animation.hasFilter() ? group.createPartSelection(animation.filter) : group.createPartSelection(); - if (packetAnimationPlayer){ + if (packetAnimationPlayer) { DisplayAPI .getScheduler() .partRunLaterAsync(group.getMasterPart(), () -> executeAnimation(null, animation, group, selection, frame, frameId, playSingleFrame), Math.max(delay, 0)); - } - else{ - if (delay <= 0){ + } else { + if (delay <= 0) { executeAnimation(null, animation, group, selection, frame, frameId, playSingleFrame); - } - else{ + } else { DisplayAPI.getScheduler().runLater(() -> executeAnimation(null, animation, group, selection, frame, frameId, playSingleFrame), delay); } } } - protected void executeAnimation(Collection players, SpawnedDisplayAnimation animation, ActiveGroup group, MultiPartSelection selection, SpawnedDisplayAnimationFrame frame, int frameId, boolean playSingleFrame){ + protected void executeAnimation(Collection players, SpawnedDisplayAnimation animation, ActiveGroup group, MultiPartSelection selection, SpawnedDisplayAnimationFrame frame, int frameId, boolean playSingleFrame) { if (!onStartNewFrame(group, selection)) return; //Check if the animation can continue playing - if (!canContinueAnimation(group)){ + if (!canContinueAnimation(group)) { handleAnimationInterrupted(group, selection); return; } - if (animator.type == DisplayAnimator.AnimationType.LOOP){ + if (animator.type == DisplayAnimator.AnimationType.LOOP) { SpawnedDisplayAnimationFrame startFrame = animation.frames.getFirst(); SpawnedDisplayAnimationFrame lastFrame = animation.frames.getLast(); - if (startFrame == frame){ + if (startFrame == frame) { callAnimationLoopStart(players, group); - } - else if (frame == lastFrame && startFrame.equals(frame) && !playSingleFrame && animation.frames.size() > 1){ //Skip if start and last frame are identical + } else if (frame == lastFrame && startFrame.equals(frame) && !playSingleFrame && animation.frames.size() > 1) { //Skip if start and last frame are identical executeAnimation(players, animation, group, selection, animation.frames.getFirst(), 0, false); return; } } Location groupLoc = group.getLocation(); - if (!playSingleFrame){ + if (!playSingleFrame) { callAnimationFrameStart(players, group, animation, frame, frameId); - } - else{ + } else { callAnimationSetFrame(players, group, animation, frame); } - if (players != null){ + if (players != null) { frame.playEffects(players, group); - } - else{ + } else { frame.playEffects(group, animator, true); } - if ((!packetAnimationPlayer && groupLoc.isChunkLoaded()) || players != null || group.hasTrackingPlayers()){ + if ((!packetAnimationPlayer && groupLoc.isChunkLoaded()) || players != null || group.hasTrackingPlayers()) { animateInteractions(players, groupLoc, frame, group, selection, animation); animateDisplays(players, frame, group, selection, animation); } @@ -114,30 +109,29 @@ else if (frame == lastFrame && startFrame.equals(frame) && !playSingleFrame && a if (players == null) group.setLastAnimatedTick(); - if (playSingleFrame){ + if (playSingleFrame) { handleAnimationInterrupted(group, selection); return; } //Play Next Frame - if (frame != animation.frames.getLast()){ + if (frame != animation.frames.getLast()) { prevFrame = frame; - int delay = frame.duration+frame.delay; - if (frame.duration <= 0 && frame.delay <= 0){ + int delay = frame.duration + frame.delay; + if (frame.duration <= 0 && frame.delay <= 0) { delay++; } - if (frame.duration > 0){ + if (frame.duration > 0) { useScheduler(() -> { callAnimationFrameEnd(players, group, animation, frame, frameId); }, frame.duration); - } - else{ + } else { callAnimationFrameEnd(players, group, animation, frame, frameId); } useScheduler(() -> { - SpawnedDisplayAnimationFrame nextFrame = animation.frames.get(frameId+1); - executeAnimation(players, animation, group, selection, nextFrame, frameId+1, false); + SpawnedDisplayAnimationFrame nextFrame = animation.frames.get(frameId + 1); + executeAnimation(players, animation, group, selection, nextFrame, frameId + 1, false); }, delay); } @@ -149,8 +143,7 @@ else if (frame == lastFrame && startFrame.equals(frame) && !playSingleFrame && a callAnimationComplete(players, group, animation); handleAnimationComplete(group, selection); }, frame.duration); - } - else { + } else { callAnimationComplete(players, group, animation); handleAnimationComplete(group, selection); } @@ -163,33 +156,32 @@ else if (frame == lastFrame && startFrame.equals(frame) && !playSingleFrame && a useScheduler(() -> { executeAnimation(players, animation, group, selection, firstFrame, 0, false); }, frame.duration); - } - else { + } else { executeAnimation(players, animation, group, selection, animation.frames.getFirst(), 0, false); } } } } - void animateInteractions(Collection players, Location groupLoc, SpawnedDisplayAnimationFrame frame, ActiveGroup group, MultiPartSelection selection, SpawnedDisplayAnimation animation){ - if (!group.isActiveAnimator(animator)){ + void animateInteractions(Collection players, Location groupLoc, SpawnedDisplayAnimationFrame frame, ActiveGroup group, MultiPartSelection selection, SpawnedDisplayAnimation animation) { + if (!group.isActiveAnimator(animator)) { return; } - for (Map.Entry entry : frame.interactionTransformations.entrySet()){ + for (Map.Entry entry : frame.interactionTransformations.entrySet()) { UUID partUUID = entry.getKey(); Vector3f transform = entry.getValue(); - if (transform == null){ + if (transform == null) { continue; } ActivePart part = group.getPart(partUUID); - if (part == null || !selection.contains(part)){ + if (part == null || !selection.contains(part)) { continue; } Vector currentVector = part.getNonDisplayTranslation(); - if (currentVector == null){ + if (currentVector == null) { continue; } @@ -197,95 +189,89 @@ void animateInteractions(Collection players, Location groupLoc, SpawnedD float height = part.getInteractionHeight(); float width = part.getInteractionWidth(); float yawAtCreation = InteractionTransformation.invalidDirectionValue; - if (transform instanceof InteractionTransformation t && t.vector != null){ + if (transform instanceof InteractionTransformation t && t.vector != null) { v = t.vector.clone(); - if (t.height != -1 && t.width != -1){ + if (t.height != -1 && t.width != -1) { height = t.height; width = t.width; - if (group.getScaleMultiplier() != 1 && animation.groupScaleRespect()){ - height*=group.getScaleMultiplier(); - width*=group.getScaleMultiplier(); + if (group.getScaleMultiplier() != 1 && animation.groupScaleRespect()) { + height *= group.getScaleMultiplier(); + width *= group.getScaleMultiplier(); } yawAtCreation = t.groupYawAtCreation; } - } - - else{ + } else { v = Vector.fromJOML(transform); } - if (group.getScaleMultiplier() != 1 && animation.groupScaleRespect()){ + if (group.getScaleMultiplier() != 1 && animation.groupScaleRespect()) { v.multiply(group.getScaleMultiplier()); } - if (yawAtCreation != InteractionTransformation.invalidDirectionValue){ //Pivot + if (yawAtCreation != InteractionTransformation.invalidDirectionValue) { //Pivot v.rotateAroundY(Math.toRadians(yawAtCreation - groupLoc.getYaw())); } if (!currentVector.equals(v)) { Vector moveVector = currentVector.subtract(v); - if (players == null){ + if (players == null) { part.translate(moveVector, frame.duration, 0); - } - else { + } else { PacketUtils.translateNonDisplay(players, part, moveVector, (float) moveVector.length(), frame.duration, 0); } } - if (!packetAnimationPlayer){ + if (!packetAnimationPlayer) { SpawnedDisplayEntityPart sp = (SpawnedDisplayEntityPart) part; DisplayUtils.scaleInteraction((Interaction) sp.getEntity(), height, width, frame.duration, 0); - } - else{ - if (players == null){ + } else { + if (players == null) { DisplayAttributeMap map = new DisplayAttributeMap() .add(DisplayAttributes.Interaction.HEIGHT, height) .add(DisplayAttributes.Interaction.WIDTH, width); - if (part instanceof PacketDisplayEntityPart pp){ + if (part instanceof PacketDisplayEntityPart pp) { pp.setAttributesSilent(map); } - for (Player player : part.getTrackingPlayers()){ + for (Player player : part.getTrackingPlayers()) { boolean scaleInteractions = group.isPlayerInteractionScaleMultiplier(player); float scaleMultiplier = scaleInteractions ? group.getPlayerScaleMultiplier(player) : 1; - PacketUtils.scaleInteraction(player, part, height*scaleMultiplier, width*scaleMultiplier, frame.duration, 0); + PacketUtils.scaleInteraction(player, part, height * scaleMultiplier, width * scaleMultiplier, frame.duration, 0); } - } - else{ - for (Player player : players){ + } else { + for (Player player : players) { boolean scaleInteractions = group.isPlayerInteractionScaleMultiplier(player); float scaleMultiplier = scaleInteractions ? group.getPlayerScaleMultiplier(player) : 1; - PacketUtils.scaleInteraction(player, part, height*scaleMultiplier, width*scaleMultiplier, frame.duration, 0); + PacketUtils.scaleInteraction(player, part, height * scaleMultiplier, width * scaleMultiplier, frame.duration, 0); } } } } } - private void animateDisplays(Collection players, SpawnedDisplayAnimationFrame frame, ActiveGroup group, MultiPartSelection selection, SpawnedDisplayAnimation animation){ - if (!group.isActiveAnimator(animator)){ + private void animateDisplays(Collection players, SpawnedDisplayAnimationFrame frame, ActiveGroup group, MultiPartSelection selection, SpawnedDisplayAnimation animation) { + if (!group.isActiveAnimator(animator)) { return; } - if (selection.selectedParts.size() >= frame.displayTransformations.size()){ - for (Map.Entry entry : frame.displayTransformations.entrySet()){ + if (selection.selectedParts.size() >= frame.displayTransformations.size()) { + for (Map.Entry entry : frame.displayTransformations.entrySet()) { UUID partUUID = entry.getKey(); DisplayTransformation transformation = entry.getValue(); - if (transformation == null){ //Part does not change transformation + if (transformation == null) { //Part does not change transformation continue; } ActivePart part = group.getPart(partUUID); - if (part == null || !selection.contains(part)){ + if (part == null || !selection.contains(part)) { continue; } animateDisplay(players, part, transformation, group, animation, frame); } - } - else{ - for (ActivePart part : selection.selectedParts){ + } else { + for (ActivePart part : selection.selectedParts) { DisplayTransformation transformation = frame.displayTransformations.get(part.getPartUUID()); - if (transformation == null){ //Part does not change transformation + if (transformation == null) { //Part does not change transformation continue; } animateDisplay(players, part, transformation, group, animation, frame); @@ -293,14 +279,13 @@ private void animateDisplays(Collection players, SpawnedDisplayAnimation } } - private void animateDisplay(Collection players, ActivePart part, DisplayTransformation transformation, ActiveGroup group, SpawnedDisplayAnimation animation, SpawnedDisplayAnimationFrame frame){ + private void animateDisplay(Collection players, ActivePart part, DisplayTransformation transformation, ActiveGroup group, SpawnedDisplayAnimation animation, SpawnedDisplayAnimationFrame frame) { //Prevents jittering in some cases boolean applyDataOnly; - if (!packetAnimationPlayer){ + if (!packetAnimationPlayer) { applyDataOnly = transformation.isSimilar(part.getTransformation()); applyDisplayTransformation(part, frame, animation, group, transformation, applyDataOnly); - } - else{ + } else { DisplayTransformation last = prevFrame != null ? prevFrame.displayTransformations.get(part.getPartUUID()) : null; applyDataOnly = last != null && transformation.isSimilar(last); applyDisplayTransformationWithPackets(players, part, frame, animation, group, transformation, applyDataOnly); @@ -308,14 +293,12 @@ private void animateDisplay(Collection players, ActivePart part, Display } - - private void useScheduler(Runnable runnable, int delay){ - if (packetAnimationPlayer){ + private void useScheduler(Runnable runnable, int delay) { + if (packetAnimationPlayer) { DisplayAPI.getScheduler().partRunLaterAsync(group.getMasterPart(), () -> { runnable.run(); }, delay); - } - else{ + } else { DisplayAPI.getScheduler().partRunLater(group.getMasterPart(), () -> { runnable.run(); }, delay); @@ -323,114 +306,106 @@ private void useScheduler(Runnable runnable, int delay){ } - private void callAnimationLoopStart(Collection players, ActiveGroup group){ - if (packetAnimationPlayer){ + private void callAnimationLoopStart(Collection players, ActiveGroup group) { + if (packetAnimationPlayer) { new PacketAnimationLoopStartEvent(group, animator, players).callEvent(); - } - else{ + } else { new AnimationLoopStartEvent((SpawnedDisplayEntityGroup) group, animator).callEvent(); } } - private void callAnimationFrameStart(Collection players, ActiveGroup group, SpawnedDisplayAnimation animation, SpawnedDisplayAnimationFrame frame, int frameId){ - if (packetAnimationPlayer){ + private void callAnimationFrameStart(Collection players, ActiveGroup group, SpawnedDisplayAnimation animation, SpawnedDisplayAnimationFrame frame, int frameId) { + if (packetAnimationPlayer) { new PacketAnimationFrameStartEvent(group, animator, animation, frame, frameId, players).callEvent(); - } - else{ + } else { new AnimationFrameStartEvent((SpawnedDisplayEntityGroup) group, animator, animation, frameId, frame).callEvent(); } } - private void callAnimationSetFrame(Collection players, ActiveGroup group, SpawnedDisplayAnimation animation, SpawnedDisplayAnimationFrame frame){ - if (packetAnimationPlayer){ + private void callAnimationSetFrame(Collection players, ActiveGroup group, SpawnedDisplayAnimation animation, SpawnedDisplayAnimationFrame frame) { + if (packetAnimationPlayer) { new PacketAnimationSetFrameEvent(group, animator, animation, frame, players).callEvent(); - } - else{ + } else { new AnimationSetFrameEvent((SpawnedDisplayEntityGroup) group, animator, animation, frame).callEvent(); } } - private void callAnimationFrameEnd(Collection players, ActiveGroup group, SpawnedDisplayAnimation animation, SpawnedDisplayAnimationFrame frame, int frameId){ - if (packetAnimationPlayer){ + private void callAnimationFrameEnd(Collection players, ActiveGroup group, SpawnedDisplayAnimation animation, SpawnedDisplayAnimationFrame frame, int frameId) { + if (packetAnimationPlayer) { new PacketAnimationFrameEndEvent(group, animator, animation, frame, frameId, players).callEvent(); - } - else{ + } else { new AnimationFrameEndEvent((SpawnedDisplayEntityGroup) group, animator, animation, frameId, frame).callEvent(); } } - private void callAnimationComplete(Collection players, ActiveGroup group, SpawnedDisplayAnimation animation){ - if (packetAnimationPlayer){ + private void callAnimationComplete(Collection players, ActiveGroup group, SpawnedDisplayAnimation animation) { + if (packetAnimationPlayer) { new PacketAnimationCompleteEvent(group, animator, animation, players).callEvent(); - } - else{ + } else { new AnimationCompleteEvent((SpawnedDisplayEntityGroup) group, animator, animation).callEvent(); } } - private void applyDisplayTransformationWithPackets(Collection players, ActivePart part, SpawnedDisplayAnimationFrame frame, SpawnedDisplayAnimation animation, ActiveGroup group, DisplayTransformation transformation, boolean applyDataOnly){ - if (applyDataOnly){ - if (animation.allowsTextureChanges()){ - transformation.applyData(part); + private void applyDisplayTransformationWithPackets(Collection players, ActivePart part, SpawnedDisplayAnimationFrame frame, SpawnedDisplayAnimation animation, ActiveGroup group, DisplayTransformation transformation, boolean applyDataOnly) { + if (!applyDataOnly) { + DisplayAttributeMap map = new DisplayAttributeMap(); + + //Do this manually, since you have to send one large packet and don't want to send multiple + if (frame.duration > 0) { + map.add(DisplayAttributes.Interpolation.DELAY, 0); + } else { + map.add(DisplayAttributes.Interpolation.DELAY, -1); } - return; - } - DisplayAttributeMap map = new DisplayAttributeMap(); + map.add(DisplayAttributes.Interpolation.DURATION, frame.duration); - //Do this manually, since you have to send one large packet and don't want to send multiple - if (frame.duration > 0) { - map.add(DisplayAttributes.Interpolation.DELAY, 0); - } - else { - map.add(DisplayAttributes.Interpolation.DELAY, -1); - } - map.add(DisplayAttributes.Interpolation.DURATION, frame.duration); + Vector3f translationVector = new Vector3f(transformation.getTranslation()); - Vector3f translationVector = new Vector3f(transformation.getTranslation()); - if (group.isRiding()) translationVector.add(group.getRideOffset3f()); + if (group.isRiding()) translationVector.add(group.getRideOffset3f()); - float groupScaleMultiplier = group.getScaleMultiplier(); - if (animation.respectGroupScale){ - Vector3f scaleVector = new Vector3f(transformation.getScale()); - if (group.getScaleMultiplier() != 1){ - translationVector.mul(groupScaleMultiplier); - scaleVector.mul(groupScaleMultiplier); - } - addFollowerDisplayPivot(group, part, translationVector); + float groupScaleMultiplier = group.getScaleMultiplier(); - Transformation respectTransform = new DisplayTransformation(translationVector, transformation.getLeftRotation(), scaleVector, transformation.getRightRotation()); - map.addTransformation(respectTransform); - } - else{ - addFollowerDisplayPivot(group, part, translationVector); - Transformation offsetTransformation = new DisplayTransformation(translationVector, transformation.getLeftRotation(), transformation.getScale(), transformation.getRightRotation()); - map.addTransformation(offsetTransformation); - } + final DisplayTransformation finalTransformation; - if (!group.isActiveAnimator(animator)) return; + if (animation.respectGroupScale) { + Vector3f scaleVector = new Vector3f(transformation.getScale()); + if (group.getScaleMultiplier() != 1) { + translationVector.mul(groupScaleMultiplier); + scaleVector.mul(groupScaleMultiplier); + } + addFollowerDisplayPivot(group, part, translationVector); - int entityId = part.getEntityId(); - if (players == null){ - if (part instanceof PacketDisplayEntityPart ppart) { - ppart.setAttributesSilent(map); + finalTransformation = new DisplayTransformation(translationVector, transformation.getLeftRotation(), scaleVector, transformation.getRightRotation()); + } else { + addFollowerDisplayPivot(group, part, translationVector); + finalTransformation = new DisplayTransformation(translationVector, transformation.getLeftRotation(), transformation.getScale(), transformation.getRightRotation()); } - for (Player p : part.getTrackingPlayers()){ - sendDisplayAttributes(p, entityId, map, transformation); - } - } - else{ - for (Player p : players){ - sendDisplayAttributes(p, entityId, map, transformation); + map.addTransformation(finalTransformation); + + if (!group.isActiveAnimator(animator)) return; + + int entityId = part.getEntityId(); + if (players == null) { + if (part instanceof PacketDisplayEntityPart ppart) { + ppart.setAttributesSilent(map); + } + + for (Player p : part.getTrackingPlayers()) { + sendDisplayAttributes(p, entityId, map, finalTransformation); + } + } else { + for (Player p : players) { + sendDisplayAttributes(p, entityId, map, finalTransformation); + } } } - if (animation.allowsTextureChanges()){ + if (animation.allowsTextureChanges()) { transformation.applyData(part); } } - private void sendDisplayAttributes(Player player, int entityId, DisplayAttributeMap map, Transformation transformation){ + private void sendDisplayAttributes(Player player, int entityId, DisplayAttributeMap map, Transformation transformation) { float playerScaleMultiplier = group.getPlayerScaleMultiplier(player); new PacketAttributeContainer() @@ -442,12 +417,12 @@ private void sendDisplayAttributes(Player player, int entityId, DisplayAttribute .sendAttributes(player, entityId); } - private void applyDisplayTransformation(ActivePart part, SpawnedDisplayAnimationFrame frame, SpawnedDisplayAnimation animation, ActiveGroup group, DisplayTransformation transformation, boolean applyDataOnly){ + private void applyDisplayTransformation(ActivePart part, SpawnedDisplayAnimationFrame frame, SpawnedDisplayAnimation animation, ActiveGroup group, DisplayTransformation transformation, boolean applyDataOnly) { SpawnedDisplayEntityPart sp = (SpawnedDisplayEntityPart) part; Display display = (Display) sp.getEntity(); if (!display.isValid()) return; - if (applyDataOnly){ - if (animation.allowsTextureChanges()){ + if (applyDataOnly) { + if (animation.allowsTextureChanges()) { transformation.applyData(display); } return; @@ -455,19 +430,18 @@ private void applyDisplayTransformation(ActivePart part, SpawnedDisplayAnimation if (frame.duration > 0) { display.setInterpolationDelay(0); - } - else { + } else { display.setInterpolationDelay(-1); } display.setInterpolationDuration(frame.duration); Vector3f translationVector = new Vector3f(transformation.getTranslation()); - if (group.isRiding()){ + if (group.isRiding()) { translationVector.add(group.getRideOffset3f()); } - if (animation.respectGroupScale){ + if (animation.respectGroupScale) { Vector3f scaleVector = new Vector3f(transformation.getScale()); - if (group.getScaleMultiplier() != 1){ + if (group.getScaleMultiplier() != 1) { translationVector.mul(group.getScaleMultiplier()); scaleVector.mul(group.getScaleMultiplier()); } @@ -475,23 +449,22 @@ private void applyDisplayTransformation(ActivePart part, SpawnedDisplayAnimation Transformation respectTransform = new DisplayTransformation(translationVector, transformation.getLeftRotation(), scaleVector, transformation.getRightRotation()); display.setTransformation(respectTransform); - } - else{ + } else { addFollowerDisplayPivot(group, part, translationVector); Transformation offsetTransformation = new DisplayTransformation(translationVector, transformation.getLeftRotation(), transformation.getScale(), transformation.getRightRotation()); display.setTransformation(offsetTransformation); } - if (animation.allowsTextureChanges()){ + if (animation.allowsTextureChanges()) { transformation.applyData(display); } } - private void addFollowerDisplayPivot(ActiveGroup group, ActivePart part, Vector3f translationVector){ - synchronized (group.followerLock){ - for (GroupEntityFollower follower : group.followers){ - if (!follower.hasSetDisplayPivotData()){ + private void addFollowerDisplayPivot(ActiveGroup group, ActivePart part, Vector3f translationVector) { + synchronized (group.followerLock) { + for (GroupEntityFollower follower : group.followers) { + if (!follower.hasSetDisplayPivotData()) { continue; } follower.laterManualPivot(part, translationVector); From 2d728a86c40a7196299e4358051a8712575efdf1 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:21:30 -0500 Subject: [PATCH 10/55] no changes --- .../SpawnedDisplayEntityGroup.java | 16 ++++------------ .../machine/DisplayStateMachine.java | 12 ++++++++---- .../entity/mythic/DEUMythicListener.java | 4 +--- 3 files changed, 13 insertions(+), 19 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 b935a655..dd862fcf 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 @@ -696,11 +696,10 @@ public boolean translate(@NotNull Vector direction, float distance, int duration if (distance == 0) return true; Location destination = getMasterEntity().getLocation().clone().add(direction.clone().normalize().multiply(distance)); - GroupTranslateEvent event = new GroupTranslateEvent(this, GroupTranslateEvent.GroupTranslateType.VANILLATRANSLATE, destination); - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()){ + if (!new GroupTranslateEvent(this, GroupTranslateEvent.GroupTranslateType.VANILLATRANSLATE, destination).callEvent()){ return false; } + for (SpawnedDisplayEntityPart part : groupParts.values()){ part.translateForce(direction, distance, durationInTicks, delayInTicks); } @@ -802,16 +801,9 @@ public boolean isMasterPart(@NotNull Display display){ */ public boolean rideEntity(@NotNull Entity vehicle){ Entity masterEntity = getMasterEntity(); - GroupRideEntityEvent event = new GroupRideEntityEvent(this, vehicle); - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()){ - return false; - } + if (!new GroupRideEntityEvent(this, vehicle).callEvent()) return false; - boolean result = vehicle.addPassenger(masterEntity); - if (!result){ - return false; - } + if (!vehicle.addPassenger(masterEntity)) return false; if (!rideOffset.isZero()) { translate(rideOffset, -1, -1); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/machine/DisplayStateMachine.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/machine/DisplayStateMachine.java index b98b9638..32fdb56b 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/machine/DisplayStateMachine.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/machine/DisplayStateMachine.java @@ -63,16 +63,19 @@ public boolean addGroup(@NotNull SpawnedDisplayEntityGroup group){ if (!group.isSpawned()){ return false; } - DisplayStateMachine oldStateAnimator = groupMachines.get(group); - if (oldStateAnimator == this){ + + DisplayStateMachine oldStateMachine = groupMachines.get(group); + if (oldStateMachine == this){ return false; } - if (oldStateAnimator != null){ - oldStateAnimator.removeGroup(group); + + if (oldStateMachine != null){ + oldStateMachine.removeGroup(group); } group.unsetMachineState(); groupMachines.put(group, this); + DisplayAPI.getScheduler().partRunTimer(group.getMasterPart(), new Scheduler.SchedulerRunnable() { @Override public void run() { @@ -98,6 +101,7 @@ public boolean addGroup(@NotNull PacketDisplayEntityGroup group){ if (oldStateMachine == this){ return false; } + if (oldStateMachine != null){ oldStateMachine.removeGroup(group); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUMythicListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUMythicListener.java index 47233e4f..c7d43c10 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUMythicListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUMythicListener.java @@ -23,9 +23,7 @@ public void onMythicSpawn(MythicMobSpawnEvent e){ Entity entity = e.getEntity(); String mobID = e.getMobType().getInternalName(); DisplayController controller = DisplayControllerManager.getControllerOfMythicMob(mobID); - if (controller == null){ - return; - } + if (controller == null) return; boolean persist = e.getMob().getDespawnMode().getSavesToDisk(); String disg = e.getMobType().getConfig().getString("Disguise"); From 3208c4b988b465034a9281de75be2b5e526760a2 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:25:53 -0500 Subject: [PATCH 11/55] use spawn settings when creating a packet based display controller --- .../utils/controller/DisplayController.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 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 0c399d9b..958e917d 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 @@ -299,8 +299,10 @@ public static boolean isRegistered(String controllerID){ Location spawnLoc = entity.getLocation(); ActiveGroup activeGroup = isPacketBased ? - group.createPacketGroup(spawnLoc, GroupSpawnedEvent.SpawnReason.DISPLAY_CONTROLLER, true) - .setAutoShow(groupVisibleByDefault) + group.createPacketGroup(spawnLoc, GroupSpawnedEvent.SpawnReason.DISPLAY_CONTROLLER, + new GroupSpawnSettings().visibleByDefault(groupVisibleByDefault, null) + .playSpawnAnimation(true) + .persistentByDefault(false)) : group.spawn(spawnLoc, GroupSpawnedEvent.SpawnReason.DISPLAY_CONTROLLER, new GroupSpawnSettings() .persistentByDefault(persistGroup) @@ -339,6 +341,7 @@ public boolean apply(@NotNull Entity entity, @NotNull ActiveGroup activeGroup else{ isDisguised = false; } + if (isDisguised){ if (!activeGroup.rideEntity(entity)){ return false; From 8e046885165466bbed8fd83b7b8b8e293eb01f21 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:29:34 -0500 Subject: [PATCH 12/55] move relocations in plugin module --- plugin/pom.xml | 18 ++++++++++++++++++ pom.xml | 21 --------------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/plugin/pom.xml b/plugin/pom.xml index ec6a7872..c7004478 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -33,6 +33,24 @@ displayentityutils-${project.version} false + + + org.mongodb + net.donnypz.displayentityutils.mongodb + + + com.zaxxer + net.donnypz.displayentityutils.hikaricp + + + org.bstats + net.donnypz.displayentityutils.bstats + + + com.jeff_media.customblockdata + net.donnypz.displayentityutils.customblockdata + + diff --git a/pom.xml b/pom.xml index 8f10f076..e5cf519b 100644 --- a/pom.xml +++ b/pom.xml @@ -49,27 +49,6 @@ shade - - - - org.mongodb - net.donnypz.displayentityutils.mongodb - - - - com.zaxxer - net.donnypz.displayentityutils.hikaricp - - - org.bstats - net.donnypz.displayentityutils.bstats - - - com.jeff_media.customblockdata - net.donnypz.displayentityutils.customblockdata - - - From 40ab88bbe2774acc2f8593707cb19e0bc8612844 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:41:20 -0500 Subject: [PATCH 13/55] Include rideOffset in group autocull. autocull when group rides/dismounts entities --- .../utils/DisplayEntities/ActiveGroup.java | 16 ++++++++++++++++ .../DisplayEntities/DisplayEntityGroup.java | 8 ++------ .../PacketDisplayEntityGroup.java | 7 ++++--- .../SpawnedDisplayEntityGroup.java | 11 +++++------ .../command/group/GroupAutoCullCMD.java | 4 +--- 5 files changed, 28 insertions(+), 18 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 968ecadb..8938ce24 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 @@ -1,6 +1,7 @@ package net.donnypz.displayentityutils.utils.DisplayEntities; import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.DisplayConfig; import net.donnypz.displayentityutils.events.AnimationStateChangeEvent; import net.donnypz.displayentityutils.managers.DEUUser; import net.donnypz.displayentityutils.managers.DisplayAnimationManager; @@ -120,6 +121,21 @@ public boolean hasTag(){ */ public abstract @NotNull MultiPartSelection createPartSelection(@NotNull PartFilter partFilter); + /** + * Attempt to automatically set the culling bounds for all parts within this group, using config culling values. + * @param includeRideOffset whether the group's rideOffset should be included in calculation + */ + public void autoCull(boolean includeRideOffset){ + float widthAdder = DisplayConfig.widthCullingAdder(); + float heightAdder = DisplayConfig.heightCullingAdder(); + if (includeRideOffset){ + widthAdder += (float) Math.max(Math.abs(rideOffset.getX()), Math.abs(rideOffset.getZ())); + heightAdder += (float) Math.abs(rideOffset.getY()); + } + + autoCull(widthAdder, heightAdder); + } + /** * Attempt to automatically set the culling bounds for all parts within this group. * @param widthAdder The amount of width to be added to the culling range 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 cd24b3d7..5adc1f7c 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 @@ -214,9 +214,7 @@ public String getTag() { DisplayGroupManager.addSpawnedGroup(location, group); if (DisplayConfig.autoCulling()){ - float widthCullingAdder = DisplayConfig.widthCullingAdder(); - float heightCullingAdder = DisplayConfig.heightCullingAdder(); - group.autoCull(widthCullingAdder, heightCullingAdder); + group.autoCull(false); } new GroupSpawnedEvent(group, spawnReason).callEvent(); @@ -303,9 +301,7 @@ public String getTag() { if (DisplayConfig.autoCulling()){ - float widthCullingAdder = DisplayConfig.widthCullingAdder(); - float heightCullingAdder = DisplayConfig.heightCullingAdder(); - packetGroup.autoCull(widthCullingAdder, heightCullingAdder); + packetGroup.autoCull(false); } if (spawnReason == GroupSpawnedEvent.SpawnReason.CHUNK_LOAD_PLACED || spawnReason == GroupSpawnedEvent.SpawnReason.ITEMSTACK){ 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 70e2bc66..cc5ded03 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 @@ -63,9 +63,7 @@ public PacketDisplayEntityGroup(@NotNull BDEModel model, @NotNull Location spawn if (DisplayConfig.autoCulling()){ - float widthCullingAdder = DisplayConfig.widthCullingAdder(); - float heightCullingAdder = DisplayConfig.heightCullingAdder(); - this.autoCull(widthCullingAdder, heightCullingAdder); + this.autoCull(false); } } @@ -437,6 +435,8 @@ public boolean rideEntity(@NotNull Entity vehicle, boolean runLocationUpdater){ translate(rideOffset, -1, -1); } + this.autoCull(true); + if (runLocationUpdater){ final UUID finalUUID = vehicle.getUniqueId(); DisplayAPI.getScheduler().entityRunTimer(vehicle, new Scheduler.SchedulerRunnable() { @@ -496,6 +496,7 @@ private void removeAsPassenger(UUID entityUUID){ translate(rideOffset.clone().multiply(-1), -1, -1); } } + this.autoCull(false); return vehicle; } 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 dd862fcf..33452773 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 @@ -90,9 +90,7 @@ public SpawnedDisplayEntityGroup(@NotNull Display masterDisplay){ DisplayGroupManager.addSpawnedGroup(masterDisplay.getLocation(), this); if (DisplayConfig.autoCulling()){ - float widthCullingAdder = DisplayConfig.widthCullingAdder(); - float heightCullingAdder = DisplayConfig.heightCullingAdder(); - autoCull(widthCullingAdder, heightCullingAdder); + this.autoCull(false); } } @@ -809,6 +807,8 @@ public boolean rideEntity(@NotNull Entity vehicle){ translate(rideOffset, -1, -1); } + this.autoCull(true); + updatePosition(vehicle); for (SpawnedDisplayEntityPart part : groupParts.values()){ if (part.isDisplay()) continue; @@ -877,6 +877,7 @@ public void run() { translate(rideOffset.clone().multiply(-1), -1, -1); } } + this.autoCull(false); } return vehicle; } @@ -1002,9 +1003,7 @@ public SpawnedDisplayEntityGroup merge(@NotNull SpawnedDisplayEntityGroup mergin mergingGroup.unregister(false, false); if (DisplayConfig.autoCulling()){ - float widthCullingAdder = DisplayConfig.widthCullingAdder(); - float heightCullingAdder = DisplayConfig.heightCullingAdder(); - autoCull(widthCullingAdder, heightCullingAdder); + this.autoCull(true); } for (SpawnedPartSelection sel : partSelections){ sel.refresh(); 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 00b6aec5..1eff7c6d 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 @@ -1,9 +1,7 @@ package net.donnypz.displayentityutils.command.group; import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.DisplayConfig; import net.donnypz.displayentityutils.command.*; -import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -21,6 +19,6 @@ 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("Added culling bounds to your selected group!", NamedTextColor.GREEN))); - group.autoCull(DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); + group.autoCull(true); } } From bab8ed476ce03246e51956a6446a8dcf147a8c32 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:46:32 -0500 Subject: [PATCH 14/55] 3.5.2-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 c9d4031c..c0df9163 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE + 3.5.2-PRE-1 api diff --git a/plugin/pom.xml b/plugin/pom.xml index c7004478..c49cbb59 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE + 3.5.2-PRE-1 plugin diff --git a/pom.xml b/pom.xml index e5cf519b..401814e5 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE + 3.5.2-PRE-1 pom DisplayEntityUtils From ca31c6d598ab269fcef4ba52bc29a848373f3fbc Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 30 Apr 2026 04:16:24 -0500 Subject: [PATCH 15/55] Don't attempt to respect entity if finalFollowType is null --- .../utils/DisplayEntities/GroupEntityFollower.java | 2 ++ 1 file changed, 2 insertions(+) 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 33f89ab0..51f987ec 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 @@ -119,6 +119,8 @@ else if (group instanceof PacketDisplayEntityGroup pg){ finalFollowType = group.defaultFollower.properties.followType(); } + if (finalFollowType == null) return; + if (group.defaultFollower != null && !isDefaultFollower){ //Stop part follow if default follower can't follow if (!group.defaultFollower.properties.shouldPropertiesApply(group)){ return; From 4c048f5cb5ed71af13abbcc825e7865b985b2628 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 30 Apr 2026 04:19:30 -0500 Subject: [PATCH 16/55] add "/deu group ridedespawn" --- .../command/group/GroupCMD.java | 2 + .../command/group/GroupRideCMD.java | 2 +- .../command/group/GroupRideDespawnCMD.java | 131 ++++++++++++++++++ 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupRideDespawnCMD.java 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 c6761a83..4c54b0e2 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 @@ -55,6 +55,7 @@ public GroupCMD(){ new GroupBillboardCMD(this); new GroupViewRangeCMD(this); new GroupRideCMD(this); + new GroupRideDespawnCMD(this); new GroupSafeDismountCMD(this); new GroupDismountCMD(this); new GroupWorldEditCMD(this); @@ -131,6 +132,7 @@ else if (page == 5){ 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 ridedespawn <-target | player-name | entity-uuid> [group-tag] [storage] [controller-id]", "Make a group ride an entity, despawning the group after the ridden entity despawns/disconnects. The group will not be persistent. Values in brackets [] are optional"); } else if (page == 6){ CMDUtils.sendCMD(sender, "/deu group safedismount <-target | -selected | player-name | entity-uuid>", "Safely dismount a group from an entity"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupRideCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupRideCMD.java index b398cb73..2028c4c7 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupRideCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupRideCMD.java @@ -126,7 +126,7 @@ private void attemptRide(Entity vehicle, ActiveGroup group, CommandSender sen } } - private void sendFail(CommandSender sender){ + static void sendFail(CommandSender sender){ sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to mount your group on the entity!", NamedTextColor.RED))); sender.sendMessage(Component.text("| If the group is both persistent and packet-based, this will always fail", NamedTextColor.GRAY, TextDecoration.ITALIC)); sender.sendMessage(Component.text("| This can fail for other unknown reasons, or if the riding was cancelled by another plugin", NamedTextColor.GRAY, TextDecoration.ITALIC)); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupRideDespawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupRideDespawnCMD.java new file mode 100644 index 00000000..920e0870 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupRideDespawnCMD.java @@ -0,0 +1,131 @@ +package net.donnypz.displayentityutils.command.group; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.ConsoleUsableSubCommand; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.events.GroupSpawnedEvent; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; +import net.donnypz.displayentityutils.managers.LoadMethod; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; +import net.donnypz.displayentityutils.utils.controller.DisplayController; +import net.donnypz.displayentityutils.utils.controller.GroupFollowProperties; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +class GroupRideDespawnCMD extends ConsoleUsableSubCommand { + GroupRideDespawnCMD(@NotNull DEUSubCommand parentSubCommand) { + super("ridedespawn", parentSubCommand, Permission.GROUP_RIDE); + setTabComplete(2, List.of("-target", "player-name | entity-uuid")); + setTabComplete(3, "[group-tag]"); + setTabComplete(4, "[storage]"); + setTabComplete(5, "[controller-id]"); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length == 2) { + sender.sendMessage(Component.text("Incorrect Usage! /deu group ridedespawn <-target | player-name | entity-uuid> [group-tag] [storage] [controller-id]", NamedTextColor.RED)); + return; + } + + Entity vehicle = GroupRideCMD.getVehicle(sender, args[2]); + if (vehicle == null) { + return; + } + + + //Use Selected Group + if (args.length < 5) { + if (!(sender instanceof Player player)) { + sender.sendMessage(Component.text("Incorrect Console Usage! /deu group ridedespawn <-target | player-name | entity-uuid> [group-tag] [storage] [controller-id]", NamedTextColor.RED)); + return; + } + + ActiveGroup group = DisplayGroupManager.getSelectedGroup(player); + if (group == null) { + DisplayEntityPluginCommand.noGroupSelection(player); + player.sendMessage(Component.text("Provide a group tag and storage location if you want to spawn a new group instead.", NamedTextColor.GRAY, TextDecoration.ITALIC)); + return; + } + + attemptRide(vehicle, group, sender, args.length == 4 ? args[3] : null); + return; + } + + + //Spawn A New Group + LoadMethod loadMethod; + try { + loadMethod = LoadMethod.valueOf(args[4].toUpperCase()); + } catch (IllegalArgumentException e) { + sender.sendMessage(Component.text("Invalid Storage Method!", NamedTextColor.RED)); + sender.sendMessage(Component.text("Valid storage methods are local, mongodb, or mysql", NamedTextColor.GRAY)); + return; + } + + DisplayEntityGroup savedGroup = DisplayGroupManager.getGroup(loadMethod, args[3]); + if (savedGroup == null) { + sender.sendMessage(Component.text("Failed to find group in " + loadMethod.getDisplayName() + " storage", NamedTextColor.RED)); + return; + } + + Location spawnLoc = vehicle.getLocation(); + spawnLoc.setPitch(0); + SpawnedDisplayEntityGroup group = savedGroup.spawn(spawnLoc, GroupSpawnedEvent.SpawnReason.COMMAND); + if (group == null) { + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to spawn the group! It was cancelled by another plugin!", NamedTextColor.RED))); + return; + } + + attemptRide(vehicle, group, sender, args.length == 6 ? args[5] : null); + } + + private void attemptRide(Entity vehicle, ActiveGroup group, CommandSender sender, String controllerID) { + if (group.getVehicle() == vehicle) { + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("That group is already riding that entity!", NamedTextColor.RED))); + return; + } + + group.setPersistent(false); + + //Apply Controller + if (controllerID != null) { + DisplayController controller = DisplayController.getController(controllerID); + if (controller == null) { + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to find a controller with the specified ID! (" + controllerID + ")", NamedTextColor.RED))); + return; + } + + if (controller.apply(vehicle, group)) { + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Mounting your group on the entity with a controller! (" + controllerID + ")", NamedTextColor.GREEN))); + } else { + GroupRideCMD.sendFail(sender); + } + } else { + if (group.rideEntity(vehicle)) { + group.stopFollowingEntity(); + group.followEntityDirection(vehicle, new GroupFollowProperties("cmd", + null, + 0, + false, + false + )); + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Mounted your group on the entity!", NamedTextColor.GREEN))); + } else { + GroupRideCMD.sendFail(sender); + } + } + } +} From 7c7bd43f14e58eae4d4ac3782640ef8bf34cb179 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Thu, 30 Apr 2026 04:23:11 -0500 Subject: [PATCH 17/55] 3.5.2-PRE-2 --- 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 c0df9163..d71378fd 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-1 + 3.5.2-PRE-2 api diff --git a/plugin/pom.xml b/plugin/pom.xml index c49cbb59..04895bad 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-1 + 3.5.2-PRE-2 plugin diff --git a/pom.xml b/pom.xml index 401814e5..5274e559 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-1 + 3.5.2-PRE-2 pom DisplayEntityUtils From a75363147c4f56f8131bd22269034c7d9028d8bf Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 2 May 2026 15:43:52 -0500 Subject: [PATCH 18/55] remove usage of javax.annotation.Nullable --- .../net/donnypz/displayentityutils/managers/MYSQLManager.java | 2 +- .../net/donnypz/displayentityutils/managers/MongoManager.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MYSQLManager.java b/plugin/src/main/java/net/donnypz/displayentityutils/managers/MYSQLManager.java index fc22f0b2..a24287bc 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MYSQLManager.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/managers/MYSQLManager.java @@ -14,8 +14,8 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MongoManager.java b/plugin/src/main/java/net/donnypz/displayentityutils/managers/MongoManager.java index c9034d2a..0452bb2a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MongoManager.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/managers/MongoManager.java @@ -20,8 +20,8 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; From a96eddc0cdc670d8dbfb300363e51ceddb9f0620 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 2 May 2026 16:09:04 -0500 Subject: [PATCH 19/55] Support 26.1.2 & Skript 2.15.2 --- api/pom.xml | 2 +- plugin/pom.xml | 4 ++-- pom.xml | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index d71378fd..44c8a651 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ io.papermc.paper paper-api - 1.21.10-R0.1-SNAPSHOT + 26.1.2.build.53-stable provided diff --git a/plugin/pom.xml b/plugin/pom.xml index 04895bad..3ac660ec 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -74,7 +74,7 @@ io.papermc.paper paper-api - 1.21.10-R0.1-SNAPSHOT + 26.1.2.build.53-stable provided @@ -106,7 +106,7 @@ com.github.SkriptLang Skript - 2.14.3 + 2.15.2 provided diff --git a/pom.xml b/pom.xml index 5274e559..58769c39 100644 --- a/pom.xml +++ b/pom.xml @@ -93,6 +93,10 @@ + + papermc-repo + https://repo.papermc.io/repository/maven-public/ + sk89q-repo https://maven.enginehub.org/repo/ From c87075082f933b130be28c222e67ea966aa6f6bf Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 2 May 2026 16:09:19 -0500 Subject: [PATCH 20/55] Update PacketEvents to 2.12.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 58769c39..b4e8b62e 100644 --- a/pom.xml +++ b/pom.xml @@ -151,7 +151,7 @@ com.github.retrooper packetevents-spigot - 2.11.2 + 2.12.1 provided From 9e532b494c5e6308045bbf076df381df7848e30c Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 2 May 2026 16:58:55 -0500 Subject: [PATCH 21/55] Allow part's corresponding type to be used in syntax --- .../conditions/CondTextDisplayIsShadowed.java | 18 ++++-- .../conditions/CondTextDisplaySeeThrough.java | 19 +++--- .../effects/EffInteractionResponsive.java | 24 ++++--- .../effects/EffTextDisplaySeeThrough.java | 23 ++++--- .../parts/effects/EffTextDisplayShadow.java | 22 ++++--- .../expressions/ExprTextDisplayLineWidth.java | 19 ++++-- .../expressions/ExprTextDisplayOpacity.java | 40 ++++++++---- .../expressions/ExprTextDisplayText.java | 64 ++++++++++--------- 8 files changed, 141 insertions(+), 88 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/conditions/CondTextDisplayIsShadowed.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/conditions/CondTextDisplayIsShadowed.java index d78e5dda..466f86e1 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/conditions/CondTextDisplayIsShadowed.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/conditions/CondTextDisplayIsShadowed.java @@ -9,6 +9,7 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import org.bukkit.entity.TextDisplay; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.registration.SyntaxInfo; @@ -18,15 +19,15 @@ @Description("Check if an text display part's text has shadows") @Examples({"if {_activepart} has deu text shadows:", "\tbroadcast \"This text display part has text shadow!\""}) -@Since("3.5.0") +@Since("3.5.0, 3.5.2 (Text Displays Entities)") public class CondTextDisplayIsShadowed extends Condition { - Expression partExpr; + Expression partExpr; public static void register(SyntaxRegistry registry){ registry.register(SyntaxRegistry.CONDITION, SyntaxInfo.builder(CondTextDisplayIsShadowed.class) - .addPattern("%activepart% (1¦(is|has)|2¦is(n't| not)) deu [text] [drop] shadow[ed|s]") + .addPattern("%activepart/displays% (1¦(is|has)|2¦is(n't| not)) deu [text] [drop] shadow[ed|s]") .supplier(CondTextDisplayIsShadowed::new) .build() ); @@ -34,9 +35,12 @@ public static void register(SyntaxRegistry registry){ @Override public boolean check(Event event) { - ActivePart part = partExpr.getSingle(event); - if (part != null){ - return part.isTextDisplayShadowed(); + Object obj = partExpr.getSingle(event); + if (obj instanceof ActivePart p){ + return p.isTextDisplayShadowed(); + } + else if (obj instanceof TextDisplay td){ + return td.isShadowed(); } return isNegated(); } @@ -49,7 +53,7 @@ public String toString(@Nullable Event event, boolean debug) { @SuppressWarnings("unchecked") @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - this.partExpr = (Expression) expressions[0]; + this.partExpr = expressions[0]; setNegated(parseResult.mark == 2); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/conditions/CondTextDisplaySeeThrough.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/conditions/CondTextDisplaySeeThrough.java index 69651673..99185ed5 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/conditions/CondTextDisplaySeeThrough.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/conditions/CondTextDisplaySeeThrough.java @@ -9,6 +9,7 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import org.bukkit.entity.TextDisplay; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.registration.SyntaxInfo; @@ -18,15 +19,15 @@ @Description("Check if an text display part is visible through blocks") @Examples({"if {_activepart} is deu visible through blocks:", "\tbroadcast \"This text display part is visible through walls!\""}) -@Since("3.5.0") +@Since("3.5.0, 3.5.2 (Text Displays Entities)") public class CondTextDisplaySeeThrough extends Condition { - Expression partExpr; + Expression partExpr; public static void register(SyntaxRegistry registry){ registry.register(SyntaxRegistry.CONDITION, SyntaxInfo.builder(CondTextDisplaySeeThrough.class) - .addPattern("%activepart% (1¦is|2¦is(n't| not)) deu visible through (blocks|walls)") + .addPattern("%activepart/displays% (1¦is|2¦is(n't| not)) deu visible through (blocks|walls)") .supplier(CondTextDisplaySeeThrough::new) .build() ); @@ -34,9 +35,12 @@ public static void register(SyntaxRegistry registry){ @Override public boolean check(Event event) { - ActivePart part = partExpr.getSingle(event); - if (part != null){ - return part.isTextDisplaySeeThrough(); + Object obj = partExpr.getSingle(event); + if (obj instanceof ActivePart p){ + return p.isTextDisplaySeeThrough(); + } + else if (obj instanceof TextDisplay td){ + return td.isSeeThrough(); } return isNegated(); } @@ -46,10 +50,9 @@ public String toString(@Nullable Event event, boolean debug) { return "text display part visible through blocks: "+ partExpr.toString(event, debug); } - @SuppressWarnings("unchecked") @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - this.partExpr = (Expression) expressions[0]; + this.partExpr = expressions[0]; setNegated(parseResult.mark == 2); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffInteractionResponsive.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffInteractionResponsive.java index e3e0370b..c25ea671 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffInteractionResponsive.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffInteractionResponsive.java @@ -9,6 +9,7 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import org.bukkit.entity.Interaction; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.registration.SyntaxInfo; @@ -19,17 +20,17 @@ @Examples({ "deu make {_activepart} responsive", "deu stop {_activepart} from being responsive"}) -@Since("3.5.0") +@Since("3.5.0, 3.5.2 (Interaction Entities)") public class EffInteractionResponsive extends Effect { - Expression partExpr; + Expression partExpr; boolean negate; public static void register(SyntaxRegistry registry){ registry.register(SyntaxRegistry.EFFECT, SyntaxInfo.builder(EffInteractionResponsive.class) .addPattern("deu make %activeparts% [interaction] responsive") - .addPattern("deu (stop|prevent|block) %activeparts% from being [interaction] responsive") + .addPattern("deu (stop|prevent|block) %activeparts/entities% from being [interaction] responsive") .supplier(EffInteractionResponsive::new) .build() ); @@ -37,20 +38,25 @@ public static void register(SyntaxRegistry registry){ @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - partExpr = (Expression) expressions[0]; + partExpr = expressions[0]; negate = matchedPattern == 1; return true; } @Override protected void execute(Event event) { - ActivePart[] parts = partExpr.getArray(event); + Object[] parts = partExpr.getArray(event); if (parts == null){ return; } - for (ActivePart part : parts){ - part.setInteractionResponsive(!negate); + for (Object obj : parts){ + if (obj instanceof ActivePart part){ + part.setInteractionResponsive(!negate); + } + else if (obj instanceof Interaction i){ + i.setResponsive(!negate); + } } } @@ -58,7 +64,7 @@ protected void execute(Event event) { @Override public String toString(@Nullable Event event, boolean debug) { if (!negate) - return "deu force " + partExpr.toString(event, debug) + " to be visible through blocks"; - return "deu prevent " + partExpr.toString(event, debug) + " from being visible through blocks"; + return "deu force " + partExpr.toString(event, debug) + " to be responsive"; + return "deu prevent " + partExpr.toString(event, debug) + " from being responsive"; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffTextDisplaySeeThrough.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffTextDisplaySeeThrough.java index c1ab5749..7133b182 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffTextDisplaySeeThrough.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffTextDisplaySeeThrough.java @@ -9,6 +9,7 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import org.bukkit.entity.TextDisplay; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.registration.SyntaxInfo; @@ -19,17 +20,17 @@ @Examples({ "deu make {_activepart} visible through blocks", "deu stop {_activepart} from being seen through walls"}) -@Since("3.5.0") +@Since("3.5.0, 3.5.2 (Text Displays Entities)") public class EffTextDisplaySeeThrough extends Effect { - Expression partExpr; + Expression partExpr; boolean hide; public static void register(SyntaxRegistry registry){ registry.register(SyntaxRegistry.EFFECT, SyntaxInfo.builder(EffTextDisplaySeeThrough.class) - .addPattern("deu make %activeparts% visible through (blocks|walls)") - .addPattern("deu (stop|prevent|block) %activeparts% from being (visible|seen) through (blocks|walls)") + .addPattern("deu make %activeparts/displays% visible through (blocks|walls)") + .addPattern("deu (stop|prevent|block) %activeparts/displays% from being (visible|seen) through (blocks|walls)") .supplier(EffTextDisplaySeeThrough::new) .build() ); @@ -37,22 +38,26 @@ public static void register(SyntaxRegistry registry){ @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - partExpr = (Expression) expressions[0]; + partExpr = expressions[0]; hide = matchedPattern == 1; return true; } @Override protected void execute(Event event) { - ActivePart[] parts = partExpr.getArray(event); + Object[] parts = partExpr.getArray(event); if (parts == null){ return; } - for (ActivePart part : parts){ - part.setTextDisplaySeeThrough(!hide); + for (Object o : parts){ + if (o instanceof ActivePart p){ + p.setTextDisplaySeeThrough(!hide); + } + else if (o instanceof TextDisplay td){ + td.setSeeThrough(!hide); + } } - } @Override diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffTextDisplayShadow.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffTextDisplayShadow.java index f4eac696..cb473dce 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffTextDisplayShadow.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/effects/EffTextDisplayShadow.java @@ -9,6 +9,7 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import org.bukkit.entity.TextDisplay; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.registration.SyntaxInfo; @@ -19,17 +20,17 @@ @Examples({ "deu add text shadow to {_activepart}'s text", "deu remove text shadow from {_activepart}'s text"}) -@Since("3.5.0") +@Since({"3.5.0, 3.5.2 (Text Displays Entities)"}) public class EffTextDisplayShadow extends Effect { - Expression partExpr; + Expression partExpr; boolean remove; public static void register(SyntaxRegistry registry){ registry.register(SyntaxRegistry.EFFECT, SyntaxInfo.builder(EffTextDisplayShadow.class) - .addPattern("deu (apply|add) (drop|text) shadow to %activeparts%['s] text") - .addPattern("deu (remove|clear) (drop|text) shadow from %activeparts%['s] text") + .addPattern("deu (apply|add) (drop|text) shadow to %activeparts/displays%['s] text") + .addPattern("deu (remove|clear) (drop|text) shadow from %activeparts/displays%['s] text") .supplier(EffTextDisplayShadow::new) .build() ); @@ -37,20 +38,25 @@ public static void register(SyntaxRegistry registry){ @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - partExpr = (Expression) expressions[0]; + partExpr = expressions[0]; remove = matchedPattern == 1; return true; } @Override protected void execute(Event event) { - ActivePart[] parts = partExpr.getArray(event); + Object[] parts = partExpr.getArray(event); if (parts == null){ return; } - for (ActivePart part : parts){ - part.setTextDisplayShadowed(!remove); + for (Object obj : parts){ + if (obj instanceof ActivePart part){ + part.setTextDisplayShadowed(!remove); + } + else if (obj instanceof TextDisplay td){ + td.setShadowed(!remove); + } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayLineWidth.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayLineWidth.java index 0ce214f3..c8101c53 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayLineWidth.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayLineWidth.java @@ -22,13 +22,13 @@ @Examples({"if {_activepart}'s part type is text_display:", "\tset {_activepart}'s deu text line width to 50" }) -@Since("3.5.0") -public class ExprTextDisplayLineWidth extends SimplePropertyExpression { +@Since("3.5.0, 3.5.2 (Text Displays Entities)") +public class ExprTextDisplayLineWidth extends SimplePropertyExpression { public static void register(SyntaxRegistry registry){ registry.register(SyntaxRegistry.EXPRESSION, SyntaxInfo.Expression.builder(ExprTextDisplayLineWidth.class, Number.class) - .addPatterns(getPatterns("deu text [display] line width", "activeparts")) + .addPatterns(getPatterns("deu text [display] line width", "activeparts/displays")) .supplier(ExprTextDisplayLineWidth::new) .build() ); @@ -47,8 +47,14 @@ public Class getReturnType() { @Override @Nullable - public Number convert(ActivePart part) { - return part.getTextDisplayLineWidth(); + public Number convert(Object obj) { + if (obj instanceof ActivePart part){ + return part.getTextDisplayLineWidth(); + } + else if (obj instanceof TextDisplay td){ + return td.getLineWidth(); + } + return null; } @Override @@ -71,6 +77,9 @@ public void change(Event event, Object[] delta, Changer.ChangeMode mode){ if (o instanceof ActivePart part) { part.setTextDisplayLineWidth(width); } + else if (o instanceof TextDisplay td){ + td.setLineWidth(width); + } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayOpacity.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayOpacity.java index bd208d95..091d0efe 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayOpacity.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayOpacity.java @@ -22,13 +22,13 @@ @Examples({"if {_activepart}'s part type is text_display:", "\tset {_activepart}'s deu opacity to 105" }) -@Since("3.5.0") -public class ExprTextDisplayOpacity extends SimplePropertyExpression { +@Since("3.5.0, 3.5.2 (Text Displays Entities)") +public class ExprTextDisplayOpacity extends SimplePropertyExpression { public static void register(SyntaxRegistry registry){ registry.register(SyntaxRegistry.EXPRESSION, SyntaxInfo.Expression.builder(ExprTextDisplayOpacity.class, Number.class) - .addPatterns(getPatterns("deu [text] [display] opacity", "activeparts")) + .addPatterns(getPatterns("deu [text] [display] opacity", "activeparts/displays")) .supplier(ExprTextDisplayOpacity::new) .build() ); @@ -47,8 +47,14 @@ public Class getReturnType() { @Override @Nullable - public Number convert(ActivePart part) { - return part.getTextDisplayTextOpacity(); + public Number convert(Object obj) { + if (obj instanceof ActivePart part){ + return part.getTextDisplayTextOpacity(); + } + else if (obj instanceof TextDisplay td){ + return td.getTextOpacity(); + } + return null; } @Override @@ -72,7 +78,7 @@ public Class[] acceptChange(final Changer.ChangeMode mode) { @Override public void change(Event event, Object[] delta, Changer.ChangeMode mode) { - ActivePart[] parts = getExpr().getArray(event); + Object[] parts = getExpr().getArray(event); int change = delta == null ? 255 : ((Number) delta[0]).intValue(); switch (mode) { case REMOVE_ALL: @@ -80,23 +86,33 @@ public void change(Event event, Object[] delta, Changer.ChangeMode mode) { change = -change; //$FALL-THROUGH$ case ADD: - for (ActivePart part : parts) { - byte value = convertToSigned(Math.clamp(convertToUnsigned(part.getTextDisplayTextOpacity()) + change, 0, 255)); - part.setTextDisplayTextOpacity(value); + for (Object obj : parts) { + if (obj instanceof ActivePart part){ + byte value = convertToSigned(Math.clamp(convertToUnsigned(part.getTextDisplayTextOpacity()) + change, 0, 255)); + part.setTextDisplayTextOpacity(value); + } + else if (obj instanceof TextDisplay td){ + byte value = convertToSigned(Math.clamp(convertToUnsigned(td.getTextOpacity()) + change, 0, 255)); + td.setTextOpacity(value); + } } break; case DELETE: case RESET: case SET: change = convertToSigned(Math.clamp(change, -128, 255)); - for (ActivePart active : parts) { - active.setTextDisplayTextOpacity((byte) change); + for (Object obj : parts) { + if (obj instanceof ActivePart part){ + part.setTextDisplayTextOpacity((byte) change); + } + else if (obj instanceof TextDisplay td){ + td.setTextOpacity((byte) change); + } } break; } } - //------From Skript's ExprTextDisplayOpacity------ private static int convertToUnsigned(byte value) { return value < 0 ? 256 + value : value; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayText.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayText.java index c8ab5fe1..4ac9eff0 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayText.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprTextDisplayText.java @@ -8,15 +8,11 @@ import ch.njol.skript.expressions.base.SimplePropertyExpression; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; -import ch.njol.skript.util.Utils; -import ch.njol.skript.util.chat.BungeeConverter; -import ch.njol.skript.util.chat.ChatMessages; import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.entity.TextDisplay; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.registration.SyntaxInfo; @@ -30,15 +26,13 @@ "if {_activepart}'s part type is text_display:", "\tset {_activepart}'s deu text to \"&aMy New Text\"" }) -@Since("3.5.0") -public class ExprTextDisplayText extends SimplePropertyExpression { - - private static final BungeeComponentSerializer SERIALIZER = BungeeComponentSerializer.get(); +@Since("3.5.0, 3.5.2 (Text Displays Entities)") +public class ExprTextDisplayText extends SimplePropertyExpression { public static void register(SyntaxRegistry registry){ registry.register(SyntaxRegistry.EXPRESSION, - SyntaxInfo.Expression.builder(ExprTextDisplayText.class, String.class) - .addPatterns(getPatterns("deu text [display] [text]", "activeparts")) + SyntaxInfo.Expression.builder(ExprTextDisplayText.class, Component.class) + .addPatterns(getPatterns("deu text [display] [text]", "activeparts/displays")) .supplier(ExprTextDisplayText::new) .build() ); @@ -51,15 +45,20 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is } @Override - public Class getReturnType() { - return String.class; + public Class getReturnType() { + return Component.class; } @Override @Nullable - public String convert(ActivePart part) { - Component comp = part.getTextDisplayText(); - return comp != null ? Utils.replaceChatStyles(LegacyComponentSerializer.legacySection().serialize(comp)) : null; + public Component convert(Object obj) { + if (obj instanceof TextDisplay td){ + return td.text(); + } + else if (obj instanceof ActivePart p){ + return p.getTextDisplayText(); + } + return null; } @Override @@ -74,29 +73,34 @@ public boolean isSingle() { @Override public void change(Event event, Object[] delta, Changer.ChangeMode mode){ - String value = delta == null ? null : String.join("\n", Arrays.copyOf(delta, delta.length, String[].class)); - final Component finalComp; - if (SERIALIZER != null && value != null) { - finalComp = SERIALIZER.deserialize(BungeeConverter.convert(ChatMessages.parseToArray(value))); - } - else{ - finalComp = null; - } - if (finalComp == null) return; + Component component = delta == null ? Component.empty() : joinByNewLine(Arrays.copyOf(delta, delta.length, Component[].class)); for (Object object : getExpr().getArray(event)) { if (object instanceof ActivePart ap){ - ap.setTextDisplayText(finalComp); + ap.setTextDisplayText(component); + } + else if (object instanceof TextDisplay td){ + td.text(component); } } } @Override public Class[] acceptChange(final Changer.ChangeMode mode) { - if (mode == Changer.ChangeMode.RESET) return CollectionUtils.array(); - if (mode == Changer.ChangeMode.SET) { - return CollectionUtils.array(String[].class); + return switch (mode) { + case RESET -> CollectionUtils.array(); + case SET -> CollectionUtils.array(Component[].class); + default -> null; + }; + } + + //from Skript's TextComponentUtils + private Component joinByNewLine(Component... components) { + // we want formatting from the first to apply to the next, so append this way + Component combined = components[0]; + for (int i = 1; i < components.length; i++) { + combined = combined.appendNewline().append(components[i]); } - return null; + return combined.compact(); } } From 827e08a8ecea451357543c47953c08fdbec6b919 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 2 May 2026 16:59:23 -0500 Subject: [PATCH 22/55] require "deu" in entity id syntax --- .../skript/parts/expressions/ExprActivePartEntityId.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprActivePartEntityId.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprActivePartEntityId.java index eaee50c2..02468827 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprActivePartEntityId.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/parts/expressions/ExprActivePartEntityId.java @@ -5,7 +5,6 @@ import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; -import net.donnypz.displayentityutils.skript.parts.effects.EffActivePartTag; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.registration.SyntaxInfo; @@ -21,7 +20,7 @@ public class ExprActivePartEntityId extends SimplePropertyExpression Date: Sat, 2 May 2026 18:05:57 -0500 Subject: [PATCH 23/55] correctly unregister group vehicle when invalid. --- .../PacketDisplayEntityGroup.java | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 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 cc5ded03..bbea059f 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 @@ -35,7 +35,7 @@ public class PacketDisplayEntityGroup extends ActiveGroup allPacketGroups = new ConcurrentHashMap<>(); private static final ConcurrentHashMap groupVehicles = new ConcurrentHashMap<>(); int[] passengerIds; - UUID vehicleUUID; + volatile UUID vehicleUUID; boolean autoShow; Predicate autoShowCondition; int persistentLocalId = -1; @@ -420,6 +420,7 @@ public boolean rideEntity(@NotNull Entity vehicle, boolean runLocationUpdater){ return false; } if (vehicle.getUniqueId() == vehicleUUID) return true; + removeAsPassenger(vehicleUUID, true); //remove old vehicle vehicleUUID = vehicle.getUniqueId(); WrapperPlayServerSetPassengers packet = new WrapperPlayServerSetPassengers(vehicle.getEntityId(), getPassengerArray(vehicle, true)); @@ -443,7 +444,7 @@ public boolean rideEntity(@NotNull Entity vehicle, boolean runLocationUpdater){ @Override public void run() { if (masterPart == null){ - vehicleUUID = null; + removeAsPassenger(vehicleUUID, true); cancel(); return; } @@ -451,14 +452,17 @@ public void run() { cancel(); return; } + Entity entity = Bukkit.getEntity(vehicleUUID); if (entity == null){ if (!DisplayControllerManager.isControllerEntity(vehicleUUID)){ + removeAsPassenger(vehicleUUID, true); cancel(); } return; } if (entity.isDead()){ + removeAsPassenger(vehicleUUID, true); cancel(); return; } @@ -469,7 +473,7 @@ public void run() { return true; } - private void removeAsPassenger(UUID entityUUID){ + private void removeAsPassenger(UUID entityUUID, boolean removeVehicleUUID){ if (vehicleUUID == null) return; PassengerGroupData data = groupVehicles.get(vehicleUUID); if (data == null) return; @@ -477,6 +481,7 @@ private void removeAsPassenger(UUID entityUUID){ if (data.isEmpty()){ groupVehicles.remove(vehicleUUID); } + if (removeVehicleUUID) vehicleUUID = null; } /** @@ -486,17 +491,17 @@ private void removeAsPassenger(UUID entityUUID){ @Override public @Nullable Entity dismount(){ Entity vehicle = getVehicle(); - removeAsPassenger(vehicleUUID); - if (vehicle == null) return null; - vehicleUUID = null; - dismount(getTrackingPlayers()); - - if (!vehicle.isDead()){ - if (!rideOffset.isZero()){ - translate(rideOffset.clone().multiply(-1), -1, -1); + removeAsPassenger(vehicleUUID, true); + if (vehicle != null){ + dismount(getTrackingPlayers(), vehicle); + + if (!vehicle.isDead()){ + if (!rideOffset.isZero()){ + translate(rideOffset.clone().multiply(-1), -1, -1); + } } + this.autoCull(false); } - this.autoCull(false); return vehicle; } @@ -518,7 +523,15 @@ public void dismount(@NotNull Player player){ *
This method must be called sync */ public void dismount(@NotNull Collection players){ - Entity vehicle = getVehicle(); + dismount(players, getVehicle()); + } + + /** + * Dismount this group from an entity for given players + * @param players the players to receive the dismount + *
This method must be called sync + */ + private void dismount(@NotNull Collection players, Entity vehicle){ if (vehicle == null) return; WrapperPlayServerSetPassengers packet = new WrapperPlayServerSetPassengers(vehicle.getEntityId(), getPassengerArray(vehicle, false)); for (Player p : players){ From ab7d212d9274b13c6629f93ad6345fe0a4108dd7 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 2 May 2026 18:06:26 -0500 Subject: [PATCH 24/55] respect group facing when updating position --- .../utils/DisplayEntities/PacketDisplayEntityGroup.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 bbea059f..1654df86 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 @@ -466,7 +466,11 @@ public void run() { cancel(); return; } - updateChunkAndWorld(entity.getLocation()); + Location newLoc = entity.getLocation(); + Location currentLoc = getLocation(); + newLoc.setPitch(currentLoc.getPitch()); + newLoc.setYaw(currentLoc.getYaw()); + updateChunkAndWorld(newLoc); } }, 0, 20); } From 2079ee30931cf3813cf5c1cf4e443c8dd2d9391b Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 2 May 2026 18:06:38 -0500 Subject: [PATCH 25/55] add PacketDisplayEntityGroup#resendLocation --- .../DisplayEntities/PacketDisplayEntityGroup.java | 12 ++++++++++++ .../DisplayEntities/PacketDisplayEntityPart.java | 14 ++++++++++++++ 2 files changed, 26 insertions(+) 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 1654df86..db190a8c 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 @@ -612,6 +612,18 @@ public void pivot(float angleInDegrees) { } } + /** + * Resend this {@link PacketDisplayEntityGroup}'s location to viewers of the group, refreshing its position. + */ + public void resendLocation(){ + Location groupLoc = getLocation(); + if (groupLoc == null) return; + for (Player p : this.getTrackingPlayers()){ + if (p == null) continue; + masterPart.teleportUnsetPassengers(groupLoc, p); + } + } + @Override public void teleportMove(@NotNull Vector direction, double distance, int durationInTicks) { Location destination = getLocation().add(direction.clone().normalize().multiply(distance)); 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 371b43c1..c52c3d1c 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 @@ -1176,6 +1176,20 @@ void teleportUnsetPassengers(@NotNull Location location){ } } + void teleportUnsetPassengers(@NotNull Location location, @NotNull Player player){ + packetLocation = new PacketLocation(location); + if (isMaster && group != null){ + group.unsetPassengers(player); + DisplayAPI.getScheduler().runAsync(() -> { + PacketUtils.teleport(player, getEntityId(), location); + group.setPassengers(player); + }); + } + else{ + PacketUtils.teleport(player, getEntityId(), location); + } + } + /** * Get the location of this packet-based entity. * @return a {@link Location} or null if not set From d251b80e2997f207e9768e488838604c828c70be Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 2 May 2026 18:27:37 -0500 Subject: [PATCH 26/55] change #updateChunkAndWorld to teleport group across worlds when location world's differ (fix vehicle/passenger desync) --- .../PacketDisplayEntityGroup.java | 488 +++++++++--------- 1 file changed, 251 insertions(+), 237 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 db190a8c..41b66d68 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 @@ -30,7 +30,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; -public class PacketDisplayEntityGroup extends ActiveGroup implements Packeted{ +public class PacketDisplayEntityGroup extends ActiveGroup implements Packeted { private static final ConcurrentHashMap allPacketGroups = new ConcurrentHashMap<>(); private static final ConcurrentHashMap groupVehicles = new ConcurrentHashMap<>(); @@ -44,7 +44,7 @@ public class PacketDisplayEntityGroup extends ActiveGroup getGroups(@NotNull World world){ + public static @NotNull Set getGroups(@NotNull World world) { WorldData data = allPacketGroups.get(world.getName()); return data != null ? data.getGroups() : Collections.emptySet(); } - public static @NotNull Set getGroups(@NotNull Chunk chunk){ + public static @NotNull Set getGroups(@NotNull Chunk chunk) { return getGroups(chunk.getWorld(), chunk.getChunkKey()); } - public static @NotNull Set getGroups(@NotNull World world, long chunkKey){ + public static @NotNull Set getGroups(@NotNull World world, long chunkKey) { WorldData data = allPacketGroups.get(world.getName()); return data != null ? data.getGroups(chunkKey) : Collections.emptySet(); } - public static boolean hasPassengerGroups(@NotNull Entity entity){ + public static boolean hasPassengerGroups(@NotNull Entity entity) { return hasPassengerGroups(entity.getUniqueId()); } - public static boolean hasPassengerGroups(@NotNull UUID entityUUID){ + public static boolean hasPassengerGroups(@NotNull UUID entityUUID) { return groupVehicles.containsKey(entityUUID); } - public static @NotNull Set getPassengerGroups(@NotNull UUID entityUUID){ + public static @NotNull Set getPassengerGroups(@NotNull UUID entityUUID) { PassengerGroupData data = groupVehicles.get(entityUUID); return data != null ? data.getGroups() : Collections.emptySet(); } - public static @NotNull Set getPassengerGroups(@NotNull Entity entity){ + public static @NotNull Set getPassengerGroups(@NotNull Entity entity) { return getPassengerGroups(entity.getUniqueId()); } @ApiStatus.Internal - public void setPersistentIds(int localId, Chunk chunk){ + public void setPersistentIds(int localId, Chunk chunk) { this.persistentLocalId = localId; this.persistentGlobalId = chunk != null ? buildPersistentGlobalId(chunk, localId) : null; } @@ -131,23 +130,25 @@ public void setPersistentIds(int localId, Chunk chunk){ /** * Get this {@link PacketDisplayEntityGroup}'s local id, relative to its current chunk + * * @return an int. -1 if this group is not persistent (stored in a chunk's PDC) */ - public int getPersistentLocalId(){ + public int getPersistentLocalId() { return this.persistentLocalId; } /** * Get this {@link PacketDisplayEntityGroup}'s global id + * * @return a string. null if this group is not persistent (stored in a chunk's PDC) */ - public @Nullable String getPersistentGlobalId(){ + public @Nullable String getPersistentGlobalId() { return this.persistentGlobalId; } - public static String buildPersistentGlobalId(@NotNull Chunk chunk, int localId){ - return chunk.getWorld().getName()+"|"+chunk.getChunkKey()+"|"+localId; //world,chunkkey,localid + public static String buildPersistentGlobalId(@NotNull Chunk chunk, int localId) { + return chunk.getWorld().getName() + "|" + chunk.getChunkKey() + "|" + localId; //world,chunkkey,localid } /** @@ -157,14 +158,13 @@ public static String buildPersistentGlobalId(@NotNull Chunk chunk, int localId){ */ @Override public void setPersistent(boolean persistent) { - if (persistent){ + if (persistent) { if (isRiding()) return; - if (!isPersistent()){ + if (!isPersistent()) { DisplayGroupManager.addPersistentPacketGroup(this, getLocation()); } - } - else{ - if (isPersistent() && !isPlaced){ + } else { + if (isPersistent() && !isPlaced) { DisplayGroupManager.removePersistentPacketGroup(this, false); setPersistentIds(-1, null); } @@ -173,43 +173,51 @@ public void setPersistent(boolean persistent) { /** * Get whether this {@link PacketDisplayEntityGroup} is saved in chunk data, and will persist after restarts + * * @return a boolean */ @Override - public boolean isPersistent(){ + 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(){ + public boolean isPlaced() { return this.isPlaced; } @ApiStatus.Internal - public static void removeWorld(@NotNull World world){ + 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) allPacketGroups.remove(world.getName()); } - void updateChunkAndWorld(@NotNull Location location){ - Location oldLoc = getLocation(); - //Remove from previous - if (oldLoc != null){ - if (location.getWorld().equals(oldLoc.getWorld()) - && ConversionUtils.getChunkKey(location) == ConversionUtils.getChunkKey(oldLoc) - && vehicleUUID == null){ - return; + void updateChunkAndWorld(@NotNull Location location) { + Location prevLoc = getLocation(); + boolean refreshViewers = false; + + //Remove from previous world data + if (prevLoc != null) { + if (location.getWorld().equals(prevLoc.getWorld()) + && ConversionUtils.getChunkKey(location) == ConversionUtils.getChunkKey(prevLoc) + && vehicleUUID == null) { + return; } - String oldWorldName = oldLoc.getWorld().getName(); - WorldData data = allPacketGroups.get(oldWorldName); - if (data != null){ - long chunkKey = ConversionUtils.getChunkKey(oldLoc); - data.removeGroup(chunkKey, this); - if (data.isEmpty() && !location.getWorld().getName().equals(oldWorldName)){ - allPacketGroups.remove(oldWorldName); + String prevWorldName = prevLoc.getWorld().getName(); + WorldData prevWorldData = allPacketGroups.get(prevWorldName); + + + if (prevWorldData != null) { + long prevChunkKey = ConversionUtils.getChunkKey(prevLoc); + prevWorldData.removeGroup(prevChunkKey, this); + + if (!location.getWorld().getName().equals(prevWorldName)){ + refreshViewers = true; + if (prevWorldData.isEmpty()) allPacketGroups.remove(prevWorldName); } } } @@ -219,38 +227,42 @@ void updateChunkAndWorld(@NotNull Location location){ allPacketGroups .computeIfAbsent(world.getName(), key -> new WorldData()) .addGroup(chunkKey, this); - if (masterPart != null){ + if (masterPart != null) { masterPart.packetLocation = new PacketDisplayEntityPart.PacketLocation(location); } + if (refreshViewers) { + hide(); + if (isAutoShow()) show(); + } } @ApiStatus.Internal - public void chunkUnloadLocation(){ + public void chunkUnloadLocation() { Entity vehicle = getVehicle(); - if (vehicle != null){ + if (vehicle != null) { updateChunkAndWorld(vehicle.getLocation()); } } @Override - public void addPart(@NotNull PacketDisplayEntityPart part){ + public void addPart(@NotNull PacketDisplayEntityPart part) { addPartSilent(part); updatePassengerIds(part.getEntityId(), true); } - void addPartSilent(PacketDisplayEntityPart part){ + void addPartSilent(PacketDisplayEntityPart part) { if (groupParts.get(part.partUUID) == part) return; - if (part.partUUID == null){ - do{ + if (part.partUUID == null) { + do { part.partUUID = UUID.randomUUID(); //for parts in old models that do not contain pdc data / part uuids AND new ungrouped parts - } while(groupParts.containsKey(part.partUUID)); + } while (groupParts.containsKey(part.partUUID)); } if (part.isMaster) masterPart = part; groupParts.put(part.partUUID, part); part.group = this; - if (this.autoShow){ + if (this.autoShow) { part.showToPlayers(getTrackingPlayers(), GroupSpawnedEvent.SpawnReason.INTERNAL); } } @@ -267,28 +279,27 @@ void addPartSilent(PacketDisplayEntityPart part){ return part; } - void updatePassengerIds(int passengerId, boolean add){ + void updatePassengerIds(int passengerId, boolean add) { if (passengerIds == null) return; int[] ids; - if (add){ - ids = new int[passengerIds.length+1]; - for (int i = 0; i < passengerIds.length; i++){ + if (add) { + ids = new int[passengerIds.length + 1]; + for (int i = 0; i < passengerIds.length; i++) { int id = passengerIds[i]; if (id == passengerId) return; ids[i] = id; } ids[passengerIds.length] = passengerId; - } - else{ - int newLength = passengerIds.length-1; - if (newLength <= 0){ + } else { + int newLength = passengerIds.length - 1; + if (newLength <= 0) { passengerIds = new int[0]; return; } - ids = new int[passengerIds.length-1]; - for (int i = 0; i < ids.length; i++){ + ids = new int[passengerIds.length - 1]; + for (int i = 0; i < ids.length; i++) { int id = passengerIds[i]; - if (id != passengerId){ + if (id != passengerId) { ids[i] = id; } } @@ -298,6 +309,7 @@ void updatePassengerIds(int passengerId, boolean add){ /** * {@inheritDoc} + * * @return a {@link PacketPartSelection} */ @Override @@ -307,6 +319,7 @@ void updatePassengerIds(int passengerId, boolean add){ /** * {@inheritDoc} + * * @return a {@link PacketPartSelection} */ @Override @@ -317,69 +330,68 @@ void updatePassengerIds(int passengerId, boolean add){ @Override public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleNonDisplays) { - if (newScaleMultiplier <= 0){ + if (newScaleMultiplier <= 0) { throw new IllegalArgumentException("New Scale Multiplier cannot be <= 0"); } - if (newScaleMultiplier == scaleMultiplier){ + if (newScaleMultiplier == scaleMultiplier) { return true; } - for (PacketDisplayEntityPart part : groupParts.values()){ + for (PacketDisplayEntityPart part : groupParts.values()) { //Displays - if (part.isDisplay()){ + if (part.isDisplay()) { DisplayAttributeMap attributeMap = new DisplayAttributeMap(); Transformation transformation = part.getTransformation(); //Reset Scale then multiply by newScaleMultiplier Vector3f scale = transformation.getScale(); - scale.x = (scale.x/scaleMultiplier)*newScaleMultiplier; - scale.y = (scale.y/scaleMultiplier)*newScaleMultiplier; - scale.z = (scale.z/scaleMultiplier)*newScaleMultiplier; + scale.x = (scale.x / scaleMultiplier) * newScaleMultiplier; + scale.y = (scale.y / scaleMultiplier) * newScaleMultiplier; + scale.z = (scale.z / scaleMultiplier) * newScaleMultiplier; //Reset Translation then multiply by newScaleMultiplier Vector3f translationVector = transformation.getTranslation(); - translationVector.x = (translationVector.x/scaleMultiplier)*newScaleMultiplier; - translationVector.y = (translationVector.y/scaleMultiplier)*newScaleMultiplier; - translationVector.z = (translationVector.z/scaleMultiplier)*newScaleMultiplier; + translationVector.x = (translationVector.x / scaleMultiplier) * newScaleMultiplier; + translationVector.y = (translationVector.y / scaleMultiplier) * newScaleMultiplier; + translationVector.z = (translationVector.z / scaleMultiplier) * newScaleMultiplier; - if (!transformation.equals(part.getTransformation())){ + if (!transformation.equals(part.getTransformation())) { attributeMap.add(DisplayAttributes.Interpolation.DURATION, durationInTicks) - .add(DisplayAttributes.Interpolation.DELAY, -1) - .addTransformation(transformation); + .add(DisplayAttributes.Interpolation.DELAY, -1) + .addTransformation(transformation); } //Culling - if (DisplayConfig.autoCulling()){ + if (DisplayConfig.autoCulling()) { float[] values = DisplayUtils.getAutoCullValues(part, DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); attributeMap.add(DisplayAttributes.Culling.HEIGHT, values[1]) - .add(DisplayAttributes.Culling.WIDTH, values[0]); + .add(DisplayAttributes.Culling.WIDTH, values[0]); } part.attributeContainer.setAttributesAndSend(attributeMap, part.getEntityId(), part.viewers); } //Non Displays - else if (scaleNonDisplays){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + 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; + 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){ + 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); + 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(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); + } 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); } } } @@ -389,34 +401,34 @@ else if (part.type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ } - public @NotNull DisplayAnimator animate(@NotNull SpawnedDisplayAnimation animation){ + public @NotNull DisplayAnimator animate(@NotNull SpawnedDisplayAnimation animation) { return DisplayAnimator.playUsingPackets(this, animation, DisplayAnimator.AnimationType.LINEAR); } - public @NotNull DisplayAnimator animateLooping(@NotNull SpawnedDisplayAnimation animation){ + public @NotNull DisplayAnimator animateLooping(@NotNull SpawnedDisplayAnimation animation) { return DisplayAnimator.playUsingPackets(this, animation, DisplayAnimator.AnimationType.LOOP); } - private int[] getPassengerArray(Entity vehicle, boolean includeGroup){ + private int[] getPassengerArray(Entity vehicle, boolean includeGroup) { List passengers = vehicle.getPassengers(); if (!includeGroup) return passengers.stream().mapToInt(Entity::getEntityId).toArray(); - int[] arr = new int[passengers.size()+1]; + int[] arr = new int[passengers.size() + 1]; - for (int i = 0; i < passengers.size(); i++){ + for (int i = 0; i < passengers.size(); i++) { arr[i] = passengers.get(i).getEntityId(); } - arr[arr.length-1] = masterPart.getEntityId(); + arr[arr.length - 1] = masterPart.getEntityId(); return arr; } @Override - public boolean rideEntity(@NotNull Entity vehicle){ + public boolean rideEntity(@NotNull Entity vehicle) { return rideEntity(vehicle, true); } - public boolean rideEntity(@NotNull Entity vehicle, boolean runLocationUpdater){ - if (isPersistent() || vehicle.isDead()){ + public boolean rideEntity(@NotNull Entity vehicle, boolean runLocationUpdater) { + if (isPersistent() || vehicle.isDead()) { return false; } if (vehicle.getUniqueId() == vehicleUUID) return true; @@ -424,7 +436,7 @@ public boolean rideEntity(@NotNull Entity vehicle, boolean runLocationUpdater){ vehicleUUID = vehicle.getUniqueId(); WrapperPlayServerSetPassengers packet = new WrapperPlayServerSetPassengers(vehicle.getEntityId(), getPassengerArray(vehicle, true)); - for (Player p : getTrackingPlayers()){ + for (Player p : getTrackingPlayers()) { PacketEvents.getAPI().getPlayerManager().sendPacketSilently(p, packet); } @@ -438,30 +450,30 @@ public boolean rideEntity(@NotNull Entity vehicle, boolean runLocationUpdater){ this.autoCull(true); - if (runLocationUpdater){ + if (runLocationUpdater) { final UUID finalUUID = vehicle.getUniqueId(); DisplayAPI.getScheduler().entityRunTimer(vehicle, new Scheduler.SchedulerRunnable() { @Override public void run() { - if (masterPart == null){ + if (masterPart == null) { removeAsPassenger(vehicleUUID, true); cancel(); return; } - if (PacketDisplayEntityGroup.this.vehicleUUID != finalUUID){ + if (PacketDisplayEntityGroup.this.vehicleUUID != finalUUID) { cancel(); return; } Entity entity = Bukkit.getEntity(vehicleUUID); - if (entity == null){ - if (!DisplayControllerManager.isControllerEntity(vehicleUUID)){ + if (entity == null) { + if (!DisplayControllerManager.isControllerEntity(vehicleUUID)) { removeAsPassenger(vehicleUUID, true); cancel(); } return; } - if (entity.isDead()){ + if (entity.isDead()) { removeAsPassenger(vehicleUUID, true); cancel(); return; @@ -470,6 +482,7 @@ public void run() { Location currentLoc = getLocation(); newLoc.setPitch(currentLoc.getPitch()); newLoc.setYaw(currentLoc.getYaw()); + updateChunkAndWorld(newLoc); } }, 0, 20); @@ -477,12 +490,12 @@ public void run() { return true; } - private void removeAsPassenger(UUID entityUUID, boolean removeVehicleUUID){ + private void removeAsPassenger(UUID entityUUID, boolean removeVehicleUUID) { if (vehicleUUID == null) return; PassengerGroupData data = groupVehicles.get(vehicleUUID); if (data == null) return; data.removeGroup(entityUUID, this); - if (data.isEmpty()){ + if (data.isEmpty()) { groupVehicles.remove(vehicleUUID); } if (removeVehicleUUID) vehicleUUID = null; @@ -493,14 +506,14 @@ private void removeAsPassenger(UUID entityUUID, boolean removeVehicleUUID){ *
This method must be called sync */ @Override - public @Nullable Entity dismount(){ + public @Nullable Entity dismount() { Entity vehicle = getVehicle(); removeAsPassenger(vehicleUUID, true); - if (vehicle != null){ + if (vehicle != null) { dismount(getTrackingPlayers(), vehicle); - if (!vehicle.isDead()){ - if (!rideOffset.isZero()){ + if (!vehicle.isDead()) { + if (!rideOffset.isZero()) { translate(rideOffset.clone().multiply(-1), -1, -1); } } @@ -511,10 +524,11 @@ private void removeAsPassenger(UUID entityUUID, boolean removeVehicleUUID){ /** * Dismount this group from an entity for a given player + * * @param player the player to receive the dismount - *
This method must be called sync + *
This method must be called sync */ - public void dismount(@NotNull Player player){ + public void dismount(@NotNull Player player) { Entity vehicle = getVehicle(); if (vehicle == null) return; WrapperPlayServerSetPassengers packet = new WrapperPlayServerSetPassengers(vehicle.getEntityId(), getPassengerArray(vehicle, false)); @@ -523,33 +537,35 @@ public void dismount(@NotNull Player player){ /** * Dismount this group from an entity for given players + * * @param players the players to receive the dismount - *
This method must be called sync + *
This method must be called sync */ - public void dismount(@NotNull Collection players){ + public void dismount(@NotNull Collection players) { dismount(players, getVehicle()); } /** * Dismount this group from an entity for given players + * * @param players the players to receive the dismount - *
This method must be called sync + *
This method must be called sync */ - private void dismount(@NotNull Collection players, Entity vehicle){ + private void dismount(@NotNull Collection players, Entity vehicle) { if (vehicle == null) return; WrapperPlayServerSetPassengers packet = new WrapperPlayServerSetPassengers(vehicle.getEntityId(), getPassengerArray(vehicle, false)); - for (Player p : players){ + for (Player p : players) { PacketEvents.getAPI().getPlayerManager().sendPacket(p, packet); } } @Override - public boolean isRiding(){ + public boolean isRiding() { return vehicleUUID != null; } @Override - public @Nullable Entity getVehicle(){ + public @Nullable Entity getVehicle() { return vehicleUUID == null ? null : Bukkit.getEntity(vehicleUUID); } @@ -566,7 +582,6 @@ public Collection getTrackingPlayers() { } - @Override public boolean hasTrackingPlayers() { return masterPart != null && !masterPart.viewers.isEmpty(); @@ -574,39 +589,40 @@ public boolean hasTrackingPlayers() { @Override public void removeInteractions() { - for (PacketDisplayEntityPart part : this.getParts(SpawnedDisplayEntityPart.PartType.INTERACTION)){ + for (PacketDisplayEntityPart part : this.getParts(SpawnedDisplayEntityPart.PartType.INTERACTION)) { part.remove(); } } - public void setAttributes(@NotNull DisplayAttributeMap attributeMap, SpawnedDisplayEntityPart.PartType... effectedPartTypes){ + public void setAttributes(@NotNull DisplayAttributeMap attributeMap, SpawnedDisplayEntityPart.PartType... effectedPartTypes) { Set effectedTypes = effectedPartTypes == null || effectedPartTypes.length == 0 ? null : EnumSet.copyOf(Arrays.asList(effectedPartTypes)); - for (PacketDisplayEntityPart part : groupParts.values()){ - if (effectedTypes == null || effectedTypes.contains(part.type)){ + for (PacketDisplayEntityPart part : groupParts.values()) { + if (effectedTypes == null || effectedTypes.contains(part.type)) { part.setAttributes(attributeMap); } } } @Override - public void setRotation(float pitch, float yaw, boolean pivot){ - for (PacketDisplayEntityPart part : groupParts.values()){ + public void setRotation(float pitch, float yaw, boolean pivot) { + for (PacketDisplayEntityPart part : groupParts.values()) { 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()){ - if (!part.isDisplay()){ + for (PacketDisplayEntityPart part : groupParts.values()) { + if (!part.isDisplay()) { part.pivot(angleInDegrees); } } @@ -615,10 +631,10 @@ public void pivot(float angleInDegrees) { /** * Resend this {@link PacketDisplayEntityGroup}'s location to viewers of the group, refreshing its position. */ - public void resendLocation(){ + public void resendLocation() { Location groupLoc = getLocation(); if (groupLoc == null) return; - for (Player p : this.getTrackingPlayers()){ + for (Player p : this.getTrackingPlayers()) { if (p == null) continue; masterPart.teleportUnsetPassengers(groupLoc, p); } @@ -628,34 +644,34 @@ public void resendLocation(){ 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); + double movementIncrement = distance / (double) Math.max(durationInTicks, 1); Vector incrementVector = direction .clone() .normalize() .multiply(movementIncrement); - for (PacketDisplayEntityPart part : groupParts.values()){ - if (!part.isDisplay()){ + for (PacketDisplayEntityPart part : groupParts.values()) { + if (!part.isDisplay()) { PacketUtils.translateNonDisplay(part, direction, distance, durationInTicks, 0); } } DisplayAPI.getScheduler().partRunTimerAsync(masterPart, new Scheduler.SchedulerRunnable() { double currentDistance = 0; + @Override public void run() { - if (masterPart == null){ + if (masterPart == null) { cancel(); return; } - currentDistance+=Math.abs(movementIncrement); + currentDistance += Math.abs(movementIncrement); Location tpLocation = getLocation().add(incrementVector); - attemptLocationUpdate(getLocation(), tpLocation); - if (currentDistance >= distance){ + updateChunkAndWorld(tpLocation); + if (currentDistance >= distance) { masterPart.teleportUnsetPassengers(destination); cancel(); - } - else{ + } else { masterPart.teleportUnsetPassengers(tpLocation); } PacketDisplayEntityGroup.this.update(); @@ -669,24 +685,23 @@ public void run() { *

This will fail if {@link #isRiding()} or {@link #isPlaced()} is true */ @Override - public boolean teleport(@NotNull Location tpLocation, boolean respectGroupDirection){ + public boolean teleport(@NotNull Location tpLocation, boolean respectGroupDirection) { if (isRiding() || isPlaced) return false; Location oldMasterLoc = getLocation(); - attemptLocationUpdate(oldMasterLoc, tpLocation); + updateChunkAndWorld(tpLocation); tpLocation = tpLocation.clone(); - if (respectGroupDirection){ + if (respectGroupDirection) { tpLocation.setPitch(oldMasterLoc.getPitch()); tpLocation.setYaw(oldMasterLoc.getYaw()); } masterPart.teleportUnsetPassengers(tpLocation); - for (PacketDisplayEntityPart part : groupParts.values()){ - if (!part.isDisplay()){ + for (PacketDisplayEntityPart part : groupParts.values()) { + if (!part.isDisplay()) { Vector vector = oldMasterLoc.toVector().subtract(part.getLocation().toVector()); Location interactionTpLoc = tpLocation.clone().subtract(vector); part.teleport(interactionTpLoc); - } - else{ + } else { part.setRotation(tpLocation.getPitch(), tpLocation.getYaw(), false); } } @@ -694,38 +709,23 @@ public boolean teleport(@NotNull Location tpLocation, boolean respectGroupDirect return true; } - private void attemptLocationUpdate(Location oldLoc, Location newLoc){ - if (oldLoc == null) { - updateChunkAndWorld(newLoc); - } - else{ - World w1 = oldLoc.getWorld(); - World w2 = newLoc.getWorld(); - if (!w1.equals(w2)){ - hide(); - updateChunkAndWorld(newLoc); - if (isAutoShow()) show(); - } - else{ - updateChunkAndWorld(newLoc); - } - } - } /** * Get the location of this group + * * @return a {@link Location} or null if not set */ @Override - public @Nullable Location getLocation(){ + public @Nullable Location getLocation() { if (masterPart == null) return null; return masterPart.getLocation(); } /** * Display the transformations of a {@link SpawnedDisplayAnimationFrame} on this group + * * @param animation the animation the frame is from - * @param frame the frame to display + * @param frame the frame to display */ @Override public void setToFrame(@NotNull SpawnedDisplayAnimation animation, @NotNull SpawnedDisplayAnimationFrame frame) { @@ -744,7 +744,7 @@ public void setToFrame(@NotNull SpawnedDisplayAnimation animation, @NotNull Spaw @Override public void setToFrame(@NotNull Player player, @NotNull SpawnedDisplayAnimation animation, @NotNull SpawnedDisplayAnimationFrame frame) { - if (masterPart.isTrackedBy(player)){ + if (masterPart.isTrackedBy(player)) { DisplayAnimator animator = new DisplayAnimator(animation, DisplayAnimator.AnimationType.LINEAR); DisplayAPI.getAnimationPlayerService().playForClient(Set.of(player), animator, animation, this, frame, -1, 0, true); } @@ -752,7 +752,7 @@ public void setToFrame(@NotNull Player player, @NotNull SpawnedDisplayAnimation @Override public void setToFrame(@NotNull Player player, @NotNull SpawnedDisplayAnimation animation, @NotNull SpawnedDisplayAnimationFrame frame, int duration, int delay) { - if (masterPart.isTrackedBy(player)){ + if (masterPart.isTrackedBy(player)) { DisplayAnimator animator = new DisplayAnimator(animation, DisplayAnimator.AnimationType.LINEAR); SpawnedDisplayAnimationFrame clonedFrame = frame.clone(); clonedFrame.duration = duration; @@ -764,8 +764,8 @@ public void setToFrame(@NotNull Player player, @NotNull SpawnedDisplayAnimation * Refresh this {@link PacketDisplayEntityGroup}'s saved data after any changes are made to it.
* This only applies to persistent groups that need any changes done to apply to the next server session. */ - public void update(){ - if (isPersistent()){ + public void update() { + if (isPersistent()) { DisplayGroupManager.updatePersistentPacketGroup(this); } } @@ -775,22 +775,23 @@ public void update(){ * @return a cloned {@link PacketDisplayEntityGroup} */ @Override - public PacketDisplayEntityGroup clone(@NotNull Location location){ + public PacketDisplayEntityGroup clone(@NotNull Location location) { return clone(location, true, true); } /** * Creates a copy of this group at a location - * @param location where to spawn the clone + * + * @param location where to spawn the clone * @param playSpawnAnimation whether this packet group should automatically play its spawn animation when created - * @param autoShow whether this packet group should automatically handle revealing and hiding itself to players + * @param autoShow whether this packet group should automatically handle revealing and hiding itself to players * @return a cloned {@link PacketDisplayEntityGroup} */ - public PacketDisplayEntityGroup clone(@NotNull Location location, boolean playSpawnAnimation, boolean autoShow){ + public PacketDisplayEntityGroup clone(@NotNull Location location, boolean playSpawnAnimation, boolean autoShow) { //Reset pivot to 0 float groupYaw = getLocation().getYaw(); HashSet resettedParts = new HashSet<>(); - for (ActivePart part : groupParts.values()){ + for (ActivePart part : groupParts.values()) { if (part.isDisplay()) continue; part.pivot(-groupYaw); resettedParts.add(part); @@ -808,7 +809,7 @@ public PacketDisplayEntityGroup clone(@NotNull Location location, boolean playSp ); //Restore pivot - for (ActivePart part : resettedParts){ + for (ActivePart part : resettedParts) { part.pivot(groupYaw); } @@ -819,38 +820,40 @@ public PacketDisplayEntityGroup clone(@NotNull Location location, boolean playSp /** * {@inheritDoc} + * * @return a string or null if the group's location was never set */ @Override - public @Nullable String getWorldName(){ + public @Nullable String getWorldName() { if (masterPart == null) return null; return masterPart.getWorldName(); } /** * Set whether this group should automatically handle revealing itself to players after they switch worlds + * * @param autoShow whether the group should autoShow */ - public synchronized PacketDisplayEntityGroup setAutoShow(boolean autoShow){ + public synchronized PacketDisplayEntityGroup setAutoShow(boolean autoShow) { boolean oldAutoshow = this.autoShow; this.autoShow = autoShow; - if (oldAutoshow != autoShow){ + if (oldAutoshow != autoShow) { this.update(); - if (autoShow){ + if (autoShow) { show(); } } return this; } - private synchronized void show(){ + private synchronized void show() { Location loc = getLocation(); if (loc == null) return; long chunkKey = ConversionUtils.getChunkKey(loc); Collection players = new ArrayList<>(); DisplayAPI.getScheduler().run(() -> { - for (Player p : loc.getWorld().getPlayers()){ - if (p.isChunkSent(chunkKey)){ + for (Player p : loc.getWorld().getPlayers()) { + if (p.isChunkSent(chunkKey)) { players.add(p); } } @@ -862,27 +865,27 @@ private synchronized void show(){ }); } - synchronized PacketDisplayEntityGroup setAutoShow(GroupSpawnSettings settings){ + synchronized PacketDisplayEntityGroup setAutoShow(GroupSpawnSettings settings) { boolean autoShow = settings.visibleByDefault; boolean oldAutoshow = this.autoShow; this.autoShow = autoShow; - if (oldAutoshow != autoShow){ + if (oldAutoshow != autoShow) { this.update(); - if (autoShow){ + if (autoShow) { show(settings); } } return this; } - private synchronized void show(GroupSpawnSettings settings){ + private synchronized void show(GroupSpawnSettings settings) { Location loc = getLocation(); if (loc == null) return; long chunkKey = ConversionUtils.getChunkKey(loc); Collection players = new ArrayList<>(); DisplayAPI.getScheduler().run(() -> { - for (Player p : loc.getWorld().getPlayers()){ - if (p.isChunkSent(chunkKey)){ + for (Player p : loc.getWorld().getPlayers()) { + if (p.isChunkSent(chunkKey)) { players.add(p); } } @@ -900,20 +903,22 @@ private synchronized void show(GroupSpawnSettings settings){ *

* The condition is tested on a player whenever they switch worlds. If the given predicate returns false, * the group must manually be shown to the player. If true, the group will be shown. - * @param autoShow whether the group should autoShow + * + * @param autoShow whether the group should autoShow * @param playerCondition the condition checked for every player. * */ - public synchronized void setAutoShow(boolean autoShow, @Nullable Predicate playerCondition){ + public synchronized void setAutoShow(boolean autoShow, @Nullable Predicate playerCondition) { setAutoShow(autoShow); this.autoShowCondition = playerCondition; } /** * Get whether this group should automatically handle revealing itself to player after a world switch + * * @return a boolean */ - public synchronized boolean isAutoShow(){ + public synchronized boolean isAutoShow() { return autoShow; } @@ -922,23 +927,26 @@ public synchronized boolean isAutoShow(){ *

* The condition is tested on a player whenever they switch worlds. If the given predicate returns false, * the group must manually be shown to the player. If true, the group will be shown. + * * @param playerCondition the condition checked for every player */ - public void setAutoShowCondition(@Nullable Predicate playerCondition){ + public void setAutoShowCondition(@Nullable Predicate playerCondition) { this.autoShowCondition = playerCondition; } /** * Get the condition that will be used on a player for this group when determining if this group should automatically reveal itself after the player switches worlds + * * @return a {@link Predicate} or null */ - public @Nullable Predicate getAutoShowCondition(){ + public @Nullable Predicate getAutoShowCondition() { return autoShowCondition; } /** * Show the group's packet-based entities to a player. Calls the {@link PacketGroupSendEvent} - * @param player the player + * + * @param player the player * @param spawnReason the spawn reason */ @Override @@ -948,9 +956,10 @@ public void showToPlayer(@NotNull Player player, @NotNull GroupSpawnedEvent.Spaw /** * Show the group's packet-based entities to a player. Calls the {@link PacketGroupSendEvent} - * @param player the player + * + * @param player the player * @param spawnReason the spawn reason - * @param location where to spawn the group for the player + * @param location where to spawn the group for the player */ @Override public void showToPlayer(@NotNull Player player, GroupSpawnedEvent.@NotNull SpawnReason spawnReason, @NotNull Location location) { @@ -959,15 +968,16 @@ public void showToPlayer(@NotNull Player player, GroupSpawnedEvent.@NotNull Spaw /** * Show the group's packet-based entities to players. Calls the {@link PacketGroupSendEvent} - * @param players the players + * + * @param players the players * @param spawnReason the spawn reason */ @Override public void showToPlayers(@NotNull Collection players, GroupSpawnedEvent.@NotNull SpawnReason spawnReason) { if (!sendShowEvent(players, spawnReason)) return; - for (Player player : players){ - if (!masterPart.isTrackedBy(player)){ - for (PacketDisplayEntityPart part : groupParts.sequencedValues()){ + for (Player player : players) { + if (!masterPart.isTrackedBy(player)) { + for (PacketDisplayEntityPart part : groupParts.sequencedValues()) { part.showToPlayer(player, spawnReason); } setPassengers(player); @@ -979,16 +989,17 @@ public void showToPlayers(@NotNull Collection players, GroupSpawnedEvent /** * Show the group's packet-based entities to players. Calls the {@link PacketGroupSendEvent} - * @param players the players + * + * @param players the players * @param spawnReason the spawn reason - * @param location where to spawn the group for the players + * @param location where to spawn the group for the players */ @Override public void showToPlayers(@NotNull Collection players, GroupSpawnedEvent.@NotNull SpawnReason spawnReason, @NotNull Location location) { if (!sendShowEvent(players, spawnReason)) return; - for (Player player : players){ - if (!masterPart.isTrackedBy(player)){ - for (PacketDisplayEntityPart part : groupParts.sequencedValues()){ + for (Player player : players) { + if (!masterPart.isTrackedBy(player)) { + for (PacketDisplayEntityPart part : groupParts.sequencedValues()) { part.showToPlayer(player, spawnReason, location); } setPassengers(player); @@ -999,9 +1010,9 @@ public void showToPlayers(@NotNull Collection players, GroupSpawnedEvent void showToPlayers(@NotNull Collection players, GroupSpawnedEvent.@NotNull SpawnReason spawnReason, @NotNull GroupSpawnSettings settings) { if (!sendShowEvent(players, spawnReason)) return; - for (Player player : players){ - if (!masterPart.isTrackedBy(player)){ - for (PacketDisplayEntityPart part : groupParts.sequencedValues()){ + for (Player player : players) { + if (!masterPart.isTrackedBy(player)) { + for (PacketDisplayEntityPart part : groupParts.sequencedValues()) { part.showToPlayer(player, part.getLocation(), settings); } setPassengers(player); @@ -1010,43 +1021,44 @@ void showToPlayers(@NotNull Collection players, GroupSpawnedEvent.@NotNu } } - void unsetPassengers(Player player){ + void unsetPassengers(Player player) { int masterId = masterPart.getEntityId(); WrapperPlayServerSetPassengers passengerPacket = new WrapperPlayServerSetPassengers(masterId, new int[0]); PacketEvents.getAPI().getPlayerManager().sendPacketSilently(player, passengerPacket); } - void setPassengers(Player player){ + void setPassengers(Player player) { if (passengerIds == null) return; int masterId = masterPart.getEntityId(); WrapperPlayServerSetPassengers passengerPacket = new WrapperPlayServerSetPassengers(masterId, passengerIds); PacketEvents.getAPI().getPlayerManager().sendPacketSilently(player, passengerPacket); } - void refreshVehicle(@NotNull Player player){ + void refreshVehicle(@NotNull Player player) { DisplayAPI.getScheduler().runLater(() -> { Entity vehicle = getVehicle(); - if (vehicle != null){ + if (vehicle != null) { WrapperPlayServerSetPassengers packet = new WrapperPlayServerSetPassengers(vehicle.getEntityId(), getPassengerArray(vehicle, true)); PacketEvents.getAPI().getPlayerManager().sendPacketSilently(player, packet); } }, 2); } - private boolean sendShowEvent(Collection players, GroupSpawnedEvent.SpawnReason spawnReason){ + private boolean sendShowEvent(Collection players, GroupSpawnedEvent.SpawnReason spawnReason) { return new PacketGroupSendEvent(this, spawnReason, players).callEvent(); } /** * Hide this group's {@link PacketDisplayEntityPart}s from all players tracking this group */ - public void hide(){ + public void hide() { Collection viewers = getTrackingPlayers(); hideFromPlayers(viewers); } /** * Hide the group's {@link PacketDisplayEntityPart}s from a player + * * @param player the player */ @Override @@ -1055,7 +1067,7 @@ public void hideFromPlayer(@NotNull Player player) { int[] ids = new int[groupParts.size()]; int i = 0; - for (PacketDisplayEntityPart part : groupParts.values()){ + for (PacketDisplayEntityPart part : groupParts.values()) { part.viewers.remove(player.getUniqueId()); DEUUser.getOrCreateUser(player).untrackPacketEntity(part); ids[i] = part.getEntityId(); @@ -1066,6 +1078,7 @@ public void hideFromPlayer(@NotNull Player player) { /** * Hide the group's {@link PacketDisplayEntityPart}s from players + * * @param players the players */ @Override @@ -1074,8 +1087,8 @@ public void hideFromPlayers(@NotNull Collection players) { int[] ids = new int[groupParts.size()]; int i = 0; - for (PacketDisplayEntityPart part : groupParts.values()){ - for (Player player : players){ + for (PacketDisplayEntityPart part : groupParts.values()) { + for (Player player : players) { part.viewers.remove(player.getUniqueId()); DEUUser.getOrCreateUser(player).untrackPacketEntity(part); } @@ -1085,14 +1098,14 @@ public void hideFromPlayers(@NotNull Collection players) { PacketUtils.hideEntities(players, ids); } - private void callDestroyEvent(Collection players){ + private void callDestroyEvent(Collection players) { new PacketGroupDestroyEvent(this, players).callEvent(); } @Override public boolean translate(@NotNull Vector direction, float distance, int durationInTicks, int delayInTicks) { if (distance == 0) return true; - for (PacketDisplayEntityPart part : groupParts.values()){ + for (PacketDisplayEntityPart part : groupParts.values()) { part.translate(direction, distance, durationInTicks, delayInTicks); } return true; @@ -1101,7 +1114,7 @@ public boolean translate(@NotNull Vector direction, float distance, int duration @Override public boolean translate(@NotNull Direction direction, float distance, int durationInTicks, int delayInTicks) { if (distance == 0) return true; - for (PacketDisplayEntityPart part : groupParts.values()){ + for (PacketDisplayEntityPart part : groupParts.values()) { part.translate(direction, distance, durationInTicks, delayInTicks); } return true; @@ -1109,7 +1122,7 @@ public boolean translate(@NotNull Direction direction, float distance, int durat @Override - public @NotNull DisplayEntityGroup toDisplayEntityGroup(){ + public @NotNull DisplayEntityGroup toDisplayEntityGroup() { return new DisplayEntityGroup(this); } @@ -1117,21 +1130,21 @@ public boolean translate(@NotNull Direction direction, float distance, int durat * Unregister this {@link PacketDisplayEntityGroup}, "despawning" it. This does not stop a persistent packet group from persisting in the future. * Use {@link DisplayGroupManager#removePersistentPacketGroup(PacketDisplayEntityGroup, boolean)} to unregister and stop persistence. */ - public void unregister(){ + public void unregister() { if (masterPart == null) return; removeScaleMultipliers(); String worldName = getWorldName(); - if (worldName != null){ + if (worldName != null) { WorldData data = allPacketGroups.get(worldName); - if (data != null){ + if (data != null) { Location groupLoc = getLocation(); - if (groupLoc != null){ + if (groupLoc != null) { long chunkKey = ConversionUtils.getChunkKey(groupLoc); data.removeGroup(chunkKey, this); } - if (data.isEmpty()){ + if (data.isEmpty()) { allPacketGroups.remove(worldName); } } @@ -1140,7 +1153,7 @@ public void unregister(){ passengerIds = null; Iterator iter = groupParts.values().iterator(); - while (iter.hasNext()){ + while (iter.hasNext()) { PacketDisplayEntityPart part = iter.next(); part.groupUnregisterRemove(); iter.remove(); @@ -1153,12 +1166,12 @@ public void unregister(){ static class WorldData extends AsyncGroupHolder { - PacketDisplayEntityGroup getGroup(long chunkKey, int localId){ - synchronized (super.lock){ + PacketDisplayEntityGroup getGroup(long chunkKey, int localId) { + synchronized (super.lock) { Set groups = getRawGroups(chunkKey); if (groups == null) return null; - for (PacketDisplayEntityGroup pdeg : groups){ - if (localId == pdeg.persistentLocalId){ + for (PacketDisplayEntityGroup pdeg : groups) { + if (localId == pdeg.persistentLocalId) { return pdeg; } } @@ -1167,5 +1180,6 @@ PacketDisplayEntityGroup getGroup(long chunkKey, int localId){ } } - private final static class PassengerGroupData extends AsyncGroupHolder {} + private final static class PassengerGroupData extends AsyncGroupHolder { + } } \ No newline at end of file From c8f4b81cf09f03310fbc628396ccfa7caff934bc Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 3 May 2026 01:05:18 -0500 Subject: [PATCH 27/55] Add ActivePartRegistry for holding parts by entityUUID and/or entityId. --- .../utils/DisplayEntities/ActivePart.java | 14 +++---- .../DisplayEntities/ActivePartRegistry.java | 39 +++++++++++++++++++ .../SpawnedDisplayEntityPart.java | 24 ++++++++++-- 3 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePartRegistry.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 a1bff6bb..633310f2 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{ - protected static final ConcurrentHashMap partsById = new ConcurrentHashMap<>(); + protected SpawnedDisplayEntityPart.PartType type; protected UUID partUUID; private int entityId; @@ -43,12 +43,12 @@ public abstract class ActivePart implements Active{ protected ActivePart(int entityId, boolean autoMap){ this.entityId = entityId; if (autoMap) { - partsById.put(entityId, this); + ActivePartRegistry.register(this); } } protected synchronized void unregister(){ - partsById.remove(entityId); + ActivePartRegistry.unregister(this); valid = false; } @@ -66,7 +66,7 @@ public boolean isValid(){ * @return an {@link ActivePart} or null */ public static @Nullable ActivePart getPart(int entityId){ - return partsById.get(entityId); + return ActivePartRegistry.getPart(entityId); } public boolean isAnimatingForPlayers(){ @@ -113,10 +113,8 @@ public int getEntityId(){ return entityId; } - protected synchronized void refreshEntityId(int newEntityId){ - partsById.remove(entityId); - entityId = newEntityId; - partsById.put(newEntityId, this); + void setEntityId(int entityId){ + this.entityId = entityId; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePartRegistry.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePartRegistry.java new file mode 100644 index 00000000..010cb642 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePartRegistry.java @@ -0,0 +1,39 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +class ActivePartRegistry { + + private static final ConcurrentHashMap partsByUUID = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap partsByEntityId = new ConcurrentHashMap<>(); + + static void register(ActivePart activePart){ + partsByEntityId.put(activePart.getEntityId(), activePart); + if (activePart instanceof SpawnedDisplayEntityPart spawnedPart){ + partsByUUID.put(spawnedPart.getEntity().getUniqueId(), spawnedPart); + } + } + + static void updateEntityId(SpawnedDisplayEntityPart spawnedPart, int newEntityId){ + partsByEntityId.remove(spawnedPart.getEntityId()); + spawnedPart.setEntityId(newEntityId); + partsByEntityId.put(newEntityId, spawnedPart); + + } + + static SpawnedDisplayEntityPart getPart(UUID entityUUID){ + return partsByUUID.get(entityUUID); + } + + static ActivePart getPart(int entityID){ + return partsByEntityId.get(entityID); + } + + static void unregister(ActivePart part){ + if (part instanceof SpawnedDisplayEntityPart sp){ + partsByUUID.remove(sp.getEntity().getUniqueId()); + } + partsByEntityId.remove(part.getEntityId()); + } +} 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 94c37ca3..768bcda2 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 @@ -101,7 +101,7 @@ private void applyData(Random random, Entity entity){ if (part != null && part.group != group){ part.remove(false); } - partsById.put(getEntityId(), this); + ActivePartRegistry.register(this); this.entityUUID = entity.getUniqueId(); @@ -251,7 +251,7 @@ public void refreshEntity(@NotNull Entity nonStaleEntity){ if (entity == nonStaleEntity) return; if (!nonStaleEntity.getUniqueId().equals(entityUUID)) return; entity = nonStaleEntity; - refreshEntityId(nonStaleEntity.getEntityId()); + ActivePartRegistry.updateEntityId(this, nonStaleEntity.getEntityId()); } /** @@ -270,7 +270,23 @@ public void refreshEntity(@NotNull Entity nonStaleEntity){ */ public static @Nullable SpawnedDisplayEntityPart getPart(@NotNull Entity entity){ if (!DisplayUtils.isPartEntity(entity)) return null; - return (SpawnedDisplayEntityPart) getPart(entity.getEntityId()); + SpawnedDisplayEntityPart part = getPart(entity.getUniqueId()); + if (part != null){ + int entityId = entity.getEntityId(); + if (part.getEntityId() != entityId){ + ActivePartRegistry.updateEntityId(part, entityId); + } + } + return part; + } + + /** + * Get the {@link SpawnedDisplayEntityPart} of an entity, during this play session, with its UUID. Use {@link #create(Entity)} if the part is not grouped. + * @param entityUUID the part entity's UUID + * @return a {@link SpawnedDisplayEntityPart} or null if not created during play session + */ + public static @Nullable SpawnedDisplayEntityPart getPart(@NotNull UUID entityUUID){ + return ActivePartRegistry.getPart(entityUUID); } @@ -1379,8 +1395,8 @@ Entity groupUnregisterRemove(boolean despawn){ entity.remove(); } } - this.entity = null; this.unregister(); + this.entity = null; return entity; } } From b5c0627c1b0b09076c39344a0b0707945b808d66 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 3 May 2026 01:06:13 -0500 Subject: [PATCH 28/55] Fix ridden (spawned) groups not staying on player when teleporting/changing worlds --- .../displayentityutils/DisplayAPI.java | 9 ++ .../SpawnedDisplayEntityGroup.java | 60 ++++++++++-- .../SpawnedDisplayEntityPart.java | 4 +- plugin/pom.xml | 11 +++ .../DisplayEntityPlugin.java | 1 + .../listeners/entity/DEUEntityListener.java | 94 +++++++++++++++++-- 6 files changed, 160 insertions(+), 19 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java index fc35e825..b090233f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java +++ b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java @@ -45,6 +45,7 @@ public final class DisplayAPI { static boolean isSkriptInstalled; static boolean isWorldEditInstalled; static boolean isPAPIInstalled; + static boolean isEssentialsInstalled; private static final String legacyPartTagPrefix = "deu.parttag_"; @@ -198,6 +199,14 @@ public static boolean isPAPIInstalled() { return isPAPIInstalled; } + /** + * Get whether EssentialsX is installed on this server + * @return true if EssentialsX is present + */ + public static boolean isEssentialsInstalled() { + return isEssentialsInstalled; + } + public static DisplayStorage getStorage(@NotNull LoadMethod method){ switch(method){ case LOCAL -> { 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 33452773..d5cfad7f 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 @@ -503,38 +503,80 @@ else if (part.type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ @Override public boolean teleport(@NotNull Location location, boolean respectGroupDirection){ + return teleport(location, respectGroupDirection, false); + } + + /** + * Change the true location of this group. + * @param location The location to teleport this group + * @param respectGroupDirection Whether to respect this group's pitch and yaw or the location's pitch and yaw + * @param force forcefully teleport this group, loading its chunk + * @return true if the teleport was successful + */ + public boolean teleport(@NotNull Location location, boolean respectGroupDirection, boolean force){ GroupTranslateEvent event = new GroupTranslateEvent(this, GroupTranslateEvent.GroupTranslateType.TELEPORT, location); Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()){ - return false; - } + if (event.isCancelled()) return false; - teleportWithoutEvent(location, respectGroupDirection); + teleportWithoutEvent(location, respectGroupDirection, force); return true; } - private void teleportWithoutEvent(Location location, boolean respectGroupDirection){ + private void teleportWithoutEvent(Location location, boolean respectGroupDirection, boolean forceChunkLoading){ Entity master = getMasterEntity(); Location oldMasterLoc = master.getLocation().clone(); + boolean sameWorld = location.getWorld().getName().equals(oldMasterLoc.getWorld().getName()); + Chunk chunk = forceChunkLoading ? oldMasterLoc.getChunk() : null; + + if (forceChunkLoading){ + chunk.addPluginChunkTicket(DisplayAPI.getPlugin()); + } + if (respectGroupDirection){ location.setPitch(oldMasterLoc.getPitch()); location.setYaw(oldMasterLoc.getYaw()); } Location lastLoc = master.getLocation(); + if (!sameWorld){ + for (SpawnedDisplayEntityPart part : groupParts.values()){ + if (part == masterPart) continue; + Entity e = part.getEntity(); + if (e == null) continue; + + master.removePassenger(e); + FoliaUtils.teleport(e, location); + } + } + FoliaUtils.teleport(master, location, TeleportFlag.EntityState.RETAIN_PASSENGERS); + DisplayGroupManager.updateSpawnedGroup(lastLoc, location, this); - for (SpawnedDisplayEntityPart part : this.getParts()){ - part.getEntity().setRotation(location.getYaw(), location.getPitch()); + for (SpawnedDisplayEntityPart part : groupParts.values()){ + Entity partEntity = part.getEntity(); + if (partEntity == null){ + continue; + } + + + partEntity.setRotation(location.getYaw(), location.getPitch()); //Non-Display TP if (!part.isDisplay()){ - Entity entity = part.getEntity(); - Vector vector = oldMasterLoc.toVector().subtract(entity.getLocation().toVector()); + Vector vector = oldMasterLoc.toVector().subtract(partEntity.getLocation().toVector()); Location tpLocation = location.clone().subtract(vector); FoliaUtils.teleport(part.getEntity(), tpLocation, TeleportFlag.EntityState.RETAIN_PASSENGERS); } + + if (!sameWorld){ + if (part == masterPart) continue; + master.addPassenger(partEntity); + } + } + + if (forceChunkLoading){ + chunk.removePluginChunkTicket(DisplayAPI.getPlugin()); } } 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 768bcda2..9b4d0fbb 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 @@ -2,6 +2,7 @@ import com.destroystokyo.paper.profile.PlayerProfile; import io.papermc.paper.datacomponent.item.ResolvableProfile; +import io.papermc.paper.entity.TeleportFlag; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.utils.Direction; import net.donnypz.displayentityutils.utils.DisplayUtils; @@ -11,6 +12,7 @@ import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.donnypz.displayentityutils.utils.version.folia.FoliaUtils; import net.kyori.adventure.text.Component; import org.bukkit.*; import org.bukkit.attribute.Attribute; @@ -197,7 +199,7 @@ public void teleport(@NotNull Location location) { return; } Entity e = getEntity(); - if (e != null) e.teleport(location); + if (e != null) FoliaUtils.teleport(e, location, TeleportFlag.EntityState.RETAIN_PASSENGERS); } @Override diff --git a/plugin/pom.xml b/plugin/pom.xml index 3ac660ec..a78f3de8 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -63,6 +63,10 @@ placeholderapi https://repo.extendedclip.com/releases/
+ + essentialsx + https://repo.essentialsx.net/releases/ +
@@ -117,6 +121,13 @@ provided + + net.essentialsx + EssentialsX + 2.21.2 + provided + + io.lumine Mythic-Dist diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index 405583f4..daea4a6b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -123,6 +123,7 @@ private void initializeDependencies(){ DisplayAPI.isViaVerInstalled = Bukkit.getPluginManager().isPluginEnabled("ViaVersion"); DisplayAPI.isWorldEditInstalled = Bukkit.getPluginManager().isPluginEnabled("WorldEdit"); DisplayAPI.isPAPIInstalled = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI"); + DisplayAPI.isEssentialsInstalled = Bukkit.getPluginManager().isPluginEnabled("Essentials"); //Skript DisplayAPI.isSkriptInstalled = Bukkit.getPluginManager().isPluginEnabled("Skript"); 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 65b2eb60..392af169 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 @@ -8,24 +8,37 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; 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 net.ess3.api.IUser; +import net.ess3.api.events.teleport.PreTeleportEvent; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.damage.DamageSource; import org.bukkit.damage.DamageType; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.*; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerTeleportEvent; import org.jetbrains.annotations.ApiStatus; +import java.util.HashMap; +import java.util.HashSet; +import java.util.UUID; + @ApiStatus.Internal public final class DEUEntityListener implements Listener { + private static final HashMap> passengerGroups = new HashMap<>(); + //============Mythic==================== @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntitySpawn(EntitySpawnEvent e){ @@ -98,24 +111,87 @@ public void onShootBow(EntityShootBowEvent e){ } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onTeleport(EntityTeleportEvent e){ + public void onTeleportMonitor(EntityTeleportEvent e){ Entity entity = e.getEntity(); - applyState(e.getEntity(), MachineState.StateType.TELEPORT); + applyState(entity, MachineState.StateType.TELEPORT); + if (!e.getTo().getWorld().equals(e.getFrom().getWorld())){ + SpawnedDisplayEntityPart.getPart(entity); //refresh entity ids + } + + } + + private void storeGroups(Player player){ + passengerGroups.computeIfAbsent(player.getUniqueId(), key -> new HashSet<>()); + HashSet groupsSet = passengerGroups.get(player.getUniqueId()); + + for (SpawnedDisplayEntityGroup group : DisplayUtils.getGroupPassengers(player)){ + group.dismount(); + groupsSet.add(group); + } + } + + + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onTeleport(PlayerTeleportEvent e){ Location fromLoc = e.getFrom(); Location toLoc = e.getTo(); + if (!fromLoc.getWorld().equals(toLoc.getWorld())){ + storeGroups(e.getPlayer()); + } + } - ActiveGroup controllerGroup = DisplayControllerManager.getControllerGroup(entity.getUniqueId()); - if (controllerGroup instanceof PacketDisplayEntityGroup pg){ - pg.teleport(toLoc, true); + + @EventHandler(priority = EventPriority.MONITOR) + public void onTPAcrossWorlds(PlayerChangedWorldEvent e){ + Player player = e.getPlayer(); + HashSet groups = passengerGroups.remove(player.getUniqueId()); + if (groups == null){ + return; } - if (!fromLoc.getWorld().equals(toLoc.getWorld())){ - for (PacketDisplayEntityGroup pg : PacketDisplayEntityGroup.getPassengerGroups(entity)){ - pg.hide(); //Hide for players in prev world - } + Location location = player.getLocation(); + for (SpawnedDisplayEntityGroup group : groups) { + group.teleport(location, true, true); + group.rideEntity(player); + } + } + + //Essentials--------------------------- + @EventHandler + public void onEssentialsPreTP(PreTeleportEvent e){ + IUser user = e.getTeleportee(); + UUID userUUID = user.getUUID(); + Player player = Bukkit.getPlayer(userUUID); + if (player == null) return; + + storeGroups(player); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onEssentialsPreTPCancelled(PreTeleportEvent e){ + if (e.isCancelled()){ + passengerGroups.remove(e.getTeleportee().getUUID()); + } + } + + //Eseentials Same World + @EventHandler(priority = EventPriority.MONITOR) + public void onTeleportMonitor(PlayerTeleportEvent e){ + if (!e.getTo().getWorld().equals(e.getFrom().getWorld())) return; //different worlds + Player player = e.getPlayer(); + HashSet groups = passengerGroups.remove(player.getUniqueId()); + if (groups == null) return; + + for (SpawnedDisplayEntityGroup group : groups){ + group.teleport(e.getTo(), true, true); + group.rideEntity(player); } } + //------------------------------------- + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onDeath(EntityDeathEvent e){ From 23c686f923126c355cb25c8214d1bbc18d5ff4b6 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 3 May 2026 01:06:42 -0500 Subject: [PATCH 29/55] 3.5.2-PRE-3 --- 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 44c8a651..84089488 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-2 + 3.5.2-PRE-3 api diff --git a/plugin/pom.xml b/plugin/pom.xml index a78f3de8..1e997f75 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-2 + 3.5.2-PRE-3 plugin diff --git a/pom.xml b/pom.xml index b4e8b62e..21a214a0 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-2 + 3.5.2-PRE-3 pom DisplayEntityUtils From e816e381d38f9c438f687744eea7ccbedccb981c Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 3 May 2026 01:16:45 -0500 Subject: [PATCH 30/55] Use java 25 for building --- .github/workflows/maven.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 9d6eacc5..1f6a3869 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -25,10 +25,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 21 + - name: Set up JDK 25 uses: actions/setup-java@v4 with: - java-version: '21' + java-version: '25' distribution: 'temurin' cache: maven - name: Build with Maven From 60cb8144fcc61389acdee123755fd50be846d632 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 5 May 2026 21:50:28 -0500 Subject: [PATCH 31/55] Save part entity's UUID in all constructors --- .../SpawnedDisplayEntityPart.java | 25 +++++++++---------- 1 file changed, 12 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 9b4d0fbb..e11b673c 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 @@ -43,30 +43,29 @@ public final class SpawnedDisplayEntityPart extends ActivePart implements Spawne private final boolean isSingle; SpawnedDisplayEntityPart(SpawnedDisplayEntityGroup group, Entity entity, Random random){ - super(entity.getEntityId(), false); - this.group = group; - this.entity = entity; - this.type = PartType.getType(entity); - + this(group, entity); applyData(random, entity); - if (isMaster()){ - group.masterPart = this; - } + if (isMaster()) group.masterPart = this; + partTags.addAll(DisplayUtils.getTags(entity)); + 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(), true); + this(null, entity); + this.partUUID = UUID.randomUUID(); + } + + private SpawnedDisplayEntityPart(SpawnedDisplayEntityGroup group, 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.group = group; this.entity = entity; this.entityUUID = entity.getUniqueId(); - this.partUUID = UUID.randomUUID(); - this.isSingle = true; + this.isSingle = group == null; } /** From 60f76021723d5d3bc4c7420d5d6d0e711064c977 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Tue, 5 May 2026 22:15:54 -0500 Subject: [PATCH 32/55] Add #setBlockReplacement and #setItemReplacement to GroupSpawnSettings --- .../DisplayEntities/GroupSpawnSettings.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) 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 be848b56..5288122d 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 @@ -8,7 +8,10 @@ import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.*; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,6 +33,18 @@ public class GroupSpawnSettings { Set visiblePlayers = new HashSet<>(); boolean hideInteractions = false; boolean playSpawnAnimation = true; + BlockReplacement blockReplacement; + ItemReplacement itemReplacement; + + public GroupSpawnSettings setBlockReplacement(BlockReplacement blockReplacement){ + this.blockReplacement = blockReplacement; + return this; + } + + public GroupSpawnSettings setItemReplacement(ItemReplacement itemReplacement){ + this.itemReplacement = itemReplacement; + return this; + } /** * Set the teleportation duration for all display entities that will be spawned from {@link DisplayEntityGroup#spawn(Location, GroupSpawnedEvent.SpawnReason, GroupSpawnSettings)}. @@ -208,6 +223,22 @@ public void applyAttributes(PacketDisplayEntityPart part){ } } } + + switch (part.type){ + case BLOCK_DISPLAY -> { + BlockData blockData = part.getBlockDisplayBlock(); + if (blockReplacement == null || !blockReplacement.hasReplacement(blockData)) return; + part.setBlockDisplayBlock(blockReplacement.getReplacement(blockData)); + } + case ITEM_DISPLAY -> { + ItemStack item = part.getItemDisplayItem(); + if (item == null) return; + Material material = item.getType(); + if (itemReplacement == null || !itemReplacement.hasReplacement(material)) return; + part.setItemDisplayItem(itemReplacement.getReplacement(material)); + } + default -> {} + } } } @@ -278,6 +309,20 @@ public void apply(Display display){ } } display.setPersistent(persistentByDefault); + + switch (display){ + case BlockDisplay bd -> { + BlockData blockData = bd.getBlock(); + if (blockReplacement == null || !blockReplacement.hasReplacement(blockData)) return; + bd.setBlock(blockReplacement.getReplacement(blockData)); + } + case ItemDisplay id -> { + Material material = id.getItemStack().getType(); + if (itemReplacement == null || !itemReplacement.hasReplacement(material)) return; + id.setItemStack(itemReplacement.getReplacement(material)); + } + default -> {} + } } /** @@ -357,4 +402,58 @@ private void reveal(Entity entity, String tag){ } } } + + protected abstract static sealed class Replacement> permits BlockReplacement, ItemReplacement{ + Map replaceMap = new HashMap<>(); + + /** + * Replace an object with another given object + * @param toReplace the object to replace + * @param replaceWIth the object to replace it with + * @return this + */ + public SELF replace(T toReplace, V replaceWIth){ + replaceMap.put(toReplace, replaceWIth); + return self(); + } + + /** + * Get whether a given object has a value to replace it with + * @param toReplace the object to be replaced + * @return a boolean + */ + public boolean hasReplacement(T toReplace){ + return replaceMap.containsKey(toReplace); + } + + /** + * Get the object that will replace the given object. + * The returned value can be null. + */ + public V getReplacement(T toReplace){ + return replaceMap.get(toReplace); + } + + protected abstract SELF self(); + } + + /** + * Holds blocks types to be replaced when spawning a group using {@link GroupSpawnSettings} + */ + public static final class BlockReplacement extends Replacement{ + @Override + protected BlockReplacement self() { + return this; + } + } + + /** + * Holds item types to be replaced when spawning a group using {@link GroupSpawnSettings} + */ + public static final class ItemReplacement extends Replacement{ + @Override + protected ItemReplacement self() { + return this; + } + } } From 83f82bda5b5d9286ee73e1bdd49be37fc1626c24 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 6 May 2026 04:57:45 -0500 Subject: [PATCH 33/55] Add allowDataChanges parameter to DisplayAnimators --- .../utils/DisplayEntities/ActiveGroup.java | 24 ++++++- .../DisplayEntities/AnimationPlayer.java | 6 +- .../DisplayEntities/DisplayAnimator.java | 70 +++++++++++++++++-- .../PacketDisplayEntityGroup.java | 11 +-- .../SpawnedDisplayEntityGroup.java | 10 ++- .../command/anim/AnimCMD.java | 5 +- .../command/anim/AnimPlayCMD.java | 19 +++-- 7 files changed, 114 insertions(+), 31 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 8938ce24..7bbe160c 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 @@ -799,7 +799,17 @@ public boolean hasAnimated(){ * @param animation the animation this group should play * @return the {@link DisplayAnimator} that will control the playing of the given animation */ - public abstract @NotNull DisplayAnimator animate(@NotNull SpawnedDisplayAnimation animation); + public @NotNull DisplayAnimator animate(@NotNull SpawnedDisplayAnimation animation){ + return animate(animation, true); + } + + /** + * Make a group perform an animation + * @param animation the animation this group should play + * @param allowDataChanges whether block/item display textures and text display text should change based on animation frame data + * @return the {@link DisplayAnimator} that will control the playing of the given animation + */ + public abstract @NotNull DisplayAnimator animate(@NotNull SpawnedDisplayAnimation animation, boolean allowDataChanges); /** @@ -807,7 +817,17 @@ public boolean hasAnimated(){ * @param animation the animation this group should play * @return the {@link DisplayAnimator} that will control the playing of the given animation */ - public abstract @NotNull DisplayAnimator animateLooping(@NotNull SpawnedDisplayAnimation animation); + public @NotNull DisplayAnimator animateLooping(@NotNull SpawnedDisplayAnimation animation){ + return animateLooping(animation, true); + } + + /** + * Make a group perform a looping animation. + * @param animation the animation this group should play + * @param allowDataChanges whether block/item display textures and text display text should change based on animation frame data + * @return the {@link DisplayAnimator} that will control the playing of the given animation + */ + public abstract @NotNull DisplayAnimator animateLooping(@NotNull SpawnedDisplayAnimation animation, boolean allowDataChanges); /** * Manually stop an animation from playing on this group 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 384859aa..38b8796f 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 @@ -400,7 +400,7 @@ private void applyDisplayTransformationWithPackets(Collection players, A } } - if (animation.allowsTextureChanges()) { + if (animator.allowDataChanges) { transformation.applyData(part); } } @@ -422,7 +422,7 @@ private void applyDisplayTransformation(ActivePart part, SpawnedDisplayAnimation Display display = (Display) sp.getEntity(); if (!display.isValid()) return; if (applyDataOnly) { - if (animation.allowsTextureChanges()) { + if (animator.allowDataChanges) { transformation.applyData(display); } return; @@ -456,7 +456,7 @@ private void applyDisplayTransformation(ActivePart part, SpawnedDisplayAnimation display.setTransformation(offsetTransformation); } - if (animation.allowsTextureChanges()) { + if (animator.allowDataChanges) { transformation.applyData(display); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimator.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimator.java index 8a985b50..c9a71878 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimator.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimator.java @@ -15,6 +15,7 @@ public class DisplayAnimator { final SpawnedDisplayAnimation animation; final AnimationType type; + final boolean allowDataChanges; private final ConcurrentHashMap> clientPlayers = new ConcurrentHashMap<>(); private final Object clientPlayerLock = new Object(); private static final int DEFAULT_START_DELAY = 0; @@ -22,13 +23,25 @@ public class DisplayAnimator { /** * Create a display animator that manages playing and stopping animations for {@link ActiveGroup}s. - * A single instance CAN be used for multiple groups. For managing animation states, see {@link DisplayStateMachine} + * A single instance CAN be used for multiple groups. For managing animation states, see {@link DisplayStateMachine} * @param animation the animation * @param type the animation play type */ public DisplayAnimator(@NotNull SpawnedDisplayAnimation animation, @NotNull AnimationType type){ + this(animation, type, true); + } + + /** + * Create a display animator that manages playing and stopping animations for {@link ActiveGroup}s. + * A single instance CAN be used for multiple groups. For managing animation states, see {@link DisplayStateMachine} + * @param animation the animation + * @param type the animation play type + * @param allowDataChanges whether block/item display textures and text display text should change based on animation frame data + */ + public DisplayAnimator(@NotNull SpawnedDisplayAnimation animation, @NotNull AnimationType type, boolean allowDataChanges){ this.animation = animation; this.type = type; + this.allowDataChanges = allowDataChanges; } /** @@ -39,7 +52,19 @@ public DisplayAnimator(@NotNull SpawnedDisplayAnimation animation, @NotNull Anim * @return the {@link DisplayAnimator} used to control the animation */ public static DisplayAnimator play(@NotNull SpawnedDisplayEntityGroup group, @NotNull SpawnedDisplayAnimation animation, @NotNull AnimationType animationType){ - DisplayAnimator animator = new DisplayAnimator(animation, animationType); + return play(group, animation, animationType, true); + } + + /** + * Plays an animation once for a {@link SpawnedDisplayEntityGroup}. + * @param group The group to play the animation + * @param animation The animation to play + * @param animationType the animation type + * @param allowDataChanges whether block/item display textures and text display text should change based on animation frame data + * @return the {@link DisplayAnimator} used to control the animation + */ + public static DisplayAnimator play(@NotNull SpawnedDisplayEntityGroup group, @NotNull SpawnedDisplayAnimation animation, @NotNull AnimationType animationType, boolean allowDataChanges){ + DisplayAnimator animator = new DisplayAnimator(animation, animationType, allowDataChanges); animator.play(group, 0); return animator; } @@ -53,7 +78,20 @@ public static DisplayAnimator play(@NotNull SpawnedDisplayEntityGroup group, @No * @return the {@link DisplayAnimator} used to control the animation */ public static DisplayAnimator play(@NotNull Player player, @NotNull ActiveGroup group, @NotNull SpawnedDisplayAnimation animation, @NotNull AnimationType animationType){ - return play(List.of(player), group, animation, animationType); + return play(List.of(player), group, animation, animationType, true); + } + + /** + * Plays an animation once for a {@link ActiveGroup} for a specified player. + * @param player the player to play the animation for + * @param group the group + * @param animation the animation to be played + * @param animationType the animation type + * @param allowDataChanges whether block/item display textures and text display text should change based on animation frame data + * @return the {@link DisplayAnimator} used to control the animation + */ + public static DisplayAnimator play(@NotNull Player player, @NotNull ActiveGroup group, @NotNull SpawnedDisplayAnimation animation, @NotNull AnimationType animationType, boolean allowDataChanges){ + return play(List.of(player), group, animation, animationType, allowDataChanges); } /** @@ -62,10 +100,11 @@ public static DisplayAnimator play(@NotNull Player player, @NotNull ActiveGroup< * @param group the group * @param animation the animation to be played * @param animationType the animation type + * @param allowDataChanges whether block/item display textures and text display text should change based on animation frame data * @return the {@link DisplayAnimator} used to control the animation */ - public static DisplayAnimator play(@NotNull Collection players, @NotNull ActiveGroup group, @NotNull SpawnedDisplayAnimation animation, @NotNull AnimationType animationType){ - DisplayAnimator animator = new DisplayAnimator(animation, animationType); + public static DisplayAnimator play(@NotNull Collection players, @NotNull ActiveGroup group, @NotNull SpawnedDisplayAnimation animation, @NotNull AnimationType animationType, boolean allowDataChanges){ + DisplayAnimator animator = new DisplayAnimator(animation, animationType, allowDataChanges); animator.play(players, group, 0); return animator; } @@ -78,6 +117,18 @@ public static DisplayAnimator play(@NotNull Collection players, @NotNull * @return the {@link DisplayAnimator} used to play the animation */ public static DisplayAnimator playUsingPackets(@NotNull ActiveGroup group, @NotNull SpawnedDisplayAnimation animation, @NotNull AnimationType animationType){ + return playUsingPackets(group, animation, animationType, true); + } + + /** + * Plays an animation once for a {@link ActiveGroup} without the use of a {@link DisplayAnimator} instance. + * To control an animation, pausing/playing/looping, create a new {@link DisplayAnimator}. + * @param group The group to play the animation + * @param animation The animation to play + * @param allowDataChanges whether block/item display textures and text display text should change based on animation frame data + * @return the {@link DisplayAnimator} used to play the animation + */ + public static DisplayAnimator playUsingPackets(@NotNull ActiveGroup group, @NotNull SpawnedDisplayAnimation animation, @NotNull AnimationType animationType, boolean allowDataChanges){ DisplayAnimator animator = new DisplayAnimator(animation, animationType); animator.playUsingPackets(group, 0); return animator; @@ -415,7 +466,6 @@ public boolean isAnimating(@NotNull ActiveGroup group){ return group.isActiveAnimator(this); } - /** * Get the {@link SpawnedDisplayAnimation} that this animator uses on groups * @return a {@link SpawnedDisplayAnimation} @@ -432,6 +482,14 @@ public boolean isAnimating(@NotNull ActiveGroup group){ return type; } + /** + * Get whether this animator allows block/item display textures and text display text to change based on animation frame data + * @return a boolean + */ + public boolean allowDataChanges(){ + return allowDataChanges; + } + public enum AnimationType{ LINEAR, 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 41b66d68..3f0799e8 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 @@ -400,13 +400,14 @@ else if (scaleNonDisplays) { return true; } - - public @NotNull DisplayAnimator animate(@NotNull SpawnedDisplayAnimation animation) { - return DisplayAnimator.playUsingPackets(this, animation, DisplayAnimator.AnimationType.LINEAR); + @Override + public @NotNull DisplayAnimator animate(@NotNull SpawnedDisplayAnimation animation, boolean allowDataChanges) { + return DisplayAnimator.playUsingPackets(this, animation, DisplayAnimator.AnimationType.LINEAR, allowDataChanges); } - public @NotNull DisplayAnimator animateLooping(@NotNull SpawnedDisplayAnimation animation) { - return DisplayAnimator.playUsingPackets(this, animation, DisplayAnimator.AnimationType.LOOP); + @Override + public @NotNull DisplayAnimator animateLooping(@NotNull SpawnedDisplayAnimation animation, boolean allowDataChanges) { + return DisplayAnimator.playUsingPackets(this, animation, DisplayAnimator.AnimationType.LOOP, allowDataChanges); } 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 d5cfad7f..70b74806 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 @@ -1086,16 +1086,14 @@ public void unsetSpawnAnimation(){ @Override - public @NotNull DisplayAnimator animate(@NotNull SpawnedDisplayAnimation animation){ - return DisplayAnimator.play(this, animation, DisplayAnimator.AnimationType.LINEAR); + public @NotNull DisplayAnimator animate(@NotNull SpawnedDisplayAnimation animation, boolean allowDataChange){ + return DisplayAnimator.play(this, animation, DisplayAnimator.AnimationType.LINEAR, allowDataChange); } @Override - public @NotNull DisplayAnimator animateLooping(@NotNull SpawnedDisplayAnimation animation){ - DisplayAnimator animator = new DisplayAnimator(animation, DisplayAnimator.AnimationType.LOOP); - animator.play(this, 0); - return animator; + public @NotNull DisplayAnimator animateLooping(@NotNull SpawnedDisplayAnimation animation, boolean allowDataChange){ + return DisplayAnimator.play(this, animation, DisplayAnimator.AnimationType.LOOP, allowDataChange); } /** diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimCMD.java index 57c9bb18..fe86c015 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimCMD.java @@ -118,10 +118,11 @@ else if (page == 5){ CMDUtils.sendCMD(sender, "/deu anim toggletexturechanges", "Toggle whether your selected animation can change block display blocks, item display items, and text display text"); CMDUtils.sendCMD(sender, "/deu anim showframe ", "Displays a frame on your selected group"); CMDUtils.sendCMD(sender, "/deu anim previewframe ", "Preview a frame on your selected group, without changing group entity data"); - CMDUtils.sendCMD(sender, "/deu anim play [-loop] [-packet] [-camera]", "Play your selected animation on your selected group." + + CMDUtils.sendCMD(sender, "/deu anim play [-loop] [-packet] [-camera] [-nodata]", "Play your selected animation on your selected group." + " \n\"-loop\" will make the animation loop." + " \n\"-packet\" will play the animation using packets." + - " \n\"-camera\" will set your view to the animation's camera, if present"); + " \n\"-camera\" will set your view to the animation's camera, if present" + + " \n\"-nodata\" will disable texture changes for item/block displays and text display text changes"); CMDUtils.sendCMD(sender, "/deu anim listanims", "List the animations actively playing for a group"); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimPlayCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimPlayCMD.java index e818a620..5b01b0e4 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimPlayCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimPlayCMD.java @@ -20,9 +20,10 @@ class AnimPlayCMD extends PlayerSubCommand { AnimPlayCMD(@NotNull DEUSubCommand parentSubCommand) { super("play", parentSubCommand, Permission.ANIM_PLAY); - setTabComplete(2, List.of("-loop", "-packet", "-camera")); - setTabComplete(3, List.of("-loop", "-packet", "-camera")); - setTabComplete(4, List.of("-loop", "-packet", "-camera")); + setTabComplete(2, List.of("-loop", "-packet", "-camera", "-nodata")); + setTabComplete(3, List.of("-loop", "-packet", "-camera", "-nodata")); + setTabComplete(4, List.of("-loop", "-packet", "-camera", "-nodata")); + setTabComplete(5, List.of("-loop", "-packet", "-camera", "-nodata")); } @Override @@ -51,6 +52,7 @@ public void execute(Player player, String[] args) { DisplayAnimator.AnimationType animationType = DisplayAnimator.AnimationType.LINEAR; boolean packet = false; boolean camera = false; + boolean dataChange = true; Component optionResult = Component.empty(); for (int i = 2; i < args.length; i++){ String arg = args[i]; @@ -66,22 +68,25 @@ else if (arg.equalsIgnoreCase("-camera") && !camera){ camera = true; optionResult.append(Component.text(" (CAMERA VIEW)", NamedTextColor.AQUA)); } + else if (arg.equalsIgnoreCase("-nodata")){ + dataChange = false; + } } if (animationType == DisplayAnimator.AnimationType.LOOP){ if (packet){ - DisplayAnimator.playUsingPackets(group, anim, DisplayAnimator.AnimationType.LOOP); + DisplayAnimator.playUsingPackets(group, anim, DisplayAnimator.AnimationType.LOOP, dataChange); } else{ - group.animateLooping(anim); + group.animateLooping(anim, dataChange); } } else{ if (packet){ - DisplayAnimator.playUsingPackets(group, anim, DisplayAnimator.AnimationType.LINEAR); + DisplayAnimator.playUsingPackets(group, anim, DisplayAnimator.AnimationType.LINEAR, dataChange); } else{ - group.animate(anim); + group.animate(anim, dataChange); } } if (camera){ From b085bb7eeb5ab53c1a4a02eb5d83be9b8bdbc665 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 6 May 2026 19:25:21 -0500 Subject: [PATCH 34/55] Move reading of DisplayController to DisplayControllerReader --- .../utils/controller/DisplayController.java | 263 +---------------- .../controller/DisplayControllerReader.java | 269 ++++++++++++++++++ 2 files changed, 273 insertions(+), 259 deletions(-) create mode 100644 api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayControllerReader.java 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 958e917d..516a4845 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 @@ -8,13 +8,8 @@ import net.donnypz.displayentityutils.managers.LoadMethod; import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.donnypz.displayentityutils.utils.DisplayEntities.machine.DisplayStateMachine; -import net.donnypz.displayentityutils.utils.DisplayEntities.machine.MachineState; -import net.donnypz.displayentityutils.utils.FollowType; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; import org.bukkit.persistence.PersistentDataContainer; @@ -31,7 +26,7 @@ public class DisplayController { - private static final HashMap controllers = new HashMap<>();//Controller ID, Controller + static final HashMap controllers = new HashMap<>();//Controller ID, Controller static final HashMap grouplessControllers = new HashMap<>(); String controllerID; @@ -377,15 +372,13 @@ private void startFollowersAndMachine(Entity entity, ActiveGroup activeGroup) } } - /** * Read a controller's configuration from a file * @param file * @return a {@link DisplayController} or null */ public static @Nullable DisplayController read(@NotNull File file){ - return read(YamlConfiguration.loadConfiguration(file), file.getName(), true); - //String fileName = file.getName().split(".yml")[0]; + return DisplayControllerReader.read(YamlConfiguration.loadConfiguration(file), file.getName(), true); } @@ -401,7 +394,7 @@ private void startFollowersAndMachine(Entity entity, ActiveGroup activeGroup) return null; } InputStreamReader reader = new InputStreamReader(controllerStream); - return read(YamlConfiguration.loadConfiguration(reader), resourcePath+" | FROM RESOURCES ("+plugin.getName()+")", false); + return DisplayControllerReader.read(YamlConfiguration.loadConfiguration(reader), resourcePath+" | FROM RESOURCES ("+plugin.getName()+")", false); } /** @@ -411,254 +404,6 @@ private void startFollowersAndMachine(Entity entity, ActiveGroup activeGroup) */ public static @Nullable DisplayController read(@NotNull InputStream stream){ InputStreamReader reader = new InputStreamReader(stream); - return read(YamlConfiguration.loadConfiguration(reader), "Unknown controller from an InputStream...", false); - } - - private static DisplayController read(YamlConfiguration config, String fileName, boolean fromFile){ - try{ - String controllerID = config.getString("controllerID"); - if (controllerID == null){ - Bukkit.getLogger().severe("Missing \"controllerID\" for display controller: "+fileName); - return null; - } - - DisplayController controller; - controller = controllers.getOrDefault(controllerID, new DisplayController(controllerID)); - if (fromFile){ - controller.configController = true; - } - - //Set Mythic Mobs - ConfigurationSection mythicSect = config.getConfigurationSection("mythicMobs"); - List mobs = mythicSect.getStringList("mobs"); - controller.setMythicMobs(mobs); - - //Group Properties - ConfigurationSection createdGroupSect = mythicSect.getConfigurationSection("group"); - String groupTag = createdGroupSect.getString("tag"); - controller.isPacketBased = createdGroupSect.getBoolean("packetBased", false); - boolean flip; - - ConfigurationSection groupProp = config.getConfigurationSection("groupProperties"); - if (groupProp != null){ - //before added vector offset - if (groupProp.contains("verticalOffset")){ - controller.rideOffset = new Vector(0, groupProp.getDouble("verticalOffset"), 0); - Bukkit.getLogger().warning("\"verticalOffset\" is outdated but will still function for display controller: "+fileName+". " + - "See new examplecontroller on GitHub for new \"offset\"'s formatting in any direction."); - } - else if (groupProp.contains("offset")){ - ConfigurationSection offsetSect = groupProp.getConfigurationSection("offset"); - double x = offsetSect.getDouble("x"); - double y = offsetSect.getDouble("y"); - double z = offsetSect.getDouble("z"); - controller.rideOffset = new Vector(x,y,z); - } - - controller.groupVisibleByDefault = groupProp.getBoolean("visibleByDefault", true); - flip = groupProp.getBoolean("flip", false); - } - else{ - flip = false; - Bukkit.getLogger().warning("Missing section \"groupProperties\" for outdated display controller: "+fileName+"."); - } - - //LoadMethod - try{ //Set with Config - LoadMethod method = LoadMethod.valueOf(createdGroupSect.getString("storage").toUpperCase()); - controller.setDisplayEntityGroup(groupTag, method); - } - //Mark Null Loader - catch(IllegalArgumentException e){ //Set with API Event - if (controller.group == null){ - grouplessControllers.put(controller, groupTag); - } - } - - ConfigurationSection defaultPropsSection = config.getConfigurationSection("defaultFollowProperties"); - int deathDespawnDelay = defaultPropsSection.getInt("deathDespawnDelay"); - - HashSet propertiesToRemove = new HashSet<>(controller.followProperties.keySet()); - - //Default Follow Properties - configureDefaultProperties(controller, defaultPropsSection, deathDespawnDelay, flip); - propertiesToRemove.remove(null); - - - //Part Follow Properties - List> partFollowMaps = config.getMapList("partFollowProperties"); - if (!partFollowMaps.isEmpty()){ - for (Map map : partFollowMaps){ - String followPropertyID = (String) map.get("id"); - GroupFollowProperties props = configurePartProperties(controller, followPropertyID, (Map) map, deathDespawnDelay, flip); - if (props != null){ - propertiesToRemove.remove(followPropertyID); - } - } - } - - //Remove old properties that weren't included in the plugin reload - for (String propID : propertiesToRemove){ - controller.followProperties.remove(propID); - } - - //Animation States - ConfigurationSection stateSect = config.getConfigurationSection("states"); - if (stateSect != null){ - DisplayStateMachine machine = new DisplayStateMachine(controllerID); - for (MachineState.StateType stateType : MachineState.StateType.values()){ - if (stateSect.contains(stateType.getStateID())){ - addState(controller, machine, stateType, stateSect.getConfigurationSection(stateType.getStateID())); - } - } - controller.setStateMachine(machine); - } - - if (!controller.isMarkedNull()){ - controller.register(); - } - else{ - Bukkit.getLogger().info("Null Group/Animation Display Controller must be handled through API: "+fileName); - } - return controller; - } - catch(Exception e){ - Bukkit.getLogger().severe("Misconfigured Display Controller: "+fileName); - e.printStackTrace(); - return null; - } - } - - private static GroupFollowProperties configureDefaultProperties(DisplayController controller, ConfigurationSection section, int deathDespawnDelay, boolean flip){ - FollowType followType = null; - try{ - followType = FollowType.valueOf(section.getString("followType")); - } catch(IllegalArgumentException followingDisabled){} - - int teleportationDuration = section.getInt("teleportationDuration"); - boolean pivotInteractions = section.getBoolean("pivotInteractions"); - boolean adjustDisplays = section.getBoolean("adjustDisplays.enabled"); - double yDisplayAdjustPercentage = section.getDouble("adjustDisplays.yDisplayAdjustPercentage"); - double zDisplayAdjustPercentage = section.getDouble("adjustDisplays.zDisplayAdjustPercentage"); - - GroupFollowProperties followProperties; - followProperties = controller.followProperties.getOrDefault(null, new GroupFollowProperties()); - - //Set Fields - followProperties.followType = followType; - followProperties.unregisterDelay = deathDespawnDelay; - followProperties.teleportationDuration = teleportationDuration; - followProperties.pivotInteractions = pivotInteractions; - followProperties.adjustDisplays = adjustDisplays; - followProperties.yDisplayAdjustPercentage = (float) yDisplayAdjustPercentage; - followProperties.zDisplayAdjustPercentage = (float) zDisplayAdjustPercentage; - followProperties.flip = flip; - - followProperties.filteredStates.clear(); - if (section.contains("stateFilter")){ - ConfigurationSection stateSect = section.getConfigurationSection("stateFilter"); - for (String state : stateSect.getStringList("states")){ - followProperties.addFilterState(state); - } - followProperties.filterBlacklist = stateSect.getBoolean("blacklist", true); - } - - controller.addFollowProperty(followProperties); - return followProperties; - } - - private static GroupFollowProperties configurePartProperties(DisplayController controller, String id, Map map, int deathDespawnDelay, boolean flip){ - List partTags = (List) map.get("partTags"); - if (partTags.isEmpty()){ - Bukkit.getConsoleSender().sendMessage(Component.text("Failed to find part tags for part follow property. It will be skipped: "+id, NamedTextColor.YELLOW)); - return null; - } - - FollowType followType = null; - try{ - followType = FollowType.valueOf((String) map.get("followType")); - } catch(IllegalArgumentException followingDisabled){} - - int teleportationDuration = (int) map.get("teleportationDuration"); - boolean pivotInteractions = (boolean) map.get("pivotInteractions"); - - Map adjustSect = (Map) map.get("adjustDisplays"); - boolean adjustDisplays; - float yDisplayAdjustPercentage; - float zDisplayAdjustPercentage; - - if (adjustSect != null){ - adjustDisplays = (boolean) adjustSect.getOrDefault("enabled", false); - yDisplayAdjustPercentage = ((Number) adjustSect.getOrDefault("yDisplayAdjustPercentage", 100f)).floatValue(); - zDisplayAdjustPercentage = ((Number) adjustSect.getOrDefault("zDisplayAdjustPercentage", 100f)).floatValue(); - } - else{ - adjustDisplays = false; - yDisplayAdjustPercentage = 100f; - zDisplayAdjustPercentage = 100f; - } - - GroupFollowProperties followProperties = controller.followProperties.getOrDefault(id, new GroupFollowProperties()); - followProperties.id = id; - followProperties.partTags = new HashSet<>(partTags); - followProperties.followType = followType; - followProperties.unregisterDelay = deathDespawnDelay; - followProperties.teleportationDuration = teleportationDuration; - followProperties.pivotInteractions = pivotInteractions; - followProperties.adjustDisplays = adjustDisplays; - followProperties.yDisplayAdjustPercentage = yDisplayAdjustPercentage; - followProperties.zDisplayAdjustPercentage = zDisplayAdjustPercentage; - followProperties.flip = flip; - - followProperties.filteredStates.clear(); - Map stateSect = (Map) map.get("stateFilter"); - if (stateSect != null){ - for (String state : (List) stateSect.getOrDefault("states", new ArrayList<>())){ - followProperties.addFilterState(state); - } - followProperties.filterBlacklist = (boolean) stateSect.getOrDefault("blacklist", true); - } - - controller.addFollowProperty(followProperties); - return followProperties; - } - - - private static void addState(DisplayController controller, DisplayStateMachine machine, MachineState.StateType stateType, ConfigurationSection section){ - List animations = section.getStringList("animations"); - //Get Load Method - LoadMethod loadMethod = null; - try{ - loadMethod = LoadMethod.valueOf(section.getString("storage").toUpperCase()); - } catch(IllegalArgumentException | NullPointerException e){} - - //Get Animation Type - DisplayAnimator.AnimationType animType; - try{ - animType = DisplayAnimator.AnimationType.valueOf(section.getString("animationType").toUpperCase()); - } - catch(IllegalArgumentException | NullPointerException e){ - animType = DisplayAnimator.AnimationType.LINEAR; //Default - } - - boolean lock = section.getBoolean("lockTransition"); - MachineState state = new MachineState(machine, stateType.getStateID(), animations, loadMethod, animType, lock); - if (!state.hasDisplayAnimators() && !state.isNullLoader()){ - if (!controller.controllerID.equalsIgnoreCase("example")){ - Bukkit.getLogger().warning("Failed to add state, \""+stateType.getStateID()+"\". No animations found: ["+machine.getId()+"]"); - } - return; - } - - machine.addState(state); - switch(stateType){ - case SPAWN, DEATH -> { - state.ignoreOtherTransitionLocks(); - } - case MELEE -> { - state.setCauseDelay(section.getInt("damageDelay")); - state.setMaxRange((float) section.getDouble("maxRange")); - } - } + return DisplayControllerReader.read(YamlConfiguration.loadConfiguration(reader), "Unknown controller from an InputStream...", false); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayControllerReader.java b/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayControllerReader.java new file mode 100644 index 00000000..2546cf4f --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayControllerReader.java @@ -0,0 +1,269 @@ +package net.donnypz.displayentityutils.utils.controller; + +import net.donnypz.displayentityutils.managers.LoadMethod; +import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimator; +import net.donnypz.displayentityutils.utils.DisplayEntities.machine.DisplayStateMachine; +import net.donnypz.displayentityutils.utils.DisplayEntities.machine.MachineState; +import net.donnypz.displayentityutils.utils.FollowType; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.util.Vector; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +class DisplayControllerReader { + + static DisplayController read(YamlConfiguration config, String fileName, boolean fromFile){ + try{ + String controllerID = config.getString("controllerID"); + if (controllerID == null){ + Bukkit.getLogger().severe("Missing \"controllerID\" for display controller: "+fileName); + return null; + } + + DisplayController controller; + controller = DisplayController.controllers.getOrDefault(controllerID, new DisplayController(controllerID)); + if (fromFile){ + controller.configController = true; + } + + //Set Mythic Mobs + ConfigurationSection mythicSect = config.getConfigurationSection("mythicMobs"); + List mobs = mythicSect.getStringList("mobs"); + controller.setMythicMobs(mobs); + + //Group Properties + ConfigurationSection createdGroupSect = mythicSect.getConfigurationSection("group"); + String groupTag = createdGroupSect.getString("tag"); + controller.isPacketBased = createdGroupSect.getBoolean("packetBased", false); + boolean flip; + + ConfigurationSection groupProp = config.getConfigurationSection("groupProperties"); + if (groupProp != null){ + //before added vector offset + if (groupProp.contains("verticalOffset")){ + controller.rideOffset = new Vector(0, groupProp.getDouble("verticalOffset"), 0); + Bukkit.getLogger().warning("\"verticalOffset\" is outdated but will still function for display controller: "+fileName+". " + + "See new examplecontroller on GitHub for new \"offset\"'s formatting in any direction."); + } + else if (groupProp.contains("offset")){ + ConfigurationSection offsetSect = groupProp.getConfigurationSection("offset"); + double x = offsetSect.getDouble("x"); + double y = offsetSect.getDouble("y"); + double z = offsetSect.getDouble("z"); + controller.rideOffset = new Vector(x,y,z); + } + + controller.groupVisibleByDefault = groupProp.getBoolean("visibleByDefault", true); + flip = groupProp.getBoolean("flip", false); + } + else{ + flip = false; + Bukkit.getLogger().warning("Missing section \"groupProperties\" for outdated display controller: "+fileName+"."); + } + + //LoadMethod + try{ //Set with Config + LoadMethod method = LoadMethod.valueOf(createdGroupSect.getString("storage").toUpperCase()); + controller.setDisplayEntityGroup(groupTag, method); + } + //Mark Null Loader + catch(IllegalArgumentException e){ //Set with API Event + if (controller.group == null){ + DisplayController.grouplessControllers.put(controller, groupTag); + } + } + + ConfigurationSection defaultPropsSection = config.getConfigurationSection("defaultFollowProperties"); + int deathDespawnDelay = defaultPropsSection.getInt("deathDespawnDelay"); + + HashSet propertiesToRemove = new HashSet<>(controller.followProperties.keySet()); + + //Default Follow Properties + configureDefaultProperties(controller, defaultPropsSection, deathDespawnDelay, flip); + propertiesToRemove.remove(null); + + + //Part Follow Properties + List> partFollowMaps = config.getMapList("partFollowProperties"); + if (!partFollowMaps.isEmpty()){ + for (Map map : partFollowMaps){ + String followPropertyID = (String) map.get("id"); + GroupFollowProperties props = configurePartProperties(controller, followPropertyID, (Map) map, deathDespawnDelay, flip); + if (props != null){ + propertiesToRemove.remove(followPropertyID); + } + } + } + + //Remove old properties that weren't included in the plugin reload + for (String propID : propertiesToRemove){ + controller.followProperties.remove(propID); + } + + //Animation States + ConfigurationSection stateSect = config.getConfigurationSection("states"); + if (stateSect != null){ + DisplayStateMachine machine = new DisplayStateMachine(controllerID); + for (MachineState.StateType stateType : MachineState.StateType.values()){ + if (stateSect.contains(stateType.getStateID())){ + addState(controller, machine, stateType, stateSect.getConfigurationSection(stateType.getStateID())); + } + } + controller.setStateMachine(machine); + } + + if (!controller.isMarkedNull()){ + controller.register(); + } + else{ + Bukkit.getLogger().info("Null Group/Animation Display Controller must be handled through API: "+fileName); + } + return controller; + } + catch(Exception e){ + Bukkit.getLogger().severe("Misconfigured Display Controller: "+fileName); + e.printStackTrace(); + return null; + } + } + + private static GroupFollowProperties configureDefaultProperties(DisplayController controller, ConfigurationSection section, int deathDespawnDelay, boolean flip){ + FollowType followType = null; + try{ + followType = FollowType.valueOf(section.getString("followType")); + } catch(IllegalArgumentException followingDisabled){} + + int teleportationDuration = section.getInt("teleportationDuration"); + boolean pivotInteractions = section.getBoolean("pivotInteractions"); + boolean adjustDisplays = section.getBoolean("adjustDisplays.enabled"); + double yDisplayAdjustPercentage = section.getDouble("adjustDisplays.yDisplayAdjustPercentage"); + double zDisplayAdjustPercentage = section.getDouble("adjustDisplays.zDisplayAdjustPercentage"); + + GroupFollowProperties followProperties; + followProperties = controller.followProperties.getOrDefault(null, new GroupFollowProperties()); + + //Set Fields + followProperties.followType = followType; + followProperties.unregisterDelay = deathDespawnDelay; + followProperties.teleportationDuration = teleportationDuration; + followProperties.pivotInteractions = pivotInteractions; + followProperties.adjustDisplays = adjustDisplays; + followProperties.yDisplayAdjustPercentage = (float) yDisplayAdjustPercentage; + followProperties.zDisplayAdjustPercentage = (float) zDisplayAdjustPercentage; + followProperties.flip = flip; + + followProperties.filteredStates.clear(); + if (section.contains("stateFilter")){ + ConfigurationSection stateSect = section.getConfigurationSection("stateFilter"); + for (String state : stateSect.getStringList("states")){ + followProperties.addFilterState(state); + } + followProperties.filterBlacklist = stateSect.getBoolean("blacklist", true); + } + + controller.addFollowProperty(followProperties); + return followProperties; + } + + private static GroupFollowProperties configurePartProperties(DisplayController controller, String id, Map map, int deathDespawnDelay, boolean flip){ + List partTags = (List) map.get("partTags"); + if (partTags.isEmpty()){ + Bukkit.getConsoleSender().sendMessage(Component.text("Failed to find part tags for part follow property. It will be skipped: "+id, NamedTextColor.YELLOW)); + return null; + } + + FollowType followType = null; + try{ + followType = FollowType.valueOf((String) map.get("followType")); + } catch(IllegalArgumentException followingDisabled){} + + int teleportationDuration = (int) map.get("teleportationDuration"); + boolean pivotInteractions = (boolean) map.get("pivotInteractions"); + + Map adjustSect = (Map) map.get("adjustDisplays"); + boolean adjustDisplays; + float yDisplayAdjustPercentage; + float zDisplayAdjustPercentage; + + if (adjustSect != null){ + adjustDisplays = (boolean) adjustSect.getOrDefault("enabled", false); + yDisplayAdjustPercentage = ((Number) adjustSect.getOrDefault("yDisplayAdjustPercentage", 100f)).floatValue(); + zDisplayAdjustPercentage = ((Number) adjustSect.getOrDefault("zDisplayAdjustPercentage", 100f)).floatValue(); + } + else{ + adjustDisplays = false; + yDisplayAdjustPercentage = 100f; + zDisplayAdjustPercentage = 100f; + } + + GroupFollowProperties followProperties = controller.followProperties.getOrDefault(id, new GroupFollowProperties()); + followProperties.id = id; + followProperties.partTags = new HashSet<>(partTags); + followProperties.followType = followType; + followProperties.unregisterDelay = deathDespawnDelay; + followProperties.teleportationDuration = teleportationDuration; + followProperties.pivotInteractions = pivotInteractions; + followProperties.adjustDisplays = adjustDisplays; + followProperties.yDisplayAdjustPercentage = yDisplayAdjustPercentage; + followProperties.zDisplayAdjustPercentage = zDisplayAdjustPercentage; + followProperties.flip = flip; + + followProperties.filteredStates.clear(); + Map stateSect = (Map) map.get("stateFilter"); + if (stateSect != null){ + for (String state : (List) stateSect.getOrDefault("states", new ArrayList<>())){ + followProperties.addFilterState(state); + } + followProperties.filterBlacklist = (boolean) stateSect.getOrDefault("blacklist", true); + } + + controller.addFollowProperty(followProperties); + return followProperties; + } + + + private static void addState(DisplayController controller, DisplayStateMachine machine, MachineState.StateType stateType, ConfigurationSection section){ + List animations = section.getStringList("animations"); + //Get Load Method + LoadMethod loadMethod = null; + try{ + loadMethod = LoadMethod.valueOf(section.getString("storage").toUpperCase()); + } catch(IllegalArgumentException | NullPointerException e){} + + //Get Animation Type + DisplayAnimator.AnimationType animType; + try{ + animType = DisplayAnimator.AnimationType.valueOf(section.getString("animationType").toUpperCase()); + } + catch(IllegalArgumentException | NullPointerException e){ + animType = DisplayAnimator.AnimationType.LINEAR; //Default + } + + boolean lock = section.getBoolean("lockTransition"); + MachineState state = new MachineState(machine, stateType.getStateID(), animations, loadMethod, animType, lock); + if (!state.hasDisplayAnimators() && !state.isNullLoader()){ + if (!controller.controllerID.equalsIgnoreCase("example")){ + Bukkit.getLogger().warning("Failed to add state, \""+stateType.getStateID()+"\". No animations found: ["+machine.getId()+"]"); + } + return; + } + + machine.addState(state); + switch(stateType){ + case SPAWN, DEATH -> { + state.ignoreOtherTransitionLocks(); + } + case MELEE -> { + state.setCauseDelay(section.getInt("damageDelay")); + state.setMaxRange((float) section.getDouble("maxRange")); + } + } + } +} From 119bfc79f23de6ce83b2092e54d1d368d1d82033 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 6 May 2026 22:17:37 -0500 Subject: [PATCH 35/55] Update DisplayController & MachineState to optionally play animation data changes --- .../DisplayEntities/machine/MachineState.java | 31 ++++-- .../utils/controller/DisplayController.java | 1 + .../controller/DisplayControllerReader.java | 102 +++++++++++------- .../src/main/resources/examplecontroller.yml | 4 + 4 files changed, 89 insertions(+), 49 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/machine/MachineState.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/machine/MachineState.java index 986dd81e..b8577786 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/machine/MachineState.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/machine/MachineState.java @@ -25,6 +25,7 @@ public class MachineState { int causeDelay = -1; float maxRange; boolean isSkillState = false; + boolean animationDataChanges; /** * Create a machine state for an {@link DisplayStateMachine}, determining which animation should be played when this state is active @@ -36,8 +37,8 @@ public class MachineState { * @param transitionLock whether this state should lock transitions to another state before this one's animation finishes * @apiNote Having the animation type as {@link DisplayAnimator.AnimationType#LOOP} will force the transitionLock to false, regardless of the value set. */ - public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull StateType stateType, @NotNull List animationTags, @Nullable LoadMethod loadMethod, @NotNull DisplayAnimator.AnimationType animationType, boolean transitionLock){ - this(stateMachine, stateType.getStateID(), animationTags, loadMethod, animationType, transitionLock); + public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull StateType stateType, @NotNull List animationTags, @Nullable LoadMethod loadMethod, @NotNull DisplayAnimator.AnimationType animationType, boolean transitionLock, boolean animationDataChanges){ + this(stateMachine, stateType.getStateID(), animationTags, loadMethod, animationType, transitionLock, animationDataChanges); } /** @@ -50,15 +51,16 @@ public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull StateTyp * @param transitionLock whether this state should lock transitions to another state before this one's animation finishes * @apiNote Having the animation type as {@link DisplayAnimator.AnimationType#LOOP} will force the transitionLock to false, regardless of the value set. */ - public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull String stateID, @NotNull List animationTags, @Nullable LoadMethod loadMethod, @NotNull DisplayAnimator.AnimationType animationType, boolean transitionLock){ + public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull String stateID, @NotNull List animationTags, @Nullable LoadMethod loadMethod, @NotNull DisplayAnimator.AnimationType animationType, boolean transitionLock, boolean animationDataChanges){ this.stateMachine = stateMachine; this.stateID = stateID; + this.animationDataChanges = animationDataChanges; this.transitionLock = animationType != DisplayAnimator.AnimationType.LOOP && transitionLock; for (String tag : animationTags){ if (loadMethod != null){ SpawnedDisplayAnimation animation = DisplayAnimationManager.getSpawnedDisplayAnimation(tag, loadMethod); if (animation != null){ - this.animators.add(new DisplayAnimator(animation, animationType)); + this.animators.add(new DisplayAnimator(animation, animationType, animationDataChanges)); } } else{ @@ -67,7 +69,7 @@ public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull String s animationlessStates.put(this, new AnimatorData(tag, animationType)); } else{ - this.animators.add(new DisplayAnimator(animation, animationType)); + this.animators.add(new DisplayAnimator(animation, animationType, animationDataChanges)); } } } @@ -82,8 +84,8 @@ public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull String s * @param transitionLock whether this state should lock transitions to another state before this one's animation finishes * @apiNote Having the animation type as {@link DisplayAnimator.AnimationType#LOOP} will force the transitionLock to false, regardless of the value set. */ - public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull StateType stateType, @NotNull List animations, @NotNull DisplayAnimator.AnimationType animationType, boolean transitionLock){ - this(stateMachine, stateType.getStateID(), animations, animationType, transitionLock); + public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull StateType stateType, @NotNull List animations, @NotNull DisplayAnimator.AnimationType animationType, boolean transitionLock, boolean animationDataChanges){ + this(stateMachine, stateType.getStateID(), animations, animationType, transitionLock, animationDataChanges); } /** @@ -95,13 +97,14 @@ public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull StateTyp * @param transitionLock whether this state should lock transitions to another state before this one's animation finishes * @apiNote Having the animation type as {@link DisplayAnimator.AnimationType#LOOP} will force the transitionLock to false, regardless of the value set. */ - public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull String stateID, @NotNull List animations, @NotNull DisplayAnimator.AnimationType animationType, boolean transitionLock){ + public MachineState(@NotNull DisplayStateMachine stateMachine, @NotNull String stateID, @NotNull List animations, @NotNull DisplayAnimator.AnimationType animationType, boolean transitionLock, boolean animationDataChanges){ this.stateMachine = stateMachine; this.stateID = stateID; + this.transitionLock = animationType != DisplayAnimator.AnimationType.LOOP && transitionLock; + this.animationDataChanges = animationDataChanges; for (SpawnedDisplayAnimation anim : animations){ - animators.add(new DisplayAnimator(anim, animationType)); + animators.add(new DisplayAnimator(anim, animationType, animationDataChanges)); } - this.transitionLock = animationType != DisplayAnimator.AnimationType.LOOP && transitionLock; } @@ -162,6 +165,14 @@ public boolean isSkillState() { return isSkillState; } + /** + * Get whether this {@link MachineState}'s animators allows block/item display textures and text display text to change based on animation frame data + * @return a boolean + */ + public boolean allowDataChanges(){ + return animationDataChanges; + } + /** * Get this machine state's {@link DisplayStateMachine} * @return a {@link DisplayStateMachine} 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 516a4845..07688d8b 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 @@ -40,6 +40,7 @@ public class DisplayController { Vector rideOffset = new Vector(); boolean groupVisibleByDefault; boolean isPacketBased; + boolean allowAnimationDataChanges; public DisplayController(@NotNull String controllerID) { this.controllerID = controllerID; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayControllerReader.java b/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayControllerReader.java index 2546cf4f..0e9616b6 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayControllerReader.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayControllerReader.java @@ -19,6 +19,13 @@ class DisplayControllerReader { + private static final String MYTHIC_MOBS_SECT = "mythicMobs"; + private static final String GROUP_SECT = "group"; + private static final String GROUP_PROPERTIES_SECT = "groupProperties"; + private static final String DEFAULT_FOLLOW_PROPERTIES_SECT = "defaultFollowProperties"; + private static final String PART_FOLLOW_PROPERTIES_SECT = "partFollowProperties"; + private static final String STATES_SECT = "states"; + static DisplayController read(YamlConfiguration config, String fileName, boolean fromFile){ try{ String controllerID = config.getString("controllerID"); @@ -33,65 +40,70 @@ static DisplayController read(YamlConfiguration config, String fileName, boolean controller.configController = true; } - //Set Mythic Mobs - ConfigurationSection mythicSect = config.getConfigurationSection("mythicMobs"); + //----=Set Mythic Mobs=---- + ConfigurationSection mythicSect = config.getConfigurationSection(MYTHIC_MOBS_SECT); List mobs = mythicSect.getStringList("mobs"); controller.setMythicMobs(mobs); - //Group Properties - ConfigurationSection createdGroupSect = mythicSect.getConfigurationSection("group"); - String groupTag = createdGroupSect.getString("tag"); - controller.isPacketBased = createdGroupSect.getBoolean("packetBased", false); - boolean flip; + //----=Group=----- + ConfigurationSection groupSect = mythicSect.getConfigurationSection(GROUP_SECT); + String groupTag = groupSect.getString("tag"); + try{ //Try to set LoadMethod + LoadMethod method = LoadMethod.valueOf(groupSect.getString("storage").toUpperCase()); + controller.setDisplayEntityGroup(groupTag, method); + } + catch(IllegalArgumentException e){ //Mark as Null Loader, must be set with API Event + if (controller.group == null){ + DisplayController.grouplessControllers.put(controller, groupTag); + } + } + controller.isPacketBased = groupSect.getBoolean("packetBased", false); + controller.allowAnimationDataChanges = groupSect.getBoolean("allowAnimationDataChanges", true); - ConfigurationSection groupProp = config.getConfigurationSection("groupProperties"); - if (groupProp != null){ - //before added vector offset - if (groupProp.contains("verticalOffset")){ - controller.rideOffset = new Vector(0, groupProp.getDouble("verticalOffset"), 0); + + //----Group Properties=---- + ConfigurationSection groupPropSect = config.getConfigurationSection(GROUP_PROPERTIES_SECT); + boolean flip; + if (groupPropSect == null){ + flip = false; + Bukkit.getLogger().warning("Missing section \"groupProperties\" in display controller: "+fileName+"."); + } + else{ + //before vector offset was added + if (groupPropSect.contains("verticalOffset")){ + controller.rideOffset = new Vector(0, groupPropSect.getDouble("verticalOffset"), 0); Bukkit.getLogger().warning("\"verticalOffset\" is outdated but will still function for display controller: "+fileName+". " + "See new examplecontroller on GitHub for new \"offset\"'s formatting in any direction."); } - else if (groupProp.contains("offset")){ - ConfigurationSection offsetSect = groupProp.getConfigurationSection("offset"); - double x = offsetSect.getDouble("x"); - double y = offsetSect.getDouble("y"); - double z = offsetSect.getDouble("z"); + else if (groupPropSect.contains("offset")){ + ConfigurationSection offsetSect = groupPropSect.getConfigurationSection("offset"); + double x = offsetSect.getDouble("x", 0); + double y = offsetSect.getDouble("y", 0); + double z = offsetSect.getDouble("z", 0); controller.rideOffset = new Vector(x,y,z); } - controller.groupVisibleByDefault = groupProp.getBoolean("visibleByDefault", true); - flip = groupProp.getBoolean("flip", false); - } - else{ - flip = false; - Bukkit.getLogger().warning("Missing section \"groupProperties\" for outdated display controller: "+fileName+"."); + controller.groupVisibleByDefault = groupPropSect.getBoolean("visibleByDefault", true); + flip = groupPropSect.getBoolean("flip", false); } - //LoadMethod - try{ //Set with Config - LoadMethod method = LoadMethod.valueOf(createdGroupSect.getString("storage").toUpperCase()); - controller.setDisplayEntityGroup(groupTag, method); - } - //Mark Null Loader - catch(IllegalArgumentException e){ //Set with API Event - if (controller.group == null){ - DisplayController.grouplessControllers.put(controller, groupTag); - } + //----=Default Follow Properties=---- + if (!config.contains(DEFAULT_FOLLOW_PROPERTIES_SECT)) { + printMissingSection(DEFAULT_FOLLOW_PROPERTIES_SECT, fileName, true); + return null; } - - ConfigurationSection defaultPropsSection = config.getConfigurationSection("defaultFollowProperties"); + ConfigurationSection defaultPropsSection = config.getConfigurationSection(DEFAULT_FOLLOW_PROPERTIES_SECT); int deathDespawnDelay = defaultPropsSection.getInt("deathDespawnDelay"); HashSet propertiesToRemove = new HashSet<>(controller.followProperties.keySet()); - //Default Follow Properties + configureDefaultProperties(controller, defaultPropsSection, deathDespawnDelay, flip); propertiesToRemove.remove(null); //Part Follow Properties - List> partFollowMaps = config.getMapList("partFollowProperties"); + List> partFollowMaps = config.getMapList(PART_FOLLOW_PROPERTIES_SECT); if (!partFollowMaps.isEmpty()){ for (Map map : partFollowMaps){ String followPropertyID = (String) map.get("id"); @@ -108,7 +120,7 @@ else if (groupProp.contains("offset")){ } //Animation States - ConfigurationSection stateSect = config.getConfigurationSection("states"); + ConfigurationSection stateSect = config.getConfigurationSection(STATES_SECT); if (stateSect != null){ DisplayStateMachine machine = new DisplayStateMachine(controllerID); for (MachineState.StateType stateType : MachineState.StateType.values()){ @@ -134,6 +146,16 @@ else if (groupProp.contains("offset")){ } } + private static void printMissingSection(String section, String fileName, boolean severe){ + String message = "Missing DisplayController section, \""+section+"\" in "+fileName; + if (severe){ + Bukkit.getLogger().severe(message); + } + else{ + Bukkit.getLogger().warning(message); + } + } + private static GroupFollowProperties configureDefaultProperties(DisplayController controller, ConfigurationSection section, int deathDespawnDelay, boolean flip){ FollowType followType = null; try{ @@ -247,7 +269,9 @@ private static void addState(DisplayController controller, DisplayStateMachine m } boolean lock = section.getBoolean("lockTransition"); - MachineState state = new MachineState(machine, stateType.getStateID(), animations, loadMethod, animType, lock); + boolean animDataChangeOverride = section.getBoolean("animationDataChangesOverride", controller.allowAnimationDataChanges); + + MachineState state = new MachineState(machine, stateType.getStateID(), animations, loadMethod, animType, lock, animDataChangeOverride); if (!state.hasDisplayAnimators() && !state.isNullLoader()){ if (!controller.controllerID.equalsIgnoreCase("example")){ Bukkit.getLogger().warning("Failed to add state, \""+stateType.getStateID()+"\". No animations found: ["+machine.getId()+"]"); diff --git a/plugin/src/main/resources/examplecontroller.yml b/plugin/src/main/resources/examplecontroller.yml index 3d13cb18..8e5e357b 100644 --- a/plugin/src/main/resources/examplecontroller.yml +++ b/plugin/src/main/resources/examplecontroller.yml @@ -25,6 +25,8 @@ mythicMobs: storage: LOCAL #Determine if the group should be packet based packetBased: true + #Whether played animation should be able to change the texture of this group + allowAnimationDataChanges: true #-----------------Group Properties------------------- @@ -132,6 +134,8 @@ states: storage: LOCAL animationType: LINEAR lockTransition: true + #The value that should be used for this animation state, regardless of what "group.allowAnimationDataChanges"'s is + animationDataChangesOverride: true idle: animations: ["idle_animation"] From 4a270fa9c1ab09c35686a63b94155dd30b19b754 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 6 May 2026 22:28:17 -0500 Subject: [PATCH 36/55] Update DEUAnimationMythicMechanic for optional data changes --- .../entity/mythic/DEUAnimationMythicMechanic.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUAnimationMythicMechanic.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUAnimationMythicMechanic.java index 0086963d..d732c79e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUAnimationMythicMechanic.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUAnimationMythicMechanic.java @@ -46,7 +46,15 @@ private DEUAnimationMythicMechanic(MythicLineConfig config) { loadMethod = null; } - state = new MachineState(controller.getStateMachine(), id, List.of(animTag), loadMethod, type, true); + boolean dataChanges; + try{ + dataChanges = config.getBoolean("d"); + } + catch(IllegalArgumentException e){ + dataChanges = true; + } + + state = new MachineState(controller.getStateMachine(), id, List.of(animTag), loadMethod, type, true, dataChanges); state.ignoreOtherTransitionLocks(); state.skillState(); } From 00bbeaa83e58d52727fc03125497e3d7b600fe3d Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 6 May 2026 22:34:19 -0500 Subject: [PATCH 37/55] Remove animation texture changes from animations --- .../DisplayEntities/DisplayAnimation.java | 8 --- .../SpawnedDisplayAnimation.java | 18 +----- .../command/anim/AnimCMD.java | 2 - .../command/anim/AnimInfoCMD.java | 1 - .../command/anim/AnimTextureChangesCMD.java | 34 ---------- .../skript/animation/AnimatorModule.java | 1 - .../effects/EffAnimationTextureChanges.java | 64 ------------------- 7 files changed, 1 insertion(+), 127 deletions(-) delete mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimTextureChangesCMD.java delete mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/effects/EffAnimationTextureChanges.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimation.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimation.java index 5ed6b159..2d987338 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimation.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimation.java @@ -70,14 +70,6 @@ public void removeFrame(DisplayAnimationFrame frame){ frames.remove(frame); } - /** - * Get if this animation allows for texture changes to block/item displays and text display text - * @return a boolean - */ - public boolean allowsTextureChanges(){ - return dataChanges; - } - @ApiStatus.Internal public void adaptOldSounds(){ for (DisplayAnimationFrame frame: frames){ diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimation.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimation.java index 6f0126dc..615480ea 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimation.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimation.java @@ -38,23 +38,6 @@ public void setAnimationTag(String animationTag) { this.animationTag = animationTag; } - /** - * Get if this animation allows for texture changes to block/item displays, text display text - * @return a boolean - */ - public boolean allowsTextureChanges(){ - return dataChanges; - } - - /** - * Set whether this animation should allow texture changes to block/item displays and text display text - * @param textureChanges - * @return this - */ - public SpawnedDisplayAnimation allowTextureChanges(boolean textureChanges){ - this.dataChanges = textureChanges; - return this; - } /** * Set the filter this animation should use when animating @@ -346,6 +329,7 @@ public SpawnedDisplayAnimation getReversedAnimation(){ newFrame.interactionTransformations = new HashMap<>(frame.interactionTransformations); reversed.addFrame(newFrame); } + reversed.dataChanges = this.dataChanges; reversed.animationTag = this.animationTag; if (this.filter != null){ reversed.filter = this.filter.clone(); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimCMD.java index fe86c015..4288ea17 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimCMD.java @@ -43,7 +43,6 @@ public AnimCMD(){ new AnimAddParticleCMD(this); new AnimReverseCMD(this); new AnimScaleRespectCMD(this); - new AnimTextureChangesCMD(this); new AnimSetTagCMD(this); new AnimSetFrameTagCMD(this); new AnimPreviewPlayCMD(this); @@ -115,7 +114,6 @@ else if (page == 4){ } else if (page == 5){ CMDUtils.sendCMD(sender, "/deu anim togglescalerespect", "Toggle whether your selected animation should respect the group's scale"); - CMDUtils.sendCMD(sender, "/deu anim toggletexturechanges", "Toggle whether your selected animation can change block display blocks, item display items, and text display text"); CMDUtils.sendCMD(sender, "/deu anim showframe ", "Displays a frame on your selected group"); CMDUtils.sendCMD(sender, "/deu anim previewframe ", "Preview a frame on your selected group, without changing group entity data"); CMDUtils.sendCMD(sender, "/deu anim play [-loop] [-packet] [-camera] [-nodata]", "Play your selected animation on your selected group." + diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimInfoCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimInfoCMD.java index 8882cfc4..ac709720 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimInfoCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimInfoCMD.java @@ -39,7 +39,6 @@ public void execute(Player player, String[] args) { player.sendMessage(MiniMessage.miniMessage().deserialize("Total Frames: "+animation.getFrames().size())); player.sendMessage(MiniMessage.miniMessage().deserialize("Total Duration: "+animation.getDuration()+" ticks")); player.sendMessage(MiniMessage.miniMessage().deserialize("Respect Scale: "+animation.groupScaleRespect())); - player.sendMessage(MiniMessage.miniMessage().deserialize("Allows Texture Changes: "+animation.allowsTextureChanges())); if (!animation.hasFilter()) { player.sendMessage(MiniMessage.miniMessage().deserialize("Animation Part Filter: NOT SET")); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimTextureChangesCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimTextureChangesCMD.java deleted file mode 100644 index 57307967..00000000 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimTextureChangesCMD.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.donnypz.displayentityutils.command.anim; - -import net.donnypz.displayentityutils.command.DEUSubCommand; -import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.command.PlayerSubCommand; -import net.donnypz.displayentityutils.managers.DisplayAnimationManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayAnimation; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -class AnimTextureChangesCMD extends PlayerSubCommand { - AnimTextureChangesCMD(@NotNull DEUSubCommand parentSubCommand) { - super("toggletexturechanges", parentSubCommand, Permission.ANIM_TOGGLE_TEXTURE_CHANGES); - } - - @Override - public void execute(Player player, String[] args) { - SpawnedDisplayAnimation anim = DisplayAnimationManager.getSelectedSpawnedAnimation(player); - if (anim == null) { - AnimCMD.noAnimationSelection(player); - return; - } - - boolean dataChanges = !anim.allowsTextureChanges(); - anim.allowTextureChanges(dataChanges); - player.sendMessage(Component.text("Animation Texture Changes toggled to: ", NamedTextColor.GREEN).append(Component.text(dataChanges, NamedTextColor.YELLOW))); - player.sendMessage(Component.text("| Texture Changes Apply to:", NamedTextColor.GRAY)); - player.sendMessage(Component.text("- Block Display block changes", NamedTextColor.GRAY)); - player.sendMessage(Component.text("- Item Display item changes", NamedTextColor.GRAY)); - player.sendMessage(Component.text("- Text Display text changes", NamedTextColor.GRAY)); - } -} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/AnimatorModule.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/AnimatorModule.java index 08862d3d..3c3d1182 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/AnimatorModule.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/AnimatorModule.java @@ -26,7 +26,6 @@ public void load(SkriptAddon addon) { EffActiveGroupStopAllAnimations::register, EffActiveGroupStopAnimation::register, EffActiveGroupStopAnimationCamera::register, - EffAnimationTextureChanges::register, EffPlayerStopAllPacketAnimations::register, ExprAnimatorAnimation::register, diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/effects/EffAnimationTextureChanges.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/effects/EffAnimationTextureChanges.java deleted file mode 100644 index 60ac1545..00000000 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/effects/EffAnimationTextureChanges.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.donnypz.displayentityutils.skript.animation.effects; - -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.lang.Effect; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser; -import ch.njol.util.Kleenean; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayAnimation; -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.registration.SyntaxInfo; -import org.skriptlang.skript.registration.SyntaxRegistry; - -@Name("Toggle Animation Texture Changes") -@Description("Toggle whether textures should be updated during an animation. (Player Head Changes during animation, etc.)") -@Examples({ - "enable texture changes for {_animation}", - "disable texture changes for {_animation}", - "", - "#3.4.3 and earlier", - "set {_animation} to allow texture changes", - "set {_animation} to not allow texture changes" -}) -@Since("3.3.1") -public class EffAnimationTextureChanges extends Effect { - - Expression object; - boolean enabled; - - public static void register(SyntaxRegistry registry){ - registry.register(SyntaxRegistry.EFFECT, - SyntaxInfo.builder(EffAnimationTextureChanges.class) - .addPattern("(:dis|en)able texture change[s] for %deuanimations%") - .supplier(EffAnimationTextureChanges::new) - .build() - ); - } - - @Override - public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - object = (Expression) expressions[0]; - enabled = !parseResult.hasTag("dis"); - return true; - } - - @Override - protected void execute(Event event) { - SpawnedDisplayAnimation[] animations = object.getArray(event); - if (animations == null) return; - for (SpawnedDisplayAnimation a : animations){ - if (a != null){ - a.allowTextureChanges(enabled); - } - } - } - - @Override - public String toString(@Nullable Event event, boolean debug) { - return "animation texture changes: "+object.toString(event, debug); - } -} From 1b4525ff4d2510d9ed05cedc90cd7751e84c525e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 6 May 2026 22:36:18 -0500 Subject: [PATCH 38/55] Updated example --- .../skript/animation/effects/EffActiveGroupPlayAnimation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/effects/EffActiveGroupPlayAnimation.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/effects/EffActiveGroupPlayAnimation.java index c4444704..b049b460 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/effects/EffActiveGroupPlayAnimation.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/effects/EffActiveGroupPlayAnimation.java @@ -22,7 +22,7 @@ @Name("Play Animation") @Description("Play an animation on an active group with a display animator") -@Examples({"play animation on {_spawnedgroup} using {_displayanimator}", +@Examples({"play animation on {_activegroup} using {_displayanimator}", "", "#3.0.0 or later", "start packet animation on {_packetgroup} with {_displayanimator} starting at frame 3", From e8e7df8a4b8b56f47d2b8ae343976e41acbd6cd4 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 6 May 2026 23:01:12 -0500 Subject: [PATCH 39/55] Add optional animation data changes to Skript syntax --- .../expressions/ExprDisplayAnimator.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/expressions/ExprDisplayAnimator.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/expressions/ExprDisplayAnimator.java index e7cb49cd..b03cd45c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/expressions/ExprDisplayAnimator.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/animation/expressions/ExprDisplayAnimator.java @@ -17,18 +17,25 @@ @Name("Create Display Animator") @Description("Create a display animator to play animations on an active group") -@Examples({"set {_animator} to a new linear display animator using {_animation}", - "set {_loopanimator} to a loop animator using {_animation}"}) -@Since("2.6.2") +@Examples({ + "set {_animator} to a new linear display animator using {_animation}", + "set {_loopanimator} to a loop animator using {_animation}", + "", + "#3.5.2 and later", + "#Play an animation and ONLY update transformation, not textures/text/data", + "set {_animator} to a linear animator using {_animation} without data changes" +}) +@Since("2.6.2, 3.5.2 (Data Changes)") public class ExprDisplayAnimator extends SimpleExpression { private boolean loop; + private boolean dataChanges; private Expression animation; - public static void register(SyntaxRegistry registry){ + public static void register(SyntaxRegistry registry) { registry.register(SyntaxRegistry.EXPRESSION, SyntaxInfo.Expression.builder(ExprDisplayAnimator.class, DisplayAnimator.class) - .addPatterns("[a] [new] (linear|loop:loop[ing]) [display] animator using [anim[ation]] %deuanimation%") + .addPatterns("[a] [new] (linear|loop:loop[ing]) [display] animator using [anim[ation]] %deuanimation% [d:without (data|texture) change[s]]") .supplier(ExprDisplayAnimator::new) .build() ); @@ -38,10 +45,10 @@ public static void register(SyntaxRegistry registry){ protected DisplayAnimator[] get(Event event) { DisplayAnimator.AnimationType type = loop ? DisplayAnimator.AnimationType.LOOP : DisplayAnimator.AnimationType.LINEAR; SpawnedDisplayAnimation anim = animation.getSingle(event); - if (anim == null){ + if (anim == null) { return null; } - return new DisplayAnimator[]{new DisplayAnimator(anim, type)}; + return new DisplayAnimator[]{new DisplayAnimator(anim, type, dataChanges)}; } @Override @@ -56,12 +63,13 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - return (loop ? "loop" : "") + " display animator "+animation.toString(event, debug); + return (loop ? "loop" : "") + " display animator " + animation.toString(event, debug) + (!dataChanges ? "w/o data changes" : ""); } @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { loop = parseResult.hasTag("loop"); + dataChanges = !parseResult.hasTag("d"); animation = (Expression) expressions[0]; return true; } From a0218a6e307374d0e954e65487b4ae3a92570622 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 6 May 2026 23:21:50 -0500 Subject: [PATCH 40/55] 3.5.2-PRE-4 --- 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 84089488..8bf2d304 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-3 + 3.5.2-PRE-4 api diff --git a/plugin/pom.xml b/plugin/pom.xml index 1e997f75..1fdfad53 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-3 + 3.5.2-PRE-4 plugin diff --git a/pom.xml b/pom.xml index 21a214a0..04d4b54b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-3 + 3.5.2-PRE-4 pom DisplayEntityUtils From 79fb2391e0aa3d44b9c21c779a9209e9d0961ec0 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Wed, 6 May 2026 23:32:24 -0500 Subject: [PATCH 41/55] add additional config option for animation data changes --- .../entity/mythic/DEUAnimationMythicMechanic.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUAnimationMythicMechanic.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUAnimationMythicMechanic.java index d732c79e..fbce974b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUAnimationMythicMechanic.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/mythic/DEUAnimationMythicMechanic.java @@ -50,8 +50,13 @@ private DEUAnimationMythicMechanic(MythicLineConfig config) { try{ dataChanges = config.getBoolean("d"); } - catch(IllegalArgumentException e){ - dataChanges = true; + catch(IllegalArgumentException e1){ + try{ + dataChanges = config.getBoolean("datachanges"); + } + catch(IllegalArgumentException e2){ + dataChanges = true; + } } state = new MachineState(controller.getStateMachine(), id, List.of(animTag), loadMethod, type, true, dataChanges); From 29d9c3fe31beed1de719bac2a8e3cf99c7eae031 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 8 May 2026 18:19:26 -0500 Subject: [PATCH 42/55] update jitpack.yml --- jitpack.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/jitpack.yml b/jitpack.yml index 727c9abd..b1690226 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,2 +1,11 @@ jdk: - openjdk21 + +before_install: + - rm -rf ~/.m2/repository/net/kyori + - rm -rf ~/.m2/repository/org/apache/maven + - rm -rf ~/.m2/repository/com/google/code/findbugs + - rm -rf ~/.m2/repository/org/codehaus/plexus + +install: + - mvn clean install -U -DskipTests \ No newline at end of file From 3b3cf55fd72c936a1a1ca522ec3d97046ac42278 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 8 May 2026 18:45:50 -0500 Subject: [PATCH 43/55] update jitpack.yml to use java 25 --- jitpack.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/jitpack.yml b/jitpack.yml index b1690226..c39ce5d6 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,11 +1,2 @@ jdk: - - openjdk21 - -before_install: - - rm -rf ~/.m2/repository/net/kyori - - rm -rf ~/.m2/repository/org/apache/maven - - rm -rf ~/.m2/repository/com/google/code/findbugs - - rm -rf ~/.m2/repository/org/codehaus/plexus - -install: - - mvn clean install -U -DskipTests \ No newline at end of file + - openjdk25 \ No newline at end of file From e7d2b428219153feb8c999d1a367477a811cad0e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Fri, 8 May 2026 18:50:18 -0500 Subject: [PATCH 44/55] 3.5.2-PRE-5 --- 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 8bf2d304..bedcabc5 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-4 + 3.5.2-PRE-5 api diff --git a/plugin/pom.xml b/plugin/pom.xml index 1fdfad53..497c938a 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-4 + 3.5.2-PRE-5 plugin diff --git a/pom.xml b/pom.xml index 04d4b54b..1ee95713 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-4 + 3.5.2-PRE-5 pom DisplayEntityUtils From f66a02a815eaa4a58f9006fdb0676f2455987104 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 23 May 2026 21:22:08 -0500 Subject: [PATCH 45/55] Added "/deu mannequin spawn" command --- .../command/Permission.java | 1 + .../command/mannequin/MannequinCMD.java | 4 +- .../command/mannequin/MannequinSpawnCMD.java | 61 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.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 531190a4..c3838266 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -90,6 +90,7 @@ public enum Permission { INTERACTION_SPAWN("deu.interaction.spawn"), INTERACTION_INFO("deu.interaction.info"), + MANNEQUIN_SPAWN("deu.mannequin.spawn"), MANNEQUIN_SKIN("deu.mannequin.skin"), MANNEQUIN_NAME("deu.mannequin.name"), MANNEQUIN_NAME_VISIBLE("deu.mannequin.namevisible"), 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 c4a9bc4e..13654507 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 @@ -11,6 +11,7 @@ public class MannequinCMD extends ConsoleUsableSubCommand { public MannequinCMD() { super(Permission.HELP, new MannequinHelpCMD()); + new MannequinSpawnCMD(this); new MannequinNameCMD(this); new MannequinUnnameCMD(this); new MannequinBelowNameCMD(this); @@ -51,14 +52,15 @@ 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 spawn [-g]", "Spawn a mannequin at your location.\nUse \"-g\" to add it to your selected group"); CMDUtils.sendCMD(sender, "/deu mannequin name ", "Set 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"); - CMDUtils.sendCMD(sender, "/deu mannequin togglegravity [-all ]", "Toggle the gravity of an mannequin"); } else{ + 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 equipment ", "Open a GUI to edit your selected mannequin's equipment."); CMDUtils.sendCMD(sender, "/deu mannequin mainhand ", "Set your selected mannequin's main hand"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java new file mode 100644 index 00000000..7c8a5638 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java @@ -0,0 +1,61 @@ +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.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.DEUUser; +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 net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Location; +import org.bukkit.entity.Mannequin; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +class MannequinSpawnCMD extends PlayerSubCommand { + MannequinSpawnCMD(@NotNull DEUSubCommand parentSubCommand) { + super("spawn", parentSubCommand, Permission.MANNEQUIN_SPAWN); + setTabComplete(2, List.of("-g")); + } + + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu mannequin spawn [-g]", NamedTextColor.RED))); + } + + @Override + public void execute(Player player, String[] args) { + Location location = player.getLocation(); + Mannequin mannequin = location.getWorld().spawn(location, Mannequin.class, m -> { + m.setProfile(ResolvableProfile.resolvableProfile(player.getPlayerProfile())); + m.customName(Component.text("New Mannequin")); + m.setCustomNameVisible(true); + }); + DisplayUtils.prepareMannequin(mannequin); + + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("A new mannequin has been spawned at your location!"))); + + + if (args.length >= 3 && args[2].equalsIgnoreCase("-g")){ + ActiveGroup group = DEUUser.getOrCreateUser(player).getSelectedGroup(); + if (group == null) { + player.sendMessage(Component.text("- You must have a group selected to add the mannequin to a group", NamedTextColor.YELLOW)); + return; + } + + ActivePart part = group.addEntity(mannequin); + if (part == null){ + player.sendMessage(Component.text("- Failed to add the mannequin to your selected group", NamedTextColor.YELLOW)); + return; + } + + player.sendMessage(Component.text("- The mannequin has been added to your selected group", NamedTextColor.GRAY)); + } + } +} From c242d999a6bd5e03a7fb58993e7e79ef90bf4165 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 23 May 2026 21:44:00 -0500 Subject: [PATCH 46/55] Remove duplicate listings in list cmds, add message showing that items are clickable --- .../displayentityutils/command/ListCMD.java | 75 +++++++++---------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/ListCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/ListCMD.java index a84fbc94..88056f35 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/ListCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/ListCMD.java @@ -10,6 +10,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import java.util.List; @@ -17,11 +18,12 @@ public class ListCMD extends ConsoleUsableSubCommand { Component incorrectUsageMessage; int minLength, storageIndex, pageNumberIndex; boolean listsGroups; + public ListCMD(Component incorrectUsageMessage, int minLength, boolean listsGroups) { super(listsGroups ? Permission.LIST_GROUPS : Permission.LIST_ANIMATIONS); this.incorrectUsageMessage = incorrectUsageMessage; this.minLength = minLength; - this.storageIndex = minLength-1; + this.storageIndex = minLength - 1; this.pageNumberIndex = minLength; this.listsGroups = listsGroups; setTabComplete(storageIndex, TabSuggestion.STORAGES); @@ -30,74 +32,69 @@ public ListCMD(Component incorrectUsageMessage, int minLength, boolean listsGrou @Override public void execute(CommandSender sender, String[] args) { - if (args.length < minLength){ + if (args.length < minLength) { sender.sendMessage(incorrectUsageMessage); return; } - list(sender,storageIndex, pageNumberIndex, args); + list(sender, storageIndex, pageNumberIndex, args); } - public void list(CommandSender sender, int storageIndex, int pageNumberIndex, String[] args){ + public void list(CommandSender sender, int storageIndex, int pageNumberIndex, String[] args) { DisplayAPI.getScheduler().runAsync(() -> { - LoadMethod method; - try{ - method = LoadMethod.valueOf(args[storageIndex].toUpperCase()); - } - catch(IllegalArgumentException e){ + LoadMethod loadMethod; + try { + loadMethod = LoadMethod.valueOf(args[storageIndex].toUpperCase()); + } catch (IllegalArgumentException e) { DisplayEntityPluginCommand.invalidStorage(sender); return; } List tags = listsGroups ? - DisplayGroupManager.getSavedDisplayEntityGroups(method) + DisplayGroupManager.getSavedDisplayEntityGroups(loadMethod) : - DisplayAnimationManager.getSavedDisplayAnimations(method); + DisplayAnimationManager.getSavedDisplayAnimations(loadMethod); sender.sendMessage(DisplayAPI.pluginPrefixLong); - sender.sendMessage(MiniMessage.miniMessage().deserialize("Storage Location: "+method.getDisplayName())); - if (tags.isEmpty()){ + sender.sendMessage(MiniMessage.miniMessage().deserialize("Storage Location: " + loadMethod.getDisplayName())); + if (tags.isEmpty()) { sender.sendMessage(Component.text("That storage location is empty!", NamedTextColor.RED)); return; } + if (sender instanceof Player) { + sender.sendMessage(Component.text("Click to a listed item to " + (listsGroups ? "spawn" : "select") + " it", NamedTextColor.GRAY)); + } + int pageNumber = 1; - if (args.length > minLength){ - try{ + if (args.length > minLength) { + try { pageNumber = Math.max(1, Integer.parseInt(args[pageNumberIndex])); + } catch (NumberFormatException ignored) { } - catch(NumberFormatException ignored){} } - int end = pageNumber*7; - int start = end-7; - sender.sendMessage(Component.text("Page Number: "+pageNumber, NamedTextColor.AQUA)); - for (int i = start; i <= end; i++){ - if (i >= tags.size()){ + int end = pageNumber * 6; + int start = end - 6; + + for (int i = start; i < end; i++) { + if (i >= tags.size()) { break; } - Component message; String tag = tags.get(i); - if (listsGroups){ - message = spawnGroup(tag, method); - } - else{ - message = selectAnimation(tag, method); - } - sender.sendMessage(message); + sender.sendMessage(getMessage(tag, loadMethod)); } - sender.sendMessage("------------------------"); + sender.sendMessage(Component.text("----------" + "Page " + pageNumber + "----------", NamedTextColor.GRAY)); }); } - private static Component spawnGroup(String tag, LoadMethod loadMethod){ - return MiniMessage.miniMessage().deserialize("- "+tag) - .hoverEvent(HoverEvent.showText(Component.text("Click to spawn", NamedTextColor.AQUA))) - .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/deu group spawn "+tag+" "+loadMethod.name())); - } - private static Component selectAnimation(String tag, LoadMethod loadMethod){ - return MiniMessage.miniMessage().deserialize("- "+tag) - .hoverEvent(HoverEvent.showText(Component.text("Click to select", NamedTextColor.AQUA))) - .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/deu anim select "+tag+" "+loadMethod.name())); + private Component getMessage(String tag, LoadMethod loadMethod) { + return MiniMessage.miniMessage().deserialize("- " + tag) + .hoverEvent(HoverEvent.showText( + Component.text( + (listsGroups ? "Click to spawn" : "Click to select"), + NamedTextColor.GREEN)) + ).clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, + "/deu " + (listsGroups ? "group spawn " : "anim select ") + tag + " " + loadMethod.name())); } } From 27a424c6b556e68021f350556dbcacfacb28f9b6 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sat, 23 May 2026 22:57:39 -0500 Subject: [PATCH 47/55] refresh selection when adding mannequin to group. use correct selection type --- .../command/group/GroupAddTargetCMD.java | 11 ++--------- .../command/interaction/InteractionAddToGroupCMD.java | 3 +-- .../command/mannequin/MannequinSpawnCMD.java | 2 ++ 3 files changed, 5 insertions(+), 11 deletions(-) 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 38ffa548..93ec8352 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 @@ -5,16 +5,10 @@ import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; -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.donnypz.displayentityutils.utils.DisplayEntities.*; 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; @@ -51,8 +45,7 @@ public void execute(Player player, String[] args) { } else { group.addEntity(entity); - SpawnedPartSelection sel = (SpawnedPartSelection) DisplayGroupManager.getPartSelection(player); - sel.refresh(); + ((MultiPartSelection) DisplayGroupManager.getPartSelection(player)).refresh(); } player.sendMessage(Component.text("Added entity to your selected group!", NamedTextColor.GREEN)); } 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 dca92698..f1150211 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 @@ -47,8 +47,7 @@ else if (group instanceof PacketDisplayEntityGroup pg){ } player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("| The interaction has been added to your group!", NamedTextColor.YELLOW))); - MultiPartSelection sel = (MultiPartSelection) DisplayGroupManager.getPartSelection(player); - sel.refresh(); + ((MultiPartSelection) DisplayGroupManager.getPartSelection(player)).refresh(); } static Interaction spawnInteraction(Player player, Location spawnLoc, String[] args){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java index 7c8a5638..a92eb5ac 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java @@ -6,6 +6,7 @@ import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.donnypz.displayentityutils.utils.DisplayUtils; import net.kyori.adventure.text.Component; @@ -54,6 +55,7 @@ public void execute(Player player, String[] args) { player.sendMessage(Component.text("- Failed to add the mannequin to your selected group", NamedTextColor.YELLOW)); return; } + ((MultiPartSelection) DisplayGroupManager.getPartSelection(player)).refresh(); player.sendMessage(Component.text("- The mannequin has been added to your selected group", NamedTextColor.GRAY)); } From fcde80702246765f8aabc692526895f43ec70463 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 24 May 2026 03:22:02 -0500 Subject: [PATCH 48/55] prevent mannequins dmg from creative players, if invulnerable --- .../listeners/entity/DEUEntityListener.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) 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 392af169..17412279 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 @@ -13,14 +13,13 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.machine.MachineState; import net.donnypz.displayentityutils.utils.DisplayUtils; import net.donnypz.displayentityutils.utils.controller.DisplayControllerManager; -import net.ess3.api.IUser; -import net.ess3.api.events.teleport.PreTeleportEvent; -import org.bukkit.Bukkit; -import org.bukkit.Location; +import net.donnypz.displayentityutils.utils.version.VersionUtils; +import org.bukkit.GameMode; import org.bukkit.damage.DamageSource; import org.bukkit.damage.DamageType; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Mannequin; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -58,12 +57,15 @@ 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); - } + //Disable Mannequin Damage, if invulnerable + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onDamage(EntityDamageByEntityEvent e){ + if (!VersionUtils.canSpawnMannequins()) return; + if (!(e.getDamager() instanceof Player p)) return; + if (!(e.getEntity() instanceof Mannequin m)) return; + if (!DisplayUtils.isInGroup(m)) return; + + if (p.getGameMode() == GameMode.CREATIVE && m.isInvulnerable()) e.setCancelled(true); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) From 72f1ada6635d484a6478fb12eabcd8f0e3c907ac Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 24 May 2026 03:28:47 -0500 Subject: [PATCH 49/55] fix plugin's listeners not loading if essentials isn't installed --- .../DisplayEntityPlugin.java | 5 ++ .../listeners/entity/DEUEntityListener.java | 77 ------------------- .../player/DEUPlayerTeleportListener.java | 58 ++++++++++++++ .../essentials/DEUEssentialsListener.java | 49 ++++++++++++ 4 files changed, 112 insertions(+), 77 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerTeleportListener.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/essentials/DEUEssentialsListener.java diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index daea4a6b..9951cf31 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -12,6 +12,7 @@ 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.listeners.player.essentials.DEUEssentialsListener; import net.donnypz.displayentityutils.managers.LocalManager; import net.donnypz.displayentityutils.managers.MYSQLManager; import net.donnypz.displayentityutils.managers.MongoManager; @@ -124,6 +125,9 @@ private void initializeDependencies(){ DisplayAPI.isWorldEditInstalled = Bukkit.getPluginManager().isPluginEnabled("WorldEdit"); DisplayAPI.isPAPIInstalled = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI"); DisplayAPI.isEssentialsInstalled = Bukkit.getPluginManager().isPluginEnabled("Essentials"); + if (DisplayAPI.isEssentialsInstalled){ + Bukkit.getPluginManager().registerEvents(new DEUEssentialsListener(), this); + } //Skript DisplayAPI.isSkriptInstalled = Bukkit.getPluginManager().isPluginEnabled("Skript"); @@ -167,6 +171,7 @@ private void registerListeners(){ Bukkit.getPluginManager().registerEvents(new DEUPlayerWorldListener(), this); Bukkit.getPluginManager().registerEvents(new DEUPlayerPlaceBlockListener(), this); Bukkit.getPluginManager().registerEvents(new DEUPlayerDigListener(), this); + Bukkit.getPluginManager().registerEvents(new DEUPlayerTeleportListener(), this); Bukkit.getPluginManager().registerEvents(new DEUInteractionListener(), this); Bukkit.getPluginManager().registerEvents(new DEUMannequinEditorListener(), this); } 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 17412279..cd826cb6 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 @@ -25,18 +25,11 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.*; -import org.bukkit.event.player.PlayerChangedWorldEvent; -import org.bukkit.event.player.PlayerTeleportEvent; import org.jetbrains.annotations.ApiStatus; -import java.util.HashMap; -import java.util.HashSet; -import java.util.UUID; - @ApiStatus.Internal public final class DEUEntityListener implements Listener { - private static final HashMap> passengerGroups = new HashMap<>(); //============Mythic==================== @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -123,76 +116,6 @@ public void onTeleportMonitor(EntityTeleportEvent e){ } - private void storeGroups(Player player){ - passengerGroups.computeIfAbsent(player.getUniqueId(), key -> new HashSet<>()); - HashSet groupsSet = passengerGroups.get(player.getUniqueId()); - - for (SpawnedDisplayEntityGroup group : DisplayUtils.getGroupPassengers(player)){ - group.dismount(); - groupsSet.add(group); - } - } - - - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onTeleport(PlayerTeleportEvent e){ - Location fromLoc = e.getFrom(); - Location toLoc = e.getTo(); - if (!fromLoc.getWorld().equals(toLoc.getWorld())){ - storeGroups(e.getPlayer()); - } - } - - - @EventHandler(priority = EventPriority.MONITOR) - public void onTPAcrossWorlds(PlayerChangedWorldEvent e){ - Player player = e.getPlayer(); - HashSet groups = passengerGroups.remove(player.getUniqueId()); - if (groups == null){ - return; - } - - Location location = player.getLocation(); - for (SpawnedDisplayEntityGroup group : groups) { - group.teleport(location, true, true); - group.rideEntity(player); - } - } - - //Essentials--------------------------- - @EventHandler - public void onEssentialsPreTP(PreTeleportEvent e){ - IUser user = e.getTeleportee(); - UUID userUUID = user.getUUID(); - Player player = Bukkit.getPlayer(userUUID); - if (player == null) return; - - storeGroups(player); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onEssentialsPreTPCancelled(PreTeleportEvent e){ - if (e.isCancelled()){ - passengerGroups.remove(e.getTeleportee().getUUID()); - } - } - - //Eseentials Same World - @EventHandler(priority = EventPriority.MONITOR) - public void onTeleportMonitor(PlayerTeleportEvent e){ - if (!e.getTo().getWorld().equals(e.getFrom().getWorld())) return; //different worlds - Player player = e.getPlayer(); - HashSet groups = passengerGroups.remove(player.getUniqueId()); - if (groups == null) return; - - for (SpawnedDisplayEntityGroup group : groups){ - group.teleport(e.getTo(), true, true); - group.rideEntity(player); - } - } - //------------------------------------- - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerTeleportListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerTeleportListener.java new file mode 100644 index 00000000..07b541bf --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerTeleportListener.java @@ -0,0 +1,58 @@ +package net.donnypz.displayentityutils.listeners.player; + +import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; +import net.donnypz.displayentityutils.utils.DisplayUtils; +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.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerTeleportEvent; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.UUID; + +public class DEUPlayerTeleportListener implements Listener { + + private static final HashMap> passengerGroups = new HashMap<>(); + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onTeleport(PlayerTeleportEvent e) { + Location fromLoc = e.getFrom(); + Location toLoc = e.getTo(); + if (!fromLoc.getWorld().equals(toLoc.getWorld())) { + storeGroups(e.getPlayer()); + } + } + + + @EventHandler(priority = EventPriority.MONITOR) + public void onTPAcrossWorlds(PlayerChangedWorldEvent e) { + Player player = e.getPlayer(); + HashSet groups = removePlayerGroupPassengers(player.getUniqueId()); + if (groups == null) { + return; + } + + Location location = player.getLocation(); + for (SpawnedDisplayEntityGroup group : groups) { + group.teleport(location, true, true); + group.rideEntity(player); + } + } + + public static void storeGroups(Player player) { + HashSet groupsSet = passengerGroups.computeIfAbsent(player.getUniqueId(), key -> new HashSet<>()); + + for (SpawnedDisplayEntityGroup group : DisplayUtils.getGroupPassengers(player)) { + group.dismount(); + groupsSet.add(group); + } + } + + public static HashSet removePlayerGroupPassengers(UUID playerUUID) { + return passengerGroups.remove(playerUUID); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/essentials/DEUEssentialsListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/essentials/DEUEssentialsListener.java new file mode 100644 index 00000000..8fff1c35 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/essentials/DEUEssentialsListener.java @@ -0,0 +1,49 @@ +package net.donnypz.displayentityutils.listeners.player.essentials; + +import net.donnypz.displayentityutils.listeners.player.DEUPlayerTeleportListener; +import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; +import net.ess3.api.IUser; +import net.ess3.api.events.teleport.PreTeleportEvent; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerTeleportEvent; + +import java.util.HashSet; +import java.util.UUID; + +public class DEUEssentialsListener implements Listener { + + @EventHandler + public void onEssentialsPreTP(PreTeleportEvent e) { + IUser user = e.getTeleportee(); + UUID userUUID = user.getUUID(); + Player player = Bukkit.getPlayer(userUUID); + if (player == null) return; + + DEUPlayerTeleportListener.storeGroups(player); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onEssentialsPreTPCancelled(PreTeleportEvent e) { + if (e.isCancelled()) { + DEUPlayerTeleportListener.removePlayerGroupPassengers(e.getTeleportee().getUUID()); + } + } + + //Eseentials Same World + @EventHandler(priority = EventPriority.MONITOR) + public void onTeleportMonitor(PlayerTeleportEvent e) { + if (!e.getTo().getWorld().equals(e.getFrom().getWorld())) return; //different worlds + Player player = e.getPlayer(); + HashSet groups = DEUPlayerTeleportListener.removePlayerGroupPassengers(player.getUniqueId()); + if (groups == null) return; + + for (SpawnedDisplayEntityGroup group : groups) { + group.teleport(e.getTo(), true, true); + group.rideEntity(player); + } + } +} From 47ef6229a2ca05b1bdb20cdfb91d75358f8c5d6e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 24 May 2026 04:08:57 -0500 Subject: [PATCH 50/55] Rework "/deu interaction spawnhere" to "spawn" w/ optional group adding. Remove "/deu interaction addtogroup" --- .../displayentityutils/command/CMDUtils.java | 27 ++++++ .../interaction/InteractionAddToGroupCMD.java | 92 ------------------- .../command/interaction/InteractionCMD.java | 10 +- .../interaction/InteractionSpawnCMD.java | 55 +++++++++++ .../interaction/InteractionSpawnHereCMD.java | 28 ------ .../command/mannequin/MannequinSpawnCMD.java | 22 +---- 6 files changed, 88 insertions(+), 146 deletions(-) delete mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionAddToGroupCMD.java create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionSpawnCMD.java delete mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionSpawnHereCMD.java diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/CMDUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/CMDUtils.java index 8bf6d7b0..3cf4296c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/CMDUtils.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/CMDUtils.java @@ -1,10 +1,17 @@ package net.donnypz.displayentityutils.command; +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.ActivePart; +import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; public final class CMDUtils { @@ -29,4 +36,24 @@ public static void sendUnsafeCMD(CommandSender sender, String command, String de } sender.sendMessage(msg); } + + public static void tryAddEntityToGroup(Player player, Entity entity, String[] args, int groupArg){ + String entityTypeName = entity.getType().getKey().getKey(); + if (args.length >= groupArg+1 && args[groupArg].equalsIgnoreCase("-g")){ + ActiveGroup group = DEUUser.getOrCreateUser(player).getSelectedGroup(); + if (group == null) { + player.sendMessage(Component.text("- You must have a group selected to add the "+entityTypeName+" to a group", NamedTextColor.YELLOW)); + return; + } + + ActivePart part = group.addEntity(entity); + if (part == null){ + player.sendMessage(Component.text("- Failed to add the "+entityTypeName+" to your selected group", NamedTextColor.YELLOW)); + return; + } + ((MultiPartSelection) DisplayGroupManager.getPartSelection(player)).refresh(); + + player.sendMessage(Component.text("- The "+entityTypeName+" has been added to your selected group", NamedTextColor.GRAY)); + } + } } 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 deleted file mode 100644 index f1150211..00000000 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionAddToGroupCMD.java +++ /dev/null @@ -1,92 +0,0 @@ -package net.donnypz.displayentityutils.command.interaction; - -import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.command.*; -import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.*; -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.format.NamedTextColor; -import org.bukkit.Location; -import org.bukkit.entity.Interaction; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -class InteractionAddToGroupCMD extends GroupSubCommand { - InteractionAddToGroupCMD(@NotNull DEUSubCommand parentSubCommand) { - super("addtogroup", parentSubCommand, Permission.INTERACTION_SPAWN, 4, true); - setTabComplete(2, ""); - setTabComplete(3, ""); - setTabComplete(4, "-here"); - } - - - @Override - protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage! /deu interaction addtogroup [-here]", NamedTextColor.RED))); - } - - @Override - protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @NotNull String[] args) { - Location spawn; - if (args.length >= 5){ - spawn = args[4].equalsIgnoreCase("-here") ? player.getLocation() : group.getLocation(); - } - else{ - spawn = group.getLocation(); - } - if (group instanceof SpawnedDisplayEntityGroup sg){ - Interaction i = spawnInteraction(player, spawn, args); - if (i == null) return; - sg.addEntity(i); - } - else if (group instanceof PacketDisplayEntityGroup pg){ - spawnInteraction(pg, player, spawn, args); - } - - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("| The interaction has been added to your group!", NamedTextColor.YELLOW))); - ((MultiPartSelection) DisplayGroupManager.getPartSelection(player)).refresh(); - } - - static Interaction spawnInteraction(Player player, Location spawnLoc, String[] args){ - try{ - - float height = Float.parseFloat(args[2]); - float width = Float.parseFloat(args[3]); - - Interaction interaction = spawnLoc.getWorld().spawn(spawnLoc, Interaction.class, i -> { - i.setInteractionHeight(height); - i.setInteractionWidth(width); - }); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Spawned a new Interaction entity", NamedTextColor.GREEN))); - player.sendMessage(Component.text("| Height: "+height, NamedTextColor.GRAY)); - player.sendMessage(Component.text("| Width: "+width, NamedTextColor.GRAY)); - return interaction; - } - catch(NumberFormatException e){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter valid numbers!", NamedTextColor.RED))); - return null; - } - } - - static void spawnInteraction(PacketDisplayEntityGroup group, Player player, Location spawnLoc, String[] args){ - try{ - float height = Float.parseFloat(args[2]); - float width = Float.parseFloat(args[3]); - - PacketDisplayEntityPart part = new PacketAttributeContainer() - .setAttribute(DisplayAttributes.Interaction.HEIGHT, height) - .setAttribute(DisplayAttributes.Interaction.WIDTH, width) - .createPart(SpawnedDisplayEntityPart.PartType.INTERACTION, spawnLoc); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Spawned a new packet-based Interaction entity", NamedTextColor.GREEN))); - player.sendMessage(Component.text("| Height: "+height, NamedTextColor.GRAY)); - player.sendMessage(Component.text("| Width: "+width, NamedTextColor.GRAY)); - group.addPart(part); - } - catch(NumberFormatException e){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter valid numbers!", NamedTextColor.RED))); - } - } -} \ No newline at end of file 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 37cb4ddf..78d15808 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 @@ -22,6 +22,7 @@ public final class InteractionCMD extends ConsoleUsableSubCommand { public InteractionCMD(){ super(Permission.HELP, new InteractionHelpCMD()); + new InteractionSpawnCMD(this); new InteractionAddCMD(this); new InteractionListCMD(this); new InteractionHeightCMD(this); @@ -29,8 +30,6 @@ public InteractionCMD(){ new InteractionScaleCMD(this); new InteractionPivotCMD(this); new InteractionResponsiveCMD(this); - new InteractionAddToGroupCMD(this); - new InteractionSpawnHereCMD(this); new InteractionInfoCMD(this); } @@ -53,16 +52,15 @@ public void execute(CommandSender sender, String[] args) { static void interactionHelp(CommandSender sender, int page){ sender.sendMessage(DisplayAPI.pluginPrefixLong); if (page == 1){ - sender.sendMessage(Component.text("Where applicable, these commands prioritize the interaction entity you're looking at over the one you may have selected", NamedTextColor.AQUA)); + sender.sendMessage(Component.text("Where applicable, these commands prioritize the interaction entity you're looking at over the one you may have selected", NamedTextColor.YELLOW)); CMDUtils.sendCMD(sender, "/deu interaction help", "Get help for interactions"); + CMDUtils.sendCMD(sender, "/deu interaction spawn [-g]", "Spawn an interaction entity at your location.\nUse \"-g\" to add it to your selected group"); CMDUtils.sendCMD(sender, "/deu interaction info", "Get info about an interaction entity, targeted or selected"); - CMDUtils.sendCMD(sender, "/deu interaction addtogroup [-here]", "Create an interaction entity part for a group, at the group's location. Use \"-here\" to spawn it at your location"); - CMDUtils.sendCMD(sender, "/deu interaction spawnhere ", "Create an interaction entity at your location"); CMDUtils.sendCMD(sender, "/deu interaction height ", "Set the height of an interaction"); CMDUtils.sendCMD(sender, "/deu interaction width ", "Set the width of an interaction"); + CMDUtils.sendCMD(sender, "/deu interaction scale [tick-duration] [tick-delay]", "Scale an interaction entity, optionally over a period of time"); } else{ - CMDUtils.sendCMD(sender, "/deu interaction scale [tick-duration] [tick-delay]", "Scale an interaction entity, optionally 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 [-all]", " Pivot an interaction around it's group's"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionSpawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionSpawnCMD.java new file mode 100644 index 00000000..7b10f786 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionSpawnCMD.java @@ -0,0 +1,55 @@ +package net.donnypz.displayentityutils.command.interaction; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.CMDUtils; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Location; +import org.bukkit.entity.Interaction; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +class InteractionSpawnCMD extends PlayerSubCommand { + InteractionSpawnCMD(@NotNull DEUSubCommand parentSubCommand) { + super("spawn", parentSubCommand, Permission.INTERACTION_SPAWN); + setTabComplete(2, ""); + setTabComplete(3, ""); + setTabComplete(4, "-g"); + } + + @Override + public void execute(Player player, String[] args) { + if (args.length < 4){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage! /deu interaction spawn [-g]", NamedTextColor.RED))); + return; + } + + Interaction interaction = spawnInteraction(player, player.getLocation(), args); + CMDUtils.tryAddEntityToGroup(player, interaction, args, 4); + } + + private Interaction spawnInteraction(Player player, Location spawnLoc, String[] args){ + try{ + + float height = Float.parseFloat(args[2]); + float width = Float.parseFloat(args[3]); + + Interaction interaction = spawnLoc.getWorld().spawn(spawnLoc, Interaction.class, i -> { + i.setInteractionHeight(height); + i.setInteractionWidth(width); + }); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("A new interaction has been spawned at your location!", NamedTextColor.GREEN))); + player.sendMessage(Component.text("| Height: "+height, NamedTextColor.GRAY)); + player.sendMessage(Component.text("| Width: "+width, NamedTextColor.GRAY)); + return interaction; + } + catch(NumberFormatException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter valid numbers!", NamedTextColor.RED))); + return null; + } + } +} \ No newline at end of file diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionSpawnHereCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionSpawnHereCMD.java deleted file mode 100644 index 72b0eada..00000000 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionSpawnHereCMD.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.donnypz.displayentityutils.command.interaction; - -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.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -class InteractionSpawnHereCMD extends PlayerSubCommand { - InteractionSpawnHereCMD(@NotNull DEUSubCommand parentSubCommand) { - super("spawnhere", parentSubCommand, Permission.INTERACTION_SPAWN); - setTabComplete(2, ""); - setTabComplete(3, ""); - } - - @Override - public void execute(Player player, String[] args) { - if (args.length < 4){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage! /deu interaction spawnhere ", NamedTextColor.RED))); - return; - } - - InteractionAddToGroupCMD.spawnInteraction(player, player.getLocation(), args); - } -} \ No newline at end of file diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java index a92eb5ac..81812924 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSpawnCMD.java @@ -2,11 +2,10 @@ import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.CMDUtils; 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.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.donnypz.displayentityutils.utils.DisplayUtils; import net.kyori.adventure.text.Component; @@ -41,23 +40,6 @@ public void execute(Player player, String[] args) { player.sendMessage(DisplayAPI.pluginPrefix .append(MiniMessage.miniMessage().deserialize("A new mannequin has been spawned at your location!"))); - - - if (args.length >= 3 && args[2].equalsIgnoreCase("-g")){ - ActiveGroup group = DEUUser.getOrCreateUser(player).getSelectedGroup(); - if (group == null) { - player.sendMessage(Component.text("- You must have a group selected to add the mannequin to a group", NamedTextColor.YELLOW)); - return; - } - - ActivePart part = group.addEntity(mannequin); - if (part == null){ - player.sendMessage(Component.text("- Failed to add the mannequin to your selected group", NamedTextColor.YELLOW)); - return; - } - ((MultiPartSelection) DisplayGroupManager.getPartSelection(player)).refresh(); - - player.sendMessage(Component.text("- The mannequin has been added to your selected group", NamedTextColor.GRAY)); - } + CMDUtils.tryAddEntityToGroup(player, mannequin, args, 2); } } From 02b95131e99c8419a135012e188268297af0ecbb Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 24 May 2026 04:10:45 -0500 Subject: [PATCH 51/55] no changes --- .../donnypz/displayentityutils/utils/version/VersionUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c6dc6c52..b05282c2 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 @@ -30,7 +30,7 @@ public static boolean canViewDialogs(@NotNull Player player, boolean sendErrorMe } return false; } - else if (getProtocolVersion(player) < 771){ //1.21.6 + else if (IS_1_21_6){ if (!serverHasDialogs()){ if (sendErrorMessage){ player.sendMessage(DisplayAPI.pluginPrefix From 7778d3b15dfbfd8bcbeb82f639bb2ba07ba35bfc Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 24 May 2026 04:11:06 -0500 Subject: [PATCH 52/55] use java 25 when publishing release --- .github/workflows/modrinth.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/modrinth.yml b/.github/workflows/modrinth.yml index 4c8d25ac..3ed48f8d 100644 --- a/.github/workflows/modrinth.yml +++ b/.github/workflows/modrinth.yml @@ -15,8 +15,8 @@ jobs: - name: Set up JDK uses: actions/setup-java@v5 with: - java-version: 21 - distribution: temurin + java-version: '25' + distribution: 'temurin' cache: maven - name: Set version from release tag @@ -38,4 +38,5 @@ jobs: game-versions: |- 1.20.x 1.21.x + 26.1.x files: plugin/target/displayentityutils-${{ github.event.release.tag_name }}.jar \ No newline at end of file From 31121cc077655f0730489a3e72b337e111d2551e Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 24 May 2026 18:04:10 -0500 Subject: [PATCH 53/55] Fix animations not converting in worlds other than the overworld. Ensure resources close correctly --- .../utils/ConversionUtils.java | 2 +- .../convert/datapack/BDEngineDPConverter.java | 32 +++++++------------ 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/ConversionUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/ConversionUtils.java index 188bce4c..af5f5a5d 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/ConversionUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/ConversionUtils.java @@ -83,7 +83,7 @@ public static String getExecuteCommandWorldName(@NotNull World w){ worldName = "overworld"; } else{ - worldName = w.getName(); + worldName = w.getKey().toString(); } return worldName; } 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 c18ff03a..d0509570 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 @@ -152,6 +152,11 @@ private void playAndSave(Player player, String datapackName, ZipFile zipFile){ } DisplayAPI.getScheduler().run(() -> createdGroup.unregister(true, true)); + + try{ + zipFile.close(); + } + catch(IOException ignored){} }, delay+5); } @@ -223,9 +228,8 @@ private void executeCommands(ZipEntry zipEntry, ZipFile zipFile, Player player, SpawnedDisplayAnimationFrame frame){ - try{ - InputStream stream = zipFile.getInputStream(zipEntry); - BufferedReader br = new BufferedReader(new InputStreamReader(stream)); + try(InputStream stream = zipFile.getInputStream(zipEntry); + BufferedReader br = new BufferedReader(new InputStreamReader(stream))){ String line; while ((line = br.readLine()) != null){ if (line.startsWith("#") || line.isEmpty()){ @@ -253,17 +257,10 @@ private void executeCommands(ZipEntry zipEntry, try{ DatapackEntitySpawned.prepareAnimationMaster(projectName); } - catch(NumberFormatException e){ - br.close(); - zipFile.close(); + catch(NumberFormatException | ArrayIndexOutOfBoundsException e){ player.sendMessage(Component.text("Animation conversion failed! Read console", NamedTextColor.RED)); - throw new RuntimeException("Failed to read command from zip entry: Invalid timestamp value"); - } - catch(ArrayIndexOutOfBoundsException e){ - br.close(); - zipFile.close(); - player.sendMessage(Component.text("Animation conversion failed! Read console", NamedTextColor.RED)); - throw new RuntimeException("Failed to read command from zip entry: Wrong game version downloaded"); + String message = e instanceof NumberFormatException ? "Invalid timestamp value" : "Wrong game version downloaded"; + throw new RuntimeException("Failed to read command from zip entry: "+message, e); } } @@ -307,17 +304,12 @@ else if (line.startsWith("execute") && line.contains("playsound")){ World w = spawnLoc.getWorld(); String worldName = ConversionUtils.getExecuteCommandWorldName(w); - Bukkit.dispatchCommand(silentSender, "execute positioned "+coordinates+" in "+worldName+" run "+line); + Bukkit.dispatchCommand(silentSender, "execute at "+player.getName()+" positioned "+coordinates+" in "+worldName+" run "+line); } - br.close(); } catch (IOException e){ player.sendMessage(Component.text("Animation conversion failed! Read console")); - try{ - zipFile.close(); - } - catch(IOException ignored){} - throw new RuntimeException("Failed to execute command from ZipEntry: "+zipEntry.getName()); + throw new RuntimeException("Failed to execute command from ZipEntry: "+zipEntry.getName(), e); } } From fed8cf8dfcabcf91716b750a76ffdedddefd0565 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 24 May 2026 18:05:32 -0500 Subject: [PATCH 54/55] ensure schedulers fallback to correct value for periods --- .../utils/version/folia/SchedulerImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/version/folia/SchedulerImpl.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/version/folia/SchedulerImpl.java index a18ec179..b221e2e2 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/version/folia/SchedulerImpl.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/version/folia/SchedulerImpl.java @@ -77,7 +77,7 @@ public Task runTimer(SchedulerRunnable runnable, long delay, long period) { Task task; if (FoliaUtils.isFolia()){ task = new Task(Bukkit.getGlobalRegionScheduler() - .runAtFixedRate(DisplayAPI.getPlugin(), t -> runnable.run(), Math.max(delay, 1), Math.max(delay, 1))); + .runAtFixedRate(DisplayAPI.getPlugin(), t -> runnable.run(), Math.max(delay, 1), Math.max(period, 1))); } else{ task = new Task(Bukkit.getScheduler().runTaskTimer(DisplayAPI.getPlugin(), runnable, delay, period)); @@ -91,7 +91,7 @@ public Task runTimerAsync(SchedulerRunnable runnable, long delay, long period) { Task task; if (FoliaUtils.isFolia()){ task = new Task(Bukkit.getGlobalRegionScheduler() - .runAtFixedRate(DisplayAPI.getPlugin(), t -> runnable.run(), Math.max(delay, 1), Math.max(delay, 1))); + .runAtFixedRate(DisplayAPI.getPlugin(), t -> runnable.run(), Math.max(delay, 1), Math.max(period, 1))); } else{ task = new Task(Bukkit.getScheduler().runTaskTimerAsynchronously(DisplayAPI.getPlugin(), runnable, delay, period)); @@ -163,7 +163,7 @@ public Task entityRunTimer(@NotNull Entity entity, SchedulerRunnable runnable, l Task task; if (FoliaUtils.isFolia()){ task = new Task(entity.getScheduler() - .runAtFixedRate(DisplayAPI.getPlugin(), t -> runnable.run(), null, Math.max(delay, 1), Math.max(delay, 1))); + .runAtFixedRate(DisplayAPI.getPlugin(), t -> runnable.run(), null, Math.max(delay, 1), Math.max(period, 1))); } else{ task = new Task(Bukkit.getScheduler().runTaskTimer(DisplayAPI.getPlugin(), runnable, delay, period)); @@ -177,7 +177,7 @@ public Task entityRunTimerAsync(@NotNull Entity entity, SchedulerRunnable runnab Task task; if (FoliaUtils.isFolia()){ task = new Task(entity.getScheduler() - .runAtFixedRate(DisplayAPI.getPlugin(), t -> runnable.run(), null, Math.max(delay, 1), Math.max(delay, 1))); + .runAtFixedRate(DisplayAPI.getPlugin(), t -> runnable.run(), null, Math.max(delay, 1), Math.max(period, 1))); } else{ task = new Task(Bukkit.getScheduler().runTaskTimerAsynchronously(DisplayAPI.getPlugin(), runnable, delay, period)); From ad2c13d63794a4b68deea06ab76d0f981ab060ed Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 24 May 2026 18:36:16 -0500 Subject: [PATCH 55/55] 3.5.2 --- 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 bedcabc5..5a33ffab 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-5 + 3.5.2 api diff --git a/plugin/pom.xml b/plugin/pom.xml index 497c938a..d00be887 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-5 + 3.5.2 plugin diff --git a/pom.xml b/pom.xml index 1ee95713..a5b3a8df 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.5.2-PRE-5 + 3.5.2 pom DisplayEntityUtils